mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-28 16:24:39 +02:00
- More reformatting merged from OpenBSD CVS
- Merged OpenBSD CVS changes: - [channels.c] report from mrwizard@psu.edu via djm@ibs.com.au - [channels.c] set SO_REUSEADDR and SO_LINGER for forwarded ports. chip@valinux.com via damien@ibs.com.au - [nchan.c] it's not an error() if shutdown_write failes in nchan. - [readconf.c] remove dead #ifdef-0-code - [readconf.c servconf.c] strcasecmp instead of tolower - [scp.c] progress meter overflow fix from damien@ibs.com.au - [ssh-add.1 ssh-add.c] SSH_ASKPASS support - [ssh.1 ssh.c] postpone fork_after_authentication until command execution, request/patch from jahakala@cc.jyu.fi via damien@ibs.com.au plus: use daemon() for backgrounding
This commit is contained in:
parent
9072e18896
commit
5428f646ad
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#ifndef HAVE_PAM
|
#ifndef HAVE_PAM
|
||||||
|
|
||||||
RCSID("$Id: auth-passwd.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
|
RCSID("$Id: auth-passwd.c,v 1.7 1999/11/25 00:54:57 damien Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -39,14 +39,10 @@ auth_password(struct passwd * pw, const char *password)
|
|||||||
struct spwd *spw;
|
struct spwd *spw;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pw->pw_uid == 0 && options.permit_root_login == 2) {
|
if (pw->pw_uid == 0 && options.permit_root_login == 2)
|
||||||
/* Server does not permit root login with password */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
if (*password == '\0' && options.permit_empty_passwd == 0)
|
||||||
if (*password == '\0' && options.permit_empty_passwd == 0) {
|
|
||||||
/* Server does not permit empty password login */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
/* deny if no user. */
|
/* deny if no user. */
|
||||||
if (pw == NULL)
|
if (pw == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@ -74,8 +70,10 @@ auth_password(struct passwd * pw, const char *password)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(KRB4)
|
#if defined(KRB4)
|
||||||
/* Support for Kerberos v4 authentication - Dug Song
|
/*
|
||||||
<dugsong@UMICH.EDU> */
|
* Support for Kerberos v4 authentication
|
||||||
|
* - Dug Song <dugsong@UMICH.EDU>
|
||||||
|
*/
|
||||||
if (options.kerberos_authentication) {
|
if (options.kerberos_authentication) {
|
||||||
AUTH_DAT adata;
|
AUTH_DAT adata;
|
||||||
KTEXT_ST tkt;
|
KTEXT_ST tkt;
|
||||||
@ -86,8 +84,10 @@ auth_password(struct passwd * pw, const char *password)
|
|||||||
char realm[REALM_SZ];
|
char realm[REALM_SZ];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Try Kerberos password authentication only for non-root
|
/*
|
||||||
users and only if Kerberos is installed. */
|
* Try Kerberos password authentication only for non-root
|
||||||
|
* users and only if Kerberos is installed.
|
||||||
|
*/
|
||||||
if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
|
if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
|
||||||
|
|
||||||
/* Set up our ticket file. */
|
/* Set up our ticket file. */
|
||||||
@ -144,14 +144,17 @@ auth_password(struct passwd * pw, const char *password)
|
|||||||
goto kerberos_auth_failure;
|
goto kerberos_auth_failure;
|
||||||
}
|
}
|
||||||
} else if (r == KDC_PR_UNKNOWN) {
|
} else if (r == KDC_PR_UNKNOWN) {
|
||||||
/* Allow login if no rcmd service exists,
|
/*
|
||||||
but log the error. */
|
* Allow login if no rcmd service exists, but
|
||||||
|
* log the error.
|
||||||
|
*/
|
||||||
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
|
log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
|
||||||
"not registered, or srvtab is wrong?", pw->pw_name,
|
"not registered, or srvtab is wrong?", pw->pw_name,
|
||||||
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
|
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
|
||||||
} else {
|
} else {
|
||||||
/* TGT is bad, forget it. Possibly
|
/*
|
||||||
spoofed! */
|
* TGT is bad, forget it. Possibly spoofed!
|
||||||
|
*/
|
||||||
packet_send_debug("WARNING: Kerberos V4 TGT "
|
packet_send_debug("WARNING: Kerberos V4 TGT "
|
||||||
"possibly spoofed for %s: %s",
|
"possibly spoofed for %s: %s",
|
||||||
pw->pw_name, krb_err_txt[r]);
|
pw->pw_name, krb_err_txt[r]);
|
||||||
@ -175,11 +178,8 @@ auth_password(struct passwd * pw, const char *password)
|
|||||||
#endif /* KRB4 */
|
#endif /* KRB4 */
|
||||||
|
|
||||||
/* Check for users with no password. */
|
/* Check for users with no password. */
|
||||||
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) {
|
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
|
||||||
packet_send_debug("Login permitted without a password "
|
|
||||||
"because the account has no password.");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_SHADOW_H
|
#ifdef HAVE_SHADOW_H
|
||||||
spw = getspnam(pw->pw_name);
|
spw = getspnam(pw->pw_name);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: auth-rh-rsa.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
|
RCSID("$Id: auth-rh-rsa.c,v 1.7 1999/11/25 00:54:57 damien Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -23,8 +23,10 @@ RCSID("$Id: auth-rh-rsa.c,v 1.6 1999/11/24 13:26:21 damien Exp $");
|
|||||||
#include "uidswap.h"
|
#include "uidswap.h"
|
||||||
#include "servconf.h"
|
#include "servconf.h"
|
||||||
|
|
||||||
/* Tries to authenticate the user using the .rhosts file and the host using
|
/*
|
||||||
its host key. Returns true if authentication succeeds. */
|
* Tries to authenticate the user using the .rhosts file and the host using
|
||||||
|
* its host key. Returns true if authentication succeeds.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
auth_rhosts_rsa(struct passwd *pw, const char *client_user,
|
auth_rhosts_rsa(struct passwd *pw, const char *client_user,
|
||||||
@ -57,8 +59,10 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user,
|
|||||||
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
|
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid);
|
char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid);
|
||||||
/* Check file permissions of SSH_USER_HOSTFILE, auth_rsa()
|
/*
|
||||||
did already check pw->pw_dir, but there is a race XXX */
|
* Check file permissions of SSH_USER_HOSTFILE, auth_rsa()
|
||||||
|
* did already check pw->pw_dir, but there is a race XXX
|
||||||
|
*/
|
||||||
if (options.strict_modes &&
|
if (options.strict_modes &&
|
||||||
(stat(user_hostfile, &st) == 0) &&
|
(stat(user_hostfile, &st) == 0) &&
|
||||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||||
@ -91,8 +95,10 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user,
|
|||||||
canonical_hostname);
|
canonical_hostname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* We have authenticated the user using .rhosts or /etc/hosts.equiv, and the host using RSA.
|
/*
|
||||||
We accept the authentication. */
|
* We have authenticated the user using .rhosts or /etc/hosts.equiv,
|
||||||
|
* and the host using RSA. We accept the authentication.
|
||||||
|
*/
|
||||||
|
|
||||||
verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
|
verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
|
||||||
pw->pw_name, client_user, canonical_hostname);
|
pw->pw_name, client_user, canonical_hostname);
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: auth-rhosts.c,v 1.5 1999/11/24 13:26:21 damien Exp $");
|
RCSID("$Id: auth-rhosts.c,v 1.6 1999/11/25 00:54:57 damien Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -24,9 +24,11 @@ RCSID("$Id: auth-rhosts.c,v 1.5 1999/11/24 13:26:21 damien Exp $");
|
|||||||
#include "uidswap.h"
|
#include "uidswap.h"
|
||||||
#include "servconf.h"
|
#include "servconf.h"
|
||||||
|
|
||||||
/* This function processes an rhosts-style file (.rhosts, .shosts, or
|
/*
|
||||||
/etc/hosts.equiv). This returns true if authentication can be granted
|
* This function processes an rhosts-style file (.rhosts, .shosts, or
|
||||||
based on the file, and returns zero otherwise. */
|
* /etc/hosts.equiv). This returns true if authentication can be granted
|
||||||
|
* based on the file, and returns zero otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
check_rhosts_file(const char *filename, const char *hostname,
|
check_rhosts_file(const char *filename, const char *hostname,
|
||||||
@ -41,7 +43,6 @@ check_rhosts_file(const char *filename, const char *hostname,
|
|||||||
if (!f)
|
if (!f)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Go through the file, checking every entry. */
|
|
||||||
while (fgets(buf, sizeof(buf), f)) {
|
while (fgets(buf, sizeof(buf), f)) {
|
||||||
/* All three must be at least as big as buf to avoid overflows. */
|
/* All three must be at least as big as buf to avoid overflows. */
|
||||||
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
|
char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
|
||||||
@ -52,13 +53,17 @@ check_rhosts_file(const char *filename, const char *hostname,
|
|||||||
if (*cp == '#' || *cp == '\n' || !*cp)
|
if (*cp == '#' || *cp == '\n' || !*cp)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* NO_PLUS is supported at least on OSF/1. We skip it (we
|
/*
|
||||||
don't ever support the plus syntax). */
|
* NO_PLUS is supported at least on OSF/1. We skip it (we
|
||||||
|
* don't ever support the plus syntax).
|
||||||
|
*/
|
||||||
if (strncmp(cp, "NO_PLUS", 7) == 0)
|
if (strncmp(cp, "NO_PLUS", 7) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* This should be safe because each buffer is as big as
|
/*
|
||||||
the whole string, and thus cannot be overwritten. */
|
* This should be safe because each buffer is as big as the
|
||||||
|
* whole string, and thus cannot be overwritten.
|
||||||
|
*/
|
||||||
switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
|
switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
|
||||||
case 0:
|
case 0:
|
||||||
packet_send_debug("Found empty line in %.100s.", filename);
|
packet_send_debug("Found empty line in %.100s.", filename);
|
||||||
@ -135,10 +140,11 @@ check_rhosts_file(const char *filename, const char *hostname,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tries to authenticate the user using the .shosts or .rhosts file.
|
/*
|
||||||
Returns true if authentication succeeds. If ignore_rhosts is
|
* Tries to authenticate the user using the .shosts or .rhosts file. Returns
|
||||||
true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
|
* true if authentication succeeds. If ignore_rhosts is true, only
|
||||||
are ignored). */
|
* /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
auth_rhosts(struct passwd *pw, const char *client_user)
|
auth_rhosts(struct passwd *pw, const char *client_user)
|
||||||
@ -150,11 +156,13 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||||||
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
|
static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
|
||||||
unsigned int rhosts_file_index;
|
unsigned int rhosts_file_index;
|
||||||
|
|
||||||
/* Quick check: if the user has no .shosts or .rhosts files,
|
|
||||||
return failure immediately without doing costly lookups from
|
|
||||||
name servers. */
|
|
||||||
/* Switch to the user's uid. */
|
/* Switch to the user's uid. */
|
||||||
temporarily_use_uid(pw->pw_uid);
|
temporarily_use_uid(pw->pw_uid);
|
||||||
|
/*
|
||||||
|
* Quick check: if the user has no .shosts or .rhosts files, return
|
||||||
|
* failure immediately without doing costly lookups from name
|
||||||
|
* servers.
|
||||||
|
*/
|
||||||
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
|
||||||
rhosts_file_index++) {
|
rhosts_file_index++) {
|
||||||
/* Check users .rhosts or .shosts. */
|
/* Check users .rhosts or .shosts. */
|
||||||
@ -172,7 +180,6 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||||||
stat(SSH_HOSTS_EQUIV, &st) < 0)
|
stat(SSH_HOSTS_EQUIV, &st) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Get the name, address, and port of the remote host. */
|
|
||||||
hostname = get_canonical_hostname();
|
hostname = get_canonical_hostname();
|
||||||
ipaddr = get_remote_ipaddr();
|
ipaddr = get_remote_ipaddr();
|
||||||
|
|
||||||
@ -191,8 +198,10 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Check that the home directory is owned by root or the user, and
|
/*
|
||||||
is not group or world writable. */
|
* Check that the home directory is owned by root or the user, and is
|
||||||
|
* not group or world writable.
|
||||||
|
*/
|
||||||
if (stat(pw->pw_dir, &st) < 0) {
|
if (stat(pw->pw_dir, &st) < 0) {
|
||||||
log("Rhosts authentication refused for %.100s: no home directory %.200s",
|
log("Rhosts authentication refused for %.100s: no home directory %.200s",
|
||||||
pw->pw_name, pw->pw_dir);
|
pw->pw_name, pw->pw_dir);
|
||||||
@ -221,10 +230,12 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||||||
if (stat(buf, &st) < 0)
|
if (stat(buf, &st) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Make sure that the file is either owned by the user or
|
/*
|
||||||
by root, and make sure it is not writable by anyone but
|
* Make sure that the file is either owned by the user or by
|
||||||
the owner. This is to help avoid novices accidentally
|
* root, and make sure it is not writable by anyone but the
|
||||||
allowing access to their account by anyone. */
|
* owner. This is to help avoid novices accidentally
|
||||||
|
* allowing access to their account by anyone.
|
||||||
|
*/
|
||||||
if (options.strict_modes &&
|
if (options.strict_modes &&
|
||||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||||
(st.st_mode & 022) != 0)) {
|
(st.st_mode & 022) != 0)) {
|
||||||
|
93
auth-rsa.c
93
auth-rsa.c
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: auth-rsa.c,v 1.9 1999/11/24 13:26:21 damien Exp $");
|
RCSID("$Id: auth-rsa.c,v 1.10 1999/11/25 00:54:57 damien Exp $");
|
||||||
|
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@ -43,22 +43,27 @@ extern int no_pty_flag;
|
|||||||
extern char *forced_command;
|
extern char *forced_command;
|
||||||
extern struct envstring *custom_environment;
|
extern struct envstring *custom_environment;
|
||||||
|
|
||||||
/* Session identifier that is used to bind key exchange and authentication
|
/*
|
||||||
responses to a particular session. */
|
* Session identifier that is used to bind key exchange and authentication
|
||||||
|
* responses to a particular session.
|
||||||
|
*/
|
||||||
extern unsigned char session_id[16];
|
extern unsigned char session_id[16];
|
||||||
|
|
||||||
/* The .ssh/authorized_keys file contains public keys, one per line, in the
|
/*
|
||||||
following format:
|
* The .ssh/authorized_keys file contains public keys, one per line, in the
|
||||||
options bits e n comment
|
* following format:
|
||||||
where bits, e and n are decimal numbers,
|
* options bits e n comment
|
||||||
and comment is any string of characters up to newline. The maximum
|
* where bits, e and n are decimal numbers,
|
||||||
length of a line is 8000 characters. See the documentation for a
|
* and comment is any string of characters up to newline. The maximum
|
||||||
description of the options.
|
* length of a line is 8000 characters. See the documentation for a
|
||||||
*/
|
* description of the options.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Performs the RSA authentication challenge-response dialog with the client,
|
/*
|
||||||
and returns true (non-zero) if the client gave the correct answer to
|
* Performs the RSA authentication challenge-response dialog with the client,
|
||||||
our challenge; returns zero if the client gives a wrong answer. */
|
* and returns true (non-zero) if the client gave the correct answer to
|
||||||
|
* our challenge; returns zero if the client gives a wrong answer.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
|
auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
|
||||||
@ -128,9 +133,11 @@ auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Performs the RSA authentication dialog with the client. This returns
|
/*
|
||||||
0 if the client could not be authenticated, and 1 if authentication was
|
* Performs the RSA authentication dialog with the client. This returns
|
||||||
successful. This may exit if there is a serious protocol violation. */
|
* 0 if the client could not be authenticated, and 1 if authentication was
|
||||||
|
* successful. This may exit if there is a serious protocol violation.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||||
@ -204,30 +211,32 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
/* Flag indicating whether authentication has succeeded. */
|
/* Flag indicating whether authentication has succeeded. */
|
||||||
authenticated = 0;
|
authenticated = 0;
|
||||||
|
|
||||||
/* Initialize mp-int variables. */
|
|
||||||
e = BN_new();
|
e = BN_new();
|
||||||
n = BN_new();
|
n = BN_new();
|
||||||
|
|
||||||
/* Go though the accepted keys, looking for the current key. If
|
/*
|
||||||
found, perform a challenge-response dialog to verify that the
|
* Go though the accepted keys, looking for the current key. If
|
||||||
user really has the corresponding private key. */
|
* found, perform a challenge-response dialog to verify that the
|
||||||
|
* user really has the corresponding private key.
|
||||||
|
*/
|
||||||
while (fgets(line, sizeof(line), f)) {
|
while (fgets(line, sizeof(line), f)) {
|
||||||
char *cp;
|
char *cp;
|
||||||
char *options;
|
char *options;
|
||||||
|
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
/* Skip leading whitespace. */
|
/* Skip leading whitespace, empty and comment lines. */
|
||||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++);
|
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
|
;
|
||||||
/* Skip empty and comment lines. */
|
|
||||||
if (!*cp || *cp == '\n' || *cp == '#')
|
if (!*cp || *cp == '\n' || *cp == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Check if there are options for this key, and if so,
|
/*
|
||||||
save their starting address and skip the option part
|
* Check if there are options for this key, and if so,
|
||||||
for now. If there are no options, set the starting
|
* save their starting address and skip the option part
|
||||||
address to NULL. */
|
* for now. If there are no options, set the starting
|
||||||
|
* address to NULL.
|
||||||
|
*/
|
||||||
if (*cp < '0' || *cp > '9') {
|
if (*cp < '0' || *cp > '9') {
|
||||||
int quoted = 0;
|
int quoted = 0;
|
||||||
options = cp;
|
options = cp;
|
||||||
@ -258,7 +267,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
|
|
||||||
/* Check if the we have found the desired key (identified by its modulus). */
|
/* Check if the we have found the desired key (identified by its modulus). */
|
||||||
if (BN_cmp(n, client_n) != 0)
|
if (BN_cmp(n, client_n) != 0)
|
||||||
continue; /* Wrong key. */
|
continue;
|
||||||
|
|
||||||
/* We have found the desired key. */
|
/* We have found the desired key. */
|
||||||
|
|
||||||
@ -269,10 +278,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
packet_send_debug("Wrong response to RSA authentication challenge.");
|
packet_send_debug("Wrong response to RSA authentication challenge.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Correct response. The client has been successfully
|
/*
|
||||||
authenticated. Note that we have not yet processed the
|
* Correct response. The client has been successfully
|
||||||
options; this will be reset if the options cause the
|
* authenticated. Note that we have not yet processed the
|
||||||
authentication to be rejected. */
|
* options; this will be reset if the options cause the
|
||||||
|
* authentication to be rejected.
|
||||||
|
*/
|
||||||
authenticated = 1;
|
authenticated = 1;
|
||||||
|
|
||||||
/* RSA part of authentication was accepted. Now process the options. */
|
/* RSA part of authentication was accepted. Now process the options. */
|
||||||
@ -412,7 +423,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
goto next_option;
|
goto next_option;
|
||||||
}
|
}
|
||||||
bad_option:
|
bad_option:
|
||||||
/* Unknown option. */
|
|
||||||
log("Bad options in %.100s file, line %lu: %.50s",
|
log("Bad options in %.100s file, line %lu: %.50s",
|
||||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||||
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
||||||
@ -421,8 +431,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
next_option:
|
next_option:
|
||||||
/* Skip the comma, and move to the next option
|
/*
|
||||||
(or break out if there are no more). */
|
* Skip the comma, and move to the next option
|
||||||
|
* (or break out if there are no more).
|
||||||
|
*/
|
||||||
if (!*options)
|
if (!*options)
|
||||||
fatal("Bugs in auth-rsa.c option processing.");
|
fatal("Bugs in auth-rsa.c option processing.");
|
||||||
if (*options == ' ' || *options == '\t')
|
if (*options == ' ' || *options == '\t')
|
||||||
@ -434,8 +446,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Break out of the loop if authentication was successful;
|
/*
|
||||||
otherwise continue searching. */
|
* Break out of the loop if authentication was successful;
|
||||||
|
* otherwise continue searching.
|
||||||
|
*/
|
||||||
if (authenticated)
|
if (authenticated)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -446,7 +460,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
/* Close the file. */
|
/* Close the file. */
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
/* Clear any mp-int variables. */
|
|
||||||
BN_clear_free(n);
|
BN_clear_free(n);
|
||||||
BN_clear_free(e);
|
BN_clear_free(e);
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
#ifdef SKEY
|
#ifdef SKEY
|
||||||
|
|
||||||
RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $");
|
RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include <sha1.h>
|
#ifdef HAVE_OPENSSL
|
||||||
|
#include <openssl/sha1.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SSL
|
||||||
|
#include <ssl/sha1.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
|
/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */
|
||||||
|
|
||||||
|
127
authfd.c
127
authfd.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: authfd.c,v 1.7 1999/11/24 13:26:21 damien Exp $");
|
RCSID("$Id: authfd.c,v 1.8 1999/11/25 00:54:57 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -63,9 +63,11 @@ ssh_get_authentication_socket()
|
|||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Closes the agent socket if it should be closed (depends on how it was
|
/*
|
||||||
obtained). The argument must have been returned by
|
* Closes the agent socket if it should be closed (depends on how it was
|
||||||
ssh_get_authentication_socket(). */
|
* obtained). The argument must have been returned by
|
||||||
|
* ssh_get_authentication_socket().
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ssh_close_authentication_socket(int sock)
|
ssh_close_authentication_socket(int sock)
|
||||||
@ -74,11 +76,13 @@ ssh_close_authentication_socket(int sock)
|
|||||||
close(sock);
|
close(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opens and connects a private socket for communication with the
|
/*
|
||||||
authentication agent. Returns the file descriptor (which must be
|
* Opens and connects a private socket for communication with the
|
||||||
shut down and closed by the caller when no longer needed).
|
* authentication agent. Returns the file descriptor (which must be
|
||||||
Returns NULL if an error occurred and the connection could not be
|
* shut down and closed by the caller when no longer needed).
|
||||||
opened. */
|
* Returns NULL if an error occurred and the connection could not be
|
||||||
|
* opened.
|
||||||
|
*/
|
||||||
|
|
||||||
AuthenticationConnection *
|
AuthenticationConnection *
|
||||||
ssh_get_authentication_connection()
|
ssh_get_authentication_connection()
|
||||||
@ -88,12 +92,13 @@ ssh_get_authentication_connection()
|
|||||||
|
|
||||||
sock = ssh_get_authentication_socket();
|
sock = ssh_get_authentication_socket();
|
||||||
|
|
||||||
/* Fail if we couldn't obtain a connection. This happens if we
|
/*
|
||||||
exited due to a timeout. */
|
* Fail if we couldn't obtain a connection. This happens if we
|
||||||
|
* exited due to a timeout.
|
||||||
|
*/
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Applocate the connection structure and initialize it. */
|
|
||||||
auth = xmalloc(sizeof(*auth));
|
auth = xmalloc(sizeof(*auth));
|
||||||
auth->fd = sock;
|
auth->fd = sock;
|
||||||
buffer_init(&auth->packet);
|
buffer_init(&auth->packet);
|
||||||
@ -103,8 +108,10 @@ ssh_get_authentication_connection()
|
|||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Closes the connection to the authentication agent and frees any associated
|
/*
|
||||||
memory. */
|
* Closes the connection to the authentication agent and frees any associated
|
||||||
|
* memory.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ssh_close_authentication_connection(AuthenticationConnection *ac)
|
ssh_close_authentication_connection(AuthenticationConnection *ac)
|
||||||
@ -115,10 +122,12 @@ ssh_close_authentication_connection(AuthenticationConnection *ac)
|
|||||||
xfree(ac);
|
xfree(ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the first authentication identity held by the agent.
|
/*
|
||||||
Returns true if an identity is available, 0 otherwise.
|
* Returns the first authentication identity held by the agent.
|
||||||
The caller must initialize the integers before the call, and free the
|
* Returns true if an identity is available, 0 otherwise.
|
||||||
comment after a successful call (before calling ssh_get_next_identity). */
|
* The caller must initialize the integers before the call, and free the
|
||||||
|
* comment after a successful call (before calling ssh_get_next_identity).
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ssh_get_first_identity(AuthenticationConnection *auth,
|
ssh_get_first_identity(AuthenticationConnection *auth,
|
||||||
@ -127,8 +136,10 @@ ssh_get_first_identity(AuthenticationConnection *auth,
|
|||||||
unsigned char msg[8192];
|
unsigned char msg[8192];
|
||||||
int len, l;
|
int len, l;
|
||||||
|
|
||||||
/* Send a message to the agent requesting for a list of the
|
/*
|
||||||
identities it can represent. */
|
* Send a message to the agent requesting for a list of the
|
||||||
|
* identities it can represent.
|
||||||
|
*/
|
||||||
msg[0] = 0;
|
msg[0] = 0;
|
||||||
msg[1] = 0;
|
msg[1] = 0;
|
||||||
msg[2] = 0;
|
msg[2] = 0;
|
||||||
@ -149,8 +160,10 @@ ssh_get_first_identity(AuthenticationConnection *auth,
|
|||||||
len -= l;
|
len -= l;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract the length, and check it for sanity. (We cannot trust
|
/*
|
||||||
authentication agents). */
|
* Extract the length, and check it for sanity. (We cannot trust
|
||||||
|
* authentication agents).
|
||||||
|
*/
|
||||||
len = GET_32BIT(msg);
|
len = GET_32BIT(msg);
|
||||||
if (len < 1 || len > 256 * 1024)
|
if (len < 1 || len > 256 * 1024)
|
||||||
fatal("Authentication reply message too long: %d\n", len);
|
fatal("Authentication reply message too long: %d\n", len);
|
||||||
@ -182,10 +195,12 @@ ssh_get_first_identity(AuthenticationConnection *auth,
|
|||||||
return ssh_get_next_identity(auth, e, n, comment);
|
return ssh_get_next_identity(auth, e, n, comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the next authentication identity for the agent. Other functions
|
/*
|
||||||
can be called between this and ssh_get_first_identity or two calls of this
|
* Returns the next authentication identity for the agent. Other functions
|
||||||
function. This returns 0 if there are no more identities. The caller
|
* can be called between this and ssh_get_first_identity or two calls of this
|
||||||
must free comment after a successful return. */
|
* function. This returns 0 if there are no more identities. The caller
|
||||||
|
* must free comment after a successful return.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ssh_get_next_identity(AuthenticationConnection *auth,
|
ssh_get_next_identity(AuthenticationConnection *auth,
|
||||||
@ -197,8 +212,10 @@ ssh_get_next_identity(AuthenticationConnection *auth,
|
|||||||
if (auth->howmany <= 0)
|
if (auth->howmany <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Get the next entry from the packet. These will abort with a
|
/*
|
||||||
fatal error if the packet is too short or contains corrupt data. */
|
* Get the next entry from the packet. These will abort with a fatal
|
||||||
|
* error if the packet is too short or contains corrupt data.
|
||||||
|
*/
|
||||||
bits = buffer_get_int(&auth->identities);
|
bits = buffer_get_int(&auth->identities);
|
||||||
buffer_get_bignum(&auth->identities, e);
|
buffer_get_bignum(&auth->identities, e);
|
||||||
buffer_get_bignum(&auth->identities, n);
|
buffer_get_bignum(&auth->identities, n);
|
||||||
@ -214,11 +231,13 @@ ssh_get_next_identity(AuthenticationConnection *auth,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates a random challenge, sends it to the agent, and waits for response
|
/*
|
||||||
from the agent. Returns true (non-zero) if the agent gave the correct
|
* Generates a random challenge, sends it to the agent, and waits for
|
||||||
answer, zero otherwise. Response type selects the style of response
|
* response from the agent. Returns true (non-zero) if the agent gave the
|
||||||
desired, with 0 corresponding to protocol version 1.0 (no longer supported)
|
* correct answer, zero otherwise. Response type selects the style of
|
||||||
and 1 corresponding to protocol version 1.1. */
|
* response desired, with 0 corresponding to protocol version 1.0 (no longer
|
||||||
|
* supported) and 1 corresponding to protocol version 1.1.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||||
@ -259,8 +278,10 @@ error_cleanup:
|
|||||||
buffer_free(&buffer);
|
buffer_free(&buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Wait for response from the agent. First read the length of the
|
/*
|
||||||
response packet. */
|
* Wait for response from the agent. First read the length of the
|
||||||
|
* response packet.
|
||||||
|
*/
|
||||||
len = 4;
|
len = 4;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = read(auth->fd, buf + 4 - len, len);
|
l = read(auth->fd, buf + 4 - len, len);
|
||||||
@ -303,8 +324,10 @@ error_cleanup:
|
|||||||
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
|
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
|
||||||
fatal("Bad authentication response: %d", buf[0]);
|
fatal("Bad authentication response: %d", buf[0]);
|
||||||
|
|
||||||
/* Get the response from the packet. This will abort with a fatal
|
/*
|
||||||
error if the packet is corrupt. */
|
* Get the response from the packet. This will abort with a fatal
|
||||||
|
* error if the packet is corrupt.
|
||||||
|
*/
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
response[i] = buffer_get_char(&buffer);
|
response[i] = buffer_get_char(&buffer);
|
||||||
|
|
||||||
@ -315,8 +338,10 @@ error_cleanup:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds an identity to the authentication server. This call is not meant to
|
/*
|
||||||
be used by normal applications. */
|
* Adds an identity to the authentication server. This call is not meant to
|
||||||
|
* be used by normal applications.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ssh_add_identity(AuthenticationConnection *auth,
|
ssh_add_identity(AuthenticationConnection *auth,
|
||||||
@ -401,8 +426,10 @@ error_cleanup:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removes an identity from the authentication server. This call is not meant
|
/*
|
||||||
to be used by normal applications. */
|
* Removes an identity from the authentication server. This call is not
|
||||||
|
* meant to be used by normal applications.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||||
@ -431,8 +458,10 @@ error_cleanup:
|
|||||||
buffer_free(&buffer);
|
buffer_free(&buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Wait for response from the agent. First read the length of the
|
/*
|
||||||
response packet. */
|
* Wait for response from the agent. First read the length of the
|
||||||
|
* response packet.
|
||||||
|
*/
|
||||||
len = 4;
|
len = 4;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = read(auth->fd, buf + 4 - len, len);
|
l = read(auth->fd, buf + 4 - len, len);
|
||||||
@ -480,8 +509,10 @@ error_cleanup:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Removes all identities from the agent. This call is not meant
|
/*
|
||||||
to be used by normal applications. */
|
* Removes all identities from the agent. This call is not meant to be used
|
||||||
|
* by normal applications.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
ssh_remove_all_identities(AuthenticationConnection *auth)
|
ssh_remove_all_identities(AuthenticationConnection *auth)
|
||||||
@ -499,8 +530,10 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
|
|||||||
error("Error writing to authentication socket.");
|
error("Error writing to authentication socket.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Wait for response from the agent. First read the length of the
|
/*
|
||||||
response packet. */
|
* Wait for response from the agent. First read the length of the
|
||||||
|
* response packet.
|
||||||
|
*/
|
||||||
len = 4;
|
len = 4;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
l = read(auth->fd, buf + 4 - len, len);
|
l = read(auth->fd, buf + 4 - len, len);
|
||||||
|
82
authfd.h
82
authfd.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: authfd.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: authfd.h,v 1.4 1999/11/25 00:54:58 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef AUTHFD_H
|
#ifndef AUTHFD_H
|
||||||
#define AUTHFD_H
|
#define AUTHFD_H
|
||||||
@ -40,33 +40,43 @@ typedef struct {
|
|||||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||||
int ssh_get_authentication_socket();
|
int ssh_get_authentication_socket();
|
||||||
|
|
||||||
/* This should be called for any descriptor returned by
|
/*
|
||||||
ssh_get_authentication_socket(). Depending on the way the descriptor was
|
* This should be called for any descriptor returned by
|
||||||
obtained, this may close the descriptor. */
|
* ssh_get_authentication_socket(). Depending on the way the descriptor was
|
||||||
|
* obtained, this may close the descriptor.
|
||||||
|
*/
|
||||||
void ssh_close_authentication_socket(int authfd);
|
void ssh_close_authentication_socket(int authfd);
|
||||||
|
|
||||||
/* Opens and connects a private socket for communication with the
|
/*
|
||||||
authentication agent. Returns NULL if an error occurred and the
|
* Opens and connects a private socket for communication with the
|
||||||
connection could not be opened. The connection should be closed by
|
* authentication agent. Returns NULL if an error occurred and the
|
||||||
the caller by calling ssh_close_authentication_connection(). */
|
* connection could not be opened. The connection should be closed by the
|
||||||
|
* caller by calling ssh_close_authentication_connection().
|
||||||
|
*/
|
||||||
AuthenticationConnection *ssh_get_authentication_connection();
|
AuthenticationConnection *ssh_get_authentication_connection();
|
||||||
|
|
||||||
/* Closes the connection to the authentication agent and frees any associated
|
/*
|
||||||
memory. */
|
* Closes the connection to the authentication agent and frees any associated
|
||||||
|
* memory.
|
||||||
|
*/
|
||||||
void ssh_close_authentication_connection(AuthenticationConnection * ac);
|
void ssh_close_authentication_connection(AuthenticationConnection * ac);
|
||||||
|
|
||||||
/* Returns the first authentication identity held by the agent.
|
/*
|
||||||
Returns true if an identity is available, 0 otherwise.
|
* Returns the first authentication identity held by the agent. Returns true
|
||||||
The caller must initialize the integers before the call, and free the
|
* if an identity is available, 0 otherwise. The caller must initialize the
|
||||||
comment after a successful call (before calling ssh_get_next_identity). */
|
* integers before the call, and free the comment after a successful call
|
||||||
|
* (before calling ssh_get_next_identity).
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
ssh_get_first_identity(AuthenticationConnection * connection,
|
ssh_get_first_identity(AuthenticationConnection * connection,
|
||||||
BIGNUM * e, BIGNUM * n, char **comment);
|
BIGNUM * e, BIGNUM * n, char **comment);
|
||||||
|
|
||||||
/* Returns the next authentication identity for the agent. Other functions
|
/*
|
||||||
can be called between this and ssh_get_first_identity or two calls of this
|
* Returns the next authentication identity for the agent. Other functions
|
||||||
function. This returns 0 if there are no more identities. The caller
|
* can be called between this and ssh_get_first_identity or two calls of this
|
||||||
must free comment after a successful return. */
|
* function. This returns 0 if there are no more identities. The caller
|
||||||
|
* must free comment after a successful return.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
ssh_get_next_identity(AuthenticationConnection * connection,
|
ssh_get_next_identity(AuthenticationConnection * connection,
|
||||||
BIGNUM * e, BIGNUM * n, char **comment);
|
BIGNUM * e, BIGNUM * n, char **comment);
|
||||||
@ -80,24 +90,30 @@ ssh_decrypt_challenge(AuthenticationConnection * auth,
|
|||||||
unsigned int response_type,
|
unsigned int response_type,
|
||||||
unsigned char response[16]);
|
unsigned char response[16]);
|
||||||
|
|
||||||
/* Adds an identity to the authentication server. This call is not meant to
|
/*
|
||||||
be used by normal applications. This returns true if the identity
|
* Adds an identity to the authentication server. This call is not meant to
|
||||||
was successfully added. */
|
* be used by normal applications. This returns true if the identity was
|
||||||
int ssh_add_identity(AuthenticationConnection * connection,
|
* successfully added.
|
||||||
RSA * key, const char *comment);
|
*/
|
||||||
|
int
|
||||||
|
ssh_add_identity(AuthenticationConnection * connection, RSA * key,
|
||||||
|
const char *comment);
|
||||||
|
|
||||||
/* Removes the identity from the authentication server. This call is
|
/*
|
||||||
not meant to be used by normal applications. This returns true if the
|
* Removes the identity from the authentication server. This call is not
|
||||||
identity was successfully added. */
|
* meant to be used by normal applications. This returns true if the
|
||||||
int ssh_remove_identity(AuthenticationConnection * connection,
|
* identity was successfully added.
|
||||||
RSA * key);
|
*/
|
||||||
|
int ssh_remove_identity(AuthenticationConnection * connection, RSA * key);
|
||||||
|
|
||||||
/* Removes all identities from the authentication agent. This call is not
|
/*
|
||||||
meant to be used by normal applications. This returns true if the
|
* Removes all identities from the authentication agent. This call is not
|
||||||
operation was successful. */
|
* meant to be used by normal applications. This returns true if the
|
||||||
int ssh_remove_all_identities(AuthenticationConnection * connection);
|
* operation was successful.
|
||||||
|
*/
|
||||||
|
int ssh_remove_all_identities(AuthenticationConnection * connection);
|
||||||
|
|
||||||
/* Closes the connection to the authentication agent. */
|
/* Closes the connection to the authentication agent. */
|
||||||
void ssh_close_authentication(AuthenticationConnection * connection);
|
void ssh_close_authentication(AuthenticationConnection * connection);
|
||||||
|
|
||||||
#endif /* AUTHFD_H */
|
#endif /* AUTHFD_H */
|
||||||
|
63
authfile.c
63
authfile.c
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: authfile.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: authfile.c,v 1.5 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
@ -33,10 +33,12 @@ RCSID("$Id: authfile.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
|||||||
/* Version identification string for identity files. */
|
/* Version identification string for identity files. */
|
||||||
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||||
|
|
||||||
/* Saves the authentication (private) key in a file, encrypting it with
|
/*
|
||||||
passphrase. The identification of the file (lowest 64 bits of n)
|
* Saves the authentication (private) key in a file, encrypting it with
|
||||||
will precede the key to provide identification of the key without
|
* passphrase. The identification of the file (lowest 64 bits of n) will
|
||||||
needing a passphrase. */
|
* precede the key to provide identification of the key without needing a
|
||||||
|
* passphrase.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
save_private_key(const char *filename, const char *passphrase,
|
save_private_key(const char *filename, const char *passphrase,
|
||||||
@ -49,9 +51,10 @@ save_private_key(const char *filename, const char *passphrase,
|
|||||||
int cipher_type;
|
int cipher_type;
|
||||||
u_int32_t rand;
|
u_int32_t rand;
|
||||||
|
|
||||||
/* If the passphrase is empty, use SSH_CIPHER_NONE to ease
|
/*
|
||||||
converting to another cipher; otherwise use
|
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
|
||||||
SSH_AUTHFILE_CIPHER. */
|
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
|
||||||
|
*/
|
||||||
if (strcmp(passphrase, "") == 0)
|
if (strcmp(passphrase, "") == 0)
|
||||||
cipher_type = SSH_CIPHER_NONE;
|
cipher_type = SSH_CIPHER_NONE;
|
||||||
else
|
else
|
||||||
@ -68,9 +71,11 @@ save_private_key(const char *filename, const char *passphrase,
|
|||||||
buf[3] = buf[1];
|
buf[3] = buf[1];
|
||||||
buffer_append(&buffer, buf, 4);
|
buffer_append(&buffer, buf, 4);
|
||||||
|
|
||||||
/* Store the private key (n and e will not be stored because they
|
/*
|
||||||
will be stored in plain text, and storing them also in
|
* Store the private key (n and e will not be stored because they
|
||||||
encrypted format would just give known plaintext). */
|
* will be stored in plain text, and storing them also in encrypted
|
||||||
|
* format would just give known plaintext).
|
||||||
|
*/
|
||||||
buffer_put_bignum(&buffer, key->d);
|
buffer_put_bignum(&buffer, key->d);
|
||||||
buffer_put_bignum(&buffer, key->iqmp);
|
buffer_put_bignum(&buffer, key->iqmp);
|
||||||
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
|
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
|
||||||
@ -112,11 +117,9 @@ save_private_key(const char *filename, const char *passphrase,
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
buffer_free(&buffer);
|
buffer_free(&buffer);
|
||||||
|
|
||||||
/* Write to a file. */
|
|
||||||
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||||
if (f < 0)
|
if (f < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
|
if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
|
||||||
buffer_len(&encrypted)) {
|
buffer_len(&encrypted)) {
|
||||||
debug("Write to key file %.200s failed: %.100s", filename,
|
debug("Write to key file %.200s failed: %.100s", filename,
|
||||||
@ -131,9 +134,11 @@ save_private_key(const char *filename, const char *passphrase,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads the public part of the key file. Returns 0 if an error
|
/*
|
||||||
was encountered (the file does not exist or is not readable), and
|
* Loads the public part of the key file. Returns 0 if an error was
|
||||||
non-zero otherwise. */
|
* encountered (the file does not exist or is not readable), and non-zero
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
load_public_key(const char *filename, RSA * pub,
|
load_public_key(const char *filename, RSA * pub,
|
||||||
@ -144,11 +149,9 @@ load_public_key(const char *filename, RSA * pub,
|
|||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
/* Read data from the file into the buffer. */
|
|
||||||
f = open(filename, O_RDONLY);
|
f = open(filename, O_RDONLY);
|
||||||
if (f < 0)
|
if (f < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
len = lseek(f, (off_t) 0, SEEK_END);
|
len = lseek(f, (off_t) 0, SEEK_END);
|
||||||
lseek(f, (off_t) 0, SEEK_SET);
|
lseek(f, (off_t) 0, SEEK_SET);
|
||||||
|
|
||||||
@ -170,8 +173,10 @@ load_public_key(const char *filename, RSA * pub,
|
|||||||
buffer_free(&buffer);
|
buffer_free(&buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Make sure it begins with the id string. Consume the id string
|
/*
|
||||||
from the buffer. */
|
* Make sure it begins with the id string. Consume the id string
|
||||||
|
* from the buffer.
|
||||||
|
*/
|
||||||
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
|
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
|
||||||
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||||
debug("Bad key file %.200s.", filename);
|
debug("Bad key file %.200s.", filename);
|
||||||
@ -197,9 +202,12 @@ load_public_key(const char *filename, RSA * pub,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads the private key from the file. Returns 0 if an error is encountered
|
/*
|
||||||
(file does not exist or is not readable, or passphrase is bad).
|
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||||
This initializes the private key. */
|
* (file does not exist or is not readable, or passphrase is bad). This
|
||||||
|
* initializes the private key.
|
||||||
|
* Assumes we are called under uid of the owner of the file.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
load_private_key(const char *filename, const char *passphrase,
|
load_private_key(const char *filename, const char *passphrase,
|
||||||
@ -214,12 +222,11 @@ load_private_key(const char *filename, const char *passphrase,
|
|||||||
BIGNUM *aux;
|
BIGNUM *aux;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
/* Read the file into the buffer. */
|
|
||||||
f = open(filename, O_RDONLY);
|
f = open(filename, O_RDONLY);
|
||||||
if (f < 0)
|
if (f < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* We assume we are called under uid of the owner of the file */
|
/* check owner and modes */
|
||||||
if (fstat(f, &st) < 0 ||
|
if (fstat(f, &st) < 0 ||
|
||||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||||
(st.st_mode & 077) != 0) {
|
(st.st_mode & 077) != 0) {
|
||||||
@ -252,8 +259,10 @@ load_private_key(const char *filename, const char *passphrase,
|
|||||||
buffer_free(&buffer);
|
buffer_free(&buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Make sure it begins with the id string. Consume the id string
|
/*
|
||||||
from the buffer. */
|
* Make sure it begins with the id string. Consume the id string
|
||||||
|
* from the buffer.
|
||||||
|
*/
|
||||||
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
|
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
|
||||||
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||||
debug("Bad key file %.200s.", filename);
|
debug("Bad key file %.200s.", filename);
|
||||||
|
4
bufaux.c
4
bufaux.c
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: bufaux.c,v 1.6 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: bufaux.c,v 1.7 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
|
|||||||
buffer_append(buffer, msg, 2);
|
buffer_append(buffer, msg, 2);
|
||||||
/* Store the binary data. */
|
/* Store the binary data. */
|
||||||
buffer_append(buffer, buf, oi);
|
buffer_append(buffer, buf, oi);
|
||||||
/* Clear the temporary data. */
|
|
||||||
memset(buf, 0, bin_size);
|
memset(buf, 0, bin_size);
|
||||||
xfree(buf);
|
xfree(buf);
|
||||||
}
|
}
|
||||||
|
22
bufaux.h
22
bufaux.h
@ -11,15 +11,17 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: bufaux.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: bufaux.h,v 1.3 1999/11/25 00:54:58 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef BUFAUX_H
|
#ifndef BUFAUX_H
|
||||||
#define BUFAUX_H
|
#define BUFAUX_H
|
||||||
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
/*
|
||||||
by (bits+7)/8 bytes of binary data, msb first. */
|
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
|
||||||
|
* by (bits+7)/8 bytes of binary data, msb first.
|
||||||
|
*/
|
||||||
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
|
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
|
||||||
|
|
||||||
/* Retrieves an BIGNUM from the buffer. */
|
/* Retrieves an BIGNUM from the buffer. */
|
||||||
@ -37,12 +39,14 @@ int buffer_get_char(Buffer * buffer);
|
|||||||
/* Stores a character in the buffer. */
|
/* Stores a character in the buffer. */
|
||||||
void buffer_put_char(Buffer * buffer, int value);
|
void buffer_put_char(Buffer * buffer, int value);
|
||||||
|
|
||||||
/* Returns an arbitrary binary string from the buffer. The string cannot
|
/*
|
||||||
be longer than 256k. The returned value points to memory allocated
|
* Returns an arbitrary binary string from the buffer. The string cannot be
|
||||||
with xmalloc; it is the responsibility of the calling function to free
|
* longer than 256k. The returned value points to memory allocated with
|
||||||
the data. If length_ptr is non-NULL, the length of the returned data
|
* xmalloc; it is the responsibility of the calling function to free the
|
||||||
will be stored there. A null character will be automatically appended
|
* data. If length_ptr is non-NULL, the length of the returned data will be
|
||||||
to the returned string, and is not counted in length. */
|
* stored there. A null character will be automatically appended to the
|
||||||
|
* returned string, and is not counted in length.
|
||||||
|
*/
|
||||||
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
|
char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
|
||||||
|
|
||||||
/* Stores and arbitrary binary string in the buffer. */
|
/* Stores and arbitrary binary string in the buffer. */
|
||||||
|
22
buffer.c
22
buffer.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: buffer.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: buffer.c,v 1.3 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
@ -40,8 +40,10 @@ buffer_free(Buffer *buffer)
|
|||||||
xfree(buffer->buf);
|
xfree(buffer->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clears any data from the buffer, making it empty. This does not actually
|
/*
|
||||||
zero the memory. */
|
* Clears any data from the buffer, making it empty. This does not actually
|
||||||
|
* zero the memory.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
buffer_clear(Buffer *buffer)
|
buffer_clear(Buffer *buffer)
|
||||||
@ -60,9 +62,11 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len)
|
|||||||
memcpy(cp, data, len);
|
memcpy(cp, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Appends space to the buffer, expanding the buffer if necessary.
|
/*
|
||||||
This does not actually copy the data into the buffer, but instead
|
* Appends space to the buffer, expanding the buffer if necessary. This does
|
||||||
returns a pointer to the allocated region. */
|
* not actually copy the data into the buffer, but instead returns a pointer
|
||||||
|
* to the allocated region.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
|
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
|
||||||
@ -79,8 +83,10 @@ restart:
|
|||||||
buffer->end += len;
|
buffer->end += len;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* If the buffer is quite empty, but all data is at the end, move
|
/*
|
||||||
the data to the beginning and retry. */
|
* If the buffer is quite empty, but all data is at the end, move the
|
||||||
|
* data to the beginning and retry.
|
||||||
|
*/
|
||||||
if (buffer->offset > buffer->alloc / 2) {
|
if (buffer->offset > buffer->alloc / 2) {
|
||||||
memmove(buffer->buf, buffer->buf + buffer->offset,
|
memmove(buffer->buf, buffer->buf + buffer->offset,
|
||||||
buffer->end - buffer->offset);
|
buffer->end - buffer->offset);
|
||||||
|
16
buffer.h
16
buffer.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: buffer.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: buffer.h,v 1.3 1999/11/25 00:54:58 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef BUFFER_H
|
#ifndef BUFFER_H
|
||||||
#define BUFFER_H
|
#define BUFFER_H
|
||||||
@ -37,9 +37,11 @@ void buffer_clear(Buffer * buffer);
|
|||||||
/* Appends data to the buffer, expanding it if necessary. */
|
/* Appends data to the buffer, expanding it if necessary. */
|
||||||
void buffer_append(Buffer * buffer, const char *data, unsigned int len);
|
void buffer_append(Buffer * buffer, const char *data, unsigned int len);
|
||||||
|
|
||||||
/* Appends space to the buffer, expanding the buffer if necessary.
|
/*
|
||||||
This does not actually copy the data into the buffer, but instead
|
* Appends space to the buffer, expanding the buffer if necessary. This does
|
||||||
returns a pointer to the allocated region. */
|
* not actually copy the data into the buffer, but instead returns a pointer
|
||||||
|
* to the allocated region.
|
||||||
|
*/
|
||||||
void buffer_append_space(Buffer * buffer, char **datap, unsigned int len);
|
void buffer_append_space(Buffer * buffer, char **datap, unsigned int len);
|
||||||
|
|
||||||
/* Returns the number of bytes of data in the buffer. */
|
/* Returns the number of bytes of data in the buffer. */
|
||||||
@ -57,8 +59,10 @@ void buffer_consume_end(Buffer * buffer, unsigned int bytes);
|
|||||||
/* Returns a pointer to the first used byte in the buffer. */
|
/* Returns a pointer to the first used byte in the buffer. */
|
||||||
char *buffer_ptr(Buffer * buffer);
|
char *buffer_ptr(Buffer * buffer);
|
||||||
|
|
||||||
/* Dumps the contents of the buffer to stderr in hex. This intended for
|
/*
|
||||||
debugging purposes only. */
|
* Dumps the contents of the buffer to stderr in hex. This intended for
|
||||||
|
* debugging purposes only.
|
||||||
|
*/
|
||||||
void buffer_dump(Buffer * buffer);
|
void buffer_dump(Buffer * buffer);
|
||||||
|
|
||||||
#endif /* BUFFER_H */
|
#endif /* BUFFER_H */
|
||||||
|
79
canohost.c
79
canohost.c
@ -14,14 +14,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: canohost.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: canohost.c,v 1.4 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
/* Return the canonical name of the host at the other end of the socket.
|
/*
|
||||||
The caller should free the returned string with xfree. */
|
* Return the canonical name of the host at the other end of the socket. The
|
||||||
|
* caller should free the returned string with xfree.
|
||||||
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
get_remote_hostname(int socket)
|
get_remote_hostname(int socket)
|
||||||
@ -52,19 +54,23 @@ get_remote_hostname(int socket)
|
|||||||
else
|
else
|
||||||
strlcpy(name, hp->h_name, sizeof(name));
|
strlcpy(name, hp->h_name, sizeof(name));
|
||||||
|
|
||||||
/* Convert it to all lowercase (which is expected by the
|
/*
|
||||||
rest of this software). */
|
* Convert it to all lowercase (which is expected by the rest
|
||||||
|
* of this software).
|
||||||
|
*/
|
||||||
for (i = 0; name[i]; i++)
|
for (i = 0; name[i]; i++)
|
||||||
if (isupper(name[i]))
|
if (isupper(name[i]))
|
||||||
name[i] = tolower(name[i]);
|
name[i] = tolower(name[i]);
|
||||||
|
|
||||||
/* Map it back to an IP address and check that the given
|
/*
|
||||||
address actually is an address of this host. This is
|
* Map it back to an IP address and check that the given
|
||||||
necessary because anyone with access to a name server
|
* address actually is an address of this host. This is
|
||||||
can define arbitrary names for an IP address. Mapping
|
* necessary because anyone with access to a name server can
|
||||||
from name to IP address can be trusted better (but can
|
* define arbitrary names for an IP address. Mapping from
|
||||||
still be fooled if the intruder has access to the name
|
* name to IP address can be trusted better (but can still be
|
||||||
server of the domain). */
|
* fooled if the intruder has access to the name server of
|
||||||
|
* the domain).
|
||||||
|
*/
|
||||||
hp = gethostbyname(name);
|
hp = gethostbyname(name);
|
||||||
if (!hp) {
|
if (!hp) {
|
||||||
log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
|
log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
|
||||||
@ -76,8 +82,10 @@ get_remote_hostname(int socket)
|
|||||||
if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
|
if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
|
||||||
== 0)
|
== 0)
|
||||||
break;
|
break;
|
||||||
/* If we reached the end of the list, the address was not
|
/*
|
||||||
there. */
|
* If we reached the end of the list, the address was not
|
||||||
|
* there.
|
||||||
|
*/
|
||||||
if (!hp->h_addr_list[i]) {
|
if (!hp->h_addr_list[i]) {
|
||||||
/* Address not found for the host name. */
|
/* Address not found for the host name. */
|
||||||
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
|
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
|
||||||
@ -94,16 +102,17 @@ get_remote_hostname(int socket)
|
|||||||
|
|
||||||
check_ip_options:
|
check_ip_options:
|
||||||
|
|
||||||
/* If IP options are supported, make sure there are none (log and
|
/*
|
||||||
disconnect them if any are found). Basically we are worried
|
* If IP options are supported, make sure there are none (log and
|
||||||
about source routing; it can be used to pretend you are
|
* disconnect them if any are found). Basically we are worried about
|
||||||
somebody (ip-address) you are not. That itself may be "almost
|
* source routing; it can be used to pretend you are somebody
|
||||||
acceptable" under certain circumstances, but rhosts
|
* (ip-address) you are not. That itself may be "almost acceptable"
|
||||||
autentication is useless if source routing is accepted. Notice
|
* under certain circumstances, but rhosts autentication is useless
|
||||||
also that if we just dropped source routing here, the other
|
* if source routing is accepted. Notice also that if we just dropped
|
||||||
side could use IP spoofing to do rest of the interaction and
|
* source routing here, the other side could use IP spoofing to do
|
||||||
could still bypass security. So we exit here if we detect any
|
* rest of the interaction and could still bypass security. So we
|
||||||
IP options. */
|
* exit here if we detect any IP options.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
unsigned char options[200], *ucp;
|
unsigned char options[200], *ucp;
|
||||||
char text[1024], *cp;
|
char text[1024], *cp;
|
||||||
@ -134,9 +143,11 @@ check_ip_options:
|
|||||||
static char *canonical_host_name = NULL;
|
static char *canonical_host_name = NULL;
|
||||||
static char *canonical_host_ip = NULL;
|
static char *canonical_host_ip = NULL;
|
||||||
|
|
||||||
/* Return the canonical name of the host in the other side of the current
|
/*
|
||||||
connection. The host name is cached, so it is efficient to call this
|
* Return the canonical name of the host in the other side of the current
|
||||||
several times. */
|
* connection. The host name is cached, so it is efficient to call this
|
||||||
|
* several times.
|
||||||
|
*/
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
get_canonical_hostname()
|
get_canonical_hostname()
|
||||||
@ -154,8 +165,10 @@ get_canonical_hostname()
|
|||||||
return canonical_host_name;
|
return canonical_host_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the IP-address of the remote host as a string. The returned
|
/*
|
||||||
string need not be freed. */
|
* Returns the IP-address of the remote host as a string. The returned
|
||||||
|
* string need not be freed.
|
||||||
|
*/
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
get_remote_ipaddr()
|
get_remote_ipaddr()
|
||||||
@ -163,7 +176,7 @@ get_remote_ipaddr()
|
|||||||
struct sockaddr_in from;
|
struct sockaddr_in from;
|
||||||
int fromlen, socket;
|
int fromlen, socket;
|
||||||
|
|
||||||
/* Check if we have previously retrieved this same name. */
|
/* Check whether we have chached the name. */
|
||||||
if (canonical_host_ip != NULL)
|
if (canonical_host_ip != NULL)
|
||||||
return canonical_host_ip;
|
return canonical_host_ip;
|
||||||
|
|
||||||
@ -215,8 +228,10 @@ get_remote_port()
|
|||||||
{
|
{
|
||||||
int socket;
|
int socket;
|
||||||
|
|
||||||
/* If the connection is not a socket, return 65535. This is
|
/*
|
||||||
intentionally chosen to be an unprivileged port number. */
|
* If the connection is not a socket, return 65535. This is
|
||||||
|
* intentionally chosen to be an unprivileged port number.
|
||||||
|
*/
|
||||||
if (packet_get_connection_in() != packet_get_connection_out())
|
if (packet_get_connection_in() != packet_get_connection_out())
|
||||||
return 65535;
|
return 65535;
|
||||||
|
|
||||||
|
376
channels.c
376
channels.c
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: channels.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: channels.c,v 1.8 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@ -37,17 +37,23 @@ RCSID("$Id: channels.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
|
|||||||
/* Max len of agent socket */
|
/* Max len of agent socket */
|
||||||
#define MAX_SOCKET_NAME 100
|
#define MAX_SOCKET_NAME 100
|
||||||
|
|
||||||
/* Pointer to an array containing all allocated channels. The array is
|
/*
|
||||||
dynamically extended as needed. */
|
* Pointer to an array containing all allocated channels. The array is
|
||||||
|
* dynamically extended as needed.
|
||||||
|
*/
|
||||||
static Channel *channels = NULL;
|
static Channel *channels = NULL;
|
||||||
|
|
||||||
/* Size of the channel array. All slots of the array must always be
|
/*
|
||||||
initialized (at least the type field); unused slots are marked with
|
* Size of the channel array. All slots of the array must always be
|
||||||
type SSH_CHANNEL_FREE. */
|
* initialized (at least the type field); unused slots are marked with type
|
||||||
|
* SSH_CHANNEL_FREE.
|
||||||
|
*/
|
||||||
static int channels_alloc = 0;
|
static int channels_alloc = 0;
|
||||||
|
|
||||||
/* Maximum file descriptor value used in any of the channels. This is updated
|
/*
|
||||||
in channel_allocate. */
|
* Maximum file descriptor value used in any of the channels. This is
|
||||||
|
* updated in channel_allocate.
|
||||||
|
*/
|
||||||
static int channel_max_fd_value = 0;
|
static int channel_max_fd_value = 0;
|
||||||
|
|
||||||
/* Name and directory of socket for authentication agent forwarding. */
|
/* Name and directory of socket for authentication agent forwarding. */
|
||||||
@ -61,15 +67,19 @@ char *x11_saved_proto = NULL;
|
|||||||
char *x11_saved_data = NULL;
|
char *x11_saved_data = NULL;
|
||||||
unsigned int x11_saved_data_len = 0;
|
unsigned int x11_saved_data_len = 0;
|
||||||
|
|
||||||
/* Fake X11 authentication data. This is what the server will be sending
|
/*
|
||||||
us; we should replace any occurrences of this by the real data. */
|
* Fake X11 authentication data. This is what the server will be sending us;
|
||||||
|
* we should replace any occurrences of this by the real data.
|
||||||
|
*/
|
||||||
char *x11_fake_data = NULL;
|
char *x11_fake_data = NULL;
|
||||||
unsigned int x11_fake_data_len;
|
unsigned int x11_fake_data_len;
|
||||||
|
|
||||||
/* Data structure for storing which hosts are permitted for forward requests.
|
/*
|
||||||
The local sides of any remote forwards are stored in this array to prevent
|
* Data structure for storing which hosts are permitted for forward requests.
|
||||||
a corrupt remote server from accessing arbitrary TCP/IP ports on our
|
* The local sides of any remote forwards are stored in this array to prevent
|
||||||
local network (which might be behind a firewall). */
|
* a corrupt remote server from accessing arbitrary TCP/IP ports on our local
|
||||||
|
* network (which might be behind a firewall).
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *host; /* Host name. */
|
char *host; /* Host name. */
|
||||||
int port; /* Port number. */
|
int port; /* Port number. */
|
||||||
@ -79,9 +89,11 @@ typedef struct {
|
|||||||
static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
|
static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||||
/* Number of permitted host/port pairs in the array. */
|
/* Number of permitted host/port pairs in the array. */
|
||||||
static int num_permitted_opens = 0;
|
static int num_permitted_opens = 0;
|
||||||
/* If this is true, all opens are permitted. This is the case on the
|
/*
|
||||||
server on which we have to trust the client anyway, and the user could
|
* If this is true, all opens are permitted. This is the case on the server
|
||||||
do anything after logging in anyway. */
|
* on which we have to trust the client anyway, and the user could do
|
||||||
|
* anything after logging in anyway.
|
||||||
|
*/
|
||||||
static int all_opens_permitted = 0;
|
static int all_opens_permitted = 0;
|
||||||
|
|
||||||
/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */
|
/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */
|
||||||
@ -95,9 +107,11 @@ channel_set_options(int hostname_in_open)
|
|||||||
have_hostname_in_open = hostname_in_open;
|
have_hostname_in_open = hostname_in_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
|
/*
|
||||||
called by the server, because the user could connect to any port anyway,
|
* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
|
||||||
and the server has no way to know but to trust the client anyway. */
|
* called by the server, because the user could connect to any port anyway,
|
||||||
|
* and the server has no way to know but to trust the client anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_permit_all_opens()
|
channel_permit_all_opens()
|
||||||
@ -105,8 +119,10 @@ channel_permit_all_opens()
|
|||||||
all_opens_permitted = 1;
|
all_opens_permitted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a new channel object and set its type and socket.
|
/*
|
||||||
This will cause remote_name to be freed. */
|
* Allocate a new channel object and set its type and socket. This will cause
|
||||||
|
* remote_name to be freed.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
channel_allocate(int type, int sock, char *remote_name)
|
channel_allocate(int type, int sock, char *remote_name)
|
||||||
@ -117,6 +133,7 @@ channel_allocate(int type, int sock, char *remote_name)
|
|||||||
/* Update the maximum file descriptor value. */
|
/* Update the maximum file descriptor value. */
|
||||||
if (sock > channel_max_fd_value)
|
if (sock > channel_max_fd_value)
|
||||||
channel_max_fd_value = sock;
|
channel_max_fd_value = sock;
|
||||||
|
/* XXX set close-on-exec -markus */
|
||||||
|
|
||||||
/* Do initial allocation if this is the first call. */
|
/* Do initial allocation if this is the first call. */
|
||||||
if (channels_alloc == 0) {
|
if (channels_alloc == 0) {
|
||||||
@ -124,9 +141,10 @@ channel_allocate(int type, int sock, char *remote_name)
|
|||||||
channels = xmalloc(channels_alloc * sizeof(Channel));
|
channels = xmalloc(channels_alloc * sizeof(Channel));
|
||||||
for (i = 0; i < channels_alloc; i++)
|
for (i = 0; i < channels_alloc; i++)
|
||||||
channels[i].type = SSH_CHANNEL_FREE;
|
channels[i].type = SSH_CHANNEL_FREE;
|
||||||
|
/*
|
||||||
/* Kludge: arrange a call to channel_stop_listening if we
|
* Kludge: arrange a call to channel_stop_listening if we
|
||||||
terminate with fatal(). */
|
* terminate with fatal().
|
||||||
|
*/
|
||||||
fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
|
fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
|
||||||
}
|
}
|
||||||
/* Try to find a free slot where to put the new channel. */
|
/* Try to find a free slot where to put the new channel. */
|
||||||
@ -137,8 +155,7 @@ channel_allocate(int type, int sock, char *remote_name)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (found == -1) {
|
if (found == -1) {
|
||||||
/* There are no free slots. Take last+1 slot and expand
|
/* There are no free slots. Take last+1 slot and expand the array. */
|
||||||
the array. */
|
|
||||||
found = channels_alloc;
|
found = channels_alloc;
|
||||||
channels_alloc += 10;
|
channels_alloc += 10;
|
||||||
debug("channel: expanding %d", channels_alloc);
|
debug("channel: expanding %d", channels_alloc);
|
||||||
@ -181,8 +198,10 @@ channel_free(int channel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called just before select() to add any bits relevant to
|
/*
|
||||||
channels in the select bitmasks. */
|
* This is called just before select() to add any bits relevant to channels
|
||||||
|
* in the select bitmasks.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_prepare_select(fd_set * readset, fd_set * writeset)
|
channel_prepare_select(fd_set * readset, fd_set * writeset)
|
||||||
@ -248,15 +267,16 @@ redo:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_CHANNEL_X11_OPEN:
|
case SSH_CHANNEL_X11_OPEN:
|
||||||
/* This is a special state for X11 authentication
|
/*
|
||||||
spoofing. An opened X11 connection (when
|
* This is a special state for X11 authentication
|
||||||
authentication spoofing is being done) remains
|
* spoofing. An opened X11 connection (when
|
||||||
in this state until the first packet has been
|
* authentication spoofing is being done) remains in
|
||||||
completely read. The authentication data in
|
* this state until the first packet has been
|
||||||
that packet is then substituted by the real
|
* completely read. The authentication data in that
|
||||||
data if it matches the fake data, and the
|
* packet is then substituted by the real data if it
|
||||||
channel is put into normal mode. */
|
* matches the fake data, and the channel is put into
|
||||||
|
* normal mode.
|
||||||
|
*/
|
||||||
/* Check if the fixed size part of the packet is in buffer. */
|
/* Check if the fixed size part of the packet is in buffer. */
|
||||||
if (buffer_len(&ch->output) < 12)
|
if (buffer_len(&ch->output) < 12)
|
||||||
break;
|
break;
|
||||||
@ -303,9 +323,11 @@ redo:
|
|||||||
ch->type = SSH_CHANNEL_OPEN;
|
ch->type = SSH_CHANNEL_OPEN;
|
||||||
goto reject;
|
goto reject;
|
||||||
}
|
}
|
||||||
/* Received authentication protocol and data match
|
/*
|
||||||
our fake data. Substitute the fake data with
|
* Received authentication protocol and data match
|
||||||
real data. */
|
* our fake data. Substitute the fake data with real
|
||||||
|
* data.
|
||||||
|
*/
|
||||||
memcpy(ucp + 12 + ((proto_len + 3) & ~3),
|
memcpy(ucp + 12 + ((proto_len + 3) & ~3),
|
||||||
x11_saved_data, x11_saved_data_len);
|
x11_saved_data, x11_saved_data_len);
|
||||||
|
|
||||||
@ -314,8 +336,10 @@ redo:
|
|||||||
goto redo;
|
goto redo;
|
||||||
|
|
||||||
reject:
|
reject:
|
||||||
/* We have received an X11 connection that has bad
|
/*
|
||||||
authentication information. */
|
* We have received an X11 connection that has bad
|
||||||
|
* authentication information.
|
||||||
|
*/
|
||||||
log("X11 connection rejected because of wrong authentication.\r\n");
|
log("X11 connection rejected because of wrong authentication.\r\n");
|
||||||
buffer_clear(&ch->input);
|
buffer_clear(&ch->input);
|
||||||
buffer_clear(&ch->output);
|
buffer_clear(&ch->output);
|
||||||
@ -341,8 +365,10 @@ redo:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After select, perform any appropriate operations for channels which
|
/*
|
||||||
have events pending. */
|
* After select, perform any appropriate operations for channels which have
|
||||||
|
* events pending.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_after_select(fd_set * readset, fd_set * writeset)
|
channel_after_select(fd_set * readset, fd_set * writeset)
|
||||||
@ -381,8 +407,10 @@ channel_after_select(fd_set * readset, fd_set * writeset)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_CHANNEL_PORT_LISTENER:
|
case SSH_CHANNEL_PORT_LISTENER:
|
||||||
/* This socket is listening for connections to a
|
/*
|
||||||
forwarded TCP/IP port. */
|
* This socket is listening for connections to a
|
||||||
|
* forwarded TCP/IP port.
|
||||||
|
*/
|
||||||
if (FD_ISSET(ch->sock, readset)) {
|
if (FD_ISSET(ch->sock, readset)) {
|
||||||
debug("Connection to port %d forwarding to %.100s:%d requested.",
|
debug("Connection to port %d forwarding to %.100s:%d requested.",
|
||||||
ch->listening_port, ch->path, ch->host_port);
|
ch->listening_port, ch->path, ch->host_port);
|
||||||
@ -410,8 +438,10 @@ channel_after_select(fd_set * readset, fd_set * writeset)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_CHANNEL_AUTH_SOCKET:
|
case SSH_CHANNEL_AUTH_SOCKET:
|
||||||
/* This is the authentication agent socket
|
/*
|
||||||
listening for connections from clients. */
|
* This is the authentication agent socket listening
|
||||||
|
* for connections from clients.
|
||||||
|
*/
|
||||||
if (FD_ISSET(ch->sock, readset)) {
|
if (FD_ISSET(ch->sock, readset)) {
|
||||||
int nchan;
|
int nchan;
|
||||||
len = sizeof(addr);
|
len = sizeof(addr);
|
||||||
@ -429,13 +459,16 @@ channel_after_select(fd_set * readset, fd_set * writeset)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_CHANNEL_OPEN:
|
case SSH_CHANNEL_OPEN:
|
||||||
/* This is an open two-way communication channel.
|
/*
|
||||||
It is not of interest to us at this point what
|
* This is an open two-way communication channel. It
|
||||||
kind of data is being transmitted. */
|
* is not of interest to us at this point what kind
|
||||||
|
* of data is being transmitted.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Read available incoming data and append it to
|
/*
|
||||||
buffer; shutdown socket, if read or write
|
* Read available incoming data and append it to
|
||||||
failes */
|
* buffer; shutdown socket, if read or write failes
|
||||||
|
*/
|
||||||
if (FD_ISSET(ch->sock, readset)) {
|
if (FD_ISSET(ch->sock, readset)) {
|
||||||
len = read(ch->sock, buf, sizeof(buf));
|
len = read(ch->sock, buf, sizeof(buf));
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
@ -500,8 +533,7 @@ channel_output_poll()
|
|||||||
|
|
||||||
for (i = 0; i < channels_alloc; i++) {
|
for (i = 0; i < channels_alloc; i++) {
|
||||||
ch = &channels[i];
|
ch = &channels[i];
|
||||||
/* We are only interested in channels that can have
|
/* We are only interested in channels that can have buffered incoming data. */
|
||||||
buffered incoming data. */
|
|
||||||
if (ch->type != SSH_CHANNEL_OPEN &&
|
if (ch->type != SSH_CHANNEL_OPEN &&
|
||||||
ch->type != SSH_CHANNEL_INPUT_DRAINING)
|
ch->type != SSH_CHANNEL_INPUT_DRAINING)
|
||||||
continue;
|
continue;
|
||||||
@ -509,8 +541,7 @@ channel_output_poll()
|
|||||||
/* Get the amount of buffered data for this channel. */
|
/* Get the amount of buffered data for this channel. */
|
||||||
len = buffer_len(&ch->input);
|
len = buffer_len(&ch->input);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
/* Send some data for the other side over the
|
/* Send some data for the other side over the secure connection. */
|
||||||
secure connection. */
|
|
||||||
if (packet_is_interactive()) {
|
if (packet_is_interactive()) {
|
||||||
if (len > 1024)
|
if (len > 1024)
|
||||||
len = 512;
|
len = 512;
|
||||||
@ -527,17 +558,20 @@ channel_output_poll()
|
|||||||
} else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
|
} else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
|
||||||
if (compat13)
|
if (compat13)
|
||||||
fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
|
fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
|
||||||
/* input-buffer is empty and read-socket shutdown:
|
/*
|
||||||
tell peer, that we will not send more data:
|
* input-buffer is empty and read-socket shutdown:
|
||||||
send IEOF */
|
* tell peer, that we will not send more data: send IEOF
|
||||||
|
*/
|
||||||
chan_ibuf_empty(ch);
|
chan_ibuf_empty(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called when a packet of type CHANNEL_DATA has just been received.
|
/*
|
||||||
The message type has already been consumed, but channel number and data
|
* This is called when a packet of type CHANNEL_DATA has just been received.
|
||||||
is still there. */
|
* The message type has already been consumed, but channel number and data is
|
||||||
|
* still there.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_input_data(int payload_len)
|
channel_input_data(int payload_len)
|
||||||
@ -564,8 +598,10 @@ channel_input_data(int payload_len)
|
|||||||
xfree(data);
|
xfree(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if no channel has too much buffered data, and false if
|
/*
|
||||||
one or more channel is overfull. */
|
* Returns true if no channel has too much buffered data, and false if one or
|
||||||
|
* more channel is overfull.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
channel_not_very_much_buffered_data()
|
channel_not_very_much_buffered_data()
|
||||||
@ -615,20 +651,27 @@ channel_input_close()
|
|||||||
chan_rcvd_ieof(&channels[channel]);
|
chan_rcvd_ieof(&channels[channel]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Send a confirmation that we have closed the channel and no more
|
|
||||||
data is coming for it. */
|
/*
|
||||||
|
* Send a confirmation that we have closed the channel and no more
|
||||||
|
* data is coming for it.
|
||||||
|
*/
|
||||||
packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
|
packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
|
||||||
packet_put_int(channels[channel].remote_id);
|
packet_put_int(channels[channel].remote_id);
|
||||||
packet_send();
|
packet_send();
|
||||||
|
|
||||||
/* If the channel is in closed state, we have sent a close
|
/*
|
||||||
request, and the other side will eventually respond with a
|
* If the channel is in closed state, we have sent a close request,
|
||||||
confirmation. Thus, we cannot free the channel here, because
|
* and the other side will eventually respond with a confirmation.
|
||||||
then there would be no-one to receive the confirmation. The
|
* Thus, we cannot free the channel here, because then there would be
|
||||||
channel gets freed when the confirmation arrives. */
|
* no-one to receive the confirmation. The channel gets freed when
|
||||||
|
* the confirmation arrives.
|
||||||
|
*/
|
||||||
if (channels[channel].type != SSH_CHANNEL_CLOSED) {
|
if (channels[channel].type != SSH_CHANNEL_CLOSED) {
|
||||||
/* Not a closed channel - mark it as draining, which will
|
/*
|
||||||
cause it to be freed later. */
|
* Not a closed channel - mark it as draining, which will
|
||||||
|
* cause it to be freed later.
|
||||||
|
*/
|
||||||
buffer_consume(&channels[channel].input,
|
buffer_consume(&channels[channel].input,
|
||||||
buffer_len(&channels[channel].input));
|
buffer_len(&channels[channel].input));
|
||||||
channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
|
channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
|
||||||
@ -678,8 +721,7 @@ channel_input_open_confirmation()
|
|||||||
/* Get remote side's id for this channel. */
|
/* Get remote side's id for this channel. */
|
||||||
remote_channel = packet_get_int();
|
remote_channel = packet_get_int();
|
||||||
|
|
||||||
/* Record the remote channel number and mark that the channel is
|
/* Record the remote channel number and mark that the channel is now open. */
|
||||||
now open. */
|
|
||||||
channels[channel].remote_id = remote_channel;
|
channels[channel].remote_id = remote_channel;
|
||||||
channels[channel].type = SSH_CHANNEL_OPEN;
|
channels[channel].type = SSH_CHANNEL_OPEN;
|
||||||
}
|
}
|
||||||
@ -702,8 +744,10 @@ channel_input_open_failure()
|
|||||||
channel_free(channel);
|
channel_free(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stops listening for channels, and removes any unix domain sockets that
|
/*
|
||||||
we might have. */
|
* Stops listening for channels, and removes any unix domain sockets that we
|
||||||
|
* might have.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_stop_listening()
|
channel_stop_listening()
|
||||||
@ -727,8 +771,10 @@ channel_stop_listening()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Closes the sockets of all channels. This is used to close extra file
|
/*
|
||||||
descriptors after a fork. */
|
* Closes the sockets of all channels. This is used to close extra file
|
||||||
|
* descriptors after a fork.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_close_all()
|
channel_close_all()
|
||||||
@ -778,9 +824,11 @@ channel_still_open()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a message describing the currently open forwarded
|
/*
|
||||||
connections, suitable for sending to the client. The message
|
* Returns a message describing the currently open forwarded connections,
|
||||||
contains crlf pairs for newlines. */
|
* suitable for sending to the client. The message contains crlf pairs for
|
||||||
|
* newlines.
|
||||||
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
channel_open_message()
|
channel_open_message()
|
||||||
@ -822,16 +870,19 @@ channel_open_message()
|
|||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initiate forwarding of connections to local port "port" through the secure
|
/*
|
||||||
channel to host:port from remote side. */
|
* Initiate forwarding of connections to local port "port" through the secure
|
||||||
|
* channel to host:port from remote side.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_request_local_forwarding(int port, const char *host,
|
channel_request_local_forwarding(int port, const char *host,
|
||||||
int host_port)
|
int host_port)
|
||||||
{
|
{
|
||||||
int ch, sock;
|
int ch, sock, on = 1;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
extern Options options;
|
extern Options options;
|
||||||
|
struct linger linger;
|
||||||
|
|
||||||
if (strlen(host) > sizeof(channels[0].path) - 1)
|
if (strlen(host) > sizeof(channels[0].path) - 1)
|
||||||
packet_disconnect("Forward host name too long.");
|
packet_disconnect("Forward host name too long.");
|
||||||
@ -850,6 +901,15 @@ channel_request_local_forwarding(int port, const char *host,
|
|||||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
sin.sin_port = htons(port);
|
sin.sin_port = htons(port);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set socket options. We would like the socket to disappear as soon
|
||||||
|
* as it has been closed for whatever reason.
|
||||||
|
*/
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
|
||||||
|
linger.l_onoff = 1;
|
||||||
|
linger.l_linger = 5;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
|
||||||
|
|
||||||
/* Bind the socket to the address. */
|
/* Bind the socket to the address. */
|
||||||
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
|
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
|
||||||
packet_disconnect("bind: %.100s", strerror(errno));
|
packet_disconnect("bind: %.100s", strerror(errno));
|
||||||
@ -866,8 +926,10 @@ channel_request_local_forwarding(int port, const char *host,
|
|||||||
channels[ch].listening_port = port;
|
channels[ch].listening_port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initiate forwarding of connections to port "port" on remote host through
|
/*
|
||||||
the secure channel to host:port from local side. */
|
* Initiate forwarding of connections to port "port" on remote host through
|
||||||
|
* the secure channel to host:port from local side.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_request_remote_forwarding(int port, const char *host,
|
channel_request_remote_forwarding(int port, const char *host,
|
||||||
@ -890,15 +952,18 @@ channel_request_remote_forwarding(int port, const char *host,
|
|||||||
packet_send();
|
packet_send();
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
|
|
||||||
/* Wait for response from the remote side. It will send a
|
/*
|
||||||
disconnect message on failure, and we will never see it here. */
|
* Wait for response from the remote side. It will send a disconnect
|
||||||
|
* message on failure, and we will never see it here.
|
||||||
|
*/
|
||||||
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
|
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
/*
|
||||||
listening for the port, and sends back a success reply (or disconnect
|
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
||||||
message if there was an error). This never returns if there was an
|
* listening for the port, and sends back a success reply (or disconnect
|
||||||
error. */
|
* message if there was an error). This never returns if there was an error.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_input_port_forward_request(int is_root)
|
channel_input_port_forward_request(int is_root)
|
||||||
@ -915,8 +980,10 @@ channel_input_port_forward_request(int is_root)
|
|||||||
if ((port & 0xffff) != port)
|
if ((port & 0xffff) != port)
|
||||||
packet_disconnect("Requested forwarding of nonexistent port %d.", port);
|
packet_disconnect("Requested forwarding of nonexistent port %d.", port);
|
||||||
|
|
||||||
/* Check that an unprivileged user is not trying to forward a
|
/*
|
||||||
privileged port. */
|
* Check that an unprivileged user is not trying to forward a
|
||||||
|
* privileged port.
|
||||||
|
*/
|
||||||
if (port < IPPORT_RESERVED && !is_root)
|
if (port < IPPORT_RESERVED && !is_root)
|
||||||
packet_disconnect("Requested forwarding of port %d but user is not root.",
|
packet_disconnect("Requested forwarding of port %d but user is not root.",
|
||||||
port);
|
port);
|
||||||
@ -928,9 +995,11 @@ channel_input_port_forward_request(int is_root)
|
|||||||
xfree(hostname);
|
xfree(hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called after receiving PORT_OPEN message. This attempts to connect
|
/*
|
||||||
to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or
|
* This is called after receiving PORT_OPEN message. This attempts to
|
||||||
CHANNEL_OPEN_FAILURE. */
|
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
|
||||||
|
* or CHANNEL_OPEN_FAILURE.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_input_port_open(int payload_len)
|
channel_input_port_open(int payload_len)
|
||||||
@ -951,13 +1020,16 @@ channel_input_port_open(int payload_len)
|
|||||||
host_port = packet_get_int();
|
host_port = packet_get_int();
|
||||||
|
|
||||||
/* Get remote originator name. */
|
/* Get remote originator name. */
|
||||||
if (have_hostname_in_open)
|
if (have_hostname_in_open) {
|
||||||
originator_string = packet_get_string(&originator_len);
|
originator_string = packet_get_string(&originator_len);
|
||||||
else
|
originator_len += 4; /* size of packet_int */
|
||||||
|
} else {
|
||||||
originator_string = xstrdup("unknown (remote did not supply name)");
|
originator_string = xstrdup("unknown (remote did not supply name)");
|
||||||
|
originator_len = 0; /* no originator supplied */
|
||||||
|
}
|
||||||
|
|
||||||
packet_integrity_check(payload_len,
|
packet_integrity_check(payload_len,
|
||||||
4 + 4 + host_len + 4 + 4 + originator_len,
|
4 + 4 + host_len + 4 + originator_len,
|
||||||
SSH_MSG_PORT_OPEN);
|
SSH_MSG_PORT_OPEN);
|
||||||
|
|
||||||
/* Check if opening that port is permitted. */
|
/* Check if opening that port is permitted. */
|
||||||
@ -1040,9 +1112,11 @@ fail:
|
|||||||
packet_send();
|
packet_send();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates an internet domain socket for listening for X11 connections.
|
/*
|
||||||
Returns a suitable value for the DISPLAY variable, or NULL if an error
|
* Creates an internet domain socket for listening for X11 connections.
|
||||||
occurs. */
|
* Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||||
|
* occurs.
|
||||||
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
x11_create_display_inet(int screen_number)
|
x11_create_display_inet(int screen_number)
|
||||||
@ -1134,9 +1208,11 @@ connect_local_xsocket(unsigned dnr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
|
/*
|
||||||
the remote channel number. We should do whatever we want, and respond
|
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
|
||||||
with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
|
* the remote channel number. We should do whatever we want, and respond
|
||||||
|
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
x11_input_open(int payload_len)
|
x11_input_open(int payload_len)
|
||||||
@ -1152,13 +1228,16 @@ x11_input_open(int payload_len)
|
|||||||
remote_channel = packet_get_int();
|
remote_channel = packet_get_int();
|
||||||
|
|
||||||
/* Get remote originator name. */
|
/* Get remote originator name. */
|
||||||
if (have_hostname_in_open)
|
if (have_hostname_in_open) {
|
||||||
remote_host = packet_get_string(&remote_len);
|
remote_host = packet_get_string(&remote_len);
|
||||||
else
|
remote_len += 4;
|
||||||
|
} else {
|
||||||
remote_host = xstrdup("unknown (remote did not supply name)");
|
remote_host = xstrdup("unknown (remote did not supply name)");
|
||||||
|
remote_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
debug("Received X11 open request.");
|
debug("Received X11 open request.");
|
||||||
packet_integrity_check(payload_len, 4 + 4 + remote_len, SSH_SMSG_X11_OPEN);
|
packet_integrity_check(payload_len, 4 + remote_len, SSH_SMSG_X11_OPEN);
|
||||||
|
|
||||||
/* Try to open a socket for the local X server. */
|
/* Try to open a socket for the local X server. */
|
||||||
display = getenv("DISPLAY");
|
display = getenv("DISPLAY");
|
||||||
@ -1166,11 +1245,15 @@ x11_input_open(int payload_len)
|
|||||||
error("DISPLAY not set.");
|
error("DISPLAY not set.");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/* Now we decode the value of the DISPLAY variable and make a
|
/*
|
||||||
connection to the real X server. */
|
* Now we decode the value of the DISPLAY variable and make a
|
||||||
|
* connection to the real X server.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Check if it is a unix domain socket. Unix domain displays are
|
/*
|
||||||
in one of the following formats: unix:d[.s], :d[.s], ::d[.s] */
|
* Check if it is a unix domain socket. Unix domain displays are in
|
||||||
|
* one of the following formats: unix:d[.s], :d[.s], ::d[.s]
|
||||||
|
*/
|
||||||
if (strncmp(display, "unix:", 5) == 0 ||
|
if (strncmp(display, "unix:", 5) == 0 ||
|
||||||
display[0] == ':') {
|
display[0] == ':') {
|
||||||
/* Connect to the unix domain socket. */
|
/* Connect to the unix domain socket. */
|
||||||
@ -1187,8 +1270,10 @@ x11_input_open(int payload_len)
|
|||||||
/* OK, we now have a connection to the display. */
|
/* OK, we now have a connection to the display. */
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
/* Connect to an inet socket. The DISPLAY value is supposedly
|
/*
|
||||||
hostname:d[.s], where hostname may also be numeric IP address. */
|
* Connect to an inet socket. The DISPLAY value is supposedly
|
||||||
|
* hostname:d[.s], where hostname may also be numeric IP address.
|
||||||
|
*/
|
||||||
strncpy(buf, display, sizeof(buf));
|
strncpy(buf, display, sizeof(buf));
|
||||||
buf[sizeof(buf) - 1] = 0;
|
buf[sizeof(buf) - 1] = 0;
|
||||||
cp = strchr(buf, ':');
|
cp = strchr(buf, ':');
|
||||||
@ -1197,8 +1282,7 @@ x11_input_open(int payload_len)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
*cp = 0;
|
*cp = 0;
|
||||||
/* buf now contains the host name. But first we parse the display
|
/* buf now contains the host name. But first we parse the display number. */
|
||||||
number. */
|
|
||||||
if (sscanf(cp + 1, "%d", &display_number) != 1) {
|
if (sscanf(cp + 1, "%d", &display_number) != 1) {
|
||||||
error("Could not parse display number from DISPLAY: %.100s",
|
error("Could not parse display number from DISPLAY: %.100s",
|
||||||
display);
|
display);
|
||||||
@ -1267,8 +1351,10 @@ fail:
|
|||||||
packet_send();
|
packet_send();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requests forwarding of X11 connections, generates fake authentication
|
/*
|
||||||
data, and enables authentication spoofing. */
|
* Requests forwarding of X11 connections, generates fake authentication
|
||||||
|
* data, and enables authentication spoofing.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
x11_request_forwarding_with_spoofing(const char *proto, const char *data)
|
x11_request_forwarding_with_spoofing(const char *proto, const char *data)
|
||||||
@ -1293,8 +1379,10 @@ x11_request_forwarding_with_spoofing(const char *proto, const char *data)
|
|||||||
/* Save protocol name. */
|
/* Save protocol name. */
|
||||||
x11_saved_proto = xstrdup(proto);
|
x11_saved_proto = xstrdup(proto);
|
||||||
|
|
||||||
/* Extract real authentication data and generate fake data of the
|
/*
|
||||||
same length. */
|
* Extract real authentication data and generate fake data of the
|
||||||
|
* same length.
|
||||||
|
*/
|
||||||
x11_saved_data = xmalloc(data_len);
|
x11_saved_data = xmalloc(data_len);
|
||||||
x11_fake_data = xmalloc(data_len);
|
x11_fake_data = xmalloc(data_len);
|
||||||
for (i = 0; i < data_len; i++) {
|
for (i = 0; i < data_len; i++) {
|
||||||
@ -1334,9 +1422,11 @@ auth_request_forwarding()
|
|||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the name of the forwarded authentication socket. Returns NULL
|
/*
|
||||||
if there is no forwarded authentication socket. The returned value
|
* Returns the name of the forwarded authentication socket. Returns NULL if
|
||||||
points to a static buffer. */
|
* there is no forwarded authentication socket. The returned value points to
|
||||||
|
* a static buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
auth_get_socket_name()
|
auth_get_socket_name()
|
||||||
@ -1353,8 +1443,10 @@ cleanup_socket(void)
|
|||||||
rmdir(channel_forwarded_auth_socket_dir);
|
rmdir(channel_forwarded_auth_socket_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
/*
|
||||||
This starts forwarding authentication requests. */
|
* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
||||||
|
* This starts forwarding authentication requests.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
auth_input_request_forwarding(struct passwd * pw)
|
auth_input_request_forwarding(struct passwd * pw)
|
||||||
@ -1422,14 +1514,18 @@ auth_input_open_request()
|
|||||||
/* Read the remote channel number from the message. */
|
/* Read the remote channel number from the message. */
|
||||||
remch = packet_get_int();
|
remch = packet_get_int();
|
||||||
|
|
||||||
/* Get a connection to the local authentication agent (this may
|
/*
|
||||||
again get forwarded). */
|
* Get a connection to the local authentication agent (this may again
|
||||||
|
* get forwarded).
|
||||||
|
*/
|
||||||
sock = ssh_get_authentication_socket();
|
sock = ssh_get_authentication_socket();
|
||||||
|
|
||||||
/* If we could not connect the agent, send an error message back
|
/*
|
||||||
to the server. This should never happen unless the agent dies,
|
* If we could not connect the agent, send an error message back to
|
||||||
because authentication forwarding is only enabled if we have an
|
* the server. This should never happen unless the agent dies,
|
||||||
agent. */
|
* because authentication forwarding is only enabled if we have an
|
||||||
|
* agent.
|
||||||
|
*/
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
|
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
|
||||||
packet_put_int(remch);
|
packet_put_int(remch);
|
||||||
@ -1438,9 +1534,11 @@ auth_input_open_request()
|
|||||||
}
|
}
|
||||||
debug("Forwarding authentication connection.");
|
debug("Forwarding authentication connection.");
|
||||||
|
|
||||||
/* Dummy host name. This will be freed when the channel is freed;
|
/*
|
||||||
it will still be valid in the packet_put_string below since the
|
* Dummy host name. This will be freed when the channel is freed; it
|
||||||
channel cannot yet be freed at that point. */
|
* will still be valid in the packet_put_string below since the
|
||||||
|
* channel cannot yet be freed at that point.
|
||||||
|
*/
|
||||||
dummyname = xstrdup("authentication agent connection");
|
dummyname = xstrdup("authentication agent connection");
|
||||||
|
|
||||||
newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
|
newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
|
||||||
|
23
channels.h
23
channels.h
@ -1,29 +1,26 @@
|
|||||||
/* RCSID("$Id: channels.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: channels.h,v 1.4 1999/11/25 00:54:58 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef CHANNELS_H
|
#ifndef CHANNELS_H
|
||||||
#define CHANNELS_H
|
#define CHANNELS_H
|
||||||
|
|
||||||
/* Definitions for channel types. */
|
/* Definitions for channel types. */
|
||||||
#define SSH_CHANNEL_FREE 0 /* This channel is free
|
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
|
||||||
* (unused). */
|
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
|
||||||
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11
|
|
||||||
* conn. */
|
|
||||||
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
|
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
|
||||||
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
|
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
|
||||||
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
|
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
|
||||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close
|
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
|
||||||
* confirmation */
|
|
||||||
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
|
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
|
||||||
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
|
#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
|
||||||
/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
|
/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
|
||||||
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
|
#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
|
||||||
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to
|
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
|
||||||
* conn */
|
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */
|
||||||
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to
|
|
||||||
* app */
|
|
||||||
|
|
||||||
/* Data structure for channel data. This is iniailized in channel_allocate
|
/*
|
||||||
and cleared in channel_free. */
|
* Data structure for channel data. This is iniailized in channel_allocate
|
||||||
|
* and cleared in channel_free.
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct Channel {
|
typedef struct Channel {
|
||||||
int type; /* channel type/state */
|
int type; /* channel type/state */
|
||||||
|
43
cipher.c
43
cipher.c
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: cipher.c,v 1.7 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: cipher.c,v 1.8 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
@ -121,8 +121,10 @@ detect_cbc_attack(const unsigned char *src,
|
|||||||
cipher_attack_detected("CRC-32 CBC insertion attack detected");
|
cipher_attack_detected("CRC-32 CBC insertion attack detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Names of all encryption algorithms. These must match the numbers defined
|
/*
|
||||||
int cipher.h. */
|
* Names of all encryption algorithms.
|
||||||
|
* These must match the numbers defined in cipher.h.
|
||||||
|
*/
|
||||||
static char *cipher_names[] =
|
static char *cipher_names[] =
|
||||||
{
|
{
|
||||||
"none",
|
"none",
|
||||||
@ -134,9 +136,11 @@ static char *cipher_names[] =
|
|||||||
"blowfish"
|
"blowfish"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Returns a bit mask indicating which ciphers are supported by this
|
/*
|
||||||
implementation. The bit mask has the corresponding bit set of each
|
* Returns a bit mask indicating which ciphers are supported by this
|
||||||
supported cipher. */
|
* implementation. The bit mask has the corresponding bit set of each
|
||||||
|
* supported cipher.
|
||||||
|
*/
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
cipher_mask()
|
cipher_mask()
|
||||||
@ -158,8 +162,10 @@ cipher_name(int cipher)
|
|||||||
return cipher_names[cipher];
|
return cipher_names[cipher];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parses the name of the cipher. Returns the number of the corresponding
|
/*
|
||||||
cipher, or -1 on error. */
|
* Parses the name of the cipher. Returns the number of the corresponding
|
||||||
|
* cipher, or -1 on error.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
cipher_number(const char *name)
|
cipher_number(const char *name)
|
||||||
@ -172,8 +178,10 @@ cipher_number(const char *name)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Selects the cipher, and keys if by computing the MD5 checksum of the
|
/*
|
||||||
passphrase and using the resulting 16 bytes as the key. */
|
* Selects the cipher, and keys if by computing the MD5 checksum of the
|
||||||
|
* passphrase and using the resulting 16 bytes as the key.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
cipher_set_key_string(CipherContext *context, int cipher,
|
cipher_set_key_string(CipherContext *context, int cipher,
|
||||||
@ -211,15 +219,18 @@ cipher_set_key(CipherContext *context, int cipher,
|
|||||||
/* Initialize the initialization vector. */
|
/* Initialize the initialization vector. */
|
||||||
switch (cipher) {
|
switch (cipher) {
|
||||||
case SSH_CIPHER_NONE:
|
case SSH_CIPHER_NONE:
|
||||||
/* Has to stay for authfile saving of private key with
|
/*
|
||||||
no passphrase */
|
* Has to stay for authfile saving of private key with no
|
||||||
|
* passphrase
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_CIPHER_3DES:
|
case SSH_CIPHER_3DES:
|
||||||
/* Note: the least significant bit of each byte of key is
|
/*
|
||||||
parity, and must be ignored by the implementation. 16
|
* Note: the least significant bit of each byte of key is
|
||||||
bytes of key are used (first and last keys are the
|
* parity, and must be ignored by the implementation. 16
|
||||||
same). */
|
* bytes of key are used (first and last keys are the same).
|
||||||
|
*/
|
||||||
if (keylen < 16)
|
if (keylen < 16)
|
||||||
error("Key length %d is insufficient for 3DES.", keylen);
|
error("Key length %d is insufficient for 3DES.", keylen);
|
||||||
des_set_key((void *) padded, context->u.des3.key1);
|
des_set_key((void *) padded, context->u.des3.key1);
|
||||||
|
36
cipher.h
36
cipher.h
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: cipher.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: cipher.h,v 1.5 1999/11/25 00:54:58 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef CIPHER_H
|
#ifndef CIPHER_H
|
||||||
#define CIPHER_H
|
#define CIPHER_H
|
||||||
@ -54,26 +54,34 @@ typedef struct {
|
|||||||
} bf;
|
} bf;
|
||||||
} u;
|
} u;
|
||||||
} CipherContext;
|
} CipherContext;
|
||||||
/* Returns a bit mask indicating which ciphers are supported by this
|
/*
|
||||||
implementation. The bit mask has the corresponding bit set of each
|
* Returns a bit mask indicating which ciphers are supported by this
|
||||||
supported cipher. */
|
* implementation. The bit mask has the corresponding bit set of each
|
||||||
|
* supported cipher.
|
||||||
|
*/
|
||||||
unsigned int cipher_mask();
|
unsigned int cipher_mask();
|
||||||
|
|
||||||
/* Returns the name of the cipher. */
|
/* Returns the name of the cipher. */
|
||||||
const char *cipher_name(int cipher);
|
const char *cipher_name(int cipher);
|
||||||
|
|
||||||
/* Parses the name of the cipher. Returns the number of the corresponding
|
/*
|
||||||
cipher, or -1 on error. */
|
* Parses the name of the cipher. Returns the number of the corresponding
|
||||||
|
* cipher, or -1 on error.
|
||||||
|
*/
|
||||||
int cipher_number(const char *name);
|
int cipher_number(const char *name);
|
||||||
|
|
||||||
/* Selects the cipher to use and sets the key. If for_encryption is true,
|
/*
|
||||||
the key is setup for encryption; otherwise it is setup for decryption. */
|
* Selects the cipher to use and sets the key. If for_encryption is true,
|
||||||
|
* the key is setup for encryption; otherwise it is setup for decryption.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
cipher_set_key(CipherContext * context, int cipher,
|
cipher_set_key(CipherContext * context, int cipher,
|
||||||
const unsigned char *key, int keylen, int for_encryption);
|
const unsigned char *key, int keylen, int for_encryption);
|
||||||
|
|
||||||
/* Sets key for the cipher by computing the MD5 checksum of the passphrase,
|
/*
|
||||||
and using the resulting 16 bytes as the key. */
|
* Sets key for the cipher by computing the MD5 checksum of the passphrase,
|
||||||
|
* and using the resulting 16 bytes as the key.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
cipher_set_key_string(CipherContext * context, int cipher,
|
cipher_set_key_string(CipherContext * context, int cipher,
|
||||||
const char *passphrase, int for_encryption);
|
const char *passphrase, int for_encryption);
|
||||||
@ -88,8 +96,10 @@ void
|
|||||||
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
||||||
const unsigned char *src, unsigned int len);
|
const unsigned char *src, unsigned int len);
|
||||||
|
|
||||||
/* If and CRC-32 attack is detected this function is called. Defaults
|
/*
|
||||||
* to fatal, changed to packet_disconnect in sshd and ssh. */
|
* If and CRC-32 attack is detected this function is called. Defaults to
|
||||||
extern void (*cipher_attack_detected) (const char *fmt,...);
|
* fatal, changed to packet_disconnect in sshd and ssh.
|
||||||
|
*/
|
||||||
|
extern void (*cipher_attack_detected) (const char *fmt, ...);
|
||||||
|
|
||||||
#endif /* CIPHER_H */
|
#endif /* CIPHER_H */
|
||||||
|
317
clientloop.c
317
clientloop.c
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: clientloop.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: clientloop.c,v 1.6 1999/11/25 00:54:58 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -27,22 +27,28 @@ RCSID("$Id: clientloop.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
|||||||
/* Flag indicating that stdin should be redirected from /dev/null. */
|
/* Flag indicating that stdin should be redirected from /dev/null. */
|
||||||
extern int stdin_null_flag;
|
extern int stdin_null_flag;
|
||||||
|
|
||||||
/* Name of the host we are connecting to. This is the name given on the
|
/*
|
||||||
command line, or the HostName specified for the user-supplied name
|
* Name of the host we are connecting to. This is the name given on the
|
||||||
in a configuration file. */
|
* command line, or the HostName specified for the user-supplied name in a
|
||||||
|
* configuration file.
|
||||||
|
*/
|
||||||
extern char *host;
|
extern char *host;
|
||||||
|
|
||||||
/* 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
|
* Flag to indicate that we have received a window change signal which has
|
||||||
window size to be sent to the server a little later. This is volatile
|
* not yet been processed. This will cause a message indicating the new
|
||||||
because this is updated in a signal handler. */
|
* window size to be sent to the server a little later. This is volatile
|
||||||
|
* because this is updated in a signal handler.
|
||||||
|
*/
|
||||||
static volatile int received_window_change_signal = 0;
|
static volatile int received_window_change_signal = 0;
|
||||||
|
|
||||||
/* Terminal modes, as saved by enter_raw_mode. */
|
/* Terminal modes, as saved by enter_raw_mode. */
|
||||||
static struct termios saved_tio;
|
static struct termios saved_tio;
|
||||||
|
|
||||||
/* Flag indicating whether we are in raw mode. This is used by enter_raw_mode
|
/*
|
||||||
and leave_raw_mode. */
|
* Flag indicating whether we are in raw mode. This is used by
|
||||||
|
* enter_raw_mode and leave_raw_mode.
|
||||||
|
*/
|
||||||
static int in_raw_mode = 0;
|
static int in_raw_mode = 0;
|
||||||
|
|
||||||
/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
|
/* Flag indicating whether the user\'s terminal is in non-blocking mode. */
|
||||||
@ -64,8 +70,7 @@ static unsigned long stdin_bytes, stdout_bytes, stderr_bytes;
|
|||||||
static int quit_pending; /* Set to non-zero to quit the client loop. */
|
static int quit_pending; /* Set to non-zero to quit the client loop. */
|
||||||
static int escape_char; /* Escape character. */
|
static int escape_char; /* Escape character. */
|
||||||
|
|
||||||
/* Returns the user\'s terminal to normal mode if it had been put in raw
|
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
|
||||||
mode. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
leave_raw_mode()
|
leave_raw_mode()
|
||||||
@ -127,8 +132,10 @@ enter_non_blocking()
|
|||||||
fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
|
fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signal handler for the window change signal (SIGWINCH). This just
|
/*
|
||||||
sets a flag indicating that the window has changed. */
|
* Signal handler for the window change signal (SIGWINCH). This just sets a
|
||||||
|
* flag indicating that the window has changed.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
window_change_handler(int sig)
|
window_change_handler(int sig)
|
||||||
@ -137,8 +144,10 @@ window_change_handler(int sig)
|
|||||||
signal(SIGWINCH, window_change_handler);
|
signal(SIGWINCH, window_change_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signal handler for signals that cause the program to terminate. These
|
/*
|
||||||
signals must be trapped to restore terminal modes. */
|
* Signal handler for signals that cause the program to terminate. These
|
||||||
|
* signals must be trapped to restore terminal modes.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
signal_handler(int sig)
|
signal_handler(int sig)
|
||||||
@ -152,8 +161,10 @@ signal_handler(int sig)
|
|||||||
fatal("Killed by signal %d.", sig);
|
fatal("Killed by signal %d.", sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns current time in seconds from Jan 1, 1970 with the maximum available
|
/*
|
||||||
resolution. */
|
* Returns current time in seconds from Jan 1, 1970 with the maximum
|
||||||
|
* available resolution.
|
||||||
|
*/
|
||||||
|
|
||||||
double
|
double
|
||||||
get_current_time()
|
get_current_time()
|
||||||
@ -163,9 +174,11 @@ get_current_time()
|
|||||||
return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
|
return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called when the interactive is entered. This checks if there
|
/*
|
||||||
is an EOF coming on stdin. We must check this explicitly, as select()
|
* This is called when the interactive is entered. This checks if there is
|
||||||
does not appear to wake up when redirecting from /dev/null. */
|
* an EOF coming on stdin. We must check this explicitly, as select() does
|
||||||
|
* not appear to wake up when redirecting from /dev/null.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
client_check_initial_eof_on_stdin()
|
client_check_initial_eof_on_stdin()
|
||||||
@ -173,13 +186,14 @@ client_check_initial_eof_on_stdin()
|
|||||||
int len;
|
int len;
|
||||||
char buf[1];
|
char buf[1];
|
||||||
|
|
||||||
/* If standard input is to be "redirected from /dev/null", we
|
/*
|
||||||
simply mark that we have seen an EOF and send an EOF message to
|
* If standard input is to be "redirected from /dev/null", we simply
|
||||||
the server. Otherwise, we try to read a single character; it
|
* mark that we have seen an EOF and send an EOF message to the
|
||||||
appears that for some files, such /dev/null, select() never
|
* server. Otherwise, we try to read a single character; it appears
|
||||||
wakes up for read for this descriptor, which means that we
|
* that for some files, such /dev/null, select() never wakes up for
|
||||||
never get EOF. This way we will get the EOF if stdin comes
|
* read for this descriptor, which means that we never get EOF. This
|
||||||
from /dev/null or similar. */
|
* way we will get the EOF if stdin comes from /dev/null or similar.
|
||||||
|
*/
|
||||||
if (stdin_null_flag) {
|
if (stdin_null_flag) {
|
||||||
/* Fake EOF on stdin. */
|
/* Fake EOF on stdin. */
|
||||||
debug("Sending eof.");
|
debug("Sending eof.");
|
||||||
@ -187,22 +201,22 @@ client_check_initial_eof_on_stdin()
|
|||||||
packet_start(SSH_CMSG_EOF);
|
packet_start(SSH_CMSG_EOF);
|
||||||
packet_send();
|
packet_send();
|
||||||
} else {
|
} else {
|
||||||
/* Enter non-blocking mode for stdin. */
|
|
||||||
enter_non_blocking();
|
enter_non_blocking();
|
||||||
|
|
||||||
/* Check for immediate EOF on stdin. */
|
/* Check for immediate EOF on stdin. */
|
||||||
len = read(fileno(stdin), buf, 1);
|
len = read(fileno(stdin), buf, 1);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
/* EOF. Record that we have seen it and send EOF
|
/* EOF. Record that we have seen it and send EOF to server. */
|
||||||
to server. */
|
|
||||||
debug("Sending eof.");
|
debug("Sending eof.");
|
||||||
stdin_eof = 1;
|
stdin_eof = 1;
|
||||||
packet_start(SSH_CMSG_EOF);
|
packet_start(SSH_CMSG_EOF);
|
||||||
packet_send();
|
packet_send();
|
||||||
} else if (len > 0) {
|
} else if (len > 0) {
|
||||||
/* Got data. We must store the data in the
|
/*
|
||||||
buffer, and also process it as an escape
|
* Got data. We must store the data in the buffer,
|
||||||
character if appropriate. */
|
* and also process it as an escape character if
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
if ((unsigned char) buf[0] == escape_char)
|
if ((unsigned char) buf[0] == escape_char)
|
||||||
escape_pending = 1;
|
escape_pending = 1;
|
||||||
else {
|
else {
|
||||||
@ -210,13 +224,14 @@ client_check_initial_eof_on_stdin()
|
|||||||
stdin_bytes += 1;
|
stdin_bytes += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Leave non-blocking mode. */
|
|
||||||
leave_non_blocking();
|
leave_non_blocking();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get packets from the connection input buffer, and process them as long
|
/*
|
||||||
as there are packets available. */
|
* Get packets from the connection input buffer, and process them as long as
|
||||||
|
* there are packets available.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
client_process_buffered_input_packets()
|
client_process_buffered_input_packets()
|
||||||
@ -255,8 +270,10 @@ client_process_buffered_input_packets()
|
|||||||
/* Acknowledge the exit. */
|
/* Acknowledge the exit. */
|
||||||
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
||||||
packet_send();
|
packet_send();
|
||||||
/* Must wait for packet to be sent since we are
|
/*
|
||||||
exiting the loop. */
|
* Must wait for packet to be sent since we are
|
||||||
|
* exiting the loop.
|
||||||
|
*/
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
/* Flag that we want to exit. */
|
/* Flag that we want to exit. */
|
||||||
quit_pending = 1;
|
quit_pending = 1;
|
||||||
@ -300,20 +317,24 @@ client_process_buffered_input_packets()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Any unknown packets received during the actual
|
/*
|
||||||
session cause the session to terminate. This
|
* Any unknown packets received during the actual
|
||||||
is intended to make debugging easier since no
|
* session cause the session to terminate. This is
|
||||||
confirmations are sent. Any compatible
|
* intended to make debugging easier since no
|
||||||
protocol extensions must be negotiated during
|
* confirmations are sent. Any compatible protocol
|
||||||
the preparatory phase. */
|
* extensions must be negotiated during the
|
||||||
|
* preparatory phase.
|
||||||
|
*/
|
||||||
packet_disconnect("Protocol error during session: type %d",
|
packet_disconnect("Protocol error during session: type %d",
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make packets from buffered stdin data, and buffer them for sending to
|
/*
|
||||||
the connection. */
|
* Make packets from buffered stdin data, and buffer them for sending to the
|
||||||
|
* connection.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
client_make_packets_from_stdin_data()
|
client_make_packets_from_stdin_data()
|
||||||
@ -339,10 +360,12 @@ client_make_packets_from_stdin_data()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if the client window has changed, and sends a packet about it to
|
/*
|
||||||
the server if so. The actual change is detected elsewhere (by a software
|
* Checks if the client window has changed, and sends a packet about it to
|
||||||
interrupt on Unix); this just checks the flag and sends a message if
|
* the server if so. The actual change is detected elsewhere (by a software
|
||||||
appropriate. */
|
* interrupt on Unix); this just checks the flag and sends a message if
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
client_check_window_change()
|
client_check_window_change()
|
||||||
@ -367,8 +390,10 @@ client_check_window_change()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Waits until the client can do something (some data becomes available on
|
/*
|
||||||
one of the file descriptors). */
|
* Waits until the client can do something (some data becomes available on
|
||||||
|
* one of the file descriptors).
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
||||||
@ -382,8 +407,10 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
|||||||
channel_not_very_much_buffered_data())
|
channel_not_very_much_buffered_data())
|
||||||
FD_SET(connection_in, readset);
|
FD_SET(connection_in, readset);
|
||||||
|
|
||||||
/* Read from stdin, unless we have seen EOF or have very much
|
/*
|
||||||
buffered data to send to the server. */
|
* Read from stdin, unless we have seen EOF or have very much
|
||||||
|
* buffered data to send to the server.
|
||||||
|
*/
|
||||||
if (!stdin_eof && packet_not_very_much_data_to_write())
|
if (!stdin_eof && packet_not_very_much_data_to_write())
|
||||||
FD_SET(fileno(stdin), readset);
|
FD_SET(fileno(stdin), readset);
|
||||||
|
|
||||||
@ -408,13 +435,14 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
|||||||
if (channel_max_fd() > max_fd)
|
if (channel_max_fd() > max_fd)
|
||||||
max_fd = channel_max_fd();
|
max_fd = channel_max_fd();
|
||||||
|
|
||||||
/* Wait for something to happen. This will suspend the process
|
/*
|
||||||
until some selected descriptor can be read, written, or has
|
* Wait for something to happen. This will suspend the process until
|
||||||
some other event pending.
|
* some selected descriptor can be read, written, or has some other
|
||||||
Note: if you want to implement SSH_MSG_IGNORE messages to fool
|
* event pending. Note: if you want to implement SSH_MSG_IGNORE
|
||||||
traffic analysis, this might be the place to do it:
|
* messages to fool traffic analysis, this might be the place to do
|
||||||
just have a random timeout for the select, and send a random
|
* it: just have a random timeout for the select, and send a random
|
||||||
SSH_MSG_IGNORE packet when the timeout expires. */
|
* SSH_MSG_IGNORE packet when the timeout expires.
|
||||||
|
*/
|
||||||
|
|
||||||
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
|
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
|
||||||
char buf[100];
|
char buf[100];
|
||||||
@ -446,11 +474,12 @@ client_suspend_self()
|
|||||||
buffer_ptr(&stderr_buffer),
|
buffer_ptr(&stderr_buffer),
|
||||||
buffer_len(&stderr_buffer));
|
buffer_len(&stderr_buffer));
|
||||||
|
|
||||||
/* Leave raw mode. */
|
|
||||||
leave_raw_mode();
|
leave_raw_mode();
|
||||||
|
|
||||||
/* Free (and clear) the buffer to reduce the amount of data that
|
/*
|
||||||
gets written to swap. */
|
* Free (and clear) the buffer to reduce the amount of data that gets
|
||||||
|
* written to swap.
|
||||||
|
*/
|
||||||
buffer_free(&stdin_buffer);
|
buffer_free(&stdin_buffer);
|
||||||
buffer_free(&stdout_buffer);
|
buffer_free(&stdout_buffer);
|
||||||
buffer_free(&stderr_buffer);
|
buffer_free(&stderr_buffer);
|
||||||
@ -474,7 +503,6 @@ client_suspend_self()
|
|||||||
buffer_init(&stdout_buffer);
|
buffer_init(&stdout_buffer);
|
||||||
buffer_init(&stderr_buffer);
|
buffer_init(&stderr_buffer);
|
||||||
|
|
||||||
/* Re-enter raw mode. */
|
|
||||||
enter_raw_mode();
|
enter_raw_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,8 +512,10 @@ client_process_input(fd_set * readset)
|
|||||||
int len, pid;
|
int len, pid;
|
||||||
char buf[8192], *s;
|
char buf[8192], *s;
|
||||||
|
|
||||||
/* Read input from the server, and add any such data to the buffer
|
/*
|
||||||
of the packet subsystem. */
|
* Read input from the server, and add any such data to the buffer of
|
||||||
|
* the packet subsystem.
|
||||||
|
*/
|
||||||
if (FD_ISSET(connection_in, readset)) {
|
if (FD_ISSET(connection_in, readset)) {
|
||||||
/* Read as much as possible. */
|
/* Read as much as possible. */
|
||||||
len = read(connection_in, buf, sizeof(buf));
|
len = read(connection_in, buf, sizeof(buf));
|
||||||
@ -498,9 +528,10 @@ client_process_input(fd_set * readset)
|
|||||||
quit_pending = 1;
|
quit_pending = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* There is a kernel bug on Solaris that causes select to
|
/*
|
||||||
sometimes wake up even though there is no data
|
* There is a kernel bug on Solaris that causes select to
|
||||||
available. */
|
* sometimes wake up even though there is no data available.
|
||||||
|
*/
|
||||||
if (len < 0 && errno == EAGAIN)
|
if (len < 0 && errno == EAGAIN)
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
@ -520,9 +551,11 @@ client_process_input(fd_set * readset)
|
|||||||
/* Read as much as possible. */
|
/* Read as much as possible. */
|
||||||
len = read(fileno(stdin), buf, sizeof(buf));
|
len = read(fileno(stdin), buf, sizeof(buf));
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
/* Received EOF or error. They are treated
|
/*
|
||||||
similarly, except that an error message is
|
* Received EOF or error. They are treated
|
||||||
printed if it was an error condition. */
|
* similarly, except that an error message is printed
|
||||||
|
* if it was an error condition.
|
||||||
|
*/
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
|
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
|
||||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||||
@ -530,32 +563,35 @@ client_process_input(fd_set * readset)
|
|||||||
}
|
}
|
||||||
/* Mark that we have seen EOF. */
|
/* Mark that we have seen EOF. */
|
||||||
stdin_eof = 1;
|
stdin_eof = 1;
|
||||||
/* Send an EOF message to the server unless there
|
/*
|
||||||
is data in the buffer. If there is data in the
|
* Send an EOF message to the server unless there is
|
||||||
buffer, no message will be sent now. Code
|
* data in the buffer. If there is data in the
|
||||||
elsewhere will send the EOF when the buffer
|
* buffer, no message will be sent now. Code
|
||||||
becomes empty if stdin_eof is set. */
|
* elsewhere will send the EOF when the buffer
|
||||||
|
* becomes empty if stdin_eof is set.
|
||||||
|
*/
|
||||||
if (buffer_len(&stdin_buffer) == 0) {
|
if (buffer_len(&stdin_buffer) == 0) {
|
||||||
packet_start(SSH_CMSG_EOF);
|
packet_start(SSH_CMSG_EOF);
|
||||||
packet_send();
|
packet_send();
|
||||||
}
|
}
|
||||||
} else if (escape_char == -1) {
|
} else if (escape_char == -1) {
|
||||||
/* Normal successful read, and no escape
|
/*
|
||||||
character. Just append the data to buffer. */
|
* Normal successful read, and no escape character.
|
||||||
|
* Just append the data to buffer.
|
||||||
|
*/
|
||||||
buffer_append(&stdin_buffer, buf, len);
|
buffer_append(&stdin_buffer, buf, len);
|
||||||
stdin_bytes += len;
|
stdin_bytes += len;
|
||||||
} else {
|
} else {
|
||||||
/* Normal, successful read. But we have an escape
|
/*
|
||||||
character and have to process the characters
|
* Normal, successful read. But we have an escape character
|
||||||
one by one. */
|
* and have to process the characters one by one.
|
||||||
|
*/
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
unsigned char ch;
|
unsigned char ch;
|
||||||
/* Get one character at a time. */
|
/* Get one character at a time. */
|
||||||
ch = buf[i];
|
ch = buf[i];
|
||||||
|
|
||||||
/* Check if we have a pending escape
|
|
||||||
character. */
|
|
||||||
if (escape_pending) {
|
if (escape_pending) {
|
||||||
/* We have previously seen an escape character. */
|
/* We have previously seen an escape character. */
|
||||||
/* Clear the flag now. */
|
/* Clear the flag now. */
|
||||||
@ -584,12 +620,16 @@ client_process_input(fd_set * readset)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case '&':
|
case '&':
|
||||||
/* Detach the program (continue to serve connections,
|
/*
|
||||||
but put in background and no more new connections). */
|
* Detach the program (continue to serve connections,
|
||||||
|
* but put in background and no more new connections).
|
||||||
|
*/
|
||||||
if (!stdin_eof) {
|
if (!stdin_eof) {
|
||||||
/* Sending SSH_CMSG_EOF alone does not always appear
|
/*
|
||||||
to be enough. So we try to send an EOF character
|
* Sending SSH_CMSG_EOF alone does not always appear
|
||||||
first. */
|
* to be enough. So we try to send an EOF character
|
||||||
|
* first.
|
||||||
|
*/
|
||||||
packet_start(SSH_CMSG_STDIN_DATA);
|
packet_start(SSH_CMSG_STDIN_DATA);
|
||||||
packet_put_string("\004", 1);
|
packet_put_string("\004", 1);
|
||||||
packet_send();
|
packet_send();
|
||||||
@ -646,22 +686,28 @@ Supported escape sequences:\r\n\
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (ch != escape_char) {
|
if (ch != escape_char) {
|
||||||
/* Escape character followed by non-special character.
|
/*
|
||||||
Append both to the input buffer. */
|
* Escape character followed by non-special character.
|
||||||
|
* Append both to the input buffer.
|
||||||
|
*/
|
||||||
buf[0] = escape_char;
|
buf[0] = escape_char;
|
||||||
buf[1] = ch;
|
buf[1] = ch;
|
||||||
buffer_append(&stdin_buffer, buf, 2);
|
buffer_append(&stdin_buffer, buf, 2);
|
||||||
stdin_bytes += 2;
|
stdin_bytes += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Note that escape character typed twice
|
/*
|
||||||
falls through here; the latter gets processed
|
* Note that escape character typed twice
|
||||||
as a normal character below. */
|
* falls through here; the latter gets processed
|
||||||
|
* as a normal character below.
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* The previous character was not an escape char. Check if this
|
/*
|
||||||
is an escape. */
|
* The previous character was not an escape char. Check if this
|
||||||
|
* is an escape.
|
||||||
|
*/
|
||||||
if (last_was_cr && ch == escape_char) {
|
if (last_was_cr && ch == escape_char) {
|
||||||
/* It is. Set the flag and continue to next character. */
|
/* It is. Set the flag and continue to next character. */
|
||||||
escape_pending = 1;
|
escape_pending = 1;
|
||||||
@ -669,8 +715,10 @@ Supported escape sequences:\r\n\
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Normal character. Record whether it was a newline, and append it to the
|
/*
|
||||||
buffer. */
|
* Normal character. Record whether it was a newline,
|
||||||
|
* and append it to the buffer.
|
||||||
|
*/
|
||||||
last_was_cr = (ch == '\r' || ch == '\n');
|
last_was_cr = (ch == '\r' || ch == '\n');
|
||||||
buf[0] = ch;
|
buf[0] = ch;
|
||||||
buffer_append(&stdin_buffer, buf, 1);
|
buffer_append(&stdin_buffer, buf, 1);
|
||||||
@ -696,8 +744,10 @@ client_process_output(fd_set * writeset)
|
|||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
len = 0;
|
len = 0;
|
||||||
else {
|
else {
|
||||||
/* An error or EOF was encountered. Put
|
/*
|
||||||
an error message to stderr buffer. */
|
* An error or EOF was encountered. Put an
|
||||||
|
* error message to stderr buffer.
|
||||||
|
*/
|
||||||
snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
|
snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
|
||||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||||
stderr_bytes += strlen(buf);
|
stderr_bytes += strlen(buf);
|
||||||
@ -717,8 +767,7 @@ client_process_output(fd_set * writeset)
|
|||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
len = 0;
|
len = 0;
|
||||||
else {
|
else {
|
||||||
/* EOF or error, but can't even print
|
/* EOF or error, but can't even print error message. */
|
||||||
error message. */
|
|
||||||
quit_pending = 1;
|
quit_pending = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -728,11 +777,12 @@ client_process_output(fd_set * writeset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implements the interactive session with the server. This is called
|
/*
|
||||||
after the user has been authenticated, and a command has been
|
* Implements the interactive session with the server. This is called after
|
||||||
started on the remote host. If escape_char != -1, it is the character
|
* the user has been authenticated, and a command has been started on the
|
||||||
used as an escape character for terminating or suspending the
|
* remote host. If escape_char != -1, it is the character used as an escape
|
||||||
session. */
|
* character for terminating or suspending the session.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
client_loop(int have_pty, int escape_char_arg)
|
client_loop(int have_pty, int escape_char_arg)
|
||||||
@ -776,7 +826,6 @@ client_loop(int have_pty, int escape_char_arg)
|
|||||||
if (have_pty)
|
if (have_pty)
|
||||||
signal(SIGWINCH, window_change_handler);
|
signal(SIGWINCH, window_change_handler);
|
||||||
|
|
||||||
/* Enter raw mode if have a pseudo terminal. */
|
|
||||||
if (have_pty)
|
if (have_pty)
|
||||||
enter_raw_mode();
|
enter_raw_mode();
|
||||||
|
|
||||||
@ -787,27 +836,35 @@ client_loop(int have_pty, int escape_char_arg)
|
|||||||
while (!quit_pending) {
|
while (!quit_pending) {
|
||||||
fd_set readset, writeset;
|
fd_set readset, writeset;
|
||||||
|
|
||||||
/* Precess buffered packets sent by the server. */
|
/* Process buffered packets sent by the server. */
|
||||||
client_process_buffered_input_packets();
|
client_process_buffered_input_packets();
|
||||||
|
|
||||||
/* Make packets of buffered stdin data, and buffer them
|
/*
|
||||||
for sending to the server. */
|
* Make packets of buffered stdin data, and buffer them for
|
||||||
|
* sending to the server.
|
||||||
|
*/
|
||||||
client_make_packets_from_stdin_data();
|
client_make_packets_from_stdin_data();
|
||||||
|
|
||||||
/* Make packets from buffered channel data, and buffer
|
/*
|
||||||
them for sending to the server. */
|
* Make packets from buffered channel data, and buffer them
|
||||||
|
* for sending to the server.
|
||||||
|
*/
|
||||||
if (packet_not_very_much_data_to_write())
|
if (packet_not_very_much_data_to_write())
|
||||||
channel_output_poll();
|
channel_output_poll();
|
||||||
|
|
||||||
/* Check if the window size has changed, and buffer a
|
/*
|
||||||
message about it to the server if so. */
|
* Check if the window size has changed, and buffer a message
|
||||||
|
* about it to the server if so.
|
||||||
|
*/
|
||||||
client_check_window_change();
|
client_check_window_change();
|
||||||
|
|
||||||
if (quit_pending)
|
if (quit_pending)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Wait until we have something to do (something becomes
|
/*
|
||||||
available on one of the descriptors). */
|
* Wait until we have something to do (something becomes
|
||||||
|
* available on one of the descriptors).
|
||||||
|
*/
|
||||||
client_wait_until_can_do_something(&readset, &writeset);
|
client_wait_until_can_do_something(&readset, &writeset);
|
||||||
|
|
||||||
if (quit_pending)
|
if (quit_pending)
|
||||||
@ -816,16 +873,19 @@ client_loop(int have_pty, int escape_char_arg)
|
|||||||
/* Do channel operations. */
|
/* Do channel operations. */
|
||||||
channel_after_select(&readset, &writeset);
|
channel_after_select(&readset, &writeset);
|
||||||
|
|
||||||
/* Process input from the connection and from stdin.
|
/*
|
||||||
Buffer any data that is available. */
|
* Process input from the connection and from stdin. Buffer
|
||||||
|
* any data that is available.
|
||||||
|
*/
|
||||||
client_process_input(&readset);
|
client_process_input(&readset);
|
||||||
|
|
||||||
/* Process output to stdout and stderr. Output to the
|
/*
|
||||||
connection is processed elsewhere (above). */
|
* Process output to stdout and stderr. Output to the
|
||||||
|
* connection is processed elsewhere (above).
|
||||||
|
*/
|
||||||
client_process_output(&writeset);
|
client_process_output(&writeset);
|
||||||
|
|
||||||
/* Send as much buffered packet data as possible to the
|
/* Send as much buffered packet data as possible to the sender. */
|
||||||
sender. */
|
|
||||||
if (FD_ISSET(connection_out, &writeset))
|
if (FD_ISSET(connection_out, &writeset))
|
||||||
packet_write_poll();
|
packet_write_poll();
|
||||||
}
|
}
|
||||||
@ -839,8 +899,10 @@ client_loop(int have_pty, int escape_char_arg)
|
|||||||
/* Stop listening for connections. */
|
/* Stop listening for connections. */
|
||||||
channel_stop_listening();
|
channel_stop_listening();
|
||||||
|
|
||||||
/* In interactive mode (with pseudo tty) display a message
|
/*
|
||||||
indicating that the connection has been closed. */
|
* In interactive mode (with pseudo tty) display a message indicating
|
||||||
|
* that the connection has been closed.
|
||||||
|
*/
|
||||||
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
|
if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
|
||||||
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
|
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
|
||||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||||
@ -868,7 +930,6 @@ client_loop(int have_pty, int escape_char_arg)
|
|||||||
buffer_consume(&stderr_buffer, len);
|
buffer_consume(&stderr_buffer, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Leave raw mode. */
|
|
||||||
if (have_pty)
|
if (have_pty)
|
||||||
leave_raw_mode();
|
leave_raw_mode();
|
||||||
|
|
||||||
|
31
compat.c
31
compat.c
@ -1,5 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1999 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.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Markus Friedl.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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"
|
#include "includes.h"
|
||||||
RCSID("$Id: compat.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: compat.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
|
30
compat.h
30
compat.h
@ -1,4 +1,32 @@
|
|||||||
/* RCSID("$Id: compat.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/*
|
||||||
|
* Copyright (c) 1999 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.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Markus Friedl.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/* RCSID("$Id: compat.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef COMPAT_H
|
#ifndef COMPAT_H
|
||||||
#define COMPAT_H
|
#define COMPAT_H
|
||||||
|
46
compress.c
46
compress.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: compress.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: compress.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
@ -23,8 +23,10 @@ RCSID("$Id: compress.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
|||||||
static z_stream incoming_stream;
|
static z_stream incoming_stream;
|
||||||
static z_stream outgoing_stream;
|
static z_stream outgoing_stream;
|
||||||
|
|
||||||
/* Initializes compression; level is compression level from 1 to 9
|
/*
|
||||||
(as in gzip). */
|
* Initializes compression; level is compression level from 1 to 9
|
||||||
|
* (as in gzip).
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
buffer_compress_init(int level)
|
buffer_compress_init(int level)
|
||||||
@ -53,13 +55,14 @@ buffer_compress_uninit()
|
|||||||
deflateEnd(&outgoing_stream);
|
deflateEnd(&outgoing_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compresses the contents of input_buffer into output_buffer. All
|
/*
|
||||||
packets compressed using this function will form a single
|
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||||
compressed data stream; however, data will be flushed at the end of
|
* compressed using this function will form a single compressed data stream;
|
||||||
every call so that each output_buffer can be decompressed
|
* however, data will be flushed at the end of every call so that each
|
||||||
independently (but in the appropriate order since they together
|
* output_buffer can be decompressed independently (but in the appropriate
|
||||||
form a single compression stream) by the receiver. This appends
|
* order since they together form a single compression stream) by the
|
||||||
the compressed data to the output buffer. */
|
* receiver. This appends the compressed data to the output buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
||||||
@ -106,13 +109,14 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
|||||||
while (outgoing_stream.avail_out == 0);
|
while (outgoing_stream.avail_out == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Uncompresses the contents of input_buffer into output_buffer. All
|
/*
|
||||||
packets uncompressed using this function will form a single
|
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||||
compressed data stream; however, data will be flushed at the end of
|
* uncompressed using this function will form a single compressed data
|
||||||
every call so that each output_buffer. This must be called for the
|
* stream; however, data will be flushed at the end of every call so that
|
||||||
same size units that the buffer_compress was called, and in the
|
* each output_buffer. This must be called for the same size units that the
|
||||||
same order that buffers compressed with that. This appends the
|
* buffer_compress was called, and in the same order that buffers compressed
|
||||||
uncompressed data to the output buffer. */
|
* with that. This appends the uncompressed data to the output buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
||||||
@ -145,9 +149,11 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
|||||||
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
|
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
case Z_BUF_ERROR:
|
case Z_BUF_ERROR:
|
||||||
/* Comments in zlib.h say that we should keep
|
/*
|
||||||
calling inflate() until we get an error. This
|
* Comments in zlib.h say that we should keep calling
|
||||||
appears to be the error that we get. */
|
* inflate() until we get an error. This appears to
|
||||||
|
* be the error that we get.
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
case Z_MEM_ERROR:
|
case Z_MEM_ERROR:
|
||||||
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
|
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
|
||||||
|
38
compress.h
38
compress.h
@ -13,34 +13,38 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: compress.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: compress.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef COMPRESS_H
|
#ifndef COMPRESS_H
|
||||||
#define COMPRESS_H
|
#define COMPRESS_H
|
||||||
|
|
||||||
/* Initializes compression; level is compression level from 1 to 9 (as in
|
/*
|
||||||
gzip). */
|
* Initializes compression; level is compression level from 1 to 9 (as in
|
||||||
|
* gzip).
|
||||||
|
*/
|
||||||
void buffer_compress_init(int level);
|
void buffer_compress_init(int level);
|
||||||
|
|
||||||
/* Frees any data structures allocated by buffer_compress_init. */
|
/* Frees any data structures allocated by buffer_compress_init. */
|
||||||
void buffer_compress_uninit();
|
void buffer_compress_uninit();
|
||||||
|
|
||||||
/* Compresses the contents of input_buffer into output_buffer. All
|
/*
|
||||||
packets compressed using this function will form a single
|
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||||
compressed data stream; however, data will be flushed at the end of
|
* compressed using this function will form a single compressed data stream;
|
||||||
every call so that each output_buffer can be decompressed
|
* however, data will be flushed at the end of every call so that each
|
||||||
independently (but in the appropriate order since they together
|
* output_buffer can be decompressed independently (but in the appropriate
|
||||||
form a single compression stream) by the receiver. This appends
|
* order since they together form a single compression stream) by the
|
||||||
the compressed data to the output buffer. */
|
* receiver. This appends the compressed data to the output buffer.
|
||||||
|
*/
|
||||||
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
|
void buffer_compress(Buffer * input_buffer, Buffer * output_buffer);
|
||||||
|
|
||||||
/* Uncompresses the contents of input_buffer into output_buffer. All
|
/*
|
||||||
packets uncompressed using this function will form a single
|
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||||
compressed data stream; however, data will be flushed at the end of
|
* uncompressed using this function will form a single compressed data
|
||||||
every call so that each output_buffer. This must be called for the
|
* stream; however, data will be flushed at the end of every call so that
|
||||||
same size units that the buffer_compress was called, and in the
|
* each output_buffer. This must be called for the same size units that the
|
||||||
same order that buffers compressed with that. This appends the
|
* buffer_compress was called, and in the same order that buffers compressed
|
||||||
uncompressed data to the output buffer. */
|
* with that. This appends the uncompressed data to the output buffer.
|
||||||
|
*/
|
||||||
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
|
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
|
||||||
|
|
||||||
#endif /* COMPRESS_H */
|
#endif /* COMPRESS_H */
|
||||||
|
8
crc32.h
8
crc32.h
@ -13,13 +13,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: crc32.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: crc32.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef CRC32_H
|
#ifndef CRC32_H
|
||||||
#define CRC32_H
|
#define CRC32_H
|
||||||
|
|
||||||
/* This computes a 32 bit CRC of the data in the buffer, and returns the
|
/*
|
||||||
CRC. The polynomial used is 0xedb88320. */
|
* This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
|
||||||
|
* The polynomial used is 0xedb88320.
|
||||||
|
*/
|
||||||
unsigned int crc32(const unsigned char *buf, unsigned int len);
|
unsigned int crc32(const unsigned char *buf, unsigned int len);
|
||||||
|
|
||||||
#endif /* CRC32_H */
|
#endif /* CRC32_H */
|
||||||
|
@ -1,5 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1999 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.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Markus Friedl.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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"
|
#include "includes.h"
|
||||||
RCSID("$Id: fingerprint.c,v 1.3 1999/11/24 00:26:01 deraadt Exp $");
|
RCSID("$Id: fingerprint.c,v 1.4 1999/11/24 16:15:25 markus Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
@ -1,4 +1,32 @@
|
|||||||
/* RCSID("$Id: fingerprint.h,v 1.2 1999/11/24 00:26:02 deraadt Exp $"); */
|
/*
|
||||||
|
* Copyright (c) 1999 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.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Markus Friedl.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/* RCSID("$Id: fingerprint.h,v 1.3 1999/11/24 16:15:25 markus Exp $"); */
|
||||||
|
|
||||||
#ifndef FINGERPRINT_H
|
#ifndef FINGERPRINT_H
|
||||||
#define FINGERPRINT_H
|
#define FINGERPRINT_H
|
||||||
|
117
hostfile.c
117
hostfile.c
@ -14,16 +14,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: hostfile.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: hostfile.c,v 1.6 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
/* Reads a multiple-precision integer in hex from the buffer, and advances the
|
/*
|
||||||
pointer. The integer must already be initialized. This function is
|
* Reads a multiple-precision integer in hex from the buffer, and advances
|
||||||
permitted to modify the buffer. This leaves *cpp to point just beyond
|
* the pointer. The integer must already be initialized. This function is
|
||||||
the last processed (and maybe modified) character. Note that this may
|
* permitted to modify the buffer. This leaves *cpp to point just beyond the
|
||||||
modify the buffer containing the number. */
|
* last processed (and maybe modified) character. Note that this may modify
|
||||||
|
* the buffer containing the number.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
||||||
@ -32,7 +34,8 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||||||
int len, old;
|
int len, old;
|
||||||
|
|
||||||
/* Skip any leading whitespace. */
|
/* Skip any leading whitespace. */
|
||||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
|
;
|
||||||
|
|
||||||
/* Check that it begins with a hex digit. */
|
/* Check that it begins with a hex digit. */
|
||||||
if (*cp < '0' || *cp > '9')
|
if (*cp < '0' || *cp > '9')
|
||||||
@ -42,7 +45,8 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||||||
*cpp = cp;
|
*cpp = cp;
|
||||||
|
|
||||||
/* Move forward until all hex digits skipped. */
|
/* Move forward until all hex digits skipped. */
|
||||||
for (; *cp >= '0' && *cp <= '9'; cp++);
|
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||||
|
;
|
||||||
|
|
||||||
/* Compute the length of the hex number. */
|
/* Compute the length of the hex number. */
|
||||||
len = cp - *cpp;
|
len = cp - *cpp;
|
||||||
@ -51,7 +55,6 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||||||
old = *cp;
|
old = *cp;
|
||||||
*cp = 0;
|
*cp = 0;
|
||||||
|
|
||||||
|
|
||||||
/* Parse the number. */
|
/* Parse the number. */
|
||||||
if (BN_dec2bn(&value, *cpp) == 0)
|
if (BN_dec2bn(&value, *cpp) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -64,8 +67,10 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
|
/*
|
||||||
over the key. Skips any whitespace at the beginning and at end. */
|
* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
|
||||||
|
* over the key. Skips any whitespace at the beginning and at end.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
||||||
@ -74,7 +79,8 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
|||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
/* Skip leading whitespace. */
|
/* Skip leading whitespace. */
|
||||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++);
|
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
|
;
|
||||||
|
|
||||||
/* Get number of bits. */
|
/* Get number of bits. */
|
||||||
if (*cp < '0' || *cp > '9')
|
if (*cp < '0' || *cp > '9')
|
||||||
@ -91,7 +97,8 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Skip trailing whitespace. */
|
/* Skip trailing whitespace. */
|
||||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
|
;
|
||||||
|
|
||||||
/* Return results. */
|
/* Return results. */
|
||||||
*cpp = cp;
|
*cpp = cp;
|
||||||
@ -99,10 +106,12 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tries to match the host name (which must be in all lowercase) against the
|
/*
|
||||||
comma-separated sequence of subpatterns (each possibly preceded by ! to
|
* Tries to match the host name (which must be in all lowercase) against the
|
||||||
indicate negation). Returns true if there is a positive match; zero
|
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||||
otherwise. */
|
* indicate negation). Returns true if there is a positive match; zero
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
match_hostname(const char *host, const char *pattern, unsigned int len)
|
match_hostname(const char *host, const char *pattern, unsigned int len)
|
||||||
@ -121,8 +130,10 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
|
|||||||
} else
|
} else
|
||||||
negated = 0;
|
negated = 0;
|
||||||
|
|
||||||
/* Extract the subpattern up to a comma or end. Convert
|
/*
|
||||||
the subpattern to lowercase. */
|
* Extract the subpattern up to a comma or end. Convert the
|
||||||
|
* subpattern to lowercase.
|
||||||
|
*/
|
||||||
for (subi = 0;
|
for (subi = 0;
|
||||||
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
||||||
subi++, i++)
|
subi++, i++)
|
||||||
@ -131,8 +142,7 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
|
|||||||
if (subi >= sizeof(sub) - 1)
|
if (subi >= sizeof(sub) - 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If the subpattern was terminated by a comma, skip the
|
/* If the subpattern was terminated by a comma, skip the comma. */
|
||||||
comma. */
|
|
||||||
if (i < len && pattern[i] == ',')
|
if (i < len && pattern[i] == ',')
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
@ -142,24 +152,25 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
|
|||||||
/* Try to match the subpattern against the host name. */
|
/* Try to match the subpattern against the host name. */
|
||||||
if (match_pattern(host, sub)) {
|
if (match_pattern(host, sub)) {
|
||||||
if (negated)
|
if (negated)
|
||||||
return 0; /* Fail if host matches
|
return 0; /* Fail */
|
||||||
any negated subpattern. */
|
|
||||||
else
|
else
|
||||||
got_positive = 1;
|
got_positive = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return success if got a positive match. If there was a
|
/*
|
||||||
negative match, we have already returned zero and never get
|
* Return success if got a positive match. If there was a negative
|
||||||
here. */
|
* match, we have already returned zero and never get here.
|
||||||
|
*/
|
||||||
return got_positive;
|
return got_positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks whether the given host (which must be in all lowercase) is
|
/*
|
||||||
already in the list of our known hosts.
|
* Checks whether the given host (which must be in all lowercase) is already
|
||||||
Returns HOST_OK if the host is known and has the specified key,
|
* in the list of our known hosts. Returns HOST_OK if the host is known and
|
||||||
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
|
* has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
|
||||||
but used to have a different host key. */
|
* if the host is known but used to have a different host key.
|
||||||
|
*/
|
||||||
|
|
||||||
HostStatus
|
HostStatus
|
||||||
check_host_in_hostfile(const char *filename, const char *host,
|
check_host_in_hostfile(const char *filename, const char *host,
|
||||||
@ -180,9 +191,11 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||||||
/* Cache the length of the host name. */
|
/* Cache the length of the host name. */
|
||||||
hostlen = strlen(host);
|
hostlen = strlen(host);
|
||||||
|
|
||||||
/* Return value when the loop terminates. This is set to
|
/*
|
||||||
HOST_CHANGED if we have seen a different key for the host and
|
* Return value when the loop terminates. This is set to
|
||||||
have not found the proper one. */
|
* HOST_CHANGED if we have seen a different key for the host and have
|
||||||
|
* not found the proper one.
|
||||||
|
*/
|
||||||
end_return = HOST_NEW;
|
end_return = HOST_NEW;
|
||||||
|
|
||||||
/* size of modulus 'n' */
|
/* size of modulus 'n' */
|
||||||
@ -193,15 +206,15 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||||||
cp = line;
|
cp = line;
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
/* Skip any leading whitespace. */
|
/* Skip any leading whitespace, comments and empty lines. */
|
||||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
|
;
|
||||||
/* Ignore comment lines and empty lines. */
|
|
||||||
if (!*cp || *cp == '#' || *cp == '\n')
|
if (!*cp || *cp == '#' || *cp == '\n')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Find the end of the host name portion. */
|
/* Find the end of the host name portion. */
|
||||||
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++);
|
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
|
||||||
|
;
|
||||||
|
|
||||||
/* Check if the host name matches. */
|
/* Check if the host name matches. */
|
||||||
if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
|
if (!match_hostname(host, cp, (unsigned int) (cp2 - cp)))
|
||||||
@ -210,8 +223,10 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||||||
/* Got a match. Skip host name. */
|
/* Got a match. Skip host name. */
|
||||||
cp = cp2;
|
cp = cp2;
|
||||||
|
|
||||||
/* Extract the key from the line. This will skip any
|
/*
|
||||||
leading whitespace. Ignore badly formatted lines. */
|
* Extract the key from the line. This will skip any leading
|
||||||
|
* whitespace. Ignore badly formatted lines.
|
||||||
|
*/
|
||||||
if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
|
if (!auth_rsa_read_key(&cp, &kbits, ke, kn))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -228,21 +243,27 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
return HOST_OK;
|
return HOST_OK;
|
||||||
}
|
}
|
||||||
/* They do not match. We will continue to go through the
|
/*
|
||||||
file; however, we note that we will not return that it
|
* They do not match. We will continue to go through the
|
||||||
is new. */
|
* file; however, we note that we will not return that it is
|
||||||
|
* new.
|
||||||
|
*/
|
||||||
end_return = HOST_CHANGED;
|
end_return = HOST_CHANGED;
|
||||||
}
|
}
|
||||||
/* Clear variables and close the file. */
|
/* Clear variables and close the file. */
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
/* Return either HOST_NEW or HOST_CHANGED, depending on whether we
|
/*
|
||||||
saw a different key for the host. */
|
* Return either HOST_NEW or HOST_CHANGED, depending on whether we
|
||||||
|
* saw a different key for the host.
|
||||||
|
*/
|
||||||
return end_return;
|
return end_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Appends an entry to the host file. Returns false if the entry
|
/*
|
||||||
could not be appended. */
|
* Appends an entry to the host file. Returns false if the entry could not
|
||||||
|
* be appended.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
add_host_to_hostfile(const char *filename, const char *host,
|
add_host_to_hostfile(const char *filename, const char *host,
|
||||||
|
@ -87,8 +87,10 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
|
|||||||
#define _PATH_RSH "/usr/bin/rsh"
|
#define _PATH_RSH "/usr/bin/rsh"
|
||||||
#endif /* _PATH_RSH */
|
#endif /* _PATH_RSH */
|
||||||
|
|
||||||
/* Define this to use pipes instead of socketpairs for communicating with the
|
/*
|
||||||
client program. Socketpairs do not seem to work on all systems. */
|
* Define this to use pipes instead of socketpairs for communicating with the
|
||||||
|
* client program. Socketpairs do not seem to work on all systems.
|
||||||
|
*/
|
||||||
#define USE_PIPES 1
|
#define USE_PIPES 1
|
||||||
|
|
||||||
#endif /* INCLUDES_H */
|
#endif /* INCLUDES_H */
|
||||||
|
6
log.c
6
log.c
@ -1,11 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
*
|
|
||||||
* Shared versions of debug(), log(), etc.
|
* Shared versions of debug(), log(), etc.
|
||||||
*
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: log.c,v 1.5 1999/11/24 00:26:02 deraadt Exp $");
|
RCSID("$OpenBSD: log.c,v 1.6 1999/11/24 19:53:47 markus Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
29
login.c
29
login.c
@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: login.c,v 1.4 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include <utmp.h>
|
#include <utmp.h>
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -30,12 +30,16 @@ RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
|||||||
# include <lastlog.h>
|
# include <lastlog.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Returns the time when the user last logged in. Returns 0 if the
|
/*
|
||||||
information is not available. This must be called before record_login.
|
* Returns the time when the user last logged in. Returns 0 if the
|
||||||
The host the user logged in from will be returned in buf. */
|
* information is not available. This must be called before record_login.
|
||||||
|
* The host the user logged in from will be returned in buf.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Returns the time when the user last logged in (or 0 if no previous login
|
/*
|
||||||
is found). The name of the host used last time is returned in buf. */
|
* Returns the time when the user last logged in (or 0 if no previous login
|
||||||
|
* is found). The name of the host used last time is returned in buf.
|
||||||
|
*/
|
||||||
|
|
||||||
unsigned long
|
unsigned long
|
||||||
get_last_login_time(uid_t uid, const char *logname,
|
get_last_login_time(uid_t uid, const char *logname,
|
||||||
@ -64,8 +68,10 @@ get_last_login_time(uid_t uid, const char *logname,
|
|||||||
return ll.ll_time;
|
return ll.ll_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Records that the user has logged in. I these parts of operating systems
|
/*
|
||||||
were more standardized. */
|
* Records that the user has logged in. I these parts of operating systems
|
||||||
|
* were more standardized.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||||
@ -95,9 +101,10 @@ record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
|||||||
|
|
||||||
/* Update lastlog unless actually recording a logout. */
|
/* Update lastlog unless actually recording a logout. */
|
||||||
if (strcmp(user, "") != 0) {
|
if (strcmp(user, "") != 0) {
|
||||||
/* It is safer to bzero the lastlog structure first
|
/*
|
||||||
because some systems might have some extra fields in it
|
* It is safer to bzero the lastlog structure first because
|
||||||
(e.g. SGI) */
|
* some systems might have some extra fields in it (e.g. SGI)
|
||||||
|
*/
|
||||||
memset(&ll, 0, sizeof(ll));
|
memset(&ll, 0, sizeof(ll));
|
||||||
|
|
||||||
/* Update lastlog. */
|
/* Update lastlog. */
|
||||||
|
35
match.c
35
match.c
@ -14,12 +14,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: match.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: match.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
/* Returns true if the given string matches the pattern (which may contain
|
/*
|
||||||
? and * as wildcards), and zero if it does not match. */
|
* Returns true if the given string matches the pattern (which may contain ?
|
||||||
|
* and * as wildcards), and zero if it does not match.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
match_pattern(const char *s, const char *pattern)
|
match_pattern(const char *s, const char *pattern)
|
||||||
@ -29,7 +31,6 @@ match_pattern(const char *s, const char *pattern)
|
|||||||
if (!*pattern)
|
if (!*pattern)
|
||||||
return !*s;
|
return !*s;
|
||||||
|
|
||||||
/* Process '*'. */
|
|
||||||
if (*pattern == '*') {
|
if (*pattern == '*') {
|
||||||
/* Skip the asterisk. */
|
/* Skip the asterisk. */
|
||||||
pattern++;
|
pattern++;
|
||||||
@ -40,9 +41,11 @@ match_pattern(const char *s, const char *pattern)
|
|||||||
|
|
||||||
/* If next character in pattern is known, optimize. */
|
/* If next character in pattern is known, optimize. */
|
||||||
if (*pattern != '?' && *pattern != '*') {
|
if (*pattern != '?' && *pattern != '*') {
|
||||||
/* Look instances of the next character in
|
/*
|
||||||
pattern, and try to match starting from
|
* Look instances of the next character in
|
||||||
those. */
|
* pattern, and try to match starting from
|
||||||
|
* those.
|
||||||
|
*/
|
||||||
for (; *s; s++)
|
for (; *s; s++)
|
||||||
if (*s == *pattern &&
|
if (*s == *pattern &&
|
||||||
match_pattern(s + 1, pattern + 1))
|
match_pattern(s + 1, pattern + 1))
|
||||||
@ -50,26 +53,28 @@ match_pattern(const char *s, const char *pattern)
|
|||||||
/* Failed. */
|
/* Failed. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Move ahead one character at a time and try to
|
/*
|
||||||
match at each position. */
|
* Move ahead one character at a time and try to
|
||||||
|
* match at each position.
|
||||||
|
*/
|
||||||
for (; *s; s++)
|
for (; *s; s++)
|
||||||
if (match_pattern(s, pattern))
|
if (match_pattern(s, pattern))
|
||||||
return 1;
|
return 1;
|
||||||
/* Failed. */
|
/* Failed. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* There must be at least one more character in the
|
/*
|
||||||
string. If we are at the end, fail. */
|
* There must be at least one more character in the string.
|
||||||
|
* If we are at the end, fail.
|
||||||
|
*/
|
||||||
if (!*s)
|
if (!*s)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Check if the next character of the string is
|
/* Check if the next character of the string is acceptable. */
|
||||||
acceptable. */
|
|
||||||
if (*pattern != '?' && *pattern != *s)
|
if (*pattern != '?' && *pattern != *s)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Move to the next character, both in string and in
|
/* Move to the next character, both in string and in pattern. */
|
||||||
pattern. */
|
|
||||||
s++;
|
s++;
|
||||||
pattern++;
|
pattern++;
|
||||||
}
|
}
|
||||||
|
10
mpaux.h
10
mpaux.h
@ -13,14 +13,16 @@
|
|||||||
* precision integers.
|
* precision integers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: mpaux.h,v 1.3 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: mpaux.h,v 1.4 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef MPAUX_H
|
#ifndef MPAUX_H
|
||||||
#define MPAUX_H
|
#define MPAUX_H
|
||||||
|
|
||||||
/* Computes a 16-byte session id in the global variable session_id.
|
/*
|
||||||
The session id is computed by concatenating the linearized, msb
|
* Computes a 16-byte session id in the global variable session_id. The
|
||||||
first representations of host_key_n, session_key_n, and the cookie. */
|
* session id is computed by concatenating the linearized, msb first
|
||||||
|
* representations of host_key_n, session_key_n, and the cookie.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
compute_session_id(unsigned char session_id[16],
|
compute_session_id(unsigned char session_id[16],
|
||||||
unsigned char cookie[8],
|
unsigned char cookie[8],
|
||||||
|
34
nchan.c
34
nchan.c
@ -1,5 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1999 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.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Markus Friedl.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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"
|
#include "includes.h"
|
||||||
RCSID("$Id: nchan.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: nchan.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
|
||||||
@ -173,9 +202,10 @@ chan_send_oclose(Channel *c)
|
|||||||
static void
|
static void
|
||||||
chan_shutdown_write(Channel *c)
|
chan_shutdown_write(Channel *c)
|
||||||
{
|
{
|
||||||
|
/* shutdown failure is allowed if write failed already */
|
||||||
debug("channel %d: shutdown_write", c->self);
|
debug("channel %d: shutdown_write", c->self);
|
||||||
if (shutdown(c->sock, SHUT_WR) < 0)
|
if (shutdown(c->sock, SHUT_WR) < 0)
|
||||||
error("chan_shutdown_write failed for #%d/fd%d: %.100s",
|
debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
|
||||||
c->self, c->sock, strerror(errno));
|
c->self, c->sock, strerror(errno));
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
|
31
nchan.h
31
nchan.h
@ -1,4 +1,33 @@
|
|||||||
/* RCSID("$Id: nchan.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/*
|
||||||
|
* Copyright (c) 1999 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.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Markus Friedl.
|
||||||
|
* 4. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* RCSID("$Id: nchan.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef NCHAN_H
|
#ifndef NCHAN_H
|
||||||
#define NCHAN_H
|
#define NCHAN_H
|
||||||
|
28
nchan.ms
28
nchan.ms
@ -1,3 +1,31 @@
|
|||||||
|
.\"
|
||||||
|
.\" Copyright (c) 1999 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.
|
||||||
|
.\" 3. All advertising materials mentioning features or use of this software
|
||||||
|
.\" must display the following acknowledgement:
|
||||||
|
.\" This product includes software developed by Markus Friedl.
|
||||||
|
.\" 4. The name of the author may not be used to endorse or promote products
|
||||||
|
.\" derived from this software without specific prior written permission.
|
||||||
|
.\"
|
||||||
|
.\" 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.
|
||||||
|
.\"
|
||||||
.TL
|
.TL
|
||||||
OpenSSH Channel Close Protocol 1.5 Implementation
|
OpenSSH Channel Close Protocol 1.5 Implementation
|
||||||
.SH
|
.SH
|
||||||
|
181
packet.c
181
packet.c
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: packet.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: packet.c,v 1.6 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
@ -29,15 +29,19 @@ RCSID("$Id: packet.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
|||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
#include "deattack.h"
|
#include "deattack.h"
|
||||||
|
|
||||||
/* This variable contains the file descriptors used for communicating with
|
/*
|
||||||
the other side. connection_in is used for reading; connection_out
|
* This variable contains the file descriptors used for communicating with
|
||||||
for writing. These can be the same descriptor, in which case it is
|
* the other side. connection_in is used for reading; connection_out for
|
||||||
assumed to be a socket. */
|
* writing. These can be the same descriptor, in which case it is assumed to
|
||||||
|
* be a socket.
|
||||||
|
*/
|
||||||
static int connection_in = -1;
|
static int connection_in = -1;
|
||||||
static int connection_out = -1;
|
static int connection_out = -1;
|
||||||
|
|
||||||
/* Cipher type. This value is only used to determine whether to pad the
|
/*
|
||||||
packets with zeroes or random data. */
|
* Cipher type. This value is only used to determine whether to pad the
|
||||||
|
* packets with zeroes or random data.
|
||||||
|
*/
|
||||||
static int cipher_type = SSH_CIPHER_NONE;
|
static int cipher_type = SSH_CIPHER_NONE;
|
||||||
|
|
||||||
/* Protocol flags for the remote side. */
|
/* Protocol flags for the remote side. */
|
||||||
@ -76,8 +80,10 @@ static int initialized = 0;
|
|||||||
/* Set to true if the connection is interactive. */
|
/* Set to true if the connection is interactive. */
|
||||||
static int interactive_mode = 0;
|
static int interactive_mode = 0;
|
||||||
|
|
||||||
/* Sets the descriptors used for communication. Disables encryption until
|
/*
|
||||||
packet_set_encryption_key is called. */
|
* Sets the descriptors used for communication. Disables encryption until
|
||||||
|
* packet_set_encryption_key is called.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_set_connection(int fd_in, int fd_out)
|
packet_set_connection(int fd_in, int fd_out)
|
||||||
@ -171,8 +177,10 @@ packet_get_protocol_flags()
|
|||||||
return remote_protocol_flags;
|
return remote_protocol_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Starts packet compression from the next packet on in both directions.
|
/*
|
||||||
Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */
|
* Starts packet compression from the next packet on in both directions.
|
||||||
|
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_start_compression(int level)
|
packet_start_compression(int level)
|
||||||
@ -184,8 +192,10 @@ packet_start_compression(int level)
|
|||||||
buffer_compress_init(level);
|
buffer_compress_init(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encrypts the given number of bytes, copying from src to dest.
|
/*
|
||||||
bytes is known to be a multiple of 8. */
|
* Encrypts the given number of bytes, copying from src to dest. bytes is
|
||||||
|
* known to be a multiple of 8.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_encrypt(CipherContext * cc, void *dest, void *src,
|
packet_encrypt(CipherContext * cc, void *dest, void *src,
|
||||||
@ -194,8 +204,10 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
|
|||||||
cipher_encrypt(cc, dest, src, bytes);
|
cipher_encrypt(cc, dest, src, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decrypts the given number of bytes, copying from src to dest.
|
/*
|
||||||
bytes is known to be a multiple of 8. */
|
* Decrypts the given number of bytes, copying from src to dest. bytes is
|
||||||
|
* known to be a multiple of 8.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_decrypt(CipherContext * cc, void *dest, void *src,
|
packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||||
@ -206,8 +218,10 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
|||||||
if ((bytes % 8) != 0)
|
if ((bytes % 8) != 0)
|
||||||
fatal("packet_decrypt: bad ciphertext length %d", bytes);
|
fatal("packet_decrypt: bad ciphertext length %d", bytes);
|
||||||
|
|
||||||
/* Cryptographic attack detector for ssh - Modifications for packet.c
|
/*
|
||||||
(C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com) */
|
* Cryptographic attack detector for ssh - Modifications for packet.c
|
||||||
|
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
|
||||||
|
*/
|
||||||
|
|
||||||
switch (cc->type) {
|
switch (cc->type) {
|
||||||
case SSH_CIPHER_NONE:
|
case SSH_CIPHER_NONE:
|
||||||
@ -224,9 +238,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
|||||||
cipher_decrypt(cc, dest, src, bytes);
|
cipher_decrypt(cc, dest, src, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Causes any further packets to be encrypted using the given key. The same
|
/*
|
||||||
key is used for both sending and reception. However, both directions
|
* Causes any further packets to be encrypted using the given key. The same
|
||||||
are encrypted independently of each other. */
|
* key is used for both sending and reception. However, both directions are
|
||||||
|
* encrypted independently of each other.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||||
@ -283,8 +299,10 @@ packet_put_bignum(BIGNUM * value)
|
|||||||
buffer_put_bignum(&outgoing_packet, value);
|
buffer_put_bignum(&outgoing_packet, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finalizes and sends the packet. If the encryption key has been set,
|
/*
|
||||||
encrypts the packet before sending. */
|
* Finalizes and sends the packet. If the encryption key has been set,
|
||||||
|
* encrypts the packet before sending.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_send()
|
packet_send()
|
||||||
@ -294,8 +312,10 @@ packet_send()
|
|||||||
unsigned int checksum;
|
unsigned int checksum;
|
||||||
u_int32_t rand = 0;
|
u_int32_t rand = 0;
|
||||||
|
|
||||||
/* If using packet compression, compress the payload of the
|
/*
|
||||||
outgoing packet. */
|
* If using packet compression, compress the payload of the outgoing
|
||||||
|
* packet.
|
||||||
|
*/
|
||||||
if (packet_compression) {
|
if (packet_compression) {
|
||||||
buffer_clear(&compression_buffer);
|
buffer_clear(&compression_buffer);
|
||||||
/* Skip padding. */
|
/* Skip padding. */
|
||||||
@ -348,14 +368,18 @@ packet_send()
|
|||||||
|
|
||||||
buffer_clear(&outgoing_packet);
|
buffer_clear(&outgoing_packet);
|
||||||
|
|
||||||
/* Note that the packet is now only buffered in output. It won\'t
|
/*
|
||||||
be actually sent until packet_write_wait or packet_write_poll
|
* Note that the packet is now only buffered in output. It won\'t be
|
||||||
is called. */
|
* actually sent until packet_write_wait or packet_write_poll is
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Waits until a packet has been received, and returns its type. Note that
|
/*
|
||||||
no other data is processed until this returns, so this function should
|
* Waits until a packet has been received, and returns its type. Note that
|
||||||
not be used during the interactive session. */
|
* no other data is processed until this returns, so this function should not
|
||||||
|
* be used during the interactive session.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
packet_read(int *payload_len_ptr)
|
packet_read(int *payload_len_ptr)
|
||||||
@ -379,12 +403,16 @@ packet_read(int *payload_len_ptr)
|
|||||||
/* If we got a packet, return it. */
|
/* If we got a packet, return it. */
|
||||||
if (type != SSH_MSG_NONE)
|
if (type != SSH_MSG_NONE)
|
||||||
return type;
|
return type;
|
||||||
/* Otherwise, wait for some data to arrive, add it to the
|
/*
|
||||||
buffer, and try again. */
|
* Otherwise, wait for some data to arrive, add it to the
|
||||||
|
* buffer, and try again.
|
||||||
|
*/
|
||||||
FD_ZERO(&set);
|
FD_ZERO(&set);
|
||||||
FD_SET(connection_in, &set);
|
FD_SET(connection_in, &set);
|
||||||
|
|
||||||
/* Wait for some data to arrive. */
|
/* Wait for some data to arrive. */
|
||||||
select(connection_in + 1, &set, NULL, NULL, NULL);
|
select(connection_in + 1, &set, NULL, NULL, NULL);
|
||||||
|
|
||||||
/* Read data from the socket. */
|
/* Read data from the socket. */
|
||||||
len = read(connection_in, buf, sizeof(buf));
|
len = read(connection_in, buf, sizeof(buf));
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
@ -397,8 +425,10 @@ packet_read(int *payload_len_ptr)
|
|||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Waits until a packet has been received, verifies that its type matches
|
/*
|
||||||
that given, and gives a fatal error and exits if there is a mismatch. */
|
* Waits until a packet has been received, verifies that its type matches
|
||||||
|
* that given, and gives a fatal error and exits if there is a mismatch.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_read_expect(int *payload_len_ptr, int expected_type)
|
packet_read_expect(int *payload_len_ptr, int expected_type)
|
||||||
@ -516,8 +546,10 @@ restart:
|
|||||||
return (unsigned char) buf[0];
|
return (unsigned char) buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buffers the given amount of input characters. This is intended to be
|
/*
|
||||||
used together with packet_read_poll. */
|
* Buffers the given amount of input characters. This is intended to be used
|
||||||
|
* together with packet_read_poll.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_process_incoming(const char *buf, unsigned int len)
|
packet_process_incoming(const char *buf, unsigned int len)
|
||||||
@ -543,8 +575,10 @@ packet_get_int()
|
|||||||
return buffer_get_int(&incoming_packet);
|
return buffer_get_int(&incoming_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns an arbitrary precision integer from the packet data. The integer
|
/*
|
||||||
must have been initialized before this call. */
|
* Returns an arbitrary precision integer from the packet data. The integer
|
||||||
|
* must have been initialized before this call.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_get_bignum(BIGNUM * value, int *length_ptr)
|
packet_get_bignum(BIGNUM * value, int *length_ptr)
|
||||||
@ -552,25 +586,27 @@ packet_get_bignum(BIGNUM * value, int *length_ptr)
|
|||||||
*length_ptr = buffer_get_bignum(&incoming_packet, value);
|
*length_ptr = buffer_get_bignum(&incoming_packet, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a string from the packet data. The string is allocated using
|
/*
|
||||||
xmalloc; it is the responsibility of the calling program to free it when
|
* Returns a string from the packet data. The string is allocated using
|
||||||
no longer needed. The length_ptr argument may be NULL, or point to an
|
* xmalloc; it is the responsibility of the calling program to free it when
|
||||||
integer into which the length of the string is stored. */
|
* no longer needed. The length_ptr argument may be NULL, or point to an
|
||||||
|
* integer into which the length of the string is stored.
|
||||||
|
*/
|
||||||
|
|
||||||
char
|
char *
|
||||||
*
|
|
||||||
packet_get_string(unsigned int *length_ptr)
|
packet_get_string(unsigned int *length_ptr)
|
||||||
{
|
{
|
||||||
return buffer_get_string(&incoming_packet, length_ptr);
|
return buffer_get_string(&incoming_packet, length_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sends a diagnostic message from the server to the client. This message
|
/*
|
||||||
can be sent at any time (but not while constructing another message).
|
* Sends a diagnostic message from the server to the client. This message
|
||||||
The message is printed immediately, but only if the client is being
|
* can be sent at any time (but not while constructing another message). The
|
||||||
executed in verbose mode. These messages are primarily intended to
|
* message is printed immediately, but only if the client is being executed
|
||||||
ease debugging authentication problems. The length of the formatted
|
* in verbose mode. These messages are primarily intended to ease debugging
|
||||||
message must not exceed 1024 bytes. This will automatically call
|
* authentication problems. The length of the formatted message must not
|
||||||
packet_write_wait. */
|
* exceed 1024 bytes. This will automatically call packet_write_wait.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_send_debug(const char *fmt,...)
|
packet_send_debug(const char *fmt,...)
|
||||||
@ -588,10 +624,12 @@ packet_send_debug(const char *fmt,...)
|
|||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Logs the error plus constructs and sends a disconnect
|
/*
|
||||||
packet, closes the connection, and exits. This function never returns.
|
* Logs the error plus constructs and sends a disconnect packet, closes the
|
||||||
The error message should not contain a newline. The length of the
|
* connection, and exits. This function never returns. The error message
|
||||||
formatted message must not exceed 1024 bytes. */
|
* should not contain a newline. The length of the formatted message must
|
||||||
|
* not exceed 1024 bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_disconnect(const char *fmt,...)
|
packet_disconnect(const char *fmt,...)
|
||||||
@ -603,8 +641,10 @@ packet_disconnect(const char *fmt,...)
|
|||||||
fatal("packet_disconnect called recursively.");
|
fatal("packet_disconnect called recursively.");
|
||||||
disconnecting = 1;
|
disconnecting = 1;
|
||||||
|
|
||||||
/* Format the message. Note that the caller must make sure the
|
/*
|
||||||
message is of limited size. */
|
* Format the message. Note that the caller must make sure the
|
||||||
|
* message is of limited size.
|
||||||
|
*/
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
@ -625,8 +665,7 @@ packet_disconnect(const char *fmt,...)
|
|||||||
fatal("Disconnecting: %.100s", buf);
|
fatal("Disconnecting: %.100s", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if there is any buffered output, and tries to write some of the
|
/* Checks if there is any buffered output, and tries to write some of the output. */
|
||||||
output. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_write_poll()
|
packet_write_poll()
|
||||||
@ -644,8 +683,10 @@ packet_write_poll()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calls packet_write_poll repeatedly until all pending output data has
|
/*
|
||||||
been written. */
|
* Calls packet_write_poll repeatedly until all pending output data has been
|
||||||
|
* written.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
packet_write_wait()
|
packet_write_wait()
|
||||||
@ -689,8 +730,10 @@ packet_set_interactive(int interactive, int keepalives)
|
|||||||
/* Record that we are in interactive mode. */
|
/* Record that we are in interactive mode. */
|
||||||
interactive_mode = interactive;
|
interactive_mode = interactive;
|
||||||
|
|
||||||
/* Only set socket options if using a socket (as indicated by the
|
/*
|
||||||
descriptors being the same). */
|
* Only set socket options if using a socket (as indicated by the
|
||||||
|
* descriptors being the same).
|
||||||
|
*/
|
||||||
if (connection_in != connection_out)
|
if (connection_in != connection_out)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -701,8 +744,10 @@ packet_set_interactive(int interactive, int keepalives)
|
|||||||
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
|
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
|
||||||
}
|
}
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* Set IP options for an interactive connection. Use
|
/*
|
||||||
IPTOS_LOWDELAY and TCP_NODELAY. */
|
* Set IP options for an interactive connection. Use
|
||||||
|
* IPTOS_LOWDELAY and TCP_NODELAY.
|
||||||
|
*/
|
||||||
int lowdelay = IPTOS_LOWDELAY;
|
int lowdelay = IPTOS_LOWDELAY;
|
||||||
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
|
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
|
||||||
sizeof(lowdelay)) < 0)
|
sizeof(lowdelay)) < 0)
|
||||||
@ -711,8 +756,10 @@ packet_set_interactive(int interactive, int keepalives)
|
|||||||
sizeof(on)) < 0)
|
sizeof(on)) < 0)
|
||||||
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
|
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
/* Set IP options for a non-interactive connection. Use
|
/*
|
||||||
IPTOS_THROUGHPUT. */
|
* Set IP options for a non-interactive connection. Use
|
||||||
|
* IPTOS_THROUGHPUT.
|
||||||
|
*/
|
||||||
int throughput = IPTOS_THROUGHPUT;
|
int throughput = IPTOS_THROUGHPUT;
|
||||||
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
|
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
|
||||||
sizeof(throughput)) < 0)
|
sizeof(throughput)) < 0)
|
||||||
|
118
packet.h
118
packet.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: packet.h,v 1.6 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: packet.h,v 1.7 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef PACKET_H
|
#ifndef PACKET_H
|
||||||
#define PACKET_H
|
#define PACKET_H
|
||||||
@ -27,10 +27,11 @@
|
|||||||
#include <ssl/bn.h>
|
#include <ssl/bn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Sets the socket used for communication. Disables encryption until
|
/*
|
||||||
packet_set_encryption_key is called. It is permissible that fd_in
|
* Sets the socket used for communication. Disables encryption until
|
||||||
and fd_out are the same descriptor; in that case it is assumed to
|
* packet_set_encryption_key is called. It is permissible that fd_in and
|
||||||
be a socket. */
|
* fd_out are the same descriptor; in that case it is assumed to be a socket.
|
||||||
|
*/
|
||||||
void packet_set_connection(int fd_in, int fd_out);
|
void packet_set_connection(int fd_in, int fd_out);
|
||||||
|
|
||||||
/* Puts the connection file descriptors into non-blocking mode. */
|
/* Puts the connection file descriptors into non-blocking mode. */
|
||||||
@ -42,20 +43,25 @@ int packet_get_connection_in(void);
|
|||||||
/* Returns the file descriptor used for output. */
|
/* Returns the file descriptor used for output. */
|
||||||
int packet_get_connection_out(void);
|
int packet_get_connection_out(void);
|
||||||
|
|
||||||
/* Closes the connection (both descriptors) and clears and frees
|
/*
|
||||||
internal data structures. */
|
* Closes the connection (both descriptors) and clears and frees internal
|
||||||
|
* data structures.
|
||||||
|
*/
|
||||||
void packet_close(void);
|
void packet_close(void);
|
||||||
|
|
||||||
/* Causes any further packets to be encrypted using the given key. The same
|
/*
|
||||||
key is used for both sending and reception. However, both directions
|
* Causes any further packets to be encrypted using the given key. The same
|
||||||
are encrypted independently of each other. Cipher types are
|
* key is used for both sending and reception. However, both directions are
|
||||||
defined in ssh.h. */
|
* encrypted independently of each other. Cipher types are defined in ssh.h.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||||
int cipher_type);
|
int cipher_type);
|
||||||
|
|
||||||
/* Sets remote side protocol flags for the current connection. This can
|
/*
|
||||||
be called at any time. */
|
* Sets remote side protocol flags for the current connection. This can be
|
||||||
|
* called at any time.
|
||||||
|
*/
|
||||||
void packet_set_protocol_flags(unsigned int flags);
|
void packet_set_protocol_flags(unsigned int flags);
|
||||||
|
|
||||||
/* Returns the remote protocol flags set earlier by the above function. */
|
/* Returns the remote protocol flags set earlier by the above function. */
|
||||||
@ -64,8 +70,10 @@ unsigned int packet_get_protocol_flags(void);
|
|||||||
/* Enables compression in both directions starting from the next packet. */
|
/* Enables compression in both directions starting from the next packet. */
|
||||||
void packet_start_compression(int level);
|
void packet_start_compression(int level);
|
||||||
|
|
||||||
/* Informs that the current session is interactive. Sets IP flags for optimal
|
/*
|
||||||
performance in interactive use. */
|
* Informs that the current session is interactive. Sets IP flags for
|
||||||
|
* optimal performance in interactive use.
|
||||||
|
*/
|
||||||
void packet_set_interactive(int interactive, int keepalives);
|
void packet_set_interactive(int interactive, int keepalives);
|
||||||
|
|
||||||
/* Returns true if the current connection is interactive. */
|
/* Returns true if the current connection is interactive. */
|
||||||
@ -86,28 +94,35 @@ void packet_put_bignum(BIGNUM * value);
|
|||||||
/* Appends a string to packet data. */
|
/* Appends a string to packet data. */
|
||||||
void packet_put_string(const char *buf, unsigned int len);
|
void packet_put_string(const char *buf, unsigned int len);
|
||||||
|
|
||||||
/* Finalizes and sends the packet. If the encryption key has been set,
|
/*
|
||||||
encrypts the packet before sending. */
|
* Finalizes and sends the packet. If the encryption key has been set,
|
||||||
|
* encrypts the packet before sending.
|
||||||
|
*/
|
||||||
void packet_send(void);
|
void packet_send(void);
|
||||||
|
|
||||||
/* Waits until a packet has been received, and returns its type. */
|
/* Waits until a packet has been received, and returns its type. */
|
||||||
int packet_read(int *payload_len_ptr);
|
int packet_read(int *payload_len_ptr);
|
||||||
|
|
||||||
/* Waits until a packet has been received, verifies that its type matches
|
/*
|
||||||
that given, and gives a fatal error and exits if there is a mismatch. */
|
* Waits until a packet has been received, verifies that its type matches
|
||||||
|
* that given, and gives a fatal error and exits if there is a mismatch.
|
||||||
|
*/
|
||||||
void packet_read_expect(int *payload_len_ptr, int type);
|
void packet_read_expect(int *payload_len_ptr, int type);
|
||||||
|
|
||||||
/* Checks if a full packet is available in the data received so far via
|
/*
|
||||||
packet_process_incoming. If so, reads the packet; otherwise returns
|
* Checks if a full packet is available in the data received so far via
|
||||||
SSH_MSG_NONE. This does not wait for data from the connection.
|
* packet_process_incoming. If so, reads the packet; otherwise returns
|
||||||
|
* SSH_MSG_NONE. This does not wait for data from the connection.
|
||||||
SSH_MSG_DISCONNECT is handled specially here. Also,
|
* SSH_MSG_DISCONNECT is handled specially here. Also, SSH_MSG_IGNORE
|
||||||
SSH_MSG_IGNORE messages are skipped by this function and are never returned
|
* messages are skipped by this function and are never returned to higher
|
||||||
to higher levels. */
|
* levels.
|
||||||
|
*/
|
||||||
int packet_read_poll(int *packet_len_ptr);
|
int packet_read_poll(int *packet_len_ptr);
|
||||||
|
|
||||||
/* Buffers the given amount of input characters. This is intended to be
|
/*
|
||||||
used together with packet_read_poll. */
|
* Buffers the given amount of input characters. This is intended to be used
|
||||||
|
* together with packet_read_poll.
|
||||||
|
*/
|
||||||
void packet_process_incoming(const char *buf, unsigned int len);
|
void packet_process_incoming(const char *buf, unsigned int len);
|
||||||
|
|
||||||
/* Returns a character (0-255) from the packet data. */
|
/* Returns a character (0-255) from the packet data. */
|
||||||
@ -116,34 +131,41 @@ unsigned int packet_get_char(void);
|
|||||||
/* Returns an integer from the packet data. */
|
/* Returns an integer from the packet data. */
|
||||||
unsigned int packet_get_int(void);
|
unsigned int packet_get_int(void);
|
||||||
|
|
||||||
/* Returns an arbitrary precision integer from the packet data. The integer
|
/*
|
||||||
must have been initialized before this call. */
|
* Returns an arbitrary precision integer from the packet data. The integer
|
||||||
|
* must have been initialized before this call.
|
||||||
|
*/
|
||||||
void packet_get_bignum(BIGNUM * value, int *length_ptr);
|
void packet_get_bignum(BIGNUM * value, int *length_ptr);
|
||||||
|
|
||||||
/* Returns a string from the packet data. The string is allocated using
|
/*
|
||||||
xmalloc; it is the responsibility of the calling program to free it when
|
* Returns a string from the packet data. The string is allocated using
|
||||||
no longer needed. The length_ptr argument may be NULL, or point to an
|
* xmalloc; it is the responsibility of the calling program to free it when
|
||||||
integer into which the length of the string is stored. */
|
* no longer needed. The length_ptr argument may be NULL, or point to an
|
||||||
|
* integer into which the length of the string is stored.
|
||||||
|
*/
|
||||||
char *packet_get_string(unsigned int *length_ptr);
|
char *packet_get_string(unsigned int *length_ptr);
|
||||||
|
|
||||||
/* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
|
/*
|
||||||
packet, closes the connection, and exits. This function never returns.
|
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
|
||||||
The error message should not contain a newline. The total length of the
|
* packet, closes the connection, and exits. This function never returns.
|
||||||
message must not exceed 1024 bytes. */
|
* The error message should not contain a newline. The total length of the
|
||||||
|
* message must not exceed 1024 bytes.
|
||||||
|
*/
|
||||||
void packet_disconnect(const char *fmt,...);
|
void packet_disconnect(const char *fmt,...);
|
||||||
|
|
||||||
/* Sends a diagnostic message to the other side. This message
|
/*
|
||||||
can be sent at any time (but not while constructing another message).
|
* Sends a diagnostic message to the other side. This message can be sent at
|
||||||
The message is printed immediately, but only if the client is being
|
* any time (but not while constructing another message). The message is
|
||||||
executed in verbose mode. These messages are primarily intended to
|
* printed immediately, but only if the client is being executed in verbose
|
||||||
ease debugging authentication problems. The total length of the message
|
* mode. These messages are primarily intended to ease debugging
|
||||||
must not exceed 1024 bytes. This will automatically call
|
* authentication problems. The total length of the message must not exceed
|
||||||
packet_write_wait. If the remote side protocol flags do not indicate
|
* 1024 bytes. This will automatically call packet_write_wait. If the
|
||||||
that it supports SSH_MSG_DEBUG, this will do nothing. */
|
* remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
|
||||||
|
* this will do nothing.
|
||||||
|
*/
|
||||||
void packet_send_debug(const char *fmt,...);
|
void packet_send_debug(const char *fmt,...);
|
||||||
|
|
||||||
/* Checks if there is any buffered output, and tries to write some of the
|
/* Checks if there is any buffered output, and tries to write some of the output. */
|
||||||
output. */
|
|
||||||
void packet_write_poll(void);
|
void packet_write_poll(void);
|
||||||
|
|
||||||
/* Waits until all pending output data has been written. */
|
/* Waits until all pending output data has been written. */
|
||||||
|
44
pty.c
44
pty.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: pty.c,v 1.5 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "pty.h"
|
#include "pty.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -32,10 +32,12 @@ RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
|||||||
#define O_NOCTTY 0
|
#define O_NOCTTY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
|
/*
|
||||||
or nonzero if a pty was successfully allocated. On success, open file
|
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
|
||||||
descriptors for the pty and tty sides and the name of the tty side are
|
* nonzero if a pty was successfully allocated. On success, open file
|
||||||
returned (the buffer must be able to hold at least 64 characters). */
|
* descriptors for the pty and tty sides and the name of the tty side are
|
||||||
|
* returned (the buffer must be able to hold at least 64 characters).
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
||||||
@ -52,8 +54,10 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||||||
return 1;
|
return 1;
|
||||||
#else /* HAVE_OPENPTY */
|
#else /* HAVE_OPENPTY */
|
||||||
#ifdef HAVE__GETPTY
|
#ifdef HAVE__GETPTY
|
||||||
/* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates
|
/*
|
||||||
more pty's automagically when needed */
|
* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
|
||||||
|
* pty's automagically when needed
|
||||||
|
*/
|
||||||
char *slave;
|
char *slave;
|
||||||
|
|
||||||
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
||||||
@ -72,8 +76,10 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||||||
return 1;
|
return 1;
|
||||||
#else /* HAVE__GETPTY */
|
#else /* HAVE__GETPTY */
|
||||||
#ifdef HAVE_DEV_PTMX
|
#ifdef HAVE_DEV_PTMX
|
||||||
/* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
|
/*
|
||||||
also has bsd-style ptys, but they simply do not work.) */
|
* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
|
||||||
|
* also has bsd-style ptys, but they simply do not work.)
|
||||||
|
*/
|
||||||
int ptm;
|
int ptm;
|
||||||
char *pts;
|
char *pts;
|
||||||
|
|
||||||
@ -103,8 +109,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||||||
close(*ptyfd);
|
close(*ptyfd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Push the appropriate streams modules, as described in Solaris
|
/* Push the appropriate streams modules, as described in Solaris pts(7). */
|
||||||
pts(7). */
|
|
||||||
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
|
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
|
||||||
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
|
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
|
||||||
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
|
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
|
||||||
@ -138,8 +143,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||||||
/* BSD-style pty code. */
|
/* BSD-style pty code. */
|
||||||
char buf[64];
|
char buf[64];
|
||||||
int i;
|
int i;
|
||||||
const char *ptymajors =
|
const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
"pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
const char *ptyminors = "0123456789abcdef";
|
const char *ptyminors = "0123456789abcdef";
|
||||||
int num_minors = strlen(ptyminors);
|
int num_minors = strlen(ptyminors);
|
||||||
int num_ptys = strlen(ptymajors) * num_minors;
|
int num_ptys = strlen(ptymajors) * num_minors;
|
||||||
@ -198,8 +202,10 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
|||||||
if (setsid() < 0)
|
if (setsid() < 0)
|
||||||
error("setsid: %.100s", strerror(errno));
|
error("setsid: %.100s", strerror(errno));
|
||||||
|
|
||||||
/* Verify that we are successfully disconnected from the
|
/*
|
||||||
controlling tty. */
|
* Verify that we are successfully disconnected from the controlling
|
||||||
|
* tty.
|
||||||
|
*/
|
||||||
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
|
fd = open("/dev/tty", O_RDWR | O_NOCTTY);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
error("Failed to disconnect from controlling tty.");
|
error("Failed to disconnect from controlling tty.");
|
||||||
@ -208,9 +214,11 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
|||||||
/* Make it our controlling tty. */
|
/* Make it our controlling tty. */
|
||||||
#ifdef TIOCSCTTY
|
#ifdef TIOCSCTTY
|
||||||
debug("Setting controlling tty using TIOCSCTTY.");
|
debug("Setting controlling tty using TIOCSCTTY.");
|
||||||
/* We ignore errors from this, because HPSUX defines TIOCSCTTY,
|
/*
|
||||||
but returns EINVAL with these arguments, and there is
|
* We ignore errors from this, because HPSUX defines TIOCSCTTY, but
|
||||||
absolutely no documentation. */
|
* returns EINVAL with these arguments, and there is absolutely no
|
||||||
|
* documentation.
|
||||||
|
*/
|
||||||
ioctl(*ttyfd, TIOCSCTTY, NULL);
|
ioctl(*ttyfd, TIOCSCTTY, NULL);
|
||||||
#endif /* TIOCSCTTY */
|
#endif /* TIOCSCTTY */
|
||||||
fd = open(ttyname, O_RDWR);
|
fd = open(ttyname, O_RDWR);
|
||||||
|
24
pty.h
24
pty.h
@ -13,23 +13,29 @@
|
|||||||
* tty.
|
* tty.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: pty.h,v 1.2 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: pty.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef PTY_H
|
#ifndef PTY_H
|
||||||
#define PTY_H
|
#define PTY_H
|
||||||
|
|
||||||
/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
|
/*
|
||||||
or nonzero if a pty was successfully allocated. On success, open file
|
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
|
||||||
descriptors for the pty and tty sides and the name of the tty side are
|
* nonzero if a pty was successfully allocated. On success, open file
|
||||||
returned (the buffer must be able to hold at least 64 characters). */
|
* descriptors for the pty and tty sides and the name of the tty side are
|
||||||
|
* returned (the buffer must be able to hold at least 64 characters).
|
||||||
|
*/
|
||||||
int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname);
|
int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname);
|
||||||
|
|
||||||
/* Releases the tty. Its ownership is returned to root, and permissions to
|
/*
|
||||||
0666. */
|
* Releases the tty. Its ownership is returned to root, and permissions to
|
||||||
|
* 0666.
|
||||||
|
*/
|
||||||
void pty_release(const char *ttyname);
|
void pty_release(const char *ttyname);
|
||||||
|
|
||||||
/* Makes the tty the processes controlling tty and sets it to sane modes.
|
/*
|
||||||
This may need to reopen the tty to get rid of possible eavesdroppers. */
|
* Makes the tty the processes controlling tty and sets it to sane modes.
|
||||||
|
* This may need to reopen the tty to get rid of possible eavesdroppers.
|
||||||
|
*/
|
||||||
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
|
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
|
||||||
|
|
||||||
/* Changes the window size associated with the pty. */
|
/* Changes the window size associated with the pty. */
|
||||||
|
8
radix.c
8
radix.c
@ -74,9 +74,11 @@ uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
|
|||||||
while (*bufcoded == ' ' || *bufcoded == '\t')
|
while (*bufcoded == ' ' || *bufcoded == '\t')
|
||||||
bufcoded++;
|
bufcoded++;
|
||||||
|
|
||||||
/* Figure out how many characters are in the input buffer. If this
|
/*
|
||||||
would decode into more bytes than would fit into the output
|
* Figure out how many characters are in the input buffer. If this
|
||||||
buffer, adjust the number of input bytes downwards. */
|
* would decode into more bytes than would fit into the output
|
||||||
|
* buffer, adjust the number of input bytes downwards.
|
||||||
|
*/
|
||||||
bufin = bufcoded;
|
bufin = bufcoded;
|
||||||
while (DEC(*(bufin++)) <= MAXVAL);
|
while (DEC(*(bufin++)) <= MAXVAL);
|
||||||
nprbytes = bufin - bufcoded - 1;
|
nprbytes = bufin - bufcoded - 1;
|
||||||
|
90
readconf.c
90
readconf.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: readconf.c,v 1.5 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: readconf.c,v 1.6 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
@ -158,8 +158,10 @@ static struct {
|
|||||||
#define WHITESPACE " \t\r\n"
|
#define WHITESPACE " \t\r\n"
|
||||||
|
|
||||||
|
|
||||||
/* Adds a local TCP/IP port forward to options. Never returns if there
|
/*
|
||||||
is an error. */
|
* Adds a local TCP/IP port forward to options. Never returns if there is an
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
add_local_forward(Options *options, int port, const char *host,
|
add_local_forward(Options *options, int port, const char *host,
|
||||||
@ -179,8 +181,10 @@ add_local_forward(Options *options, int port, const char *host,
|
|||||||
fwd->host_port = host_port;
|
fwd->host_port = host_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds a remote TCP/IP port forward to options. Never returns if there
|
/*
|
||||||
is an error. */
|
* Adds a remote TCP/IP port forward to options. Never returns if there is
|
||||||
|
* an error.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
add_remote_forward(Options *options, int port, const char *host,
|
add_remote_forward(Options *options, int port, const char *host,
|
||||||
@ -196,8 +200,10 @@ add_remote_forward(Options *options, int port, const char *host,
|
|||||||
fwd->host_port = host_port;
|
fwd->host_port = host_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the number of the token pointed to by cp of length len.
|
/*
|
||||||
Never returns if the token is not known. */
|
* Returns the number of the token pointed to by cp of length len. Never
|
||||||
|
* returns if the token is not known.
|
||||||
|
*/
|
||||||
|
|
||||||
static OpCodes
|
static OpCodes
|
||||||
parse_token(const char *cp, const char *filename, int linenum)
|
parse_token(const char *cp, const char *filename, int linenum)
|
||||||
@ -205,7 +211,7 @@ parse_token(const char *cp, const char *filename, int linenum)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; keywords[i].name; i++)
|
for (i = 0; keywords[i].name; i++)
|
||||||
if (strcmp(cp, keywords[i].name) == 0)
|
if (strcasecmp(cp, keywords[i].name) == 0)
|
||||||
return keywords[i].opcode;
|
return keywords[i].opcode;
|
||||||
|
|
||||||
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
||||||
@ -213,15 +219,17 @@ parse_token(const char *cp, const char *filename, int linenum)
|
|||||||
return oBadOption;
|
return oBadOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Processes a single option line as used in the configuration files.
|
/*
|
||||||
This only sets those values that have not already been set. */
|
* Processes a single option line as used in the configuration files. This
|
||||||
|
* only sets those values that have not already been set.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
process_config_line(Options *options, const char *host,
|
process_config_line(Options *options, const char *host,
|
||||||
char *line, const char *filename, int linenum,
|
char *line, const char *filename, int linenum,
|
||||||
int *activep)
|
int *activep)
|
||||||
{
|
{
|
||||||
char buf[256], *cp, *string, **charptr;
|
char buf[256], *cp, *string, **charptr, *cp2;
|
||||||
int opcode, *intptr, value, fwd_port, fwd_host_port;
|
int opcode, *intptr, value, fwd_port, fwd_host_port;
|
||||||
|
|
||||||
/* Skip leading whitespace. */
|
/* Skip leading whitespace. */
|
||||||
@ -229,21 +237,14 @@ process_config_line(Options *options, const char *host,
|
|||||||
if (!*cp || *cp == '\n' || *cp == '#')
|
if (!*cp || *cp == '\n' || *cp == '#')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Get the keyword. (Each line is supposed to begin with a
|
/* Get the keyword. (Each line is supposed to begin with a keyword). */
|
||||||
keyword). */
|
|
||||||
cp = strtok(cp, WHITESPACE);
|
cp = strtok(cp, WHITESPACE);
|
||||||
{
|
|
||||||
char *t = cp;
|
|
||||||
for (; *t != 0; t++)
|
|
||||||
if ('A' <= *t && *t <= 'Z')
|
|
||||||
*t = *t - 'A' + 'a'; /* tolower */
|
|
||||||
|
|
||||||
}
|
|
||||||
opcode = parse_token(cp, filename, linenum);
|
opcode = parse_token(cp, filename, linenum);
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case oBadOption:
|
case oBadOption:
|
||||||
return -1; /* don't panic, but count bad options */
|
/* don't panic, but count bad options */
|
||||||
|
return -1;
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
case oForwardAgent:
|
case oForwardAgent:
|
||||||
intptr = &options->forward_agent;
|
intptr = &options->forward_agent;
|
||||||
@ -419,17 +420,11 @@ parse_int:
|
|||||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||||
if (cp[0] < '0' || cp[0] > '9')
|
if (cp[0] < '0' || cp[0] > '9')
|
||||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||||
#if 0
|
|
||||||
value = atoi(cp);
|
/* Octal, decimal, or hex format? */
|
||||||
#else
|
value = strtol(cp, &cp2, 0);
|
||||||
{
|
if (cp == cp2)
|
||||||
char *ptr;
|
|
||||||
value = strtol(cp, &ptr, 0); /* Octal, decimal, or
|
|
||||||
hex format? */
|
|
||||||
if (cp == ptr)
|
|
||||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (*activep && *intptr == -1)
|
if (*activep && *intptr == -1)
|
||||||
*intptr = value;
|
*intptr = value;
|
||||||
break;
|
break;
|
||||||
@ -506,8 +501,7 @@ parse_int:
|
|||||||
*activep = 1;
|
*activep = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Avoid garbage check below, as strtok already returned
|
/* Avoid garbage check below, as strtok already returned NULL. */
|
||||||
NULL. */
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case oEscapeChar:
|
case oEscapeChar:
|
||||||
@ -544,9 +538,11 @@ parse_int:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Reads the config file and modifies the options accordingly. Options should
|
/*
|
||||||
already be initialized before this call. This never returns if there
|
* Reads the config file and modifies the options accordingly. Options
|
||||||
is an error. If the file does not exist, this returns immediately. */
|
* should already be initialized before this call. This never returns if
|
||||||
|
* there is an error. If the file does not exist, this returns immediately.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
read_config_file(const char *filename, const char *host, Options *options)
|
read_config_file(const char *filename, const char *host, Options *options)
|
||||||
@ -563,8 +559,10 @@ read_config_file(const char *filename, const char *host, Options *options)
|
|||||||
|
|
||||||
debug("Reading configuration data %.200s", filename);
|
debug("Reading configuration data %.200s", filename);
|
||||||
|
|
||||||
/* Mark that we are now processing the options. This flag is
|
/*
|
||||||
turned on/off by Host specifications. */
|
* Mark that we are now processing the options. This flag is turned
|
||||||
|
* on/off by Host specifications.
|
||||||
|
*/
|
||||||
active = 1;
|
active = 1;
|
||||||
linenum = 0;
|
linenum = 0;
|
||||||
while (fgets(line, sizeof(line), f)) {
|
while (fgets(line, sizeof(line), f)) {
|
||||||
@ -579,10 +577,12 @@ read_config_file(const char *filename, const char *host, Options *options)
|
|||||||
filename, bad_options);
|
filename, bad_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initializes options to special values that indicate that they have not
|
/*
|
||||||
yet been set. Read_config_file will only set options with this value.
|
* Initializes options to special values that indicate that they have not yet
|
||||||
Options are processed in the following order: command line, user config
|
* been set. Read_config_file will only set options with this value. Options
|
||||||
file, system config file. Last, fill_default_options is called. */
|
* are processed in the following order: command line, user config file,
|
||||||
|
* system config file. Last, fill_default_options is called.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
initialize_options(Options * options)
|
initialize_options(Options * options)
|
||||||
@ -628,8 +628,10 @@ initialize_options(Options * options)
|
|||||||
options->log_level = (LogLevel) - 1;
|
options->log_level = (LogLevel) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called after processing other sources of option data, this fills those
|
/*
|
||||||
options for which no value has been specified with their default values. */
|
* Called after processing other sources of option data, this fills those
|
||||||
|
* options for which no value has been specified with their default values.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
fill_default_options(Options * options)
|
fill_default_options(Options * options)
|
||||||
|
47
readconf.h
47
readconf.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: readconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: readconf.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef READCONF_H
|
#ifndef READCONF_H
|
||||||
#define READCONF_H
|
#define READCONF_H
|
||||||
@ -85,42 +85,53 @@ typedef struct {
|
|||||||
} Options;
|
} Options;
|
||||||
|
|
||||||
|
|
||||||
/* Initializes options to special values that indicate that they have not
|
/*
|
||||||
yet been set. Read_config_file will only set options with this value.
|
* Initializes options to special values that indicate that they have not yet
|
||||||
Options are processed in the following order: command line, user config
|
* been set. Read_config_file will only set options with this value. Options
|
||||||
file, system config file. Last, fill_default_options is called. */
|
* are processed in the following order: command line, user config file,
|
||||||
|
* system config file. Last, fill_default_options is called.
|
||||||
|
*/
|
||||||
void initialize_options(Options * options);
|
void initialize_options(Options * options);
|
||||||
|
|
||||||
/* Called after processing other sources of option data, this fills those
|
/*
|
||||||
options for which no value has been specified with their default values. */
|
* Called after processing other sources of option data, this fills those
|
||||||
|
* options for which no value has been specified with their default values.
|
||||||
|
*/
|
||||||
void fill_default_options(Options * options);
|
void fill_default_options(Options * options);
|
||||||
|
|
||||||
/* Processes a single option line as used in the configuration files.
|
/*
|
||||||
This only sets those values that have not already been set.
|
* Processes a single option line as used in the configuration files. This
|
||||||
Returns 0 for legal options */
|
* only sets those values that have not already been set. Returns 0 for legal
|
||||||
|
* options
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
process_config_line(Options * options, const char *host,
|
process_config_line(Options * options, const char *host,
|
||||||
char *line, const char *filename, int linenum,
|
char *line, const char *filename, int linenum,
|
||||||
int *activep);
|
int *activep);
|
||||||
|
|
||||||
/* Reads the config file and modifies the options accordingly. Options should
|
/*
|
||||||
already be initialized before this call. This never returns if there
|
* Reads the config file and modifies the options accordingly. Options
|
||||||
is an error. If the file does not exist, this returns immediately. */
|
* should already be initialized before this call. This never returns if
|
||||||
|
* there is an error. If the file does not exist, this returns immediately.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
read_config_file(const char *filename, const char *host,
|
read_config_file(const char *filename, const char *host,
|
||||||
Options * options);
|
Options * options);
|
||||||
|
|
||||||
/* Adds a local TCP/IP port forward to options. Never returns if there
|
/*
|
||||||
is an error. */
|
* Adds a local TCP/IP port forward to options. Never returns if there is an
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
add_local_forward(Options * options, int port, const char *host,
|
add_local_forward(Options * options, int port, const char *host,
|
||||||
int host_port);
|
int host_port);
|
||||||
|
|
||||||
/* Adds a remote TCP/IP port forward to options. Never returns if there
|
/*
|
||||||
is an error. */
|
* Adds a remote TCP/IP port forward to options. Never returns if there is
|
||||||
|
* an error.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
add_remote_forward(Options * options, int port, const char *host,
|
add_remote_forward(Options * options, int port, const char *host,
|
||||||
int host_port);
|
int host_port);
|
||||||
|
|
||||||
|
|
||||||
#endif /* READCONF_H */
|
#endif /* READCONF_H */
|
||||||
|
24
readpass.c
24
readpass.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: readpass.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: readpass.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -38,10 +38,12 @@ intr_handler(int sig)
|
|||||||
kill(getpid(), sig);
|
kill(getpid(), sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
/*
|
||||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||||
The passphrase if read from stdin if from_stdin is true (as is the
|
* passphrase (allocated with xmalloc). Exits if EOF is encountered. The
|
||||||
case with ssh-keygen). */
|
* passphrase if read from stdin if from_stdin is true (as is the case with
|
||||||
|
* ssh-keygen).
|
||||||
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
read_passphrase(const char *prompt, int from_stdin)
|
read_passphrase(const char *prompt, int from_stdin)
|
||||||
@ -53,8 +55,10 @@ read_passphrase(const char *prompt, int from_stdin)
|
|||||||
if (from_stdin)
|
if (from_stdin)
|
||||||
f = stdin;
|
f = stdin;
|
||||||
else {
|
else {
|
||||||
/* Read the passphrase from /dev/tty to make it possible
|
/*
|
||||||
to ask it even when stdin has been redirected. */
|
* Read the passphrase from /dev/tty to make it possible to
|
||||||
|
* ask it even when stdin has been redirected.
|
||||||
|
*/
|
||||||
f = fopen("/dev/tty", "r");
|
f = fopen("/dev/tty", "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
/* No controlling terminal and no DISPLAY. Nowhere to read. */
|
/* No controlling terminal and no DISPLAY. Nowhere to read. */
|
||||||
@ -101,8 +105,10 @@ read_passphrase(const char *prompt, int from_stdin)
|
|||||||
*strchr(buf, '\n') = 0;
|
*strchr(buf, '\n') = 0;
|
||||||
/* Allocate a copy of the passphrase. */
|
/* Allocate a copy of the passphrase. */
|
||||||
cp = xstrdup(buf);
|
cp = xstrdup(buf);
|
||||||
/* Clear the buffer so we don\'t leave copies of the passphrase
|
/*
|
||||||
laying around. */
|
* Clear the buffer so we don\'t leave copies of the passphrase
|
||||||
|
* laying around.
|
||||||
|
*/
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
/* Print a newline since the prompt probably didn\'t have one. */
|
/* Print a newline since the prompt probably didn\'t have one. */
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
10
rsa.c
10
rsa.c
@ -35,7 +35,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: rsa.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: rsa.c,v 1.5 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -55,9 +55,11 @@ rsa_alive()
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates RSA public and private keys. This initializes the data
|
/*
|
||||||
structures; they should be freed with rsa_clear_private_key and
|
* Generates RSA public and private keys. This initializes the data
|
||||||
rsa_clear_public_key. */
|
* structures; they should be freed with rsa_clear_private_key and
|
||||||
|
* rsa_clear_public_key.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)
|
rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)
|
||||||
|
8
rsa.h
8
rsa.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: rsa.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef RSA_H
|
#ifndef RSA_H
|
||||||
#define RSA_H
|
#define RSA_H
|
||||||
@ -33,8 +33,10 @@
|
|||||||
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
||||||
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
|
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
|
||||||
|
|
||||||
/* Indicates whether the rsa module is permitted to show messages on
|
/*
|
||||||
the terminal. */
|
* Indicates whether the rsa module is permitted to show messages on the
|
||||||
|
* terminal.
|
||||||
|
*/
|
||||||
void rsa_set_verbose __P((int verbose));
|
void rsa_set_verbose __P((int verbose));
|
||||||
|
|
||||||
int rsa_alive __P((void));
|
int rsa_alive __P((void));
|
||||||
|
20
scp.c
20
scp.c
@ -45,7 +45,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: scp.c,v 1.9 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: scp.c,v 1.10 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
@ -97,9 +97,11 @@ char *identity = NULL;
|
|||||||
/* This is the port to use in contacting the remote site (is non-NULL). */
|
/* This is the port to use in contacting the remote site (is non-NULL). */
|
||||||
char *port = NULL;
|
char *port = NULL;
|
||||||
|
|
||||||
/* This function executes the given command as the specified user on the given
|
/*
|
||||||
host. This returns < 0 if execution fails, and >= 0 otherwise.
|
* This function executes the given command as the specified user on the
|
||||||
This assigns the input and output file descriptors on success. */
|
* given host. This returns < 0 if execution fails, and >= 0 otherwise. This
|
||||||
|
* assigns the input and output file descriptors on success.
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
|
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
|
||||||
@ -110,8 +112,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
|
|||||||
fprintf(stderr, "Executing: host %s, user %s, command %s\n",
|
fprintf(stderr, "Executing: host %s, user %s, command %s\n",
|
||||||
host, remuser ? remuser : "(unspecified)", cmd);
|
host, remuser ? remuser : "(unspecified)", cmd);
|
||||||
|
|
||||||
/* Reserve two descriptors so that the real pipes won't get
|
/*
|
||||||
descriptors 0 and 1 because that will screw up dup2 below. */
|
* Reserve two descriptors so that the real pipes won't get
|
||||||
|
* descriptors 0 and 1 because that will screw up dup2 below.
|
||||||
|
*/
|
||||||
pipe(reserved);
|
pipe(reserved);
|
||||||
|
|
||||||
/* Create a socket pair for communicating with ssh. */
|
/* Create a socket pair for communicating with ssh. */
|
||||||
@ -970,7 +974,7 @@ run_err(const char *fmt,...)
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: scp.c,v 1.9 1999/11/24 13:26:22 damien Exp $
|
* $Id: scp.c,v 1.10 1999/11/25 00:54:59 damien Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *
|
char *
|
||||||
@ -1142,7 +1146,7 @@ progressmeter(int flag)
|
|||||||
(void) gettimeofday(&now, (struct timezone *) 0);
|
(void) gettimeofday(&now, (struct timezone *) 0);
|
||||||
cursize = statbytes;
|
cursize = statbytes;
|
||||||
if (totalbytes != 0) {
|
if (totalbytes != 0) {
|
||||||
ratio = cursize * 100.0 / totalbytes;
|
ratio = 100.0 * cursize / totalbytes;
|
||||||
ratio = MAX(ratio, 0);
|
ratio = MAX(ratio, 0);
|
||||||
ratio = MIN(ratio, 100);
|
ratio = MIN(ratio, 100);
|
||||||
} else
|
} else
|
||||||
|
17
servconf.c
17
servconf.c
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: servconf.c,v 1.6 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: servconf.c,v 1.7 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "servconf.h"
|
#include "servconf.h"
|
||||||
@ -212,8 +212,10 @@ static struct {
|
|||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Returns the number of the token pointed to by cp of length len.
|
/*
|
||||||
Never returns if the token is not known. */
|
* Returns the number of the token pointed to by cp of length len. Never
|
||||||
|
* returns if the token is not known.
|
||||||
|
*/
|
||||||
|
|
||||||
static ServerOpCodes
|
static ServerOpCodes
|
||||||
parse_token(const char *cp, const char *filename,
|
parse_token(const char *cp, const char *filename,
|
||||||
@ -222,7 +224,7 @@ parse_token(const char *cp, const char *filename,
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; keywords[i].name; i++)
|
for (i = 0; keywords[i].name; i++)
|
||||||
if (strcmp(cp, keywords[i].name) == 0)
|
if (strcasecmp(cp, keywords[i].name) == 0)
|
||||||
return keywords[i].opcode;
|
return keywords[i].opcode;
|
||||||
|
|
||||||
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
||||||
@ -254,13 +256,6 @@ read_server_config(ServerOptions *options, const char *filename)
|
|||||||
if (!*cp || *cp == '#')
|
if (!*cp || *cp == '#')
|
||||||
continue;
|
continue;
|
||||||
cp = strtok(cp, WHITESPACE);
|
cp = strtok(cp, WHITESPACE);
|
||||||
{
|
|
||||||
char *t = cp;
|
|
||||||
for (; *t != 0; t++)
|
|
||||||
if ('A' <= *t && *t <= 'Z')
|
|
||||||
*t = *t - 'A' + 'a'; /* tolower */
|
|
||||||
|
|
||||||
}
|
|
||||||
opcode = parse_token(cp, filename, linenum);
|
opcode = parse_token(cp, filename, linenum);
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case sBadOption:
|
case sBadOption:
|
||||||
|
14
servconf.h
14
servconf.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: servconf.h,v 1.4 1999/11/24 13:26:22 damien Exp $"); */
|
/* RCSID("$Id: servconf.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef SERVCONF_H
|
#ifndef SERVCONF_H
|
||||||
#define SERVCONF_H
|
#define SERVCONF_H
|
||||||
@ -84,12 +84,16 @@ typedef struct {
|
|||||||
unsigned int num_deny_groups;
|
unsigned int num_deny_groups;
|
||||||
char *deny_groups[MAX_DENY_GROUPS];
|
char *deny_groups[MAX_DENY_GROUPS];
|
||||||
} ServerOptions;
|
} ServerOptions;
|
||||||
/* Initializes the server options to special values that indicate that they
|
/*
|
||||||
have not yet been set. */
|
* Initializes the server options to special values that indicate that they
|
||||||
|
* have not yet been set.
|
||||||
|
*/
|
||||||
void initialize_server_options(ServerOptions * options);
|
void initialize_server_options(ServerOptions * options);
|
||||||
|
|
||||||
/* Reads the server configuration file. This only sets the values for those
|
/*
|
||||||
options that have the special value indicating they have not been set. */
|
* Reads the server configuration file. This only sets the values for those
|
||||||
|
* options that have the special value indicating they have not been set.
|
||||||
|
*/
|
||||||
void read_server_config(ServerOptions * options, const char *filename);
|
void read_server_config(ServerOptions * options, const char *filename);
|
||||||
|
|
||||||
/* Sets values for those values that have not yet been set. */
|
/* Sets values for those values that have not yet been set. */
|
||||||
|
114
serverloop.c
114
serverloop.c
@ -33,8 +33,10 @@ static int connection_out; /* Connection to client (output). */
|
|||||||
static unsigned int buffer_high;/* "Soft" max buffer size. */
|
static unsigned int buffer_high;/* "Soft" max buffer size. */
|
||||||
static int max_fd; /* Max file descriptor number for select(). */
|
static int max_fd; /* Max file descriptor number for select(). */
|
||||||
|
|
||||||
/* This SIGCHLD kludge is used to detect when the child exits. The server
|
/*
|
||||||
will exit after that, as soon as forwarded connections have terminated. */
|
* This SIGCHLD kludge is used to detect when the child exits. The server
|
||||||
|
* will exit after that, as soon as forwarded connections have terminated.
|
||||||
|
*/
|
||||||
|
|
||||||
static int child_pid; /* Pid of the child. */
|
static int child_pid; /* Pid of the child. */
|
||||||
static volatile int child_terminated; /* The child has terminated. */
|
static volatile int child_terminated; /* The child has terminated. */
|
||||||
@ -87,9 +89,11 @@ process_buffered_input_packets()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SSH_CMSG_EOF:
|
case SSH_CMSG_EOF:
|
||||||
/* Eof from the client. The stdin descriptor to
|
/*
|
||||||
the program will be closed when all buffered
|
* Eof from the client. The stdin descriptor to the
|
||||||
data has drained. */
|
* program will be closed when all buffered data has
|
||||||
|
* drained.
|
||||||
|
*/
|
||||||
debug("EOF received for stdin.");
|
debug("EOF received for stdin.");
|
||||||
packet_integrity_check(payload_len, 0, type);
|
packet_integrity_check(payload_len, 0, type);
|
||||||
stdin_eof = 1;
|
stdin_eof = 1;
|
||||||
@ -140,13 +144,15 @@ process_buffered_input_packets()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* In this phase, any unexpected messages cause a
|
/*
|
||||||
protocol error. This is to ease debugging;
|
* In this phase, any unexpected messages cause a
|
||||||
also, since no confirmations are sent messages,
|
* protocol error. This is to ease debugging; also,
|
||||||
unprocessed unknown messages could cause
|
* since no confirmations are sent messages,
|
||||||
strange problems. Any compatible protocol
|
* unprocessed unknown messages could cause strange
|
||||||
extensions must be negotiated before entering
|
* problems. Any compatible protocol extensions must
|
||||||
the interactive session. */
|
* be negotiated before entering the interactive
|
||||||
|
* session.
|
||||||
|
*/
|
||||||
packet_disconnect("Protocol error during session: type %d",
|
packet_disconnect("Protocol error during session: type %d",
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
@ -230,14 +236,18 @@ retry_select:
|
|||||||
/* Initialize select() masks. */
|
/* Initialize select() masks. */
|
||||||
FD_ZERO(readset);
|
FD_ZERO(readset);
|
||||||
|
|
||||||
/* Read packets from the client unless we have too much buffered
|
/*
|
||||||
stdin or channel data. */
|
* Read packets from the client unless we have too much buffered
|
||||||
|
* stdin or channel data.
|
||||||
|
*/
|
||||||
if (buffer_len(&stdin_buffer) < 4096 &&
|
if (buffer_len(&stdin_buffer) < 4096 &&
|
||||||
channel_not_very_much_buffered_data())
|
channel_not_very_much_buffered_data())
|
||||||
FD_SET(connection_in, readset);
|
FD_SET(connection_in, readset);
|
||||||
|
|
||||||
/* If there is not too much data already buffered going to the
|
/*
|
||||||
client, try to get some more data from the program. */
|
* If there is not too much data already buffered going to the
|
||||||
|
* client, try to get some more data from the program.
|
||||||
|
*/
|
||||||
if (packet_not_very_much_data_to_write()) {
|
if (packet_not_very_much_data_to_write()) {
|
||||||
if (!fdout_eof)
|
if (!fdout_eof)
|
||||||
FD_SET(fdout, readset);
|
FD_SET(fdout, readset);
|
||||||
@ -249,8 +259,10 @@ retry_select:
|
|||||||
/* Set masks for channel descriptors. */
|
/* Set masks for channel descriptors. */
|
||||||
channel_prepare_select(readset, writeset);
|
channel_prepare_select(readset, writeset);
|
||||||
|
|
||||||
/* If we have buffered packet data going to the client, mark that
|
/*
|
||||||
descriptor. */
|
* If we have buffered packet data going to the client, mark that
|
||||||
|
* descriptor.
|
||||||
|
*/
|
||||||
if (packet_have_data_to_write())
|
if (packet_have_data_to_write())
|
||||||
FD_SET(connection_out, writeset);
|
FD_SET(connection_out, writeset);
|
||||||
|
|
||||||
@ -263,8 +275,10 @@ retry_select:
|
|||||||
if (channel_max_fd() > max_fd)
|
if (channel_max_fd() > max_fd)
|
||||||
max_fd = channel_max_fd();
|
max_fd = channel_max_fd();
|
||||||
|
|
||||||
/* If child has terminated and there is enough buffer space to
|
/*
|
||||||
read from it, then read as much as is available and exit. */
|
* If child has terminated and there is enough buffer space to read
|
||||||
|
* from it, then read as much as is available and exit.
|
||||||
|
*/
|
||||||
if (child_terminated && packet_not_very_much_data_to_write())
|
if (child_terminated && packet_not_very_much_data_to_write())
|
||||||
if (max_time_milliseconds == 0)
|
if (max_time_milliseconds == 0)
|
||||||
max_time_milliseconds = 100;
|
max_time_milliseconds = 100;
|
||||||
@ -305,9 +319,10 @@ process_input(fd_set * readset)
|
|||||||
verbose("Connection closed by remote host.");
|
verbose("Connection closed by remote host.");
|
||||||
fatal_cleanup();
|
fatal_cleanup();
|
||||||
}
|
}
|
||||||
/* There is a kernel bug on Solaris that causes select to
|
/*
|
||||||
sometimes wake up even though there is no data
|
* There is a kernel bug on Solaris that causes select to
|
||||||
available. */
|
* sometimes wake up even though there is no data available.
|
||||||
|
*/
|
||||||
if (len < 0 && errno == EAGAIN)
|
if (len < 0 && errno == EAGAIN)
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
@ -456,11 +471,12 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
|||||||
buffer_init(&stdout_buffer);
|
buffer_init(&stdout_buffer);
|
||||||
buffer_init(&stderr_buffer);
|
buffer_init(&stderr_buffer);
|
||||||
|
|
||||||
/* If we have no separate fderr (which is the case when we have a
|
/*
|
||||||
pty - there we cannot make difference between data sent to
|
* If we have no separate fderr (which is the case when we have a pty
|
||||||
stdout and stderr), indicate that we have seen an EOF from
|
* - there we cannot make difference between data sent to stdout and
|
||||||
stderr. This way we don\'t need to check the descriptor
|
* stderr), indicate that we have seen an EOF from stderr. This way
|
||||||
everywhere. */
|
* we don\'t need to check the descriptor everywhere.
|
||||||
|
*/
|
||||||
if (fderr == -1)
|
if (fderr == -1)
|
||||||
fderr_eof = 1;
|
fderr_eof = 1;
|
||||||
|
|
||||||
@ -471,8 +487,10 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
|||||||
/* Process buffered packets from the client. */
|
/* Process buffered packets from the client. */
|
||||||
process_buffered_input_packets();
|
process_buffered_input_packets();
|
||||||
|
|
||||||
/* If we have received eof, and there is no more pending
|
/*
|
||||||
input data, cause a real eof by closing fdin. */
|
* If we have received eof, and there is no more pending
|
||||||
|
* input data, cause a real eof by closing fdin.
|
||||||
|
*/
|
||||||
if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
|
if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) {
|
||||||
#ifdef USE_PIPES
|
#ifdef USE_PIPES
|
||||||
close(fdin);
|
close(fdin);
|
||||||
@ -484,16 +502,16 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
|||||||
#endif
|
#endif
|
||||||
fdin = -1;
|
fdin = -1;
|
||||||
}
|
}
|
||||||
/* Make packets from buffered stderr data to send to the
|
/* Make packets from buffered stderr data to send to the client. */
|
||||||
client. */
|
|
||||||
make_packets_from_stderr_data();
|
make_packets_from_stderr_data();
|
||||||
|
|
||||||
/* Make packets from buffered stdout data to send to the
|
/*
|
||||||
client. If there is very little to send, this arranges
|
* Make packets from buffered stdout data to send to the
|
||||||
to not send them now, but to wait a short while to see
|
* client. If there is very little to send, this arranges to
|
||||||
if we are getting more data. This is necessary, as some
|
* not send them now, but to wait a short while to see if we
|
||||||
systems wake up readers from a pty after each separate
|
* are getting more data. This is necessary, as some systems
|
||||||
character. */
|
* wake up readers from a pty after each separate character.
|
||||||
|
*/
|
||||||
max_time_milliseconds = 0;
|
max_time_milliseconds = 0;
|
||||||
stdout_buffer_bytes = buffer_len(&stdout_buffer);
|
stdout_buffer_bytes = buffer_len(&stdout_buffer);
|
||||||
if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
|
if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 &&
|
||||||
@ -510,9 +528,11 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
|||||||
if (packet_not_very_much_data_to_write())
|
if (packet_not_very_much_data_to_write())
|
||||||
channel_output_poll();
|
channel_output_poll();
|
||||||
|
|
||||||
/* Bail out of the loop if the program has closed its
|
/*
|
||||||
output descriptors, and we have no more data to send to
|
* Bail out of the loop if the program has closed its output
|
||||||
the client, and there is no pending buffered data. */
|
* descriptors, and we have no more data to send to the
|
||||||
|
* client, and there is no pending buffered data.
|
||||||
|
*/
|
||||||
if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
|
if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
|
||||||
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
|
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
|
||||||
if (!channel_still_open())
|
if (!channel_still_open())
|
||||||
@ -604,11 +624,13 @@ quit:
|
|||||||
packet_send();
|
packet_send();
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
|
|
||||||
/* Wait for exit confirmation. Note that there might be
|
/*
|
||||||
other packets coming before it; however, the program
|
* Wait for exit confirmation. Note that there might be
|
||||||
has already died so we just ignore them. The client is
|
* other packets coming before it; however, the program has
|
||||||
supposed to respond with the confirmation when it
|
* already died so we just ignore them. The client is
|
||||||
receives the exit status. */
|
* supposed to respond with the confirmation when it receives
|
||||||
|
* the exit status.
|
||||||
|
*/
|
||||||
do {
|
do {
|
||||||
int plen;
|
int plen;
|
||||||
type = packet_read(&plen);
|
type = packet_read(&plen);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: ssh-add.1,v 1.4 1999/11/17 06:29:08 damien Exp $
|
.\" $Id: ssh-add.1,v 1.5 1999/11/25 00:54:59 damien Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd September 25, 1999
|
.Dd September 25, 1999
|
||||||
.Dt SSH-ADD 1
|
.Dt SSH-ADD 1
|
||||||
@ -71,8 +71,11 @@ terminal if it was run from a terminal. If
|
|||||||
.Nm
|
.Nm
|
||||||
does not have a terminal associated with it but
|
does not have a terminal associated with it but
|
||||||
.Ev DISPLAY
|
.Ev DISPLAY
|
||||||
is set, it
|
and
|
||||||
will open an X11 window to read the passphrase. This is particularly
|
.Ev SSH_ASKPASS
|
||||||
|
are set, it will execute the program specified by
|
||||||
|
.Ev SSH_ASKPASS
|
||||||
|
and open an X11 window to read the passphrase. This is particularly
|
||||||
useful when calling
|
useful when calling
|
||||||
.Nm
|
.Nm
|
||||||
from a
|
from a
|
||||||
|
161
ssh-add.c
161
ssh-add.c
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ssh-add.c,v 1.13 1999/11/24 13:26:22 damien Exp $");
|
RCSID("$Id: ssh-add.c,v 1.14 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -15,10 +15,6 @@ RCSID("$Id: ssh-add.c,v 1.13 1999/11/24 13:26:22 damien Exp $");
|
|||||||
#include "authfd.h"
|
#include "authfd.h"
|
||||||
#include "fingerprint.h"
|
#include "fingerprint.h"
|
||||||
|
|
||||||
#ifdef USE_EXTERNAL_ASKPASS
|
|
||||||
int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment);
|
|
||||||
#endif /* USE_EXTERNAL_ASKPASS */
|
|
||||||
|
|
||||||
#ifdef HAVE___PROGNAME
|
#ifdef HAVE___PROGNAME
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
#else /* HAVE___PROGNAME */
|
#else /* HAVE___PROGNAME */
|
||||||
@ -54,13 +50,53 @@ delete_all(AuthenticationConnection *ac)
|
|||||||
fprintf(stderr, "Failed to remove all identitities.\n");
|
fprintf(stderr, "Failed to remove all identitities.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
ssh_askpass(char *askpass, char *msg)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
size_t len;
|
||||||
|
char *nl, *pass;
|
||||||
|
int p[2], status;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (askpass == NULL)
|
||||||
|
fatal("internal error: askpass undefined");
|
||||||
|
if (pipe(p) < 0)
|
||||||
|
fatal("ssh_askpass: pipe: %s", strerror(errno));
|
||||||
|
if ((pid = fork()) < 0)
|
||||||
|
fatal("ssh_askpass: fork: %s", strerror(errno));
|
||||||
|
if (pid == 0) {
|
||||||
|
close(p[0]);
|
||||||
|
if (dup2(p[1], STDOUT_FILENO) < 0)
|
||||||
|
fatal("ssh_askpass: dup2: %s", strerror(errno));
|
||||||
|
execlp(askpass, askpass, msg, (char *) 0);
|
||||||
|
fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
|
||||||
|
}
|
||||||
|
close(p[1]);
|
||||||
|
len = read(p[0], buf, sizeof buf);
|
||||||
|
close(p[0]);
|
||||||
|
while (waitpid(pid, &status, 0) < 0)
|
||||||
|
if (errno != EINTR)
|
||||||
|
break;
|
||||||
|
if (len <= 1)
|
||||||
|
return xstrdup("");
|
||||||
|
nl = strchr(buf, '\n');
|
||||||
|
if (nl)
|
||||||
|
*nl = '\0';
|
||||||
|
pass = xstrdup(buf);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
add_file(AuthenticationConnection *ac, const char *filename)
|
add_file(AuthenticationConnection *ac, const char *filename)
|
||||||
{
|
{
|
||||||
RSA *key;
|
RSA *key;
|
||||||
RSA *public_key;
|
RSA *public_key;
|
||||||
char *saved_comment, *comment;
|
char *saved_comment, *comment, *askpass = NULL;
|
||||||
|
char buf[1024], msg[1024];
|
||||||
int success;
|
int success;
|
||||||
|
int interactive = isatty(STDIN_FILENO);
|
||||||
|
|
||||||
key = RSA_new();
|
key = RSA_new();
|
||||||
public_key = RSA_new();
|
public_key = RSA_new();
|
||||||
@ -70,29 +106,26 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||||||
}
|
}
|
||||||
RSA_free(public_key);
|
RSA_free(public_key);
|
||||||
|
|
||||||
|
if (!interactive && getenv("DISPLAY"))
|
||||||
|
askpass = getenv("SSH_ASKPASS");
|
||||||
|
|
||||||
/* At first, try empty passphrase */
|
/* At first, try empty passphrase */
|
||||||
success = load_private_key(filename, "", key, &comment);
|
success = load_private_key(filename, "", key, &comment);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
printf("Need passphrase for %s (%s).\n", filename, saved_comment);
|
printf("Need passphrase for %.200s\n", filename);
|
||||||
if (!isatty(STDIN_FILENO)) {
|
if (!interactive && askpass == NULL) {
|
||||||
#ifdef USE_EXTERNAL_ASKPASS
|
|
||||||
int prompts = 3;
|
|
||||||
while (prompts && !success) {
|
|
||||||
success = askpass(filename, key, saved_comment, &comment);
|
|
||||||
prompts--;
|
|
||||||
}
|
|
||||||
if (!success) {
|
|
||||||
xfree(saved_comment);
|
xfree(saved_comment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else /* !USE_EXTERNAL_ASKPASS */
|
snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
|
||||||
xfree(saved_comment);
|
for (;;) {
|
||||||
return;
|
char *pass;
|
||||||
#endif /* USE_EXTERNAL_ASKPASS */
|
if (interactive) {
|
||||||
|
snprintf(buf, sizeof buf, "%s: ", msg);
|
||||||
|
pass = read_passphrase(buf, 1);
|
||||||
|
} else {
|
||||||
|
pass = ssh_askpass(askpass, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!success) {
|
|
||||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
|
||||||
if (strcmp(pass, "") == 0) {
|
if (strcmp(pass, "") == 0) {
|
||||||
xfree(pass);
|
xfree(pass);
|
||||||
xfree(saved_comment);
|
xfree(saved_comment);
|
||||||
@ -103,7 +136,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||||||
xfree(pass);
|
xfree(pass);
|
||||||
if (success)
|
if (success)
|
||||||
break;
|
break;
|
||||||
printf("Bad passphrase.\n");
|
strlcpy(msg, "Bad passphrase, try again", sizeof msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xfree(saved_comment);
|
xfree(saved_comment);
|
||||||
@ -222,85 +255,3 @@ main(int argc, char **argv)
|
|||||||
ssh_close_authentication_connection(ac);
|
ssh_close_authentication_connection(ac);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_EXTERNAL_ASKPASS
|
|
||||||
int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment)
|
|
||||||
{
|
|
||||||
int pipes[2];
|
|
||||||
char buf[1024];
|
|
||||||
int tmp;
|
|
||||||
pid_t child;
|
|
||||||
FILE *pipef;
|
|
||||||
|
|
||||||
/* Check that we are X11-capable */
|
|
||||||
if (getenv("DISPLAY") == NULL)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
if (pipe(pipes) == -1) {
|
|
||||||
fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fflush(NULL) == EOF) {
|
|
||||||
fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
child = fork();
|
|
||||||
if (child == -1) {
|
|
||||||
fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child == 0) {
|
|
||||||
/* In child */
|
|
||||||
|
|
||||||
close(pipes[0]);
|
|
||||||
if (dup2(pipes[1], 1) ==-1) {
|
|
||||||
fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment);
|
|
||||||
/* skip the prompt if it won't fit */
|
|
||||||
if ((tmp < 0) || (tmp >= sizeof(buf)))
|
|
||||||
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
|
|
||||||
else
|
|
||||||
tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
|
|
||||||
|
|
||||||
/* Shouldn't get this far */
|
|
||||||
fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In parent */
|
|
||||||
close(pipes[1]);
|
|
||||||
|
|
||||||
if ((pipef = fdopen(pipes[0], "r")) == NULL) {
|
|
||||||
fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read passphrase back from child, abort if none presented */
|
|
||||||
if(fgets(buf, sizeof(buf), pipef) == NULL)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
fclose(pipef);
|
|
||||||
|
|
||||||
if (strchr(buf, '\n'))
|
|
||||||
*strchr(buf, '\n') = 0;
|
|
||||||
|
|
||||||
if (waitpid(child, NULL, 0) == -1) {
|
|
||||||
fprintf(stderr, "Waiting for child failed: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try password as it was presented */
|
|
||||||
tmp = load_private_key(filename, buf, key, comment);
|
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
|
||||||
|
|
||||||
return(tmp);
|
|
||||||
}
|
|
||||||
#endif /* USE_EXTERNAL_ASKPASS */
|
|
||||||
|
37
ssh-agent.c
37
ssh-agent.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $ */
|
/* $OpenBSD: ssh-agent.c,v 1.23 1999/11/24 19:53:51 markus Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: ssh-agent.c,v 1.22 1999/11/24 00:26:03 deraadt Exp $");
|
RCSID("$OpenBSD: ssh-agent.c,v 1.23 1999/11/24 19:53:51 markus Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -189,10 +189,12 @@ process_remove_identity(SocketEntry *e)
|
|||||||
/* Check if we have the key. */
|
/* Check if we have the key. */
|
||||||
for (i = 0; i < num_identities; i++)
|
for (i = 0; i < num_identities; i++)
|
||||||
if (BN_cmp(identities[i].key->n, n) == 0) {
|
if (BN_cmp(identities[i].key->n, n) == 0) {
|
||||||
/* We have this key. Free the old key. Since we
|
/*
|
||||||
don\'t want to leave empty slots in the middle
|
* We have this key. Free the old key. Since we
|
||||||
of the array, we actually free the key there
|
* don\'t want to leave empty slots in the middle of
|
||||||
and copy data from the last entry. */
|
* the array, we actually free the key there and copy
|
||||||
|
* data from the last entry.
|
||||||
|
*/
|
||||||
RSA_free(identities[i].key);
|
RSA_free(identities[i].key);
|
||||||
xfree(identities[i].comment);
|
xfree(identities[i].comment);
|
||||||
if (i < num_identities - 1)
|
if (i < num_identities - 1)
|
||||||
@ -291,8 +293,10 @@ process_add_identity(SocketEntry *e)
|
|||||||
/* Check if we already have the key. */
|
/* Check if we already have the key. */
|
||||||
for (i = 0; i < num_identities; i++)
|
for (i = 0; i < num_identities; i++)
|
||||||
if (BN_cmp(identities[i].key->n, k->n) == 0) {
|
if (BN_cmp(identities[i].key->n, k->n) == 0) {
|
||||||
/* We already have this key. Clear and free the
|
/*
|
||||||
new data and return success. */
|
* We already have this key. Clear and free the new
|
||||||
|
* data and return success.
|
||||||
|
*/
|
||||||
RSA_free(k);
|
RSA_free(k);
|
||||||
xfree(identities[num_identities].comment);
|
xfree(identities[num_identities].comment);
|
||||||
|
|
||||||
@ -511,11 +515,7 @@ main(int ac, char **av)
|
|||||||
__progname);
|
__progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#if defined(__GNU_LIBRARY__)
|
|
||||||
while ((ch = getopt(ac, av, "+cks")) != -1) {
|
|
||||||
#else
|
|
||||||
while ((ch = getopt(ac, av, "cks")) != -1) {
|
while ((ch = getopt(ac, av, "cks")) != -1) {
|
||||||
#endif /* defined(__GNU_LIBRARY__) */
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'c':
|
case 'c':
|
||||||
if (s_flag)
|
if (s_flag)
|
||||||
@ -579,8 +579,10 @@ main(int ac, char **av)
|
|||||||
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
|
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
|
||||||
parent_pid);
|
parent_pid);
|
||||||
|
|
||||||
/* Create socket early so it will exist before command gets run
|
/*
|
||||||
from the parent. */
|
* Create socket early so it will exist before command gets run from
|
||||||
|
* the parent.
|
||||||
|
*/
|
||||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
@ -597,9 +599,10 @@ main(int ac, char **av)
|
|||||||
perror("listen");
|
perror("listen");
|
||||||
cleanup_exit(1);
|
cleanup_exit(1);
|
||||||
}
|
}
|
||||||
/* Fork, and have the parent execute the command, if any, or
|
/*
|
||||||
present the socket data. The child continues as the
|
* Fork, and have the parent execute the command, if any, or present
|
||||||
authentication agent. */
|
* the socket data. The child continues as the authentication agent.
|
||||||
|
*/
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
perror("fork");
|
perror("fork");
|
||||||
|
55
ssh-keygen.c
55
ssh-keygen.c
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ssh-keygen.c,v 1.9 1999/11/24 13:26:23 damien Exp $");
|
RCSID("$Id: ssh-keygen.c,v 1.10 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -20,16 +20,19 @@ RSA *private_key;
|
|||||||
/* Generated public key. */
|
/* Generated public key. */
|
||||||
RSA *public_key;
|
RSA *public_key;
|
||||||
|
|
||||||
/* Number of bits in the RSA key. This value can be changed on the command
|
/* Number of bits in the RSA key. This value can be changed on the command line. */
|
||||||
line. */
|
|
||||||
int bits = 1024;
|
int bits = 1024;
|
||||||
|
|
||||||
/* Flag indicating that we just want to change the passphrase. This can be
|
/*
|
||||||
set on the command line. */
|
* Flag indicating that we just want to change the passphrase. This can be
|
||||||
|
* set on the command line.
|
||||||
|
*/
|
||||||
int change_passphrase = 0;
|
int change_passphrase = 0;
|
||||||
|
|
||||||
/* Flag indicating that we just want to change the comment. This can be set
|
/*
|
||||||
on the command line. */
|
* Flag indicating that we just want to change the comment. This can be set
|
||||||
|
* on the command line.
|
||||||
|
*/
|
||||||
int change_comment = 0;
|
int change_comment = 0;
|
||||||
|
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
@ -136,13 +139,10 @@ do_change_passphrase(struct passwd *pw)
|
|||||||
|
|
||||||
if (!have_identity)
|
if (!have_identity)
|
||||||
ask_filename(pw, "Enter file in which the key is");
|
ask_filename(pw, "Enter file in which the key is");
|
||||||
/* Check if the file exists. */
|
|
||||||
if (stat(identity_file, &st) < 0) {
|
if (stat(identity_file, &st) < 0) {
|
||||||
perror(identity_file);
|
perror(identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Try to load the public key from the file the verify that it is
|
|
||||||
readable and of the proper format. */
|
|
||||||
public_key = RSA_new();
|
public_key = RSA_new();
|
||||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||||
printf("%s is not a valid key file.\n", identity_file);
|
printf("%s is not a valid key file.\n", identity_file);
|
||||||
@ -154,19 +154,16 @@ do_change_passphrase(struct passwd *pw)
|
|||||||
/* Try to load the file with empty passphrase. */
|
/* Try to load the file with empty passphrase. */
|
||||||
private_key = RSA_new();
|
private_key = RSA_new();
|
||||||
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
||||||
/* Read passphrase from the user. */
|
|
||||||
if (identity_passphrase)
|
if (identity_passphrase)
|
||||||
old_passphrase = xstrdup(identity_passphrase);
|
old_passphrase = xstrdup(identity_passphrase);
|
||||||
else
|
else
|
||||||
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
|
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
|
||||||
/* Try to load using the passphrase. */
|
|
||||||
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
|
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
|
||||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||||
xfree(old_passphrase);
|
xfree(old_passphrase);
|
||||||
printf("Bad passphrase.\n");
|
printf("Bad passphrase.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Destroy the passphrase. */
|
|
||||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||||
xfree(old_passphrase);
|
xfree(old_passphrase);
|
||||||
}
|
}
|
||||||
@ -230,24 +227,24 @@ do_change_comment(struct passwd *pw)
|
|||||||
|
|
||||||
if (!have_identity)
|
if (!have_identity)
|
||||||
ask_filename(pw, "Enter file in which the key is");
|
ask_filename(pw, "Enter file in which the key is");
|
||||||
/* Check if the file exists. */
|
|
||||||
if (stat(identity_file, &st) < 0) {
|
if (stat(identity_file, &st) < 0) {
|
||||||
perror(identity_file);
|
perror(identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Try to load the public key from the file the verify that it is
|
/*
|
||||||
readable and of the proper format. */
|
* Try to load the public key from the file the verify that it is
|
||||||
|
* readable and of the proper format.
|
||||||
|
*/
|
||||||
public_key = RSA_new();
|
public_key = RSA_new();
|
||||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||||
printf("%s is not a valid key file.\n", identity_file);
|
printf("%s is not a valid key file.\n", identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
private_key = RSA_new();
|
private_key = RSA_new();
|
||||||
/* Try to load the file with empty passphrase. */
|
|
||||||
if (load_private_key(identity_file, "", private_key, &comment))
|
if (load_private_key(identity_file, "", private_key, &comment))
|
||||||
passphrase = xstrdup("");
|
passphrase = xstrdup("");
|
||||||
else {
|
else {
|
||||||
/* Read passphrase from the user. */
|
|
||||||
if (identity_passphrase)
|
if (identity_passphrase)
|
||||||
passphrase = xstrdup(identity_passphrase);
|
passphrase = xstrdup(identity_passphrase);
|
||||||
else if (identity_new_passphrase)
|
else if (identity_new_passphrase)
|
||||||
@ -274,7 +271,6 @@ do_change_comment(struct passwd *pw)
|
|||||||
RSA_free(private_key);
|
RSA_free(private_key);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Remove terminating newline from comment. */
|
|
||||||
if (strchr(new_comment, '\n'))
|
if (strchr(new_comment, '\n'))
|
||||||
*strchr(new_comment, '\n') = 0;
|
*strchr(new_comment, '\n') = 0;
|
||||||
}
|
}
|
||||||
@ -289,13 +285,10 @@ do_change_comment(struct passwd *pw)
|
|||||||
xfree(comment);
|
xfree(comment);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Destroy the passphrase and the private key in memory. */
|
|
||||||
memset(passphrase, 0, strlen(passphrase));
|
memset(passphrase, 0, strlen(passphrase));
|
||||||
xfree(passphrase);
|
xfree(passphrase);
|
||||||
RSA_free(private_key);
|
RSA_free(private_key);
|
||||||
|
|
||||||
/* Save the public key in text format in a file with the same name
|
|
||||||
but .pub appended. */
|
|
||||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||||
f = fopen(identity_file, "w");
|
f = fopen(identity_file, "w");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
@ -343,21 +336,18 @@ main(int ac, char **av)
|
|||||||
|
|
||||||
/* check if RSA support exists */
|
/* check if RSA support exists */
|
||||||
if (rsa_alive() == 0) {
|
if (rsa_alive() == 0) {
|
||||||
extern char *__progname;
|
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||||
__progname);
|
__progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Get user\'s passwd structure. We need this for the home
|
/* we need this for the home * directory. */
|
||||||
directory. */
|
|
||||||
pw = getpwuid(getuid());
|
pw = getpwuid(getuid());
|
||||||
if (!pw) {
|
if (!pw) {
|
||||||
printf("You don't exist, go away!\n");
|
printf("You don't exist, go away!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Parse command line arguments. */
|
|
||||||
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
|
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'b':
|
case 'b':
|
||||||
@ -416,14 +406,8 @@ main(int ac, char **av)
|
|||||||
}
|
}
|
||||||
if (print_fingerprint)
|
if (print_fingerprint)
|
||||||
do_fingerprint(pw);
|
do_fingerprint(pw);
|
||||||
|
|
||||||
/* If the user requested to change the passphrase, do it now.
|
|
||||||
This function never returns. */
|
|
||||||
if (change_passphrase)
|
if (change_passphrase)
|
||||||
do_change_passphrase(pw);
|
do_change_passphrase(pw);
|
||||||
|
|
||||||
/* If the user requested to change the comment, do it now. This
|
|
||||||
function never returns. */
|
|
||||||
if (change_comment)
|
if (change_comment)
|
||||||
do_change_comment(pw);
|
do_change_comment(pw);
|
||||||
|
|
||||||
@ -484,11 +468,10 @@ passphrase_again:
|
|||||||
xfree(passphrase2);
|
xfree(passphrase2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create default commend field for the passphrase. The user can
|
|
||||||
later edit this field. */
|
|
||||||
if (identity_comment) {
|
if (identity_comment) {
|
||||||
strlcpy(comment, identity_comment, sizeof(comment));
|
strlcpy(comment, identity_comment, sizeof(comment));
|
||||||
} else {
|
} else {
|
||||||
|
/* Create default commend field for the passphrase. */
|
||||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||||
perror("gethostname");
|
perror("gethostname");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -515,8 +498,6 @@ passphrase_again:
|
|||||||
if (!quiet)
|
if (!quiet)
|
||||||
printf("Your identification has been saved in %s.\n", identity_file);
|
printf("Your identification has been saved in %s.\n", identity_file);
|
||||||
|
|
||||||
/* Save the public key in text format in a file with the same name
|
|
||||||
but .pub appended. */
|
|
||||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||||
f = fopen(identity_file, "w");
|
f = fopen(identity_file, "w");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
4
ssh.1
4
ssh.1
@ -9,7 +9,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: ssh.1,v 1.9 1999/11/24 13:26:23 damien Exp $
|
.\" $Id: ssh.1,v 1.10 1999/11/25 00:54:59 damien Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd September 25, 1999
|
.Dd September 25, 1999
|
||||||
.Dt SSH 1
|
.Dt SSH 1
|
||||||
@ -293,7 +293,7 @@ disables any escapes and makes the session fully transparent.
|
|||||||
.It Fl f
|
.It Fl f
|
||||||
Requests
|
Requests
|
||||||
.Nm
|
.Nm
|
||||||
to go to background after authentication. This is useful
|
to go to background just before command execution. This is useful
|
||||||
if
|
if
|
||||||
.Nm
|
.Nm
|
||||||
is going to ask for passwords or passphrases, but the user
|
is going to ask for passwords or passphrases, but the user
|
||||||
|
179
ssh.c
179
ssh.c
@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ssh.c,v 1.11 1999/11/24 13:26:23 damien Exp $");
|
RCSID("$Id: ssh.c,v 1.12 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -30,35 +30,43 @@ const char *__progname = "ssh";
|
|||||||
/* Flag indicating whether debug mode is on. This can be set on the command line. */
|
/* Flag indicating whether debug mode is on. This can be set on the command line. */
|
||||||
int debug_flag = 0;
|
int debug_flag = 0;
|
||||||
|
|
||||||
/* Flag indicating whether to allocate a pseudo tty. This can be set on the command
|
|
||||||
line, and is automatically set if no command is given on the command line. */
|
|
||||||
int tty_flag = 0;
|
int tty_flag = 0;
|
||||||
|
|
||||||
/* Flag indicating that nothing should be read from stdin. This can be set
|
/*
|
||||||
on the command line. */
|
* Flag indicating that nothing should be read from stdin. This can be set
|
||||||
|
* on the command line.
|
||||||
|
*/
|
||||||
int stdin_null_flag = 0;
|
int stdin_null_flag = 0;
|
||||||
|
|
||||||
/* 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
|
* Flag indicating that ssh should fork after authentication. This is useful
|
||||||
background. */
|
* so that the pasphrase can be entered manually, and then ssh goes to the
|
||||||
|
* background.
|
||||||
|
*/
|
||||||
int fork_after_authentication_flag = 0;
|
int fork_after_authentication_flag = 0;
|
||||||
|
|
||||||
/* General data structure for command line options and options configurable
|
/*
|
||||||
in configuration files. See readconf.h. */
|
* General data structure for command line options and options configurable
|
||||||
|
* in configuration files. See readconf.h.
|
||||||
|
*/
|
||||||
Options options;
|
Options options;
|
||||||
|
|
||||||
/* Name of the host we are connecting to. This is the name given on the
|
/*
|
||||||
command line, or the HostName specified for the user-supplied name
|
* Name of the host we are connecting to. This is the name given on the
|
||||||
in a configuration file. */
|
* command line, or the HostName specified for the user-supplied name in a
|
||||||
|
* configuration file.
|
||||||
|
*/
|
||||||
char *host;
|
char *host;
|
||||||
|
|
||||||
/* socket address the host resolves to */
|
/* socket address the host resolves to */
|
||||||
struct sockaddr_in hostaddr;
|
struct sockaddr_in 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
|
* Flag to indicate that we have received a window change signal which has
|
||||||
window size to be sent to the server a little later. This is volatile
|
* not yet been processed. This will cause a message indicating the new
|
||||||
because this is updated in a signal handler. */
|
* 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;
|
volatile int received_window_change_signal = 0;
|
||||||
|
|
||||||
/* Value of argv[0] (set in the main program). */
|
/* Value of argv[0] (set in the main program). */
|
||||||
@ -165,8 +173,10 @@ main(int ac, char **av)
|
|||||||
uid_t original_effective_uid;
|
uid_t original_effective_uid;
|
||||||
int plen;
|
int plen;
|
||||||
|
|
||||||
/* Save the original real uid. It will be needed later
|
/*
|
||||||
(uid-swapping may clobber the real uid). */
|
* Save the original real uid. It will be needed later (uid-swapping
|
||||||
|
* may clobber the real uid).
|
||||||
|
*/
|
||||||
original_real_uid = getuid();
|
original_real_uid = getuid();
|
||||||
original_effective_uid = geteuid();
|
original_effective_uid = geteuid();
|
||||||
|
|
||||||
@ -177,18 +187,21 @@ main(int ac, char **av)
|
|||||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||||
fatal("setrlimit failed: %.100s", strerror(errno));
|
fatal("setrlimit failed: %.100s", strerror(errno));
|
||||||
}
|
}
|
||||||
/* Use uid-swapping to give up root privileges for the duration of
|
/*
|
||||||
option processing. We will re-instantiate the rights when we
|
* Use uid-swapping to give up root privileges for the duration of
|
||||||
are ready to create the privileged port, and will permanently
|
* option processing. We will re-instantiate the rights when we are
|
||||||
drop them when the port has been created (actually, when the
|
* ready to create the privileged port, and will permanently drop
|
||||||
connection has been made, as we may need to create the port
|
* them when the port has been created (actually, when the connection
|
||||||
several times). */
|
* has been made, as we may need to create the port several times).
|
||||||
|
*/
|
||||||
temporarily_use_uid(original_real_uid);
|
temporarily_use_uid(original_real_uid);
|
||||||
|
|
||||||
/* Set our umask to something reasonable, as some files are
|
/*
|
||||||
created with the default umask. This will make them
|
* Set our umask to something reasonable, as some files are created
|
||||||
world-readable but writable only by the owner, which is ok for
|
* with the default umask. This will make them world-readable but
|
||||||
all files for which we don't set the modes explicitly. */
|
* writable only by the owner, which is ok for all files for which we
|
||||||
|
* don't set the modes explicitly.
|
||||||
|
*/
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
/* Save our own name. */
|
/* Save our own name. */
|
||||||
@ -387,10 +400,11 @@ main(int ac, char **av)
|
|||||||
/* Initialize the command to execute on remote host. */
|
/* Initialize the command to execute on remote host. */
|
||||||
buffer_init(&command);
|
buffer_init(&command);
|
||||||
|
|
||||||
/* Save the command to execute on the remote host in a buffer.
|
/*
|
||||||
There is no limit on the length of the command, except by the
|
* Save the command to execute on the remote host in a buffer. There
|
||||||
maximum packet size. Also sets the tty flag if there is no
|
* is no limit on the length of the command, except by the maximum
|
||||||
command. */
|
* packet size. Also sets the tty flag if there is no command.
|
||||||
|
*/
|
||||||
if (optind == ac) {
|
if (optind == ac) {
|
||||||
/* No command specified - execute shell on a tty. */
|
/* No command specified - execute shell on a tty. */
|
||||||
tty_flag = 1;
|
tty_flag = 1;
|
||||||
@ -474,11 +488,15 @@ main(int ac, char **av)
|
|||||||
options.rhosts_authentication = 0;
|
options.rhosts_authentication = 0;
|
||||||
options.rhosts_rsa_authentication = 0;
|
options.rhosts_rsa_authentication = 0;
|
||||||
}
|
}
|
||||||
/* If using rsh has been selected, exec it now (without trying
|
/*
|
||||||
anything else). Note that we must release privileges first. */
|
* If using rsh has been selected, exec it now (without trying
|
||||||
|
* anything else). Note that we must release privileges first.
|
||||||
|
*/
|
||||||
if (options.use_rsh) {
|
if (options.use_rsh) {
|
||||||
/* Restore our superuser privileges. This must be done
|
/*
|
||||||
before permanently setting the uid. */
|
* Restore our superuser privileges. This must be done
|
||||||
|
* before permanently setting the uid.
|
||||||
|
*/
|
||||||
restore_uid();
|
restore_uid();
|
||||||
|
|
||||||
/* Switch to the original uid permanently. */
|
/* Switch to the original uid permanently. */
|
||||||
@ -491,8 +509,10 @@ main(int ac, char **av)
|
|||||||
/* Restore our superuser privileges. */
|
/* Restore our superuser privileges. */
|
||||||
restore_uid();
|
restore_uid();
|
||||||
|
|
||||||
/* Open a connection to the remote host. This needs root
|
/*
|
||||||
privileges if rhosts_{rsa_}authentication is enabled. */
|
* Open a connection to the remote host. This needs root privileges
|
||||||
|
* if rhosts_{rsa_}authentication is enabled.
|
||||||
|
*/
|
||||||
|
|
||||||
ok = ssh_connect(host, &hostaddr, options.port,
|
ok = ssh_connect(host, &hostaddr, options.port,
|
||||||
options.connection_attempts,
|
options.connection_attempts,
|
||||||
@ -501,31 +521,38 @@ main(int ac, char **av)
|
|||||||
original_real_uid,
|
original_real_uid,
|
||||||
options.proxy_command);
|
options.proxy_command);
|
||||||
|
|
||||||
/* If we successfully made the connection, load the host private
|
/*
|
||||||
key in case we will need it later for combined rsa-rhosts
|
* If we successfully made the connection, load the host private key
|
||||||
authentication. This must be done before releasing extra
|
* in case we will need it later for combined rsa-rhosts
|
||||||
privileges, because the file is only readable by root. */
|
* authentication. This must be done before releasing extra
|
||||||
|
* privileges, because the file is only readable by root.
|
||||||
|
*/
|
||||||
if (ok) {
|
if (ok) {
|
||||||
host_private_key = RSA_new();
|
host_private_key = RSA_new();
|
||||||
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
|
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
|
||||||
host_private_key_loaded = 1;
|
host_private_key_loaded = 1;
|
||||||
}
|
}
|
||||||
/* Get rid of any extra privileges that we may have. We will no
|
/*
|
||||||
longer need them. Also, extra privileges could make it very
|
* Get rid of any extra privileges that we may have. We will no
|
||||||
hard to read identity files and other non-world-readable files
|
* longer need them. Also, extra privileges could make it very hard
|
||||||
from the user's home directory if it happens to be on a NFS
|
* to read identity files and other non-world-readable files from the
|
||||||
volume where root is mapped to nobody. */
|
* user's home directory if it happens to be on a NFS volume where
|
||||||
|
* root is mapped to nobody.
|
||||||
/* 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. */
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(original_real_uid);
|
permanently_set_uid(original_real_uid);
|
||||||
|
|
||||||
/* Now that we are back to our own permissions, create ~/.ssh
|
/*
|
||||||
directory if it doesn\'t already exist. */
|
* Now that we are back to our own permissions, create ~/.ssh
|
||||||
|
* directory if it doesn\'t already exist.
|
||||||
|
*/
|
||||||
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
|
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
|
||||||
if (stat(buf, &st) < 0)
|
if (stat(buf, &st) < 0)
|
||||||
if (mkdir(buf, 0755) < 0)
|
if (mkdir(buf, 0755) < 0)
|
||||||
@ -569,15 +596,6 @@ main(int ac, char **av)
|
|||||||
/* Close connection cleanly after attack. */
|
/* Close connection cleanly after attack. */
|
||||||
cipher_attack_detected = packet_disconnect;
|
cipher_attack_detected = packet_disconnect;
|
||||||
|
|
||||||
/* If requested, fork and let ssh continue in the background. */
|
|
||||||
if (fork_after_authentication_flag) {
|
|
||||||
int ret = fork();
|
|
||||||
if (ret == -1)
|
|
||||||
fatal("fork failed: %.100s", strerror(errno));
|
|
||||||
if (ret != 0)
|
|
||||||
exit(0);
|
|
||||||
setsid();
|
|
||||||
}
|
|
||||||
/* Enable compression if requested. */
|
/* Enable compression if requested. */
|
||||||
if (options.compression) {
|
if (options.compression) {
|
||||||
debug("Requesting compression at level %d.", options.compression_level);
|
debug("Requesting compression at level %d.", options.compression_level);
|
||||||
@ -653,12 +671,14 @@ main(int ac, char **av)
|
|||||||
if (f)
|
if (f)
|
||||||
pclose(f);
|
pclose(f);
|
||||||
#endif /* XAUTH_PATH */
|
#endif /* XAUTH_PATH */
|
||||||
/* If we didn't get authentication data, just make up some
|
/*
|
||||||
data. The forwarding code will check the validity of
|
* If we didn't get authentication data, just make up some
|
||||||
the response anyway, and substitute this data. The X11
|
* data. The forwarding code will check the validity of the
|
||||||
server, however, will ignore this fake data and use
|
* response anyway, and substitute this data. The X11
|
||||||
whatever authentication mechanisms it was using
|
* server, however, will ignore this fake data and use
|
||||||
otherwise for the local connection. */
|
* whatever authentication mechanisms it was using otherwise
|
||||||
|
* for the local connection.
|
||||||
|
*/
|
||||||
if (!got_data) {
|
if (!got_data) {
|
||||||
u_int32_t rand = 0;
|
u_int32_t rand = 0;
|
||||||
|
|
||||||
@ -670,8 +690,10 @@ main(int ac, char **av)
|
|||||||
rand >>= 8;
|
rand >>= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Got local authentication reasonable information.
|
/*
|
||||||
Request forwarding with authentication spoofing. */
|
* Got local authentication reasonable information. Request
|
||||||
|
* forwarding with authentication spoofing.
|
||||||
|
*/
|
||||||
debug("Requesting X11 forwarding with authentication spoofing.");
|
debug("Requesting X11 forwarding with authentication spoofing.");
|
||||||
x11_request_forwarding_with_spoofing(proto, data);
|
x11_request_forwarding_with_spoofing(proto, data);
|
||||||
|
|
||||||
@ -728,8 +750,15 @@ main(int ac, char **av)
|
|||||||
options.remote_forwards[i].host_port);
|
options.remote_forwards[i].host_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If a command was specified on the command line, execute the
|
/* If requested, let ssh continue in the background. */
|
||||||
command now. Otherwise request the server to start a shell. */
|
if (fork_after_authentication_flag)
|
||||||
|
if (daemon(1, 1) < 0)
|
||||||
|
fatal("daemon() failed: %.200s", strerror(errno));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a command was specified on the command line, execute the
|
||||||
|
* command now. Otherwise request the server to start a shell.
|
||||||
|
*/
|
||||||
if (buffer_len(&command) > 0) {
|
if (buffer_len(&command) > 0) {
|
||||||
int len = buffer_len(&command);
|
int len = buffer_len(&command);
|
||||||
if (len > 900)
|
if (len > 900)
|
||||||
|
514
ssh.h
514
ssh.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: ssh.h,v 1.15 1999/11/24 13:26:23 damien Exp $"); */
|
/* RCSID("$Id: ssh.h,v 1.16 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef SSH_H
|
#ifndef SSH_H
|
||||||
#define SSH_H
|
#define SSH_H
|
||||||
@ -25,9 +25,11 @@
|
|||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
|
|
||||||
/* The default cipher used if IDEA is not supported by the remote host.
|
/*
|
||||||
It is recommended that this be one of the mandatory ciphers (DES, 3DES),
|
* The default cipher used if IDEA is not supported by the remote host. It is
|
||||||
though that is not required. */
|
* recommended that this be one of the mandatory ciphers (DES, 3DES), though
|
||||||
|
* that is not required.
|
||||||
|
*/
|
||||||
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
|
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
|
||||||
|
|
||||||
/* Cipher used for encrypting authentication files. */
|
/* Cipher used for encrypting authentication files. */
|
||||||
@ -39,20 +41,28 @@
|
|||||||
/* Maximum number of TCP/IP ports forwarded per direction. */
|
/* Maximum number of TCP/IP ports forwarded per direction. */
|
||||||
#define SSH_MAX_FORWARDS_PER_DIRECTION 100
|
#define SSH_MAX_FORWARDS_PER_DIRECTION 100
|
||||||
|
|
||||||
/* Maximum number of RSA authentication identity files that can be specified
|
/*
|
||||||
in configuration files or on the command line. */
|
* Maximum number of RSA authentication identity files that can be specified
|
||||||
|
* in configuration files or on the command line.
|
||||||
|
*/
|
||||||
#define SSH_MAX_IDENTITY_FILES 100
|
#define SSH_MAX_IDENTITY_FILES 100
|
||||||
|
|
||||||
/* Major protocol version. Different version indicates major incompatiblity
|
/*
|
||||||
that prevents communication. */
|
* Major protocol version. Different version indicates major incompatiblity
|
||||||
|
* that prevents communication.
|
||||||
|
*/
|
||||||
#define PROTOCOL_MAJOR 1
|
#define PROTOCOL_MAJOR 1
|
||||||
|
|
||||||
/* Minor protocol version. Different version indicates minor incompatibility
|
/*
|
||||||
that does not prevent interoperation. */
|
* Minor protocol version. Different version indicates minor incompatibility
|
||||||
|
* that does not prevent interoperation.
|
||||||
|
*/
|
||||||
#define PROTOCOL_MINOR 5
|
#define PROTOCOL_MINOR 5
|
||||||
|
|
||||||
/* Name for the service. The port named by this service overrides the default
|
/*
|
||||||
port if present. */
|
* Name for the service. The port named by this service overrides the
|
||||||
|
* default port if present.
|
||||||
|
*/
|
||||||
#define SSH_SERVICE_NAME "ssh"
|
#define SSH_SERVICE_NAME "ssh"
|
||||||
|
|
||||||
#ifndef ETCDIR
|
#ifndef ETCDIR
|
||||||
@ -63,16 +73,16 @@
|
|||||||
#define PIDDIR "/var/run"
|
#define PIDDIR "/var/run"
|
||||||
#endif /* PIDDIR */
|
#endif /* PIDDIR */
|
||||||
|
|
||||||
/* System-wide file containing host keys of known hosts. This file should be
|
/*
|
||||||
world-readable. */
|
* System-wide file containing host keys of known hosts. This file should be
|
||||||
|
* world-readable.
|
||||||
|
*/
|
||||||
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
|
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
|
||||||
|
|
||||||
/* HOST_KEY_FILE /etc/ssh_host_key,
|
/*
|
||||||
SERVER_CONFIG_FILE /etc/sshd_config,
|
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
|
||||||
and HOST_CONFIG_FILE /etc/ssh_config
|
* should be world-readable.
|
||||||
are all defined in Makefile.in. Of these, ssh_host_key should be readable
|
*/
|
||||||
only by root, whereas ssh_config should be world-readable. */
|
|
||||||
|
|
||||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
||||||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||||
@ -89,73 +99,95 @@ only by root, whereas ssh_config should be world-readable. */
|
|||||||
#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass"
|
#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass"
|
||||||
#endif /* ASKPASS_PROGRAM */
|
#endif /* ASKPASS_PROGRAM */
|
||||||
|
|
||||||
/* The process id of the daemon listening for connections is saved
|
/*
|
||||||
here to make it easier to kill the correct daemon when necessary. */
|
* The process id of the daemon listening for connections is saved here to
|
||||||
|
* make it easier to kill the correct daemon when necessary.
|
||||||
|
*/
|
||||||
#define SSH_DAEMON_PID_FILE PIDDIR "/sshd.pid"
|
#define SSH_DAEMON_PID_FILE PIDDIR "/sshd.pid"
|
||||||
|
|
||||||
/* The directory in user\'s home directory in which the files reside.
|
/*
|
||||||
The directory should be world-readable (though not all files are). */
|
* The directory in user\'s home directory in which the files reside. The
|
||||||
|
* directory should be world-readable (though not all files are).
|
||||||
|
*/
|
||||||
#define SSH_USER_DIR ".ssh"
|
#define SSH_USER_DIR ".ssh"
|
||||||
|
|
||||||
/* Per-user file containing host keys of known hosts. This file need
|
/*
|
||||||
not be readable by anyone except the user him/herself, though this does
|
* Per-user file containing host keys of known hosts. This file need not be
|
||||||
not contain anything particularly secret. */
|
* readable by anyone except the user him/herself, though this does not
|
||||||
|
* contain anything particularly secret.
|
||||||
|
*/
|
||||||
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
||||||
|
|
||||||
/* Name of the default file containing client-side authentication key.
|
/*
|
||||||
This file should only be readable by the user him/herself. */
|
* Name of the default file containing client-side authentication key. This
|
||||||
|
* file should only be readable by the user him/herself.
|
||||||
|
*/
|
||||||
#define SSH_CLIENT_IDENTITY ".ssh/identity"
|
#define SSH_CLIENT_IDENTITY ".ssh/identity"
|
||||||
|
|
||||||
/* Configuration file in user\'s home directory. This file need not be
|
/*
|
||||||
readable by anyone but the user him/herself, but does not contain
|
* Configuration file in user\'s home directory. This file need not be
|
||||||
anything particularly secret. If the user\'s home directory resides
|
* readable by anyone but the user him/herself, but does not contain anything
|
||||||
on an NFS volume where root is mapped to nobody, this may need to be
|
* particularly secret. If the user\'s home directory resides on an NFS
|
||||||
world-readable. */
|
* volume where root is mapped to nobody, this may need to be world-readable.
|
||||||
|
*/
|
||||||
#define SSH_USER_CONFFILE ".ssh/config"
|
#define SSH_USER_CONFFILE ".ssh/config"
|
||||||
|
|
||||||
/* File containing a list of those rsa keys that permit logging in as
|
/*
|
||||||
this user. This file need not be
|
* File containing a list of those rsa keys that permit logging in as this
|
||||||
readable by anyone but the user him/herself, but does not contain
|
* user. This file need not be readable by anyone but the user him/herself,
|
||||||
anything particularly secret. If the user\'s home directory resides
|
* but does not contain anything particularly secret. If the user\'s home
|
||||||
on an NFS volume where root is mapped to nobody, this may need to be
|
* directory resides on an NFS volume where root is mapped to nobody, this
|
||||||
world-readable. (This file is read by the daemon which is running as
|
* may need to be world-readable. (This file is read by the daemon which is
|
||||||
root.) */
|
* running as root.)
|
||||||
|
*/
|
||||||
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
||||||
|
|
||||||
/* Per-user and system-wide ssh "rc" files. These files are executed with
|
/*
|
||||||
/bin/sh before starting the shell or command if they exist. They
|
* Per-user and system-wide ssh "rc" files. These files are executed with
|
||||||
will be passed "proto cookie" as arguments if X11 forwarding with
|
* /bin/sh before starting the shell or command if they exist. They will be
|
||||||
spoofing is in use. xauth will be run if neither of these exists. */
|
* passed "proto cookie" as arguments if X11 forwarding with spoofing is in
|
||||||
|
* use. xauth will be run if neither of these exists.
|
||||||
|
*/
|
||||||
#define SSH_USER_RC ".ssh/rc"
|
#define SSH_USER_RC ".ssh/rc"
|
||||||
#define SSH_SYSTEM_RC ETCDIR "/sshrc"
|
#define SSH_SYSTEM_RC ETCDIR "/sshrc"
|
||||||
|
|
||||||
/* Ssh-only version of /etc/hosts.equiv. */
|
/*
|
||||||
|
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
|
||||||
|
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
|
||||||
|
*/
|
||||||
#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
|
#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
|
||||||
|
|
||||||
/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if
|
/*
|
||||||
rhosts authentication is enabled. */
|
* Name of the environment variable containing the pathname of the
|
||||||
|
* authentication socket.
|
||||||
/* Name of the environment variable containing the pathname of the
|
*/
|
||||||
authentication socket. */
|
|
||||||
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
|
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
|
||||||
|
|
||||||
/* Name of the environment variable containing the pathname of the
|
/*
|
||||||
authentication socket. */
|
* Name of the environment variable containing the pathname of the
|
||||||
|
* authentication socket.
|
||||||
|
*/
|
||||||
#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
|
#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
|
||||||
|
|
||||||
/* Force host key length and server key length to differ by at least this
|
/*
|
||||||
many bits. This is to make double encryption with rsaref work. */
|
* Force host key length and server key length to differ by at least this
|
||||||
|
* many bits. This is to make double encryption with rsaref work.
|
||||||
|
*/
|
||||||
#define SSH_KEY_BITS_RESERVED 128
|
#define SSH_KEY_BITS_RESERVED 128
|
||||||
|
|
||||||
/* Length of the session key in bytes. (Specified as 256 bits in the
|
/*
|
||||||
protocol.) */
|
* Length of the session key in bytes. (Specified as 256 bits in the
|
||||||
|
* protocol.)
|
||||||
|
*/
|
||||||
#define SSH_SESSION_KEY_LENGTH 32
|
#define SSH_SESSION_KEY_LENGTH 32
|
||||||
|
|
||||||
/* Name of Kerberos service for SSH to use. */
|
/* Name of Kerberos service for SSH to use. */
|
||||||
#define KRB4_SERVICE_NAME "rcmd"
|
#define KRB4_SERVICE_NAME "rcmd"
|
||||||
|
|
||||||
/* Authentication methods. New types can be added, but old types should not
|
/*
|
||||||
be removed for compatibility. The maximum allowed value is 31. */
|
* Authentication methods. New types can be added, but old types should not
|
||||||
|
* be removed for compatibility. The maximum allowed value is 31.
|
||||||
|
*/
|
||||||
#define SSH_AUTH_RHOSTS 1
|
#define SSH_AUTH_RHOSTS 1
|
||||||
#define SSH_AUTH_RSA 2
|
#define SSH_AUTH_RSA 2
|
||||||
#define SSH_AUTH_PASSWORD 3
|
#define SSH_AUTH_PASSWORD 3
|
||||||
@ -167,16 +199,16 @@ only by root, whereas ssh_config should be world-readable. */
|
|||||||
#define SSH_PASS_AFS_TOKEN 21
|
#define SSH_PASS_AFS_TOKEN 21
|
||||||
|
|
||||||
/* Protocol flags. These are bit masks. */
|
/* Protocol flags. These are bit masks. */
|
||||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes
|
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
|
||||||
* screen */
|
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
|
||||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain
|
|
||||||
* host */
|
|
||||||
|
|
||||||
/* Definition of message types. New values can be added, but old values
|
/*
|
||||||
should not be removed or without careful consideration of the consequences
|
* Definition of message types. New values can be added, but old values
|
||||||
for compatibility. The maximum value is 254; value 255 is reserved
|
* should not be removed or without careful consideration of the consequences
|
||||||
for future extension. */
|
* for compatibility. The maximum value is 254; value 255 is reserved for
|
||||||
/* Message name *//* msg code *//* arguments */
|
* future extension.
|
||||||
|
*/
|
||||||
|
/* Message name */ /* msg code */ /* arguments */
|
||||||
#define SSH_MSG_NONE 0 /* no message */
|
#define SSH_MSG_NONE 0 /* no message */
|
||||||
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
||||||
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
|
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
|
||||||
@ -226,45 +258,54 @@ only by root, whereas ssh_config should be world-readable. */
|
|||||||
|
|
||||||
/*------------ definitions for login.c -------------*/
|
/*------------ definitions for login.c -------------*/
|
||||||
|
|
||||||
/* Returns the time when the user last logged in. Returns 0 if the
|
/*
|
||||||
information is not available. This must be called before record_login.
|
* Returns the time when the user last logged in. Returns 0 if the
|
||||||
The host from which the user logged in is stored in buf. */
|
* information is not available. This must be called before record_login.
|
||||||
|
* The host from which the user logged in is stored in buf.
|
||||||
|
*/
|
||||||
unsigned long
|
unsigned long
|
||||||
get_last_login_time(uid_t uid, const char *logname,
|
get_last_login_time(uid_t uid, const char *logname,
|
||||||
char *buf, unsigned int bufsize);
|
char *buf, unsigned int bufsize);
|
||||||
|
|
||||||
/* Records that the user has logged in. This does many things normally
|
/*
|
||||||
done by login(1). */
|
* Records that the user has logged in. This does many things normally done
|
||||||
|
* by login(1).
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||||
const char *host, struct sockaddr_in * addr);
|
const char *host, struct sockaddr_in * addr);
|
||||||
|
|
||||||
/* Records that the user has logged out. This does many thigs normally
|
/*
|
||||||
done by login(1) or init. */
|
* Records that the user has logged out. This does many thigs normally done
|
||||||
|
* by login(1) or init.
|
||||||
|
*/
|
||||||
void record_logout(int pid, const char *ttyname);
|
void record_logout(int pid, const char *ttyname);
|
||||||
|
|
||||||
/*------------ definitions for sshconnect.c ----------*/
|
/*------------ definitions for sshconnect.c ----------*/
|
||||||
|
|
||||||
/* Opens a TCP/IP connection to the remote server on the given host. If
|
/*
|
||||||
port is 0, the default port will be used. If anonymous is zero,
|
* Opens a TCP/IP connection to the remote server on the given host. If port
|
||||||
a privileged port will be allocated to make the connection.
|
* is 0, the default port will be used. If anonymous is zero, a privileged
|
||||||
This requires super-user privileges if anonymous is false.
|
* port will be allocated to make the connection. This requires super-user
|
||||||
Connection_attempts specifies the maximum number of tries, one per
|
* privileges if anonymous is false. Connection_attempts specifies the
|
||||||
second. This returns true on success, and zero on failure. If the
|
* maximum number of tries, one per second. This returns true on success,
|
||||||
connection is successful, this calls packet_set_connection for the
|
* and zero on failure. If the connection is successful, this calls
|
||||||
connection. */
|
* packet_set_connection for the connection.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
||||||
int port, int connection_attempts,
|
int port, int connection_attempts,
|
||||||
int anonymous, uid_t original_real_uid,
|
int anonymous, uid_t original_real_uid,
|
||||||
const char *proxy_command);
|
const char *proxy_command);
|
||||||
|
|
||||||
/* Starts a dialog with the server, and authenticates the current user on the
|
/*
|
||||||
server. This does not need any extra privileges. The basic connection
|
* Starts a dialog with the server, and authenticates the current user on the
|
||||||
to the server must already have been established before this is called.
|
* server. This does not need any extra privileges. The basic connection to
|
||||||
If login fails, this function prints an error and never returns.
|
* the server must already have been established before this is called. If
|
||||||
This initializes the random state, and leaves it initialized (it will also
|
* login fails, this function prints an error and never returns. This
|
||||||
have references from the packet module). */
|
* initializes the random state, and leaves it initialized (it will also have
|
||||||
|
* references from the packet module).
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ssh_login(int host_key_valid, RSA * host_key, const char *host,
|
ssh_login(int host_key_valid, RSA * host_key, const char *host,
|
||||||
@ -272,41 +313,57 @@ ssh_login(int host_key_valid, RSA * host_key, const char *host,
|
|||||||
|
|
||||||
/*------------ Definitions for various authentication methods. -------*/
|
/*------------ Definitions for various authentication methods. -------*/
|
||||||
|
|
||||||
/* Tries to authenticate the user using the .rhosts file. Returns true if
|
/*
|
||||||
authentication succeeds. If ignore_rhosts is non-zero, this will not
|
* Tries to authenticate the user using the .rhosts file. Returns true if
|
||||||
consider .rhosts and .shosts (/etc/hosts.equiv will still be used). */
|
* authentication succeeds. If ignore_rhosts is non-zero, this will not
|
||||||
|
* consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
|
||||||
|
*/
|
||||||
int auth_rhosts(struct passwd * pw, const char *client_user);
|
int auth_rhosts(struct passwd * pw, const char *client_user);
|
||||||
|
|
||||||
/* Tries to authenticate the user using the .rhosts file and the host using
|
/*
|
||||||
its host key. Returns true if authentication succeeds. */
|
* Tries to authenticate the user using the .rhosts file and the host using
|
||||||
|
* its host key. Returns true if authentication succeeds.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
auth_rhosts_rsa(struct passwd * pw, const char *client_user,
|
auth_rhosts_rsa(struct passwd * pw, const char *client_user,
|
||||||
BIGNUM * client_host_key_e, BIGNUM * client_host_key_n);
|
BIGNUM * client_host_key_e, BIGNUM * client_host_key_n);
|
||||||
|
|
||||||
/* Tries to authenticate the user using password. Returns true if
|
/*
|
||||||
authentication succeeds. */
|
* Tries to authenticate the user using password. Returns true if
|
||||||
|
* authentication succeeds.
|
||||||
|
*/
|
||||||
int auth_password(struct passwd * pw, const char *password);
|
int auth_password(struct passwd * pw, const char *password);
|
||||||
|
|
||||||
/* Performs the RSA authentication dialog with the client. This returns
|
/*
|
||||||
0 if the client could not be authenticated, and 1 if authentication was
|
* Performs the RSA authentication dialog with the client. This returns 0 if
|
||||||
successful. This may exit if there is a serious protocol violation. */
|
* the client could not be authenticated, and 1 if authentication was
|
||||||
|
* successful. This may exit if there is a serious protocol violation.
|
||||||
|
*/
|
||||||
int auth_rsa(struct passwd * pw, BIGNUM * client_n);
|
int auth_rsa(struct passwd * pw, BIGNUM * client_n);
|
||||||
|
|
||||||
/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
|
/*
|
||||||
over the key. Skips any whitespace at the beginning and at end. */
|
* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
|
||||||
|
* over the key. Skips any whitespace at the beginning and at end.
|
||||||
|
*/
|
||||||
int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
|
int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
|
||||||
|
|
||||||
/* Returns the name of the machine at the other end of the socket. The
|
/*
|
||||||
returned string should be freed by the caller. */
|
* Returns the name of the machine at the other end of the socket. The
|
||||||
|
* returned string should be freed by the caller.
|
||||||
|
*/
|
||||||
char *get_remote_hostname(int socket);
|
char *get_remote_hostname(int socket);
|
||||||
|
|
||||||
/* Return the canonical name of the host in the other side of the current
|
/*
|
||||||
connection (as returned by packet_get_connection). The host name is
|
* Return the canonical name of the host in the other side of the current
|
||||||
cached, so it is efficient to call this several times. */
|
* connection (as returned by packet_get_connection). The host name is
|
||||||
|
* cached, so it is efficient to call this several times.
|
||||||
|
*/
|
||||||
const char *get_canonical_hostname(void);
|
const char *get_canonical_hostname(void);
|
||||||
|
|
||||||
/* Returns the remote IP address as an ascii string. The value need not be
|
/*
|
||||||
freed by the caller. */
|
* Returns the remote IP address as an ascii string. The value need not be
|
||||||
|
* freed by the caller.
|
||||||
|
*/
|
||||||
const char *get_remote_ipaddr(void);
|
const char *get_remote_ipaddr(void);
|
||||||
|
|
||||||
/* Returns the port number of the peer of the socket. */
|
/* Returns the port number of the peer of the socket. */
|
||||||
@ -315,16 +372,20 @@ int get_peer_port(int sock);
|
|||||||
/* Returns the port number of the remote host. */
|
/* Returns the port number of the remote host. */
|
||||||
int get_remote_port(void);
|
int get_remote_port(void);
|
||||||
|
|
||||||
/* Tries to match the host name (which must be in all lowercase) against the
|
/*
|
||||||
comma-separated sequence of subpatterns (each possibly preceded by ! to
|
* Tries to match the host name (which must be in all lowercase) against the
|
||||||
indicate negation). Returns true if there is a positive match; zero
|
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||||
otherwise. */
|
* indicate negation). Returns true if there is a positive match; zero
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||||
|
|
||||||
/* Checks whether the given host is already in the list of our known hosts.
|
/*
|
||||||
Returns HOST_OK if the host is known and has the specified key,
|
* Checks whether the given host is already in the list of our known hosts.
|
||||||
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
|
* Returns HOST_OK if the host is known and has the specified key, HOST_NEW
|
||||||
but used to have a different host key. The host must be in all lowercase. */
|
* if the host is not known, and HOST_CHANGED if the host is known but used
|
||||||
|
* to have a different host key. The host must be in all lowercase.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HOST_OK, HOST_NEW, HOST_CHANGED
|
HOST_OK, HOST_NEW, HOST_CHANGED
|
||||||
} HostStatus;
|
} HostStatus;
|
||||||
@ -332,43 +393,55 @@ HostStatus
|
|||||||
check_host_in_hostfile(const char *filename, const char *host,
|
check_host_in_hostfile(const char *filename, const char *host,
|
||||||
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn);
|
BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn);
|
||||||
|
|
||||||
/* Appends an entry to the host file. Returns false if the entry
|
/*
|
||||||
could not be appended. */
|
* Appends an entry to the host file. Returns false if the entry could not
|
||||||
|
* be appended.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
add_host_to_hostfile(const char *filename, const char *host,
|
add_host_to_hostfile(const char *filename, const char *host,
|
||||||
BIGNUM * e, BIGNUM * n);
|
BIGNUM * e, BIGNUM * n);
|
||||||
|
|
||||||
/* Performs the RSA authentication challenge-response dialog with the client,
|
/*
|
||||||
and returns true (non-zero) if the client gave the correct answer to
|
* Performs the RSA authentication challenge-response dialog with the client,
|
||||||
our challenge; returns zero if the client gives a wrong answer. */
|
* and returns true (non-zero) if the client gave the correct answer to our
|
||||||
|
* challenge; returns zero if the client gives a wrong answer.
|
||||||
|
*/
|
||||||
int auth_rsa_challenge_dialog(BIGNUM * e, BIGNUM * n);
|
int auth_rsa_challenge_dialog(BIGNUM * e, BIGNUM * n);
|
||||||
|
|
||||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
/*
|
||||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||||
If from_stdin is true, the passphrase will be read from stdin instead. */
|
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
|
||||||
|
* from_stdin is true, the passphrase will be read from stdin instead.
|
||||||
|
*/
|
||||||
char *read_passphrase(const char *prompt, int from_stdin);
|
char *read_passphrase(const char *prompt, int from_stdin);
|
||||||
|
|
||||||
/* Saves the authentication (private) key in a file, encrypting it with
|
/*
|
||||||
passphrase. The identification of the file (lowest 64 bits of n)
|
* Saves the authentication (private) key in a file, encrypting it with
|
||||||
will precede the key to provide identification of the key without
|
* passphrase. The identification of the file (lowest 64 bits of n) will
|
||||||
needing a passphrase. */
|
* precede the key to provide identification of the key without needing a
|
||||||
|
* passphrase.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
save_private_key(const char *filename, const char *passphrase,
|
save_private_key(const char *filename, const char *passphrase,
|
||||||
RSA * private_key, const char *comment);
|
RSA * private_key, const char *comment);
|
||||||
|
|
||||||
/* Loads the public part of the key file (public key and comment).
|
/*
|
||||||
Returns 0 if an error occurred; zero if the public key was successfully
|
* Loads the public part of the key file (public key and comment). Returns 0
|
||||||
read. The comment of the key is returned in comment_return if it is
|
* if an error occurred; zero if the public key was successfully read. The
|
||||||
non-NULL; the caller must free the value with xfree. */
|
* comment of the key is returned in comment_return if it is non-NULL; the
|
||||||
|
* caller must free the value with xfree.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
load_public_key(const char *filename, RSA * pub,
|
load_public_key(const char *filename, RSA * pub,
|
||||||
char **comment_return);
|
char **comment_return);
|
||||||
|
|
||||||
/* Loads the private key from the file. Returns 0 if an error is encountered
|
/*
|
||||||
(file does not exist or is not readable, or passphrase is bad).
|
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||||
This initializes the private key. The comment of the key is returned
|
* (file does not exist or is not readable, or passphrase is bad). This
|
||||||
in comment_return if it is non-NULL; the caller must free the value
|
* initializes the private key. The comment of the key is returned in
|
||||||
with xfree. */
|
* comment_return if it is non-NULL; the caller must free the value with
|
||||||
|
* xfree.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
load_private_key(const char *filename, const char *passphrase,
|
load_private_key(const char *filename, const char *passphrase,
|
||||||
RSA * private_key, char **comment_return);
|
RSA * private_key, char **comment_return);
|
||||||
@ -418,9 +491,11 @@ void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
|||||||
/* same as fatal() but w/o logging */
|
/* same as fatal() but w/o logging */
|
||||||
void fatal_cleanup(void);
|
void fatal_cleanup(void);
|
||||||
|
|
||||||
/* Registers a cleanup function to be called by fatal()/fatal_cleanup() before exiting.
|
/*
|
||||||
It is permissible to call fatal_remove_cleanup for the function itself
|
* Registers a cleanup function to be called by fatal()/fatal_cleanup()
|
||||||
from the function. */
|
* before exiting. It is permissible to call fatal_remove_cleanup for the
|
||||||
|
* function itself from the function.
|
||||||
|
*/
|
||||||
void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
||||||
|
|
||||||
/* Removes a cleanup function to be called at fatal(). */
|
/* Removes a cleanup function to be called at fatal(). */
|
||||||
@ -431,9 +506,11 @@ void fatal_remove_cleanup(void (*proc) (void *context), void *context);
|
|||||||
/* Sets specific protocol options. */
|
/* Sets specific protocol options. */
|
||||||
void channel_set_options(int hostname_in_open);
|
void channel_set_options(int hostname_in_open);
|
||||||
|
|
||||||
/* Allocate a new channel object and set its type and socket. Remote_name
|
/*
|
||||||
must have been allocated with xmalloc; this will free it when the channel
|
* Allocate a new channel object and set its type and socket. Remote_name
|
||||||
is freed. */
|
* must have been allocated with xmalloc; this will free it when the channel
|
||||||
|
* is freed.
|
||||||
|
*/
|
||||||
int channel_allocate(int type, int sock, char *remote_name);
|
int channel_allocate(int type, int sock, char *remote_name);
|
||||||
|
|
||||||
/* Free the channel and close its socket. */
|
/* Free the channel and close its socket. */
|
||||||
@ -442,16 +519,20 @@ void channel_free(int channel);
|
|||||||
/* Add any bits relevant to channels in select bitmasks. */
|
/* Add any bits relevant to channels in select bitmasks. */
|
||||||
void channel_prepare_select(fd_set * readset, fd_set * writeset);
|
void channel_prepare_select(fd_set * readset, fd_set * writeset);
|
||||||
|
|
||||||
/* After select, perform any appropriate operations for channels which
|
/*
|
||||||
have events pending. */
|
* After select, perform any appropriate operations for channels which have
|
||||||
|
* events pending.
|
||||||
|
*/
|
||||||
void channel_after_select(fd_set * readset, fd_set * writeset);
|
void channel_after_select(fd_set * readset, fd_set * writeset);
|
||||||
|
|
||||||
/* If there is data to send to the connection, send some of it now. */
|
/* If there is data to send to the connection, send some of it now. */
|
||||||
void channel_output_poll(void);
|
void channel_output_poll(void);
|
||||||
|
|
||||||
/* This is called when a packet of type CHANNEL_DATA has just been received.
|
/*
|
||||||
The message type has already been consumed, but channel number and data
|
* This is called when a packet of type CHANNEL_DATA has just been received.
|
||||||
is still there. */
|
* The message type has already been consumed, but channel number and data is
|
||||||
|
* still there.
|
||||||
|
*/
|
||||||
void channel_input_data(int payload_len);
|
void channel_input_data(int payload_len);
|
||||||
|
|
||||||
/* Returns true if no channel has too much buffered data. */
|
/* Returns true if no channel has too much buffered data. */
|
||||||
@ -473,8 +554,10 @@ void channel_input_open_failure(void);
|
|||||||
any unix domain sockets. */
|
any unix domain sockets. */
|
||||||
void channel_stop_listening(void);
|
void channel_stop_listening(void);
|
||||||
|
|
||||||
/* Closes the sockets of all channels. This is used to close extra file
|
/*
|
||||||
descriptors after a fork. */
|
* Closes the sockets of all channels. This is used to close extra file
|
||||||
|
* descriptors after a fork.
|
||||||
|
*/
|
||||||
void channel_close_all(void);
|
void channel_close_all(void);
|
||||||
|
|
||||||
/* Returns the maximum file descriptor number used by the channels. */
|
/* Returns the maximum file descriptor number used by the channels. */
|
||||||
@ -483,92 +566,123 @@ int channel_max_fd(void);
|
|||||||
/* Returns true if there is still an open channel over the connection. */
|
/* Returns true if there is still an open channel over the connection. */
|
||||||
int channel_still_open(void);
|
int channel_still_open(void);
|
||||||
|
|
||||||
/* Returns a string containing a list of all open channels. The list is
|
/*
|
||||||
suitable for displaying to the user. It uses crlf instead of newlines.
|
* Returns a string containing a list of all open channels. The list is
|
||||||
The caller should free the string with xfree. */
|
* suitable for displaying to the user. It uses crlf instead of newlines.
|
||||||
|
* The caller should free the string with xfree.
|
||||||
|
*/
|
||||||
char *channel_open_message(void);
|
char *channel_open_message(void);
|
||||||
|
|
||||||
/* Initiate forwarding of connections to local port "port" through the secure
|
/*
|
||||||
channel to host:port from remote side. This never returns if there
|
* Initiate forwarding of connections to local port "port" through the secure
|
||||||
was an error. */
|
* channel to host:port from remote side. This never returns if there was an
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
channel_request_local_forwarding(int port, const char *host,
|
channel_request_local_forwarding(int port, const char *host,
|
||||||
int remote_port);
|
int remote_port);
|
||||||
|
|
||||||
/* Initiate forwarding of connections to port "port" on remote host through
|
/*
|
||||||
the secure channel to host:port from local side. This never returns
|
* Initiate forwarding of connections to port "port" on remote host through
|
||||||
if there was an error. This registers that open requests for that
|
* the secure channel to host:port from local side. This never returns if
|
||||||
port are permitted. */
|
* there was an error. This registers that open requests for that port are
|
||||||
|
* permitted.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
channel_request_remote_forwarding(int port, const char *host,
|
channel_request_remote_forwarding(int port, const char *host,
|
||||||
int remote_port);
|
int remote_port);
|
||||||
|
|
||||||
/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
|
/*
|
||||||
called by the server, because the user could connect to any port anyway,
|
* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
|
||||||
and the server has no way to know but to trust the client anyway. */
|
* called by the server, because the user could connect to any port anyway,
|
||||||
|
* and the server has no way to know but to trust the client anyway.
|
||||||
|
*/
|
||||||
void channel_permit_all_opens(void);
|
void channel_permit_all_opens(void);
|
||||||
|
|
||||||
/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
/*
|
||||||
listening for the port, and sends back a success reply (or disconnect
|
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
||||||
message if there was an error). This never returns if there was an
|
* listening for the port, and sends back a success reply (or disconnect
|
||||||
error. */
|
* message if there was an error). This never returns if there was an error.
|
||||||
|
*/
|
||||||
void channel_input_port_forward_request(int is_root);
|
void channel_input_port_forward_request(int is_root);
|
||||||
|
|
||||||
/* This is called after receiving PORT_OPEN message. This attempts to connect
|
/*
|
||||||
to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or
|
* This is called after receiving PORT_OPEN message. This attempts to
|
||||||
CHANNEL_OPEN_FAILURE. */
|
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
|
||||||
|
* or CHANNEL_OPEN_FAILURE.
|
||||||
|
*/
|
||||||
void channel_input_port_open(int payload_len);
|
void channel_input_port_open(int payload_len);
|
||||||
|
|
||||||
/* Creates a port for X11 connections, and starts listening for it.
|
/*
|
||||||
Returns the display name, or NULL if an error was encountered. */
|
* Creates a port for X11 connections, and starts listening for it. Returns
|
||||||
|
* the display name, or NULL if an error was encountered.
|
||||||
|
*/
|
||||||
char *x11_create_display(int screen);
|
char *x11_create_display(int screen);
|
||||||
|
|
||||||
/* Creates an internet domain socket for listening for X11 connections.
|
/*
|
||||||
Returns a suitable value for the DISPLAY variable, or NULL if an error
|
* Creates an internet domain socket for listening for X11 connections.
|
||||||
occurs. */
|
* Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||||
|
* occurs.
|
||||||
|
*/
|
||||||
char *x11_create_display_inet(int screen);
|
char *x11_create_display_inet(int screen);
|
||||||
|
|
||||||
/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
|
/*
|
||||||
the remote channel number. We should do whatever we want, and respond
|
* This is called when SSH_SMSG_X11_OPEN is received. The packet contains
|
||||||
with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
|
* the remote channel number. We should do whatever we want, and respond
|
||||||
|
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
|
||||||
|
*/
|
||||||
void x11_input_open(int payload_len);
|
void x11_input_open(int payload_len);
|
||||||
|
|
||||||
/* Requests forwarding of X11 connections. This should be called on the
|
/*
|
||||||
client only. */
|
* Requests forwarding of X11 connections. This should be called on the
|
||||||
|
* client only.
|
||||||
|
*/
|
||||||
void x11_request_forwarding(void);
|
void x11_request_forwarding(void);
|
||||||
|
|
||||||
/* Requests forwarding for X11 connections, with authentication spoofing.
|
/*
|
||||||
This should be called in the client only. */
|
* Requests forwarding for X11 connections, with authentication spoofing.
|
||||||
|
* This should be called in the client only.
|
||||||
|
*/
|
||||||
void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
|
void x11_request_forwarding_with_spoofing(const char *proto, const char *data);
|
||||||
|
|
||||||
/* Sends a message to the server to request authentication fd forwarding. */
|
/* Sends a message to the server to request authentication fd forwarding. */
|
||||||
void auth_request_forwarding(void);
|
void auth_request_forwarding(void);
|
||||||
|
|
||||||
/* Returns the name of the forwarded authentication socket. Returns NULL
|
/*
|
||||||
if there is no forwarded authentication socket. The returned value points
|
* Returns the name of the forwarded authentication socket. Returns NULL if
|
||||||
to a static buffer. */
|
* there is no forwarded authentication socket. The returned value points to
|
||||||
|
* a static buffer.
|
||||||
|
*/
|
||||||
char *auth_get_socket_name(void);
|
char *auth_get_socket_name(void);
|
||||||
|
|
||||||
/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
/*
|
||||||
This starts forwarding authentication requests. */
|
* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server.
|
||||||
|
* This starts forwarding authentication requests.
|
||||||
|
*/
|
||||||
void auth_input_request_forwarding(struct passwd * pw);
|
void auth_input_request_forwarding(struct passwd * pw);
|
||||||
|
|
||||||
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
|
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
|
||||||
void auth_input_open_request(void);
|
void auth_input_open_request(void);
|
||||||
|
|
||||||
/* Returns true if the given string matches the pattern (which may contain
|
/*
|
||||||
? and * as wildcards), and zero if it does not match. */
|
* Returns true if the given string matches the pattern (which may contain ?
|
||||||
|
* and * as wildcards), and zero if it does not match.
|
||||||
|
*/
|
||||||
int match_pattern(const char *s, const char *pattern);
|
int match_pattern(const char *s, const char *pattern);
|
||||||
|
|
||||||
/* Expands tildes in the file name. Returns data allocated by xmalloc.
|
/*
|
||||||
Warning: this calls getpw*. */
|
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||||
|
* Warning: this calls getpw*.
|
||||||
|
*/
|
||||||
char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
||||||
|
|
||||||
/* Performs the interactive session. This handles data transmission between
|
/*
|
||||||
the client and the program. Note that the notion of stdin, stdout, and
|
* Performs the interactive session. This handles data transmission between
|
||||||
stderr in this function is sort of reversed: this function writes to
|
* the client and the program. Note that the notion of stdin, stdout, and
|
||||||
stdin (of the child program), and reads from stdout and stderr (of the
|
* stderr in this function is sort of reversed: this function writes to stdin
|
||||||
child program). */
|
* (of the child program), and reads from stdout and stderr (of the child
|
||||||
|
* program).
|
||||||
|
*/
|
||||||
void server_loop(int pid, int fdin, int fdout, int fderr);
|
void server_loop(int pid, int fdin, int fdout, int fderr);
|
||||||
|
|
||||||
/* Client side main loop for the interactive session. */
|
/* Client side main loop for the interactive session. */
|
||||||
@ -582,9 +696,11 @@ struct envstring {
|
|||||||
#ifdef KRB4
|
#ifdef KRB4
|
||||||
#include <krb.h>
|
#include <krb.h>
|
||||||
|
|
||||||
/* Performs Kerberos v4 mutual authentication with the client. This returns
|
/*
|
||||||
0 if the client could not be authenticated, and 1 if authentication was
|
* Performs Kerberos v4 mutual authentication with the client. This returns 0
|
||||||
successful. This may exit if there is a serious protocol violation. */
|
* if the client could not be authenticated, and 1 if authentication was
|
||||||
|
* successful. This may exit if there is a serious protocol violation.
|
||||||
|
*/
|
||||||
int auth_krb4(const char *server_user, KTEXT auth, char **client);
|
int auth_krb4(const char *server_user, KTEXT auth, char **client);
|
||||||
int krb4_init(uid_t uid);
|
int krb4_init(uid_t uid);
|
||||||
void krb4_cleanup_proc(void *ignore);
|
void krb4_cleanup_proc(void *ignore);
|
||||||
|
187
sshconnect.c
187
sshconnect.c
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: sshconnect.c,v 1.14 1999/11/24 13:26:23 damien Exp $");
|
RCSID("$Id: sshconnect.c,v 1.15 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
@ -142,8 +142,10 @@ ssh_create_socket(uid_t original_real_uid, int privileged)
|
|||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
|
|
||||||
/* If we are running as root and want to connect to a privileged
|
/*
|
||||||
port, bind our own socket to a privileged port. */
|
* If we are running as root and want to connect to a privileged
|
||||||
|
* port, bind our own socket to a privileged port.
|
||||||
|
*/
|
||||||
if (privileged) {
|
if (privileged) {
|
||||||
int p = IPPORT_RESERVED - 1;
|
int p = IPPORT_RESERVED - 1;
|
||||||
|
|
||||||
@ -227,9 +229,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||||||
!anonymous && geteuid() == 0 &&
|
!anonymous && geteuid() == 0 &&
|
||||||
port < IPPORT_RESERVED);
|
port < IPPORT_RESERVED);
|
||||||
|
|
||||||
/* Connect to the host. We use the user's uid in
|
/*
|
||||||
the hope that it will help with the problems of
|
* Connect to the host. We use the user's uid in the
|
||||||
tcp_wrappers showing the remote uid as root. */
|
* hope that it will help with the problems of
|
||||||
|
* tcp_wrappers showing the remote uid as root.
|
||||||
|
*/
|
||||||
temporarily_use_uid(original_real_uid);
|
temporarily_use_uid(original_real_uid);
|
||||||
if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr))
|
if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr))
|
||||||
>= 0) {
|
>= 0) {
|
||||||
@ -270,8 +274,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||||||
!anonymous && geteuid() == 0 &&
|
!anonymous && geteuid() == 0 &&
|
||||||
port < IPPORT_RESERVED);
|
port < IPPORT_RESERVED);
|
||||||
|
|
||||||
/* Connect to the host. We use the user's uid in the hope that
|
/*
|
||||||
it will help with tcp_wrappers showing the remote uid as root. */
|
* Connect to the host. We use the user's
|
||||||
|
* uid in the hope that it will help with
|
||||||
|
* tcp_wrappers showing the remote uid as
|
||||||
|
* root.
|
||||||
|
*/
|
||||||
temporarily_use_uid(original_real_uid);
|
temporarily_use_uid(original_real_uid);
|
||||||
if (connect(sock, (struct sockaddr *) hostaddr,
|
if (connect(sock, (struct sockaddr *) hostaddr,
|
||||||
sizeof(*hostaddr)) >= 0) {
|
sizeof(*hostaddr)) >= 0) {
|
||||||
@ -282,8 +290,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||||||
debug("connect: %.100s", strerror(errno));
|
debug("connect: %.100s", strerror(errno));
|
||||||
restore_uid();
|
restore_uid();
|
||||||
|
|
||||||
/* Close the failed socket; there appear to be some problems when
|
/*
|
||||||
reusing a socket for which connect() has already returned an error. */
|
* Close the failed socket; there appear to
|
||||||
|
* be some problems when reusing a socket for
|
||||||
|
* which connect() has already returned an
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
shutdown(sock, SHUT_RDWR);
|
shutdown(sock, SHUT_RDWR);
|
||||||
close(sock);
|
close(sock);
|
||||||
}
|
}
|
||||||
@ -300,10 +312,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||||||
|
|
||||||
debug("Connection established.");
|
debug("Connection established.");
|
||||||
|
|
||||||
/* Set socket options. We would like the socket to disappear as
|
/*
|
||||||
soon as it has been closed for whatever reason. */
|
* Set socket options. We would like the socket to disappear as soon
|
||||||
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
|
* as it has been closed for whatever reason.
|
||||||
sizeof(on)); */
|
*/
|
||||||
|
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
|
||||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
|
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
|
||||||
linger.l_onoff = 1;
|
linger.l_onoff = 1;
|
||||||
linger.l_linger = 5;
|
linger.l_linger = 5;
|
||||||
@ -493,8 +506,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile)
|
|||||||
/* Wait for server's response. */
|
/* Wait for server's response. */
|
||||||
type = packet_read(&plen);
|
type = packet_read(&plen);
|
||||||
|
|
||||||
/* The server responds with failure if it doesn\'t like our key or
|
/*
|
||||||
doesn\'t support RSA authentication. */
|
* The server responds with failure if it doesn\'t like our key or
|
||||||
|
* doesn\'t support RSA authentication.
|
||||||
|
*/
|
||||||
if (type == SSH_SMSG_FAILURE) {
|
if (type == SSH_SMSG_FAILURE) {
|
||||||
debug("Server refused our key.");
|
debug("Server refused our key.");
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
@ -514,8 +529,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile)
|
|||||||
debug("Received RSA challenge from server.");
|
debug("Received RSA challenge from server.");
|
||||||
|
|
||||||
private_key = RSA_new();
|
private_key = RSA_new();
|
||||||
/* Load the private key. Try first with empty passphrase; if it
|
/*
|
||||||
fails, ask for a passphrase. */
|
* Load the private key. Try first with empty passphrase; if it
|
||||||
|
* fails, ask for a passphrase.
|
||||||
|
*/
|
||||||
if (!load_private_key(authfile, "", private_key, NULL)) {
|
if (!load_private_key(authfile, "", private_key, NULL)) {
|
||||||
char buf[300];
|
char buf[300];
|
||||||
snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
|
snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
|
||||||
@ -720,9 +737,11 @@ try_kerberos_authentication()
|
|||||||
|
|
||||||
packet_integrity_check(plen, 4 + auth.length, type);
|
packet_integrity_check(plen, 4 + auth.length, type);
|
||||||
|
|
||||||
/* If his response isn't properly encrypted with the
|
/*
|
||||||
session key, and the decrypted checksum fails to match,
|
* If his response isn't properly encrypted with the session
|
||||||
he's bogus. Bail out. */
|
* key, and the decrypted checksum fails to match, he's
|
||||||
|
* bogus. Bail out.
|
||||||
|
*/
|
||||||
r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
|
r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
|
||||||
&foreign, &local, &msg_data);
|
&foreign, &local, &msg_data);
|
||||||
if (r != KSUCCESS) {
|
if (r != KSUCCESS) {
|
||||||
@ -894,8 +913,10 @@ ssh_exchange_identification()
|
|||||||
}
|
}
|
||||||
buf[sizeof(buf) - 1] = 0;
|
buf[sizeof(buf) - 1] = 0;
|
||||||
|
|
||||||
/* Check that the versions match. In future this might accept
|
/*
|
||||||
several versions and set appropriate flags to handle them. */
|
* Check that the versions match. In future this might accept
|
||||||
|
* several versions and set appropriate flags to handle them.
|
||||||
|
*/
|
||||||
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
|
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
|
||||||
remote_version) != 3)
|
remote_version) != 3)
|
||||||
fatal("Bad remote protocol version identification: '%.100s'", buf);
|
fatal("Bad remote protocol version identification: '%.100s'", buf);
|
||||||
@ -916,9 +937,11 @@ ssh_exchange_identification()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
/* Removed for now, to permit compatibility with latter versions.
|
/*
|
||||||
The server will reject our version and disconnect if it doesn't
|
* Removed for now, to permit compatibility with latter versions. The
|
||||||
support it. */
|
* server will reject our version and disconnect if it doesn't
|
||||||
|
* support it.
|
||||||
|
*/
|
||||||
if (remote_major != PROTOCOL_MAJOR)
|
if (remote_major != PROTOCOL_MAJOR)
|
||||||
fatal("Protocol major versions differ: %d vs. %d",
|
fatal("Protocol major versions differ: %d vs. %d",
|
||||||
PROTOCOL_MAJOR, remote_major);
|
PROTOCOL_MAJOR, remote_major);
|
||||||
@ -1086,10 +1109,7 @@ ssh_login(int host_key_valid,
|
|||||||
protocol_flags = packet_get_int();
|
protocol_flags = packet_get_int();
|
||||||
packet_set_protocol_flags(protocol_flags);
|
packet_set_protocol_flags(protocol_flags);
|
||||||
|
|
||||||
/* Get supported cipher types. */
|
|
||||||
supported_ciphers = packet_get_int();
|
supported_ciphers = packet_get_int();
|
||||||
|
|
||||||
/* Get supported authentication types. */
|
|
||||||
supported_authentications = packet_get_int();
|
supported_authentications = packet_get_int();
|
||||||
|
|
||||||
debug("Received server public key (%d bits) and host key (%d bits).",
|
debug("Received server public key (%d bits) and host key (%d bits).",
|
||||||
@ -1099,11 +1119,12 @@ ssh_login(int host_key_valid,
|
|||||||
8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
|
8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
|
||||||
SSH_SMSG_PUBLIC_KEY);
|
SSH_SMSG_PUBLIC_KEY);
|
||||||
|
|
||||||
/* Compute the session id. */
|
|
||||||
compute_session_id(session_id, check_bytes, host_key->n, public_key->n);
|
compute_session_id(session_id, check_bytes, host_key->n, public_key->n);
|
||||||
|
|
||||||
/* Check if the host key is present in the user\'s list of known
|
/*
|
||||||
hosts or in the systemwide list. */
|
* Check if the host key is present in the user\'s list of known
|
||||||
|
* hosts or in the systemwide list.
|
||||||
|
*/
|
||||||
host_status = check_host_in_hostfile(options.user_hostfile, host,
|
host_status = check_host_in_hostfile(options.user_hostfile, host,
|
||||||
host_key->e, host_key->n,
|
host_key->e, host_key->n,
|
||||||
file_key->e, file_key->n);
|
file_key->e, file_key->n);
|
||||||
@ -1111,18 +1132,22 @@ ssh_login(int host_key_valid,
|
|||||||
host_status = check_host_in_hostfile(options.system_hostfile, host,
|
host_status = check_host_in_hostfile(options.system_hostfile, host,
|
||||||
host_key->e, host_key->n,
|
host_key->e, host_key->n,
|
||||||
file_key->e, file_key->n);
|
file_key->e, file_key->n);
|
||||||
/* Force accepting of the host key for localhost and 127.0.0.1.
|
/*
|
||||||
The problem is that if the home directory is NFS-mounted to
|
* Force accepting of the host key for localhost and 127.0.0.1. The
|
||||||
multiple machines, localhost will refer to a different machine
|
* problem is that if the home directory is NFS-mounted to multiple
|
||||||
in each of them, and the user will get bogus HOST_CHANGED
|
* machines, localhost will refer to a different machine in each of
|
||||||
warnings. This essentially disables host authentication for
|
* them, and the user will get bogus HOST_CHANGED warnings. This
|
||||||
localhost; however, this is probably not a real problem. */
|
* essentially disables host authentication for localhost; however,
|
||||||
|
* this is probably not a real problem.
|
||||||
|
*/
|
||||||
if (local) {
|
if (local) {
|
||||||
debug("Forcing accepting of host key for localhost.");
|
debug("Forcing accepting of host key for localhost.");
|
||||||
host_status = HOST_OK;
|
host_status = HOST_OK;
|
||||||
}
|
}
|
||||||
/* Also perform check for the ip address, skip the check if we are
|
/*
|
||||||
localhost or the hostname was an ip address to begin with */
|
* Also perform check for the ip address, skip the check if we are
|
||||||
|
* localhost or the hostname was an ip address to begin with
|
||||||
|
*/
|
||||||
if (options.check_host_ip && !local && strcmp(host, ip)) {
|
if (options.check_host_ip && !local && strcmp(host, ip)) {
|
||||||
RSA *ip_key = RSA_new();
|
RSA *ip_key = RSA_new();
|
||||||
ip_key->n = BN_new();
|
ip_key->n = BN_new();
|
||||||
@ -1226,13 +1251,18 @@ ssh_login(int host_key_valid,
|
|||||||
error("Add correct host key in %.100s to get rid of this message.",
|
error("Add correct host key in %.100s to get rid of this message.",
|
||||||
options.user_hostfile);
|
options.user_hostfile);
|
||||||
|
|
||||||
/* If strict host key checking is in use, the user will
|
/*
|
||||||
have to edit the key manually and we can only abort. */
|
* If strict host key checking is in use, the user will have
|
||||||
|
* to edit the key manually and we can only abort.
|
||||||
|
*/
|
||||||
if (options.strict_host_key_checking)
|
if (options.strict_host_key_checking)
|
||||||
fatal("Host key for %.200s has changed and you have requested strict checking.", host);
|
fatal("Host key for %.200s has changed and you have requested strict checking.", host);
|
||||||
|
|
||||||
/* If strict host key checking has not been requested, allow the connection
|
/*
|
||||||
but without password authentication or agent forwarding. */
|
* If strict host key checking has not been requested, allow
|
||||||
|
* the connection but without password authentication or
|
||||||
|
* agent forwarding.
|
||||||
|
*/
|
||||||
if (options.password_authentication) {
|
if (options.password_authentication) {
|
||||||
error("Password authentication is disabled to avoid trojan horses.");
|
error("Password authentication is disabled to avoid trojan horses.");
|
||||||
options.password_authentication = 0;
|
options.password_authentication = 0;
|
||||||
@ -1241,11 +1271,13 @@ ssh_login(int host_key_valid,
|
|||||||
error("Agent forwarding is disabled to avoid trojan horses.");
|
error("Agent forwarding is disabled to avoid trojan horses.");
|
||||||
options.forward_agent = 0;
|
options.forward_agent = 0;
|
||||||
}
|
}
|
||||||
/* XXX Should permit the user to change to use the new id.
|
/*
|
||||||
This could be done by converting the host key to an
|
* XXX Should permit the user to change to use the new id.
|
||||||
identifying sentence, tell that the host identifies
|
* This could be done by converting the host key to an
|
||||||
itself by that sentence, and ask the user if he/she
|
* identifying sentence, tell that the host identifies itself
|
||||||
whishes to accept the authentication. */
|
* by that sentence, and ask the user if he/she whishes to
|
||||||
|
* accept the authentication.
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,9 +1287,11 @@ ssh_login(int host_key_valid,
|
|||||||
/* Generate a session key. */
|
/* Generate a session key. */
|
||||||
arc4random_stir();
|
arc4random_stir();
|
||||||
|
|
||||||
/* Generate an encryption key for the session. The key is a 256
|
/*
|
||||||
bit random number, interpreted as a 32-byte key, with the least
|
* Generate an encryption key for the session. The key is a 256 bit
|
||||||
significant 8 bits being the first byte of the key. */
|
* random number, interpreted as a 32-byte key, with the least
|
||||||
|
* significant 8 bits being the first byte of the key.
|
||||||
|
*/
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
if (i % 4 == 0)
|
if (i % 4 == 0)
|
||||||
rand = arc4random();
|
rand = arc4random();
|
||||||
@ -1265,9 +1299,11 @@ ssh_login(int host_key_valid,
|
|||||||
rand >>= 8;
|
rand >>= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* According to the protocol spec, the first byte of the session
|
/*
|
||||||
key is the highest byte of the integer. The session key is
|
* According to the protocol spec, the first byte of the session key
|
||||||
xored with the first 16 bytes of the session id. */
|
* is the highest byte of the integer. The session key is xored with
|
||||||
|
* the first 16 bytes of the session id.
|
||||||
|
*/
|
||||||
key = BN_new();
|
key = BN_new();
|
||||||
BN_set_word(key, 0);
|
BN_set_word(key, 0);
|
||||||
for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
|
for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
|
||||||
@ -1278,8 +1314,10 @@ ssh_login(int host_key_valid,
|
|||||||
BN_add_word(key, session_key[i]);
|
BN_add_word(key, session_key[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Encrypt the integer using the public key and host key of the
|
/*
|
||||||
server (key with smaller modulus first). */
|
* Encrypt the integer using the public key and host key of the
|
||||||
|
* server (key with smaller modulus first).
|
||||||
|
*/
|
||||||
if (BN_cmp(public_key->n, host_key->n) < 0) {
|
if (BN_cmp(public_key->n, host_key->n) < 0) {
|
||||||
/* Public key has smaller modulus. */
|
/* Public key has smaller modulus. */
|
||||||
if (BN_num_bits(host_key->n) <
|
if (BN_num_bits(host_key->n) <
|
||||||
@ -1354,8 +1392,10 @@ ssh_login(int host_key_valid,
|
|||||||
/* We will no longer need the session key here. Destroy any extra copies. */
|
/* We will no longer need the session key here. Destroy any extra copies. */
|
||||||
memset(session_key, 0, sizeof(session_key));
|
memset(session_key, 0, sizeof(session_key));
|
||||||
|
|
||||||
/* Expect a success message from the server. Note that this
|
/*
|
||||||
message will be received in encrypted form. */
|
* Expect a success message from the server. Note that this message
|
||||||
|
* will be received in encrypted form.
|
||||||
|
*/
|
||||||
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
|
packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
|
||||||
|
|
||||||
debug("Received encrypted confirmation.");
|
debug("Received encrypted confirmation.");
|
||||||
@ -1366,9 +1406,11 @@ ssh_login(int host_key_valid,
|
|||||||
packet_send();
|
packet_send();
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
|
|
||||||
/* The server should respond with success if no authentication is
|
/*
|
||||||
needed (the user has no password). Otherwise the server
|
* The server should respond with success if no authentication is
|
||||||
responds with failure. */
|
* needed (the user has no password). Otherwise the server responds
|
||||||
|
* with failure.
|
||||||
|
*/
|
||||||
type = packet_read(&payload_len);
|
type = packet_read(&payload_len);
|
||||||
|
|
||||||
/* check whether the connection was accepted without authentication. */
|
/* check whether the connection was accepted without authentication. */
|
||||||
@ -1410,8 +1452,10 @@ ssh_login(int host_key_valid,
|
|||||||
}
|
}
|
||||||
#endif /* KRB4 */
|
#endif /* KRB4 */
|
||||||
|
|
||||||
/* Use rhosts authentication if running in privileged socket and
|
/*
|
||||||
we do not wish to remain anonymous. */
|
* Use rhosts authentication if running in privileged socket and we
|
||||||
|
* do not wish to remain anonymous.
|
||||||
|
*/
|
||||||
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
|
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
|
||||||
options.rhosts_authentication) {
|
options.rhosts_authentication) {
|
||||||
debug("Trying rhosts authentication.");
|
debug("Trying rhosts authentication.");
|
||||||
@ -1428,8 +1472,10 @@ ssh_login(int host_key_valid,
|
|||||||
packet_disconnect("Protocol error: got %d in response to rhosts auth",
|
packet_disconnect("Protocol error: got %d in response to rhosts auth",
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
/* Try .rhosts or /etc/hosts.equiv authentication with RSA host
|
/*
|
||||||
authentication. */
|
* Try .rhosts or /etc/hosts.equiv authentication with RSA host
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
|
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
|
||||||
options.rhosts_rsa_authentication && host_key_valid) {
|
options.rhosts_rsa_authentication && host_key_valid) {
|
||||||
if (try_rhosts_rsa_authentication(local_user, own_host_key))
|
if (try_rhosts_rsa_authentication(local_user, own_host_key))
|
||||||
@ -1438,10 +1484,11 @@ ssh_login(int host_key_valid,
|
|||||||
/* Try RSA authentication if the server supports it. */
|
/* Try RSA authentication if the server supports it. */
|
||||||
if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
|
if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
|
||||||
options.rsa_authentication) {
|
options.rsa_authentication) {
|
||||||
/* Try RSA authentication using the authentication agent.
|
/*
|
||||||
The agent is tried first because no passphrase is
|
* Try RSA authentication using the authentication agent. The
|
||||||
needed for it, whereas identity files may require
|
* agent is tried first because no passphrase is needed for
|
||||||
passphrases. */
|
* it, whereas identity files may require passphrases.
|
||||||
|
*/
|
||||||
if (try_agent_authentication())
|
if (try_agent_authentication())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
499
sshd.c
499
sshd.c
@ -11,7 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: sshd.c,v 1.31 1999/11/24 23:42:08 damien Exp $");
|
RCSID("$Id: sshd.c,v 1.32 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -65,12 +65,16 @@ char *av0;
|
|||||||
/* Saved arguments to main(). */
|
/* Saved arguments to main(). */
|
||||||
char **saved_argv;
|
char **saved_argv;
|
||||||
|
|
||||||
/* This is set to the socket that the server is listening; this is used in
|
/*
|
||||||
the SIGHUP signal handler. */
|
* This is set to the socket that the server is listening; this is used in
|
||||||
|
* the SIGHUP signal handler.
|
||||||
|
*/
|
||||||
int listen_sock;
|
int listen_sock;
|
||||||
|
|
||||||
/* the client's version string, passed by sshd2 in compat mode.
|
/*
|
||||||
if != NULL, sshd will skip the version-number exchange */
|
* the client's version string, passed by sshd2 in compat mode. if != NULL,
|
||||||
|
* sshd will skip the version-number exchange
|
||||||
|
*/
|
||||||
char *client_version_string = NULL;
|
char *client_version_string = NULL;
|
||||||
|
|
||||||
/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
|
/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
|
||||||
@ -88,19 +92,23 @@ struct envstring *custom_environment = NULL;
|
|||||||
/* Session id for the current session. */
|
/* Session id for the current session. */
|
||||||
unsigned char session_id[16];
|
unsigned char session_id[16];
|
||||||
|
|
||||||
/* Any really sensitive data in the application is contained in this structure.
|
/*
|
||||||
The idea is that this structure could be locked into memory so that the
|
* Any really sensitive data in the application is contained in this
|
||||||
pages do not get written into swap. However, there are some problems.
|
* structure. The idea is that this structure could be locked into memory so
|
||||||
The private key contains BIGNUMs, and we do not (in principle) have
|
* that the pages do not get written into swap. However, there are some
|
||||||
access to the internals of them, and locking just the structure is not
|
* problems. The private key contains BIGNUMs, and we do not (in principle)
|
||||||
very useful. Currently, memory locking is not implemented. */
|
* have access to the internals of them, and locking just the structure is
|
||||||
|
* not very useful. Currently, memory locking is not implemented.
|
||||||
|
*/
|
||||||
struct {
|
struct {
|
||||||
RSA *private_key; /* Private part of server key. */
|
RSA *private_key; /* Private part of server key. */
|
||||||
RSA *host_key; /* Private part of host key. */
|
RSA *host_key; /* Private part of host key. */
|
||||||
} sensitive_data;
|
} sensitive_data;
|
||||||
|
|
||||||
/* Flag indicating whether the current session key has been used. This flag
|
/*
|
||||||
is set whenever the key is used, and cleared when the key is regenerated. */
|
* Flag indicating whether the current session key has been used. This flag
|
||||||
|
* is set whenever the key is used, and cleared when the key is regenerated.
|
||||||
|
*/
|
||||||
int key_used = 0;
|
int key_used = 0;
|
||||||
|
|
||||||
/* This is set to true when SIGHUP is received. */
|
/* This is set to true when SIGHUP is received. */
|
||||||
@ -466,7 +474,7 @@ main(int ac, char **av)
|
|||||||
fprintf(stderr, "sshd version %s\n", SSH_VERSION);
|
fprintf(stderr, "sshd version %s\n", SSH_VERSION);
|
||||||
fprintf(stderr, "Usage: %s [options]\n", av0);
|
fprintf(stderr, "Usage: %s [options]\n", av0);
|
||||||
fprintf(stderr, "Options:\n");
|
fprintf(stderr, "Options:\n");
|
||||||
fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR);
|
fprintf(stderr, " -f file Configuration file (default %s)\n", SERVER_CONFIG_FILE);
|
||||||
fprintf(stderr, " -d Debugging mode\n");
|
fprintf(stderr, " -d Debugging mode\n");
|
||||||
fprintf(stderr, " -i Started from inetd\n");
|
fprintf(stderr, " -i Started from inetd\n");
|
||||||
fprintf(stderr, " -q Quiet (no logging)\n");
|
fprintf(stderr, " -q Quiet (no logging)\n");
|
||||||
@ -614,13 +622,11 @@ main(int ac, char **av)
|
|||||||
setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger,
|
setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger,
|
||||||
sizeof(linger));
|
sizeof(linger));
|
||||||
|
|
||||||
/* Initialize the socket address. */
|
|
||||||
memset(&sin, 0, sizeof(sin));
|
memset(&sin, 0, sizeof(sin));
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
sin.sin_addr = options.listen_addr;
|
sin.sin_addr = options.listen_addr;
|
||||||
sin.sin_port = htons(options.port);
|
sin.sin_port = htons(options.port);
|
||||||
|
|
||||||
/* Bind the socket to the desired port. */
|
|
||||||
if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
|
if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
|
||||||
error("bind: %.100s", strerror(errno));
|
error("bind: %.100s", strerror(errno));
|
||||||
shutdown(listen_sock, SHUT_RDWR);
|
shutdown(listen_sock, SHUT_RDWR);
|
||||||
@ -628,12 +634,13 @@ main(int ac, char **av)
|
|||||||
fatal("Bind to port %d failed.", options.port);
|
fatal("Bind to port %d failed.", options.port);
|
||||||
}
|
}
|
||||||
if (!debug_flag) {
|
if (!debug_flag) {
|
||||||
/* Record our pid in /etc/sshd_pid to make it
|
/*
|
||||||
easier to kill the correct sshd. We don\'t
|
* Record our pid in /etc/sshd_pid to make it easier
|
||||||
want to do this before the bind above because
|
* to kill the correct sshd. We don\'t want to do
|
||||||
the bind will fail if there already is a
|
* this before the bind above because the bind will
|
||||||
daemon, and this will overwrite any old pid in
|
* fail if there already is a daemon, and this will
|
||||||
the file. */
|
* overwrite any old pid in the file.
|
||||||
|
*/
|
||||||
f = fopen(SSH_DAEMON_PID_FILE, "w");
|
f = fopen(SSH_DAEMON_PID_FILE, "w");
|
||||||
if (f) {
|
if (f) {
|
||||||
fprintf(f, "%u\n", (unsigned int) getpid());
|
fprintf(f, "%u\n", (unsigned int) getpid());
|
||||||
@ -666,8 +673,10 @@ main(int ac, char **av)
|
|||||||
/* Arrange SIGCHLD to be caught. */
|
/* Arrange SIGCHLD to be caught. */
|
||||||
signal(SIGCHLD, main_sigchld_handler);
|
signal(SIGCHLD, main_sigchld_handler);
|
||||||
|
|
||||||
/* Stay listening for connections until the system crashes
|
/*
|
||||||
or the daemon is killed with a signal. */
|
* Stay listening for connections until the system crashes or
|
||||||
|
* the daemon is killed with a signal.
|
||||||
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (received_sighup)
|
if (received_sighup)
|
||||||
sighup_restart();
|
sighup_restart();
|
||||||
@ -682,12 +691,16 @@ main(int ac, char **av)
|
|||||||
error("accept: %.100s", strerror(errno));
|
error("accept: %.100s", strerror(errno));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Got connection. Fork a child to handle it,
|
/*
|
||||||
unless we are in debugging mode. */
|
* Got connection. Fork a child to handle it, unless
|
||||||
|
* we are in debugging mode.
|
||||||
|
*/
|
||||||
if (debug_flag) {
|
if (debug_flag) {
|
||||||
/* In debugging mode. Close the listening
|
/*
|
||||||
socket, and start processing the
|
* In debugging mode. Close the listening
|
||||||
connection without forking. */
|
* socket, and start processing the
|
||||||
|
* connection without forking.
|
||||||
|
*/
|
||||||
debug("Server will not fork when running in debugging mode.");
|
debug("Server will not fork when running in debugging mode.");
|
||||||
close(listen_sock);
|
close(listen_sock);
|
||||||
sock_in = newsock;
|
sock_in = newsock;
|
||||||
@ -695,16 +708,17 @@ main(int ac, char **av)
|
|||||||
pid = getpid();
|
pid = getpid();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
/* Normal production daemon. Fork, and
|
/*
|
||||||
have the child process the connection.
|
* Normal production daemon. Fork, and have
|
||||||
The parent continues listening. */
|
* the child process the connection. The
|
||||||
|
* parent continues listening.
|
||||||
|
*/
|
||||||
if ((pid = fork()) == 0) {
|
if ((pid = fork()) == 0) {
|
||||||
/* Child. Close the listening
|
/*
|
||||||
socket, and start using the
|
* Child. Close the listening socket, and start using the
|
||||||
accepted socket. Reinitialize
|
* accepted socket. Reinitialize logging (since our pid has
|
||||||
logging (since our pid has
|
* changed). We break out of the loop to handle the connection.
|
||||||
changed). We break out of the
|
*/
|
||||||
loop to handle the connection. */
|
|
||||||
close(listen_sock);
|
close(listen_sock);
|
||||||
sock_in = newsock;
|
sock_in = newsock;
|
||||||
sock_out = newsock;
|
sock_out = newsock;
|
||||||
@ -731,9 +745,11 @@ main(int ac, char **av)
|
|||||||
|
|
||||||
/* This is the child processing a new connection. */
|
/* This is the child processing a new connection. */
|
||||||
|
|
||||||
/* Disable the key regeneration alarm. We will not regenerate the
|
/*
|
||||||
key since we are no longer in a position to give it to anyone.
|
* Disable the key regeneration alarm. We will not regenerate the
|
||||||
We will not restart on SIGHUP since it no longer makes sense. */
|
* key since we are no longer in a position to give it to anyone. We
|
||||||
|
* will not restart on SIGHUP since it no longer makes sense.
|
||||||
|
*/
|
||||||
alarm(0);
|
alarm(0);
|
||||||
signal(SIGALRM, SIG_DFL);
|
signal(SIGALRM, SIG_DFL);
|
||||||
signal(SIGHUP, SIG_DFL);
|
signal(SIGHUP, SIG_DFL);
|
||||||
@ -741,17 +757,20 @@ main(int ac, char **av)
|
|||||||
signal(SIGQUIT, SIG_DFL);
|
signal(SIGQUIT, SIG_DFL);
|
||||||
signal(SIGCHLD, SIG_DFL);
|
signal(SIGCHLD, SIG_DFL);
|
||||||
|
|
||||||
/* Set socket options for the connection. We want the socket to
|
/*
|
||||||
close as fast as possible without waiting for anything. If the
|
* Set socket options for the connection. We want the socket to
|
||||||
connection is not a socket, these will do nothing. */
|
* close as fast as possible without waiting for anything. If the
|
||||||
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
|
* connection is not a socket, these will do nothing.
|
||||||
sizeof(on)); */
|
*/
|
||||||
|
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
|
||||||
linger.l_onoff = 1;
|
linger.l_onoff = 1;
|
||||||
linger.l_linger = 5;
|
linger.l_linger = 5;
|
||||||
setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
|
setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
|
||||||
|
|
||||||
/* Register our connection. This turns encryption off because we
|
/*
|
||||||
do not have a key. */
|
* Register our connection. This turns encryption off because we do
|
||||||
|
* not have a key.
|
||||||
|
*/
|
||||||
packet_set_connection(sock_in, sock_out);
|
packet_set_connection(sock_in, sock_out);
|
||||||
|
|
||||||
remote_port = get_remote_port();
|
remote_port = get_remote_port();
|
||||||
@ -777,12 +796,14 @@ main(int ac, char **av)
|
|||||||
verbose("Connection from %.500s port %d", remote_ip, remote_port);
|
verbose("Connection from %.500s port %d", remote_ip, remote_port);
|
||||||
#endif /* LIBWRAP */
|
#endif /* LIBWRAP */
|
||||||
|
|
||||||
/* We don\'t want to listen forever unless the other side
|
/*
|
||||||
successfully authenticates itself. So we set up an alarm which
|
* We don\'t want to listen forever unless the other side
|
||||||
is cleared after successful authentication. A limit of zero
|
* successfully authenticates itself. So we set up an alarm which is
|
||||||
indicates no limit. Note that we don\'t set the alarm in
|
* cleared after successful authentication. A limit of zero
|
||||||
debugging mode; it is just annoying to have the server exit
|
* indicates no limit. Note that we don\'t set the alarm in debugging
|
||||||
just when you are about to discover the bug. */
|
* mode; it is just annoying to have the server exit just when you
|
||||||
|
* are about to discover the bug.
|
||||||
|
*/
|
||||||
signal(SIGALRM, grace_alarm_handler);
|
signal(SIGALRM, grace_alarm_handler);
|
||||||
if (!debug_flag)
|
if (!debug_flag)
|
||||||
alarm(options.login_grace_time);
|
alarm(options.login_grace_time);
|
||||||
@ -815,8 +836,10 @@ main(int ac, char **av)
|
|||||||
buf[sizeof(buf) - 1] = 0;
|
buf[sizeof(buf) - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the versions match. In future this might accept
|
/*
|
||||||
several versions and set appropriate flags to handle them. */
|
* Check that the versions match. In future this might accept
|
||||||
|
* several versions and set appropriate flags to handle them.
|
||||||
|
*/
|
||||||
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
|
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
|
||||||
remote_version) != 3) {
|
remote_version) != 3) {
|
||||||
const char *s = "Protocol mismatch.\n";
|
const char *s = "Protocol mismatch.\n";
|
||||||
@ -848,11 +871,13 @@ main(int ac, char **av)
|
|||||||
no_agent_forwarding_flag = 1;
|
no_agent_forwarding_flag = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Check that the connection comes from a privileged port. Rhosts-
|
/*
|
||||||
and Rhosts-RSA-Authentication only make sense from priviledged
|
* Check that the connection comes from a privileged port. Rhosts-
|
||||||
programs. Of course, if the intruder has root access on his
|
* and Rhosts-RSA-Authentication only make sense from priviledged
|
||||||
local machine, he can connect from any port. So do not use
|
* programs. Of course, if the intruder has root access on his local
|
||||||
these authentication methods from machines that you do not trust. */
|
* machine, he can connect from any port. So do not use these
|
||||||
|
* authentication methods from machines that you do not trust.
|
||||||
|
*/
|
||||||
if (remote_port >= IPPORT_RESERVED ||
|
if (remote_port >= IPPORT_RESERVED ||
|
||||||
remote_port < IPPORT_RESERVED / 2) {
|
remote_port < IPPORT_RESERVED / 2) {
|
||||||
options.rhosts_authentication = 0;
|
options.rhosts_authentication = 0;
|
||||||
@ -914,13 +939,15 @@ do_connection()
|
|||||||
int plen, slen;
|
int plen, slen;
|
||||||
u_int32_t rand = 0;
|
u_int32_t rand = 0;
|
||||||
|
|
||||||
/* Generate check bytes that the client must send back in the user
|
/*
|
||||||
packet in order for it to be accepted; this is used to defy ip
|
* Generate check bytes that the client must send back in the user
|
||||||
spoofing attacks. Note that this only works against somebody
|
* packet in order for it to be accepted; this is used to defy ip
|
||||||
doing IP spoofing from a remote machine; any machine on the
|
* spoofing attacks. Note that this only works against somebody
|
||||||
local network can still see outgoing packets and catch the
|
* doing IP spoofing from a remote machine; any machine on the local
|
||||||
random cookie. This only affects rhosts authentication, and
|
* network can still see outgoing packets and catch the random
|
||||||
this is one of the reasons why it is inherently insecure. */
|
* cookie. This only affects rhosts authentication, and this is one
|
||||||
|
* of the reasons why it is inherently insecure.
|
||||||
|
*/
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
if (i % 4 == 0)
|
if (i % 4 == 0)
|
||||||
rand = arc4random();
|
rand = arc4random();
|
||||||
@ -928,9 +955,11 @@ do_connection()
|
|||||||
rand >>= 8;
|
rand >>= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send our public key. We include in the packet 64 bits of
|
/*
|
||||||
random data that must be matched in the reply in order to
|
* Send our public key. We include in the packet 64 bits of random
|
||||||
prevent IP spoofing. */
|
* data that must be matched in the reply in order to prevent IP
|
||||||
|
* spoofing.
|
||||||
|
*/
|
||||||
packet_start(SSH_SMSG_PUBLIC_KEY);
|
packet_start(SSH_SMSG_PUBLIC_KEY);
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
packet_put_char(check_bytes[i]);
|
packet_put_char(check_bytes[i]);
|
||||||
@ -1002,14 +1031,15 @@ do_connection()
|
|||||||
session_key_int = BN_new();
|
session_key_int = BN_new();
|
||||||
packet_get_bignum(session_key_int, &slen);
|
packet_get_bignum(session_key_int, &slen);
|
||||||
|
|
||||||
/* Get protocol flags. */
|
|
||||||
protocol_flags = packet_get_int();
|
protocol_flags = packet_get_int();
|
||||||
packet_set_protocol_flags(protocol_flags);
|
packet_set_protocol_flags(protocol_flags);
|
||||||
|
|
||||||
packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
|
packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY);
|
||||||
|
|
||||||
/* Decrypt it using our private server key and private host key
|
/*
|
||||||
(key with larger modulus first). */
|
* Decrypt it using our private server key and private host key (key
|
||||||
|
* with larger modulus first).
|
||||||
|
*/
|
||||||
if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) {
|
if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) {
|
||||||
/* Private key has bigger modulus. */
|
/* Private key has bigger modulus. */
|
||||||
if (BN_num_bits(sensitive_data.private_key->n) <
|
if (BN_num_bits(sensitive_data.private_key->n) <
|
||||||
@ -1040,14 +1070,15 @@ do_connection()
|
|||||||
sensitive_data.private_key);
|
sensitive_data.private_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute session id for this session. */
|
|
||||||
compute_session_id(session_id, check_bytes,
|
compute_session_id(session_id, check_bytes,
|
||||||
sensitive_data.host_key->n,
|
sensitive_data.host_key->n,
|
||||||
sensitive_data.private_key->n);
|
sensitive_data.private_key->n);
|
||||||
|
|
||||||
/* Extract session key from the decrypted integer. The key is in
|
/*
|
||||||
the least significant 256 bits of the integer; the first byte
|
* Extract session key from the decrypted integer. The key is in the
|
||||||
of the key is in the highest bits. */
|
* least significant 256 bits of the integer; the first byte of the
|
||||||
|
* key is in the highest bits.
|
||||||
|
*/
|
||||||
BN_mask_bits(session_key_int, sizeof(session_key) * 8);
|
BN_mask_bits(session_key_int, sizeof(session_key) * 8);
|
||||||
len = BN_num_bytes(session_key_int);
|
len = BN_num_bytes(session_key_int);
|
||||||
if (len < 0 || len > sizeof(session_key))
|
if (len < 0 || len > sizeof(session_key))
|
||||||
@ -1125,8 +1156,7 @@ allowed_user(struct passwd * pw)
|
|||||||
if (match_pattern(pw->pw_name, options.deny_users[i]))
|
if (match_pattern(pw->pw_name, options.deny_users[i]))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Return false if AllowUsers isn't empty and user isn't listed
|
/* Return false if AllowUsers isn't empty and user isn't listed there */
|
||||||
there */
|
|
||||||
if (options.num_allow_users > 0) {
|
if (options.num_allow_users > 0) {
|
||||||
if (!pw->pw_name)
|
if (!pw->pw_name)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1151,8 +1181,10 @@ allowed_user(struct passwd * pw)
|
|||||||
if (match_pattern(grp->gr_name, options.deny_groups[i]))
|
if (match_pattern(grp->gr_name, options.deny_groups[i]))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Return false if AllowGroups isn't empty and user's
|
/*
|
||||||
group isn't listed there */
|
* Return false if AllowGroups isn't empty and user's group
|
||||||
|
* isn't listed there
|
||||||
|
*/
|
||||||
if (options.num_allow_groups > 0) {
|
if (options.num_allow_groups > 0) {
|
||||||
if (!grp->gr_name)
|
if (!grp->gr_name)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1216,8 +1248,10 @@ do_authentication(char *user)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If we are not running as root, the user must have the same uid
|
/*
|
||||||
as the server. */
|
* If we are not running as root, the user must have the same uid as
|
||||||
|
* the server.
|
||||||
|
*/
|
||||||
if (getuid() != 0 && pw->pw_uid != getuid())
|
if (getuid() != 0 && pw->pw_uid != getuid())
|
||||||
packet_disconnect("Cannot change user when server not running as root.");
|
packet_disconnect("Cannot change user when server not running as root.");
|
||||||
|
|
||||||
@ -1357,10 +1391,12 @@ do_authloop(struct passwd * pw)
|
|||||||
verbose("Rhosts authentication disabled.");
|
verbose("Rhosts authentication disabled.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Get client user name. Note that we just have
|
/*
|
||||||
to trust the client; this is one reason why
|
* Get client user name. Note that we just have to
|
||||||
rhosts authentication is insecure. (Another is
|
* trust the client; this is one reason why rhosts
|
||||||
IP-spoofing on a local network.) */
|
* authentication is insecure. (Another is
|
||||||
|
* IP-spoofing on a local network.)
|
||||||
|
*/
|
||||||
client_user = packet_get_string(&ulen);
|
client_user = packet_get_string(&ulen);
|
||||||
packet_integrity_check(plen, 4 + ulen, type);
|
packet_integrity_check(plen, 4 + ulen, type);
|
||||||
|
|
||||||
@ -1379,9 +1415,11 @@ do_authloop(struct passwd * pw)
|
|||||||
verbose("Rhosts with RSA authentication disabled.");
|
verbose("Rhosts with RSA authentication disabled.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Get client user name. Note that we just have
|
/*
|
||||||
to trust the client; root on the client machine
|
* Get client user name. Note that we just have to
|
||||||
can claim to be any user. */
|
* trust the client; root on the client machine can
|
||||||
|
* claim to be any user.
|
||||||
|
*/
|
||||||
client_user = packet_get_string(&ulen);
|
client_user = packet_get_string(&ulen);
|
||||||
|
|
||||||
/* Get the client host key. */
|
/* Get the client host key. */
|
||||||
@ -1425,9 +1463,11 @@ do_authloop(struct passwd * pw)
|
|||||||
verbose("Password authentication disabled.");
|
verbose("Password authentication disabled.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Read user password. It is in plain text, but
|
/*
|
||||||
was transmitted over the encrypted channel so
|
* Read user password. It is in plain text, but was
|
||||||
it is not visible to an outside observer. */
|
* transmitted over the encrypted channel so it is
|
||||||
|
* not visible to an outside observer.
|
||||||
|
*/
|
||||||
password = packet_get_string(&dlen);
|
password = packet_get_string(&dlen);
|
||||||
packet_integrity_check(plen, 4 + dlen, type);
|
packet_integrity_check(plen, 4 + dlen, type);
|
||||||
|
|
||||||
@ -1463,8 +1503,7 @@ do_authloop(struct passwd * pw)
|
|||||||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||||
}
|
}
|
||||||
if (skeyinfo != NULL) {
|
if (skeyinfo != NULL) {
|
||||||
/* we send our s/key- in
|
/* we send our s/key- in tis-challenge messages */
|
||||||
tis-challenge messages */
|
|
||||||
debug("sending challenge '%s'", skeyinfo);
|
debug("sending challenge '%s'", skeyinfo);
|
||||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||||
packet_put_string(skeyinfo, strlen(skeyinfo));
|
packet_put_string(skeyinfo, strlen(skeyinfo));
|
||||||
@ -1493,8 +1532,10 @@ do_authloop(struct passwd * pw)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Any unknown messages will be ignored (and
|
/*
|
||||||
failure returned) during authentication. */
|
* Any unknown messages will be ignored (and failure
|
||||||
|
* returned) during authentication.
|
||||||
|
*/
|
||||||
log("Unknown message during authentication: type %d", type);
|
log("Unknown message during authentication: type %d", type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1559,11 +1600,12 @@ do_fake_authloop(char *user)
|
|||||||
packet_send();
|
packet_send();
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
|
|
||||||
/* Keep reading packets, and always respond with a failure. This
|
/*
|
||||||
is to avoid disclosing whether such a user really exists. */
|
* Keep reading packets, and always respond with a failure. This is
|
||||||
|
* to avoid disclosing whether such a user really exists.
|
||||||
|
*/
|
||||||
for (attempt = 1;; attempt++) {
|
for (attempt = 1;; attempt++) {
|
||||||
/* Read a packet. This will not return if the client
|
/* Read a packet. This will not return if the client disconnects. */
|
||||||
disconnects. */
|
|
||||||
int plen;
|
int plen;
|
||||||
int type = packet_read(&plen);
|
int type = packet_read(&plen);
|
||||||
#ifdef SKEY
|
#ifdef SKEY
|
||||||
@ -1583,8 +1625,10 @@ do_fake_authloop(char *user)
|
|||||||
if (attempt > AUTH_FAIL_MAX)
|
if (attempt > AUTH_FAIL_MAX)
|
||||||
packet_disconnect(AUTH_FAIL_MSG, user);
|
packet_disconnect(AUTH_FAIL_MSG, user);
|
||||||
|
|
||||||
/* Send failure. This should be indistinguishable from a
|
/*
|
||||||
failed authentication. */
|
* Send failure. This should be indistinguishable from a
|
||||||
|
* failed authentication.
|
||||||
|
*/
|
||||||
packet_start(SSH_SMSG_FAILURE);
|
packet_start(SSH_SMSG_FAILURE);
|
||||||
packet_send();
|
packet_send();
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
@ -1630,19 +1674,25 @@ do_authenticated(struct passwd * pw)
|
|||||||
mode_t tty_mode;
|
mode_t tty_mode;
|
||||||
int n_bytes;
|
int n_bytes;
|
||||||
|
|
||||||
/* Cancel the alarm we set to limit the time taken for
|
/*
|
||||||
authentication. */
|
* Cancel the alarm we set to limit the time taken for
|
||||||
|
* authentication.
|
||||||
|
*/
|
||||||
alarm(0);
|
alarm(0);
|
||||||
|
|
||||||
/* Inform the channel mechanism that we are the server side and
|
/*
|
||||||
that the client may request to connect to any port at all.
|
* Inform the channel mechanism that we are the server side and that
|
||||||
(The user could do it anyway, and we wouldn\'t know what is
|
* the client may request to connect to any port at all. (The user
|
||||||
permitted except by the client telling us, so we can equally
|
* could do it anyway, and we wouldn\'t know what is permitted except
|
||||||
well trust the client not to request anything bogus.) */
|
* by the client telling us, so we can equally well trust the client
|
||||||
|
* not to request anything bogus.)
|
||||||
|
*/
|
||||||
channel_permit_all_opens();
|
channel_permit_all_opens();
|
||||||
|
|
||||||
/* We stay in this loop until the client requests to execute a
|
/*
|
||||||
shell or a command. */
|
* We stay in this loop until the client requests to execute a shell
|
||||||
|
* or a command.
|
||||||
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
int plen, dlen;
|
int plen, dlen;
|
||||||
|
|
||||||
@ -1826,8 +1876,10 @@ do_authenticated(struct passwd * pw)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Any unknown messages in this phase are ignored,
|
/*
|
||||||
and a failure message is returned. */
|
* Any unknown messages in this phase are ignored,
|
||||||
|
* and a failure message is returned.
|
||||||
|
*/
|
||||||
log("Unknown packet type received after authentication: %d", type);
|
log("Unknown packet type received after authentication: %d", type);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -1852,8 +1904,10 @@ fail:
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
do_forced_command:
|
do_forced_command:
|
||||||
/* There is a forced command specified for this login.
|
/*
|
||||||
Execute it. */
|
* There is a forced command specified for this login.
|
||||||
|
* Execute it.
|
||||||
|
*/
|
||||||
debug("Executing forced command: %.900s", forced_command);
|
debug("Executing forced command: %.900s", forced_command);
|
||||||
if (have_pty)
|
if (have_pty)
|
||||||
do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
|
do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
|
||||||
@ -1897,14 +1951,18 @@ do_exec_no_pty(const char *command, struct passwd * pw,
|
|||||||
/* Child. Reinitialize the log since the pid has changed. */
|
/* Child. Reinitialize the log since the pid has changed. */
|
||||||
log_init(av0, options.log_level, options.log_facility, log_stderr);
|
log_init(av0, 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. */
|
* Create a new session and process group since the 4.4BSD
|
||||||
|
* setlogin() affects the entire process group.
|
||||||
|
*/
|
||||||
if (setsid() < 0)
|
if (setsid() < 0)
|
||||||
error("setsid failed: %.100s", strerror(errno));
|
error("setsid failed: %.100s", strerror(errno));
|
||||||
|
|
||||||
#ifdef USE_PIPES
|
#ifdef USE_PIPES
|
||||||
/* Redirect stdin. We close the parent side of the socket
|
/*
|
||||||
pair, and make the child side the standard input. */
|
* Redirect stdin. We close the parent side of the socket
|
||||||
|
* pair, and make the child side the standard input.
|
||||||
|
*/
|
||||||
close(pin[1]);
|
close(pin[1]);
|
||||||
if (dup2(pin[0], 0) < 0)
|
if (dup2(pin[0], 0) < 0)
|
||||||
perror("dup2 stdin");
|
perror("dup2 stdin");
|
||||||
@ -1922,9 +1980,11 @@ do_exec_no_pty(const char *command, struct passwd * pw,
|
|||||||
perror("dup2 stderr");
|
perror("dup2 stderr");
|
||||||
close(perr[1]);
|
close(perr[1]);
|
||||||
#else /* USE_PIPES */
|
#else /* USE_PIPES */
|
||||||
/* Redirect stdin, stdout, and stderr. Stdin and stdout
|
/*
|
||||||
will use the same socket, as some programs
|
* Redirect stdin, stdout, and stderr. Stdin and stdout will
|
||||||
(particularly rdist) seem to depend on it. */
|
* use the same socket, as some programs (particularly rdist)
|
||||||
|
* seem to depend on it.
|
||||||
|
*/
|
||||||
close(inout[1]);
|
close(inout[1]);
|
||||||
close(err[1]);
|
close(err[1]);
|
||||||
if (dup2(inout[0], 0) < 0) /* stdin */
|
if (dup2(inout[0], 0) < 0) /* stdin */
|
||||||
@ -1955,8 +2015,10 @@ do_exec_no_pty(const char *command, struct passwd * pw,
|
|||||||
close(inout[0]);
|
close(inout[0]);
|
||||||
close(err[0]);
|
close(err[0]);
|
||||||
|
|
||||||
/* Enter the interactive session. Note: server_loop must be able
|
/*
|
||||||
to handle the case that fdin and fdout are the same. */
|
* Enter the interactive session. Note: server_loop must be able to
|
||||||
|
* handle the case that fdin and fdout are the same.
|
||||||
|
*/
|
||||||
server_loop(pid, inout[1], inout[1], err[1]);
|
server_loop(pid, inout[1], inout[1], err[1]);
|
||||||
/* server_loop has closed inout[1] and err[1]. */
|
/* server_loop has closed inout[1] and err[1]. */
|
||||||
#endif /* USE_PIPES */
|
#endif /* USE_PIPES */
|
||||||
@ -2012,8 +2074,10 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||||||
/* Get remote host name. */
|
/* Get remote host name. */
|
||||||
hostname = get_canonical_hostname();
|
hostname = get_canonical_hostname();
|
||||||
|
|
||||||
/* Get the time when the user last logged in. Buf will be set to
|
/*
|
||||||
contain the hostname the last login was from. */
|
* Get the time when the user last logged in. Buf will be set to
|
||||||
|
* contain the hostname the last login was from.
|
||||||
|
*/
|
||||||
if (!options.use_login) {
|
if (!options.use_login) {
|
||||||
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
|
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
|
||||||
buf, sizeof(buf));
|
buf, sizeof(buf));
|
||||||
@ -2049,9 +2113,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||||||
/* Close the extra descriptor for the pseudo tty. */
|
/* Close the extra descriptor for the pseudo tty. */
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
|
|
||||||
/* Get IP address of client. This is needed because we
|
/*
|
||||||
want to record where the user logged in from. If the
|
* Get IP address of client. This is needed because we want
|
||||||
connection is not a socket, let the ip address be 0.0.0.0. */
|
* to record where the user logged in from. If the
|
||||||
|
* connection is not a socket, let the ip address be 0.0.0.0.
|
||||||
|
*/
|
||||||
memset(&from, 0, sizeof(from));
|
memset(&from, 0, sizeof(from));
|
||||||
if (packet_get_connection_in() == packet_get_connection_out()) {
|
if (packet_get_connection_in() == packet_get_connection_out()) {
|
||||||
fromlen = sizeof(from);
|
fromlen = sizeof(from);
|
||||||
@ -2075,12 +2141,14 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||||||
fprintf(stderr, pamconv_msg);
|
fprintf(stderr, pamconv_msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If the user has logged in before, display the time of
|
/*
|
||||||
last login. However, don't display anything extra if a
|
* If the user has logged in before, display the time of last
|
||||||
command has been specified (so that ssh can be used to
|
* login. However, don't display anything extra if a command
|
||||||
execute commands on a remote machine without users
|
* has been specified (so that ssh can be used to execute
|
||||||
knowing they are going to another machine). Login(1)
|
* commands on a remote machine without users knowing they
|
||||||
will do this for us as well, so check if login(1) is used */
|
* are going to another machine). Login(1) will do this for
|
||||||
|
* us as well, so check if login(1) is used
|
||||||
|
*/
|
||||||
if (command == NULL && last_login_time != 0 && !quiet_login &&
|
if (command == NULL && last_login_time != 0 && !quiet_login &&
|
||||||
!options.use_login) {
|
!options.use_login) {
|
||||||
/* Convert the date to a string. */
|
/* Convert the date to a string. */
|
||||||
@ -2095,10 +2163,12 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||||||
else
|
else
|
||||||
printf("Last login: %s from %s\r\n", time_string, buf);
|
printf("Last login: %s from %s\r\n", time_string, buf);
|
||||||
}
|
}
|
||||||
/* Print /etc/motd unless a command was specified or
|
/*
|
||||||
printing it was disabled in server options or login(1)
|
* Print /etc/motd unless a command was specified or printing
|
||||||
will be used. Note that some machines appear to print
|
* it was disabled in server options or login(1) will be
|
||||||
it in /etc/profile or similar. */
|
* used. Note that some machines appear to print it in
|
||||||
|
* /etc/profile or similar.
|
||||||
|
*/
|
||||||
if (command == NULL && options.print_motd && !quiet_login &&
|
if (command == NULL && options.print_motd && !quiet_login &&
|
||||||
!options.use_login) {
|
!options.use_login) {
|
||||||
/* Print /etc/motd if it exists. */
|
/* Print /etc/motd if it exists. */
|
||||||
@ -2118,15 +2188,19 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||||||
/* Parent. Close the slave side of the pseudo tty. */
|
/* Parent. Close the slave side of the pseudo tty. */
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
|
|
||||||
/* Create another descriptor of the pty master side for use as the
|
/*
|
||||||
standard input. We could use the original descriptor, but this
|
* Create another descriptor of the pty master side for use as the
|
||||||
simplifies code in server_loop. The descriptor is bidirectional. */
|
* standard input. We could use the original descriptor, but this
|
||||||
|
* simplifies code in server_loop. The descriptor is bidirectional.
|
||||||
|
*/
|
||||||
fdout = dup(ptyfd);
|
fdout = dup(ptyfd);
|
||||||
if (fdout < 0)
|
if (fdout < 0)
|
||||||
packet_disconnect("dup failed: %.100s", strerror(errno));
|
packet_disconnect("dup failed: %.100s", strerror(errno));
|
||||||
|
|
||||||
/* Add a cleanup function to clear the utmp entry and record logout
|
/*
|
||||||
time in case we call fatal() (e.g., the connection gets closed). */
|
* Add a cleanup function to clear the utmp entry and record logout
|
||||||
|
* time in case we call fatal() (e.g., the connection gets closed).
|
||||||
|
*/
|
||||||
cleanup_context.pid = pid;
|
cleanup_context.pid = pid;
|
||||||
cleanup_context.ttyname = ttyname;
|
cleanup_context.ttyname = ttyname;
|
||||||
fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
|
fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
|
||||||
@ -2144,9 +2218,11 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||||||
/* Release the pseudo-tty. */
|
/* Release the pseudo-tty. */
|
||||||
pty_release(ttyname);
|
pty_release(ttyname);
|
||||||
|
|
||||||
/* Close the server side of the socket pairs. We must do this
|
/*
|
||||||
after the pty cleanup, so that another process doesn't get this
|
* Close the server side of the socket pairs. We must do this after
|
||||||
pty while we're still cleaning up. */
|
* the pty cleanup, so that another process doesn't get this pty
|
||||||
|
* while we're still cleaning up.
|
||||||
|
*/
|
||||||
close(ptyfd);
|
close(ptyfd);
|
||||||
close(fdout);
|
close(fdout);
|
||||||
}
|
}
|
||||||
@ -2162,19 +2238,21 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name,
|
|||||||
unsigned int i, namelen;
|
unsigned int i, namelen;
|
||||||
char **env;
|
char **env;
|
||||||
|
|
||||||
/* Find the slot where the value should be stored. If the
|
/*
|
||||||
variable already exists, we reuse the slot; otherwise we append
|
* Find the slot where the value should be stored. If the variable
|
||||||
a new slot at the end of the array, expanding if necessary. */
|
* already exists, we reuse the slot; otherwise we append a new slot
|
||||||
|
* at the end of the array, expanding if necessary.
|
||||||
|
*/
|
||||||
env = *envp;
|
env = *envp;
|
||||||
namelen = strlen(name);
|
namelen = strlen(name);
|
||||||
for (i = 0; env[i]; i++)
|
for (i = 0; env[i]; i++)
|
||||||
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
|
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
|
||||||
break;
|
break;
|
||||||
if (env[i]) {
|
if (env[i]) {
|
||||||
/* Name already exists. Reuse the slot. */
|
/* Reuse the slot. */
|
||||||
xfree(env[i]);
|
xfree(env[i]);
|
||||||
} else {
|
} else {
|
||||||
/* New variable. Expand the array if necessary. */
|
/* New variable. Expand if necessary. */
|
||||||
if (i >= (*envsizep) - 1) {
|
if (i >= (*envsizep) - 1) {
|
||||||
(*envsizep) += 50;
|
(*envsizep) += 50;
|
||||||
env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
|
env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
|
||||||
@ -2202,40 +2280,27 @@ read_environment_file(char ***env, unsigned int *envsize,
|
|||||||
char buf[4096];
|
char buf[4096];
|
||||||
char *cp, *value;
|
char *cp, *value;
|
||||||
|
|
||||||
/* Open the environment file. */
|
|
||||||
f = fopen(filename, "r");
|
f = fopen(filename, "r");
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Process each line. */
|
|
||||||
while (fgets(buf, sizeof(buf), f)) {
|
while (fgets(buf, sizeof(buf), f)) {
|
||||||
/* Skip leading whitespace. */
|
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++);
|
;
|
||||||
|
|
||||||
/* Ignore empty and comment lines. */
|
|
||||||
if (!*cp || *cp == '#' || *cp == '\n')
|
if (!*cp || *cp == '#' || *cp == '\n')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Remove newline. */
|
|
||||||
if (strchr(cp, '\n'))
|
if (strchr(cp, '\n'))
|
||||||
*strchr(cp, '\n') = '\0';
|
*strchr(cp, '\n') = '\0';
|
||||||
|
|
||||||
/* Find the equals sign. Its lack indicates badly
|
|
||||||
formatted line. */
|
|
||||||
value = strchr(cp, '=');
|
value = strchr(cp, '=');
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
|
fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Replace the equals sign by nul, and advance value to
|
/* Replace the equals sign by nul, and advance value to the value string. */
|
||||||
the value string. */
|
|
||||||
*value = '\0';
|
*value = '\0';
|
||||||
value++;
|
value++;
|
||||||
|
|
||||||
/* Set the value in environment. */
|
|
||||||
child_set_env(env, envsize, cp, value);
|
child_set_env(env, envsize, cp, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2299,8 +2364,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
|
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
|
||||||
fatal("Failed to set uids to %d.", (int) pw->pw_uid);
|
fatal("Failed to set uids to %d.", (int) pw->pw_uid);
|
||||||
}
|
}
|
||||||
/* Get the shell from the password data. An empty shell field is
|
/*
|
||||||
legal, and means /bin/sh. */
|
* Get the shell from the password data. An empty shell field is
|
||||||
|
* legal, and means /bin/sh.
|
||||||
|
*/
|
||||||
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
|
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
|
||||||
|
|
||||||
#ifdef AFS
|
#ifdef AFS
|
||||||
@ -2315,8 +2382,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
}
|
}
|
||||||
#endif /* AFS */
|
#endif /* AFS */
|
||||||
|
|
||||||
/* Initialize the environment. In the first part we allocate
|
/* Initialize the environment. */
|
||||||
space for all environment variables. */
|
|
||||||
envsize = 100;
|
envsize = 100;
|
||||||
env = xmalloc(envsize * sizeof(char *));
|
env = xmalloc(envsize * sizeof(char *));
|
||||||
env[0] = NULL;
|
env[0] = NULL;
|
||||||
@ -2335,7 +2401,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
/* Normal systems set SHELL by default. */
|
/* Normal systems set SHELL by default. */
|
||||||
child_set_env(&env, &envsize, "SHELL", shell);
|
child_set_env(&env, &envsize, "SHELL", shell);
|
||||||
}
|
}
|
||||||
/* Let it inherit timezone if we have one. */
|
|
||||||
if (getenv("TZ"))
|
if (getenv("TZ"))
|
||||||
child_set_env(&env, &envsize, "TZ", getenv("TZ"));
|
child_set_env(&env, &envsize, "TZ", getenv("TZ"));
|
||||||
|
|
||||||
@ -2354,20 +2419,14 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
xfree(ce);
|
xfree(ce);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set SSH_CLIENT. */
|
|
||||||
snprintf(buf, sizeof buf, "%.50s %d %d",
|
snprintf(buf, sizeof buf, "%.50s %d %d",
|
||||||
get_remote_ipaddr(), get_remote_port(), options.port);
|
get_remote_ipaddr(), get_remote_port(), options.port);
|
||||||
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
|
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
|
||||||
|
|
||||||
/* Set SSH_TTY if we have a pty. */
|
|
||||||
if (ttyname)
|
if (ttyname)
|
||||||
child_set_env(&env, &envsize, "SSH_TTY", ttyname);
|
child_set_env(&env, &envsize, "SSH_TTY", ttyname);
|
||||||
|
|
||||||
/* Set TERM if we have a pty. */
|
|
||||||
if (term)
|
if (term)
|
||||||
child_set_env(&env, &envsize, "TERM", term);
|
child_set_env(&env, &envsize, "TERM", term);
|
||||||
|
|
||||||
/* Set DISPLAY if we have one. */
|
|
||||||
if (display)
|
if (display)
|
||||||
child_set_env(&env, &envsize, "DISPLAY", display);
|
child_set_env(&env, &envsize, "DISPLAY", display);
|
||||||
|
|
||||||
@ -2400,52 +2459,57 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
}
|
}
|
||||||
#endif /* HAVE_LIBPAM */
|
#endif /* HAVE_LIBPAM */
|
||||||
|
|
||||||
/* Set XAUTHORITY to always be a local file. */
|
|
||||||
if (xauthfile)
|
if (xauthfile)
|
||||||
child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
|
child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
|
||||||
|
|
||||||
/* Set variable for forwarded authentication connection, if we
|
|
||||||
have one. */
|
|
||||||
if (auth_get_socket_name() != NULL)
|
if (auth_get_socket_name() != NULL)
|
||||||
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
|
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
|
||||||
auth_get_socket_name());
|
auth_get_socket_name());
|
||||||
|
|
||||||
/* Read $HOME/.ssh/environment. */
|
/* read $HOME/.ssh/environment. */
|
||||||
if (!options.use_login) {
|
if (!options.use_login) {
|
||||||
snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
|
snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
|
||||||
read_environment_file(&env, &envsize, buf);
|
read_environment_file(&env, &envsize, buf);
|
||||||
}
|
}
|
||||||
/* If debugging, dump the environment to stderr. */
|
|
||||||
if (debug_flag) {
|
if (debug_flag) {
|
||||||
|
/* dump the environment */
|
||||||
fprintf(stderr, "Environment:\n");
|
fprintf(stderr, "Environment:\n");
|
||||||
for (i = 0; env[i]; i++)
|
for (i = 0; env[i]; i++)
|
||||||
fprintf(stderr, " %.200s\n", env[i]);
|
fprintf(stderr, " %.200s\n", env[i]);
|
||||||
}
|
}
|
||||||
/* Close the connection descriptors; note that this is the child,
|
/*
|
||||||
and the server will still have the socket open, and it is
|
* Close the connection descriptors; note that this is the child, and
|
||||||
important that we do not shutdown it. Note that the
|
* the server will still have the socket open, and it is important
|
||||||
descriptors cannot be closed before building the environment,
|
* that we do not shutdown it. Note that the descriptors cannot be
|
||||||
as we call get_remote_ipaddr there. */
|
* closed before building the environment, as we call
|
||||||
|
* get_remote_ipaddr there.
|
||||||
|
*/
|
||||||
if (packet_get_connection_in() == packet_get_connection_out())
|
if (packet_get_connection_in() == packet_get_connection_out())
|
||||||
close(packet_get_connection_in());
|
close(packet_get_connection_in());
|
||||||
else {
|
else {
|
||||||
close(packet_get_connection_in());
|
close(packet_get_connection_in());
|
||||||
close(packet_get_connection_out());
|
close(packet_get_connection_out());
|
||||||
}
|
}
|
||||||
/* Close all descriptors related to channels. They will still
|
/*
|
||||||
remain open in the parent. */
|
* Close all descriptors related to channels. They will still remain
|
||||||
|
* open in the parent.
|
||||||
|
*/
|
||||||
|
/* XXX better use close-on-exec? -markus */
|
||||||
channel_close_all();
|
channel_close_all();
|
||||||
|
|
||||||
/* Close any extra file descriptors. Note that there may still be
|
/*
|
||||||
descriptors left by system functions. They will be closed
|
* Close any extra file descriptors. Note that there may still be
|
||||||
later. */
|
* descriptors left by system functions. They will be closed later.
|
||||||
|
*/
|
||||||
endpwent();
|
endpwent();
|
||||||
endhostent();
|
endhostent();
|
||||||
|
|
||||||
/* Close any extra open file descriptors so that we don\'t have
|
/*
|
||||||
them hanging around in clients. Note that we want to do this
|
* Close any extra open file descriptors so that we don\'t have them
|
||||||
after initgroups, because at least on Solaris 2.3 it leaves
|
* hanging around in clients. Note that we want to do this after
|
||||||
file descriptors open. */
|
* initgroups, because at least on Solaris 2.3 it leaves file
|
||||||
|
* descriptors open.
|
||||||
|
*/
|
||||||
for (i = 3; i < 64; i++)
|
for (i = 3; i < 64; i++)
|
||||||
close(i);
|
close(i);
|
||||||
|
|
||||||
@ -2454,12 +2518,16 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
fprintf(stderr, "Could not chdir to home directory %s: %s\n",
|
fprintf(stderr, "Could not chdir to home directory %s: %s\n",
|
||||||
pw->pw_dir, strerror(errno));
|
pw->pw_dir, strerror(errno));
|
||||||
|
|
||||||
/* Must take new environment into use so that .ssh/rc, /etc/sshrc
|
/*
|
||||||
and xauth are run in the proper environment. */
|
* Must take new environment into use so that .ssh/rc, /etc/sshrc and
|
||||||
|
* xauth are run in the proper environment.
|
||||||
|
*/
|
||||||
environ = env;
|
environ = env;
|
||||||
|
|
||||||
/* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found
|
/*
|
||||||
first in this order). */
|
* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
|
||||||
|
* in this order).
|
||||||
|
*/
|
||||||
if (!options.use_login) {
|
if (!options.use_login) {
|
||||||
if (stat(SSH_USER_RC, &st) >= 0) {
|
if (stat(SSH_USER_RC, &st) >= 0) {
|
||||||
if (debug_flag)
|
if (debug_flag)
|
||||||
@ -2486,8 +2554,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
}
|
}
|
||||||
#ifdef XAUTH_PATH
|
#ifdef XAUTH_PATH
|
||||||
else {
|
else {
|
||||||
/* Add authority data to .Xauthority if
|
/* Add authority data to .Xauthority if appropriate. */
|
||||||
appropriate. */
|
|
||||||
if (auth_proto != NULL && auth_data != NULL) {
|
if (auth_proto != NULL && auth_data != NULL) {
|
||||||
if (debug_flag)
|
if (debug_flag)
|
||||||
fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
|
fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
|
||||||
@ -2510,15 +2577,19 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
else
|
else
|
||||||
cp = shell;
|
cp = shell;
|
||||||
}
|
}
|
||||||
/* If we have no command, execute the shell. In this case, the
|
/*
|
||||||
shell name to be passed in argv[0] is preceded by '-' to
|
* If we have no command, execute the shell. In this case, the shell
|
||||||
indicate that this is a login shell. */
|
* name to be passed in argv[0] is preceded by '-' to indicate that
|
||||||
|
* this is a login shell.
|
||||||
|
*/
|
||||||
if (!command) {
|
if (!command) {
|
||||||
if (!options.use_login) {
|
if (!options.use_login) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
/* Check for mail if we have a tty and it was
|
/*
|
||||||
enabled in server options. */
|
* Check for mail if we have a tty and it was enabled
|
||||||
|
* in server options.
|
||||||
|
*/
|
||||||
if (ttyname && options.check_mail) {
|
if (ttyname && options.check_mail) {
|
||||||
char *mailbox;
|
char *mailbox;
|
||||||
struct stat mailstat;
|
struct stat mailstat;
|
||||||
@ -2558,8 +2629,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Execute the command using the user's shell. This uses the -c
|
/*
|
||||||
option to execute the command. */
|
* Execute the command using the user's shell. This uses the -c
|
||||||
|
* option to execute the command.
|
||||||
|
*/
|
||||||
argv[0] = (char *) cp;
|
argv[0] = (char *) cp;
|
||||||
argv[1] = "-c";
|
argv[1] = "-c";
|
||||||
argv[2] = (char *) command;
|
argv[2] = (char *) command;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: tildexpand.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
RCSID("$Id: tildexpand.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -47,12 +47,12 @@ tilde_expand_filename(const char *filename, uid_t my_uid)
|
|||||||
user[userlen] = 0;
|
user[userlen] = 0;
|
||||||
pw = getpwnam(user);
|
pw = getpwnam(user);
|
||||||
}
|
}
|
||||||
/* Check that we found the user. */
|
|
||||||
if (!pw)
|
if (!pw)
|
||||||
fatal("Unknown user %100s.", user);
|
fatal("Unknown user %100s.", user);
|
||||||
|
|
||||||
/* If referring to someones home directory, return it now. */
|
/* If referring to someones home directory, return it now. */
|
||||||
if (!cp) { /* Only home directory specified */
|
if (!cp) {
|
||||||
|
/* Only home directory specified */
|
||||||
return xstrdup(pw->pw_dir);
|
return xstrdup(pw->pw_dir);
|
||||||
}
|
}
|
||||||
/* Build a path combining the specified directory and path. */
|
/* Build a path combining the specified directory and path. */
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ttymodes.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
RCSID("$Id: ttymodes.c,v 1.3 1999/11/25 00:54:59 damien Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -209,7 +209,6 @@ tty_make_modes(int fd)
|
|||||||
struct termios tio;
|
struct termios tio;
|
||||||
int baud;
|
int baud;
|
||||||
|
|
||||||
/* Get the modes. */
|
|
||||||
if (tcgetattr(fd, &tio) < 0) {
|
if (tcgetattr(fd, &tio) < 0) {
|
||||||
packet_put_char(TTY_OP_END);
|
packet_put_char(TTY_OP_END);
|
||||||
log("tcgetattr: %.100s", strerror(errno));
|
log("tcgetattr: %.100s", strerror(errno));
|
||||||
|
11
ttymodes.h
11
ttymodes.h
@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: ttymodes.h,v 1.2 1999/11/24 13:26:23 damien Exp $"); */
|
/* RCSID("$Id: ttymodes.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */
|
||||||
|
|
||||||
/* The tty mode description is a stream of bytes. The stream consists of
|
/* The tty mode description is a stream of bytes. The stream consists of
|
||||||
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
|
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
|
||||||
@ -29,10 +29,10 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Some constants and prototypes are defined in packet.h; this file
|
* Some constants and prototypes are defined in packet.h; this file
|
||||||
* is only intended for including from ttymodes.h.
|
* is only intended for including from ttymodes.c.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* termios macro *//* sgtty macro */
|
/* termios macro */ /* sgtty macro */
|
||||||
/* name, op */
|
/* name, op */
|
||||||
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
||||||
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
||||||
@ -92,7 +92,7 @@ TTYMODE(IXON, c_iflag, 38) /* n/a */
|
|||||||
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
||||||
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
||||||
#ifdef IMAXBEL
|
#ifdef IMAXBEL
|
||||||
TTYMODE(IMAXBEL, c_iflag, 41) /* n/a */
|
TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */
|
||||||
#endif /* IMAXBEL */
|
#endif /* IMAXBEL */
|
||||||
|
|
||||||
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
||||||
@ -110,7 +110,7 @@ TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
|
|||||||
TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
|
TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
|
||||||
#endif /* IEXTEN */
|
#endif /* IEXTEN */
|
||||||
#if defined(ECHOCTL)
|
#if defined(ECHOCTL)
|
||||||
TTYMODE(ECHOCTL, c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
||||||
#endif /* ECHOCTL */
|
#endif /* ECHOCTL */
|
||||||
#ifdef ECHOKE
|
#ifdef ECHOKE
|
||||||
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
||||||
@ -138,3 +138,4 @@ TTYMODE(CS7, c_cflag, 90) /* n/a */
|
|||||||
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
||||||
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
||||||
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
||||||
|
|
||||||
|
11
uidswap.c
11
uidswap.c
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: uidswap.c,v 1.2 1999/11/24 13:26:23 damien Exp $");
|
RCSID("$Id: uidswap.c,v 1.3 1999/11/25 00:55:00 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "uidswap.h"
|
#include "uidswap.h"
|
||||||
@ -66,10 +66,11 @@ restore_uid()
|
|||||||
if (seteuid(saved_euid) < 0)
|
if (seteuid(saved_euid) < 0)
|
||||||
debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
|
debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
|
||||||
#else /* SAVED_IDS_WORK_WITH_SETEUID */
|
#else /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||||
/* We are unable to restore the real uid to its unprivileged
|
/*
|
||||||
value. */
|
* We are unable to restore the real uid to its unprivileged value.
|
||||||
/* Propagate the real uid (usually more privileged) to effective
|
* Propagate the real uid (usually more privileged) to effective uid
|
||||||
uid as well. */
|
* as well.
|
||||||
|
*/
|
||||||
setuid(getuid());
|
setuid(getuid());
|
||||||
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user