зеркало из https://github.com/Azure/sonic-openssh.git
- 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:
Родитель
9072e18896
Коммит
5428f646ad
|
@ -11,7 +11,7 @@
|
|||
|
||||
#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 "ssh.h"
|
||||
|
@ -39,14 +39,10 @@ auth_password(struct passwd * pw, const char *password)
|
|||
struct spwd *spw;
|
||||
#endif
|
||||
|
||||
if (pw->pw_uid == 0 && options.permit_root_login == 2) {
|
||||
/* Server does not permit root login with password */
|
||||
if (pw->pw_uid == 0 && options.permit_root_login == 2)
|
||||
return 0;
|
||||
}
|
||||
if (*password == '\0' && options.permit_empty_passwd == 0) {
|
||||
/* Server does not permit empty password login */
|
||||
if (*password == '\0' && options.permit_empty_passwd == 0)
|
||||
return 0;
|
||||
}
|
||||
/* deny if no user. */
|
||||
if (pw == NULL)
|
||||
return 0;
|
||||
|
@ -74,8 +70,10 @@ auth_password(struct passwd * pw, const char *password)
|
|||
#endif
|
||||
|
||||
#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) {
|
||||
AUTH_DAT adata;
|
||||
KTEXT_ST tkt;
|
||||
|
@ -86,8 +84,10 @@ auth_password(struct passwd * pw, const char *password)
|
|||
char realm[REALM_SZ];
|
||||
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) {
|
||||
|
||||
/* Set up our ticket file. */
|
||||
|
@ -144,14 +144,17 @@ auth_password(struct passwd * pw, const char *password)
|
|||
goto kerberos_auth_failure;
|
||||
}
|
||||
} 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 "
|
||||
"not registered, or srvtab is wrong?", pw->pw_name,
|
||||
krb_err_txt[r], KRB4_SERVICE_NAME, phost);
|
||||
} else {
|
||||
/* TGT is bad, forget it. Possibly
|
||||
spoofed! */
|
||||
/*
|
||||
* TGT is bad, forget it. Possibly spoofed!
|
||||
*/
|
||||
packet_send_debug("WARNING: Kerberos V4 TGT "
|
||||
"possibly spoofed for %s: %s",
|
||||
pw->pw_name, krb_err_txt[r]);
|
||||
|
@ -175,11 +178,8 @@ auth_password(struct passwd * pw, const char *password)
|
|||
#endif /* KRB4 */
|
||||
|
||||
/* Check for users with no password. */
|
||||
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) {
|
||||
packet_send_debug("Login permitted without a password "
|
||||
"because the account has no password.");
|
||||
if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
spw = getspnam(pw->pw_name);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#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 "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 "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
|
||||
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) {
|
||||
struct stat st;
|
||||
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 &&
|
||||
(stat(user_hostfile, &st) == 0) &&
|
||||
((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);
|
||||
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.",
|
||||
pw->pw_name, client_user, canonical_hostname);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#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 "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 "servconf.h"
|
||||
|
||||
/* This function processes an rhosts-style file (.rhosts, .shosts, or
|
||||
/etc/hosts.equiv). This returns true if authentication can be granted
|
||||
based on the file, and returns zero otherwise. */
|
||||
/*
|
||||
* This function processes an rhosts-style file (.rhosts, .shosts, or
|
||||
* /etc/hosts.equiv). This returns true if authentication can be granted
|
||||
* based on the file, and returns zero otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
check_rhosts_file(const char *filename, const char *hostname,
|
||||
|
@ -41,7 +43,6 @@ check_rhosts_file(const char *filename, const char *hostname,
|
|||
if (!f)
|
||||
return 0;
|
||||
|
||||
/* Go through the file, checking every entry. */
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
/* All three must be at least as big as buf to avoid overflows. */
|
||||
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)
|
||||
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)
|
||||
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)) {
|
||||
case 0:
|
||||
packet_send_debug("Found empty line in %.100s.", filename);
|
||||
|
@ -135,10 +140,11 @@ check_rhosts_file(const char *filename, const char *hostname,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Tries to authenticate the user using the .shosts or .rhosts file.
|
||||
Returns true if authentication succeeds. If ignore_rhosts is
|
||||
true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
|
||||
are ignored). */
|
||||
/*
|
||||
* Tries to authenticate the user using the .shosts or .rhosts file. Returns
|
||||
* true if authentication succeeds. If ignore_rhosts is true, only
|
||||
* /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
|
||||
*/
|
||||
|
||||
int
|
||||
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};
|
||||
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. */
|
||||
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];
|
||||
rhosts_file_index++) {
|
||||
/* Check users .rhosts or .shosts. */
|
||||
|
@ -172,7 +180,6 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||
stat(SSH_HOSTS_EQUIV, &st) < 0)
|
||||
return 0;
|
||||
|
||||
/* Get the name, address, and port of the remote host. */
|
||||
hostname = get_canonical_hostname();
|
||||
ipaddr = get_remote_ipaddr();
|
||||
|
||||
|
@ -191,8 +198,10 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||
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) {
|
||||
log("Rhosts authentication refused for %.100s: no home directory %.200s",
|
||||
pw->pw_name, pw->pw_dir);
|
||||
|
@ -221,10 +230,12 @@ auth_rhosts(struct passwd *pw, const char *client_user)
|
|||
if (stat(buf, &st) < 0)
|
||||
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
|
||||
the owner. This is to help avoid novices accidentally
|
||||
allowing access to their account by anyone. */
|
||||
/*
|
||||
* Make sure that the file is either owned by the user or by
|
||||
* root, and make sure it is not writable by anyone but the
|
||||
* owner. This is to help avoid novices accidentally
|
||||
* allowing access to their account by anyone.
|
||||
*/
|
||||
if (options.strict_modes &&
|
||||
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0)) {
|
||||
|
|
95
auth-rsa.c
95
auth-rsa.c
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#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 "packet.h"
|
||||
|
@ -43,22 +43,27 @@ extern int no_pty_flag;
|
|||
extern char *forced_command;
|
||||
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];
|
||||
|
||||
/* The .ssh/authorized_keys file contains public keys, one per line, in the
|
||||
following format:
|
||||
options bits e n comment
|
||||
where bits, e and n are decimal numbers,
|
||||
and comment is any string of characters up to newline. The maximum
|
||||
length of a line is 8000 characters. See the documentation for a
|
||||
description of the options.
|
||||
*/
|
||||
/*
|
||||
* The .ssh/authorized_keys file contains public keys, one per line, in the
|
||||
* following format:
|
||||
* options bits e n comment
|
||||
* where bits, e and n are decimal numbers,
|
||||
* and comment is any string of characters up to newline. The maximum
|
||||
* 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
|
||||
our challenge; returns zero if the client gives a wrong answer. */
|
||||
/*
|
||||
* Performs the RSA authentication challenge-response dialog with the client,
|
||||
* 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)
|
||||
|
@ -128,9 +133,11 @@ auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n)
|
|||
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
|
||||
successful. This may exit if there is a serious protocol violation. */
|
||||
/*
|
||||
* Performs the RSA authentication dialog with the client. This returns
|
||||
* 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
|
||||
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. */
|
||||
authenticated = 0;
|
||||
|
||||
/* Initialize mp-int variables. */
|
||||
e = 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
|
||||
user really has the corresponding private key. */
|
||||
/*
|
||||
* Go though the accepted keys, looking for the current key. If
|
||||
* found, perform a challenge-response dialog to verify that the
|
||||
* user really has the corresponding private key.
|
||||
*/
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *cp;
|
||||
char *options;
|
||||
|
||||
linenum++;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Skip empty and comment lines. */
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
/* Check if there are options for this key, and if so,
|
||||
save their starting address and skip the option part
|
||||
for now. If there are no options, set the starting
|
||||
address to NULL. */
|
||||
/*
|
||||
* Check if there are options for this key, and if so,
|
||||
* save their starting address and skip the option part
|
||||
* for now. If there are no options, set the starting
|
||||
* address to NULL.
|
||||
*/
|
||||
if (*cp < '0' || *cp > '9') {
|
||||
int quoted = 0;
|
||||
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). */
|
||||
if (BN_cmp(n, client_n) != 0)
|
||||
continue; /* Wrong key. */
|
||||
continue;
|
||||
|
||||
/* 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.");
|
||||
continue;
|
||||
}
|
||||
/* Correct response. The client has been successfully
|
||||
authenticated. Note that we have not yet processed the
|
||||
options; this will be reset if the options cause the
|
||||
authentication to be rejected. */
|
||||
/*
|
||||
* Correct response. The client has been successfully
|
||||
* authenticated. Note that we have not yet processed the
|
||||
* options; this will be reset if the options cause the
|
||||
* authentication to be rejected.
|
||||
*/
|
||||
authenticated = 1;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
bad_option:
|
||||
/* Unknown option. */
|
||||
log("Bad options in %.100s file, line %lu: %.50s",
|
||||
SSH_USER_PERMITTED_KEYS, linenum, options);
|
||||
packet_send_debug("Bad options in %.100s file, line %lu: %.50s",
|
||||
|
@ -421,12 +431,14 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||
break;
|
||||
|
||||
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)
|
||||
fatal("Bugs in auth-rsa.c option processing.");
|
||||
if (*options == ' ' || *options == '\t')
|
||||
break; /* End of options. */
|
||||
break; /* End of options. */
|
||||
if (*options != ',')
|
||||
goto bad_option;
|
||||
options++;
|
||||
|
@ -434,8 +446,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||
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)
|
||||
break;
|
||||
}
|
||||
|
@ -446,7 +460,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||
/* Close the file. */
|
||||
fclose(f);
|
||||
|
||||
/* Clear any mp-int variables. */
|
||||
BN_clear_free(n);
|
||||
BN_clear_free(e);
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#include "includes.h"
|
||||
|
||||
#ifdef SKEY
|
||||
|
||||
RCSID("$Id: auth-skey.c,v 1.3 1999/11/23 22:25:52 markus Exp $");
|
||||
|
||||
#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 % */
|
||||
|
||||
|
|
127
authfd.c
127
authfd.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#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 "rsa.h"
|
||||
|
@ -63,9 +63,11 @@ ssh_get_authentication_socket()
|
|||
return sock;
|
||||
}
|
||||
|
||||
/* Closes the agent socket if it should be closed (depends on how it was
|
||||
obtained). The argument must have been returned by
|
||||
ssh_get_authentication_socket(). */
|
||||
/*
|
||||
* Closes the agent socket if it should be closed (depends on how it was
|
||||
* obtained). The argument must have been returned by
|
||||
* ssh_get_authentication_socket().
|
||||
*/
|
||||
|
||||
void
|
||||
ssh_close_authentication_socket(int sock)
|
||||
|
@ -74,11 +76,13 @@ ssh_close_authentication_socket(int sock)
|
|||
close(sock);
|
||||
}
|
||||
|
||||
/* Opens and connects a private socket for communication with the
|
||||
authentication agent. Returns the file descriptor (which must be
|
||||
shut down and closed by the caller when no longer needed).
|
||||
Returns NULL if an error occurred and the connection could not be
|
||||
opened. */
|
||||
/*
|
||||
* Opens and connects a private socket for communication with the
|
||||
* authentication agent. Returns the file descriptor (which must be
|
||||
* shut down and closed by the caller when no longer needed).
|
||||
* Returns NULL if an error occurred and the connection could not be
|
||||
* opened.
|
||||
*/
|
||||
|
||||
AuthenticationConnection *
|
||||
ssh_get_authentication_connection()
|
||||
|
@ -88,12 +92,13 @@ ssh_get_authentication_connection()
|
|||
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
/* Applocate the connection structure and initialize it. */
|
||||
auth = xmalloc(sizeof(*auth));
|
||||
auth->fd = sock;
|
||||
buffer_init(&auth->packet);
|
||||
|
@ -103,8 +108,10 @@ ssh_get_authentication_connection()
|
|||
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
|
||||
ssh_close_authentication_connection(AuthenticationConnection *ac)
|
||||
|
@ -115,10 +122,12 @@ ssh_close_authentication_connection(AuthenticationConnection *ac)
|
|||
xfree(ac);
|
||||
}
|
||||
|
||||
/* Returns the first authentication identity held by the agent.
|
||||
Returns true if an identity is available, 0 otherwise.
|
||||
The caller must initialize the integers before the call, and free the
|
||||
comment after a successful call (before calling ssh_get_next_identity). */
|
||||
/*
|
||||
* Returns the first authentication identity held by the agent.
|
||||
* Returns true if an identity is available, 0 otherwise.
|
||||
* The caller must initialize the integers before the call, and free the
|
||||
* comment after a successful call (before calling ssh_get_next_identity).
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_get_first_identity(AuthenticationConnection *auth,
|
||||
|
@ -127,8 +136,10 @@ ssh_get_first_identity(AuthenticationConnection *auth,
|
|||
unsigned char msg[8192];
|
||||
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[1] = 0;
|
||||
msg[2] = 0;
|
||||
|
@ -149,8 +160,10 @@ ssh_get_first_identity(AuthenticationConnection *auth,
|
|||
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);
|
||||
if (len < 1 || len > 256 * 1024)
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
function. This returns 0 if there are no more identities. The caller
|
||||
must free comment after a successful return. */
|
||||
/*
|
||||
* 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
|
||||
* function. This returns 0 if there are no more identities. The caller
|
||||
* must free comment after a successful return.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_get_next_identity(AuthenticationConnection *auth,
|
||||
|
@ -197,8 +212,10 @@ ssh_get_next_identity(AuthenticationConnection *auth,
|
|||
if (auth->howmany <= 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);
|
||||
buffer_get_bignum(&auth->identities, e);
|
||||
buffer_get_bignum(&auth->identities, n);
|
||||
|
@ -214,11 +231,13 @@ ssh_get_next_identity(AuthenticationConnection *auth,
|
|||
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
|
||||
answer, zero otherwise. Response type selects the style of response
|
||||
desired, with 0 corresponding to protocol version 1.0 (no longer supported)
|
||||
and 1 corresponding to protocol version 1.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 answer, zero otherwise. Response type selects the style of
|
||||
* response desired, with 0 corresponding to protocol version 1.0 (no longer
|
||||
* supported) and 1 corresponding to protocol version 1.1.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
|
@ -259,8 +278,10 @@ error_cleanup:
|
|||
buffer_free(&buffer);
|
||||
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;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
|
@ -303,8 +324,10 @@ error_cleanup:
|
|||
if (buf[0] != SSH_AGENT_RSA_RESPONSE)
|
||||
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++)
|
||||
response[i] = buffer_get_char(&buffer);
|
||||
|
||||
|
@ -315,8 +338,10 @@ error_cleanup:
|
|||
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
|
||||
ssh_add_identity(AuthenticationConnection *auth,
|
||||
|
@ -401,8 +426,10 @@ error_cleanup:
|
|||
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
|
||||
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||
|
@ -431,8 +458,10 @@ error_cleanup:
|
|||
buffer_free(&buffer);
|
||||
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;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
|
@ -480,8 +509,10 @@ error_cleanup:
|
|||
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
|
||||
ssh_remove_all_identities(AuthenticationConnection *auth)
|
||||
|
@ -499,8 +530,10 @@ ssh_remove_all_identities(AuthenticationConnection *auth)
|
|||
error("Error writing to authentication socket.");
|
||||
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;
|
||||
while (len > 0) {
|
||||
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
|
||||
#define AUTHFD_H
|
||||
|
@ -40,33 +40,43 @@ typedef struct {
|
|||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
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
|
||||
obtained, this may close the descriptor. */
|
||||
/*
|
||||
* This should be called for any descriptor returned by
|
||||
* ssh_get_authentication_socket(). Depending on the way the descriptor was
|
||||
* obtained, this may close the descriptor.
|
||||
*/
|
||||
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
|
||||
connection could not be opened. The connection should be closed by
|
||||
the caller by calling ssh_close_authentication_connection(). */
|
||||
/*
|
||||
* Opens and connects a private socket for communication with the
|
||||
* authentication agent. Returns NULL if an error occurred and the
|
||||
* connection could not be opened. The connection should be closed by the
|
||||
* caller by calling ssh_close_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);
|
||||
|
||||
/* Returns the first authentication identity held by the agent.
|
||||
Returns true if an identity is available, 0 otherwise.
|
||||
The caller must initialize the integers before the call, and free the
|
||||
comment after a successful call (before calling ssh_get_next_identity). */
|
||||
/*
|
||||
* Returns the first authentication identity held by the agent. Returns true
|
||||
* if an identity is available, 0 otherwise. The caller must initialize the
|
||||
* integers before the call, and free the comment after a successful call
|
||||
* (before calling ssh_get_next_identity).
|
||||
*/
|
||||
int
|
||||
ssh_get_first_identity(AuthenticationConnection * connection,
|
||||
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
|
||||
function. This returns 0 if there are no more identities. The caller
|
||||
must free comment after a successful return. */
|
||||
/*
|
||||
* 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
|
||||
* function. This returns 0 if there are no more identities. The caller
|
||||
* must free comment after a successful return.
|
||||
*/
|
||||
int
|
||||
ssh_get_next_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
@ -80,24 +90,30 @@ ssh_decrypt_challenge(AuthenticationConnection * auth,
|
|||
unsigned int response_type,
|
||||
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
|
||||
was successfully added. */
|
||||
int ssh_add_identity(AuthenticationConnection * connection,
|
||||
RSA * key, const char *comment);
|
||||
/*
|
||||
* Adds an identity to the authentication server. This call is not meant to
|
||||
* be used by normal applications. This returns true if the identity was
|
||||
* successfully added.
|
||||
*/
|
||||
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
|
||||
identity was successfully added. */
|
||||
int ssh_remove_identity(AuthenticationConnection * connection,
|
||||
RSA * key);
|
||||
/*
|
||||
* Removes the identity from the authentication server. This call is not
|
||||
* meant to be used by normal applications. This returns true if the
|
||||
* identity was successfully added.
|
||||
*/
|
||||
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
|
||||
operation was successful. */
|
||||
int ssh_remove_all_identities(AuthenticationConnection * connection);
|
||||
/*
|
||||
* Removes all identities from the authentication agent. This call is not
|
||||
* meant to be used by normal applications. This returns true if the
|
||||
* operation was successful.
|
||||
*/
|
||||
int ssh_remove_all_identities(AuthenticationConnection * connection);
|
||||
|
||||
/* Closes the connection to the authentication agent. */
|
||||
void ssh_close_authentication(AuthenticationConnection * connection);
|
||||
void ssh_close_authentication(AuthenticationConnection * connection);
|
||||
|
||||
#endif /* AUTHFD_H */
|
||||
|
|
63
authfile.c
63
authfile.c
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#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
|
||||
#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. */
|
||||
#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)
|
||||
will precede the key to provide identification of the key without
|
||||
needing a passphrase. */
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase. The identification of the file (lowest 64 bits of n) will
|
||||
* precede the key to provide identification of the key without needing a
|
||||
* passphrase.
|
||||
*/
|
||||
|
||||
int
|
||||
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;
|
||||
u_int32_t rand;
|
||||
|
||||
/* If the passphrase is empty, use SSH_CIPHER_NONE to ease
|
||||
converting to another cipher; otherwise use
|
||||
SSH_AUTHFILE_CIPHER. */
|
||||
/*
|
||||
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
|
||||
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
|
||||
*/
|
||||
if (strcmp(passphrase, "") == 0)
|
||||
cipher_type = SSH_CIPHER_NONE;
|
||||
else
|
||||
|
@ -68,9 +71,11 @@ save_private_key(const char *filename, const char *passphrase,
|
|||
buf[3] = buf[1];
|
||||
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
|
||||
encrypted format would just give known plaintext). */
|
||||
/*
|
||||
* Store the private key (n and e will not be stored because they
|
||||
* 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->iqmp);
|
||||
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));
|
||||
buffer_free(&buffer);
|
||||
|
||||
/* Write to a file. */
|
||||
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
|
||||
if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
|
||||
buffer_len(&encrypted)) {
|
||||
debug("Write to key file %.200s failed: %.100s", filename,
|
||||
|
@ -131,9 +134,11 @@ save_private_key(const char *filename, const char *passphrase,
|
|||
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
|
||||
non-zero otherwise. */
|
||||
/*
|
||||
* 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 non-zero
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
|
@ -144,11 +149,9 @@ load_public_key(const char *filename, RSA * pub,
|
|||
Buffer buffer;
|
||||
char *cp;
|
||||
|
||||
/* Read data from the file into the buffer. */
|
||||
f = open(filename, O_RDONLY);
|
||||
if (f < 0)
|
||||
return 0;
|
||||
|
||||
len = lseek(f, (off_t) 0, SEEK_END);
|
||||
lseek(f, (off_t) 0, SEEK_SET);
|
||||
|
||||
|
@ -170,8 +173,10 @@ load_public_key(const char *filename, RSA * pub,
|
|||
buffer_free(&buffer);
|
||||
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++)
|
||||
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
|
@ -197,9 +202,12 @@ load_public_key(const char *filename, RSA * pub,
|
|||
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).
|
||||
This initializes the private key. */
|
||||
/*
|
||||
* 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). This
|
||||
* initializes the private key.
|
||||
* Assumes we are called under uid of the owner of the file.
|
||||
*/
|
||||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
|
@ -214,12 +222,11 @@ load_private_key(const char *filename, const char *passphrase,
|
|||
BIGNUM *aux;
|
||||
struct stat st;
|
||||
|
||||
/* Read the file into the buffer. */
|
||||
f = open(filename, O_RDONLY);
|
||||
if (f < 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 ||
|
||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_mode & 077) != 0) {
|
||||
|
@ -252,8 +259,10 @@ load_private_key(const char *filename, const char *passphrase,
|
|||
buffer_free(&buffer);
|
||||
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++)
|
||||
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
|
|
4
bufaux.c
4
bufaux.c
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#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"
|
||||
|
||||
|
@ -54,7 +54,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
|
|||
buffer_append(buffer, msg, 2);
|
||||
/* Store the binary data. */
|
||||
buffer_append(buffer, buf, oi);
|
||||
/* Clear the temporary data. */
|
||||
|
||||
memset(buf, 0, bin_size);
|
||||
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
|
||||
#define BUFAUX_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);
|
||||
|
||||
/* Retrieves an BIGNUM from the buffer. */
|
||||
|
@ -37,12 +39,14 @@ int buffer_get_char(Buffer * buffer);
|
|||
/* Stores a character in the buffer. */
|
||||
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
|
||||
with xmalloc; it is the responsibility of the calling function to free
|
||||
the data. If length_ptr is non-NULL, the length of the returned data
|
||||
will be stored there. A null character will be automatically appended
|
||||
to the returned string, and is not counted in length. */
|
||||
/*
|
||||
* Returns an arbitrary binary string from the buffer. The string cannot be
|
||||
* longer than 256k. The returned value points to memory allocated with
|
||||
* xmalloc; it is the responsibility of the calling function to free the
|
||||
* data. If length_ptr is non-NULL, the length of the returned data will be
|
||||
* 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);
|
||||
|
||||
/* Stores and arbitrary binary string in the buffer. */
|
||||
|
|
22
buffer.c
22
buffer.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#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 "buffer.h"
|
||||
|
@ -40,8 +40,10 @@ buffer_free(Buffer *buffer)
|
|||
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
|
||||
buffer_clear(Buffer *buffer)
|
||||
|
@ -60,9 +62,11 @@ buffer_append(Buffer *buffer, const char *data, unsigned int 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
|
||||
returns a pointer to the allocated region. */
|
||||
/*
|
||||
* Appends space to the buffer, expanding the buffer if necessary. This does
|
||||
* 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)
|
||||
|
@ -79,8 +83,10 @@ restart:
|
|||
buffer->end += len;
|
||||
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) {
|
||||
memmove(buffer->buf, buffer->buf + 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
|
||||
#define BUFFER_H
|
||||
|
@ -37,9 +37,11 @@ void buffer_clear(Buffer * buffer);
|
|||
/* Appends data to the buffer, expanding it if necessary. */
|
||||
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
|
||||
returns a pointer to the allocated region. */
|
||||
/*
|
||||
* Appends space to the buffer, expanding the buffer if necessary. This does
|
||||
* 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);
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
|
||||
#endif /* BUFFER_H */
|
||||
|
|
79
canohost.c
79
canohost.c
|
@ -14,14 +14,16 @@
|
|||
*/
|
||||
|
||||
#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 "xmalloc.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 *
|
||||
get_remote_hostname(int socket)
|
||||
|
@ -52,19 +54,23 @@ get_remote_hostname(int socket)
|
|||
else
|
||||
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++)
|
||||
if (isupper(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
|
||||
necessary because anyone with access to a name server
|
||||
can define arbitrary names for an IP address. Mapping
|
||||
from name to IP address can be trusted better (but can
|
||||
still be fooled if the intruder has access to the name
|
||||
server of the domain). */
|
||||
/*
|
||||
* Map it back to an IP address and check that the given
|
||||
* address actually is an address of this host. This is
|
||||
* necessary because anyone with access to a name server can
|
||||
* define arbitrary names for an IP address. Mapping from
|
||||
* name to IP address can be trusted better (but can still be
|
||||
* fooled if the intruder has access to the name server of
|
||||
* the domain).
|
||||
*/
|
||||
hp = gethostbyname(name);
|
||||
if (!hp) {
|
||||
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))
|
||||
== 0)
|
||||
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]) {
|
||||
/* 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!",
|
||||
|
@ -94,16 +102,17 @@ get_remote_hostname(int socket)
|
|||
|
||||
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
|
||||
about source routing; it can be used to pretend you are
|
||||
somebody (ip-address) you are not. That itself may be "almost
|
||||
acceptable" under certain circumstances, but rhosts
|
||||
autentication is useless if source routing is accepted. Notice
|
||||
also that if we just dropped source routing here, the other
|
||||
side could use IP spoofing to do rest of the interaction and
|
||||
could still bypass security. So we exit here if we detect any
|
||||
IP options. */
|
||||
/*
|
||||
* If IP options are supported, make sure there are none (log and
|
||||
* disconnect them if any are found). Basically we are worried about
|
||||
* source routing; it can be used to pretend you are somebody
|
||||
* (ip-address) you are not. That itself may be "almost acceptable"
|
||||
* under certain circumstances, but rhosts autentication is useless
|
||||
* if source routing is accepted. Notice also that if we just dropped
|
||||
* source routing here, the other side could use IP spoofing to do
|
||||
* rest of the interaction and could still bypass security. So we
|
||||
* exit here if we detect any IP options.
|
||||
*/
|
||||
{
|
||||
unsigned char options[200], *ucp;
|
||||
char text[1024], *cp;
|
||||
|
@ -134,9 +143,11 @@ check_ip_options:
|
|||
static char *canonical_host_name = 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
|
||||
several times. */
|
||||
/*
|
||||
* 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
|
||||
* several times.
|
||||
*/
|
||||
|
||||
const char *
|
||||
get_canonical_hostname()
|
||||
|
@ -154,8 +165,10 @@ get_canonical_hostname()
|
|||
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 *
|
||||
get_remote_ipaddr()
|
||||
|
@ -163,7 +176,7 @@ get_remote_ipaddr()
|
|||
struct sockaddr_in from;
|
||||
int fromlen, socket;
|
||||
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
/* Check whether we have chached the name. */
|
||||
if (canonical_host_ip != NULL)
|
||||
return canonical_host_ip;
|
||||
|
||||
|
@ -215,8 +228,10 @@ get_remote_port()
|
|||
{
|
||||
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())
|
||||
return 65535;
|
||||
|
||||
|
|
376
channels.c
376
channels.c
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#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 "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 */
|
||||
#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;
|
||||
|
||||
/* Size of the channel array. All slots of the array must always be
|
||||
initialized (at least the type field); unused slots are marked with
|
||||
type SSH_CHANNEL_FREE. */
|
||||
/*
|
||||
* Size of the channel array. All slots of the array must always be
|
||||
* initialized (at least the type field); unused slots are marked with type
|
||||
* SSH_CHANNEL_FREE.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* Name and directory of socket for authentication agent forwarding. */
|
||||
|
@ -61,15 +67,19 @@ char *x11_saved_proto = NULL;
|
|||
char *x11_saved_data = NULL;
|
||||
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;
|
||||
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
|
||||
a corrupt remote server from accessing arbitrary TCP/IP ports on our
|
||||
local network (which might be behind a firewall). */
|
||||
/*
|
||||
* 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
|
||||
* a corrupt remote server from accessing arbitrary TCP/IP ports on our local
|
||||
* network (which might be behind a firewall).
|
||||
*/
|
||||
typedef struct {
|
||||
char *host; /* Host name. */
|
||||
int port; /* Port number. */
|
||||
|
@ -79,9 +89,11 @@ typedef struct {
|
|||
static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
|
||||
/* Number of permitted host/port pairs in the array. */
|
||||
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
|
||||
do anything after logging in anyway. */
|
||||
/*
|
||||
* 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 do
|
||||
* anything after logging in anyway.
|
||||
*/
|
||||
static int all_opens_permitted = 0;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
and the server has no way to know but to trust the client anyway. */
|
||||
/*
|
||||
* 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,
|
||||
* and the server has no way to know but to trust the client anyway.
|
||||
*/
|
||||
|
||||
void
|
||||
channel_permit_all_opens()
|
||||
|
@ -105,8 +119,10 @@ channel_permit_all_opens()
|
|||
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
|
||||
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. */
|
||||
if (sock > channel_max_fd_value)
|
||||
channel_max_fd_value = sock;
|
||||
/* XXX set close-on-exec -markus */
|
||||
|
||||
/* Do initial allocation if this is the first call. */
|
||||
if (channels_alloc == 0) {
|
||||
|
@ -124,9 +141,10 @@ channel_allocate(int type, int sock, char *remote_name)
|
|||
channels = xmalloc(channels_alloc * sizeof(Channel));
|
||||
for (i = 0; i < channels_alloc; i++)
|
||||
channels[i].type = SSH_CHANNEL_FREE;
|
||||
|
||||
/* Kludge: arrange a call to channel_stop_listening if we
|
||||
terminate with fatal(). */
|
||||
/*
|
||||
* Kludge: arrange a call to channel_stop_listening if we
|
||||
* terminate with fatal().
|
||||
*/
|
||||
fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
if (found == -1) {
|
||||
/* There are no free slots. Take last+1 slot and expand
|
||||
the array. */
|
||||
/* There are no free slots. Take last+1 slot and expand the array. */
|
||||
found = channels_alloc;
|
||||
channels_alloc += 10;
|
||||
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
|
||||
channel_prepare_select(fd_set * readset, fd_set * writeset)
|
||||
|
@ -248,15 +267,16 @@ redo:
|
|||
break;
|
||||
|
||||
case SSH_CHANNEL_X11_OPEN:
|
||||
/* This is a special state for X11 authentication
|
||||
spoofing. An opened X11 connection (when
|
||||
authentication spoofing is being done) remains
|
||||
in this state until the first packet has been
|
||||
completely read. The authentication data in
|
||||
that packet is then substituted by the real
|
||||
data if it matches the fake data, and the
|
||||
channel is put into normal mode. */
|
||||
|
||||
/*
|
||||
* This is a special state for X11 authentication
|
||||
* spoofing. An opened X11 connection (when
|
||||
* authentication spoofing is being done) remains in
|
||||
* this state until the first packet has been
|
||||
* completely read. The authentication data in that
|
||||
* packet is then substituted by the real data if it
|
||||
* matches the fake data, and the channel is put into
|
||||
* normal mode.
|
||||
*/
|
||||
/* Check if the fixed size part of the packet is in buffer. */
|
||||
if (buffer_len(&ch->output) < 12)
|
||||
break;
|
||||
|
@ -303,9 +323,11 @@ redo:
|
|||
ch->type = SSH_CHANNEL_OPEN;
|
||||
goto reject;
|
||||
}
|
||||
/* Received authentication protocol and data match
|
||||
our fake data. Substitute the fake data with
|
||||
real data. */
|
||||
/*
|
||||
* Received authentication protocol and data match
|
||||
* our fake data. Substitute the fake data with real
|
||||
* data.
|
||||
*/
|
||||
memcpy(ucp + 12 + ((proto_len + 3) & ~3),
|
||||
x11_saved_data, x11_saved_data_len);
|
||||
|
||||
|
@ -314,8 +336,10 @@ redo:
|
|||
goto redo;
|
||||
|
||||
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");
|
||||
buffer_clear(&ch->input);
|
||||
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
|
||||
channel_after_select(fd_set * readset, fd_set * writeset)
|
||||
|
@ -381,8 +407,10 @@ channel_after_select(fd_set * readset, fd_set * writeset)
|
|||
break;
|
||||
|
||||
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)) {
|
||||
debug("Connection to port %d forwarding to %.100s:%d requested.",
|
||||
ch->listening_port, ch->path, ch->host_port);
|
||||
|
@ -410,8 +438,10 @@ channel_after_select(fd_set * readset, fd_set * writeset)
|
|||
break;
|
||||
|
||||
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)) {
|
||||
int nchan;
|
||||
len = sizeof(addr);
|
||||
|
@ -429,13 +459,16 @@ channel_after_select(fd_set * readset, fd_set * writeset)
|
|||
break;
|
||||
|
||||
case SSH_CHANNEL_OPEN:
|
||||
/* This is an open two-way communication channel.
|
||||
It is not of interest to us at this point what
|
||||
kind of data is being transmitted. */
|
||||
/*
|
||||
* This is an open two-way communication channel. It
|
||||
* 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
|
||||
failes */
|
||||
/*
|
||||
* Read available incoming data and append it to
|
||||
* buffer; shutdown socket, if read or write failes
|
||||
*/
|
||||
if (FD_ISSET(ch->sock, readset)) {
|
||||
len = read(ch->sock, buf, sizeof(buf));
|
||||
if (len <= 0) {
|
||||
|
@ -500,8 +533,7 @@ channel_output_poll()
|
|||
|
||||
for (i = 0; i < channels_alloc; i++) {
|
||||
ch = &channels[i];
|
||||
/* We are only interested in channels that can have
|
||||
buffered incoming data. */
|
||||
/* We are only interested in channels that can have buffered incoming data. */
|
||||
if (ch->type != SSH_CHANNEL_OPEN &&
|
||||
ch->type != SSH_CHANNEL_INPUT_DRAINING)
|
||||
continue;
|
||||
|
@ -509,8 +541,7 @@ channel_output_poll()
|
|||
/* Get the amount of buffered data for this channel. */
|
||||
len = buffer_len(&ch->input);
|
||||
if (len > 0) {
|
||||
/* Send some data for the other side over the
|
||||
secure connection. */
|
||||
/* Send some data for the other side over the secure connection. */
|
||||
if (packet_is_interactive()) {
|
||||
if (len > 1024)
|
||||
len = 512;
|
||||
|
@ -527,17 +558,20 @@ channel_output_poll()
|
|||
} else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
|
||||
if (compat13)
|
||||
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:
|
||||
send IEOF */
|
||||
/*
|
||||
* input-buffer is empty and read-socket shutdown:
|
||||
* tell peer, that we will not send more data: send IEOF
|
||||
*/
|
||||
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
|
||||
is still there. */
|
||||
/*
|
||||
* 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 is
|
||||
* still there.
|
||||
*/
|
||||
|
||||
void
|
||||
channel_input_data(int payload_len)
|
||||
|
@ -564,8 +598,10 @@ channel_input_data(int payload_len)
|
|||
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
|
||||
channel_not_very_much_buffered_data()
|
||||
|
@ -615,20 +651,27 @@ channel_input_close()
|
|||
chan_rcvd_ieof(&channels[channel]);
|
||||
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_put_int(channels[channel].remote_id);
|
||||
packet_send();
|
||||
|
||||
/* If the channel is in closed state, we have sent a close
|
||||
request, and the other side will eventually respond with a
|
||||
confirmation. Thus, we cannot free the channel here, because
|
||||
then there would be no-one to receive the confirmation. The
|
||||
channel gets freed when the confirmation arrives. */
|
||||
/*
|
||||
* If the channel is in closed state, we have sent a close request,
|
||||
* and the other side will eventually respond with a confirmation.
|
||||
* Thus, we cannot free the channel here, because then there would be
|
||||
* no-one to receive the confirmation. The channel gets freed when
|
||||
* the confirmation arrives.
|
||||
*/
|
||||
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_len(&channels[channel].input));
|
||||
channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
|
||||
|
@ -678,8 +721,7 @@ channel_input_open_confirmation()
|
|||
/* Get remote side's id for this channel. */
|
||||
remote_channel = packet_get_int();
|
||||
|
||||
/* Record the remote channel number and mark that the channel is
|
||||
now open. */
|
||||
/* Record the remote channel number and mark that the channel is now open. */
|
||||
channels[channel].remote_id = remote_channel;
|
||||
channels[channel].type = SSH_CHANNEL_OPEN;
|
||||
}
|
||||
|
@ -702,8 +744,10 @@ channel_input_open_failure()
|
|||
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
|
||||
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
|
||||
channel_close_all()
|
||||
|
@ -778,9 +824,11 @@ channel_still_open()
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Returns a message describing the currently open forwarded
|
||||
connections, suitable for sending to the client. The message
|
||||
contains crlf pairs for newlines. */
|
||||
/*
|
||||
* Returns a message describing the currently open forwarded connections,
|
||||
* suitable for sending to the client. The message contains crlf pairs for
|
||||
* newlines.
|
||||
*/
|
||||
|
||||
char *
|
||||
channel_open_message()
|
||||
|
@ -822,16 +870,19 @@ channel_open_message()
|
|||
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
|
||||
channel_request_local_forwarding(int port, const char *host,
|
||||
int host_port)
|
||||
{
|
||||
int ch, sock;
|
||||
int ch, sock, on = 1;
|
||||
struct sockaddr_in sin;
|
||||
extern Options options;
|
||||
struct linger linger;
|
||||
|
||||
if (strlen(host) > sizeof(channels[0].path) - 1)
|
||||
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_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. */
|
||||
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
|
||||
packet_disconnect("bind: %.100s", strerror(errno));
|
||||
|
@ -866,8 +926,10 @@ channel_request_local_forwarding(int port, const char *host,
|
|||
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
|
||||
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_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);
|
||||
}
|
||||
|
||||
/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
||||
listening for the port, and sends back a success reply (or disconnect
|
||||
message if there was an error). This never returns if there was an
|
||||
error. */
|
||||
/*
|
||||
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
||||
* listening for the port, and sends back a success reply (or disconnect
|
||||
* message if there was an error). This never returns if there was an error.
|
||||
*/
|
||||
|
||||
void
|
||||
channel_input_port_forward_request(int is_root)
|
||||
|
@ -915,8 +980,10 @@ channel_input_port_forward_request(int is_root)
|
|||
if ((port & 0xffff) != 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)
|
||||
packet_disconnect("Requested forwarding of port %d but user is not root.",
|
||||
port);
|
||||
|
@ -928,9 +995,11 @@ channel_input_port_forward_request(int is_root)
|
|||
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
|
||||
CHANNEL_OPEN_FAILURE. */
|
||||
/*
|
||||
* This is called after receiving PORT_OPEN message. This attempts to
|
||||
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
|
||||
* or CHANNEL_OPEN_FAILURE.
|
||||
*/
|
||||
|
||||
void
|
||||
channel_input_port_open(int payload_len)
|
||||
|
@ -951,13 +1020,16 @@ channel_input_port_open(int payload_len)
|
|||
host_port = packet_get_int();
|
||||
|
||||
/* Get remote originator name. */
|
||||
if (have_hostname_in_open)
|
||||
if (have_hostname_in_open) {
|
||||
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_len = 0; /* no originator supplied */
|
||||
}
|
||||
|
||||
packet_integrity_check(payload_len,
|
||||
4 + 4 + host_len + 4 + 4 + originator_len,
|
||||
4 + 4 + host_len + 4 + originator_len,
|
||||
SSH_MSG_PORT_OPEN);
|
||||
|
||||
/* Check if opening that port is permitted. */
|
||||
|
@ -1040,9 +1112,11 @@ fail:
|
|||
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
|
||||
occurs. */
|
||||
/*
|
||||
* Creates an internet domain socket for listening for X11 connections.
|
||||
* Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||
* occurs.
|
||||
*/
|
||||
|
||||
char *
|
||||
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
|
||||
with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
|
||||
/*
|
||||
* 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
|
||||
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
|
||||
*/
|
||||
|
||||
void
|
||||
x11_input_open(int payload_len)
|
||||
|
@ -1152,13 +1228,16 @@ x11_input_open(int payload_len)
|
|||
remote_channel = packet_get_int();
|
||||
|
||||
/* Get remote originator name. */
|
||||
if (have_hostname_in_open)
|
||||
if (have_hostname_in_open) {
|
||||
remote_host = packet_get_string(&remote_len);
|
||||
else
|
||||
remote_len += 4;
|
||||
} else {
|
||||
remote_host = xstrdup("unknown (remote did not supply name)");
|
||||
remote_len = 0;
|
||||
}
|
||||
|
||||
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. */
|
||||
display = getenv("DISPLAY");
|
||||
|
@ -1166,11 +1245,15 @@ x11_input_open(int payload_len)
|
|||
error("DISPLAY not set.");
|
||||
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 ||
|
||||
display[0] == ':') {
|
||||
/* 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. */
|
||||
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));
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
cp = strchr(buf, ':');
|
||||
|
@ -1197,8 +1282,7 @@ x11_input_open(int payload_len)
|
|||
goto fail;
|
||||
}
|
||||
*cp = 0;
|
||||
/* buf now contains the host name. But first we parse the display
|
||||
number. */
|
||||
/* buf now contains the host name. But first we parse the display number. */
|
||||
if (sscanf(cp + 1, "%d", &display_number) != 1) {
|
||||
error("Could not parse display number from DISPLAY: %.100s",
|
||||
display);
|
||||
|
@ -1267,8 +1351,10 @@ fail:
|
|||
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
|
||||
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. */
|
||||
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_fake_data = xmalloc(data_len);
|
||||
for (i = 0; i < data_len; i++) {
|
||||
|
@ -1334,9 +1422,11 @@ auth_request_forwarding()
|
|||
packet_write_wait();
|
||||
}
|
||||
|
||||
/* Returns the name of the forwarded authentication socket. Returns NULL
|
||||
if there is no forwarded authentication socket. The returned value
|
||||
points to a static buffer. */
|
||||
/*
|
||||
* Returns the name of the forwarded authentication socket. Returns NULL if
|
||||
* there is no forwarded authentication socket. The returned value points to
|
||||
* a static buffer.
|
||||
*/
|
||||
|
||||
char *
|
||||
auth_get_socket_name()
|
||||
|
@ -1353,8 +1443,10 @@ cleanup_socket(void)
|
|||
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
|
||||
auth_input_request_forwarding(struct passwd * pw)
|
||||
|
@ -1422,14 +1514,18 @@ auth_input_open_request()
|
|||
/* Read the remote channel number from the message. */
|
||||
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();
|
||||
|
||||
/* If we could not connect the agent, send an error message back
|
||||
to the server. This should never happen unless the agent dies,
|
||||
because authentication forwarding is only enabled if we have an
|
||||
agent. */
|
||||
/*
|
||||
* If we could not connect the agent, send an error message back to
|
||||
* the server. This should never happen unless the agent dies,
|
||||
* because authentication forwarding is only enabled if we have an
|
||||
* agent.
|
||||
*/
|
||||
if (sock < 0) {
|
||||
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(remch);
|
||||
|
@ -1438,9 +1534,11 @@ auth_input_open_request()
|
|||
}
|
||||
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
|
||||
channel cannot yet be freed at that point. */
|
||||
/*
|
||||
* 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
|
||||
* channel cannot yet be freed at that point.
|
||||
*/
|
||||
dummyname = xstrdup("authentication agent connection");
|
||||
|
||||
newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname);
|
||||
|
|
27
channels.h
27
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
|
||||
#define CHANNELS_H
|
||||
|
||||
/* Definitions for channel types. */
|
||||
#define SSH_CHANNEL_FREE 0 /* This channel is free
|
||||
* (unused). */
|
||||
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11
|
||||
* conn. */
|
||||
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
|
||||
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
|
||||
#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
|
||||
#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
|
||||
#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
|
||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close
|
||||
* confirmation */
|
||||
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
|
||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
|
||||
/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
|
||||
#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_INPUT_DRAINING 10 /* sending remaining data to
|
||||
* conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to
|
||||
* app */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
|
||||
#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 {
|
||||
int type; /* channel type/state */
|
||||
|
|
43
cipher.c
43
cipher.c
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
#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 "cipher.h"
|
||||
|
@ -121,8 +121,10 @@ detect_cbc_attack(const unsigned char *src,
|
|||
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[] =
|
||||
{
|
||||
"none",
|
||||
|
@ -134,9 +136,11 @@ static char *cipher_names[] =
|
|||
"blowfish"
|
||||
};
|
||||
|
||||
/* Returns a bit mask indicating which ciphers are supported by this
|
||||
implementation. The bit mask has the corresponding bit set of each
|
||||
supported cipher. */
|
||||
/*
|
||||
* Returns a bit mask indicating which ciphers are supported by this
|
||||
* implementation. The bit mask has the corresponding bit set of each
|
||||
* supported cipher.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
|
@ -158,8 +162,10 @@ cipher_name(int 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
|
||||
cipher_number(const char *name)
|
||||
|
@ -172,8 +178,10 @@ cipher_number(const char *name)
|
|||
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
|
||||
cipher_set_key_string(CipherContext *context, int cipher,
|
||||
|
@ -211,15 +219,18 @@ cipher_set_key(CipherContext *context, int cipher,
|
|||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
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;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
/* Note: the least significant bit of each byte of key is
|
||||
parity, and must be ignored by the implementation. 16
|
||||
bytes of key are used (first and last keys are the
|
||||
same). */
|
||||
/*
|
||||
* Note: the least significant bit of each byte of key is
|
||||
* parity, and must be ignored by the implementation. 16
|
||||
* bytes of key are used (first and last keys are the same).
|
||||
*/
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for 3DES.", keylen);
|
||||
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
|
||||
#define CIPHER_H
|
||||
|
@ -54,26 +54,34 @@ typedef struct {
|
|||
} bf;
|
||||
} u;
|
||||
} CipherContext;
|
||||
/* Returns a bit mask indicating which ciphers are supported by this
|
||||
implementation. The bit mask has the corresponding bit set of each
|
||||
supported cipher. */
|
||||
/*
|
||||
* Returns a bit mask indicating which ciphers are supported by this
|
||||
* implementation. The bit mask has the corresponding bit set of each
|
||||
* supported cipher.
|
||||
*/
|
||||
unsigned int cipher_mask();
|
||||
|
||||
/* Returns the name of the 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);
|
||||
|
||||
/* 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
|
||||
cipher_set_key(CipherContext * context, int cipher,
|
||||
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
|
||||
cipher_set_key_string(CipherContext * context, int cipher,
|
||||
const char *passphrase, int for_encryption);
|
||||
|
@ -88,8 +96,10 @@ void
|
|||
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
||||
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. */
|
||||
extern void (*cipher_attack_detected) (const char *fmt,...);
|
||||
/*
|
||||
* If and CRC-32 attack is detected this function is called. Defaults to
|
||||
* fatal, changed to packet_disconnect in sshd and ssh.
|
||||
*/
|
||||
extern void (*cipher_attack_detected) (const char *fmt, ...);
|
||||
|
||||
#endif /* CIPHER_H */
|
||||
|
|
317
clientloop.c
317
clientloop.c
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#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 "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. */
|
||||
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
|
||||
in a configuration file. */
|
||||
/*
|
||||
* 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 in a
|
||||
* configuration file.
|
||||
*/
|
||||
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
|
||||
window size to be sent to the server a little later. This is volatile
|
||||
because this is updated in a signal handler. */
|
||||
/*
|
||||
* Flag to indicate that we have received a window change signal which has
|
||||
* not yet been processed. This will cause a message indicating the new
|
||||
* window size to be sent to the server a little later. This is volatile
|
||||
* because this is updated in a signal handler.
|
||||
*/
|
||||
static volatile int received_window_change_signal = 0;
|
||||
|
||||
/* Terminal modes, as saved by enter_raw_mode. */
|
||||
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;
|
||||
|
||||
/* 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 escape_char; /* Escape character. */
|
||||
|
||||
/* Returns the user\'s terminal to normal mode if it had been put in raw
|
||||
mode. */
|
||||
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
|
||||
|
||||
void
|
||||
leave_raw_mode()
|
||||
|
@ -127,8 +132,10 @@ enter_non_blocking()
|
|||
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
|
||||
window_change_handler(int sig)
|
||||
|
@ -137,8 +144,10 @@ window_change_handler(int sig)
|
|||
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
|
||||
signal_handler(int sig)
|
||||
|
@ -152,8 +161,10 @@ signal_handler(int 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
|
||||
get_current_time()
|
||||
|
@ -163,9 +174,11 @@ get_current_time()
|
|||
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()
|
||||
does not appear to wake up when redirecting from /dev/null. */
|
||||
/*
|
||||
* 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() does
|
||||
* not appear to wake up when redirecting from /dev/null.
|
||||
*/
|
||||
|
||||
void
|
||||
client_check_initial_eof_on_stdin()
|
||||
|
@ -173,13 +186,14 @@ client_check_initial_eof_on_stdin()
|
|||
int len;
|
||||
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
|
||||
the server. Otherwise, we try to read a single character; it
|
||||
appears that for some files, such /dev/null, select() never
|
||||
wakes up for read for this descriptor, which means that we
|
||||
never get EOF. This way we will get the EOF if stdin comes
|
||||
from /dev/null or similar. */
|
||||
/*
|
||||
* 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 the
|
||||
* server. Otherwise, we try to read a single character; it appears
|
||||
* that for some files, such /dev/null, select() never wakes up for
|
||||
* read for this descriptor, which means that we never get EOF. This
|
||||
* way we will get the EOF if stdin comes from /dev/null or similar.
|
||||
*/
|
||||
if (stdin_null_flag) {
|
||||
/* Fake EOF on stdin. */
|
||||
debug("Sending eof.");
|
||||
|
@ -187,22 +201,22 @@ client_check_initial_eof_on_stdin()
|
|||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
} else {
|
||||
/* Enter non-blocking mode for stdin. */
|
||||
enter_non_blocking();
|
||||
|
||||
/* Check for immediate EOF on stdin. */
|
||||
len = read(fileno(stdin), buf, 1);
|
||||
if (len == 0) {
|
||||
/* EOF. Record that we have seen it and send EOF
|
||||
to server. */
|
||||
/* EOF. Record that we have seen it and send EOF to server. */
|
||||
debug("Sending eof.");
|
||||
stdin_eof = 1;
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
} else if (len > 0) {
|
||||
/* Got data. We must store the data in the
|
||||
buffer, and also process it as an escape
|
||||
character if appropriate. */
|
||||
/*
|
||||
* Got data. We must store the data in the buffer,
|
||||
* and also process it as an escape character if
|
||||
* appropriate.
|
||||
*/
|
||||
if ((unsigned char) buf[0] == escape_char)
|
||||
escape_pending = 1;
|
||||
else {
|
||||
|
@ -210,13 +224,14 @@ client_check_initial_eof_on_stdin()
|
|||
stdin_bytes += 1;
|
||||
}
|
||||
}
|
||||
/* Leave non-blocking mode. */
|
||||
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
|
||||
client_process_buffered_input_packets()
|
||||
|
@ -255,8 +270,10 @@ client_process_buffered_input_packets()
|
|||
/* Acknowledge the exit. */
|
||||
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
||||
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();
|
||||
/* Flag that we want to exit. */
|
||||
quit_pending = 1;
|
||||
|
@ -300,20 +317,24 @@ client_process_buffered_input_packets()
|
|||
break;
|
||||
|
||||
default:
|
||||
/* Any unknown packets received during the actual
|
||||
session cause the session to terminate. This
|
||||
is intended to make debugging easier since no
|
||||
confirmations are sent. Any compatible
|
||||
protocol extensions must be negotiated during
|
||||
the preparatory phase. */
|
||||
/*
|
||||
* Any unknown packets received during the actual
|
||||
* session cause the session to terminate. This is
|
||||
* intended to make debugging easier since no
|
||||
* confirmations are sent. Any compatible protocol
|
||||
* extensions must be negotiated during the
|
||||
* preparatory phase.
|
||||
*/
|
||||
packet_disconnect("Protocol error during session: type %d",
|
||||
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
|
||||
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
|
||||
interrupt on Unix); this just checks the flag and sends a message if
|
||||
appropriate. */
|
||||
/*
|
||||
* 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
|
||||
* interrupt on Unix); this just checks the flag and sends a message if
|
||||
* appropriate.
|
||||
*/
|
||||
|
||||
void
|
||||
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
|
||||
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())
|
||||
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())
|
||||
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)
|
||||
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
|
||||
some other event pending.
|
||||
Note: if you want to implement SSH_MSG_IGNORE messages to fool
|
||||
traffic analysis, this might be the place to do it:
|
||||
just have a random timeout for the select, and send a random
|
||||
SSH_MSG_IGNORE packet when the timeout expires. */
|
||||
/*
|
||||
* Wait for something to happen. This will suspend the process until
|
||||
* some selected descriptor can be read, written, or has some other
|
||||
* event pending. Note: if you want to implement SSH_MSG_IGNORE
|
||||
* messages to fool traffic analysis, this might be the place to do
|
||||
* it: just have a random timeout for the select, and send a random
|
||||
* SSH_MSG_IGNORE packet when the timeout expires.
|
||||
*/
|
||||
|
||||
if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) {
|
||||
char buf[100];
|
||||
|
@ -446,11 +474,12 @@ client_suspend_self()
|
|||
buffer_ptr(&stderr_buffer),
|
||||
buffer_len(&stderr_buffer));
|
||||
|
||||
/* 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(&stdout_buffer);
|
||||
buffer_free(&stderr_buffer);
|
||||
|
@ -474,7 +503,6 @@ client_suspend_self()
|
|||
buffer_init(&stdout_buffer);
|
||||
buffer_init(&stderr_buffer);
|
||||
|
||||
/* Re-enter raw mode. */
|
||||
enter_raw_mode();
|
||||
}
|
||||
|
||||
|
@ -484,8 +512,10 @@ client_process_input(fd_set * readset)
|
|||
int len, pid;
|
||||
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)) {
|
||||
/* Read as much as possible. */
|
||||
len = read(connection_in, buf, sizeof(buf));
|
||||
|
@ -498,9 +528,10 @@ client_process_input(fd_set * readset)
|
|||
quit_pending = 1;
|
||||
return;
|
||||
}
|
||||
/* There is a kernel bug on Solaris that causes select to
|
||||
sometimes wake up even though there is no data
|
||||
available. */
|
||||
/*
|
||||
* There is a kernel bug on Solaris that causes select to
|
||||
* sometimes wake up even though there is no data available.
|
||||
*/
|
||||
if (len < 0 && errno == EAGAIN)
|
||||
len = 0;
|
||||
|
||||
|
@ -520,9 +551,11 @@ client_process_input(fd_set * readset)
|
|||
/* Read as much as possible. */
|
||||
len = read(fileno(stdin), buf, sizeof(buf));
|
||||
if (len <= 0) {
|
||||
/* Received EOF or error. They are treated
|
||||
similarly, except that an error message is
|
||||
printed if it was an error condition. */
|
||||
/*
|
||||
* Received EOF or error. They are treated
|
||||
* similarly, except that an error message is printed
|
||||
* if it was an error condition.
|
||||
*/
|
||||
if (len < 0) {
|
||||
snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
|
@ -530,32 +563,35 @@ client_process_input(fd_set * readset)
|
|||
}
|
||||
/* Mark that we have seen EOF. */
|
||||
stdin_eof = 1;
|
||||
/* Send an EOF message to the server unless there
|
||||
is data in the buffer. If there is data in the
|
||||
buffer, no message will be sent now. Code
|
||||
elsewhere will send the EOF when the buffer
|
||||
becomes empty if stdin_eof is set. */
|
||||
/*
|
||||
* Send an EOF message to the server unless there is
|
||||
* data in the buffer. If there is data in the
|
||||
* buffer, no message will be sent now. Code
|
||||
* elsewhere will send the EOF when the buffer
|
||||
* becomes empty if stdin_eof is set.
|
||||
*/
|
||||
if (buffer_len(&stdin_buffer) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
} 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);
|
||||
stdin_bytes += len;
|
||||
} else {
|
||||
/* Normal, successful read. But we have an escape
|
||||
character and have to process the characters
|
||||
one by one. */
|
||||
/*
|
||||
* Normal, successful read. But we have an escape character
|
||||
* and have to process the characters one by one.
|
||||
*/
|
||||
unsigned int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
unsigned char ch;
|
||||
/* Get one character at a time. */
|
||||
ch = buf[i];
|
||||
|
||||
/* Check if we have a pending escape
|
||||
character. */
|
||||
if (escape_pending) {
|
||||
/* We have previously seen an escape character. */
|
||||
/* Clear the flag now. */
|
||||
|
@ -584,12 +620,16 @@ client_process_input(fd_set * readset)
|
|||
continue;
|
||||
|
||||
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) {
|
||||
/* Sending SSH_CMSG_EOF alone does not always appear
|
||||
to be enough. So we try to send an EOF character
|
||||
first. */
|
||||
/*
|
||||
* Sending SSH_CMSG_EOF alone does not always appear
|
||||
* to be enough. So we try to send an EOF character
|
||||
* first.
|
||||
*/
|
||||
packet_start(SSH_CMSG_STDIN_DATA);
|
||||
packet_put_string("\004", 1);
|
||||
packet_send();
|
||||
|
@ -646,22 +686,28 @@ Supported escape sequences:\r\n\
|
|||
|
||||
default:
|
||||
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[1] = ch;
|
||||
buffer_append(&stdin_buffer, buf, 2);
|
||||
stdin_bytes += 2;
|
||||
continue;
|
||||
}
|
||||
/* Note that escape character typed twice
|
||||
falls through here; the latter gets processed
|
||||
as a normal character below. */
|
||||
/*
|
||||
* Note that escape character typed twice
|
||||
* falls through here; the latter gets processed
|
||||
* as a normal character below.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} 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) {
|
||||
/* It is. Set the flag and continue to next character. */
|
||||
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');
|
||||
buf[0] = ch;
|
||||
buffer_append(&stdin_buffer, buf, 1);
|
||||
|
@ -696,8 +744,10 @@ client_process_output(fd_set * writeset)
|
|||
if (errno == EAGAIN)
|
||||
len = 0;
|
||||
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));
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
stderr_bytes += strlen(buf);
|
||||
|
@ -717,8 +767,7 @@ client_process_output(fd_set * writeset)
|
|||
if (errno == EAGAIN)
|
||||
len = 0;
|
||||
else {
|
||||
/* EOF or error, but can't even print
|
||||
error message. */
|
||||
/* EOF or error, but can't even print error message. */
|
||||
quit_pending = 1;
|
||||
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
|
||||
started on the remote host. If escape_char != -1, it is the character
|
||||
used as an escape character for terminating or suspending the
|
||||
session. */
|
||||
/*
|
||||
* Implements the interactive session with the server. This is called after
|
||||
* the user has been authenticated, and a command has been started on the
|
||||
* remote host. If escape_char != -1, it is the character used as an escape
|
||||
* character for terminating or suspending the session.
|
||||
*/
|
||||
|
||||
int
|
||||
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)
|
||||
signal(SIGWINCH, window_change_handler);
|
||||
|
||||
/* Enter raw mode if have a pseudo terminal. */
|
||||
if (have_pty)
|
||||
enter_raw_mode();
|
||||
|
||||
|
@ -787,27 +836,35 @@ client_loop(int have_pty, int escape_char_arg)
|
|||
while (!quit_pending) {
|
||||
fd_set readset, writeset;
|
||||
|
||||
/* Precess buffered packets sent by the server. */
|
||||
/* Process buffered packets sent by the server. */
|
||||
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();
|
||||
|
||||
/* 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())
|
||||
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();
|
||||
|
||||
if (quit_pending)
|
||||
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);
|
||||
|
||||
if (quit_pending)
|
||||
|
@ -816,16 +873,19 @@ client_loop(int have_pty, int escape_char_arg)
|
|||
/* Do channel operations. */
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Send as much buffered packet data as possible to the
|
||||
sender. */
|
||||
/* Send as much buffered packet data as possible to the sender. */
|
||||
if (FD_ISSET(connection_out, &writeset))
|
||||
packet_write_poll();
|
||||
}
|
||||
|
@ -839,8 +899,10 @@ client_loop(int have_pty, int escape_char_arg)
|
|||
/* Stop listening for connections. */
|
||||
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) {
|
||||
snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Leave raw mode. */
|
||||
if (have_pty)
|
||||
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"
|
||||
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"
|
||||
|
||||
|
|
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
|
||||
#define COMPAT_H
|
||||
|
|
46
compress.c
46
compress.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#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 "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 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
|
||||
buffer_compress_init(int level)
|
||||
|
@ -53,13 +55,14 @@ buffer_compress_uninit()
|
|||
deflateEnd(&outgoing_stream);
|
||||
}
|
||||
|
||||
/* Compresses the contents of input_buffer into output_buffer. All
|
||||
packets compressed using this function will form a single
|
||||
compressed data stream; however, data will be flushed at the end of
|
||||
every call so that each output_buffer can be decompressed
|
||||
independently (but in the appropriate order since they together
|
||||
form a single compression stream) by the receiver. This appends
|
||||
the compressed data to the output buffer. */
|
||||
/*
|
||||
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||
* compressed using this function will form a single compressed data stream;
|
||||
* however, data will be flushed at the end of every call so that each
|
||||
* output_buffer can be decompressed independently (but in the appropriate
|
||||
* order since they together form a single compression stream) by the
|
||||
* receiver. This appends the compressed data to the output buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
|
||||
/* Uncompresses the contents of input_buffer into output_buffer. All
|
||||
packets uncompressed using this function will form a single
|
||||
compressed data stream; however, data will be flushed at the end of
|
||||
every call so that each output_buffer. This must be called for the
|
||||
same size units that the buffer_compress was called, and in the
|
||||
same order that buffers compressed with that. This appends the
|
||||
uncompressed data to the output buffer. */
|
||||
/*
|
||||
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||
* uncompressed using this function will form a single compressed data
|
||||
* stream; however, data will be flushed at the end of every call so that
|
||||
* each output_buffer. This must be called for the same size units that the
|
||||
* buffer_compress was called, and in the same order that buffers compressed
|
||||
* with that. This appends the uncompressed data to the output buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
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");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
/* Comments in zlib.h say that we should keep
|
||||
calling inflate() until we get an error. This
|
||||
appears to be the error that we get. */
|
||||
/*
|
||||
* Comments in zlib.h say that we should keep calling
|
||||
* inflate() until we get an error. This appears to
|
||||
* be the error that we get.
|
||||
*/
|
||||
return;
|
||||
case 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
|
||||
#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);
|
||||
|
||||
/* Frees any data structures allocated by buffer_compress_init. */
|
||||
void buffer_compress_uninit();
|
||||
|
||||
/* Compresses the contents of input_buffer into output_buffer. All
|
||||
packets compressed using this function will form a single
|
||||
compressed data stream; however, data will be flushed at the end of
|
||||
every call so that each output_buffer can be decompressed
|
||||
independently (but in the appropriate order since they together
|
||||
form a single compression stream) by the receiver. This appends
|
||||
the compressed data to the output buffer. */
|
||||
/*
|
||||
* Compresses the contents of input_buffer into output_buffer. All packets
|
||||
* compressed using this function will form a single compressed data stream;
|
||||
* however, data will be flushed at the end of every call so that each
|
||||
* output_buffer can be decompressed independently (but in the appropriate
|
||||
* order since they together form a single compression stream) by the
|
||||
* receiver. This appends the compressed data to the 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
|
||||
compressed data stream; however, data will be flushed at the end of
|
||||
every call so that each output_buffer. This must be called for the
|
||||
same size units that the buffer_compress was called, and in the
|
||||
same order that buffers compressed with that. This appends the
|
||||
uncompressed data to the output buffer. */
|
||||
/*
|
||||
* Uncompresses the contents of input_buffer into output_buffer. All packets
|
||||
* uncompressed using this function will form a single compressed data
|
||||
* stream; however, data will be flushed at the end of every call so that
|
||||
* each output_buffer. This must be called for the same size units that the
|
||||
* buffer_compress was called, and in the same order that buffers compressed
|
||||
* with that. This appends the uncompressed data to the output buffer.
|
||||
*/
|
||||
void buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer);
|
||||
|
||||
#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
|
||||
#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);
|
||||
|
||||
#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"
|
||||
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 "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
|
||||
#define FINGERPRINT_H
|
||||
|
|
119
hostfile.c
119
hostfile.c
|
@ -14,16 +14,18 @@
|
|||
*/
|
||||
|
||||
#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 "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
|
||||
permitted to modify the buffer. This leaves *cpp to point just beyond
|
||||
the last processed (and maybe modified) character. Note that this may
|
||||
modify the buffer containing the number. */
|
||||
/*
|
||||
* Reads a multiple-precision integer in hex from the buffer, and advances
|
||||
* the pointer. The integer must already be initialized. This function is
|
||||
* permitted to modify the buffer. This leaves *cpp to point just beyond the
|
||||
* last processed (and maybe modified) character. Note that this may modify
|
||||
* the buffer containing the number.
|
||||
*/
|
||||
|
||||
int
|
||||
auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
||||
|
@ -32,7 +34,8 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||
int len, old;
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Check that it begins with a hex digit. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
|
@ -42,7 +45,8 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||
*cpp = cp;
|
||||
|
||||
/* 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. */
|
||||
len = cp - *cpp;
|
||||
|
@ -51,7 +55,6 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||
old = *cp;
|
||||
*cp = 0;
|
||||
|
||||
|
||||
/* Parse the number. */
|
||||
if (BN_dec2bn(&value, *cpp) == 0)
|
||||
return 0;
|
||||
|
@ -64,8 +67,10 @@ auth_rsa_read_bignum(char **cpp, BIGNUM * value)
|
|||
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
|
||||
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;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++);
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
|
@ -91,7 +97,8 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
|||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Return results. */
|
||||
*cpp = cp;
|
||||
|
@ -99,10 +106,12 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
|||
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
|
||||
indicate negation). Returns true if there is a positive match; zero
|
||||
otherwise. */
|
||||
/*
|
||||
* Tries to match the host name (which must be in all lowercase) against the
|
||||
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
* indicate negation). Returns true if there is a positive match; zero
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
match_hostname(const char *host, const char *pattern, unsigned int len)
|
||||
|
@ -121,18 +130,19 @@ match_hostname(const char *host, const char *pattern, unsigned int len)
|
|||
} else
|
||||
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;
|
||||
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
||||
i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
|
||||
subi++, i++)
|
||||
sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i];
|
||||
/* If subpattern too long, return failure (no match). */
|
||||
if (subi >= sizeof(sub) - 1)
|
||||
return 0;
|
||||
|
||||
/* If the subpattern was terminated by a comma, skip the
|
||||
comma. */
|
||||
/* If the subpattern was terminated by a comma, skip the comma. */
|
||||
if (i < len && pattern[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. */
|
||||
if (match_pattern(host, sub)) {
|
||||
if (negated)
|
||||
return 0; /* Fail if host matches
|
||||
any negated subpattern. */
|
||||
return 0; /* Fail */
|
||||
else
|
||||
got_positive = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return success if got a positive match. If there was a
|
||||
negative match, we have already returned zero and never get
|
||||
here. */
|
||||
/*
|
||||
* Return success if got a positive match. If there was a negative
|
||||
* match, we have already returned zero and never get here.
|
||||
*/
|
||||
return got_positive;
|
||||
}
|
||||
|
||||
/* Checks whether the given host (which must be in all lowercase) is
|
||||
already in the list of our known hosts.
|
||||
Returns HOST_OK if the host is known and has the specified key,
|
||||
HOST_NEW if the host is not known, and HOST_CHANGED if the host is known
|
||||
but used to have a different host key. */
|
||||
/*
|
||||
* Checks whether the given host (which must be in all lowercase) is already
|
||||
* in the list of our known hosts. Returns HOST_OK if the host is known and
|
||||
* has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
|
||||
* if the host is known but used to have a different host key.
|
||||
*/
|
||||
|
||||
HostStatus
|
||||
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. */
|
||||
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
|
||||
have not found the proper one. */
|
||||
/*
|
||||
* Return value when the loop terminates. This is set to
|
||||
* HOST_CHANGED if we have seen a different key for the host and have
|
||||
* not found the proper one.
|
||||
*/
|
||||
end_return = HOST_NEW;
|
||||
|
||||
/* size of modulus 'n' */
|
||||
|
@ -193,15 +206,15 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||
cp = line;
|
||||
linenum++;
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Ignore comment lines and empty lines. */
|
||||
/* Skip any leading whitespace, comments and empty lines. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '#' || *cp == '\n')
|
||||
continue;
|
||||
|
||||
/* 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. */
|
||||
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. */
|
||||
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))
|
||||
continue;
|
||||
|
||||
|
@ -228,21 +243,27 @@ check_host_in_hostfile(const char *filename, const char *host,
|
|||
fclose(f);
|
||||
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
|
||||
is new. */
|
||||
/*
|
||||
* They do not match. We will continue to go through the
|
||||
* file; however, we note that we will not return that it is
|
||||
* new.
|
||||
*/
|
||||
end_return = HOST_CHANGED;
|
||||
}
|
||||
/* Clear variables and close the file. */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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"
|
||||
#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
|
||||
|
||||
#endif /* INCLUDES_H */
|
||||
|
|
6
log.c
6
log.c
|
@ -1,11 +1,9 @@
|
|||
/*
|
||||
*
|
||||
* Shared versions of debug(), log(), etc.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
#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 "xmalloc.h"
|
||||
|
|
29
login.c
29
login.c
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
|
@ -30,12 +30,16 @@ RCSID("$Id: login.c,v 1.3 1999/11/24 13:26:22 damien Exp $");
|
|||
# include <lastlog.h>
|
||||
#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.
|
||||
The host the user logged in from will be returned in buf. */
|
||||
/*
|
||||
* Returns the time when the user last logged in. Returns 0 if the
|
||||
* 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
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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. */
|
||||
if (strcmp(user, "") != 0) {
|
||||
/* It is safer to bzero the lastlog structure first
|
||||
because some systems might have some extra fields in it
|
||||
(e.g. SGI) */
|
||||
/*
|
||||
* It is safer to bzero the lastlog structure first because
|
||||
* some systems might have some extra fields in it (e.g. SGI)
|
||||
*/
|
||||
memset(&ll, 0, sizeof(ll));
|
||||
|
||||
/* Update lastlog. */
|
||||
|
|
35
match.c
35
match.c
|
@ -14,12 +14,14 @@
|
|||
*/
|
||||
|
||||
#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"
|
||||
|
||||
/* 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)
|
||||
|
@ -29,7 +31,6 @@ match_pattern(const char *s, const char *pattern)
|
|||
if (!*pattern)
|
||||
return !*s;
|
||||
|
||||
/* Process '*'. */
|
||||
if (*pattern == '*') {
|
||||
/* Skip the asterisk. */
|
||||
pattern++;
|
||||
|
@ -40,9 +41,11 @@ match_pattern(const char *s, const char *pattern)
|
|||
|
||||
/* If next character in pattern is known, optimize. */
|
||||
if (*pattern != '?' && *pattern != '*') {
|
||||
/* Look instances of the next character in
|
||||
pattern, and try to match starting from
|
||||
those. */
|
||||
/*
|
||||
* Look instances of the next character in
|
||||
* pattern, and try to match starting from
|
||||
* those.
|
||||
*/
|
||||
for (; *s; s++)
|
||||
if (*s == *pattern &&
|
||||
match_pattern(s + 1, pattern + 1))
|
||||
|
@ -50,26 +53,28 @@ match_pattern(const char *s, const char *pattern)
|
|||
/* Failed. */
|
||||
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++)
|
||||
if (match_pattern(s, pattern))
|
||||
return 1;
|
||||
/* Failed. */
|
||||
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)
|
||||
return 0;
|
||||
|
||||
/* Check if the next character of the string is
|
||||
acceptable. */
|
||||
/* Check if the next character of the string is acceptable. */
|
||||
if (*pattern != '?' && *pattern != *s)
|
||||
return 0;
|
||||
|
||||
/* Move to the next character, both in string and in
|
||||
pattern. */
|
||||
/* Move to the next character, both in string and in pattern. */
|
||||
s++;
|
||||
pattern++;
|
||||
}
|
||||
|
|
10
mpaux.h
10
mpaux.h
|
@ -13,14 +13,16 @@
|
|||
* 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
|
||||
#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
|
||||
first representations of host_key_n, session_key_n, and the cookie. */
|
||||
/*
|
||||
* Computes a 16-byte session id in the global variable session_id. The
|
||||
* session id is computed by concatenating the linearized, msb first
|
||||
* representations of host_key_n, session_key_n, and the cookie.
|
||||
*/
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
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"
|
||||
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"
|
||||
|
||||
|
@ -173,9 +202,10 @@ chan_send_oclose(Channel *c)
|
|||
static void
|
||||
chan_shutdown_write(Channel *c)
|
||||
{
|
||||
/* shutdown failure is allowed if write failed already */
|
||||
debug("channel %d: shutdown_write", c->self);
|
||||
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));
|
||||
}
|
||||
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
|
||||
#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
|
||||
OpenSSH Channel Close Protocol 1.5 Implementation
|
||||
.SH
|
||||
|
|
181
packet.c
181
packet.c
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#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 "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 "deattack.h"
|
||||
|
||||
/* This variable contains the file descriptors used for communicating with
|
||||
the other side. connection_in is used for reading; connection_out
|
||||
for writing. These can be the same descriptor, in which case it is
|
||||
assumed to be a socket. */
|
||||
/*
|
||||
* This variable contains the file descriptors used for communicating with
|
||||
* the other side. connection_in is used for reading; connection_out for
|
||||
* 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_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;
|
||||
|
||||
/* Protocol flags for the remote side. */
|
||||
|
@ -76,8 +80,10 @@ static int initialized = 0;
|
|||
/* Set to true if the connection is interactive. */
|
||||
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
|
||||
packet_set_connection(int fd_in, int fd_out)
|
||||
|
@ -171,8 +177,10 @@ packet_get_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
|
||||
packet_start_compression(int level)
|
||||
|
@ -184,8 +192,10 @@ packet_start_compression(int 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
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||
|
@ -206,8 +218,10 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
|||
if ((bytes % 8) != 0)
|
||||
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) {
|
||||
case SSH_CIPHER_NONE:
|
||||
|
@ -224,9 +238,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
|||
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
|
||||
are encrypted independently of each other. */
|
||||
/*
|
||||
* Causes any further packets to be encrypted using the given key. The same
|
||||
* key is used for both sending and reception. However, both directions are
|
||||
* encrypted independently of each other.
|
||||
*/
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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()
|
||||
|
@ -294,8 +312,10 @@ packet_send()
|
|||
unsigned int checksum;
|
||||
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) {
|
||||
buffer_clear(&compression_buffer);
|
||||
/* Skip padding. */
|
||||
|
@ -348,14 +368,18 @@ packet_send()
|
|||
|
||||
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
|
||||
is called. */
|
||||
/*
|
||||
* Note that the packet is now only buffered in output. It won\'t be
|
||||
* 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
|
||||
not be used during the interactive session. */
|
||||
/*
|
||||
* 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 not
|
||||
* be used during the interactive session.
|
||||
*/
|
||||
|
||||
int
|
||||
packet_read(int *payload_len_ptr)
|
||||
|
@ -379,12 +403,16 @@ packet_read(int *payload_len_ptr)
|
|||
/* If we got a packet, return it. */
|
||||
if (type != SSH_MSG_NONE)
|
||||
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_SET(connection_in, &set);
|
||||
|
||||
/* Wait for some data to arrive. */
|
||||
select(connection_in + 1, &set, NULL, NULL, NULL);
|
||||
|
||||
/* Read data from the socket. */
|
||||
len = read(connection_in, buf, sizeof(buf));
|
||||
if (len == 0)
|
||||
|
@ -397,8 +425,10 @@ packet_read(int *payload_len_ptr)
|
|||
/* 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
|
||||
packet_read_expect(int *payload_len_ptr, int expected_type)
|
||||
|
@ -516,8 +546,10 @@ restart:
|
|||
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
|
||||
packet_process_incoming(const char *buf, unsigned int len)
|
||||
|
@ -543,8 +575,10 @@ packet_get_int()
|
|||
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
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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
|
||||
no longer needed. The length_ptr argument may be NULL, or point to an
|
||||
integer into which the length of the string is stored. */
|
||||
/*
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
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).
|
||||
The message is printed immediately, but only if the client is being
|
||||
executed in verbose mode. These messages are primarily intended to
|
||||
ease debugging authentication problems. The length of the formatted
|
||||
message must not exceed 1024 bytes. This will automatically call
|
||||
packet_write_wait. */
|
||||
/*
|
||||
* Sends a diagnostic message from the server to the client. This message
|
||||
* can be sent at any time (but not while constructing another message). The
|
||||
* message is printed immediately, but only if the client is being executed
|
||||
* in verbose mode. These messages are primarily intended to ease debugging
|
||||
* authentication problems. The length of the formatted message must not
|
||||
* exceed 1024 bytes. This will automatically call packet_write_wait.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_send_debug(const char *fmt,...)
|
||||
|
@ -588,10 +624,12 @@ packet_send_debug(const char *fmt,...)
|
|||
packet_write_wait();
|
||||
}
|
||||
|
||||
/* Logs the error plus constructs and sends a disconnect
|
||||
packet, closes the connection, and exits. This function never returns.
|
||||
The error message should not contain a newline. The length of the
|
||||
formatted message must not exceed 1024 bytes. */
|
||||
/*
|
||||
* Logs the error plus constructs and sends a disconnect packet, closes the
|
||||
* connection, and exits. This function never returns. The error message
|
||||
* should not contain a newline. The length of the formatted message must
|
||||
* not exceed 1024 bytes.
|
||||
*/
|
||||
|
||||
void
|
||||
packet_disconnect(const char *fmt,...)
|
||||
|
@ -603,8 +641,10 @@ packet_disconnect(const char *fmt,...)
|
|||
fatal("packet_disconnect called recursively.");
|
||||
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);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
@ -625,8 +665,7 @@ packet_disconnect(const char *fmt,...)
|
|||
fatal("Disconnecting: %.100s", buf);
|
||||
}
|
||||
|
||||
/* Checks if there is any buffered output, and tries to write some of the
|
||||
output. */
|
||||
/* Checks if there is any buffered output, and tries to write some of the output. */
|
||||
|
||||
void
|
||||
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
|
||||
packet_write_wait()
|
||||
|
@ -689,8 +730,10 @@ packet_set_interactive(int interactive, int keepalives)
|
|||
/* Record that we are in interactive mode. */
|
||||
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)
|
||||
return;
|
||||
|
||||
|
@ -701,8 +744,10 @@ packet_set_interactive(int interactive, int keepalives)
|
|||
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
|
||||
}
|
||||
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;
|
||||
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
|
||||
sizeof(lowdelay)) < 0)
|
||||
|
@ -711,8 +756,10 @@ packet_set_interactive(int interactive, int keepalives)
|
|||
sizeof(on)) < 0)
|
||||
error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
|
||||
} 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;
|
||||
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
|
||||
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
|
||||
#define PACKET_H
|
||||
|
@ -27,10 +27,11 @@
|
|||
#include <ssl/bn.h>
|
||||
#endif
|
||||
|
||||
/* Sets the socket used for communication. Disables encryption until
|
||||
packet_set_encryption_key is called. It is permissible that fd_in
|
||||
and fd_out are the same descriptor; in that case it is assumed to
|
||||
be a socket. */
|
||||
/*
|
||||
* Sets the socket used for communication. Disables encryption until
|
||||
* packet_set_encryption_key is called. It is permissible that fd_in and
|
||||
* 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);
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
|
||||
/* Causes any further packets to be encrypted using the given key. The same
|
||||
key is used for both sending and reception. However, both directions
|
||||
are encrypted independently of each other. Cipher types are
|
||||
defined in ssh.h. */
|
||||
/*
|
||||
* Causes any further packets to be encrypted using the given key. The same
|
||||
* key is used for both sending and reception. However, both directions are
|
||||
* encrypted independently of each other. Cipher types are defined in ssh.h.
|
||||
*/
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||
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);
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
|
||||
/* Returns true if the current connection is interactive. */
|
||||
|
@ -86,28 +94,35 @@ void packet_put_bignum(BIGNUM * value);
|
|||
/* Appends a string to packet data. */
|
||||
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);
|
||||
|
||||
/* Waits until a packet has been received, and returns its type. */
|
||||
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);
|
||||
|
||||
/* Checks if a full packet is available in the data received so far via
|
||||
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_IGNORE messages are skipped by this function and are never returned
|
||||
to higher levels. */
|
||||
/*
|
||||
* Checks if a full packet is available in the data received so far via
|
||||
* 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_IGNORE
|
||||
* messages are skipped by this function and are never returned to higher
|
||||
* levels.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
|
||||
/* 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
|
||||
no longer needed. The length_ptr argument may be NULL, or point to an
|
||||
integer into which the length of the string is stored. */
|
||||
/*
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
|
||||
packet, closes the connection, and exits. This function never returns.
|
||||
The error message should not contain a newline. The total length of the
|
||||
message must not exceed 1024 bytes. */
|
||||
/*
|
||||
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
|
||||
* packet, closes the connection, and exits. This function never returns.
|
||||
* 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,...);
|
||||
|
||||
/* Sends a diagnostic message to the other side. This message
|
||||
can be sent at any time (but not while constructing another message).
|
||||
The message is printed immediately, but only if the client is being
|
||||
executed in verbose mode. These messages are primarily intended to
|
||||
ease debugging authentication problems. The total length of the message
|
||||
must not exceed 1024 bytes. This will automatically call
|
||||
packet_write_wait. If the remote side protocol flags do not indicate
|
||||
that it supports SSH_MSG_DEBUG, this will do nothing. */
|
||||
/*
|
||||
* Sends a diagnostic message to the other side. This message can be sent at
|
||||
* any time (but not while constructing another message). The message is
|
||||
* printed immediately, but only if the client is being executed in verbose
|
||||
* mode. These messages are primarily intended to ease debugging
|
||||
* authentication problems. The total length of the message must not exceed
|
||||
* 1024 bytes. This will automatically call packet_write_wait. If the
|
||||
* remote side protocol flags do not indicate that it supports SSH_MSG_DEBUG,
|
||||
* this will do nothing.
|
||||
*/
|
||||
void packet_send_debug(const char *fmt,...);
|
||||
|
||||
/* Checks if there is any buffered output, and tries to write some of the
|
||||
output. */
|
||||
/* Checks if there is any buffered output, and tries to write some of the output. */
|
||||
void packet_write_poll(void);
|
||||
|
||||
/* Waits until all pending output data has been written. */
|
||||
|
|
44
pty.c
44
pty.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#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 "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
|
||||
#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
|
||||
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). */
|
||||
/*
|
||||
* 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
|
||||
* 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 *namebuf)
|
||||
|
@ -52,8 +54,10 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||
return 1;
|
||||
#else /* HAVE_OPENPTY */
|
||||
#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;
|
||||
|
||||
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
|
||||
|
@ -72,8 +76,10 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||
return 1;
|
||||
#else /* HAVE__GETPTY */
|
||||
#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;
|
||||
char *pts;
|
||||
|
||||
|
@ -103,8 +109,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||
close(*ptyfd);
|
||||
return 0;
|
||||
}
|
||||
/* Push the appropriate streams modules, as described in Solaris
|
||||
pts(7). */
|
||||
/* Push the appropriate streams modules, as described in Solaris pts(7). */
|
||||
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
|
||||
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
|
||||
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
|
||||
|
@ -138,8 +143,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
|
|||
/* BSD-style pty code. */
|
||||
char buf[64];
|
||||
int i;
|
||||
const char *ptymajors =
|
||||
"pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const char *ptyminors = "0123456789abcdef";
|
||||
int num_minors = strlen(ptyminors);
|
||||
int num_ptys = strlen(ptymajors) * num_minors;
|
||||
|
@ -198,8 +202,10 @@ pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
|||
if (setsid() < 0)
|
||||
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);
|
||||
if (fd >= 0) {
|
||||
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. */
|
||||
#ifdef 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
|
||||
absolutely no documentation. */
|
||||
/*
|
||||
* We ignore errors from this, because HPSUX defines TIOCSCTTY, but
|
||||
* returns EINVAL with these arguments, and there is absolutely no
|
||||
* documentation.
|
||||
*/
|
||||
ioctl(*ttyfd, TIOCSCTTY, NULL);
|
||||
#endif /* TIOCSCTTY */
|
||||
fd = open(ttyname, O_RDWR);
|
||||
|
|
24
pty.h
24
pty.h
|
@ -13,23 +13,29 @@
|
|||
* 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
|
||||
#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
|
||||
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). */
|
||||
/*
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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')
|
||||
bufcoded++;
|
||||
|
||||
/* Figure out how many characters are in the input buffer. If this
|
||||
would decode into more bytes than would fit into the output
|
||||
buffer, adjust the number of input bytes downwards. */
|
||||
/*
|
||||
* Figure out how many characters are in the input buffer. If this
|
||||
* would decode into more bytes than would fit into the output
|
||||
* buffer, adjust the number of input bytes downwards.
|
||||
*/
|
||||
bufin = bufcoded;
|
||||
while (DEC(*(bufin++)) <= MAXVAL);
|
||||
nprbytes = bufin - bufcoded - 1;
|
||||
|
|
92
readconf.c
92
readconf.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#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 "cipher.h"
|
||||
|
@ -158,8 +158,10 @@ static struct {
|
|||
#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
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
process_config_line(Options *options, const char *host,
|
||||
char *line, const char *filename, int linenum,
|
||||
int *activep)
|
||||
{
|
||||
char buf[256], *cp, *string, **charptr;
|
||||
char buf[256], *cp, *string, **charptr, *cp2;
|
||||
int opcode, *intptr, value, fwd_port, fwd_host_port;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
|
@ -229,21 +237,14 @@ process_config_line(Options *options, const char *host,
|
|||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
return 0;
|
||||
|
||||
/* Get the keyword. (Each line is supposed to begin with a
|
||||
keyword). */
|
||||
/* Get the keyword. (Each line is supposed to begin with a keyword). */
|
||||
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);
|
||||
|
||||
switch (opcode) {
|
||||
case oBadOption:
|
||||
return -1; /* don't panic, but count bad options */
|
||||
/* don't panic, but count bad options */
|
||||
return -1;
|
||||
/* NOTREACHED */
|
||||
case oForwardAgent:
|
||||
intptr = &options->forward_agent;
|
||||
|
@ -419,17 +420,11 @@ parse_int:
|
|||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (cp[0] < '0' || cp[0] > '9')
|
||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||
#if 0
|
||||
value = atoi(cp);
|
||||
#else
|
||||
{
|
||||
char *ptr;
|
||||
value = strtol(cp, &ptr, 0); /* Octal, decimal, or
|
||||
hex format? */
|
||||
if (cp == ptr)
|
||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Octal, decimal, or hex format? */
|
||||
value = strtol(cp, &cp2, 0);
|
||||
if (cp == cp2)
|
||||
fatal("%.200s line %d: Bad number.", filename, linenum);
|
||||
if (*activep && *intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
@ -506,8 +501,7 @@ parse_int:
|
|||
*activep = 1;
|
||||
break;
|
||||
}
|
||||
/* Avoid garbage check below, as strtok already returned
|
||||
NULL. */
|
||||
/* Avoid garbage check below, as strtok already returned NULL. */
|
||||
return 0;
|
||||
|
||||
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
|
||||
is an error. If the file does not exist, this returns immediately. */
|
||||
/*
|
||||
* Reads the config file and modifies the options accordingly. Options
|
||||
* 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
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
linenum = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
|
@ -579,10 +577,12 @@ read_config_file(const char *filename, const char *host, Options *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.
|
||||
Options are processed in the following order: command line, user config
|
||||
file, system config file. Last, fill_default_options is called. */
|
||||
/*
|
||||
* Initializes options to special values that indicate that they have not yet
|
||||
* been set. Read_config_file will only set options with this value. Options
|
||||
* 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)
|
||||
|
@ -628,8 +628,10 @@ initialize_options(Options * options)
|
|||
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
|
||||
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
|
||||
#define READCONF_H
|
||||
|
@ -85,42 +85,53 @@ typedef struct {
|
|||
} 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.
|
||||
Options are processed in the following order: command line, user config
|
||||
file, system config file. Last, fill_default_options is called. */
|
||||
/*
|
||||
* Initializes options to special values that indicate that they have not yet
|
||||
* been set. Read_config_file will only set options with this value. Options
|
||||
* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Processes a single option line as used in the configuration files.
|
||||
This only sets those values that have not already been set.
|
||||
Returns 0 for legal options */
|
||||
/*
|
||||
* Processes a single option line as used in the configuration files. This
|
||||
* only sets those values that have not already been set. Returns 0 for legal
|
||||
* options
|
||||
*/
|
||||
int
|
||||
process_config_line(Options * options, const char *host,
|
||||
char *line, const char *filename, int linenum,
|
||||
int *activep);
|
||||
|
||||
/* Reads the config file and modifies the options accordingly. Options should
|
||||
already be initialized before this call. This never returns if there
|
||||
is an error. If the file does not exist, this returns immediately. */
|
||||
/*
|
||||
* Reads the config file and modifies the options accordingly. Options
|
||||
* 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
|
||||
read_config_file(const char *filename, const char *host,
|
||||
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
|
||||
add_local_forward(Options * options, int port, const char *host,
|
||||
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
|
||||
add_remote_forward(Options * options, int port, const char *host,
|
||||
int host_port);
|
||||
|
||||
|
||||
#endif /* READCONF_H */
|
||||
|
|
24
readpass.c
24
readpass.c
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
|
@ -38,10 +38,12 @@ intr_handler(int 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.
|
||||
The passphrase if read from stdin if from_stdin is true (as is the
|
||||
case with ssh-keygen). */
|
||||
/*
|
||||
* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
* passphrase (allocated with xmalloc). Exits if EOF is encountered. The
|
||||
* passphrase if read from stdin if from_stdin is true (as is the case with
|
||||
* ssh-keygen).
|
||||
*/
|
||||
|
||||
char *
|
||||
read_passphrase(const char *prompt, int from_stdin)
|
||||
|
@ -53,8 +55,10 @@ read_passphrase(const char *prompt, int from_stdin)
|
|||
if (from_stdin)
|
||||
f = stdin;
|
||||
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");
|
||||
if (!f) {
|
||||
/* 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;
|
||||
/* Allocate a copy of the passphrase. */
|
||||
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));
|
||||
/* Print a newline since the prompt probably didn\'t have one. */
|
||||
fprintf(stderr, "\n");
|
||||
|
|
10
rsa.c
10
rsa.c
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
|
@ -55,9 +55,11 @@ rsa_alive()
|
|||
return (1);
|
||||
}
|
||||
|
||||
/* Generates RSA public and private keys. This initializes the data
|
||||
structures; they should be freed with rsa_clear_private_key and
|
||||
rsa_clear_public_key. */
|
||||
/*
|
||||
* Generates RSA public and private keys. This initializes the data
|
||||
* structures; they should be freed with rsa_clear_private_key and
|
||||
* rsa_clear_public_key.
|
||||
*/
|
||||
|
||||
void
|
||||
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
|
||||
#define RSA_H
|
||||
|
@ -33,8 +33,10 @@
|
|||
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
||||
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));
|
||||
|
||||
int rsa_alive __P((void));
|
||||
|
|
20
scp.c
20
scp.c
|
@ -45,7 +45,7 @@
|
|||
*/
|
||||
|
||||
#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 "xmalloc.h"
|
||||
|
@ -97,9 +97,11 @@ char *identity = NULL;
|
|||
/* This is the port to use in contacting the remote site (is non-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 assigns the input and output file descriptors on success. */
|
||||
/*
|
||||
* This function executes the given command as the specified user on the
|
||||
* given host. This returns < 0 if execution fails, and >= 0 otherwise. This
|
||||
* assigns the input and output file descriptors on success.
|
||||
*/
|
||||
|
||||
int
|
||||
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",
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* 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 *
|
||||
|
@ -1142,7 +1146,7 @@ progressmeter(int flag)
|
|||
(void) gettimeofday(&now, (struct timezone *) 0);
|
||||
cursize = statbytes;
|
||||
if (totalbytes != 0) {
|
||||
ratio = cursize * 100.0 / totalbytes;
|
||||
ratio = 100.0 * cursize / totalbytes;
|
||||
ratio = MAX(ratio, 0);
|
||||
ratio = MIN(ratio, 100);
|
||||
} else
|
||||
|
|
17
servconf.c
17
servconf.c
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
#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 "servconf.h"
|
||||
|
@ -212,8 +212,10 @@ static struct {
|
|||
{ 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
|
||||
parse_token(const char *cp, const char *filename,
|
||||
|
@ -222,7 +224,7 @@ parse_token(const char *cp, const char *filename,
|
|||
unsigned int 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;
|
||||
|
||||
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 == '#')
|
||||
continue;
|
||||
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);
|
||||
switch (opcode) {
|
||||
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
|
||||
#define SERVCONF_H
|
||||
|
@ -84,12 +84,16 @@ typedef struct {
|
|||
unsigned int num_deny_groups;
|
||||
char *deny_groups[MAX_DENY_GROUPS];
|
||||
} 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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 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 volatile int child_terminated; /* The child has terminated. */
|
||||
|
@ -87,9 +89,11 @@ process_buffered_input_packets()
|
|||
break;
|
||||
|
||||
case SSH_CMSG_EOF:
|
||||
/* Eof from the client. The stdin descriptor to
|
||||
the program will be closed when all buffered
|
||||
data has drained. */
|
||||
/*
|
||||
* Eof from the client. The stdin descriptor to the
|
||||
* program will be closed when all buffered data has
|
||||
* drained.
|
||||
*/
|
||||
debug("EOF received for stdin.");
|
||||
packet_integrity_check(payload_len, 0, type);
|
||||
stdin_eof = 1;
|
||||
|
@ -140,13 +144,15 @@ process_buffered_input_packets()
|
|||
break;
|
||||
|
||||
default:
|
||||
/* In this phase, any unexpected messages cause a
|
||||
protocol error. This is to ease debugging;
|
||||
also, since no confirmations are sent messages,
|
||||
unprocessed unknown messages could cause
|
||||
strange problems. Any compatible protocol
|
||||
extensions must be negotiated before entering
|
||||
the interactive session. */
|
||||
/*
|
||||
* In this phase, any unexpected messages cause a
|
||||
* protocol error. This is to ease debugging; also,
|
||||
* since no confirmations are sent messages,
|
||||
* unprocessed unknown messages could cause strange
|
||||
* problems. Any compatible protocol extensions must
|
||||
* be negotiated before entering the interactive
|
||||
* session.
|
||||
*/
|
||||
packet_disconnect("Protocol error during session: type %d",
|
||||
type);
|
||||
}
|
||||
|
@ -230,14 +236,18 @@ retry_select:
|
|||
/* Initialize select() masks. */
|
||||
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 &&
|
||||
channel_not_very_much_buffered_data())
|
||||
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 (!fdout_eof)
|
||||
FD_SET(fdout, readset);
|
||||
|
@ -249,8 +259,10 @@ retry_select:
|
|||
/* Set masks for channel descriptors. */
|
||||
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())
|
||||
FD_SET(connection_out, writeset);
|
||||
|
||||
|
@ -263,8 +275,10 @@ retry_select:
|
|||
if (channel_max_fd() > 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 (max_time_milliseconds == 0)
|
||||
max_time_milliseconds = 100;
|
||||
|
@ -305,9 +319,10 @@ process_input(fd_set * readset)
|
|||
verbose("Connection closed by remote host.");
|
||||
fatal_cleanup();
|
||||
}
|
||||
/* There is a kernel bug on Solaris that causes select to
|
||||
sometimes wake up even though there is no data
|
||||
available. */
|
||||
/*
|
||||
* There is a kernel bug on Solaris that causes select to
|
||||
* sometimes wake up even though there is no data available.
|
||||
*/
|
||||
if (len < 0 && errno == EAGAIN)
|
||||
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(&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
|
||||
stdout and stderr), indicate that we have seen an EOF from
|
||||
stderr. This way we don\'t need to check the descriptor
|
||||
everywhere. */
|
||||
/*
|
||||
* If we have no separate fderr (which is the case when we have a pty
|
||||
* - there we cannot make difference between data sent to stdout and
|
||||
* stderr), indicate that we have seen an EOF from stderr. This way
|
||||
* we don\'t need to check the descriptor everywhere.
|
||||
*/
|
||||
if (fderr == -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_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) {
|
||||
#ifdef USE_PIPES
|
||||
close(fdin);
|
||||
|
@ -484,16 +502,16 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
|||
#endif
|
||||
fdin = -1;
|
||||
}
|
||||
/* Make packets from buffered stderr data to send to the
|
||||
client. */
|
||||
/* Make packets from buffered stderr data to send to the client. */
|
||||
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
|
||||
to not send them now, but to wait a short while to see
|
||||
if we are getting more data. This is necessary, as some
|
||||
systems wake up readers from a pty after each separate
|
||||
character. */
|
||||
/*
|
||||
* Make packets from buffered stdout data to send to the
|
||||
* client. If there is very little to send, this arranges to
|
||||
* not send them now, but to wait a short while to see if we
|
||||
* are getting more data. This is necessary, as some systems
|
||||
* wake up readers from a pty after each separate character.
|
||||
*/
|
||||
max_time_milliseconds = 0;
|
||||
stdout_buffer_bytes = buffer_len(&stdout_buffer);
|
||||
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())
|
||||
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
|
||||
the client, and there is no pending buffered data. */
|
||||
/*
|
||||
* Bail out of the loop if the program has closed its output
|
||||
* 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() &&
|
||||
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
|
||||
if (!channel_still_open())
|
||||
|
@ -604,11 +624,13 @@ quit:
|
|||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Wait for exit confirmation. Note that there might be
|
||||
other packets coming before it; however, the program
|
||||
has already died so we just ignore them. The client is
|
||||
supposed to respond with the confirmation when it
|
||||
receives the exit status. */
|
||||
/*
|
||||
* Wait for exit confirmation. Note that there might be
|
||||
* other packets coming before it; however, the program has
|
||||
* already died so we just ignore them. The client is
|
||||
* supposed to respond with the confirmation when it receives
|
||||
* the exit status.
|
||||
*/
|
||||
do {
|
||||
int plen;
|
||||
type = packet_read(&plen);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
.\"
|
||||
.\" 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
|
||||
.Dt SSH-ADD 1
|
||||
|
@ -71,8 +71,11 @@ terminal if it was run from a terminal. If
|
|||
.Nm
|
||||
does not have a terminal associated with it but
|
||||
.Ev DISPLAY
|
||||
is set, it
|
||||
will open an X11 window to read the passphrase. This is particularly
|
||||
and
|
||||
.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
|
||||
.Nm
|
||||
from a
|
||||
|
|
167
ssh-add.c
167
ssh-add.c
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
#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 "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 "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
|
||||
extern char *__progname;
|
||||
#else /* HAVE___PROGNAME */
|
||||
|
@ -54,13 +50,53 @@ delete_all(AuthenticationConnection *ac)
|
|||
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
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
RSA *public_key;
|
||||
char *saved_comment, *comment;
|
||||
char *saved_comment, *comment, *askpass = NULL;
|
||||
char buf[1024], msg[1024];
|
||||
int success;
|
||||
int interactive = isatty(STDIN_FILENO);
|
||||
|
||||
key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
|
@ -70,29 +106,26 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||
}
|
||||
RSA_free(public_key);
|
||||
|
||||
if (!interactive && getenv("DISPLAY"))
|
||||
askpass = getenv("SSH_ASKPASS");
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
success = load_private_key(filename, "", key, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %s (%s).\n", filename, saved_comment);
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
#ifdef USE_EXTERNAL_ASKPASS
|
||||
int prompts = 3;
|
||||
while (prompts && !success) {
|
||||
success = askpass(filename, key, saved_comment, &comment);
|
||||
prompts--;
|
||||
}
|
||||
if (!success) {
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
#else /* !USE_EXTERNAL_ASKPASS */
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
#endif /* USE_EXTERNAL_ASKPASS */
|
||||
printf("Need passphrase for %.200s\n", filename);
|
||||
if (!interactive && askpass == NULL) {
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!success) {
|
||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
||||
snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
|
||||
for (;;) {
|
||||
char *pass;
|
||||
if (interactive) {
|
||||
snprintf(buf, sizeof buf, "%s: ", msg);
|
||||
pass = read_passphrase(buf, 1);
|
||||
} else {
|
||||
pass = ssh_askpass(askpass, msg);
|
||||
}
|
||||
if (strcmp(pass, "") == 0) {
|
||||
xfree(pass);
|
||||
xfree(saved_comment);
|
||||
|
@ -103,7 +136,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||
xfree(pass);
|
||||
if (success)
|
||||
break;
|
||||
printf("Bad passphrase.\n");
|
||||
strlcpy(msg, "Bad passphrase, try again", sizeof msg);
|
||||
}
|
||||
}
|
||||
xfree(saved_comment);
|
||||
|
@ -222,85 +255,3 @@ main(int argc, char **argv)
|
|||
ssh_close_authentication_connection(ac);
|
||||
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>
|
||||
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
#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 "rsa.h"
|
||||
|
@ -189,10 +189,12 @@ process_remove_identity(SocketEntry *e)
|
|||
/* Check if we have the key. */
|
||||
for (i = 0; i < num_identities; i++)
|
||||
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
|
||||
of the array, we actually free the key there
|
||||
and copy data from the last entry. */
|
||||
/*
|
||||
* We have this key. Free the old key. Since we
|
||||
* don\'t want to leave empty slots in the middle of
|
||||
* the array, we actually free the key there and copy
|
||||
* data from the last entry.
|
||||
*/
|
||||
RSA_free(identities[i].key);
|
||||
xfree(identities[i].comment);
|
||||
if (i < num_identities - 1)
|
||||
|
@ -291,8 +293,10 @@ process_add_identity(SocketEntry *e)
|
|||
/* Check if we already have the key. */
|
||||
for (i = 0; i < num_identities; i++)
|
||||
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);
|
||||
xfree(identities[num_identities].comment);
|
||||
|
||||
|
@ -511,11 +515,7 @@ main(int ac, char **av)
|
|||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
#if defined(__GNU_LIBRARY__)
|
||||
while ((ch = getopt(ac, av, "+cks")) != -1) {
|
||||
#else
|
||||
while ((ch = getopt(ac, av, "cks")) != -1) {
|
||||
#endif /* defined(__GNU_LIBRARY__) */
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
if (s_flag)
|
||||
|
@ -579,8 +579,10 @@ main(int ac, char **av)
|
|||
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
|
||||
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);
|
||||
if (sock < 0) {
|
||||
perror("socket");
|
||||
|
@ -597,9 +599,10 @@ main(int ac, char **av)
|
|||
perror("listen");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
/* Fork, and have the parent execute the command, if any, or
|
||||
present the socket data. The child continues as the
|
||||
authentication agent. */
|
||||
/*
|
||||
* Fork, and have the parent execute the command, if any, or present
|
||||
* the socket data. The child continues as the authentication agent.
|
||||
*/
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
|
|
55
ssh-keygen.c
55
ssh-keygen.c
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
|
@ -20,16 +20,19 @@ RSA *private_key;
|
|||
/* Generated public key. */
|
||||
RSA *public_key;
|
||||
|
||||
/* Number of bits in the RSA key. This value can be changed on the command
|
||||
line. */
|
||||
/* Number of bits in the RSA key. This value can be changed on the command line. */
|
||||
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;
|
||||
|
||||
/* 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 quiet = 0;
|
||||
|
@ -136,13 +139,10 @@ do_change_passphrase(struct passwd *pw)
|
|||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
/* Check if the file exists. */
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
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();
|
||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||
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. */
|
||||
private_key = RSA_new();
|
||||
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
||||
/* Read passphrase from the user. */
|
||||
if (identity_passphrase)
|
||||
old_passphrase = xstrdup(identity_passphrase);
|
||||
else
|
||||
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)) {
|
||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||
xfree(old_passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the passphrase. */
|
||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||
xfree(old_passphrase);
|
||||
}
|
||||
|
@ -230,24 +227,24 @@ do_change_comment(struct passwd *pw)
|
|||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
/* Check if the file exists. */
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
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();
|
||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
private_key = RSA_new();
|
||||
/* Try to load the file with empty passphrase. */
|
||||
|
||||
if (load_private_key(identity_file, "", private_key, &comment))
|
||||
passphrase = xstrdup("");
|
||||
else {
|
||||
/* Read passphrase from the user. */
|
||||
if (identity_passphrase)
|
||||
passphrase = xstrdup(identity_passphrase);
|
||||
else if (identity_new_passphrase)
|
||||
|
@ -274,7 +271,6 @@ do_change_comment(struct passwd *pw)
|
|||
RSA_free(private_key);
|
||||
exit(1);
|
||||
}
|
||||
/* Remove terminating newline from comment. */
|
||||
if (strchr(new_comment, '\n'))
|
||||
*strchr(new_comment, '\n') = 0;
|
||||
}
|
||||
|
@ -289,13 +285,10 @@ do_change_comment(struct passwd *pw)
|
|||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the passphrase and the private key in memory. */
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
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));
|
||||
f = fopen(identity_file, "w");
|
||||
if (!f) {
|
||||
|
@ -343,21 +336,18 @@ main(int ac, char **av)
|
|||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
extern char *__progname;
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
/* Get user\'s passwd structure. We need this for the home
|
||||
directory. */
|
||||
/* we need this for the home * directory. */
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
printf("You don't exist, go away!\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Parse command line arguments. */
|
||||
|
||||
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
|
@ -416,14 +406,8 @@ main(int ac, char **av)
|
|||
}
|
||||
if (print_fingerprint)
|
||||
do_fingerprint(pw);
|
||||
|
||||
/* If the user requested to change the passphrase, do it now.
|
||||
This function never returns. */
|
||||
if (change_passphrase)
|
||||
do_change_passphrase(pw);
|
||||
|
||||
/* If the user requested to change the comment, do it now. This
|
||||
function never returns. */
|
||||
if (change_comment)
|
||||
do_change_comment(pw);
|
||||
|
||||
|
@ -484,11 +468,10 @@ passphrase_again:
|
|||
xfree(passphrase2);
|
||||
}
|
||||
|
||||
/* Create default commend field for the passphrase. The user can
|
||||
later edit this field. */
|
||||
if (identity_comment) {
|
||||
strlcpy(comment, identity_comment, sizeof(comment));
|
||||
} else {
|
||||
/* Create default commend field for the passphrase. */
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
perror("gethostname");
|
||||
exit(1);
|
||||
|
@ -515,8 +498,6 @@ passphrase_again:
|
|||
if (!quiet)
|
||||
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));
|
||||
f = fopen(identity_file, "w");
|
||||
if (!f) {
|
||||
|
|
4
ssh.1
4
ssh.1
|
@ -9,7 +9,7 @@
|
|||
.\"
|
||||
.\" 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
|
||||
.Dt SSH 1
|
||||
|
@ -293,7 +293,7 @@ disables any escapes and makes the session fully transparent.
|
|||
.It Fl f
|
||||
Requests
|
||||
.Nm
|
||||
to go to background after authentication. This is useful
|
||||
to go to background just before command execution. This is useful
|
||||
if
|
||||
.Nm
|
||||
is going to ask for passwords or passphrases, but the user
|
||||
|
|
179
ssh.c
179
ssh.c
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
|
||||
#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 "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. */
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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
|
||||
background. */
|
||||
/*
|
||||
* 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
|
||||
* background.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* 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
|
||||
in a configuration file. */
|
||||
/*
|
||||
* 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 in a
|
||||
* configuration file.
|
||||
*/
|
||||
char *host;
|
||||
|
||||
/* socket address the host resolves to */
|
||||
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
|
||||
window size to be sent to the server a little later. This is volatile
|
||||
because this is updated in a signal handler. */
|
||||
/*
|
||||
* Flag to indicate that we have received a window change signal which has
|
||||
* not yet been processed. This will cause a message indicating the new
|
||||
* window size to be sent to the server a little later. This is volatile
|
||||
* because this is updated in a signal handler.
|
||||
*/
|
||||
volatile int received_window_change_signal = 0;
|
||||
|
||||
/* Value of argv[0] (set in the main program). */
|
||||
|
@ -165,8 +173,10 @@ main(int ac, char **av)
|
|||
uid_t original_effective_uid;
|
||||
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_effective_uid = geteuid();
|
||||
|
||||
|
@ -177,18 +187,21 @@ main(int ac, char **av)
|
|||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||
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
|
||||
are ready to create the privileged port, and will permanently
|
||||
drop them when the port has been created (actually, when the
|
||||
connection has been made, as we may need to create the port
|
||||
several times). */
|
||||
/*
|
||||
* Use uid-swapping to give up root privileges for the duration of
|
||||
* option processing. We will re-instantiate the rights when we are
|
||||
* ready to create the privileged port, and will permanently drop
|
||||
* them when the port has been created (actually, when the connection
|
||||
* has been made, as we may need to create the port several times).
|
||||
*/
|
||||
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
|
||||
world-readable but writable only by the owner, which is ok for
|
||||
all files for which we don't set the modes explicitly. */
|
||||
/*
|
||||
* Set our umask to something reasonable, as some files are created
|
||||
* with the default umask. This will make them world-readable but
|
||||
* writable only by the owner, which is ok for all files for which we
|
||||
* don't set the modes explicitly.
|
||||
*/
|
||||
umask(022);
|
||||
|
||||
/* Save our own name. */
|
||||
|
@ -387,10 +400,11 @@ main(int ac, char **av)
|
|||
/* Initialize the command to execute on remote host. */
|
||||
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
|
||||
maximum packet size. Also sets the tty flag if there is no
|
||||
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 maximum
|
||||
* packet size. Also sets the tty flag if there is no command.
|
||||
*/
|
||||
if (optind == ac) {
|
||||
/* No command specified - execute shell on a tty. */
|
||||
tty_flag = 1;
|
||||
|
@ -474,11 +488,15 @@ main(int ac, char **av)
|
|||
options.rhosts_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) {
|
||||
/* 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();
|
||||
|
||||
/* Switch to the original uid permanently. */
|
||||
|
@ -491,8 +509,10 @@ main(int ac, char **av)
|
|||
/* Restore our superuser privileges. */
|
||||
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,
|
||||
options.connection_attempts,
|
||||
|
@ -501,31 +521,38 @@ main(int ac, char **av)
|
|||
original_real_uid,
|
||||
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
|
||||
authentication. This must be done before releasing extra
|
||||
privileges, because the file is only readable by root. */
|
||||
/*
|
||||
* If we successfully made the connection, load the host private key
|
||||
* in case we will need it later for combined rsa-rhosts
|
||||
* authentication. This must be done before releasing extra
|
||||
* privileges, because the file is only readable by root.
|
||||
*/
|
||||
if (ok) {
|
||||
host_private_key = RSA_new();
|
||||
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
|
||||
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
|
||||
hard to read identity files and other non-world-readable files
|
||||
from the 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. */
|
||||
/*
|
||||
* Get rid of any extra privileges that we may have. We will no
|
||||
* longer need them. Also, extra privileges could make it very hard
|
||||
* to read identity files and other non-world-readable files from the
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
if (stat(buf, &st) < 0)
|
||||
if (mkdir(buf, 0755) < 0)
|
||||
|
@ -569,15 +596,6 @@ main(int ac, char **av)
|
|||
/* Close connection cleanly after attack. */
|
||||
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. */
|
||||
if (options.compression) {
|
||||
debug("Requesting compression at level %d.", options.compression_level);
|
||||
|
@ -653,12 +671,14 @@ main(int ac, char **av)
|
|||
if (f)
|
||||
pclose(f);
|
||||
#endif /* XAUTH_PATH */
|
||||
/* If we didn't get authentication data, just make up some
|
||||
data. The forwarding code will check the validity of
|
||||
the response anyway, and substitute this data. The X11
|
||||
server, however, will ignore this fake data and use
|
||||
whatever authentication mechanisms it was using
|
||||
otherwise for the local connection. */
|
||||
/*
|
||||
* If we didn't get authentication data, just make up some
|
||||
* data. The forwarding code will check the validity of the
|
||||
* response anyway, and substitute this data. The X11
|
||||
* server, however, will ignore this fake data and use
|
||||
* whatever authentication mechanisms it was using otherwise
|
||||
* for the local connection.
|
||||
*/
|
||||
if (!got_data) {
|
||||
u_int32_t rand = 0;
|
||||
|
||||
|
@ -670,8 +690,10 @@ main(int ac, char **av)
|
|||
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.");
|
||||
x11_request_forwarding_with_spoofing(proto, data);
|
||||
|
||||
|
@ -728,8 +750,15 @@ main(int ac, char **av)
|
|||
options.remote_forwards[i].host_port);
|
||||
}
|
||||
|
||||
/* If a command was specified on the command line, execute the
|
||||
command now. Otherwise request the server to start a shell. */
|
||||
/* If requested, let ssh continue in the background. */
|
||||
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) {
|
||||
int len = buffer_len(&command);
|
||||
if (len > 900)
|
||||
|
|
516
ssh.h
516
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
|
||||
#define SSH_H
|
||||
|
@ -25,9 +25,11 @@
|
|||
#include "rsa.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),
|
||||
though that is not required. */
|
||||
/*
|
||||
* 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), though
|
||||
* that is not required.
|
||||
*/
|
||||
#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES
|
||||
|
||||
/* Cipher used for encrypting authentication files. */
|
||||
|
@ -39,20 +41,28 @@
|
|||
/* Maximum number of TCP/IP ports forwarded per direction. */
|
||||
#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
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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"
|
||||
|
||||
#ifndef ETCDIR
|
||||
|
@ -63,16 +73,16 @@
|
|||
#define PIDDIR "/var/run"
|
||||
#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"
|
||||
|
||||
/* HOST_KEY_FILE /etc/ssh_host_key,
|
||||
SERVER_CONFIG_FILE /etc/sshd_config,
|
||||
and HOST_CONFIG_FILE /etc/ssh_config
|
||||
are all defined in Makefile.in. Of these, ssh_host_key should be readable
|
||||
only by root, whereas ssh_config should be world-readable. */
|
||||
|
||||
/*
|
||||
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
|
||||
* should be world-readable.
|
||||
*/
|
||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_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"
|
||||
#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"
|
||||
|
||||
/* 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"
|
||||
|
||||
/* 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
|
||||
not contain anything particularly secret. */
|
||||
/*
|
||||
* 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 not
|
||||
* contain anything particularly secret.
|
||||
*/
|
||||
#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"
|
||||
|
||||
/* Configuration file in user\'s home directory. This file need not be
|
||||
readable by anyone but the user him/herself, but does not contain
|
||||
anything particularly secret. If the user\'s home directory resides
|
||||
on an NFS volume where root is mapped to nobody, this may need to be
|
||||
world-readable. */
|
||||
/*
|
||||
* Configuration file in user\'s home directory. This file need not be
|
||||
* readable by anyone but the user him/herself, but does not contain anything
|
||||
* particularly secret. If the user\'s home directory resides on an NFS
|
||||
* volume where root is mapped to nobody, this may need to be world-readable.
|
||||
*/
|
||||
#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
|
||||
readable by anyone but the user him/herself, but does not contain
|
||||
anything particularly secret. If the user\'s home directory resides
|
||||
on an NFS volume where root is mapped to nobody, this may need to be
|
||||
world-readable. (This file is read by the daemon which is running as
|
||||
root.) */
|
||||
/*
|
||||
* File containing a list of those rsa keys that permit logging in as this
|
||||
* user. This file need not be readable by anyone but the user him/herself,
|
||||
* but does not contain anything particularly secret. If the user\'s home
|
||||
* directory resides on an NFS volume where root is mapped to nobody, this
|
||||
* may need to be world-readable. (This file is read by the daemon which is
|
||||
* running as root.)
|
||||
*/
|
||||
#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
|
||||
will be passed "proto cookie" as arguments if X11 forwarding with
|
||||
spoofing is in use. xauth will be run if neither of these exists. */
|
||||
/*
|
||||
* 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 will be
|
||||
* 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_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"
|
||||
|
||||
/* 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"
|
||||
|
||||
/* 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"
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
/* Name of Kerberos service for SSH to use. */
|
||||
#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_RSA 2
|
||||
#define SSH_AUTH_PASSWORD 3
|
||||
|
@ -163,20 +195,20 @@ only by root, whereas ssh_config should be world-readable. */
|
|||
#define SSH_AUTH_TIS 5
|
||||
#define SSH_AUTH_KERBEROS 6
|
||||
#define SSH_PASS_KERBEROS_TGT 7
|
||||
/* 8 to 15 are reserved */
|
||||
/* 8 to 15 are reserved */
|
||||
#define SSH_PASS_AFS_TOKEN 21
|
||||
|
||||
/* Protocol flags. These are bit masks. */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes
|
||||
* screen */
|
||||
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain
|
||||
* host */
|
||||
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
|
||||
#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
|
||||
for compatibility. The maximum value is 254; value 255 is reserved
|
||||
for future extension. */
|
||||
/* Message name *//* msg code *//* arguments */
|
||||
/*
|
||||
* Definition of message types. New values can be added, but old values
|
||||
* should not be removed or without careful consideration of the consequences
|
||||
* for compatibility. The maximum value is 254; value 255 is reserved for
|
||||
* future extension.
|
||||
*/
|
||||
/* Message name */ /* msg code */ /* arguments */
|
||||
#define SSH_MSG_NONE 0 /* no message */
|
||||
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
|
||||
#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 -------------*/
|
||||
|
||||
/* Returns the time when the user last logged in. Returns 0 if the
|
||||
information is not available. This must be called before record_login.
|
||||
The host from which the user logged in is stored in buf. */
|
||||
/*
|
||||
* Returns the time when the user last logged in. Returns 0 if the
|
||||
* 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
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
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
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
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);
|
||||
|
||||
/*------------ 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,
|
||||
a privileged port will be allocated to make the connection.
|
||||
This requires super-user privileges if anonymous is false.
|
||||
Connection_attempts specifies the maximum number of tries, one per
|
||||
second. This returns true on success, and zero on failure. If the
|
||||
connection is successful, this calls packet_set_connection for the
|
||||
connection. */
|
||||
/*
|
||||
* 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, a privileged
|
||||
* port will be allocated to make the connection. This requires super-user
|
||||
* privileges if anonymous is false. Connection_attempts specifies the
|
||||
* maximum number of tries, one per second. This returns true on success,
|
||||
* and zero on failure. If the connection is successful, this calls
|
||||
* packet_set_connection for the connection.
|
||||
*/
|
||||
int
|
||||
ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
||||
int port, int connection_attempts,
|
||||
int anonymous, uid_t original_real_uid,
|
||||
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
|
||||
to the server must already have been established before this is called.
|
||||
If login fails, this function prints an error and never returns.
|
||||
This initializes the random state, and leaves it initialized (it will also
|
||||
have references from the packet module). */
|
||||
/*
|
||||
* Starts a dialog with the server, and authenticates the current user on the
|
||||
* server. This does not need any extra privileges. The basic connection to
|
||||
* the server must already have been established before this is called. If
|
||||
* login fails, this function prints an error and never returns. This
|
||||
* initializes the random state, and leaves it initialized (it will also have
|
||||
* references from the packet module).
|
||||
*/
|
||||
|
||||
void
|
||||
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. -------*/
|
||||
|
||||
/* Tries to authenticate the user using the .rhosts file. Returns true if
|
||||
authentication succeeds. If ignore_rhosts is non-zero, this will not
|
||||
consider .rhosts and .shosts (/etc/hosts.equiv will still be used). */
|
||||
/*
|
||||
* Tries to authenticate the user using the .rhosts file. Returns true if
|
||||
* 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);
|
||||
|
||||
/* 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
|
||||
auth_rhosts_rsa(struct passwd * pw, const char *client_user,
|
||||
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);
|
||||
|
||||
/* Performs the RSA authentication dialog with the client. This returns
|
||||
0 if the client could not be authenticated, and 1 if authentication was
|
||||
successful. This may exit if there is a serious protocol violation. */
|
||||
/*
|
||||
* Performs the RSA authentication dialog with the client. This returns 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 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
cached, so it is efficient to call this several times. */
|
||||
/*
|
||||
* 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
|
||||
* cached, so it is efficient to call this several times.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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. */
|
||||
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
|
||||
indicate negation). Returns true if there is a positive match; zero
|
||||
otherwise. */
|
||||
/*
|
||||
* Tries to match the host name (which must be in all lowercase) against the
|
||||
* comma-separated sequence of subpatterns (each possibly preceded by ! to
|
||||
* indicate negation). Returns true if there is a positive match; zero
|
||||
* otherwise.
|
||||
*/
|
||||
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,
|
||||
HOST_NEW 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. */
|
||||
/*
|
||||
* 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, HOST_NEW
|
||||
* 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 {
|
||||
HOST_OK, HOST_NEW, HOST_CHANGED
|
||||
} HostStatus;
|
||||
|
@ -332,43 +393,55 @@ HostStatus
|
|||
check_host_in_hostfile(const char *filename, const char *host,
|
||||
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
|
||||
add_host_to_hostfile(const char *filename, const char *host,
|
||||
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
|
||||
our challenge; returns zero if the client gives a wrong answer. */
|
||||
/*
|
||||
* Performs the RSA authentication challenge-response dialog with the client,
|
||||
* 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);
|
||||
|
||||
/* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
passphrase (allocated with xmalloc). Exits if EOF is encountered.
|
||||
If from_stdin is true, the passphrase will be read from stdin instead. */
|
||||
/*
|
||||
* Reads a passphrase from /dev/tty with echo turned off. Returns the
|
||||
* 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);
|
||||
|
||||
/* Saves the authentication (private) key in a file, encrypting it with
|
||||
passphrase. The identification of the file (lowest 64 bits of n)
|
||||
will precede the key to provide identification of the key without
|
||||
needing a passphrase. */
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase. The identification of the file (lowest 64 bits of n) will
|
||||
* precede the key to provide identification of the key without needing a
|
||||
* passphrase.
|
||||
*/
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
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
|
||||
read. The comment of the key is returned in comment_return if it is
|
||||
non-NULL; the caller must free the value with xfree. */
|
||||
/*
|
||||
* 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 read. The
|
||||
* comment of the key is returned in comment_return if it is non-NULL; the
|
||||
* caller must free the value with xfree.
|
||||
*/
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
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).
|
||||
This initializes the private key. The comment of the key is returned
|
||||
in comment_return if it is non-NULL; the caller must free the value
|
||||
with xfree. */
|
||||
/*
|
||||
* 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). This
|
||||
* initializes the private key. The comment of the key is returned in
|
||||
* comment_return if it is non-NULL; the caller must free the value with
|
||||
* xfree.
|
||||
*/
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
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 */
|
||||
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
|
||||
from the function. */
|
||||
/*
|
||||
* 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 from the function.
|
||||
*/
|
||||
void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
||||
|
||||
/* 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. */
|
||||
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
|
||||
is freed. */
|
||||
/*
|
||||
* 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
|
||||
* is freed.
|
||||
*/
|
||||
int channel_allocate(int type, int sock, char *remote_name);
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
|
||||
/* If there is data to send to the connection, send some of it now. */
|
||||
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
|
||||
is still there. */
|
||||
/*
|
||||
* 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 is
|
||||
* still there.
|
||||
*/
|
||||
void channel_input_data(int payload_len);
|
||||
|
||||
/* Returns true if no channel has too much buffered data. */
|
||||
|
@ -473,8 +554,10 @@ void channel_input_open_failure(void);
|
|||
any unix domain sockets. */
|
||||
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);
|
||||
|
||||
/* 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. */
|
||||
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.
|
||||
The caller should free the string with xfree. */
|
||||
/*
|
||||
* 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.
|
||||
* The caller should free the string with xfree.
|
||||
*/
|
||||
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
|
||||
was an error. */
|
||||
/*
|
||||
* Initiate forwarding of connections to local port "port" through the secure
|
||||
* channel to host:port from remote side. This never returns if there was an
|
||||
* error.
|
||||
*/
|
||||
void
|
||||
channel_request_local_forwarding(int port, const char *host,
|
||||
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
|
||||
if there was an error. This registers that open requests for that
|
||||
port are permitted. */
|
||||
/*
|
||||
* Initiate forwarding of connections to port "port" on remote host through
|
||||
* the secure channel to host:port from local side. This never returns if
|
||||
* there was an error. This registers that open requests for that port are
|
||||
* permitted.
|
||||
*/
|
||||
void
|
||||
channel_request_remote_forwarding(int port, const char *host,
|
||||
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,
|
||||
and the server has no way to know but to trust the client anyway. */
|
||||
/*
|
||||
* 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,
|
||||
* and the server has no way to know but to trust the client anyway.
|
||||
*/
|
||||
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
|
||||
message if there was an error). This never returns if there was an
|
||||
error. */
|
||||
/*
|
||||
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
|
||||
* listening for the port, and sends back a success reply (or disconnect
|
||||
* message if there was an error). This never returns if there was an error.
|
||||
*/
|
||||
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
|
||||
CHANNEL_OPEN_FAILURE. */
|
||||
/*
|
||||
* This is called after receiving PORT_OPEN message. This attempts to
|
||||
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
|
||||
* or CHANNEL_OPEN_FAILURE.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Creates an internet domain socket for listening for X11 connections.
|
||||
Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||
occurs. */
|
||||
/*
|
||||
* Creates an internet domain socket for listening for X11 connections.
|
||||
* Returns a suitable value for the DISPLAY variable, or NULL if an error
|
||||
* occurs.
|
||||
*/
|
||||
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
|
||||
with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */
|
||||
/*
|
||||
* 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
|
||||
* with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Sends a message to the server to request authentication fd forwarding. */
|
||||
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
|
||||
to a static buffer. */
|
||||
/*
|
||||
* Returns the name of the forwarded authentication socket. Returns NULL if
|
||||
* there is no forwarded authentication socket. The returned value points to
|
||||
* a static buffer.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Performs the interactive session. This handles data transmission between
|
||||
the client and the program. Note that the notion of stdin, stdout, and
|
||||
stderr in this function is sort of reversed: this function writes to
|
||||
stdin (of the child program), and reads from stdout and stderr (of the
|
||||
child program). */
|
||||
/*
|
||||
* Performs the interactive session. This handles data transmission between
|
||||
* the client and the program. Note that the notion of stdin, stdout, and
|
||||
* stderr in this function is sort of reversed: this function writes to stdin
|
||||
* (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);
|
||||
|
||||
/* Client side main loop for the interactive session. */
|
||||
|
@ -582,9 +696,11 @@ struct envstring {
|
|||
#ifdef KRB4
|
||||
#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
|
||||
successful. This may exit if there is a serious protocol violation. */
|
||||
/*
|
||||
* Performs Kerberos v4 mutual authentication with the client. This returns 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 auth_krb4(const char *server_user, KTEXT auth, char **client);
|
||||
int krb4_init(uid_t uid);
|
||||
void krb4_cleanup_proc(void *ignore);
|
||||
|
|
187
sshconnect.c
187
sshconnect.c
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
#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
|
||||
#include <openssl/bn.h>
|
||||
|
@ -142,8 +142,10 @@ ssh_create_socket(uid_t original_real_uid, int privileged)
|
|||
{
|
||||
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) {
|
||||
int p = IPPORT_RESERVED - 1;
|
||||
|
||||
|
@ -227,9 +229,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||
!anonymous && geteuid() == 0 &&
|
||||
port < IPPORT_RESERVED);
|
||||
|
||||
/* Connect to the host. We use the user's uid in
|
||||
the hope that it will help with the problems of
|
||||
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 the problems of
|
||||
* tcp_wrappers showing the remote uid as root.
|
||||
*/
|
||||
temporarily_use_uid(original_real_uid);
|
||||
if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr))
|
||||
>= 0) {
|
||||
|
@ -270,8 +274,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||
!anonymous && geteuid() == 0 &&
|
||||
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);
|
||||
if (connect(sock, (struct sockaddr *) hostaddr,
|
||||
sizeof(*hostaddr)) >= 0) {
|
||||
|
@ -282,8 +290,12 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||
debug("connect: %.100s", strerror(errno));
|
||||
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);
|
||||
close(sock);
|
||||
}
|
||||
|
@ -300,10 +312,11 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
|
|||
|
||||
debug("Connection established.");
|
||||
|
||||
/* 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)); */
|
||||
/*
|
||||
* 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)); */
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
|
@ -493,8 +506,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile)
|
|||
/* Wait for server's response. */
|
||||
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) {
|
||||
debug("Server refused our key.");
|
||||
xfree(comment);
|
||||
|
@ -514,8 +529,10 @@ try_rsa_authentication(struct passwd * pw, const char *authfile)
|
|||
debug("Received RSA challenge from server.");
|
||||
|
||||
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)) {
|
||||
char buf[300];
|
||||
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);
|
||||
|
||||
/* If his response isn't properly encrypted with the
|
||||
session key, and the decrypted checksum fails to match,
|
||||
he's bogus. Bail out. */
|
||||
/*
|
||||
* If his response isn't properly encrypted with the session
|
||||
* key, and the decrypted checksum fails to match, he's
|
||||
* bogus. Bail out.
|
||||
*/
|
||||
r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
|
||||
&foreign, &local, &msg_data);
|
||||
if (r != KSUCCESS) {
|
||||
|
@ -894,8 +913,10 @@ ssh_exchange_identification()
|
|||
}
|
||||
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,
|
||||
remote_version) != 3)
|
||||
fatal("Bad remote protocol version identification: '%.100s'", buf);
|
||||
|
@ -916,9 +937,11 @@ ssh_exchange_identification()
|
|||
}
|
||||
}
|
||||
#if 0
|
||||
/* Removed for now, to permit compatibility with latter versions.
|
||||
The server will reject our version and disconnect if it doesn't
|
||||
support it. */
|
||||
/*
|
||||
* Removed for now, to permit compatibility with latter versions. The
|
||||
* server will reject our version and disconnect if it doesn't
|
||||
* support it.
|
||||
*/
|
||||
if (remote_major != PROTOCOL_MAJOR)
|
||||
fatal("Protocol major versions differ: %d vs. %d",
|
||||
PROTOCOL_MAJOR, remote_major);
|
||||
|
@ -1086,10 +1109,7 @@ ssh_login(int host_key_valid,
|
|||
protocol_flags = packet_get_int();
|
||||
packet_set_protocol_flags(protocol_flags);
|
||||
|
||||
/* Get supported cipher types. */
|
||||
supported_ciphers = packet_get_int();
|
||||
|
||||
/* Get supported authentication types. */
|
||||
supported_authentications = packet_get_int();
|
||||
|
||||
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,
|
||||
SSH_SMSG_PUBLIC_KEY);
|
||||
|
||||
/* Compute the session id. */
|
||||
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_key->e, host_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_key->e, host_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
|
||||
multiple machines, localhost will refer to a different machine
|
||||
in each of them, and the user will get bogus HOST_CHANGED
|
||||
warnings. This essentially disables host authentication for
|
||||
localhost; however, this is probably not a real problem. */
|
||||
/*
|
||||
* 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 multiple
|
||||
* machines, localhost will refer to a different machine in each of
|
||||
* them, and the user will get bogus HOST_CHANGED warnings. This
|
||||
* essentially disables host authentication for localhost; however,
|
||||
* this is probably not a real problem.
|
||||
*/
|
||||
if (local) {
|
||||
debug("Forcing accepting of host key for localhost.");
|
||||
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)) {
|
||||
RSA *ip_key = RSA_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.",
|
||||
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)
|
||||
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) {
|
||||
error("Password authentication is disabled to avoid trojan horses.");
|
||||
options.password_authentication = 0;
|
||||
|
@ -1241,11 +1271,13 @@ ssh_login(int host_key_valid,
|
|||
error("Agent forwarding is disabled to avoid trojan horses.");
|
||||
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
|
||||
identifying sentence, tell that the host identifies
|
||||
itself by that sentence, and ask the user if he/she
|
||||
whishes to accept the authentication. */
|
||||
/*
|
||||
* XXX Should permit the user to change to use the new id.
|
||||
* This could be done by converting the host key to an
|
||||
* identifying sentence, tell that the host identifies itself
|
||||
* by that sentence, and ask the user if he/she whishes to
|
||||
* accept the authentication.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1255,9 +1287,11 @@ ssh_login(int host_key_valid,
|
|||
/* Generate a session key. */
|
||||
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
|
||||
significant 8 bits being the first byte of the key. */
|
||||
/*
|
||||
* Generate an encryption key for the session. The key is a 256 bit
|
||||
* 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++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
|
@ -1265,9 +1299,11 @@ ssh_login(int host_key_valid,
|
|||
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
|
||||
xored with the first 16 bytes of the session id. */
|
||||
/*
|
||||
* According to the protocol spec, the first byte of the session key
|
||||
* is the highest byte of the integer. The session key is xored with
|
||||
* the first 16 bytes of the session id.
|
||||
*/
|
||||
key = BN_new();
|
||||
BN_set_word(key, 0);
|
||||
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]);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
/* Public key has smaller modulus. */
|
||||
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. */
|
||||
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);
|
||||
|
||||
debug("Received encrypted confirmation.");
|
||||
|
@ -1366,9 +1406,11 @@ ssh_login(int host_key_valid,
|
|||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* The server should respond with success if no authentication is
|
||||
needed (the user has no password). Otherwise the server
|
||||
responds with failure. */
|
||||
/*
|
||||
* The server should respond with success if no authentication is
|
||||
* needed (the user has no password). Otherwise the server responds
|
||||
* with failure.
|
||||
*/
|
||||
type = packet_read(&payload_len);
|
||||
|
||||
/* check whether the connection was accepted without authentication. */
|
||||
|
@ -1410,8 +1452,10 @@ ssh_login(int host_key_valid,
|
|||
}
|
||||
#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)) &&
|
||||
options.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",
|
||||
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)) &&
|
||||
options.rhosts_rsa_authentication && host_key_valid) {
|
||||
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. */
|
||||
if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
|
||||
options.rsa_authentication) {
|
||||
/* Try RSA authentication using the authentication agent.
|
||||
The agent is tried first because no passphrase is
|
||||
needed for it, whereas identity files may require
|
||||
passphrases. */
|
||||
/*
|
||||
* Try RSA authentication using the authentication agent. The
|
||||
* agent is tried first because no passphrase is needed for
|
||||
* it, whereas identity files may require passphrases.
|
||||
*/
|
||||
if (try_agent_authentication())
|
||||
return;
|
||||
|
||||
|
|
499
sshd.c
499
sshd.c
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
|
||||
#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 "rsa.h"
|
||||
|
@ -65,12 +65,16 @@ char *av0;
|
|||
/* Saved arguments to main(). */
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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. */
|
||||
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
|
||||
pages do not get written into swap. However, there are some problems.
|
||||
The private key contains BIGNUMs, and we do not (in principle) have
|
||||
access to the internals of them, and locking just the structure is not
|
||||
very useful. Currently, memory locking is not implemented. */
|
||||
/*
|
||||
* 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 pages do not get written into swap. However, there are some
|
||||
* problems. The private key contains BIGNUMs, and we do not (in principle)
|
||||
* have access to the internals of them, and locking just the structure is
|
||||
* not very useful. Currently, memory locking is not implemented.
|
||||
*/
|
||||
struct {
|
||||
RSA *private_key; /* Private part of server key. */
|
||||
RSA *host_key; /* Private part of host key. */
|
||||
} 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;
|
||||
|
||||
/* 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, "Usage: %s [options]\n", av0);
|
||||
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, " -i Started from inetd\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,
|
||||
sizeof(linger));
|
||||
|
||||
/* Initialize the socket address. */
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = options.listen_addr;
|
||||
sin.sin_port = htons(options.port);
|
||||
|
||||
/* Bind the socket to the desired port. */
|
||||
if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
|
||||
error("bind: %.100s", strerror(errno));
|
||||
shutdown(listen_sock, SHUT_RDWR);
|
||||
|
@ -628,12 +634,13 @@ main(int ac, char **av)
|
|||
fatal("Bind to port %d failed.", options.port);
|
||||
}
|
||||
if (!debug_flag) {
|
||||
/* Record our pid in /etc/sshd_pid to make it
|
||||
easier to kill the correct sshd. We don\'t
|
||||
want to do this before the bind above because
|
||||
the bind will fail if there already is a
|
||||
daemon, and this will overwrite any old pid in
|
||||
the file. */
|
||||
/*
|
||||
* Record our pid in /etc/sshd_pid to make it easier
|
||||
* to kill the correct sshd. We don\'t want to do
|
||||
* this before the bind above because the bind will
|
||||
* fail if there already is a daemon, and this will
|
||||
* overwrite any old pid in the file.
|
||||
*/
|
||||
f = fopen(SSH_DAEMON_PID_FILE, "w");
|
||||
if (f) {
|
||||
fprintf(f, "%u\n", (unsigned int) getpid());
|
||||
|
@ -666,8 +673,10 @@ main(int ac, char **av)
|
|||
/* Arrange SIGCHLD to be caught. */
|
||||
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 (;;) {
|
||||
if (received_sighup)
|
||||
sighup_restart();
|
||||
|
@ -682,12 +691,16 @@ main(int ac, char **av)
|
|||
error("accept: %.100s", strerror(errno));
|
||||
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) {
|
||||
/* In debugging mode. Close the listening
|
||||
socket, and start processing the
|
||||
connection without forking. */
|
||||
/*
|
||||
* In debugging mode. Close the listening
|
||||
* socket, and start processing the
|
||||
* connection without forking.
|
||||
*/
|
||||
debug("Server will not fork when running in debugging mode.");
|
||||
close(listen_sock);
|
||||
sock_in = newsock;
|
||||
|
@ -695,16 +708,17 @@ main(int ac, char **av)
|
|||
pid = getpid();
|
||||
break;
|
||||
} else {
|
||||
/* Normal production daemon. Fork, and
|
||||
have the child process the connection.
|
||||
The parent continues listening. */
|
||||
/*
|
||||
* Normal production daemon. Fork, and have
|
||||
* the child process the connection. The
|
||||
* parent continues listening.
|
||||
*/
|
||||
if ((pid = fork()) == 0) {
|
||||
/* Child. Close the listening
|
||||
socket, and start using the
|
||||
accepted socket. Reinitialize
|
||||
logging (since our pid has
|
||||
changed). We break out of the
|
||||
loop to handle the connection. */
|
||||
/*
|
||||
* Child. Close the listening socket, and start using the
|
||||
* accepted socket. Reinitialize logging (since our pid has
|
||||
* changed). We break out of the loop to handle the connection.
|
||||
*/
|
||||
close(listen_sock);
|
||||
sock_in = newsock;
|
||||
sock_out = newsock;
|
||||
|
@ -731,9 +745,11 @@ main(int ac, char **av)
|
|||
|
||||
/* 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.
|
||||
We will not restart on SIGHUP since it no longer makes sense. */
|
||||
/*
|
||||
* Disable the key regeneration alarm. We will not regenerate the
|
||||
* 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);
|
||||
signal(SIGALRM, SIG_DFL);
|
||||
signal(SIGHUP, SIG_DFL);
|
||||
|
@ -741,17 +757,20 @@ main(int ac, char **av)
|
|||
signal(SIGQUIT, 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
|
||||
connection is not a socket, these will do nothing. */
|
||||
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
|
||||
sizeof(on)); */
|
||||
/*
|
||||
* Set socket options for the connection. We want the socket to
|
||||
* close as fast as possible without waiting for anything. If the
|
||||
* connection is not a socket, these will do nothing.
|
||||
*/
|
||||
/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
|
||||
linger.l_onoff = 1;
|
||||
linger.l_linger = 5;
|
||||
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);
|
||||
|
||||
remote_port = get_remote_port();
|
||||
|
@ -777,12 +796,14 @@ main(int ac, char **av)
|
|||
verbose("Connection from %.500s port %d", remote_ip, remote_port);
|
||||
#endif /* LIBWRAP */
|
||||
|
||||
/* We don\'t want to listen forever unless the other side
|
||||
successfully authenticates itself. So we set up an alarm which
|
||||
is cleared after successful authentication. A limit of zero
|
||||
indicates no limit. Note that we don\'t set the alarm in
|
||||
debugging mode; it is just annoying to have the server exit
|
||||
just when you are about to discover the bug. */
|
||||
/*
|
||||
* We don\'t want to listen forever unless the other side
|
||||
* successfully authenticates itself. So we set up an alarm which is
|
||||
* cleared after successful authentication. A limit of zero
|
||||
* indicates no limit. Note that we don\'t set the alarm in debugging
|
||||
* mode; it is just annoying to have the server exit just when you
|
||||
* are about to discover the bug.
|
||||
*/
|
||||
signal(SIGALRM, grace_alarm_handler);
|
||||
if (!debug_flag)
|
||||
alarm(options.login_grace_time);
|
||||
|
@ -815,8 +836,10 @@ main(int ac, char **av)
|
|||
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,
|
||||
remote_version) != 3) {
|
||||
const char *s = "Protocol mismatch.\n";
|
||||
|
@ -848,11 +871,13 @@ main(int ac, char **av)
|
|||
no_agent_forwarding_flag = 1;
|
||||
}
|
||||
}
|
||||
/* Check that the connection comes from a privileged port. Rhosts-
|
||||
and Rhosts-RSA-Authentication only make sense from priviledged
|
||||
programs. Of course, if the intruder has root access on his
|
||||
local machine, he can connect from any port. So do not use
|
||||
these authentication methods from machines that you do not trust. */
|
||||
/*
|
||||
* Check that the connection comes from a privileged port. Rhosts-
|
||||
* and Rhosts-RSA-Authentication only make sense from priviledged
|
||||
* programs. Of course, if the intruder has root access on his local
|
||||
* 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 ||
|
||||
remote_port < IPPORT_RESERVED / 2) {
|
||||
options.rhosts_authentication = 0;
|
||||
|
@ -914,13 +939,15 @@ do_connection()
|
|||
int plen, slen;
|
||||
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
|
||||
spoofing attacks. Note that this only works against somebody
|
||||
doing IP spoofing from a remote machine; any machine on the
|
||||
local network can still see outgoing packets and catch the
|
||||
random cookie. This only affects rhosts authentication, and
|
||||
this is one of the reasons why it is inherently insecure. */
|
||||
/*
|
||||
* 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
|
||||
* spoofing attacks. Note that this only works against somebody
|
||||
* doing IP spoofing from a remote machine; any machine on the local
|
||||
* network can still see outgoing packets and catch the random
|
||||
* cookie. This only affects rhosts authentication, and this is one
|
||||
* of the reasons why it is inherently insecure.
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
|
@ -928,9 +955,11 @@ do_connection()
|
|||
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
|
||||
prevent IP spoofing. */
|
||||
/*
|
||||
* Send our public key. We include in the packet 64 bits of random
|
||||
* data that must be matched in the reply in order to prevent IP
|
||||
* spoofing.
|
||||
*/
|
||||
packet_start(SSH_SMSG_PUBLIC_KEY);
|
||||
for (i = 0; i < 8; i++)
|
||||
packet_put_char(check_bytes[i]);
|
||||
|
@ -1002,14 +1031,15 @@ do_connection()
|
|||
session_key_int = BN_new();
|
||||
packet_get_bignum(session_key_int, &slen);
|
||||
|
||||
/* Get protocol flags. */
|
||||
protocol_flags = packet_get_int();
|
||||
packet_set_protocol_flags(protocol_flags);
|
||||
|
||||
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) {
|
||||
/* Private key has bigger modulus. */
|
||||
if (BN_num_bits(sensitive_data.private_key->n) <
|
||||
|
@ -1040,14 +1070,15 @@ do_connection()
|
|||
sensitive_data.private_key);
|
||||
}
|
||||
|
||||
/* Compute session id for this session. */
|
||||
compute_session_id(session_id, check_bytes,
|
||||
sensitive_data.host_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
|
||||
of the key is in the highest bits. */
|
||||
/*
|
||||
* Extract session key from the decrypted integer. The key is in the
|
||||
* 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);
|
||||
len = BN_num_bytes(session_key_int);
|
||||
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]))
|
||||
return 0;
|
||||
}
|
||||
/* Return false if AllowUsers isn't empty and user isn't listed
|
||||
there */
|
||||
/* Return false if AllowUsers isn't empty and user isn't listed there */
|
||||
if (options.num_allow_users > 0) {
|
||||
if (!pw->pw_name)
|
||||
return 0;
|
||||
|
@ -1151,8 +1181,10 @@ allowed_user(struct passwd * pw)
|
|||
if (match_pattern(grp->gr_name, options.deny_groups[i]))
|
||||
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 (!grp->gr_name)
|
||||
return 0;
|
||||
|
@ -1216,8 +1248,10 @@ do_authentication(char *user)
|
|||
}
|
||||
#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())
|
||||
packet_disconnect("Cannot change user when server not running as root.");
|
||||
|
||||
|
@ -1357,10 +1391,12 @@ do_authloop(struct passwd * pw)
|
|||
verbose("Rhosts authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/* Get client user name. Note that we just have
|
||||
to trust the client; this is one reason why
|
||||
rhosts authentication is insecure. (Another is
|
||||
IP-spoofing on a local network.) */
|
||||
/*
|
||||
* Get client user name. Note that we just have to
|
||||
* trust the client; this is one reason why rhosts
|
||||
* authentication is insecure. (Another is
|
||||
* IP-spoofing on a local network.)
|
||||
*/
|
||||
client_user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, 4 + ulen, type);
|
||||
|
||||
|
@ -1379,9 +1415,11 @@ do_authloop(struct passwd * pw)
|
|||
verbose("Rhosts with RSA authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/* Get client user name. Note that we just have
|
||||
to trust the client; root on the client machine
|
||||
can claim to be any user. */
|
||||
/*
|
||||
* Get client user name. Note that we just have to
|
||||
* trust the client; root on the client machine can
|
||||
* claim to be any user.
|
||||
*/
|
||||
client_user = packet_get_string(&ulen);
|
||||
|
||||
/* Get the client host key. */
|
||||
|
@ -1425,9 +1463,11 @@ do_authloop(struct passwd * pw)
|
|||
verbose("Password authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/* Read user password. It is in plain text, but
|
||||
was transmitted over the encrypted channel so
|
||||
it is not visible to an outside observer. */
|
||||
/*
|
||||
* Read user password. It is in plain text, but was
|
||||
* transmitted over the encrypted channel so it is
|
||||
* not visible to an outside observer.
|
||||
*/
|
||||
password = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
|
||||
|
@ -1463,8 +1503,7 @@ do_authloop(struct passwd * pw)
|
|||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||
}
|
||||
if (skeyinfo != NULL) {
|
||||
/* we send our s/key- in
|
||||
tis-challenge messages */
|
||||
/* we send our s/key- in tis-challenge messages */
|
||||
debug("sending challenge '%s'", skeyinfo);
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_string(skeyinfo, strlen(skeyinfo));
|
||||
|
@ -1493,8 +1532,10 @@ do_authloop(struct passwd * pw)
|
|||
#endif
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -1559,11 +1600,12 @@ do_fake_authloop(char *user)
|
|||
packet_send();
|
||||
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++) {
|
||||
/* Read a packet. This will not return if the client
|
||||
disconnects. */
|
||||
/* Read a packet. This will not return if the client disconnects. */
|
||||
int plen;
|
||||
int type = packet_read(&plen);
|
||||
#ifdef SKEY
|
||||
|
@ -1583,8 +1625,10 @@ do_fake_authloop(char *user)
|
|||
if (attempt > AUTH_FAIL_MAX)
|
||||
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_send();
|
||||
packet_write_wait();
|
||||
|
@ -1630,19 +1674,25 @@ do_authenticated(struct passwd * pw)
|
|||
mode_t tty_mode;
|
||||
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);
|
||||
|
||||
/* Inform the channel mechanism that we are the server side and
|
||||
that the client may request to connect to any port at all.
|
||||
(The user could do it anyway, and we wouldn\'t know what is
|
||||
permitted except by the client telling us, so we can equally
|
||||
well trust the client not to request anything bogus.) */
|
||||
/*
|
||||
* Inform the channel mechanism that we are the server side and that
|
||||
* the client may request to connect to any port at all. (The user
|
||||
* could do it anyway, and we wouldn\'t know what is permitted except
|
||||
* by the client telling us, so we can equally well trust the client
|
||||
* not to request anything bogus.)
|
||||
*/
|
||||
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) {
|
||||
int plen, dlen;
|
||||
|
||||
|
@ -1826,8 +1876,10 @@ do_authenticated(struct passwd * pw)
|
|||
return;
|
||||
|
||||
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);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1852,8 +1904,10 @@ fail:
|
|||
continue;
|
||||
|
||||
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);
|
||||
if (have_pty)
|
||||
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. */
|
||||
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)
|
||||
error("setsid failed: %.100s", strerror(errno));
|
||||
|
||||
#ifdef USE_PIPES
|
||||
/* Redirect stdin. We close the parent side of the socket
|
||||
pair, and make the child side the standard input. */
|
||||
/*
|
||||
* Redirect stdin. We close the parent side of the socket
|
||||
* pair, and make the child side the standard input.
|
||||
*/
|
||||
close(pin[1]);
|
||||
if (dup2(pin[0], 0) < 0)
|
||||
perror("dup2 stdin");
|
||||
|
@ -1922,9 +1980,11 @@ do_exec_no_pty(const char *command, struct passwd * pw,
|
|||
perror("dup2 stderr");
|
||||
close(perr[1]);
|
||||
#else /* USE_PIPES */
|
||||
/* Redirect stdin, stdout, and stderr. Stdin and stdout
|
||||
will use the same socket, as some programs
|
||||
(particularly rdist) seem to depend on it. */
|
||||
/*
|
||||
* Redirect stdin, stdout, and stderr. Stdin and stdout will
|
||||
* use the same socket, as some programs (particularly rdist)
|
||||
* seem to depend on it.
|
||||
*/
|
||||
close(inout[1]);
|
||||
close(err[1]);
|
||||
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(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 has closed inout[1] and err[1]. */
|
||||
#endif /* USE_PIPES */
|
||||
|
@ -2012,8 +2074,10 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||
/* Get remote host name. */
|
||||
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) {
|
||||
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
|
||||
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(ttyfd);
|
||||
|
||||
/* Get IP address of client. This is needed because we
|
||||
want to record where the user logged in from. If the
|
||||
connection is not a socket, let the ip address be 0.0.0.0. */
|
||||
/*
|
||||
* Get IP address of client. This is needed because we want
|
||||
* 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));
|
||||
if (packet_get_connection_in() == packet_get_connection_out()) {
|
||||
fromlen = sizeof(from);
|
||||
|
@ -2075,12 +2141,14 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||
fprintf(stderr, pamconv_msg);
|
||||
#endif
|
||||
|
||||
/* If the user has logged in before, display the time of
|
||||
last login. However, don't display anything extra if a
|
||||
command has been specified (so that ssh can be used to
|
||||
execute commands on a remote machine without users
|
||||
knowing they are going to another machine). Login(1)
|
||||
will do this for us as well, so check if login(1) is used */
|
||||
/*
|
||||
* If the user has logged in before, display the time of last
|
||||
* login. However, don't display anything extra if a command
|
||||
* has been specified (so that ssh can be used to execute
|
||||
* commands on a remote machine without users knowing they
|
||||
* 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 &&
|
||||
!options.use_login) {
|
||||
/* Convert the date to a string. */
|
||||
|
@ -2095,10 +2163,12 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
|
|||
else
|
||||
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)
|
||||
will be used. Note that some machines appear to print
|
||||
it in /etc/profile or similar. */
|
||||
/*
|
||||
* Print /etc/motd unless a command was specified or printing
|
||||
* it was disabled in server options or login(1) will be
|
||||
* used. Note that some machines appear to print it in
|
||||
* /etc/profile or similar.
|
||||
*/
|
||||
if (command == NULL && options.print_motd && !quiet_login &&
|
||||
!options.use_login) {
|
||||
/* 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. */
|
||||
close(ttyfd);
|
||||
|
||||
/* Create another descriptor of the pty master side for use as the
|
||||
standard input. We could use the original descriptor, but this
|
||||
simplifies code in server_loop. The descriptor is bidirectional. */
|
||||
/*
|
||||
* Create another descriptor of the pty master side for use as the
|
||||
* standard input. We could use the original descriptor, but this
|
||||
* simplifies code in server_loop. The descriptor is bidirectional.
|
||||
*/
|
||||
fdout = dup(ptyfd);
|
||||
if (fdout < 0)
|
||||
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.ttyname = ttyname;
|
||||
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. */
|
||||
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
|
||||
pty while we're still cleaning up. */
|
||||
/*
|
||||
* Close the server side of the socket pairs. We must do this after
|
||||
* the pty cleanup, so that another process doesn't get this pty
|
||||
* while we're still cleaning up.
|
||||
*/
|
||||
close(ptyfd);
|
||||
close(fdout);
|
||||
}
|
||||
|
@ -2162,19 +2238,21 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name,
|
|||
unsigned int i, namelen;
|
||||
char **env;
|
||||
|
||||
/* Find the slot where the value should be stored. If the
|
||||
variable already exists, we reuse the slot; otherwise we append
|
||||
a new slot at the end of the array, expanding if necessary. */
|
||||
/*
|
||||
* Find the slot where the value should be stored. If the variable
|
||||
* already exists, we reuse the slot; otherwise we append a new slot
|
||||
* at the end of the array, expanding if necessary.
|
||||
*/
|
||||
env = *envp;
|
||||
namelen = strlen(name);
|
||||
for (i = 0; env[i]; i++)
|
||||
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
|
||||
break;
|
||||
if (env[i]) {
|
||||
/* Name already exists. Reuse the slot. */
|
||||
/* Reuse the slot. */
|
||||
xfree(env[i]);
|
||||
} else {
|
||||
/* New variable. Expand the array if necessary. */
|
||||
/* New variable. Expand if necessary. */
|
||||
if (i >= (*envsizep) - 1) {
|
||||
(*envsizep) += 50;
|
||||
env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
|
||||
|
@ -2202,40 +2280,27 @@ read_environment_file(char ***env, unsigned int *envsize,
|
|||
char buf[4096];
|
||||
char *cp, *value;
|
||||
|
||||
/* Open the environment file. */
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
/* Process each line. */
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++);
|
||||
|
||||
/* Ignore empty and comment lines. */
|
||||
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '#' || *cp == '\n')
|
||||
continue;
|
||||
|
||||
/* Remove newline. */
|
||||
if (strchr(cp, '\n'))
|
||||
*strchr(cp, '\n') = '\0';
|
||||
|
||||
/* Find the equals sign. Its lack indicates badly
|
||||
formatted line. */
|
||||
value = strchr(cp, '=');
|
||||
if (value == NULL) {
|
||||
fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
|
||||
continue;
|
||||
}
|
||||
/* Replace the equals sign by nul, and advance value to
|
||||
the value string. */
|
||||
/* Replace the equals sign by nul, and advance value to the value string. */
|
||||
*value = '\0';
|
||||
value++;
|
||||
|
||||
/* Set the value in environment. */
|
||||
child_set_env(env, envsize, cp, value);
|
||||
}
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
#ifdef AFS
|
||||
|
@ -2315,8 +2382,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||
}
|
||||
#endif /* AFS */
|
||||
|
||||
/* Initialize the environment. In the first part we allocate
|
||||
space for all environment variables. */
|
||||
/* Initialize the environment. */
|
||||
envsize = 100;
|
||||
env = xmalloc(envsize * sizeof(char *));
|
||||
env[0] = NULL;
|
||||
|
@ -2335,7 +2401,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||
/* Normal systems set SHELL by default. */
|
||||
child_set_env(&env, &envsize, "SHELL", shell);
|
||||
}
|
||||
/* Let it inherit timezone if we have one. */
|
||||
if (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);
|
||||
}
|
||||
|
||||
/* Set SSH_CLIENT. */
|
||||
snprintf(buf, sizeof buf, "%.50s %d %d",
|
||||
get_remote_ipaddr(), get_remote_port(), options.port);
|
||||
child_set_env(&env, &envsize, "SSH_CLIENT", buf);
|
||||
|
||||
/* Set SSH_TTY if we have a pty. */
|
||||
if (ttyname)
|
||||
child_set_env(&env, &envsize, "SSH_TTY", ttyname);
|
||||
|
||||
/* Set TERM if we have a pty. */
|
||||
if (term)
|
||||
child_set_env(&env, &envsize, "TERM", term);
|
||||
|
||||
/* Set DISPLAY if we have one. */
|
||||
if (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 */
|
||||
|
||||
/* Set XAUTHORITY to always be a local file. */
|
||||
if (xauthfile)
|
||||
child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
|
||||
|
||||
/* Set variable for forwarded authentication connection, if we
|
||||
have one. */
|
||||
if (auth_get_socket_name() != NULL)
|
||||
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
|
||||
auth_get_socket_name());
|
||||
|
||||
/* Read $HOME/.ssh/environment. */
|
||||
/* read $HOME/.ssh/environment. */
|
||||
if (!options.use_login) {
|
||||
snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
|
||||
read_environment_file(&env, &envsize, buf);
|
||||
}
|
||||
/* If debugging, dump the environment to stderr. */
|
||||
if (debug_flag) {
|
||||
/* dump the environment */
|
||||
fprintf(stderr, "Environment:\n");
|
||||
for (i = 0; env[i]; 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
|
||||
important that we do not shutdown it. Note that the
|
||||
descriptors cannot be closed before building the environment,
|
||||
as we call get_remote_ipaddr there. */
|
||||
/*
|
||||
* Close the connection descriptors; note that this is the child, and
|
||||
* the server will still have the socket open, and it is important
|
||||
* that we do not shutdown it. Note that the descriptors cannot be
|
||||
* closed before building the environment, as we call
|
||||
* get_remote_ipaddr there.
|
||||
*/
|
||||
if (packet_get_connection_in() == packet_get_connection_out())
|
||||
close(packet_get_connection_in());
|
||||
else {
|
||||
close(packet_get_connection_in());
|
||||
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();
|
||||
|
||||
/* Close any extra file descriptors. Note that there may still be
|
||||
descriptors left by system functions. They will be closed
|
||||
later. */
|
||||
/*
|
||||
* Close any extra file descriptors. Note that there may still be
|
||||
* descriptors left by system functions. They will be closed later.
|
||||
*/
|
||||
endpwent();
|
||||
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
|
||||
after initgroups, because at least on Solaris 2.3 it leaves
|
||||
file descriptors open. */
|
||||
/*
|
||||
* Close any extra open file descriptors so that we don\'t have them
|
||||
* hanging around in clients. Note that we want to do this after
|
||||
* initgroups, because at least on Solaris 2.3 it leaves file
|
||||
* descriptors open.
|
||||
*/
|
||||
for (i = 3; i < 64; 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",
|
||||
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;
|
||||
|
||||
/* 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 (stat(SSH_USER_RC, &st) >= 0) {
|
||||
if (debug_flag)
|
||||
|
@ -2486,8 +2554,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||
}
|
||||
#ifdef XAUTH_PATH
|
||||
else {
|
||||
/* Add authority data to .Xauthority if
|
||||
appropriate. */
|
||||
/* Add authority data to .Xauthority if appropriate. */
|
||||
if (auth_proto != NULL && auth_data != NULL) {
|
||||
if (debug_flag)
|
||||
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
|
||||
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
|
||||
indicate that this is a login 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 indicate that
|
||||
* this is a login shell.
|
||||
*/
|
||||
if (!command) {
|
||||
if (!options.use_login) {
|
||||
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) {
|
||||
char *mailbox;
|
||||
struct stat mailstat;
|
||||
|
@ -2558,8 +2629,10 @@ do_child(const char *command, struct passwd * pw, const char *term,
|
|||
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[1] = "-c";
|
||||
argv[2] = (char *) command;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
|
@ -38,7 +38,7 @@ tilde_expand_filename(const char *filename, uid_t my_uid)
|
|||
else
|
||||
userlen = strlen(filename); /* Nothing after username. */
|
||||
if (userlen == 0)
|
||||
pw = getpwuid(my_uid); /* Own home directory. */
|
||||
pw = getpwuid(my_uid); /* Own home directory. */
|
||||
else {
|
||||
/* Tilde refers to someone elses home directory. */
|
||||
if (userlen > sizeof(user) - 1)
|
||||
|
@ -47,12 +47,12 @@ tilde_expand_filename(const char *filename, uid_t my_uid)
|
|||
user[userlen] = 0;
|
||||
pw = getpwnam(user);
|
||||
}
|
||||
/* Check that we found the user. */
|
||||
if (!pw)
|
||||
fatal("Unknown user %100s.", user);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
/* Build a path combining the specified directory and path. */
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
|
@ -209,7 +209,6 @@ tty_make_modes(int fd)
|
|||
struct termios tio;
|
||||
int baud;
|
||||
|
||||
/* Get the modes. */
|
||||
if (tcgetattr(fd, &tio) < 0) {
|
||||
packet_put_char(TTY_OP_END);
|
||||
log("tcgetattr: %.100s", strerror(errno));
|
||||
|
|
139
ttymodes.h
139
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
|
||||
* opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
|
||||
|
@ -29,112 +29,113 @@
|
|||
|
||||
/*
|
||||
* 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 */
|
||||
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
||||
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
||||
TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3)
|
||||
TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1)
|
||||
TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2)
|
||||
TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3)
|
||||
#if defined(VKILL)
|
||||
TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4)
|
||||
#endif /* VKILL */
|
||||
TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5)
|
||||
TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4)
|
||||
#endif /* VKILL */
|
||||
TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5)
|
||||
#if defined(VEOL)
|
||||
TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6)
|
||||
#endif /* VEOL */
|
||||
TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6)
|
||||
#endif /* VEOL */
|
||||
#ifdef VEOL2 /* n/a */
|
||||
TTYCHAR(VEOL2, 7)
|
||||
#endif /* VEOL2 */
|
||||
TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8)
|
||||
TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9)
|
||||
#endif /* VEOL2 */
|
||||
TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8)
|
||||
TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9)
|
||||
#if defined(VSUSP)
|
||||
TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10)
|
||||
#endif /* VSUSP */
|
||||
TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10)
|
||||
#endif /* VSUSP */
|
||||
#if defined(VDSUSP)
|
||||
TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11)
|
||||
#endif /* VDSUSP */
|
||||
TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11)
|
||||
#endif /* VDSUSP */
|
||||
#if defined(VREPRINT)
|
||||
TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12)
|
||||
#endif /* VREPRINT */
|
||||
TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12)
|
||||
#endif /* VREPRINT */
|
||||
#if defined(VWERASE)
|
||||
TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13)
|
||||
#endif /* VWERASE */
|
||||
TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13)
|
||||
#endif /* VWERASE */
|
||||
#if defined(VLNEXT)
|
||||
TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14)
|
||||
#endif /* VLNEXT */
|
||||
TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14)
|
||||
#endif /* VLNEXT */
|
||||
#if defined(VFLUSH)
|
||||
TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15)
|
||||
#endif /* VFLUSH */
|
||||
TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15)
|
||||
#endif /* VFLUSH */
|
||||
#ifdef VSWTCH
|
||||
TTYCHAR(VSWTCH, 16) /* n/a */
|
||||
#endif /* VSWTCH */
|
||||
#endif /* VSWTCH */
|
||||
#if defined(VSTATUS)
|
||||
TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17)
|
||||
#endif /* VSTATUS */
|
||||
TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17)
|
||||
#endif /* VSTATUS */
|
||||
#ifdef VDISCARD
|
||||
TTYCHAR(VDISCARD, 18) /* n/a */
|
||||
#endif /* VDISCARD */
|
||||
#endif /* VDISCARD */
|
||||
|
||||
/* name, field, op */
|
||||
TTYMODE(IGNPAR, c_iflag, 30) /* n/a */
|
||||
TTYMODE(PARMRK, c_iflag, 31) /* n/a */
|
||||
TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32)
|
||||
TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33)
|
||||
TTYMODE(INLCR, c_iflag, 34) /* n/a */
|
||||
TTYMODE(IGNCR, c_iflag, 35) /* n/a */
|
||||
TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36)
|
||||
TTYMODE(IGNPAR, c_iflag, 30) /* n/a */
|
||||
TTYMODE(PARMRK, c_iflag, 31) /* n/a */
|
||||
TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32)
|
||||
TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33)
|
||||
TTYMODE(INLCR, c_iflag, 34) /* n/a */
|
||||
TTYMODE(IGNCR, c_iflag, 35) /* n/a */
|
||||
TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36)
|
||||
#if defined(IUCLC)
|
||||
TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37)
|
||||
TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37)
|
||||
#endif
|
||||
TTYMODE(IXON, c_iflag, 38) /* n/a */
|
||||
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
||||
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
||||
TTYMODE(IXON, c_iflag, 38) /* n/a */
|
||||
TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39)
|
||||
TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40)
|
||||
#ifdef IMAXBEL
|
||||
TTYMODE(IMAXBEL, c_iflag, 41) /* n/a */
|
||||
#endif /* IMAXBEL */
|
||||
TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */
|
||||
#endif /* IMAXBEL */
|
||||
|
||||
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
||||
TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51)
|
||||
TTYMODE(ISIG, c_lflag, 50) /* n/a */
|
||||
TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51)
|
||||
#ifdef XCASE
|
||||
TTYMODE(XCASE, c_lflag, 52) /* n/a */
|
||||
TTYMODE(XCASE, c_lflag, 52) /* n/a */
|
||||
#endif
|
||||
TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53)
|
||||
TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54)
|
||||
TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55)
|
||||
TTYMODE(ECHONL, c_lflag, 56) /* n/a */
|
||||
TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57)
|
||||
TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
|
||||
TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53)
|
||||
TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54)
|
||||
TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55)
|
||||
TTYMODE(ECHONL, c_lflag, 56) /* n/a */
|
||||
TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57)
|
||||
TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58)
|
||||
#ifdef IEXTEN
|
||||
TTYMODE(IEXTEN, c_lflag, 59) /* n/a */
|
||||
#endif /* IEXTEN */
|
||||
#endif /* IEXTEN */
|
||||
#if defined(ECHOCTL)
|
||||
TTYMODE(ECHOCTL, c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
||||
#endif /* ECHOCTL */
|
||||
TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60)
|
||||
#endif /* ECHOCTL */
|
||||
#ifdef ECHOKE
|
||||
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
||||
#endif /* ECHOKE */
|
||||
TTYMODE(ECHOKE, c_lflag, 61) /* n/a */
|
||||
#endif /* ECHOKE */
|
||||
#if defined(PENDIN)
|
||||
TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62)
|
||||
#endif /* PENDIN */
|
||||
TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62)
|
||||
#endif /* PENDIN */
|
||||
|
||||
TTYMODE(OPOST, c_oflag, 70) /* n/a */
|
||||
TTYMODE(OPOST, c_oflag, 70) /* n/a */
|
||||
#if defined(OLCUC)
|
||||
TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71)
|
||||
TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71)
|
||||
#endif
|
||||
TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72)
|
||||
TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72)
|
||||
#ifdef OCRNL
|
||||
TTYMODE(OCRNL, c_oflag, 73) /* n/a */
|
||||
TTYMODE(OCRNL, c_oflag, 73) /* n/a */
|
||||
#endif
|
||||
#ifdef ONOCR
|
||||
TTYMODE(ONOCR, c_oflag, 74) /* n/a */
|
||||
TTYMODE(ONOCR, c_oflag, 74) /* n/a */
|
||||
#endif
|
||||
#ifdef ONLRET
|
||||
TTYMODE(ONLRET, c_oflag, 75) /* n/a */
|
||||
TTYMODE(ONLRET, c_oflag, 75) /* n/a */
|
||||
#endif
|
||||
|
||||
TTYMODE(CS7, c_cflag, 90) /* n/a */
|
||||
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
||||
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
||||
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
||||
TTYMODE(CS7, c_cflag, 90) /* n/a */
|
||||
TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91)
|
||||
TTYMODE(PARENB, c_cflag, 92) /* n/a */
|
||||
TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93)
|
||||
|
||||
|
|
11
uidswap.c
11
uidswap.c
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
#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 "uidswap.h"
|
||||
|
@ -66,10 +66,11 @@ restore_uid()
|
|||
if (seteuid(saved_euid) < 0)
|
||||
debug("seteuid %d: %.100s", (int) saved_euid, strerror(errno));
|
||||
#else /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
/* We are unable to restore the real uid to its unprivileged
|
||||
value. */
|
||||
/* Propagate the real uid (usually more privileged) to effective
|
||||
uid as well. */
|
||||
/*
|
||||
* We are unable to restore the real uid to its unprivileged value.
|
||||
* Propagate the real uid (usually more privileged) to effective uid
|
||||
* as well.
|
||||
*/
|
||||
setuid(getuid());
|
||||
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче