This commit was generated by cvs2svn to compensate for changes in r60573,
which included commits to RCS files with non-trunk default branches.
This commit is contained in:
commit
fe01acb846
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=60574
44
crypto/openssh/README.openssh2
Normal file
44
crypto/openssh/README.openssh2
Normal file
@ -0,0 +1,44 @@
|
||||
$Id: README.openssh2,v 1.8 2000/05/07 18:30:03 markus Exp $
|
||||
|
||||
howto:
|
||||
1) generate server key:
|
||||
$ ssh-keygen -d -f /etc/ssh_host_dsa_key -N ''
|
||||
2) enable ssh2:
|
||||
server: add 'Protocol 2,1' to /etc/sshd_config
|
||||
client: ssh -o 'Protocol 2,1', or add to .ssh/config
|
||||
3) DSA authentication similar to RSA (add keys to ~/.ssh/authorized_keys2)
|
||||
interop w/ ssh.com dsa-keys:
|
||||
ssh-keygen -f /key/from/ssh.com -X >> ~/.ssh/authorized_keys2
|
||||
and vice versa
|
||||
ssh-keygen -f /privatekey/from/openssh -x > ~/.ssh2/mykey.pub
|
||||
echo Key mykey.pub >> ~/.ssh2/authorization
|
||||
|
||||
works:
|
||||
secsh-transport: works w/o rekey
|
||||
proposal exchange, i.e. different enc/mac/comp per direction
|
||||
encryption: blowfish-cbc, 3des-cbc, arcfour, cast128-cbc
|
||||
mac: hmac-md5, hmac-sha1, (hmac-ripemd160)
|
||||
compression: zlib, none
|
||||
secsh-userauth: passwd and pubkey with DSA
|
||||
secsh-connection: pty+shell or command, flow control works (window adjust)
|
||||
tcp-forwarding: -L works, -R incomplete
|
||||
x11-fwd
|
||||
dss/dsa: host key database in ~/.ssh/known_hosts2
|
||||
client interops w/ sshd2, lshd
|
||||
server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT, F-Secure SSH Client 4.0, SecureFX (secure ftp)
|
||||
server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
|
||||
todo:
|
||||
re-keying
|
||||
secsh-connection features:
|
||||
tcp-forwarding, agent-fwd
|
||||
auth other than passwd, and DSA-pubkey:
|
||||
keyboard-interactive, (PGP-pubkey?)
|
||||
config
|
||||
server-auth w/ old host-keys
|
||||
cleanup
|
||||
advanced key storage?
|
||||
keynote
|
||||
sftp
|
||||
|
||||
-markus
|
||||
$Date: 2000/05/07 18:30:03 $
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* auth-rhosts.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Fri Mar 17 05:12:18 1995 ylo
|
||||
*
|
||||
*
|
||||
* Rhosts authentication. This file contains code to check whether to admit
|
||||
* the login based on rhosts authentication. This file also processes
|
||||
* /etc/hosts.equiv.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rhosts.c,v 1.12 1999/12/27 10:46:11 markus Exp $");
|
||||
RCSID("$Id: auth-rhosts.c,v 1.13 2000/04/14 10:30:29 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
@ -30,7 +30,7 @@ RCSID("$Id: auth-rhosts.c,v 1.12 1999/12/27 10:46:11 markus Exp $");
|
||||
* based on the file, and returns zero otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
check_rhosts_file(const char *filename, const char *hostname,
|
||||
const char *ipaddr, const char *client_user,
|
||||
const char *server_user)
|
||||
@ -146,7 +146,7 @@ check_rhosts_file(const char *filename, const char *hostname,
|
||||
* /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
auth_rhosts(struct passwd *pw, const char *client_user)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-skey.c,v 1.5 1999/12/06 19:04:57 deraadt Exp $");
|
||||
RCSID("$Id: auth-skey.c,v 1.6 2000/04/14 10:30:29 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include <sha1.h>
|
||||
|
||||
/*
|
||||
/*
|
||||
* try skey authentication,
|
||||
* return 1 on success, 0 on failure, -1 if skey is not available
|
||||
* return 1 on success, 0 on failure, -1 if skey is not available
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
auth_skey_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
if (strncasecmp(password, "s/key", 5) == 0) {
|
||||
@ -43,18 +43,18 @@ auth_skey_password(struct passwd * pw, const char *password)
|
||||
*/
|
||||
static u_int32_t
|
||||
hash_collapse(s)
|
||||
u_char *s;
|
||||
u_char *s;
|
||||
{
|
||||
int len, target;
|
||||
int len, target;
|
||||
u_int32_t i;
|
||||
|
||||
if ((strlen(s) % sizeof(u_int32_t)) == 0)
|
||||
target = strlen(s); /* Multiple of 4 */
|
||||
target = strlen(s); /* Multiple of 4 */
|
||||
else
|
||||
target = strlen(s) - (strlen(s) % sizeof(u_int32_t));
|
||||
|
||||
|
||||
for (i = 0, len = 0; len < target; len += 4)
|
||||
i ^= ROUND(s + len);
|
||||
i ^= ROUND(s + len);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
111
crypto/openssh/auth.c
Normal file
111
crypto/openssh/auth.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth.c,v 1.6 2000/04/26 21:28:31 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "match.h"
|
||||
|
||||
#include "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern char *forced_command;
|
||||
|
||||
/*
|
||||
* Check if the user is allowed to log in via ssh. If user is listed in
|
||||
* DenyUsers or user's primary group is listed in DenyGroups, false will
|
||||
* be returned. If AllowUsers isn't empty and user isn't listed there, or
|
||||
* if AllowGroups isn't empty and user isn't listed there, false will be
|
||||
* returned.
|
||||
* If the user's shell is not executable, false will be returned.
|
||||
* Otherwise true is returned.
|
||||
*/
|
||||
int
|
||||
allowed_user(struct passwd * pw)
|
||||
{
|
||||
struct stat st;
|
||||
struct group *grp;
|
||||
int i;
|
||||
|
||||
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
|
||||
if (!pw)
|
||||
return 0;
|
||||
|
||||
/* deny if shell does not exists or is not executable */
|
||||
if (stat(pw->pw_shell, &st) != 0)
|
||||
return 0;
|
||||
if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
|
||||
return 0;
|
||||
|
||||
/* Return false if user is listed in DenyUsers */
|
||||
if (options.num_deny_users > 0) {
|
||||
if (!pw->pw_name)
|
||||
return 0;
|
||||
for (i = 0; i < options.num_deny_users; i++)
|
||||
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 */
|
||||
if (options.num_allow_users > 0) {
|
||||
if (!pw->pw_name)
|
||||
return 0;
|
||||
for (i = 0; i < options.num_allow_users; i++)
|
||||
if (match_pattern(pw->pw_name, options.allow_users[i]))
|
||||
break;
|
||||
/* i < options.num_allow_users iff we break for loop */
|
||||
if (i >= options.num_allow_users)
|
||||
return 0;
|
||||
}
|
||||
/* Get the primary group name if we need it. Return false if it fails */
|
||||
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
|
||||
grp = getgrgid(pw->pw_gid);
|
||||
if (!grp)
|
||||
return 0;
|
||||
|
||||
/* Return false if user's group is listed in DenyGroups */
|
||||
if (options.num_deny_groups > 0) {
|
||||
if (!grp->gr_name)
|
||||
return 0;
|
||||
for (i = 0; i < options.num_deny_groups; i++)
|
||||
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
|
||||
*/
|
||||
if (options.num_allow_groups > 0) {
|
||||
if (!grp->gr_name)
|
||||
return 0;
|
||||
for (i = 0; i < options.num_allow_groups; i++)
|
||||
if (match_pattern(grp->gr_name, options.allow_groups[i]))
|
||||
break;
|
||||
/* i < options.num_allow_groups iff we break for
|
||||
loop */
|
||||
if (i >= options.num_allow_groups)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* We found no reason not to let this user try to log on... */
|
||||
return 1;
|
||||
}
|
17
crypto/openssh/auth.h
Normal file
17
crypto/openssh/auth.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef AUTH_H
|
||||
#define AUTH_H
|
||||
|
||||
void do_authentication(void);
|
||||
void do_authentication2(void);
|
||||
|
||||
struct passwd *
|
||||
auth_get_user(void);
|
||||
|
||||
int allowed_user(struct passwd * pw);;
|
||||
|
||||
#define AUTH_FAIL_MAX 6
|
||||
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
|
||||
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
|
||||
|
||||
#endif
|
||||
|
468
crypto/openssh/auth1.c
Normal file
468
crypto/openssh/auth1.c
Normal file
@ -0,0 +1,468 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth1.c,v 1.2 2000/04/29 18:11:52 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "mpaux.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern char *forced_command;
|
||||
|
||||
/*
|
||||
* convert ssh auth msg type into description
|
||||
*/
|
||||
char *
|
||||
get_authname(int type)
|
||||
{
|
||||
static char buf[1024];
|
||||
switch (type) {
|
||||
case SSH_CMSG_AUTH_PASSWORD:
|
||||
return "password";
|
||||
case SSH_CMSG_AUTH_RSA:
|
||||
return "rsa";
|
||||
case SSH_CMSG_AUTH_RHOSTS_RSA:
|
||||
return "rhosts-rsa";
|
||||
case SSH_CMSG_AUTH_RHOSTS:
|
||||
return "rhosts";
|
||||
#ifdef KRB4
|
||||
case SSH_CMSG_AUTH_KERBEROS:
|
||||
return "kerberos";
|
||||
#endif
|
||||
#ifdef SKEY
|
||||
case SSH_CMSG_AUTH_TIS_RESPONSE:
|
||||
return "s/key";
|
||||
#endif
|
||||
}
|
||||
snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* The user does not exist or access is denied,
|
||||
* but fake indication that authentication is needed.
|
||||
*/
|
||||
void
|
||||
do_fake_authloop1(char *user)
|
||||
{
|
||||
int attempt = 0;
|
||||
|
||||
log("Faking authloop for illegal user %.200s from %.200s port %d",
|
||||
user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
|
||||
/* Indicate that authentication is needed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
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.
|
||||
*/
|
||||
for (attempt = 1;; attempt++) {
|
||||
/* Read a packet. This will not return if the client disconnects. */
|
||||
int plen;
|
||||
int type = packet_read(&plen);
|
||||
#ifdef SKEY
|
||||
unsigned int dlen;
|
||||
char *password, *skeyinfo;
|
||||
password = NULL;
|
||||
/* Try to send a fake s/key challenge. */
|
||||
if (options.skey_authentication == 1 &&
|
||||
(skeyinfo = skey_fake_keyinfo(user)) != NULL) {
|
||||
if (type == SSH_CMSG_AUTH_TIS) {
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_string(skeyinfo, strlen(skeyinfo));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
} else if (type == SSH_CMSG_AUTH_PASSWORD &&
|
||||
options.password_authentication &&
|
||||
(password = packet_get_string(&dlen)) != NULL &&
|
||||
dlen == 5 &&
|
||||
strncasecmp(password, "s/key", 5) == 0 ) {
|
||||
packet_send_debug(skeyinfo);
|
||||
}
|
||||
}
|
||||
if (password != NULL)
|
||||
xfree(password);
|
||||
#endif
|
||||
if (attempt > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, user);
|
||||
|
||||
/*
|
||||
* Send failure. This should be indistinguishable from a
|
||||
* failed authentication.
|
||||
*/
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* read packets and try to authenticate local user *pw.
|
||||
* return if authentication is successfull
|
||||
*/
|
||||
void
|
||||
do_authloop(struct passwd * pw)
|
||||
{
|
||||
int attempt = 0;
|
||||
unsigned int bits;
|
||||
RSA *client_host_key;
|
||||
BIGNUM *n;
|
||||
char *client_user, *password;
|
||||
char user[1024];
|
||||
unsigned int dlen;
|
||||
int plen, nlen, elen;
|
||||
unsigned int ulen;
|
||||
int type = 0;
|
||||
void (*authlog) (const char *fmt,...) = verbose;
|
||||
|
||||
/* Indicate that authentication is needed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
for (attempt = 1;; attempt++) {
|
||||
int authenticated = 0;
|
||||
strlcpy(user, "", sizeof user);
|
||||
|
||||
/* Get a packet from the client. */
|
||||
type = packet_read(&plen);
|
||||
|
||||
/* Process the packet. */
|
||||
switch (type) {
|
||||
#ifdef AFS
|
||||
case SSH_CMSG_HAVE_KERBEROS_TGT:
|
||||
if (!options.kerberos_tgt_passing) {
|
||||
/* packet_get_all(); */
|
||||
verbose("Kerberos tgt passing disabled.");
|
||||
break;
|
||||
} else {
|
||||
/* Accept Kerberos tgt. */
|
||||
char *tgt = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
if (!auth_kerberos_tgt(pw, tgt))
|
||||
verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
|
||||
xfree(tgt);
|
||||
}
|
||||
continue;
|
||||
|
||||
case SSH_CMSG_HAVE_AFS_TOKEN:
|
||||
if (!options.afs_token_passing || !k_hasafs()) {
|
||||
/* packet_get_all(); */
|
||||
verbose("AFS token passing disabled.");
|
||||
break;
|
||||
} else {
|
||||
/* Accept AFS token. */
|
||||
char *token_string = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
if (!auth_afs_token(pw, token_string))
|
||||
verbose("AFS token REFUSED for %s", pw->pw_name);
|
||||
xfree(token_string);
|
||||
}
|
||||
continue;
|
||||
#endif /* AFS */
|
||||
#ifdef KRB4
|
||||
case SSH_CMSG_AUTH_KERBEROS:
|
||||
if (!options.kerberos_authentication) {
|
||||
/* packet_get_all(); */
|
||||
verbose("Kerberos authentication disabled.");
|
||||
break;
|
||||
} else {
|
||||
/* Try Kerberos v4 authentication. */
|
||||
KTEXT_ST auth;
|
||||
char *tkt_user = NULL;
|
||||
char *kdata = packet_get_string((unsigned int *) &auth.length);
|
||||
packet_integrity_check(plen, 4 + auth.length, type);
|
||||
|
||||
if (auth.length < MAX_KTXT_LEN)
|
||||
memcpy(auth.dat, kdata, auth.length);
|
||||
xfree(kdata);
|
||||
|
||||
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
|
||||
|
||||
if (authenticated) {
|
||||
snprintf(user, sizeof user, " tktuser %s", tkt_user);
|
||||
xfree(tkt_user);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* KRB4 */
|
||||
|
||||
case SSH_CMSG_AUTH_RHOSTS:
|
||||
if (!options.rhosts_authentication) {
|
||||
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.)
|
||||
*/
|
||||
client_user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, 4 + ulen, type);
|
||||
|
||||
/* Try to authenticate using /etc/hosts.equiv and
|
||||
.rhosts. */
|
||||
authenticated = auth_rhosts(pw, client_user);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
xfree(client_user);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_RHOSTS_RSA:
|
||||
if (!options.rhosts_rsa_authentication) {
|
||||
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.
|
||||
*/
|
||||
client_user = packet_get_string(&ulen);
|
||||
|
||||
/* Get the client host key. */
|
||||
client_host_key = RSA_new();
|
||||
if (client_host_key == NULL)
|
||||
fatal("RSA_new failed");
|
||||
client_host_key->e = BN_new();
|
||||
client_host_key->n = BN_new();
|
||||
if (client_host_key->e == NULL || client_host_key->n == NULL)
|
||||
fatal("BN_new failed");
|
||||
bits = packet_get_int();
|
||||
packet_get_bignum(client_host_key->e, &elen);
|
||||
packet_get_bignum(client_host_key->n, &nlen);
|
||||
|
||||
if (bits != BN_num_bits(client_host_key->n))
|
||||
log("Warning: keysize mismatch for client_host_key: "
|
||||
"actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
|
||||
packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
|
||||
|
||||
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
|
||||
RSA_free(client_host_key);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
xfree(client_user);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_RSA:
|
||||
if (!options.rsa_authentication) {
|
||||
verbose("RSA authentication disabled.");
|
||||
break;
|
||||
}
|
||||
/* RSA authentication requested. */
|
||||
n = BN_new();
|
||||
packet_get_bignum(n, &nlen);
|
||||
packet_integrity_check(plen, nlen, type);
|
||||
authenticated = auth_rsa(pw, n);
|
||||
BN_clear_free(n);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_PASSWORD:
|
||||
if (!options.password_authentication) {
|
||||
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.
|
||||
*/
|
||||
password = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
|
||||
/* Try authentication with the password. */
|
||||
authenticated = auth_password(pw, password);
|
||||
|
||||
memset(password, 0, strlen(password));
|
||||
xfree(password);
|
||||
break;
|
||||
|
||||
#ifdef SKEY
|
||||
case SSH_CMSG_AUTH_TIS:
|
||||
debug("rcvd SSH_CMSG_AUTH_TIS");
|
||||
if (options.skey_authentication == 1) {
|
||||
char *skeyinfo = skey_keyinfo(pw->pw_name);
|
||||
if (skeyinfo == NULL) {
|
||||
debug("generating fake skeyinfo for %.100s.", pw->pw_name);
|
||||
skeyinfo = skey_fake_keyinfo(pw->pw_name);
|
||||
}
|
||||
if (skeyinfo != NULL) {
|
||||
/* 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));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_CMSG_AUTH_TIS_RESPONSE:
|
||||
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
|
||||
if (options.skey_authentication == 1) {
|
||||
char *response = packet_get_string(&dlen);
|
||||
debug("skey response == '%s'", response);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
authenticated = (skey_haskey(pw->pw_name) == 0 &&
|
||||
skey_passcheck(pw->pw_name, response) != -1);
|
||||
xfree(response);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case SSH_CMSG_AUTH_TIS:
|
||||
/* TIS Authentication is unsupported */
|
||||
log("TIS authentication unsupported.");
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/*
|
||||
* Any unknown messages will be ignored (and failure
|
||||
* returned) during authentication.
|
||||
*/
|
||||
log("Unknown message during authentication: type %d", type);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the user is logging in as root and root logins
|
||||
* are disallowed.
|
||||
* Note that root login is allowed for forced commands.
|
||||
*/
|
||||
if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
if (forced_command) {
|
||||
log("Root login accepted for forced command.");
|
||||
} else {
|
||||
authenticated = 0;
|
||||
log("ROOT LOGIN REFUSED FROM %.200s",
|
||||
get_canonical_hostname());
|
||||
}
|
||||
}
|
||||
|
||||
/* Raise logging level */
|
||||
if (authenticated ||
|
||||
attempt == AUTH_FAIL_LOG ||
|
||||
type == SSH_CMSG_AUTH_PASSWORD)
|
||||
authlog = log;
|
||||
|
||||
authlog("%s %s for %.200s from %.200s port %d%s",
|
||||
authenticated ? "Accepted" : "Failed",
|
||||
get_authname(type),
|
||||
pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port(),
|
||||
user);
|
||||
|
||||
if (authenticated)
|
||||
return;
|
||||
|
||||
if (attempt > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
|
||||
|
||||
/* Send a message indicating that the authentication attempt failed. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs authentication of an incoming connection. Session key has already
|
||||
* been exchanged and encryption is enabled.
|
||||
*/
|
||||
void
|
||||
do_authentication()
|
||||
{
|
||||
struct passwd *pw, pwcopy;
|
||||
int plen;
|
||||
unsigned int ulen;
|
||||
char *user;
|
||||
|
||||
/* Get the name of the user that we wish to log in as. */
|
||||
packet_read_expect(&plen, SSH_CMSG_USER);
|
||||
|
||||
/* Get the user name. */
|
||||
user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
|
||||
|
||||
setproctitle("%s", user);
|
||||
|
||||
#ifdef AFS
|
||||
/* If machine has AFS, set process authentication group. */
|
||||
if (k_hasafs()) {
|
||||
k_setpag();
|
||||
k_unlog();
|
||||
}
|
||||
#endif /* AFS */
|
||||
|
||||
/* Verify that the user is a valid user. */
|
||||
pw = getpwnam(user);
|
||||
if (!pw || !allowed_user(pw))
|
||||
do_fake_authloop1(user);
|
||||
xfree(user);
|
||||
|
||||
/* Take a copy of the returned structure. */
|
||||
memset(&pwcopy, 0, sizeof(pwcopy));
|
||||
pwcopy.pw_name = xstrdup(pw->pw_name);
|
||||
pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
|
||||
pwcopy.pw_uid = pw->pw_uid;
|
||||
pwcopy.pw_gid = pw->pw_gid;
|
||||
pwcopy.pw_dir = xstrdup(pw->pw_dir);
|
||||
pwcopy.pw_shell = xstrdup(pw->pw_shell);
|
||||
pw = &pwcopy;
|
||||
|
||||
/*
|
||||
* 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.");
|
||||
|
||||
debug("Attempting authentication for %.100s.", pw->pw_name);
|
||||
|
||||
/* If the user has no password, accept authentication immediately. */
|
||||
if (options.password_authentication &&
|
||||
#ifdef KRB4
|
||||
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
|
||||
#endif /* KRB4 */
|
||||
auth_password(pw, "")) {
|
||||
/* Authentication with empty password succeeded. */
|
||||
log("Login for user %s from %.100s, accepted without authentication.",
|
||||
pw->pw_name, get_remote_ipaddr());
|
||||
} else {
|
||||
/* Loop until the user has been authenticated or the
|
||||
connection is closed, do_authloop() returns only if
|
||||
authentication is successfull */
|
||||
do_authloop(pw);
|
||||
}
|
||||
|
||||
/* The user has been authenticated and accepted. */
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Perform session preparation. */
|
||||
do_authenticated(pw);
|
||||
}
|
467
crypto/openssh/auth2.c
Normal file
467
crypto/openssh/auth2.c
Normal file
@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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("$OpenBSD: auth2.c,v 1.8 2000/05/08 17:42:24 markus Exp $");
|
||||
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
#include "auth.h"
|
||||
#include "key.h"
|
||||
#include "kex.h"
|
||||
|
||||
#include "dsa.h"
|
||||
#include "uidswap.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern unsigned char *session_id2;
|
||||
extern int session_id2_len;
|
||||
|
||||
/* protocol */
|
||||
|
||||
void input_service_request(int type, int plen);
|
||||
void input_userauth_request(int type, int plen);
|
||||
void protocol_error(int type, int plen);
|
||||
|
||||
/* auth */
|
||||
int ssh2_auth_none(struct passwd *pw);
|
||||
int ssh2_auth_password(struct passwd *pw);
|
||||
int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
|
||||
|
||||
/* helper */
|
||||
struct passwd* auth_set_user(char *u, char *s);
|
||||
int user_dsa_key_allowed(struct passwd *pw, Key *key);
|
||||
|
||||
typedef struct Authctxt Authctxt;
|
||||
struct Authctxt {
|
||||
char *user;
|
||||
char *service;
|
||||
struct passwd pw;
|
||||
int valid;
|
||||
};
|
||||
static Authctxt *authctxt = NULL;
|
||||
static int userauth_success = 0;
|
||||
|
||||
/*
|
||||
* loop until userauth_success == TRUE
|
||||
*/
|
||||
|
||||
void
|
||||
do_authentication2()
|
||||
{
|
||||
/* turn off skey/kerberos, not supported by SSH2 */
|
||||
#ifdef SKEY
|
||||
options.skey_authentication = 0;
|
||||
#endif
|
||||
#ifdef KRB4
|
||||
options.kerberos_authentication = 0;
|
||||
#endif
|
||||
|
||||
dispatch_init(&protocol_error);
|
||||
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
dispatch_run(DISPATCH_BLOCK, &userauth_success);
|
||||
do_authenticated2();
|
||||
}
|
||||
|
||||
void
|
||||
protocol_error(int type, int plen)
|
||||
{
|
||||
log("auth: protocol error: type %d plen %d", type, plen);
|
||||
packet_start(SSH2_MSG_UNIMPLEMENTED);
|
||||
packet_put_int(0);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
void
|
||||
input_service_request(int type, int plen)
|
||||
{
|
||||
unsigned int len;
|
||||
int accept = 0;
|
||||
char *service = packet_get_string(&len);
|
||||
packet_done();
|
||||
|
||||
if (strcmp(service, "ssh-userauth") == 0) {
|
||||
if (!userauth_success) {
|
||||
accept = 1;
|
||||
/* now we can handle user-auth requests */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
|
||||
}
|
||||
}
|
||||
/* XXX all other service requests are denied */
|
||||
|
||||
if (accept) {
|
||||
packet_start(SSH2_MSG_SERVICE_ACCEPT);
|
||||
packet_put_cstring(service);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
} else {
|
||||
debug("bad service request %s", service);
|
||||
packet_disconnect("bad service request %s", service);
|
||||
}
|
||||
xfree(service);
|
||||
}
|
||||
|
||||
void
|
||||
input_userauth_request(int type, int plen)
|
||||
{
|
||||
static void (*authlog) (const char *fmt,...) = verbose;
|
||||
static int attempt = 0;
|
||||
unsigned int len, rlen;
|
||||
int authenticated = 0;
|
||||
char *raw, *user, *service, *method, *authmsg = NULL;
|
||||
struct passwd *pw;
|
||||
|
||||
if (++attempt == AUTH_FAIL_MAX)
|
||||
packet_disconnect("too many failed userauth_requests");
|
||||
|
||||
raw = packet_get_raw(&rlen);
|
||||
if (plen != rlen)
|
||||
fatal("plen != rlen");
|
||||
user = packet_get_string(&len);
|
||||
service = packet_get_string(&len);
|
||||
method = packet_get_string(&len);
|
||||
debug("userauth-request for user %s service %s method %s", user, service, method);
|
||||
|
||||
/* XXX we only allow the ssh-connection service */
|
||||
pw = auth_set_user(user, service);
|
||||
if (pw && strcmp(service, "ssh-connection")==0) {
|
||||
if (strcmp(method, "none") == 0) {
|
||||
authenticated = ssh2_auth_none(pw);
|
||||
} else if (strcmp(method, "password") == 0) {
|
||||
authenticated = ssh2_auth_password(pw);
|
||||
} else if (strcmp(method, "publickey") == 0) {
|
||||
authenticated = ssh2_auth_pubkey(pw, raw, rlen);
|
||||
}
|
||||
}
|
||||
if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
|
||||
authenticated = 0;
|
||||
log("ROOT LOGIN REFUSED FROM %.200s",
|
||||
get_canonical_hostname());
|
||||
}
|
||||
|
||||
/* Raise logging level */
|
||||
if (authenticated == 1 ||
|
||||
attempt == AUTH_FAIL_LOG ||
|
||||
strcmp(method, "password") == 0)
|
||||
authlog = log;
|
||||
|
||||
/* Log before sending the reply */
|
||||
if (authenticated == 1) {
|
||||
authmsg = "Accepted";
|
||||
} else if (authenticated == 0) {
|
||||
authmsg = "Failed";
|
||||
} else {
|
||||
authmsg = "Postponed";
|
||||
}
|
||||
authlog("%s %s for %.200s from %.200s port %d ssh2",
|
||||
authmsg,
|
||||
method,
|
||||
pw && pw->pw_uid == 0 ? "ROOT" : user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
|
||||
/* XXX todo: check if multiple auth methods are needed */
|
||||
if (authenticated == 1) {
|
||||
/* turn off userauth */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
|
||||
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
/* now we can break out */
|
||||
userauth_success = 1;
|
||||
} else if (authenticated == 0) {
|
||||
packet_start(SSH2_MSG_USERAUTH_FAILURE);
|
||||
packet_put_cstring("publickey,password"); /* XXX dynamic */
|
||||
packet_put_char(0); /* XXX partial success, unused */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
xfree(service);
|
||||
xfree(user);
|
||||
xfree(method);
|
||||
}
|
||||
|
||||
int
|
||||
ssh2_auth_none(struct passwd *pw)
|
||||
{
|
||||
packet_done();
|
||||
return auth_password(pw, "");
|
||||
}
|
||||
int
|
||||
ssh2_auth_password(struct passwd *pw)
|
||||
{
|
||||
char *password;
|
||||
int authenticated = 0;
|
||||
int change;
|
||||
unsigned int len;
|
||||
change = packet_get_char();
|
||||
if (change)
|
||||
log("password change not supported");
|
||||
password = packet_get_string(&len);
|
||||
packet_done();
|
||||
if (options.password_authentication &&
|
||||
auth_password(pw, password) == 1)
|
||||
authenticated = 1;
|
||||
memset(password, 0, len);
|
||||
xfree(password);
|
||||
return authenticated;
|
||||
}
|
||||
int
|
||||
ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
|
||||
{
|
||||
Buffer b;
|
||||
Key *key;
|
||||
char *pkalg, *pkblob, *sig;
|
||||
unsigned int alen, blen, slen;
|
||||
int have_sig;
|
||||
int authenticated = 0;
|
||||
|
||||
if (options.dsa_authentication == 0) {
|
||||
debug("pubkey auth disabled");
|
||||
return 0;
|
||||
}
|
||||
if (datafellows & SSH_BUG_PUBKEYAUTH) {
|
||||
log("bug compatibility with ssh-2.0.13 pubkey not implemented");
|
||||
return 0;
|
||||
}
|
||||
have_sig = packet_get_char();
|
||||
pkalg = packet_get_string(&alen);
|
||||
if (strcmp(pkalg, KEX_DSS) != 0) {
|
||||
xfree(pkalg);
|
||||
log("bad pkalg %s", pkalg); /*XXX*/
|
||||
return 0;
|
||||
}
|
||||
pkblob = packet_get_string(&blen);
|
||||
key = dsa_key_from_blob(pkblob, blen);
|
||||
if (key != NULL) {
|
||||
if (have_sig) {
|
||||
sig = packet_get_string(&slen);
|
||||
packet_done();
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, session_id2, session_id2_len);
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
if (slen + 4 > rlen)
|
||||
fatal("bad rlen/slen");
|
||||
buffer_append(&b, raw, rlen - slen - 4);
|
||||
#ifdef DEBUG_DSS
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
/* test for correct signature */
|
||||
if (user_dsa_key_allowed(pw, key) &&
|
||||
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
|
||||
authenticated = 1;
|
||||
buffer_clear(&b);
|
||||
xfree(sig);
|
||||
} else {
|
||||
packet_done();
|
||||
debug("test key...");
|
||||
/* test whether pkalg/pkblob are acceptable */
|
||||
/* XXX fake reply and always send PK_OK ? */
|
||||
/*
|
||||
* XXX this allows testing whether a user is allowed
|
||||
* to login: if you happen to have a valid pubkey this
|
||||
* message is sent. the message is NEVER sent at all
|
||||
* if a user is not allowed to login. is this an
|
||||
* issue? -markus
|
||||
*/
|
||||
if (user_dsa_key_allowed(pw, key)) {
|
||||
packet_start(SSH2_MSG_USERAUTH_PK_OK);
|
||||
packet_put_string(pkalg, alen);
|
||||
packet_put_string(pkblob, blen);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
authenticated = -1;
|
||||
}
|
||||
}
|
||||
key_free(key);
|
||||
}
|
||||
xfree(pkalg);
|
||||
xfree(pkblob);
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
/* set and get current user */
|
||||
|
||||
struct passwd*
|
||||
auth_get_user(void)
|
||||
{
|
||||
return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
|
||||
}
|
||||
|
||||
struct passwd*
|
||||
auth_set_user(char *u, char *s)
|
||||
{
|
||||
struct passwd *pw, *copy;
|
||||
|
||||
if (authctxt == NULL) {
|
||||
authctxt = xmalloc(sizeof(*authctxt));
|
||||
authctxt->valid = 0;
|
||||
authctxt->user = xstrdup(u);
|
||||
authctxt->service = xstrdup(s);
|
||||
setproctitle("%s", u);
|
||||
pw = getpwnam(u);
|
||||
if (!pw || !allowed_user(pw)) {
|
||||
log("auth_set_user: illegal user %s", u);
|
||||
return NULL;
|
||||
}
|
||||
copy = &authctxt->pw;
|
||||
memset(copy, 0, sizeof(*copy));
|
||||
copy->pw_name = xstrdup(pw->pw_name);
|
||||
copy->pw_passwd = xstrdup(pw->pw_passwd);
|
||||
copy->pw_uid = pw->pw_uid;
|
||||
copy->pw_gid = pw->pw_gid;
|
||||
copy->pw_dir = xstrdup(pw->pw_dir);
|
||||
copy->pw_shell = xstrdup(pw->pw_shell);
|
||||
authctxt->valid = 1;
|
||||
} else {
|
||||
if (strcmp(u, authctxt->user) != 0 ||
|
||||
strcmp(s, authctxt->service) != 0) {
|
||||
log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
|
||||
u, s, authctxt->user, authctxt->service);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return auth_get_user();
|
||||
}
|
||||
|
||||
/* return 1 if user allows given key */
|
||||
int
|
||||
user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
{
|
||||
char line[8192], file[1024];
|
||||
int found_key = 0;
|
||||
unsigned int bits = -1;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
struct stat st;
|
||||
Key *found;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
|
||||
/* The authorized keys. */
|
||||
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
|
||||
SSH_USER_PERMITTED_KEYS2);
|
||||
|
||||
/* Fail quietly if file does not exist */
|
||||
if (stat(file, &st) < 0) {
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
/* Open the file containing the authorized keys. */
|
||||
f = fopen(file, "r");
|
||||
if (!f) {
|
||||
/* Restore the privileged uid. */
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
if (options.strict_modes) {
|
||||
int fail = 0;
|
||||
char buf[1024];
|
||||
/* Check open file in order to avoid open/stat races */
|
||||
if (fstat(fileno(f), &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.", pw->pw_name, file);
|
||||
fail = 1;
|
||||
} else {
|
||||
/* Check path to SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", SSH_USER_DIR, NULL
|
||||
};
|
||||
for (i = 0; check[i]; i++) {
|
||||
snprintf(line, sizeof line, "%.500s/%.100s",
|
||||
pw->pw_dir, check[i]);
|
||||
if (stat(line, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(buf, sizeof buf,
|
||||
"DSA authentication refused for %.100s: "
|
||||
"bad ownership or modes for '%s'.",
|
||||
pw->pw_name, line);
|
||||
fail = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
log(buf);
|
||||
fclose(f);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
found_key = 0;
|
||||
found = key_new(KEY_DSA);
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
char *cp;
|
||||
linenum++;
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
bits = key_read(found, &cp);
|
||||
if (bits == 0)
|
||||
continue;
|
||||
if (key_equal(found, key)) {
|
||||
found_key = 1;
|
||||
debug("matching key found: file %s, line %ld",
|
||||
file, linenum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
restore_uid();
|
||||
fclose(f);
|
||||
key_free(found);
|
||||
return found_key;
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* authfd.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Mar 29 01:17:41 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions to interface with the SSH_AUTHENTICATION_FD socket.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: authfd.h,v 1.6 1999/11/24 19:53:44 markus Exp $"); */
|
||||
/* RCSID("$Id: authfd.h,v 1.7 2000/04/14 10:30:30 markus Exp $"); */
|
||||
|
||||
#ifndef AUTHFD_H
|
||||
#define AUTHFD_H
|
||||
@ -67,7 +67,7 @@ void ssh_close_authentication_connection(AuthenticationConnection * ac);
|
||||
* integers before the call, and free the comment after a successful call
|
||||
* (before calling ssh_get_next_identity).
|
||||
*/
|
||||
int
|
||||
int
|
||||
ssh_get_first_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
||||
@ -77,13 +77,13 @@ ssh_get_first_identity(AuthenticationConnection * connection,
|
||||
* function. This returns 0 if there are no more identities. The caller
|
||||
* must free comment after a successful return.
|
||||
*/
|
||||
int
|
||||
int
|
||||
ssh_get_next_identity(AuthenticationConnection * connection,
|
||||
BIGNUM * e, BIGNUM * n, char **comment);
|
||||
|
||||
/* Requests the agent to decrypt the given challenge. Returns true if
|
||||
the agent claims it was able to decrypt it. */
|
||||
int
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection * auth,
|
||||
BIGNUM * e, BIGNUM * n, BIGNUM * challenge,
|
||||
unsigned char session_id[16],
|
||||
@ -95,7 +95,7 @@ ssh_decrypt_challenge(AuthenticationConnection * auth,
|
||||
* be used by normal applications. This returns true if the identity was
|
||||
* successfully added.
|
||||
*/
|
||||
int
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection * connection, RSA * key,
|
||||
const char *comment);
|
||||
|
||||
|
36
crypto/openssh/authfile.h
Normal file
36
crypto/openssh/authfile.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef AUTHFILE_H
|
||||
#define AUTHFILE_H
|
||||
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase.
|
||||
* For RSA keys: 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,
|
||||
Key * 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.
|
||||
*/
|
||||
int
|
||||
load_public_key(const char *filename, Key * 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.
|
||||
*/
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
Key * private_key, char **comment_return);
|
||||
|
||||
#endif
|
@ -1,17 +1,17 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* bufaux.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Mar 29 02:18:23 1995 ylo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: bufaux.h,v 1.4 1999/11/24 19:53:44 markus Exp $"); */
|
||||
/* RCSID("$Id: bufaux.h,v 1.6 2000/04/14 10:30:30 markus Exp $"); */
|
||||
|
||||
#ifndef BUFAUX_H
|
||||
#define BUFAUX_H
|
||||
@ -23,9 +23,11 @@
|
||||
* by (bits+7)/8 bytes of binary data, msb first.
|
||||
*/
|
||||
void buffer_put_bignum(Buffer * buffer, BIGNUM * value);
|
||||
void buffer_put_bignum2(Buffer * buffer, BIGNUM * value);
|
||||
|
||||
/* Retrieves an BIGNUM from the buffer. */
|
||||
int buffer_get_bignum(Buffer * buffer, BIGNUM * value);
|
||||
int buffer_get_bignum2(Buffer *buffer, BIGNUM * value);
|
||||
|
||||
/* Returns an integer from the buffer (4 bytes, msb first). */
|
||||
unsigned int buffer_get_int(Buffer * buffer);
|
||||
@ -51,5 +53,6 @@ char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr);
|
||||
|
||||
/* Stores and arbitrary binary string in the buffer. */
|
||||
void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len);
|
||||
void buffer_put_cstring(Buffer *buffer, const char *s);
|
||||
|
||||
#endif /* BUFAUX_H */
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* buffer.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Mar 18 04:15:33 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for manipulating fifo buffers (that can grow if needed).
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: buffer.c,v 1.4 1999/11/24 19:53:44 markus Exp $");
|
||||
RCSID("$Id: buffer.c,v 1.6 2000/04/14 10:30:30 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
@ -22,7 +22,7 @@ RCSID("$Id: buffer.c,v 1.4 1999/11/24 19:53:44 markus Exp $");
|
||||
|
||||
/* Initializes the buffer structure. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_init(Buffer *buffer)
|
||||
{
|
||||
buffer->alloc = 4096;
|
||||
@ -33,7 +33,7 @@ buffer_init(Buffer *buffer)
|
||||
|
||||
/* Frees any memory used for the buffer. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_free(Buffer *buffer)
|
||||
{
|
||||
memset(buffer->buf, 0, buffer->alloc);
|
||||
@ -45,7 +45,7 @@ buffer_free(Buffer *buffer)
|
||||
* zero the memory.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
buffer_clear(Buffer *buffer)
|
||||
{
|
||||
buffer->offset = 0;
|
||||
@ -54,7 +54,7 @@ buffer_clear(Buffer *buffer)
|
||||
|
||||
/* Appends data to the buffer, expanding it if necessary. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_append(Buffer *buffer, const char *data, unsigned int len)
|
||||
{
|
||||
char *cp;
|
||||
@ -68,7 +68,7 @@ buffer_append(Buffer *buffer, const char *data, unsigned int len)
|
||||
* to the allocated region.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
|
||||
{
|
||||
/* If the buffer is empty, start using it from the beginning. */
|
||||
@ -102,7 +102,7 @@ buffer_append_space(Buffer *buffer, char **datap, unsigned int len)
|
||||
|
||||
/* Returns the number of bytes of data in the buffer. */
|
||||
|
||||
unsigned int
|
||||
unsigned int
|
||||
buffer_len(Buffer *buffer)
|
||||
{
|
||||
return buffer->end - buffer->offset;
|
||||
@ -110,32 +110,32 @@ buffer_len(Buffer *buffer)
|
||||
|
||||
/* Gets data from the beginning of the buffer. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_get(Buffer *buffer, char *buf, unsigned int len)
|
||||
{
|
||||
if (len > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
fatal("buffer_get: trying to get more bytes than in buffer");
|
||||
memcpy(buf, buffer->buf + buffer->offset, len);
|
||||
buffer->offset += len;
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the beginning of the buffer. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_consume(Buffer *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
fatal("buffer_consume: trying to get more bytes than in buffer");
|
||||
buffer->offset += bytes;
|
||||
}
|
||||
|
||||
/* Consumes the given number of bytes from the end of the buffer. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_consume_end(Buffer *buffer, unsigned int bytes)
|
||||
{
|
||||
if (bytes > buffer->end - buffer->offset)
|
||||
fatal("buffer_get trying to get more bytes than in buffer");
|
||||
fatal("buffer_consume_end: trying to get more bytes than in buffer");
|
||||
buffer->end -= bytes;
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ buffer_ptr(Buffer *buffer)
|
||||
|
||||
/* Dumps the contents of the buffer to stderr. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_dump(Buffer *buffer)
|
||||
{
|
||||
int i;
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* buffer.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Mar 18 04:12:25 1995 ylo
|
||||
*
|
||||
*
|
||||
* Code for manipulating FIFO buffers.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: buffer.h,v 1.3 1999/11/24 19:53:44 markus Exp $"); */
|
||||
/* RCSID("$Id: buffer.h,v 1.4 2000/04/14 10:30:30 markus Exp $"); */
|
||||
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* canohost.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sun Jul 2 17:52:22 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for returning the canonical host name of the remote site.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: canohost.c,v 1.11 2000/01/04 13:41:32 markus Exp $");
|
||||
RCSID("$Id: canohost.c,v 1.12 2000/04/14 10:30:30 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
@ -241,7 +241,7 @@ get_sock_port(int sock, int local)
|
||||
|
||||
/* Returns remote/local port number for the current connection. */
|
||||
|
||||
int
|
||||
int
|
||||
get_port(int local)
|
||||
{
|
||||
/*
|
||||
@ -255,13 +255,13 @@ get_port(int local)
|
||||
return get_sock_port(packet_get_connection_in(), local);
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
get_peer_port(int sock)
|
||||
{
|
||||
return get_sock_port(sock, 0);
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
get_remote_port()
|
||||
{
|
||||
return get_port(0);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/* RCSID("$Id: channels.h,v 1.6 1999/11/24 19:53:45 markus Exp $"); */
|
||||
/* RCSID("$Id: channels.h,v 1.12 2000/05/03 18:03:06 markus Exp $"); */
|
||||
|
||||
#ifndef CHANNELS_H
|
||||
#define CHANNELS_H
|
||||
@ -10,17 +10,18 @@
|
||||
#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_AUTH_SOCKET 7 /* authentication 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_AUTH_SOCKET 6 /* authentication socket */
|
||||
#define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */
|
||||
#define SSH_CHANNEL_LARVAL 10 /* larval session */
|
||||
#define SSH_CHANNEL_MAX_TYPE 11
|
||||
|
||||
/*
|
||||
* Data structure for channel data. This is iniailized in channel_allocate
|
||||
* and cleared in channel_free.
|
||||
*/
|
||||
typedef void channel_callback_fn(int id, void *arg);
|
||||
|
||||
typedef struct Channel {
|
||||
int type; /* channel type/state */
|
||||
@ -29,15 +30,208 @@ typedef struct Channel {
|
||||
/* peer can be reached over encrypted connection, via packet-sent */
|
||||
int istate; /* input from channel (state of receive half) */
|
||||
int ostate; /* output to channel (state of transmit half) */
|
||||
int sock; /* data socket, linked to this channel */
|
||||
int flags; /* close sent/rcvd */
|
||||
int rfd; /* read fd */
|
||||
int wfd; /* write fd */
|
||||
int efd; /* extended fd */
|
||||
int sock; /* sock fd */
|
||||
Buffer input; /* data read from socket, to be sent over
|
||||
* encrypted connection */
|
||||
Buffer output; /* data received over encrypted connection for
|
||||
* send on socket */
|
||||
Buffer extended;
|
||||
char path[200]; /* path for unix domain sockets, or host name
|
||||
* for forwards */
|
||||
int listening_port; /* port being listened for forwards */
|
||||
int host_port; /* remote port to connect for forwards */
|
||||
char *remote_name; /* remote hostname */
|
||||
|
||||
int remote_window;
|
||||
int remote_maxpacket;
|
||||
int local_window;
|
||||
int local_window_max;
|
||||
int local_consumed;
|
||||
int local_maxpacket;
|
||||
int extended_usage;
|
||||
|
||||
char *ctype; /* type */
|
||||
|
||||
/* callback */
|
||||
channel_callback_fn *cb_fn;
|
||||
void *cb_arg;
|
||||
int cb_event;
|
||||
channel_callback_fn *dettach_user;
|
||||
} Channel;
|
||||
|
||||
#define CHAN_EXTENDED_IGNORE 0
|
||||
#define CHAN_EXTENDED_READ 1
|
||||
#define CHAN_EXTENDED_WRITE 2
|
||||
|
||||
void channel_set_fds(int id, int rfd, int wfd, int efd, int extusage);
|
||||
void channel_open(int id);
|
||||
void channel_request(int id, char *service, int wantconfirm);
|
||||
void channel_request_start(int id, char *service, int wantconfirm);
|
||||
void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
|
||||
void channel_register_cleanup(int id, channel_callback_fn *fn);
|
||||
void channel_cancel_cleanup(int id);
|
||||
Channel *channel_lookup(int id);
|
||||
|
||||
int
|
||||
channel_new(char *ctype, int type, int rfd, int wfd, int efd,
|
||||
int window, int maxpack, int extended_usage, char *remote_name);
|
||||
|
||||
void channel_input_channel_request(int type, int plen);
|
||||
void channel_input_close(int type, int plen);
|
||||
void channel_input_close_confirmation(int type, int plen);
|
||||
void channel_input_data(int type, int plen);
|
||||
void channel_input_extended_data(int type, int plen);
|
||||
void channel_input_ieof(int type, int plen);
|
||||
void channel_input_oclose(int type, int plen);
|
||||
void channel_input_open_confirmation(int type, int plen);
|
||||
void channel_input_open_failure(int type, int plen);
|
||||
void channel_input_port_open(int type, int plen);
|
||||
void channel_input_window_adjust(int type, int plen);
|
||||
void channel_input_open(int type, int plen);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
int channel_allocate(int type, int sock, char *remote_name);
|
||||
|
||||
/* Free the channel and close its socket. */
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Returns true if no channel has too much buffered data. */
|
||||
int channel_not_very_much_buffered_data(void);
|
||||
|
||||
/* This closes any sockets that are listening for connections; this removes
|
||||
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.
|
||||
*/
|
||||
void channel_close_all(void);
|
||||
|
||||
/* Returns the maximum file descriptor number used by the channels. */
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void
|
||||
channel_request_local_forwarding(u_short port, const char *host,
|
||||
u_short remote_port, int gateway_ports);
|
||||
|
||||
/*
|
||||
* 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(u_short port, const char *host,
|
||||
u_short 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void channel_input_port_forward_request(int is_root, int gateway_ports);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
char *x11_create_display_inet(int screen, int x11_display_offset);
|
||||
|
||||
/*
|
||||
* 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 type, int plen);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
x11_request_forwarding_with_spoofing(int client_session_id,
|
||||
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.
|
||||
*/
|
||||
char *auth_get_socket_name(void);
|
||||
|
||||
/*
|
||||
* 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(int type, int plen);
|
||||
|
||||
/* XXX */
|
||||
int channel_connect_to(const char *host, u_short host_port);
|
||||
int x11_connect_display(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,21 +1,22 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* clientloop.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Created: Sat Sep 23 12:23:57 1995 ylo
|
||||
*
|
||||
*
|
||||
* The main loop for the interactive session (client side).
|
||||
*
|
||||
*
|
||||
* SSH2 support added by Markus Friedl.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: clientloop.c,v 1.14 1999/12/06 20:15:26 deraadt Exp $");
|
||||
RCSID("$Id: clientloop.c,v 1.26 2000/05/08 17:42:24 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
@ -24,6 +25,12 @@ RCSID("$Id: clientloop.c,v 1.14 1999/12/06 20:15:26 deraadt Exp $");
|
||||
#include "authfd.h"
|
||||
#include "readconf.h"
|
||||
|
||||
#include "ssh2.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "dispatch.h"
|
||||
|
||||
|
||||
/* Flag indicating that stdin should be redirected from /dev/null. */
|
||||
extern int stdin_null_flag;
|
||||
|
||||
@ -70,9 +77,13 @@ 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. */
|
||||
|
||||
|
||||
void client_init_dispatch(void);
|
||||
int session_ident = -1;
|
||||
|
||||
/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */
|
||||
|
||||
void
|
||||
void
|
||||
leave_raw_mode()
|
||||
{
|
||||
if (!in_raw_mode)
|
||||
@ -86,7 +97,7 @@ leave_raw_mode()
|
||||
|
||||
/* Puts the user\'s terminal in raw mode. */
|
||||
|
||||
void
|
||||
void
|
||||
enter_raw_mode()
|
||||
{
|
||||
struct termios tio;
|
||||
@ -112,7 +123,7 @@ enter_raw_mode()
|
||||
|
||||
/* Restores stdin to blocking mode. */
|
||||
|
||||
void
|
||||
void
|
||||
leave_non_blocking()
|
||||
{
|
||||
if (in_non_blocking_mode) {
|
||||
@ -124,7 +135,7 @@ leave_non_blocking()
|
||||
|
||||
/* Puts stdin terminal in non-blocking mode. */
|
||||
|
||||
void
|
||||
void
|
||||
enter_non_blocking()
|
||||
{
|
||||
in_non_blocking_mode = 1;
|
||||
@ -137,7 +148,7 @@ enter_non_blocking()
|
||||
* flag indicating that the window has changed.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
window_change_handler(int sig)
|
||||
{
|
||||
received_window_change_signal = 1;
|
||||
@ -149,7 +160,7 @@ window_change_handler(int sig)
|
||||
* signals must be trapped to restore terminal modes.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
if (in_raw_mode)
|
||||
@ -166,7 +177,7 @@ signal_handler(int sig)
|
||||
* available resolution.
|
||||
*/
|
||||
|
||||
double
|
||||
double
|
||||
get_current_time()
|
||||
{
|
||||
struct timeval tv;
|
||||
@ -180,7 +191,7 @@ get_current_time()
|
||||
* not appear to wake up when redirecting from /dev/null.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
client_check_initial_eof_on_stdin()
|
||||
{
|
||||
int len;
|
||||
@ -228,115 +239,13 @@ client_check_initial_eof_on_stdin()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get packets from the connection input buffer, and process them as long as
|
||||
* there are packets available.
|
||||
*/
|
||||
|
||||
void
|
||||
client_process_buffered_input_packets()
|
||||
{
|
||||
int type;
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
int payload_len;
|
||||
|
||||
/* Process any buffered packets from the server. */
|
||||
while (!quit_pending &&
|
||||
(type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
|
||||
switch (type) {
|
||||
|
||||
case SSH_SMSG_STDOUT_DATA:
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(payload_len, 4 + data_len, type);
|
||||
buffer_append(&stdout_buffer, data, data_len);
|
||||
stdout_bytes += data_len;
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
break;
|
||||
|
||||
case SSH_SMSG_STDERR_DATA:
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(payload_len, 4 + data_len, type);
|
||||
buffer_append(&stderr_buffer, data, data_len);
|
||||
stdout_bytes += data_len;
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
break;
|
||||
|
||||
case SSH_SMSG_EXITSTATUS:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
exit_status = packet_get_int();
|
||||
/* Acknowledge the exit. */
|
||||
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
||||
packet_send();
|
||||
/*
|
||||
* 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;
|
||||
break;
|
||||
|
||||
case SSH_SMSG_X11_OPEN:
|
||||
x11_input_open(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_PORT_OPEN:
|
||||
channel_input_port_open(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_SMSG_AGENT_OPEN:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
auth_input_open_request();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
packet_integrity_check(payload_len, 4 + 4, type);
|
||||
channel_input_open_confirmation();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_FAILURE:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_open_failure();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_DATA:
|
||||
channel_input_data(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close_confirmation();
|
||||
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.
|
||||
*/
|
||||
packet_disconnect("Protocol error during session: type %d",
|
||||
type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets from buffered stdin data, and buffer them for sending to the
|
||||
* connection.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
client_make_packets_from_stdin_data()
|
||||
{
|
||||
unsigned int len;
|
||||
@ -367,26 +276,35 @@ client_make_packets_from_stdin_data()
|
||||
* appropriate.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
client_check_window_change()
|
||||
{
|
||||
/* Send possible window change message to the server. */
|
||||
if (received_window_change_signal) {
|
||||
struct winsize ws;
|
||||
struct winsize ws;
|
||||
|
||||
/* Clear the window change indicator. */
|
||||
received_window_change_signal = 0;
|
||||
if (! received_window_change_signal)
|
||||
return;
|
||||
/** XXX race */
|
||||
received_window_change_signal = 0;
|
||||
|
||||
/* Read new window size. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) {
|
||||
/* Successful, send the packet now. */
|
||||
packet_start(SSH_CMSG_WINDOW_SIZE);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_send();
|
||||
}
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
return;
|
||||
|
||||
debug("client_check_window_change: changed");
|
||||
|
||||
if (compat20) {
|
||||
channel_request_start(session_ident, "window-change", 0);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_send();
|
||||
} else {
|
||||
packet_start(SSH_CMSG_WINDOW_SIZE);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,27 +313,37 @@ client_check_window_change()
|
||||
* one of the file descriptors).
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
||||
{
|
||||
/*debug("client_wait_until_can_do_something"); */
|
||||
|
||||
/* Initialize select masks. */
|
||||
FD_ZERO(readset);
|
||||
|
||||
/* Read from the connection, unless our buffers are full. */
|
||||
if (buffer_len(&stdout_buffer) < buffer_high &&
|
||||
buffer_len(&stderr_buffer) < buffer_high &&
|
||||
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.
|
||||
*/
|
||||
if (!stdin_eof && packet_not_very_much_data_to_write())
|
||||
FD_SET(fileno(stdin), readset);
|
||||
|
||||
FD_ZERO(writeset);
|
||||
|
||||
if (!compat20) {
|
||||
/* Read from the connection, unless our buffers are full. */
|
||||
if (buffer_len(&stdout_buffer) < buffer_high &&
|
||||
buffer_len(&stderr_buffer) < buffer_high &&
|
||||
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.
|
||||
*/
|
||||
if (!stdin_eof && packet_not_very_much_data_to_write())
|
||||
FD_SET(fileno(stdin), readset);
|
||||
|
||||
/* Select stdout/stderr if have data in buffer. */
|
||||
if (buffer_len(&stdout_buffer) > 0)
|
||||
FD_SET(fileno(stdout), writeset);
|
||||
if (buffer_len(&stderr_buffer) > 0)
|
||||
FD_SET(fileno(stderr), writeset);
|
||||
} else {
|
||||
FD_SET(connection_in, readset);
|
||||
}
|
||||
|
||||
/* Add any selections by the channel mechanism. */
|
||||
channel_prepare_select(readset, writeset);
|
||||
|
||||
@ -423,14 +351,7 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
||||
if (packet_have_data_to_write())
|
||||
FD_SET(connection_out, writeset);
|
||||
|
||||
/* Select stdout if have data in buffer. */
|
||||
if (buffer_len(&stdout_buffer) > 0)
|
||||
FD_SET(fileno(stdout), writeset);
|
||||
|
||||
/* Select stderr if have data in buffer. */
|
||||
if (buffer_len(&stderr_buffer) > 0)
|
||||
FD_SET(fileno(stderr), writeset);
|
||||
|
||||
/* move UP XXX */
|
||||
/* Update maximum file descriptor number, if appropriate. */
|
||||
if (channel_max_fd() > max_fd)
|
||||
max_fd = channel_max_fd();
|
||||
@ -459,7 +380,7 @@ client_wait_until_can_do_something(fd_set * readset, fd_set * writeset)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
client_suspend_self()
|
||||
{
|
||||
struct winsize oldws, newws;
|
||||
@ -504,11 +425,11 @@ client_suspend_self()
|
||||
enter_raw_mode();
|
||||
}
|
||||
|
||||
void
|
||||
client_process_input(fd_set * readset)
|
||||
void
|
||||
client_process_net_input(fd_set * readset)
|
||||
{
|
||||
int len, pid;
|
||||
char buf[8192], *s;
|
||||
int len;
|
||||
char buf[8192];
|
||||
|
||||
/*
|
||||
* Read input from the server, and add any such data to the buffer of
|
||||
@ -517,6 +438,7 @@ client_process_input(fd_set * readset)
|
||||
if (FD_ISSET(connection_in, readset)) {
|
||||
/* Read as much as possible. */
|
||||
len = read(connection_in, buf, sizeof(buf));
|
||||
/*debug("read connection_in len %d", len); XXX */
|
||||
if (len == 0) {
|
||||
/* Received EOF. The remote host has closed the connection. */
|
||||
snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
|
||||
@ -544,6 +466,15 @@ client_process_input(fd_set * readset)
|
||||
}
|
||||
packet_process_incoming(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
client_process_input(fd_set * readset)
|
||||
{
|
||||
int len;
|
||||
pid_t pid;
|
||||
char buf[8192], *s;
|
||||
|
||||
/* Read input from stdin. */
|
||||
if (FD_ISSET(fileno(stdin), readset)) {
|
||||
/* Read as much as possible. */
|
||||
@ -727,7 +658,7 @@ Supported escape sequences:\r\n\
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
client_process_output(fd_set * writeset)
|
||||
{
|
||||
int len;
|
||||
@ -775,6 +706,24 @@ client_process_output(fd_set * writeset)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get packets from the connection input buffer, and process them as long as
|
||||
* there are packets available.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
void
|
||||
client_process_buffered_input_packets()
|
||||
{
|
||||
dispatch_run(DISPATCH_NONBLOCK, &quit_pending);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements the interactive session with the server. This is called after
|
||||
* the user has been authenticated, and a command has been started on the
|
||||
@ -782,7 +731,7 @@ client_process_output(fd_set * writeset)
|
||||
* character for terminating or suspending the session.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
client_loop(int have_pty, int escape_char_arg)
|
||||
{
|
||||
extern Options options;
|
||||
@ -816,6 +765,8 @@ client_loop(int have_pty, int escape_char_arg)
|
||||
buffer_init(&stdout_buffer);
|
||||
buffer_init(&stderr_buffer);
|
||||
|
||||
client_init_dispatch();
|
||||
|
||||
/* Set signal handlers to restore non-blocking mode. */
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGQUIT, signal_handler);
|
||||
@ -828,7 +779,8 @@ client_loop(int have_pty, int escape_char_arg)
|
||||
enter_raw_mode();
|
||||
|
||||
/* Check if we should immediately send of on stdin. */
|
||||
client_check_initial_eof_on_stdin();
|
||||
if (!compat20)
|
||||
client_check_initial_eof_on_stdin();
|
||||
|
||||
/* Main loop of the client for the interactive session mode. */
|
||||
while (!quit_pending) {
|
||||
@ -837,11 +789,17 @@ client_loop(int have_pty, int escape_char_arg)
|
||||
/* Process buffered packets sent by the server. */
|
||||
client_process_buffered_input_packets();
|
||||
|
||||
if (compat20 && !channel_still_open()) {
|
||||
debug("!channel_still_open.");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets of buffered stdin data, and buffer them for
|
||||
* sending to the server.
|
||||
*/
|
||||
client_make_packets_from_stdin_data();
|
||||
if (!compat20)
|
||||
client_make_packets_from_stdin_data();
|
||||
|
||||
/*
|
||||
* Make packets from buffered channel data, and buffer them
|
||||
@ -871,17 +829,21 @@ 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.
|
||||
*/
|
||||
client_process_input(&readset);
|
||||
/* Buffer input from the connection. */
|
||||
client_process_net_input(&readset);
|
||||
|
||||
/*
|
||||
* Process output to stdout and stderr. Output to the
|
||||
* connection is processed elsewhere (above).
|
||||
*/
|
||||
client_process_output(&writeset);
|
||||
if (quit_pending)
|
||||
break;
|
||||
|
||||
if (!compat20) {
|
||||
/* Buffer data from stdin */
|
||||
client_process_input(&readset);
|
||||
/*
|
||||
* 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. */
|
||||
if (FD_ISSET(connection_out, &writeset))
|
||||
@ -950,3 +912,206 @@ client_loop(int have_pty, int escape_char_arg)
|
||||
debug("Exit status %d", exit_status);
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
/*********/
|
||||
|
||||
void
|
||||
client_input_stdout_data(int type, int plen)
|
||||
{
|
||||
unsigned int data_len;
|
||||
char *data = packet_get_string(&data_len);
|
||||
packet_integrity_check(plen, 4 + data_len, type);
|
||||
buffer_append(&stdout_buffer, data, data_len);
|
||||
stdout_bytes += data_len;
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
}
|
||||
void
|
||||
client_input_stderr_data(int type, int plen)
|
||||
{
|
||||
unsigned int data_len;
|
||||
char *data = packet_get_string(&data_len);
|
||||
packet_integrity_check(plen, 4 + data_len, type);
|
||||
buffer_append(&stderr_buffer, data, data_len);
|
||||
stdout_bytes += data_len;
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
}
|
||||
void
|
||||
client_input_exit_status(int type, int plen)
|
||||
{
|
||||
packet_integrity_check(plen, 4, type);
|
||||
exit_status = packet_get_int();
|
||||
/* Acknowledge the exit. */
|
||||
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
||||
packet_send();
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* XXXX move to generic input handler */
|
||||
void
|
||||
client_input_channel_open(int type, int plen)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
char *ctype;
|
||||
int id;
|
||||
unsigned int len;
|
||||
int rchan;
|
||||
int rmaxpack;
|
||||
int rwindow;
|
||||
|
||||
ctype = packet_get_string(&len);
|
||||
rchan = packet_get_int();
|
||||
rwindow = packet_get_int();
|
||||
rmaxpack = packet_get_int();
|
||||
|
||||
debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
|
||||
ctype, rchan, rwindow, rmaxpack);
|
||||
|
||||
if (strcmp(ctype, "x11") == 0) {
|
||||
int sock;
|
||||
char *originator;
|
||||
int originator_port;
|
||||
originator = packet_get_string(NULL);
|
||||
if (datafellows & SSH_BUG_X11FWD) {
|
||||
debug("buggy server: x11 request w/o originator_port");
|
||||
originator_port = 0;
|
||||
} else {
|
||||
originator_port = packet_get_int();
|
||||
}
|
||||
packet_done();
|
||||
/* XXX check permission */
|
||||
xfree(originator);
|
||||
/* XXX move to channels.c */
|
||||
sock = x11_connect_display();
|
||||
if (sock >= 0) {
|
||||
id = channel_new("x11", SSH_CHANNEL_X11_OPEN,
|
||||
sock, sock, -1, 4*1024, 32*1024, 0,
|
||||
xstrdup("x11"));
|
||||
c = channel_lookup(id);
|
||||
}
|
||||
}
|
||||
/* XXX duplicate : */
|
||||
if (c != NULL) {
|
||||
debug("confirm %s", ctype);
|
||||
c->remote_id = rchan;
|
||||
c->remote_window = rwindow;
|
||||
c->remote_maxpacket = rmaxpack;
|
||||
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
packet_send();
|
||||
} else {
|
||||
debug("failure %s", ctype);
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(rchan);
|
||||
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
|
||||
packet_put_cstring("bla bla");
|
||||
packet_put_cstring("");
|
||||
packet_send();
|
||||
}
|
||||
xfree(ctype);
|
||||
}
|
||||
|
||||
void
|
||||
client_init_dispatch_20()
|
||||
{
|
||||
dispatch_init(&dispatch_protocol_error);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
|
||||
}
|
||||
void
|
||||
client_init_dispatch_13()
|
||||
{
|
||||
dispatch_init(NULL);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
|
||||
dispatch_set(SSH_SMSG_AGENT_OPEN, &auth_input_open_request);
|
||||
dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
|
||||
dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
|
||||
dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
|
||||
dispatch_set(SSH_SMSG_X11_OPEN, &x11_input_open);
|
||||
}
|
||||
void
|
||||
client_init_dispatch_15()
|
||||
{
|
||||
client_init_dispatch_13();
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
|
||||
}
|
||||
void
|
||||
client_init_dispatch()
|
||||
{
|
||||
if (compat20)
|
||||
client_init_dispatch_20();
|
||||
else if (compat13)
|
||||
client_init_dispatch_13();
|
||||
else
|
||||
client_init_dispatch_15();
|
||||
}
|
||||
|
||||
void
|
||||
client_input_channel_req(int id, void *arg)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
unsigned int len;
|
||||
int success = 0;
|
||||
int reply;
|
||||
char *rtype;
|
||||
|
||||
rtype = packet_get_string(&len);
|
||||
reply = packet_get_char();
|
||||
|
||||
debug("client_input_channel_req: rtype %s reply %d", rtype, reply);
|
||||
|
||||
c = channel_lookup(id);
|
||||
if (c == NULL)
|
||||
fatal("session_input_channel_req: channel %d: bad channel", id);
|
||||
|
||||
if (session_ident == -1) {
|
||||
error("client_input_channel_req: no channel %d", id);
|
||||
} else if (id != session_ident) {
|
||||
error("client_input_channel_req: bad channel %d != %d",
|
||||
id, session_ident);
|
||||
} else if (strcmp(rtype, "exit-status") == 0) {
|
||||
success = 1;
|
||||
exit_status = packet_get_int();
|
||||
packet_done();
|
||||
}
|
||||
if (reply) {
|
||||
packet_start(success ?
|
||||
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
}
|
||||
xfree(rtype);
|
||||
}
|
||||
|
||||
void
|
||||
client_set_session_ident(int id)
|
||||
{
|
||||
debug("client_set_session_ident: id %d", id);
|
||||
session_ident = id;
|
||||
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
|
||||
client_input_channel_req, (void *)0);
|
||||
}
|
||||
|
@ -28,15 +28,77 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: compat.c,v 1.5 1999/11/24 16:15:24 markus Exp $");
|
||||
RCSID("$Id: compat.c,v 1.13 2000/05/08 17:42:24 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.h"
|
||||
|
||||
int compat13 = 0;
|
||||
int compat20 = 0;
|
||||
int datafellows = 0;
|
||||
|
||||
void
|
||||
void
|
||||
enable_compat20(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 2.0");
|
||||
compat20 = 1;
|
||||
}
|
||||
void
|
||||
enable_compat13(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 1.3");
|
||||
compat13 = 1;
|
||||
}
|
||||
/* datafellows bug compatibility */
|
||||
void
|
||||
compat_datafellows(const char *version)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
struct {
|
||||
char *version;
|
||||
int bugs;
|
||||
} check[] = {
|
||||
{"2.1.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC},
|
||||
{"2.0.1", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD},
|
||||
{NULL, 0}
|
||||
};
|
||||
for (i = 0; check[i].version; i++) {
|
||||
len = strlen(check[i].version);
|
||||
if (strlen(version) >= len &&
|
||||
(strncmp(version, check[i].version, len) == 0)) {
|
||||
verbose("datafellows: %.200s", version);
|
||||
datafellows = check[i].bugs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define SEP ","
|
||||
int
|
||||
proto_spec(const char *spec)
|
||||
{
|
||||
char *s = xstrdup(spec);
|
||||
char *p;
|
||||
int ret = SSH_PROTO_UNKNOWN;
|
||||
|
||||
for ((p = strtok(s, SEP)); p; (p = strtok(NULL, SEP))) {
|
||||
switch(atoi(p)) {
|
||||
case 1:
|
||||
if (ret == SSH_PROTO_UNKNOWN)
|
||||
ret |= SSH_PROTO_1_PREFERRED;
|
||||
ret |= SSH_PROTO_1;
|
||||
break;
|
||||
case 2:
|
||||
ret |= SSH_PROTO_2;
|
||||
break;
|
||||
default:
|
||||
log("ignoring bad proto spec: '%s'.", p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xfree(s);
|
||||
return ret;
|
||||
}
|
||||
|
@ -26,10 +26,26 @@
|
||||
* (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.4 1999/11/24 16:15:24 markus Exp $"); */
|
||||
/* RCSID("$Id: compat.h,v 1.7 2000/05/08 17:42:24 markus Exp $"); */
|
||||
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H
|
||||
|
||||
#define SSH_PROTO_UNKNOWN 0x00
|
||||
#define SSH_PROTO_1 0x01
|
||||
#define SSH_PROTO_1_PREFERRED 0x02
|
||||
#define SSH_PROTO_2 0x04
|
||||
|
||||
#define SSH_BUG_SIGBLOB 0x01
|
||||
#define SSH_BUG_PUBKEYAUTH 0x02
|
||||
#define SSH_BUG_HMAC 0x04
|
||||
#define SSH_BUG_X11FWD 0x08
|
||||
|
||||
void enable_compat13(void);
|
||||
void enable_compat20(void);
|
||||
void compat_datafellows(const char *s);
|
||||
int proto_spec(const char *spec);
|
||||
extern int compat13;
|
||||
extern int compat20;
|
||||
extern int datafellows;
|
||||
#endif
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* compress.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
*
|
||||
*
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: compress.c,v 1.5 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$Id: compress.c,v 1.7 2000/04/14 10:30:31 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
@ -28,7 +28,7 @@ static z_stream outgoing_stream;
|
||||
* (as in gzip).
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
buffer_compress_init(int level)
|
||||
{
|
||||
debug("Enabling compression at level %d.", level);
|
||||
@ -40,7 +40,7 @@ buffer_compress_init(int level)
|
||||
|
||||
/* Frees any data structures allocated for compression. */
|
||||
|
||||
void
|
||||
void
|
||||
buffer_compress_uninit()
|
||||
{
|
||||
debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f",
|
||||
@ -64,7 +64,7 @@ buffer_compress_uninit()
|
||||
* receiver. This appends the compressed data to the output buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
{
|
||||
char buf[4096];
|
||||
@ -90,23 +90,13 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
case Z_OK:
|
||||
/* Append compressed data to output_buffer. */
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - outgoing_stream.avail_out);
|
||||
sizeof(buf) - outgoing_stream.avail_out);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_END");
|
||||
/* NOTREACHED */
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_STREAM_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
fatal("buffer_compress: deflate returned Z_BUF_ERROR");
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatal("buffer_compress: deflate returned %d", status);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
while (outgoing_stream.avail_out == 0);
|
||||
} while (outgoing_stream.avail_out == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -118,7 +108,7 @@ buffer_compress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
* with that. This appends the uncompressed data to the output buffer.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
{
|
||||
char buf[4096];
|
||||
@ -127,27 +117,17 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
incoming_stream.next_in = (unsigned char *) buffer_ptr(input_buffer);
|
||||
incoming_stream.avail_in = buffer_len(input_buffer);
|
||||
|
||||
incoming_stream.next_out = (unsigned char *) buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
|
||||
for (;;) {
|
||||
/* Set up fixed-size output buffer. */
|
||||
incoming_stream.next_out = (unsigned char *) buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
|
||||
status = inflate(&incoming_stream, Z_PARTIAL_FLUSH);
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
buffer_append(output_buffer, buf,
|
||||
sizeof(buf) - incoming_stream.avail_out);
|
||||
incoming_stream.next_out = (unsigned char *) buf;
|
||||
incoming_stream.avail_out = sizeof(buf);
|
||||
sizeof(buf) - incoming_stream.avail_out);
|
||||
break;
|
||||
case Z_STREAM_END:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_END");
|
||||
/* NOTREACHED */
|
||||
case Z_DATA_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_DATA_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_STREAM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR");
|
||||
/* NOTREACHED */
|
||||
case Z_BUF_ERROR:
|
||||
/*
|
||||
* Comments in zlib.h say that we should keep calling
|
||||
@ -155,11 +135,9 @@ buffer_uncompress(Buffer * input_buffer, Buffer * output_buffer)
|
||||
* be the error that we get.
|
||||
*/
|
||||
return;
|
||||
case Z_MEM_ERROR:
|
||||
fatal("buffer_uncompress: inflate returned Z_MEM_ERROR");
|
||||
/* NOTREACHED */
|
||||
default:
|
||||
fatal("buffer_uncompress: inflate returned %d", status);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* compress.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Oct 25 22:12:46 1995 ylo
|
||||
*
|
||||
*
|
||||
* Interface to packet compression for ssh.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: compress.h,v 1.3 1999/11/24 19:53:46 markus Exp $"); */
|
||||
/* RCSID("$Id: compress.h,v 1.4 2000/04/14 10:30:31 markus Exp $"); */
|
||||
|
||||
#ifndef COMPRESS_H
|
||||
#define COMPRESS_H
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* crc32.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Tue Feb 11 14:37:27 1992 ylo
|
||||
*
|
||||
*
|
||||
* Functions for computing 32-bit CRC.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: crc32.h,v 1.4 1999/11/24 19:53:46 markus Exp $"); */
|
||||
/* RCSID("$Id: crc32.h,v 1.5 2000/04/14 10:30:31 markus Exp $"); */
|
||||
|
||||
#ifndef CRC32_H
|
||||
#define CRC32_H
|
||||
|
78
crypto/openssh/dispatch.c
Normal file
78
crypto/openssh/dispatch.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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: dispatch.c,v 1.2 2000/04/14 10:30:31 markus Exp $");
|
||||
#include "ssh.h"
|
||||
#include "dispatch.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define DISPATCH_MIN 0
|
||||
#define DISPATCH_MAX 255
|
||||
|
||||
dispatch_fn *dispatch[DISPATCH_MAX];
|
||||
|
||||
void
|
||||
dispatch_protocol_error(int type, int plen)
|
||||
{
|
||||
error("Hm, dispatch protocol error: type %d plen %d", type, plen);
|
||||
}
|
||||
void
|
||||
dispatch_init(dispatch_fn *dflt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DISPATCH_MAX; i++)
|
||||
dispatch[i] = dflt;
|
||||
}
|
||||
void
|
||||
dispatch_set(int type, dispatch_fn *fn)
|
||||
{
|
||||
dispatch[type] = fn;
|
||||
}
|
||||
void
|
||||
dispatch_run(int mode, int *done)
|
||||
{
|
||||
for (;;) {
|
||||
int plen;
|
||||
int type;
|
||||
|
||||
if (mode == DISPATCH_BLOCK) {
|
||||
type = packet_read(&plen);
|
||||
} else {
|
||||
type = packet_read_poll(&plen);
|
||||
if (type == SSH_MSG_NONE)
|
||||
return;
|
||||
}
|
||||
if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
|
||||
(*dispatch[type])(type, plen);
|
||||
else
|
||||
packet_disconnect("protocol error: rcvd type %d", type);
|
||||
if (done != NULL && *done)
|
||||
return;
|
||||
}
|
||||
}
|
11
crypto/openssh/dispatch.h
Normal file
11
crypto/openssh/dispatch.h
Normal file
@ -0,0 +1,11 @@
|
||||
enum {
|
||||
DISPATCH_BLOCK,
|
||||
DISPATCH_NONBLOCK
|
||||
};
|
||||
|
||||
typedef void dispatch_fn(int type, int plen);
|
||||
|
||||
void dispatch_init(dispatch_fn *dflt);
|
||||
void dispatch_set(int type, dispatch_fn *fn);
|
||||
void dispatch_run(int mode, int *done);
|
||||
void dispatch_protocol_error(int type, int plen);
|
300
crypto/openssh/dsa.c
Normal file
300
crypto/openssh/dsa.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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: dsa.c,v 1.7 2000/05/08 17:42:24 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "compat.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
#include "kex.h"
|
||||
#include "key.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#define INTBLOB_LEN 20
|
||||
#define SIGBLOB_LEN (2*INTBLOB_LEN)
|
||||
|
||||
Key *
|
||||
dsa_key_from_blob(
|
||||
char *blob, int blen)
|
||||
{
|
||||
Buffer b;
|
||||
char *ktype;
|
||||
int rlen;
|
||||
DSA *dsa;
|
||||
Key *key;
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
dump_base64(stderr, blob, blen);
|
||||
#endif
|
||||
/* fetch & parse DSA/DSS pubkey */
|
||||
key = key_new(KEY_DSA);
|
||||
dsa = key->dsa;
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, blob, blen);
|
||||
ktype = buffer_get_string(&b, NULL);
|
||||
if (strcmp(KEX_DSS, ktype) != 0) {
|
||||
error("dsa_key_from_blob: cannot handle type %s", ktype);
|
||||
key_free(key);
|
||||
return NULL;
|
||||
}
|
||||
buffer_get_bignum2(&b, dsa->p);
|
||||
buffer_get_bignum2(&b, dsa->q);
|
||||
buffer_get_bignum2(&b, dsa->g);
|
||||
buffer_get_bignum2(&b, dsa->pub_key);
|
||||
rlen = buffer_len(&b);
|
||||
if(rlen != 0)
|
||||
error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
|
||||
buffer_free(&b);
|
||||
|
||||
debug("keytype %s", ktype);
|
||||
#ifdef DEBUG_DSS
|
||||
DSA_print_fp(stderr, dsa, 8);
|
||||
#endif
|
||||
return key;
|
||||
}
|
||||
int
|
||||
dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
|
||||
{
|
||||
Buffer b;
|
||||
int len;
|
||||
unsigned char *buf;
|
||||
|
||||
if (key == NULL || key->type != KEY_DSA)
|
||||
return 0;
|
||||
buffer_init(&b);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_bignum2(&b, key->dsa->p);
|
||||
buffer_put_bignum2(&b, key->dsa->q);
|
||||
buffer_put_bignum2(&b, key->dsa->g);
|
||||
buffer_put_bignum2(&b, key->dsa->pub_key);
|
||||
len = buffer_len(&b);
|
||||
buf = xmalloc(len);
|
||||
memcpy(buf, buffer_ptr(&b), len);
|
||||
memset(buffer_ptr(&b), 0, len);
|
||||
buffer_free(&b);
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
if (blobp != NULL)
|
||||
*blobp = buf;
|
||||
return len;
|
||||
}
|
||||
int
|
||||
dsa_sign(
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
unsigned char *digest;
|
||||
unsigned char *ret;
|
||||
DSA_SIG *sig;
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
unsigned int rlen;
|
||||
unsigned int slen;
|
||||
unsigned int len;
|
||||
unsigned char sigblob[SIGBLOB_LEN];
|
||||
Buffer b;
|
||||
|
||||
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
|
||||
error("dsa_sign: no DSA key");
|
||||
return -1;
|
||||
}
|
||||
digest = xmalloc(evp_md->md_size);
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, data, datalen);
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
|
||||
if (sig == NULL) {
|
||||
fatal("dsa_sign: cannot sign");
|
||||
}
|
||||
|
||||
rlen = BN_num_bytes(sig->r);
|
||||
slen = BN_num_bytes(sig->s);
|
||||
if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
|
||||
error("bad sig size %d %d", rlen, slen);
|
||||
DSA_SIG_free(sig);
|
||||
return -1;
|
||||
}
|
||||
debug("sig size %d %d", rlen, slen);
|
||||
|
||||
memset(sigblob, 0, SIGBLOB_LEN);
|
||||
BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
|
||||
BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
if (datafellows & SSH_BUG_SIGBLOB) {
|
||||
debug("datafellows");
|
||||
ret = xmalloc(SIGBLOB_LEN);
|
||||
memcpy(ret, sigblob, SIGBLOB_LEN);
|
||||
if (lenp != NULL)
|
||||
*lenp = SIGBLOB_LEN;
|
||||
if (sigp != NULL)
|
||||
*sigp = ret;
|
||||
} else {
|
||||
/* ietf-drafts */
|
||||
buffer_init(&b);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, sigblob, SIGBLOB_LEN);
|
||||
len = buffer_len(&b);
|
||||
ret = xmalloc(len);
|
||||
memcpy(ret, buffer_ptr(&b), len);
|
||||
buffer_free(&b);
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
if (sigp != NULL)
|
||||
*sigp = ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
dsa_verify(
|
||||
Key *key,
|
||||
unsigned char *signature, int signaturelen,
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
Buffer b;
|
||||
unsigned char *digest;
|
||||
DSA_SIG *sig;
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
char *ktype;
|
||||
unsigned char *sigblob;
|
||||
char *txt;
|
||||
unsigned int len;
|
||||
int rlen;
|
||||
int ret;
|
||||
|
||||
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
|
||||
error("dsa_verify: no DSA key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(datafellows & SSH_BUG_SIGBLOB) &&
|
||||
signaturelen == SIGBLOB_LEN) {
|
||||
datafellows |= ~SSH_BUG_SIGBLOB;
|
||||
log("autodetect SSH_BUG_SIGBLOB");
|
||||
} else if ((datafellows & SSH_BUG_SIGBLOB) &&
|
||||
signaturelen != SIGBLOB_LEN) {
|
||||
log("autoremove SSH_BUG_SIGBLOB");
|
||||
datafellows &= ~SSH_BUG_SIGBLOB;
|
||||
}
|
||||
|
||||
debug("len %d datafellows %d", signaturelen, datafellows);
|
||||
|
||||
/* fetch signature */
|
||||
if (datafellows & SSH_BUG_SIGBLOB) {
|
||||
sigblob = signature;
|
||||
len = signaturelen;
|
||||
} else {
|
||||
/* ietf-drafts */
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, (char *) signature, signaturelen);
|
||||
ktype = buffer_get_string(&b, NULL);
|
||||
sigblob = (unsigned char *)buffer_get_string(&b, &len);
|
||||
rlen = buffer_len(&b);
|
||||
if(rlen != 0)
|
||||
error("remaining bytes in signature %d", rlen);
|
||||
buffer_free(&b);
|
||||
}
|
||||
|
||||
if (len != SIGBLOB_LEN) {
|
||||
fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
|
||||
}
|
||||
|
||||
/* parse signature */
|
||||
sig = DSA_SIG_new();
|
||||
sig->r = BN_new();
|
||||
sig->s = BN_new();
|
||||
BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
|
||||
BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
|
||||
|
||||
if (!(datafellows & SSH_BUG_SIGBLOB)) {
|
||||
memset(sigblob, 0, len);
|
||||
xfree(sigblob);
|
||||
}
|
||||
|
||||
/* sha1 the data */
|
||||
digest = xmalloc(evp_md->md_size);
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, data, datalen);
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
|
||||
|
||||
memset(digest, 0, evp_md->md_size);
|
||||
xfree(digest);
|
||||
DSA_SIG_free(sig);
|
||||
|
||||
switch (ret) {
|
||||
case 1:
|
||||
txt = "correct";
|
||||
break;
|
||||
case 0:
|
||||
txt = "incorrect";
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
txt = "error";
|
||||
break;
|
||||
}
|
||||
debug("dsa_verify: signature %s", txt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Key *
|
||||
dsa_generate_key(unsigned int bits)
|
||||
{
|
||||
DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
|
||||
Key *k;
|
||||
if (dsa == NULL) {
|
||||
fatal("DSA_generate_parameters failed");
|
||||
}
|
||||
if (!DSA_generate_key(dsa)) {
|
||||
fatal("DSA_generate_keys failed");
|
||||
}
|
||||
|
||||
k = key_new(KEY_EMPTY);
|
||||
k->type = KEY_DSA;
|
||||
k->dsa = dsa;
|
||||
return k;
|
||||
}
|
22
crypto/openssh/dsa.h
Normal file
22
crypto/openssh/dsa.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef DSA_H
|
||||
#define DSA_H
|
||||
|
||||
Key *dsa_key_from_blob(char *blob, int blen);
|
||||
int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
|
||||
|
||||
int
|
||||
dsa_sign(
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
int
|
||||
dsa_verify(
|
||||
Key *key,
|
||||
unsigned char *signature, int signaturelen,
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
Key *
|
||||
dsa_generate_key(unsigned int bits);
|
||||
|
||||
#endif
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* getput.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Jun 28 22:36:30 1995 ylo
|
||||
*
|
||||
*
|
||||
* Macros for storing and retrieving data in msb first and lsb first order.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: getput.h,v 1.2 1999/11/24 00:26:02 deraadt Exp $"); */
|
||||
/* RCSID("$Id: getput.h,v 1.3 2000/04/14 10:30:31 markus Exp $"); */
|
||||
|
||||
#ifndef GETPUT_H
|
||||
#define GETPUT_H
|
||||
@ -21,7 +21,7 @@
|
||||
/*------------ macros for storing/extracting msb first words -------------*/
|
||||
|
||||
#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \
|
||||
((unsigned long)(unsigned char)(cp)[1] << 16) | \
|
||||
((unsigned long)(unsigned char)(cp)[1] << 16) | \
|
||||
((unsigned long)(unsigned char)(cp)[2] << 8) | \
|
||||
((unsigned long)(unsigned char)(cp)[3]))
|
||||
|
||||
|
59
crypto/openssh/hmac.c
Normal file
59
crypto/openssh/hmac.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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: hmac.c,v 1.2 2000/04/12 09:39:10 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
unsigned char *
|
||||
hmac(
|
||||
EVP_MD *evp_md,
|
||||
unsigned int seqno,
|
||||
unsigned char *data, int datalen,
|
||||
unsigned char *key, int keylen)
|
||||
{
|
||||
HMAC_CTX c;
|
||||
static unsigned char m[EVP_MAX_MD_SIZE];
|
||||
unsigned char b[4];
|
||||
|
||||
if (key == NULL)
|
||||
fatal("hmac: no key");
|
||||
HMAC_Init(&c, key, keylen, evp_md);
|
||||
PUT_32BIT(b, seqno);
|
||||
HMAC_Update(&c, b, sizeof b);
|
||||
HMAC_Update(&c, data, datalen);
|
||||
HMAC_Final(&c, m, NULL);
|
||||
HMAC_cleanup(&c);
|
||||
return(m);
|
||||
}
|
11
crypto/openssh/hmac.h
Normal file
11
crypto/openssh/hmac.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef HMAC_H
|
||||
#define HMAC_H
|
||||
|
||||
unsigned char *
|
||||
hmac(
|
||||
EVP_MD *evp_md,
|
||||
unsigned int seqno,
|
||||
unsigned char *data, int datalen,
|
||||
unsigned char *key, int len);
|
||||
|
||||
#endif
|
@ -10,7 +10,7 @@
|
||||
typedef enum {
|
||||
HOST_OK, HOST_NEW, HOST_CHANGED
|
||||
} HostStatus;
|
||||
HostStatus
|
||||
HostStatus
|
||||
check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found);
|
||||
|
||||
/*
|
||||
|
424
crypto/openssh/kex.c
Normal file
424
crypto/openssh/kex.c
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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: kex.c,v 1.6 2000/05/08 17:42:25 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "ssh2.h"
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "cipher.h"
|
||||
#include "compat.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include "kex.h"
|
||||
|
||||
Buffer *
|
||||
kex_init(char *myproposal[PROPOSAL_MAX])
|
||||
{
|
||||
char c = 0;
|
||||
unsigned char cookie[16];
|
||||
u_int32_t rand = 0;
|
||||
int i;
|
||||
Buffer *ki = xmalloc(sizeof(*ki));
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
cookie[i] = rand & 0xff;
|
||||
rand >>= 8;
|
||||
}
|
||||
buffer_init(ki);
|
||||
buffer_append(ki, (char *)cookie, sizeof cookie);
|
||||
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||
buffer_put_cstring(ki, myproposal[i]);
|
||||
buffer_append(ki, &c, 1); /* boolean first_kex_packet_follows */
|
||||
buffer_put_int(ki, 0); /* uint32 0 (reserved for future extension) */
|
||||
return ki;
|
||||
}
|
||||
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
|
||||
int
|
||||
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
|
||||
{
|
||||
int i;
|
||||
int n = BN_num_bits(dh_pub);
|
||||
int bits_set = 0;
|
||||
|
||||
/* we only accept g==2 */
|
||||
if (!BN_is_word(dh->g, 2)) {
|
||||
log("invalid DH base != 2");
|
||||
return 0;
|
||||
}
|
||||
if (dh_pub->neg) {
|
||||
log("invalid public DH value: negativ");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i <= n; i++)
|
||||
if (BN_is_bit_set(dh_pub, i))
|
||||
bits_set++;
|
||||
debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
|
||||
|
||||
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
|
||||
if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
|
||||
return 1;
|
||||
log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DH *
|
||||
dh_new_group1()
|
||||
{
|
||||
static char *group1 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
DH *dh;
|
||||
int ret, tries = 0;
|
||||
dh = DH_new();
|
||||
if(dh == NULL)
|
||||
fatal("DH_new");
|
||||
ret = BN_hex2bn(&dh->p, group1);
|
||||
if(ret<0)
|
||||
fatal("BN_hex2bn");
|
||||
dh->g = BN_new();
|
||||
if(dh->g == NULL)
|
||||
fatal("DH_new g");
|
||||
BN_set_word(dh->g, 2);
|
||||
do {
|
||||
if (DH_generate_key(dh) == 0)
|
||||
fatal("DH_generate_key");
|
||||
if (tries++ > 10)
|
||||
fatal("dh_new_group1: too many bad keys: giving up");
|
||||
} while (!dh_pub_is_valid(dh, dh->pub_key));
|
||||
return dh;
|
||||
}
|
||||
|
||||
void
|
||||
bignum_print(BIGNUM *b)
|
||||
{
|
||||
BN_print_fp(stderr,b);
|
||||
}
|
||||
|
||||
void
|
||||
dump_digest(unsigned char *digest, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i< len; i++){
|
||||
fprintf(stderr, "%02x", digest[i]);
|
||||
if(i%2!=0)
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
kex_hash(
|
||||
char *client_version_string,
|
||||
char *server_version_string,
|
||||
char *ckexinit, int ckexinitlen,
|
||||
char *skexinit, int skexinitlen,
|
||||
char *serverhostkeyblob, int sbloblen,
|
||||
BIGNUM *client_dh_pub,
|
||||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret)
|
||||
{
|
||||
Buffer b;
|
||||
static unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
|
||||
buffer_init(&b);
|
||||
buffer_put_string(&b, client_version_string, strlen(client_version_string));
|
||||
buffer_put_string(&b, server_version_string, strlen(server_version_string));
|
||||
|
||||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
|
||||
buffer_put_int(&b, ckexinitlen+1);
|
||||
buffer_put_char(&b, SSH2_MSG_KEXINIT);
|
||||
buffer_append(&b, ckexinit, ckexinitlen);
|
||||
buffer_put_int(&b, skexinitlen+1);
|
||||
buffer_put_char(&b, SSH2_MSG_KEXINIT);
|
||||
buffer_append(&b, skexinit, skexinitlen);
|
||||
|
||||
buffer_put_string(&b, serverhostkeyblob, sbloblen);
|
||||
buffer_put_bignum2(&b, client_dh_pub);
|
||||
buffer_put_bignum2(&b, server_dh_pub);
|
||||
buffer_put_bignum2(&b, shared_secret);
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
buffer_free(&b);
|
||||
|
||||
#ifdef DEBUG_KEX
|
||||
dump_digest(digest, evp_md->md_size);
|
||||
#endif
|
||||
return digest;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
|
||||
{
|
||||
Buffer b;
|
||||
EVP_MD *evp_md = EVP_sha1();
|
||||
EVP_MD_CTX md;
|
||||
char c = id;
|
||||
int have;
|
||||
int mdsz = evp_md->md_size;
|
||||
unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
|
||||
|
||||
buffer_init(&b);
|
||||
buffer_put_bignum2(&b, shared_secret);
|
||||
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
|
||||
EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
|
||||
EVP_DigestUpdate(&md, &c, 1); /* key id */
|
||||
EVP_DigestUpdate(&md, hash, mdsz); /* session id */
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
/* expand */
|
||||
for (have = mdsz; need > have; have += mdsz) {
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
|
||||
EVP_DigestUpdate(&md, hash, mdsz);
|
||||
EVP_DigestUpdate(&md, digest, have);
|
||||
EVP_DigestFinal(&md, digest + have, NULL);
|
||||
}
|
||||
buffer_free(&b);
|
||||
#ifdef DEBUG_KEX
|
||||
fprintf(stderr, "Digest '%c'== ", c);
|
||||
dump_digest(digest, need);
|
||||
#endif
|
||||
return digest;
|
||||
}
|
||||
|
||||
#define NKEYS 6
|
||||
|
||||
#define MAX_PROP 20
|
||||
#define SEP ","
|
||||
|
||||
char *
|
||||
get_match(char *client, char *server)
|
||||
{
|
||||
char *sproposals[MAX_PROP];
|
||||
char *p;
|
||||
int i, j, nproposals;
|
||||
|
||||
for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
|
||||
if (i < MAX_PROP)
|
||||
sproposals[i] = p;
|
||||
else
|
||||
break;
|
||||
}
|
||||
nproposals = i;
|
||||
|
||||
for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
|
||||
for (j = 0; j < nproposals; j++)
|
||||
if (strcmp(p, sproposals[j]) == 0)
|
||||
return xstrdup(p);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void
|
||||
choose_enc(Enc *enc, char *client, char *server)
|
||||
{
|
||||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching cipher found: client %s server %s", client, server);
|
||||
enc->type = cipher_number(name);
|
||||
|
||||
switch (enc->type) {
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
enc->key_len = 24;
|
||||
enc->iv_len = 8;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
enc->key_len = 16;
|
||||
enc->iv_len = 8;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
enc->key_len = 16;
|
||||
enc->iv_len = 0;
|
||||
enc->block_size = 8;
|
||||
break;
|
||||
default:
|
||||
fatal("unsupported cipher %s", name);
|
||||
}
|
||||
enc->name = name;
|
||||
enc->enabled = 0;
|
||||
enc->iv = NULL;
|
||||
enc->key = NULL;
|
||||
}
|
||||
void
|
||||
choose_mac(Mac *mac, char *client, char *server)
|
||||
{
|
||||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching mac found: client %s server %s", client, server);
|
||||
if (strcmp(name, "hmac-md5") == 0) {
|
||||
mac->md = EVP_md5();
|
||||
} else if (strcmp(name, "hmac-sha1") == 0) {
|
||||
mac->md = EVP_sha1();
|
||||
} else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
|
||||
mac->md = EVP_ripemd160();
|
||||
} else {
|
||||
fatal("unsupported mac %s", name);
|
||||
}
|
||||
mac->name = name;
|
||||
mac->mac_len = mac->md->md_size;
|
||||
mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
|
||||
mac->key = NULL;
|
||||
mac->enabled = 0;
|
||||
}
|
||||
void
|
||||
choose_comp(Comp *comp, char *client, char *server)
|
||||
{
|
||||
char *name = get_match(client, server);
|
||||
if (name == NULL)
|
||||
fatal("no matching comp found: client %s server %s", client, server);
|
||||
if (strcmp(name, "zlib") == 0) {
|
||||
comp->type = 1;
|
||||
} else if (strcmp(name, "none") == 0) {
|
||||
comp->type = 0;
|
||||
} else {
|
||||
fatal("unsupported comp %s", name);
|
||||
}
|
||||
comp->name = name;
|
||||
}
|
||||
void
|
||||
choose_kex(Kex *k, char *client, char *server)
|
||||
{
|
||||
k->name = get_match(client, server);
|
||||
if (k->name == NULL)
|
||||
fatal("no kex alg");
|
||||
if (strcmp(k->name, KEX_DH1) != 0)
|
||||
fatal("bad kex alg %s", k->name);
|
||||
}
|
||||
void
|
||||
choose_hostkeyalg(Kex *k, char *client, char *server)
|
||||
{
|
||||
k->hostkeyalg = get_match(client, server);
|
||||
if (k->hostkeyalg == NULL)
|
||||
fatal("no hostkey alg");
|
||||
if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
|
||||
fatal("bad hostkey alg %s", k->hostkeyalg);
|
||||
}
|
||||
|
||||
Kex *
|
||||
kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
|
||||
{
|
||||
int i;
|
||||
int mode;
|
||||
int ctos; /* direction: if true client-to-server */
|
||||
int need;
|
||||
Kex *k;
|
||||
|
||||
k = xmalloc(sizeof(*k));
|
||||
memset(k, 0, sizeof(*k));
|
||||
k->server = server;
|
||||
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
int nenc, nmac, ncomp;
|
||||
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
|
||||
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
|
||||
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
|
||||
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
|
||||
choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
|
||||
choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
|
||||
choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
|
||||
debug("kex: %s %s %s %s",
|
||||
ctos ? "client->server" : "server->client",
|
||||
k->enc[mode].name,
|
||||
k->mac[mode].name,
|
||||
k->comp[mode].name);
|
||||
}
|
||||
choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
|
||||
choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
|
||||
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
|
||||
for (i = 0; i < PROPOSAL_MAX; i++) {
|
||||
xfree(cprop[i]);
|
||||
xfree(sprop[i]);
|
||||
}
|
||||
need = 0;
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
if (need < k->enc[mode].key_len)
|
||||
need = k->enc[mode].key_len;
|
||||
if (need < k->enc[mode].iv_len)
|
||||
need = k->enc[mode].iv_len;
|
||||
if (need < k->mac[mode].key_len)
|
||||
need = k->mac[mode].key_len;
|
||||
}
|
||||
/* need runden? */
|
||||
#define WE_NEED 32
|
||||
k->we_need = WE_NEED;
|
||||
k->we_need = need;
|
||||
return k;
|
||||
}
|
||||
|
||||
int
|
||||
kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
|
||||
{
|
||||
int i;
|
||||
int mode;
|
||||
int ctos;
|
||||
unsigned char *keys[NKEYS];
|
||||
|
||||
for (i = 0; i < NKEYS; i++)
|
||||
keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
|
||||
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
|
||||
k->enc[mode].iv = keys[ctos ? 0 : 1];
|
||||
k->enc[mode].key = keys[ctos ? 2 : 3];
|
||||
k->mac[mode].key = keys[ctos ? 4 : 5];
|
||||
}
|
||||
return 0;
|
||||
}
|
112
crypto/openssh/kex.h
Normal file
112
crypto/openssh/kex.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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.
|
||||
*/
|
||||
#ifndef KEX_H
|
||||
#define KEX_H
|
||||
|
||||
#define KEX_DH1 "diffie-hellman-group1-sha1"
|
||||
#define KEX_DSS "ssh-dss"
|
||||
|
||||
enum kex_init_proposals {
|
||||
PROPOSAL_KEX_ALGS,
|
||||
PROPOSAL_SERVER_HOST_KEY_ALGS,
|
||||
PROPOSAL_ENC_ALGS_CTOS,
|
||||
PROPOSAL_ENC_ALGS_STOC,
|
||||
PROPOSAL_MAC_ALGS_CTOS,
|
||||
PROPOSAL_MAC_ALGS_STOC,
|
||||
PROPOSAL_COMP_ALGS_CTOS,
|
||||
PROPOSAL_COMP_ALGS_STOC,
|
||||
PROPOSAL_LANG_CTOS,
|
||||
PROPOSAL_LANG_STOC,
|
||||
PROPOSAL_MAX
|
||||
};
|
||||
|
||||
enum kex_modes {
|
||||
MODE_IN,
|
||||
MODE_OUT,
|
||||
MODE_MAX
|
||||
};
|
||||
|
||||
typedef struct Kex Kex;
|
||||
typedef struct Mac Mac;
|
||||
typedef struct Comp Comp;
|
||||
typedef struct Enc Enc;
|
||||
|
||||
struct Enc {
|
||||
int type;
|
||||
int enabled;
|
||||
int block_size;
|
||||
unsigned char *key;
|
||||
unsigned char *iv;
|
||||
int key_len;
|
||||
int iv_len;
|
||||
char *name;
|
||||
};
|
||||
struct Mac {
|
||||
EVP_MD *md;
|
||||
int enabled;
|
||||
int mac_len;
|
||||
unsigned char *key;
|
||||
int key_len;
|
||||
char *name;
|
||||
};
|
||||
struct Comp {
|
||||
int type;
|
||||
int enabled;
|
||||
char *name;
|
||||
};
|
||||
struct Kex {
|
||||
Enc enc [MODE_MAX];
|
||||
Mac mac [MODE_MAX];
|
||||
Comp comp[MODE_MAX];
|
||||
int we_need;
|
||||
int server;
|
||||
char *name;
|
||||
char *hostkeyalg;
|
||||
};
|
||||
|
||||
Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
|
||||
int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub);
|
||||
DH *dh_new_group1();
|
||||
Kex *kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server);
|
||||
int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
|
||||
void bignum_print(BIGNUM *b);
|
||||
void packet_set_kex(Kex *k);
|
||||
|
||||
unsigned char *
|
||||
kex_hash(
|
||||
char *client_version_string,
|
||||
char *server_version_string,
|
||||
char *ckexinit, int ckexinitlen,
|
||||
char *skexinit, int skexinitlen,
|
||||
char *serverhostkeyblob, int sbloblen,
|
||||
BIGNUM *client_dh_pub,
|
||||
BIGNUM *server_dh_pub,
|
||||
BIGNUM *shared_secret);
|
||||
|
||||
#endif
|
@ -17,7 +17,9 @@ Key *key_new(int type);
|
||||
void key_free(Key *k);
|
||||
int key_equal(Key *a, Key *b);
|
||||
char *key_fingerprint(Key *k);
|
||||
char *key_type(Key *k);
|
||||
int key_write(Key *key, FILE *f);
|
||||
int key_read(Key *key, unsigned int bits, char **cpp);
|
||||
unsigned int
|
||||
key_read(Key *key, char **cpp);
|
||||
|
||||
#endif
|
||||
|
@ -5,7 +5,7 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
|
||||
cipher.c compat.c compress.c crc32.c deattack.c fingerprint.c \
|
||||
hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \
|
||||
rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \
|
||||
key.c
|
||||
key.c dispatch.c dsa.c kex.c hmac.c uuencode.c
|
||||
|
||||
NOPROFILE= yes
|
||||
NOPIC= yes
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* log-client.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Mon Mar 20 21:13:40 1995 ylo
|
||||
*
|
||||
*
|
||||
* Client-side versions of debug(), log(), etc. These print to stderr.
|
||||
* This is a stripped down version of log-server.c.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: log-client.c,v 1.7 2000/02/27 18:50:09 deraadt Exp $");
|
||||
RCSID("$Id: log-client.c,v 1.8 2000/04/14 10:30:31 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* log-server.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Mon Mar 20 21:19:30 1995 ylo
|
||||
*
|
||||
*
|
||||
* Server-side versions of debug(), log(), etc. These normally send the output
|
||||
* to the system log.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: log-server.c,v 1.12 2000/02/27 18:50:09 deraadt Exp $");
|
||||
RCSID("$Id: log-server.c,v 1.14 2000/04/14 10:30:31 markus Exp $");
|
||||
|
||||
#include <syslog.h>
|
||||
#include "packet.h"
|
||||
@ -32,7 +32,7 @@ static int log_facility = LOG_AUTH;
|
||||
* level logging level
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
||||
{
|
||||
switch (level) {
|
||||
@ -132,9 +132,11 @@ do_log(LogLevel level, const char *fmt, va_list args)
|
||||
} else {
|
||||
vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
|
||||
}
|
||||
if (log_on_stderr)
|
||||
if (log_on_stderr) {
|
||||
fprintf(stderr, "%s\n", msgbuf);
|
||||
openlog(__progname, LOG_PID, log_facility);
|
||||
syslog(pri, "%.500s", msgbuf);
|
||||
closelog();
|
||||
} else {
|
||||
openlog(__progname, LOG_PID, log_facility);
|
||||
syslog(pri, "%.500s", msgbuf);
|
||||
closelog();
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* match.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Thu Jun 22 01:17:50 1995 ylo
|
||||
*
|
||||
*
|
||||
* Simple pattern matching, with '*' and '?' as wildcards.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: match.c,v 1.5 2000/03/23 22:15:33 markus Exp $");
|
||||
RCSID("$Id: match.c,v 1.6 2000/04/14 10:30:31 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
@ -23,7 +23,7 @@ RCSID("$Id: match.c,v 1.5 2000/03/23 22:15:33 markus Exp $");
|
||||
* and * as wildcards), and zero if it does not match.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
match_pattern(const char *s, const char *pattern)
|
||||
{
|
||||
for (;;) {
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* mpaux.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sun Jul 16 04:29:30 1995 ylo
|
||||
*
|
||||
*
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: mpaux.h,v 1.5 1999/11/24 19:53:48 markus Exp $"); */
|
||||
/* RCSID("$Id: mpaux.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */
|
||||
|
||||
#ifndef MPAUX_H
|
||||
#define MPAUX_H
|
||||
@ -23,7 +23,7 @@
|
||||
* session id is computed by concatenating the linearized, msb first
|
||||
* representations of host_key_n, session_key_n, and the cookie.
|
||||
*/
|
||||
void
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
BIGNUM * host_key_n,
|
||||
|
20
crypto/openssh/myproposal.h
Normal file
20
crypto/openssh/myproposal.h
Normal file
@ -0,0 +1,20 @@
|
||||
#define KEX_DEFAULT_KEX "diffie-hellman-group1-sha1"
|
||||
#define KEX_DEFAULT_PK_ALG "ssh-dss"
|
||||
#define KEX_DEFAULT_ENCRYPT "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
|
||||
#define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5,hmac-ripemd160@openssh.com"
|
||||
#define KEX_DEFAULT_COMP "zlib,none"
|
||||
#define KEX_DEFAULT_LANG ""
|
||||
|
||||
|
||||
static const char *myproposal[PROPOSAL_MAX] = {
|
||||
KEX_DEFAULT_KEX,
|
||||
KEX_DEFAULT_PK_ALG,
|
||||
KEX_DEFAULT_ENCRYPT,
|
||||
KEX_DEFAULT_ENCRYPT,
|
||||
KEX_DEFAULT_MAC,
|
||||
KEX_DEFAULT_MAC,
|
||||
KEX_DEFAULT_COMP,
|
||||
KEX_DEFAULT_COMP,
|
||||
KEX_DEFAULT_LANG,
|
||||
KEX_DEFAULT_LANG
|
||||
};
|
@ -28,7 +28,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
|
||||
RCSID("$Id: nchan.c,v 1.17 2000/05/08 17:44:54 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
@ -37,143 +37,192 @@ RCSID("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
|
||||
#include "channels.h"
|
||||
#include "nchan.h"
|
||||
|
||||
static void chan_send_ieof(Channel *c);
|
||||
static void chan_send_oclose(Channel *c);
|
||||
static void chan_shutdown_write(Channel *c);
|
||||
static void chan_shutdown_read(Channel *c);
|
||||
static void chan_delete_if_full_closed(Channel *c);
|
||||
#include "ssh2.h"
|
||||
#include "compat.h"
|
||||
|
||||
/* functions manipulating channel states */
|
||||
/*
|
||||
* EVENTS update channel input/output states execute ACTIONS
|
||||
*/
|
||||
|
||||
/* events concerning the INPUT from socket for channel (istate) */
|
||||
void
|
||||
chan_rcvd_oclose(Channel *c)
|
||||
chan_event_fn *chan_rcvd_oclose = NULL;
|
||||
chan_event_fn *chan_read_failed = NULL;
|
||||
chan_event_fn *chan_ibuf_empty = NULL;
|
||||
/* events concerning the OUTPUT from channel for socket (ostate) */
|
||||
chan_event_fn *chan_rcvd_ieof = NULL;
|
||||
chan_event_fn *chan_write_failed = NULL;
|
||||
chan_event_fn *chan_obuf_empty = NULL;
|
||||
/*
|
||||
* ACTIONS: should never update the channel states
|
||||
*/
|
||||
static void chan_send_ieof1(Channel *c);
|
||||
static void chan_send_oclose1(Channel *c);
|
||||
static void chan_send_close2(Channel *c);
|
||||
static void chan_send_eof2(Channel *c);
|
||||
|
||||
/* channel cleanup */
|
||||
chan_event_fn *chan_delete_if_full_closed = NULL;
|
||||
|
||||
/* helper */
|
||||
static void chan_shutdown_write(Channel *c);
|
||||
static void chan_shutdown_read(Channel *c);
|
||||
|
||||
/*
|
||||
* SSH1 specific implementation of event functions
|
||||
*/
|
||||
|
||||
static void
|
||||
chan_rcvd_oclose1(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd oclose", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_OCLOSE:
|
||||
debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
|
||||
debug("channel %d: input wait_oclose -> closed", c->self);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
debug("channel %d: input open -> closed", c->self);
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof(c);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
/* both local read_failed and remote write_failed */
|
||||
log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
|
||||
chan_send_ieof(c);
|
||||
log("channel %d: input drain -> closed", c->self);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
|
||||
error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
|
||||
c->self, c->istate);
|
||||
return;
|
||||
}
|
||||
chan_delete_if_full_closed(c);
|
||||
}
|
||||
void
|
||||
chan_read_failed(Channel *c)
|
||||
static void
|
||||
chan_read_failed_12(Channel *c)
|
||||
{
|
||||
debug("channel %d: read failed", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
|
||||
debug("channel %d: input open -> drain", c->self);
|
||||
chan_shutdown_read(c);
|
||||
c->istate = CHAN_INPUT_WAIT_DRAIN;
|
||||
if (buffer_len(&c->input) == 0) {
|
||||
debug("channel %d: input: no drain shortcut", c->self);
|
||||
chan_ibuf_empty(c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("internal error: we do not read, but chan_read_failed %d for istate %d",
|
||||
c->self, c->istate);
|
||||
error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_ibuf_empty(Channel *c)
|
||||
static void
|
||||
chan_ibuf_empty1(Channel *c)
|
||||
{
|
||||
debug("channel %d: ibuf empty", c->self);
|
||||
if (buffer_len(&c->input)) {
|
||||
error("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
|
||||
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
|
||||
chan_send_ieof(c);
|
||||
debug("channel %d: input drain -> wait_oclose", c->self);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_WAIT_OCLOSE;
|
||||
break;
|
||||
default:
|
||||
error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
|
||||
error("channel %d: internal error: chan_ibuf_empty for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* events concerning the OUTPUT from channel for socket (ostate) */
|
||||
void
|
||||
chan_rcvd_ieof(Channel *c)
|
||||
static void
|
||||
chan_rcvd_ieof1(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd ieof", c->self);
|
||||
if (c->type != SSH_CHANNEL_OPEN) {
|
||||
debug("channel %d: non-open", c->self);
|
||||
if (c->istate == CHAN_INPUT_OPEN) {
|
||||
debug("channel %d: non-open: input open -> wait_oclose", c->self);
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof1(c);
|
||||
c->istate = CHAN_INPUT_WAIT_OCLOSE;
|
||||
} else {
|
||||
error("channel %d: istate %d != open", c->self, c->istate);
|
||||
}
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN) {
|
||||
debug("channel %d: non-open: output open -> closed", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
} else {
|
||||
error("channel %d: ostate %d != open", c->self, c->ostate);
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
|
||||
debug("channel %d: output open -> drain", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_IEOF:
|
||||
debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
|
||||
debug("channel %d: output wait_ieof -> closed", c->self);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delete_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
|
||||
error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_write_failed(Channel *c)
|
||||
static void
|
||||
chan_write_failed1(Channel *c)
|
||||
{
|
||||
debug("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
|
||||
chan_send_oclose(c);
|
||||
debug("channel %d: output open -> wait_ieof", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_IEOF;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
|
||||
chan_send_oclose(c);
|
||||
debug("channel %d: output wait_drain -> closed", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delete_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
|
||||
error("channel %d: internal error: chan_write_failed for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_obuf_empty(Channel *c)
|
||||
static void
|
||||
chan_obuf_empty1(Channel *c)
|
||||
{
|
||||
debug("channel %d: obuf empty", c->self);
|
||||
if (buffer_len(&c->output)) {
|
||||
debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
|
||||
error("channel %d: internal error: chan_obuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
|
||||
chan_send_oclose(c);
|
||||
debug("channel %d: output drain -> closed", c->self);
|
||||
chan_send_oclose1(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
chan_delete_if_full_closed(c);
|
||||
break;
|
||||
default:
|
||||
error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
|
||||
error("channel %d: internal error: chan_obuf_empty for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ACTIONS: should never update the channel states: c->istate or c->ostate
|
||||
*/
|
||||
static void
|
||||
chan_send_ieof(Channel *c)
|
||||
chan_send_ieof1(Channel *c)
|
||||
{
|
||||
debug("channel %d: send ieof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
@ -182,13 +231,15 @@ chan_send_ieof(Channel *c)
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
|
||||
error("channel %d: internal error: cannot send ieof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_oclose(Channel *c)
|
||||
chan_send_oclose1(Channel *c)
|
||||
{
|
||||
debug("channel %d: send oclose", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
@ -199,40 +250,246 @@ chan_send_oclose(Channel *c)
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
|
||||
error("channel %d: internal error: cannot send oclose for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_delete_if_full_closed1(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
debug("channel %d: full closed", c->self);
|
||||
channel_free(c->self);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the same for SSH2
|
||||
*/
|
||||
static void
|
||||
chan_rcvd_oclose2(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd close", c->self);
|
||||
if (c->flags & CHAN_CLOSE_RCVD)
|
||||
error("channel %d: protocol error: close rcvd twice", c->self);
|
||||
c->flags |= CHAN_CLOSE_RCVD;
|
||||
if (c->type == SSH_CHANNEL_LARVAL) {
|
||||
/* tear down larval channels immediately */
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
/* wait until a data from the channel is consumed if a CLOSE is received */
|
||||
debug("channel %d: output open -> drain", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
break;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
debug("channel %d: input open -> closed", c->self);
|
||||
chan_shutdown_read(c);
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: input drain -> closed", c->self);
|
||||
chan_send_eof2(c);
|
||||
break;
|
||||
}
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
}
|
||||
static void
|
||||
chan_ibuf_empty2(Channel *c)
|
||||
{
|
||||
debug("channel %d: ibuf empty", c->self);
|
||||
if (buffer_len(&c->input)) {
|
||||
error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
debug("channel %d: input drain -> closed", c->self);
|
||||
if (!(c->flags & CHAN_CLOSE_SENT))
|
||||
chan_send_eof2(c);
|
||||
c->istate = CHAN_INPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_ibuf_empty for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_ieof2(Channel *c)
|
||||
{
|
||||
debug("channel %d: rcvd eof", c->self);
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN) {
|
||||
debug("channel %d: output open -> drain", c->self);
|
||||
c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_write_failed2(Channel *c)
|
||||
{
|
||||
debug("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
debug("channel %d: output open -> closed", c->self);
|
||||
chan_shutdown_write(c); /* ?? */
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: output drain -> closed", c->self);
|
||||
chan_shutdown_write(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_write_failed for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_obuf_empty2(Channel *c)
|
||||
{
|
||||
debug("channel %d: obuf empty", c->self);
|
||||
if (buffer_len(&c->output)) {
|
||||
error("internal error: chan_obuf_empty %d for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
debug("channel %d: output drain -> closed", c->self);
|
||||
chan_shutdown_write(c);
|
||||
c->ostate = CHAN_OUTPUT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: chan_obuf_empty for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_eof2(Channel *c)
|
||||
{
|
||||
debug("channel %d: send eof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH2_MSG_CHANNEL_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("channel %d: internal error: cannot send eof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_close2(Channel *c)
|
||||
{
|
||||
debug("channel %d: send close", c->self);
|
||||
if (c->ostate != CHAN_OUTPUT_CLOSED ||
|
||||
c->istate != CHAN_INPUT_CLOSED) {
|
||||
error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
|
||||
c->self, c->istate, c->ostate);
|
||||
} else if (c->flags & CHAN_CLOSE_SENT) {
|
||||
error("channel %d: internal error: already sent close", c->self);
|
||||
} else {
|
||||
packet_start(SSH2_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_delete_if_full_closed2(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
if (!(c->flags & CHAN_CLOSE_SENT)) {
|
||||
chan_send_close2(c);
|
||||
}
|
||||
if ((c->flags & CHAN_CLOSE_SENT) &&
|
||||
(c->flags & CHAN_CLOSE_RCVD)) {
|
||||
debug("channel %d: full closed2", c->self);
|
||||
channel_free(c->self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* shared */
|
||||
void
|
||||
chan_init_iostates(Channel *c)
|
||||
{
|
||||
c->ostate = CHAN_OUTPUT_OPEN;
|
||||
c->istate = CHAN_INPUT_OPEN;
|
||||
c->flags = 0;
|
||||
}
|
||||
|
||||
/* init */
|
||||
void
|
||||
chan_init(void)
|
||||
{
|
||||
if (compat20) {
|
||||
chan_rcvd_oclose = chan_rcvd_oclose2;
|
||||
chan_read_failed = chan_read_failed_12;
|
||||
chan_ibuf_empty = chan_ibuf_empty2;
|
||||
|
||||
chan_rcvd_ieof = chan_rcvd_ieof2;
|
||||
chan_write_failed = chan_write_failed2;
|
||||
chan_obuf_empty = chan_obuf_empty2;
|
||||
|
||||
chan_delete_if_full_closed = chan_delete_if_full_closed2;
|
||||
} else {
|
||||
chan_rcvd_oclose = chan_rcvd_oclose1;
|
||||
chan_read_failed = chan_read_failed_12;
|
||||
chan_ibuf_empty = chan_ibuf_empty1;
|
||||
|
||||
chan_rcvd_ieof = chan_rcvd_ieof1;
|
||||
chan_write_failed = chan_write_failed1;
|
||||
chan_obuf_empty = chan_obuf_empty1;
|
||||
|
||||
chan_delete_if_full_closed = chan_delete_if_full_closed1;
|
||||
}
|
||||
}
|
||||
|
||||
/* helper */
|
||||
static void
|
||||
chan_shutdown_write(Channel *c)
|
||||
{
|
||||
buffer_consume(&c->output, buffer_len(&c->output));
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
/* shutdown failure is allowed if write failed already */
|
||||
debug("channel %d: shutdown_write", c->self);
|
||||
if (shutdown(c->sock, SHUT_WR) < 0)
|
||||
debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
debug("channel %d: close_write", c->self);
|
||||
if (c->sock != -1) {
|
||||
if (shutdown(c->sock, SHUT_WR) < 0)
|
||||
debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
} else {
|
||||
if (close(c->wfd) < 0)
|
||||
log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
|
||||
c->self, c->wfd, strerror(errno));
|
||||
c->wfd = -1;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_shutdown_read(Channel *c)
|
||||
{
|
||||
debug("channel %d: shutdown_read", c->self);
|
||||
if (shutdown(c->sock, SHUT_RD) < 0)
|
||||
error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
|
||||
c->self, c->sock, c->istate, c->ostate, strerror(errno));
|
||||
}
|
||||
static void
|
||||
chan_delete_if_full_closed(Channel *c)
|
||||
{
|
||||
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
debug("channel %d: full closed", c->self);
|
||||
channel_free(c->self);
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
debug("channel %d: close_read", c->self);
|
||||
if (c->sock != -1) {
|
||||
if (shutdown(c->sock, SHUT_RD) < 0)
|
||||
error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
|
||||
c->self, c->sock, c->istate, c->ostate, strerror(errno));
|
||||
} else {
|
||||
if (close(c->rfd) < 0)
|
||||
log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
|
||||
c->self, c->rfd, strerror(errno));
|
||||
c->rfd = -1;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_init_iostates(Channel *c)
|
||||
{
|
||||
c->ostate = CHAN_OUTPUT_OPEN;
|
||||
c->istate = CHAN_INPUT_OPEN;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: nchan.h,v 1.5 1999/11/24 16:15:25 markus Exp $"); */
|
||||
/* RCSID("$Id: nchan.h,v 1.7 2000/04/03 07:07:15 markus Exp $"); */
|
||||
|
||||
#ifndef NCHAN_H
|
||||
#define NCHAN_H
|
||||
@ -72,15 +72,25 @@
|
||||
#define CHAN_OUTPUT_WAIT_IEOF 0x40
|
||||
#define CHAN_OUTPUT_CLOSED 0x80
|
||||
|
||||
/* EVENTS for the input state */
|
||||
void chan_rcvd_oclose(Channel * c);
|
||||
void chan_read_failed(Channel * c);
|
||||
void chan_ibuf_empty(Channel * c);
|
||||
#define CHAN_CLOSE_SENT 0x01
|
||||
#define CHAN_CLOSE_RCVD 0x02
|
||||
|
||||
/* EVENTS for the output state */
|
||||
void chan_rcvd_ieof(Channel * c);
|
||||
void chan_write_failed(Channel * c);
|
||||
void chan_obuf_empty(Channel * c);
|
||||
|
||||
/* Channel EVENTS */
|
||||
typedef void chan_event_fn(Channel * c);
|
||||
|
||||
/* for the input state */
|
||||
extern chan_event_fn *chan_rcvd_oclose;
|
||||
extern chan_event_fn *chan_read_failed;
|
||||
extern chan_event_fn *chan_ibuf_empty;
|
||||
|
||||
/* for the output state */
|
||||
extern chan_event_fn *chan_rcvd_ieof;
|
||||
extern chan_event_fn *chan_write_failed;
|
||||
extern chan_event_fn *chan_obuf_empty;
|
||||
|
||||
extern chan_event_fn *chan_delete_if_full_closed;
|
||||
|
||||
void chan_init_iostates(Channel * c);
|
||||
void chan_init(void);
|
||||
#endif
|
||||
|
64
crypto/openssh/nchan2.ms
Normal file
64
crypto/openssh/nchan2.ms
Normal file
@ -0,0 +1,64 @@
|
||||
.TL
|
||||
OpenSSH Channel Close Protocol 2.0 Implementation
|
||||
.SH
|
||||
Channel Input State Diagram
|
||||
.PS
|
||||
reset
|
||||
l=1
|
||||
s=1.2
|
||||
ellipsewid=s*ellipsewid
|
||||
boxwid=s*boxwid
|
||||
ellipseht=s*ellipseht
|
||||
S1: ellipse "INPUT" "OPEN"
|
||||
move right 2*l from last ellipse.e
|
||||
S3: ellipse invis
|
||||
move down l from last ellipse.s
|
||||
S4: ellipse "INPUT" "CLOSED"
|
||||
move down l from 1st ellipse.s
|
||||
S2: ellipse "INPUT" "WAIT" "DRAIN"
|
||||
arrow from S1.e to S4.n
|
||||
box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c
|
||||
arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w
|
||||
arrow from S1.s to S2.n
|
||||
box invis "read_failed/" "shutdown_read" with .e at last arrow.c
|
||||
ellipse wid .9*ellipsewid ht .9*ellipseht at S4
|
||||
arrow "start" "" from S1.w+(-0.5,0) to S1.w
|
||||
.PE
|
||||
.SH
|
||||
Channel Output State Diagram
|
||||
.PS
|
||||
S1: ellipse "OUTPUT" "OPEN"
|
||||
move right 2*l from last ellipse.e
|
||||
S3: ellipse invis
|
||||
move down l from last ellipse.s
|
||||
S4: ellipse "OUTPUT" "CLOSED"
|
||||
move down l from 1st ellipse.s
|
||||
S2: ellipse "OUTPUT" "WAIT" "DRAIN"
|
||||
arrow from S1.e to S4.n
|
||||
box invis "write_failed/" "shutdown_write" with .sw at last arrow.c
|
||||
arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
|
||||
arrow from S1.s to S2.n
|
||||
box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c
|
||||
ellipse wid .9*ellipsewid ht .9*ellipseht at S4
|
||||
arrow "start" "" from S1.w+(-0.5,0) to S1.w
|
||||
.PE
|
||||
.SH
|
||||
Notes
|
||||
.PP
|
||||
The input buffer is filled with data from the socket
|
||||
(the socket represents the local consumer/producer of the
|
||||
forwarded channel).
|
||||
The data is then sent over the INPUT-end (transmit-end) of the channel to the
|
||||
remote peer.
|
||||
Data sent by the peer is received on the OUTPUT-end (receive-end),
|
||||
saved in the output buffer and written to the socket.
|
||||
.PP
|
||||
If the local protocol instance has forwarded all data on the
|
||||
INPUT-end of the channel, it sends an EOF message to the peer.
|
||||
.PP
|
||||
A CLOSE message is sent to the peer if
|
||||
both the INPUT- and the OUTOUT-half of the local
|
||||
end of the channel are closed.
|
||||
.PP
|
||||
The channel can be deallocated by a protocol instance
|
||||
if a CLOSE message he been both sent and received.
|
@ -1,21 +1,23 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* packet.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Mar 18 02:40:40 1995 ylo
|
||||
*
|
||||
*
|
||||
* This file contains code implementing the packet protocol and communication
|
||||
* with the other side. This same code is used both on client and server side.
|
||||
*
|
||||
*
|
||||
* SSH2 packet format added by Markus Friedl.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: packet.c,v 1.22 2000/02/05 10:13:11 markus Exp $");
|
||||
RCSID("$Id: packet.c,v 1.32 2000/05/04 22:22:43 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
@ -28,6 +30,23 @@ RCSID("$Id: packet.c,v 1.22 2000/02/05 10:13:11 markus Exp $");
|
||||
|
||||
#include "compress.h"
|
||||
#include "deattack.h"
|
||||
#include "channels.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "ssh2.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include "buffer.h"
|
||||
#include "kex.h"
|
||||
#include "hmac.h"
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
#define DBG(x) x
|
||||
#else
|
||||
#define DBG(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This variable contains the file descriptors used for communicating with
|
||||
@ -80,19 +99,53 @@ static int initialized = 0;
|
||||
/* Set to true if the connection is interactive. */
|
||||
static int interactive_mode = 0;
|
||||
|
||||
/* True if SSH2 packet format is used */
|
||||
int use_ssh2_packet_format = 0;
|
||||
|
||||
/* Session key information for Encryption and MAC */
|
||||
Kex *kex = NULL;
|
||||
|
||||
void
|
||||
packet_set_kex(Kex *k)
|
||||
{
|
||||
if( k->mac[MODE_IN ].key == NULL ||
|
||||
k->enc[MODE_IN ].key == NULL ||
|
||||
k->enc[MODE_IN ].iv == NULL ||
|
||||
k->mac[MODE_OUT].key == NULL ||
|
||||
k->enc[MODE_OUT].key == NULL ||
|
||||
k->enc[MODE_OUT].iv == NULL)
|
||||
fatal("bad KEX");
|
||||
kex = k;
|
||||
}
|
||||
void
|
||||
clear_enc_keys(Enc *enc, int len)
|
||||
{
|
||||
memset(enc->iv, 0, len);
|
||||
memset(enc->key, 0, len);
|
||||
xfree(enc->iv);
|
||||
xfree(enc->key);
|
||||
enc->iv = NULL;
|
||||
enc->key = NULL;
|
||||
}
|
||||
void
|
||||
packet_set_ssh2_format(void)
|
||||
{
|
||||
DBG(debug("use_ssh2_packet_format"));
|
||||
use_ssh2_packet_format = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
connection_in = fd_in;
|
||||
connection_out = fd_out;
|
||||
cipher_type = SSH_CIPHER_NONE;
|
||||
cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 1);
|
||||
cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0, 0);
|
||||
cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *) "", 0);
|
||||
cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *) "", 0);
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
buffer_init(&input);
|
||||
@ -224,6 +277,7 @@ packet_get_protocol_flags()
|
||||
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
|
||||
*/
|
||||
|
||||
/*** XXXXX todo: kex means re-init */
|
||||
void
|
||||
packet_start_compression(int level)
|
||||
{
|
||||
@ -241,7 +295,7 @@ packet_start_compression(int level)
|
||||
|
||||
void
|
||||
packet_encrypt(CipherContext * cc, void *dest, void *src,
|
||||
unsigned int bytes)
|
||||
unsigned int bytes)
|
||||
{
|
||||
cipher_encrypt(cc, dest, src, bytes);
|
||||
}
|
||||
@ -253,7 +307,7 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
|
||||
|
||||
void
|
||||
packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||
unsigned int bytes)
|
||||
unsigned int bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -265,15 +319,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||
* (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
|
||||
*/
|
||||
|
||||
switch (cc->type) {
|
||||
case SSH_CIPHER_NONE:
|
||||
if (cc->type == SSH_CIPHER_NONE || compat20) {
|
||||
i = DEATTACK_OK;
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
i = detect_attack(src, bytes, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == DEATTACK_DETECTED)
|
||||
packet_disconnect("crc32 compensation attack: network attack detected");
|
||||
|
||||
@ -288,17 +338,20 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
|
||||
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||
int cipher)
|
||||
int cipher)
|
||||
{
|
||||
if (keylen < 20)
|
||||
fatal("keylen too small: %d", keylen);
|
||||
|
||||
/* All other ciphers use the same key in both directions for now. */
|
||||
cipher_set_key(&receive_context, cipher, key, keylen, 0);
|
||||
cipher_set_key(&send_context, cipher, key, keylen, 1);
|
||||
cipher_set_key(&receive_context, cipher, key, keylen);
|
||||
cipher_set_key(&send_context, cipher, key, keylen);
|
||||
}
|
||||
|
||||
/* Starts constructing a packet to send. */
|
||||
|
||||
void
|
||||
packet_start(int type)
|
||||
packet_start1(int type)
|
||||
{
|
||||
char buf[9];
|
||||
|
||||
@ -308,6 +361,29 @@ packet_start(int type)
|
||||
buffer_append(&outgoing_packet, buf, 9);
|
||||
}
|
||||
|
||||
void
|
||||
packet_start2(int type)
|
||||
{
|
||||
char buf[4+1+1];
|
||||
|
||||
buffer_clear(&outgoing_packet);
|
||||
memset(buf, 0, sizeof buf);
|
||||
/* buf[0..3] = payload_len; */
|
||||
/* buf[4] = pad_len; */
|
||||
buf[5] = type & 0xff;
|
||||
buffer_append(&outgoing_packet, buf, sizeof buf);
|
||||
}
|
||||
|
||||
void
|
||||
packet_start(int type)
|
||||
{
|
||||
DBG(debug("packet_start[%d]",type));
|
||||
if (use_ssh2_packet_format)
|
||||
packet_start2(type);
|
||||
else
|
||||
packet_start1(type);
|
||||
}
|
||||
|
||||
/* Appends a character to the packet data. */
|
||||
|
||||
void
|
||||
@ -332,6 +408,18 @@ packet_put_string(const char *buf, unsigned int len)
|
||||
{
|
||||
buffer_put_string(&outgoing_packet, buf, len);
|
||||
}
|
||||
void
|
||||
packet_put_cstring(const char *str)
|
||||
{
|
||||
buffer_put_string(&outgoing_packet, str, strlen(str));
|
||||
}
|
||||
|
||||
void
|
||||
packet_put_raw(const char *buf, unsigned int len)
|
||||
{
|
||||
buffer_append(&outgoing_packet, buf, len);
|
||||
}
|
||||
|
||||
|
||||
/* Appends an arbitrary precision integer to packet data. */
|
||||
|
||||
@ -340,6 +428,11 @@ packet_put_bignum(BIGNUM * value)
|
||||
{
|
||||
buffer_put_bignum(&outgoing_packet, value);
|
||||
}
|
||||
void
|
||||
packet_put_bignum2(BIGNUM * value)
|
||||
{
|
||||
buffer_put_bignum2(&outgoing_packet, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalizes and sends the packet. If the encryption key has been set,
|
||||
@ -347,7 +440,7 @@ packet_put_bignum(BIGNUM * value)
|
||||
*/
|
||||
|
||||
void
|
||||
packet_send()
|
||||
packet_send1()
|
||||
{
|
||||
char buf[8], *cp;
|
||||
int i, padding, len;
|
||||
@ -372,7 +465,7 @@ packet_send()
|
||||
/* Compute packet length without padding (add checksum, remove padding). */
|
||||
len = buffer_len(&outgoing_packet) + 4 - 8;
|
||||
|
||||
/* Insert padding. */
|
||||
/* Insert padding. Initialized to zero in packet_start1() */
|
||||
padding = 8 - len % 8;
|
||||
if (cipher_type != SSH_CIPHER_NONE) {
|
||||
cp = buffer_ptr(&outgoing_packet);
|
||||
@ -417,6 +510,136 @@ packet_send()
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
|
||||
*/
|
||||
void
|
||||
packet_send2()
|
||||
{
|
||||
unsigned char *macbuf = NULL;
|
||||
char *cp;
|
||||
unsigned int packet_length = 0;
|
||||
unsigned int i, padlen, len;
|
||||
u_int32_t rand = 0;
|
||||
static unsigned int seqnr = 0;
|
||||
int type;
|
||||
Enc *enc = NULL;
|
||||
Mac *mac = NULL;
|
||||
Comp *comp = NULL;
|
||||
int block_size;
|
||||
|
||||
if (kex != NULL) {
|
||||
enc = &kex->enc[MODE_OUT];
|
||||
mac = &kex->mac[MODE_OUT];
|
||||
comp = &kex->comp[MODE_OUT];
|
||||
}
|
||||
block_size = enc ? enc->block_size : 8;
|
||||
|
||||
cp = buffer_ptr(&outgoing_packet);
|
||||
type = cp[5] & 0xff;
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "plain: ");
|
||||
buffer_dump(&outgoing_packet);
|
||||
#endif
|
||||
|
||||
if (comp && comp->enabled) {
|
||||
len = buffer_len(&outgoing_packet);
|
||||
/* skip header, compress only payload */
|
||||
buffer_consume(&outgoing_packet, 5);
|
||||
buffer_clear(&compression_buffer);
|
||||
buffer_compress(&outgoing_packet, &compression_buffer);
|
||||
buffer_clear(&outgoing_packet);
|
||||
buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
|
||||
buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
|
||||
buffer_len(&compression_buffer));
|
||||
DBG(debug("compression: raw %d compressed %d", len,
|
||||
buffer_len(&outgoing_packet)));
|
||||
}
|
||||
|
||||
/* sizeof (packet_len + pad_len + payload) */
|
||||
len = buffer_len(&outgoing_packet);
|
||||
|
||||
/*
|
||||
* calc size of padding, alloc space, get random data,
|
||||
* minimum padding is 4 bytes
|
||||
*/
|
||||
padlen = block_size - (len % block_size);
|
||||
if (padlen < 4)
|
||||
padlen += block_size;
|
||||
buffer_append_space(&outgoing_packet, &cp, padlen);
|
||||
if (enc && enc->type != SSH_CIPHER_NONE) {
|
||||
/* random padding */
|
||||
for (i = 0; i < padlen; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
cp[i] = rand & 0xff;
|
||||
rand <<= 8;
|
||||
}
|
||||
} else {
|
||||
/* clear padding */
|
||||
memset(cp, 0, padlen);
|
||||
}
|
||||
/* packet_length includes payload, padding and padding length field */
|
||||
packet_length = buffer_len(&outgoing_packet) - 4;
|
||||
cp = buffer_ptr(&outgoing_packet);
|
||||
PUT_32BIT(cp, packet_length);
|
||||
cp[4] = padlen & 0xff;
|
||||
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
|
||||
|
||||
/* compute MAC over seqnr and packet(length fields, payload, padding) */
|
||||
if (mac && mac->enabled) {
|
||||
macbuf = hmac( mac->md, seqnr,
|
||||
(unsigned char *) buffer_ptr(&outgoing_packet),
|
||||
buffer_len(&outgoing_packet),
|
||||
mac->key, mac->key_len
|
||||
);
|
||||
DBG(debug("done calc HMAC out #%d", seqnr));
|
||||
}
|
||||
/* encrypt packet and append to output buffer. */
|
||||
buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
|
||||
packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
|
||||
buffer_len(&outgoing_packet));
|
||||
/* append unencrypted MAC */
|
||||
if (mac && mac->enabled)
|
||||
buffer_append(&output, (char *)macbuf, mac->mac_len);
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "encrypted: ");
|
||||
buffer_dump(&output);
|
||||
#endif
|
||||
/* increment sequence number for outgoing packets */
|
||||
if (++seqnr == 0)
|
||||
log("outgoing seqnr wraps around");
|
||||
buffer_clear(&outgoing_packet);
|
||||
|
||||
if (type == SSH2_MSG_NEWKEYS) {
|
||||
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
|
||||
fatal("packet_send2: no KEX");
|
||||
if (mac->md != NULL)
|
||||
mac->enabled = 1;
|
||||
DBG(debug("cipher_set_key_iv send_context"));
|
||||
cipher_set_key_iv(&send_context, enc->type,
|
||||
enc->key, enc->key_len,
|
||||
enc->iv, enc->iv_len);
|
||||
clear_enc_keys(enc, kex->we_need);
|
||||
if (comp->type != 0 && comp->enabled == 0) {
|
||||
comp->enabled = 1;
|
||||
if (! packet_compression)
|
||||
packet_start_compression(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
packet_send()
|
||||
{
|
||||
if (use_ssh2_packet_format)
|
||||
packet_send2();
|
||||
else
|
||||
packet_send1();
|
||||
DBG(debug("packet_send done"));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -429,6 +652,7 @@ packet_read(int *payload_len_ptr)
|
||||
int type, len;
|
||||
fd_set set;
|
||||
char buf[8192];
|
||||
DBG(debug("packet_read()"));
|
||||
|
||||
/* Since we are blocking, ensure that all written packets have been sent. */
|
||||
packet_write_wait();
|
||||
@ -437,10 +661,11 @@ packet_read(int *payload_len_ptr)
|
||||
for (;;) {
|
||||
/* Try to read a packet from the buffer. */
|
||||
type = packet_read_poll(payload_len_ptr);
|
||||
if (type == SSH_SMSG_SUCCESS
|
||||
if (!use_ssh2_packet_format && (
|
||||
type == SSH_SMSG_SUCCESS
|
||||
|| type == SSH_SMSG_FAILURE
|
||||
|| type == SSH_CMSG_EOF
|
||||
|| type == SSH_CMSG_EXIT_CONFIRMATION)
|
||||
|| type == SSH_CMSG_EXIT_CONFIRMATION))
|
||||
packet_integrity_check(*payload_len_ptr, 0, type);
|
||||
/* If we got a packet, return it. */
|
||||
if (type != SSH_MSG_NONE)
|
||||
@ -482,7 +707,7 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
|
||||
type = packet_read(payload_len_ptr);
|
||||
if (type != expected_type)
|
||||
packet_disconnect("Protocol error: expected packet type %d, got %d",
|
||||
expected_type, type);
|
||||
expected_type, type);
|
||||
}
|
||||
|
||||
/* Checks if a full packet is available in the data received so far via
|
||||
@ -501,15 +726,13 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
|
||||
*/
|
||||
|
||||
int
|
||||
packet_read_poll(int *payload_len_ptr)
|
||||
packet_read_poll1(int *payload_len_ptr)
|
||||
{
|
||||
unsigned int len, padded_len;
|
||||
unsigned char *ucp;
|
||||
char buf[8], *cp, *msg;
|
||||
char buf[8], *cp;
|
||||
unsigned int checksum, stored_checksum;
|
||||
|
||||
restart:
|
||||
|
||||
/* Check if input size is less than minimum packet size. */
|
||||
if (buffer_len(&input) < 4 + 8)
|
||||
return SSH_MSG_NONE;
|
||||
@ -542,7 +765,7 @@ packet_read_poll(int *payload_len_ptr)
|
||||
|
||||
/* Compute packet checksum. */
|
||||
checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet),
|
||||
buffer_len(&incoming_packet) - 4);
|
||||
buffer_len(&incoming_packet) - 4);
|
||||
|
||||
/* Skip padding. */
|
||||
buffer_consume(&incoming_packet, 8 - len % 8);
|
||||
@ -551,7 +774,7 @@ packet_read_poll(int *payload_len_ptr)
|
||||
|
||||
if (len != buffer_len(&incoming_packet))
|
||||
packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
|
||||
len, buffer_len(&incoming_packet));
|
||||
len, buffer_len(&incoming_packet));
|
||||
|
||||
ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
|
||||
stored_checksum = GET_32BIT(ucp);
|
||||
@ -565,7 +788,7 @@ packet_read_poll(int *payload_len_ptr)
|
||||
buffer_uncompress(&incoming_packet, &compression_buffer);
|
||||
buffer_clear(&incoming_packet);
|
||||
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
|
||||
buffer_len(&compression_buffer));
|
||||
buffer_len(&compression_buffer));
|
||||
}
|
||||
/* Get packet type. */
|
||||
buffer_get(&incoming_packet, &buf[0], 1);
|
||||
@ -573,29 +796,208 @@ packet_read_poll(int *payload_len_ptr)
|
||||
/* Return length of payload (without type field). */
|
||||
*payload_len_ptr = buffer_len(&incoming_packet);
|
||||
|
||||
/* Handle disconnect message. */
|
||||
if ((unsigned char) buf[0] == SSH_MSG_DISCONNECT) {
|
||||
msg = packet_get_string(NULL);
|
||||
log("Received disconnect: %.900s", msg);
|
||||
xfree(msg);
|
||||
fatal_cleanup();
|
||||
}
|
||||
|
||||
/* Ignore ignore messages. */
|
||||
if ((unsigned char) buf[0] == SSH_MSG_IGNORE)
|
||||
goto restart;
|
||||
|
||||
/* Send debug messages as debugging output. */
|
||||
if ((unsigned char) buf[0] == SSH_MSG_DEBUG) {
|
||||
msg = packet_get_string(NULL);
|
||||
debug("Remote: %.900s", msg);
|
||||
xfree(msg);
|
||||
goto restart;
|
||||
}
|
||||
/* Return type. */
|
||||
return (unsigned char) buf[0];
|
||||
}
|
||||
|
||||
int
|
||||
packet_read_poll2(int *payload_len_ptr)
|
||||
{
|
||||
unsigned int padlen, need;
|
||||
unsigned char buf[8], *macbuf;
|
||||
unsigned char *ucp;
|
||||
char *cp;
|
||||
static unsigned int packet_length = 0;
|
||||
static unsigned int seqnr = 0;
|
||||
int type;
|
||||
int maclen, block_size;
|
||||
Enc *enc = NULL;
|
||||
Mac *mac = NULL;
|
||||
Comp *comp = NULL;
|
||||
|
||||
if (kex != NULL) {
|
||||
enc = &kex->enc[MODE_IN];
|
||||
mac = &kex->mac[MODE_IN];
|
||||
comp = &kex->comp[MODE_IN];
|
||||
}
|
||||
maclen = mac && mac->enabled ? mac->mac_len : 0;
|
||||
block_size = enc ? enc->block_size : 8;
|
||||
|
||||
if (packet_length == 0) {
|
||||
/*
|
||||
* check if input size is less than the cipher block size,
|
||||
* decrypt first block and extract length of incoming packet
|
||||
*/
|
||||
if (buffer_len(&input) < block_size)
|
||||
return SSH_MSG_NONE;
|
||||
buffer_clear(&incoming_packet);
|
||||
buffer_append_space(&incoming_packet, &cp, block_size);
|
||||
packet_decrypt(&receive_context, cp, buffer_ptr(&input),
|
||||
block_size);
|
||||
ucp = (unsigned char *) buffer_ptr(&incoming_packet);
|
||||
packet_length = GET_32BIT(ucp);
|
||||
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
|
||||
buffer_dump(&incoming_packet);
|
||||
packet_disconnect("Bad packet length %d.", packet_length);
|
||||
}
|
||||
DBG(debug("input: packet len %d", packet_length+4));
|
||||
buffer_consume(&input, block_size);
|
||||
}
|
||||
/* we have a partial packet of block_size bytes */
|
||||
need = 4 + packet_length - block_size;
|
||||
DBG(debug("partial packet %d, need %d, maclen %d", block_size,
|
||||
need, maclen));
|
||||
if (need % block_size != 0)
|
||||
fatal("padding error: need %d block %d mod %d",
|
||||
need, block_size, need % block_size);
|
||||
/*
|
||||
* check if the entire packet has been received and
|
||||
* decrypt into incoming_packet
|
||||
*/
|
||||
if (buffer_len(&input) < need + maclen)
|
||||
return SSH_MSG_NONE;
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "read_poll enc/full: ");
|
||||
buffer_dump(&input);
|
||||
#endif
|
||||
buffer_append_space(&incoming_packet, &cp, need);
|
||||
packet_decrypt(&receive_context, cp, buffer_ptr(&input), need);
|
||||
buffer_consume(&input, need);
|
||||
/*
|
||||
* compute MAC over seqnr and packet,
|
||||
* increment sequence number for incoming packet
|
||||
*/
|
||||
if (mac && mac->enabled) {
|
||||
macbuf = hmac( mac->md, seqnr,
|
||||
(unsigned char *) buffer_ptr(&incoming_packet),
|
||||
buffer_len(&incoming_packet),
|
||||
mac->key, mac->key_len
|
||||
);
|
||||
if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
|
||||
packet_disconnect("Corrupted HMAC on input.");
|
||||
DBG(debug("HMAC #%d ok", seqnr));
|
||||
buffer_consume(&input, mac->mac_len);
|
||||
}
|
||||
if (++seqnr == 0)
|
||||
log("incoming seqnr wraps around");
|
||||
|
||||
/* get padlen */
|
||||
cp = buffer_ptr(&incoming_packet) + 4;
|
||||
padlen = *cp & 0xff;
|
||||
DBG(debug("input: padlen %d", padlen));
|
||||
if (padlen < 4)
|
||||
packet_disconnect("Corrupted padlen %d on input.", padlen);
|
||||
|
||||
/* skip packet size + padlen, discard padding */
|
||||
buffer_consume(&incoming_packet, 4 + 1);
|
||||
buffer_consume_end(&incoming_packet, padlen);
|
||||
|
||||
DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
|
||||
if (comp && comp->enabled) {
|
||||
buffer_clear(&compression_buffer);
|
||||
buffer_uncompress(&incoming_packet, &compression_buffer);
|
||||
buffer_clear(&incoming_packet);
|
||||
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
|
||||
buffer_len(&compression_buffer));
|
||||
DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet)));
|
||||
}
|
||||
/*
|
||||
* get packet type, implies consume.
|
||||
* return length of payload (without type field)
|
||||
*/
|
||||
buffer_get(&incoming_packet, (char *)&buf[0], 1);
|
||||
*payload_len_ptr = buffer_len(&incoming_packet);
|
||||
|
||||
/* reset for next packet */
|
||||
packet_length = 0;
|
||||
|
||||
/* extract packet type */
|
||||
type = (unsigned char)buf[0];
|
||||
|
||||
if (type == SSH2_MSG_NEWKEYS) {
|
||||
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
|
||||
fatal("packet_read_poll2: no KEX");
|
||||
if (mac->md != NULL)
|
||||
mac->enabled = 1;
|
||||
DBG(debug("cipher_set_key_iv receive_context"));
|
||||
cipher_set_key_iv(&receive_context, enc->type,
|
||||
enc->key, enc->key_len,
|
||||
enc->iv, enc->iv_len);
|
||||
clear_enc_keys(enc, kex->we_need);
|
||||
if (comp->type != 0 && comp->enabled == 0) {
|
||||
comp->enabled = 1;
|
||||
if (! packet_compression)
|
||||
packet_start_compression(6);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "read/plain[%d]:\r\n",type);
|
||||
buffer_dump(&incoming_packet);
|
||||
#endif
|
||||
return (unsigned char)type;
|
||||
}
|
||||
|
||||
int
|
||||
packet_read_poll(int *payload_len_ptr)
|
||||
{
|
||||
char *msg;
|
||||
for (;;) {
|
||||
int type = use_ssh2_packet_format ?
|
||||
packet_read_poll2(payload_len_ptr):
|
||||
packet_read_poll1(payload_len_ptr);
|
||||
|
||||
if(compat20) {
|
||||
int reason;
|
||||
if (type != 0)
|
||||
DBG(debug("received packet type %d", type));
|
||||
switch(type) {
|
||||
case SSH2_MSG_IGNORE:
|
||||
break;
|
||||
case SSH2_MSG_DEBUG:
|
||||
packet_get_char();
|
||||
msg = packet_get_string(NULL);
|
||||
debug("Remote: %.900s", msg);
|
||||
xfree(msg);
|
||||
msg = packet_get_string(NULL);
|
||||
xfree(msg);
|
||||
break;
|
||||
case SSH2_MSG_DISCONNECT:
|
||||
reason = packet_get_int();
|
||||
msg = packet_get_string(NULL);
|
||||
log("Received disconnect: %d: %.900s", reason, msg);
|
||||
xfree(msg);
|
||||
fatal_cleanup();
|
||||
break;
|
||||
default:
|
||||
return type;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch(type) {
|
||||
case SSH_MSG_IGNORE:
|
||||
break;
|
||||
case SSH_MSG_DEBUG:
|
||||
msg = packet_get_string(NULL);
|
||||
debug("Remote: %.900s", msg);
|
||||
xfree(msg);
|
||||
break;
|
||||
case SSH_MSG_DISCONNECT:
|
||||
msg = packet_get_string(NULL);
|
||||
log("Received disconnect: %.900s", msg);
|
||||
fatal_cleanup();
|
||||
xfree(msg);
|
||||
break;
|
||||
default:
|
||||
if (type != 0)
|
||||
DBG(debug("received packet type %d", type));
|
||||
return type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Buffers the given amount of input characters. This is intended to be used
|
||||
* together with packet_read_poll.
|
||||
@ -636,6 +1038,27 @@ packet_get_bignum(BIGNUM * value, int *length_ptr)
|
||||
*length_ptr = buffer_get_bignum(&incoming_packet, value);
|
||||
}
|
||||
|
||||
void
|
||||
packet_get_bignum2(BIGNUM * value, int *length_ptr)
|
||||
{
|
||||
*length_ptr = buffer_get_bignum2(&incoming_packet, value);
|
||||
}
|
||||
|
||||
char *
|
||||
packet_get_raw(int *length_ptr)
|
||||
{
|
||||
int bytes = buffer_len(&incoming_packet);
|
||||
if (length_ptr != NULL)
|
||||
*length_ptr = bytes;
|
||||
return buffer_ptr(&incoming_packet);
|
||||
}
|
||||
|
||||
int
|
||||
packet_remaining(void)
|
||||
{
|
||||
return buffer_len(&incoming_packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -668,8 +1091,15 @@ packet_send_debug(const char *fmt,...)
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
packet_start(SSH_MSG_DEBUG);
|
||||
packet_put_string(buf, strlen(buf));
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_DEBUG);
|
||||
packet_put_char(0); /* bool: always display */
|
||||
packet_put_cstring(buf);
|
||||
packet_put_cstring("");
|
||||
} else {
|
||||
packet_start(SSH_MSG_DEBUG);
|
||||
packet_put_cstring(buf);
|
||||
}
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
@ -700,8 +1130,15 @@ packet_disconnect(const char *fmt,...)
|
||||
va_end(args);
|
||||
|
||||
/* Send the disconnect message to the other side, and wait for it to get sent. */
|
||||
packet_start(SSH_MSG_DISCONNECT);
|
||||
packet_put_string(buf, strlen(buf));
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_DISCONNECT);
|
||||
packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
|
||||
packet_put_cstring(buf);
|
||||
packet_put_cstring("");
|
||||
} else {
|
||||
packet_start(SSH_MSG_DISCONNECT);
|
||||
packet_put_string(buf, strlen(buf));
|
||||
}
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
@ -832,7 +1269,8 @@ packet_set_maxsize(int s)
|
||||
{
|
||||
static int called = 0;
|
||||
if (called) {
|
||||
log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s);
|
||||
log("packet_set_maxsize: called twice: old %d new %d",
|
||||
max_packet_size, s);
|
||||
return -1;
|
||||
}
|
||||
if (s < 4 * 1024 || s > 1024 * 1024) {
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* pty.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Fri Mar 17 05:03:28 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for allocating a pseudo-terminal and making it the controlling
|
||||
* tty.
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: pty.h,v 1.5 2000/02/15 16:52:58 markus Exp $"); */
|
||||
/* RCSID("$Id: pty.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */
|
||||
|
||||
#ifndef PTY_H
|
||||
#define PTY_H
|
||||
@ -39,7 +39,7 @@ void pty_release(const char *ttyname);
|
||||
void pty_make_controlling_tty(int *ttyfd, const char *ttyname);
|
||||
|
||||
/* Changes the window size associated with the pty. */
|
||||
void
|
||||
void
|
||||
pty_change_window_size(int ptyfd, int row, int col,
|
||||
int xpixel, int ypixel);
|
||||
|
||||
|
@ -1,109 +1,15 @@
|
||||
/*
|
||||
* radix.c
|
||||
*
|
||||
* base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
|
||||
* Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
|
||||
* and placed in the public domain.
|
||||
*
|
||||
*
|
||||
* Dug Song <dugsong@UMICH.EDU>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#ifdef AFS
|
||||
#include <krb.h>
|
||||
|
||||
char six2pr[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
unsigned char pr2six[256];
|
||||
|
||||
int
|
||||
uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
|
||||
{
|
||||
/* ENC is the basic 1 character encoding function to make a char printing */
|
||||
#define ENC(c) six2pr[c]
|
||||
|
||||
register char *outptr = bufcoded;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < nbytes; i += 3) {
|
||||
*(outptr++) = ENC(*bufin >> 2); /* c1 */
|
||||
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */
|
||||
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */
|
||||
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
|
||||
bufin += 3;
|
||||
}
|
||||
if (i == nbytes + 1) {
|
||||
outptr[-1] = '=';
|
||||
} else if (i == nbytes + 2) {
|
||||
outptr[-1] = '=';
|
||||
outptr[-2] = '=';
|
||||
}
|
||||
*outptr = '\0';
|
||||
return (outptr - bufcoded);
|
||||
}
|
||||
|
||||
int
|
||||
uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
|
||||
{
|
||||
/* single character decode */
|
||||
#define DEC(c) pr2six[(unsigned char)c]
|
||||
#define MAXVAL 63
|
||||
|
||||
static int first = 1;
|
||||
int nbytesdecoded, j;
|
||||
const char *bufin = bufcoded;
|
||||
register unsigned char *bufout = bufplain;
|
||||
register int nprbytes;
|
||||
|
||||
/* If this is the first call, initialize the mapping table. */
|
||||
if (first) {
|
||||
first = 0;
|
||||
for (j = 0; j < 256; j++)
|
||||
pr2six[j] = MAXVAL + 1;
|
||||
for (j = 0; j < 64; j++)
|
||||
pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
|
||||
}
|
||||
/* Strip leading whitespace. */
|
||||
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.
|
||||
*/
|
||||
bufin = bufcoded;
|
||||
while (DEC(*(bufin++)) <= MAXVAL);
|
||||
nprbytes = bufin - bufcoded - 1;
|
||||
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
|
||||
if (nbytesdecoded > outbufsize)
|
||||
nprbytes = (outbufsize * 4) / 3;
|
||||
|
||||
bufin = bufcoded;
|
||||
|
||||
while (nprbytes > 0) {
|
||||
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
|
||||
bufin += 4;
|
||||
nprbytes -= 4;
|
||||
}
|
||||
if (nprbytes & 03) {
|
||||
if (DEC(bufin[-2]) > MAXVAL)
|
||||
nbytesdecoded -= 2;
|
||||
else
|
||||
nbytesdecoded -= 1;
|
||||
}
|
||||
return (nbytesdecoded);
|
||||
}
|
||||
|
||||
typedef unsigned char my_u_char;
|
||||
typedef unsigned int my_u_int32_t;
|
||||
typedef unsigned short my_u_short;
|
||||
@ -162,8 +68,8 @@ typedef unsigned short my_u_short;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
|
||||
int
|
||||
creds_to_radix(CREDENTIALS *creds, unsigned char *buf, size_t buflen)
|
||||
{
|
||||
char *p, *s;
|
||||
int len;
|
||||
@ -213,10 +119,10 @@ creds_to_radix(CREDENTIALS *creds, unsigned char *buf)
|
||||
p += creds->ticket_st.length;
|
||||
len = p - temp;
|
||||
|
||||
return (uuencode((unsigned char *)temp, len, (char *)buf));
|
||||
return (uuencode((unsigned char *)temp, len, (char *)buf, buflen));
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
radix_to_creds(const char *buf, CREDENTIALS *creds)
|
||||
{
|
||||
|
||||
@ -225,7 +131,8 @@ radix_to_creds(const char *buf, CREDENTIALS *creds)
|
||||
char version;
|
||||
char temp[2048];
|
||||
|
||||
if (!(len = uudecode(buf, (unsigned char *)temp, sizeof(temp))))
|
||||
len = uudecode(buf, (unsigned char *)temp, sizeof(temp));
|
||||
if (len < 0)
|
||||
return 0;
|
||||
|
||||
p = temp;
|
||||
|
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: readpass.c,v 1.9 2000/01/21 21:16:00 deraadt Exp $");
|
||||
RCSID("$Id: readpass.c,v 1.10 2000/04/14 10:30:32 markus Exp $");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
@ -58,7 +58,7 @@ read_passphrase(const char *prompt, int from_stdin)
|
||||
sigset_t oset, nset;
|
||||
struct sigaction sa, osa;
|
||||
int input, output, echo = 0;
|
||||
|
||||
|
||||
if (from_stdin) {
|
||||
input = STDIN_FILENO;
|
||||
output = STDERR_FILENO;
|
||||
|
@ -9,7 +9,7 @@
|
||||
.\"
|
||||
.\" Created: Sun May 7 00:14:37 1995 ylo
|
||||
.\"
|
||||
.\" $Id: scp.1,v 1.6 2000/03/23 21:10:09 aaron Exp $
|
||||
.\" $Id: scp.1,v 1.7 2000/04/12 21:47:50 aaron Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SCP 1
|
||||
@ -36,7 +36,7 @@
|
||||
.Ar host2 No :
|
||||
.Oc Ar file2
|
||||
.Sm on
|
||||
.Sh DESCRIPTION
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
copies files between hosts on a network.
|
||||
It uses
|
||||
@ -74,7 +74,7 @@ Recursively copy entire directories.
|
||||
Verbose mode.
|
||||
Causes
|
||||
.Nm
|
||||
and
|
||||
and
|
||||
.Xr ssh 1
|
||||
to print debugging messages about their progress.
|
||||
This is helpful in
|
||||
|
@ -1,13 +1,13 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* scp - secure remote copy. This is basically patched BSD rcp which uses ssh
|
||||
* to do the data transfer (instead of using rcmd).
|
||||
*
|
||||
*
|
||||
* NOTE: This version should NOT be suid root. (This uses ssh to do the transfer
|
||||
* and ssh has the necessary privileges.)
|
||||
*
|
||||
*
|
||||
* 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -45,7 +45,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: scp.c,v 1.26 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$Id: scp.c,v 1.30 2000/05/02 18:21:48 deraadt Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
@ -109,7 +109,7 @@ char *port = NULL;
|
||||
* assigns the input and output file descriptors on success.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
|
||||
{
|
||||
int pin[2], pout[2], reserved[2];
|
||||
@ -194,7 +194,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
fatal(const char *fmt,...)
|
||||
{
|
||||
va_list ap;
|
||||
@ -257,10 +257,10 @@ main(argc, argv)
|
||||
switch (ch) {
|
||||
/* User-visible flags. */
|
||||
case '4':
|
||||
IPv4 = 1;
|
||||
IPv4 = 1;
|
||||
break;
|
||||
case '6':
|
||||
IPv6 = 1;
|
||||
IPv6 = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
@ -543,7 +543,7 @@ syserr: run_err("%s: %s", name, strerror(errno));
|
||||
(void) sprintf(buf, "T%lu 0 %lu 0\n",
|
||||
(unsigned long) stb.st_mtime,
|
||||
(unsigned long) stb.st_atime);
|
||||
(void) write(remout, buf, strlen(buf));
|
||||
(void) atomicio(write, remout, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
}
|
||||
@ -556,7 +556,7 @@ syserr: run_err("%s: %s", name, strerror(errno));
|
||||
fprintf(stderr, "Sending file modes: %s", buf);
|
||||
fflush(stderr);
|
||||
}
|
||||
(void) write(remout, buf, strlen(buf));
|
||||
(void) atomicio(write, remout, buf, strlen(buf));
|
||||
if (response() < 0)
|
||||
goto next;
|
||||
if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
|
||||
@ -573,14 +573,14 @@ next: (void) close(fd);
|
||||
if (i + amt > stb.st_size)
|
||||
amt = stb.st_size - i;
|
||||
if (!haderr) {
|
||||
result = read(fd, bp->buf, amt);
|
||||
result = atomicio(read, fd, bp->buf, amt);
|
||||
if (result != amt)
|
||||
haderr = result >= 0 ? EIO : errno;
|
||||
}
|
||||
if (haderr)
|
||||
(void) write(remout, bp->buf, amt);
|
||||
(void) atomicio(write, remout, bp->buf, amt);
|
||||
else {
|
||||
result = write(remout, bp->buf, amt);
|
||||
result = atomicio(write, remout, bp->buf, amt);
|
||||
if (result != amt)
|
||||
haderr = result >= 0 ? EIO : errno;
|
||||
statbytes += result;
|
||||
@ -592,7 +592,7 @@ next: (void) close(fd);
|
||||
if (close(fd) < 0 && !haderr)
|
||||
haderr = errno;
|
||||
if (!haderr)
|
||||
(void) write(remout, "", 1);
|
||||
(void) atomicio(write, remout, "", 1);
|
||||
else
|
||||
run_err("%s: %s", name, strerror(haderr));
|
||||
(void) response();
|
||||
@ -621,7 +621,7 @@ rsource(name, statp)
|
||||
(void) sprintf(path, "T%lu 0 %lu 0\n",
|
||||
(unsigned long) statp->st_mtime,
|
||||
(unsigned long) statp->st_atime);
|
||||
(void) write(remout, path, strlen(path));
|
||||
(void) atomicio(write, remout, path, strlen(path));
|
||||
if (response() < 0) {
|
||||
closedir(dirp);
|
||||
return;
|
||||
@ -632,7 +632,7 @@ rsource(name, statp)
|
||||
0, last);
|
||||
if (verbose_mode)
|
||||
fprintf(stderr, "Entering directory: %s", path);
|
||||
(void) write(remout, path, strlen(path));
|
||||
(void) atomicio(write, remout, path, strlen(path));
|
||||
if (response() < 0) {
|
||||
closedir(dirp);
|
||||
return;
|
||||
@ -651,7 +651,7 @@ rsource(name, statp)
|
||||
source(1, vect);
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
(void) write(remout, "E\n", 2);
|
||||
(void) atomicio(write, remout, "E\n", 2);
|
||||
(void) response();
|
||||
}
|
||||
|
||||
@ -687,17 +687,17 @@ sink(argc, argv)
|
||||
if (targetshouldbedirectory)
|
||||
verifydir(targ);
|
||||
|
||||
(void) write(remout, "", 1);
|
||||
(void) atomicio(write, remout, "", 1);
|
||||
if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
|
||||
targisdir = 1;
|
||||
for (first = 1;; first = 0) {
|
||||
cp = buf;
|
||||
if (read(remin, cp, 1) <= 0)
|
||||
if (atomicio(read, remin, cp, 1) <= 0)
|
||||
return;
|
||||
if (*cp++ == '\n')
|
||||
SCREWUP("unexpected <newline>");
|
||||
do {
|
||||
if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
|
||||
if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
|
||||
SCREWUP("lost connection");
|
||||
*cp++ = ch;
|
||||
} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
|
||||
@ -705,7 +705,7 @@ sink(argc, argv)
|
||||
|
||||
if (buf[0] == '\01' || buf[0] == '\02') {
|
||||
if (iamremote == 0)
|
||||
(void) write(STDERR_FILENO,
|
||||
(void) atomicio(write, STDERR_FILENO,
|
||||
buf + 1, strlen(buf + 1));
|
||||
if (buf[0] == '\02')
|
||||
exit(1);
|
||||
@ -713,7 +713,7 @@ sink(argc, argv)
|
||||
continue;
|
||||
}
|
||||
if (buf[0] == 'E') {
|
||||
(void) write(remout, "", 1);
|
||||
(void) atomicio(write, remout, "", 1);
|
||||
return;
|
||||
}
|
||||
if (ch == '\n')
|
||||
@ -737,7 +737,7 @@ sink(argc, argv)
|
||||
getnum(dummy_usec);
|
||||
if (*cp++ != '\0')
|
||||
SCREWUP("atime.usec not delimited");
|
||||
(void) write(remout, "", 1);
|
||||
(void) atomicio(write, remout, "", 1);
|
||||
continue;
|
||||
}
|
||||
if (*cp != 'C' && *cp != 'D') {
|
||||
@ -816,7 +816,7 @@ sink(argc, argv)
|
||||
bad: run_err("%s: %s", np, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
(void) write(remout, "", 1);
|
||||
(void) atomicio(write, remout, "", 1);
|
||||
if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
|
||||
(void) close(ofd);
|
||||
continue;
|
||||
@ -835,7 +835,7 @@ bad: run_err("%s: %s", np, strerror(errno));
|
||||
amt = size - i;
|
||||
count += amt;
|
||||
do {
|
||||
j = read(remin, cp, amt);
|
||||
j = atomicio(read, remin, cp, amt);
|
||||
if (j <= 0) {
|
||||
run_err("%s", j ? strerror(errno) :
|
||||
"dropped connection");
|
||||
@ -848,7 +848,7 @@ bad: run_err("%s: %s", np, strerror(errno));
|
||||
if (count == bp->cnt) {
|
||||
/* Keep reading so we stay sync'd up. */
|
||||
if (wrerr == NO) {
|
||||
j = write(ofd, bp->buf, count);
|
||||
j = atomicio(write, ofd, bp->buf, count);
|
||||
if (j != count) {
|
||||
wrerr = YES;
|
||||
wrerrno = j >= 0 ? EIO : errno;
|
||||
@ -861,7 +861,7 @@ bad: run_err("%s: %s", np, strerror(errno));
|
||||
if (showprogress)
|
||||
progressmeter(1);
|
||||
if (count != 0 && wrerr == NO &&
|
||||
(j = write(ofd, bp->buf, count)) != count) {
|
||||
(j = atomicio(write, ofd, bp->buf, count)) != count) {
|
||||
wrerr = YES;
|
||||
wrerrno = j >= 0 ? EIO : errno;
|
||||
}
|
||||
@ -897,7 +897,7 @@ bad: run_err("%s: %s", np, strerror(errno));
|
||||
run_err("%s: %s", np, strerror(wrerrno));
|
||||
break;
|
||||
case NO:
|
||||
(void) write(remout, "", 1);
|
||||
(void) atomicio(write, remout, "", 1);
|
||||
break;
|
||||
case DISPLAYED:
|
||||
break;
|
||||
@ -913,7 +913,7 @@ response()
|
||||
{
|
||||
char ch, *cp, resp, rbuf[2048];
|
||||
|
||||
if (read(remin, &resp, sizeof(resp)) != sizeof(resp))
|
||||
if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
|
||||
lostconn(0);
|
||||
|
||||
cp = rbuf;
|
||||
@ -926,13 +926,13 @@ response()
|
||||
case 1: /* error, followed by error msg */
|
||||
case 2: /* fatal error, "" */
|
||||
do {
|
||||
if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
|
||||
if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
|
||||
lostconn(0);
|
||||
*cp++ = ch;
|
||||
} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
|
||||
|
||||
if (!iamremote)
|
||||
(void) write(STDERR_FILENO, rbuf, cp - rbuf);
|
||||
(void) atomicio(write, STDERR_FILENO, rbuf, cp - rbuf);
|
||||
++errs;
|
||||
if (resp == 1)
|
||||
return (-1);
|
||||
@ -1006,7 +1006,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.26 2000/03/16 20:56:14 markus Exp $
|
||||
* $Id: scp.c,v 1.30 2000/05/02 18:21:48 deraadt Exp $
|
||||
*/
|
||||
|
||||
char *
|
||||
@ -1209,7 +1209,12 @@ progressmeter(int flag)
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||||
" - stalled -");
|
||||
} else {
|
||||
remaining = (int) (totalbytes / (statbytes / elapsed) - elapsed);
|
||||
if (flag != 1)
|
||||
remaining =
|
||||
(int)(totalbytes / (statbytes / elapsed) - elapsed);
|
||||
else
|
||||
remaining = elapsed;
|
||||
|
||||
i = remaining / 3600;
|
||||
if (i)
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||||
@ -1219,7 +1224,8 @@ progressmeter(int flag)
|
||||
" ");
|
||||
i = remaining % 3600;
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||||
"%02d:%02d ETA", i / 60, i % 60);
|
||||
"%02d:%02d%s", i / 60, i % 60,
|
||||
(flag != 1) ? " ETA" : " ");
|
||||
}
|
||||
atomicio(write, fileno(stdout), buf, strlen(buf));
|
||||
|
||||
@ -1228,7 +1234,7 @@ progressmeter(int flag)
|
||||
alarmtimer(1);
|
||||
} else if (flag == 1) {
|
||||
alarmtimer(0);
|
||||
write(fileno(stdout), "\n", 1);
|
||||
atomicio(write, fileno(stdout), "\n", 1);
|
||||
statbytes = 0;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,10 @@
|
||||
* Created: Sun Sep 10 00:30:37 1995 ylo
|
||||
* Server main loop for handling the interactive session.
|
||||
*/
|
||||
/*
|
||||
* SSH2 support by Markus Friedl.
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "xmalloc.h"
|
||||
@ -13,6 +17,12 @@
|
||||
#include "buffer.h"
|
||||
#include "servconf.h"
|
||||
#include "pty.h"
|
||||
#include "channels.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "ssh2.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
|
||||
static Buffer stdin_buffer; /* Buffer for stdin data. */
|
||||
static Buffer stdout_buffer; /* Buffer for stdout data. */
|
||||
@ -38,15 +48,18 @@ static int max_fd; /* Max file descriptor number for select(). */
|
||||
* will exit after that, as soon as forwarded connections have terminated.
|
||||
*/
|
||||
|
||||
static int child_pid; /* Pid of the child. */
|
||||
static pid_t child_pid; /* Pid of the child. */
|
||||
static volatile int child_terminated; /* The child has terminated. */
|
||||
static volatile int child_wait_status; /* Status from wait(). */
|
||||
|
||||
void
|
||||
void server_init_dispatch(void);
|
||||
|
||||
void
|
||||
sigchld_handler(int sig)
|
||||
{
|
||||
int save_errno = errno;
|
||||
int wait_pid;
|
||||
pid_t wait_pid;
|
||||
|
||||
debug("Received SIGCHLD.");
|
||||
wait_pid = wait((int *) &child_wait_status);
|
||||
if (wait_pid != -1) {
|
||||
@ -60,110 +73,21 @@ sigchld_handler(int sig)
|
||||
signal(SIGCHLD, sigchld_handler);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process any buffered packets that have been received from the client.
|
||||
*/
|
||||
void
|
||||
process_buffered_input_packets()
|
||||
void
|
||||
sigchld_handler2(int sig)
|
||||
{
|
||||
int type;
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
int row, col, xpixel, ypixel;
|
||||
int payload_len;
|
||||
|
||||
/* Process buffered packets from the client. */
|
||||
while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) {
|
||||
switch (type) {
|
||||
case SSH_CMSG_STDIN_DATA:
|
||||
/* Stdin data from the client. Append it to the buffer. */
|
||||
/* Ignore any data if the client has closed stdin. */
|
||||
if (fdin == -1)
|
||||
break;
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(payload_len, (4 + data_len), type);
|
||||
buffer_append(&stdin_buffer, data, data_len);
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_EOF:
|
||||
/*
|
||||
* 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;
|
||||
break;
|
||||
|
||||
case SSH_CMSG_WINDOW_SIZE:
|
||||
debug("Window change received.");
|
||||
packet_integrity_check(payload_len, 4 * 4, type);
|
||||
row = packet_get_int();
|
||||
col = packet_get_int();
|
||||
xpixel = packet_get_int();
|
||||
ypixel = packet_get_int();
|
||||
if (fdin != -1)
|
||||
pty_change_window_size(fdin, row, col, xpixel, ypixel);
|
||||
break;
|
||||
|
||||
case SSH_MSG_PORT_OPEN:
|
||||
debug("Received port open request.");
|
||||
channel_input_port_open(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
debug("Received channel open confirmation.");
|
||||
packet_integrity_check(payload_len, 4 + 4, type);
|
||||
channel_input_open_confirmation();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_OPEN_FAILURE:
|
||||
debug("Received channel open failure.");
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_open_failure();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_DATA:
|
||||
channel_input_data(payload_len);
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE:
|
||||
debug("Received channel close.");
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close();
|
||||
break;
|
||||
|
||||
case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION:
|
||||
debug("Received channel close confirmation.");
|
||||
packet_integrity_check(payload_len, 4, type);
|
||||
channel_input_close_confirmation();
|
||||
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.
|
||||
*/
|
||||
packet_disconnect("Protocol error during session: type %d",
|
||||
type);
|
||||
}
|
||||
}
|
||||
int save_errno = errno;
|
||||
debug("Received SIGCHLD.");
|
||||
child_terminated = 1;
|
||||
signal(SIGCHLD, sigchld_handler2);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make packets from buffered stderr data, and buffer it for sending
|
||||
* to the client.
|
||||
*/
|
||||
void
|
||||
void
|
||||
make_packets_from_stderr_data()
|
||||
{
|
||||
int len;
|
||||
@ -192,7 +116,7 @@ make_packets_from_stderr_data()
|
||||
* Make packets from buffered stdout data, and buffer it for sending to the
|
||||
* client.
|
||||
*/
|
||||
void
|
||||
void
|
||||
make_packets_from_stdout_data()
|
||||
{
|
||||
int len;
|
||||
@ -223,7 +147,7 @@ make_packets_from_stdout_data()
|
||||
* have data or can accept data. Optionally, a maximum time can be specified
|
||||
* for the duration of the wait (0 = infinite).
|
||||
*/
|
||||
void
|
||||
void
|
||||
wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
unsigned int max_time_milliseconds)
|
||||
{
|
||||
@ -240,15 +164,21 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
* 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 (compat20) {
|
||||
/* wrong: bad condition XXX */
|
||||
if (channel_not_very_much_buffered_data())
|
||||
FD_SET(connection_in, readset);
|
||||
} else {
|
||||
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 (packet_not_very_much_data_to_write()) {
|
||||
if (!compat20 && packet_not_very_much_data_to_write()) {
|
||||
if (!fdout_eof)
|
||||
FD_SET(fdout, readset);
|
||||
if (!fderr_eof)
|
||||
@ -268,7 +198,7 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
|
||||
/* If we have buffered data, try to write some of that data to the
|
||||
program. */
|
||||
if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
|
||||
if (!compat20 && fdin != -1 && buffer_len(&stdin_buffer) > 0)
|
||||
FD_SET(fdin, writeset);
|
||||
|
||||
/* Update the maximum descriptor number if appropriate. */
|
||||
@ -290,6 +220,8 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
|
||||
tvp = &tv;
|
||||
}
|
||||
if (tvp!=NULL)
|
||||
debug("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
|
||||
|
||||
/* Wait for something to happen, or the timeout to expire. */
|
||||
ret = select(max_fd + 1, readset, writeset, NULL, tvp);
|
||||
@ -306,7 +238,7 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
* Processes input from the client and the program. Input data is stored
|
||||
* in buffers and processed later.
|
||||
*/
|
||||
void
|
||||
void
|
||||
process_input(fd_set * readset)
|
||||
{
|
||||
int len;
|
||||
@ -333,6 +265,9 @@ process_input(fd_set * readset)
|
||||
/* Buffer any received data. */
|
||||
packet_process_incoming(buf, len);
|
||||
}
|
||||
if (compat20)
|
||||
return;
|
||||
|
||||
/* Read and buffer any available stdout data from the program. */
|
||||
if (!fdout_eof && FD_ISSET(fdout, readset)) {
|
||||
len = read(fdout, buf, sizeof(buf));
|
||||
@ -356,20 +291,20 @@ process_input(fd_set * readset)
|
||||
/*
|
||||
* Sends data from internal buffers to client program stdin.
|
||||
*/
|
||||
void
|
||||
void
|
||||
process_output(fd_set * writeset)
|
||||
{
|
||||
int len;
|
||||
|
||||
/* Write buffered data to program stdin. */
|
||||
if (fdin != -1 && FD_ISSET(fdin, writeset)) {
|
||||
if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) {
|
||||
len = write(fdin, buffer_ptr(&stdin_buffer),
|
||||
buffer_len(&stdin_buffer));
|
||||
if (len <= 0) {
|
||||
#ifdef USE_PIPES
|
||||
close(fdin);
|
||||
#else
|
||||
if (fdout == -1)
|
||||
if (fdin != fdout)
|
||||
close(fdin);
|
||||
else
|
||||
shutdown(fdin, SHUT_WR); /* We will no longer send. */
|
||||
@ -391,7 +326,7 @@ process_output(fd_set * writeset)
|
||||
* Wait until all buffered output has been sent to the client.
|
||||
* This is used when the program terminates.
|
||||
*/
|
||||
void
|
||||
void
|
||||
drain_output()
|
||||
{
|
||||
/* Send any buffered stdout data to the client. */
|
||||
@ -416,6 +351,12 @@ drain_output()
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
void
|
||||
process_buffered_input_packets()
|
||||
{
|
||||
dispatch_run(DISPATCH_NONBLOCK, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs the interactive session. This handles data transmission between
|
||||
* the client and the program. Note that the notion of stdin, stdout, and
|
||||
@ -423,10 +364,11 @@ drain_output()
|
||||
* stdin (of the child program), and reads from stdout and stderr (of the
|
||||
* child program).
|
||||
*/
|
||||
void
|
||||
server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
void
|
||||
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
{
|
||||
int wait_status, wait_pid; /* Status and pid returned by wait(). */
|
||||
int wait_status; /* Status returned by wait(). */
|
||||
pid_t wait_pid; /* pid returned by wait(). */
|
||||
int waiting_termination = 0; /* Have displayed waiting close message. */
|
||||
unsigned int max_time_milliseconds;
|
||||
unsigned int previous_stdout_buffer_bytes;
|
||||
@ -480,6 +422,8 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
if (fderr == -1)
|
||||
fderr_eof = 1;
|
||||
|
||||
server_init_dispatch();
|
||||
|
||||
/* Main loop of the server for the interactive session mode. */
|
||||
for (;;) {
|
||||
fd_set readset, writeset;
|
||||
@ -495,7 +439,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
#ifdef USE_PIPES
|
||||
close(fdin);
|
||||
#else
|
||||
if (fdout == -1)
|
||||
if (fdin != fdout)
|
||||
close(fdin);
|
||||
else
|
||||
shutdown(fdin, SHUT_WR); /* We will no longer send. */
|
||||
@ -536,7 +480,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
if (fdout_eof && fderr_eof && !packet_have_data_to_write() &&
|
||||
buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) {
|
||||
if (!channel_still_open())
|
||||
goto quit;
|
||||
break;
|
||||
if (!waiting_termination) {
|
||||
const char *s = "Waiting for forwarded connections to terminate...\r\n";
|
||||
char *cp;
|
||||
@ -563,7 +507,6 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
process_output(&writeset);
|
||||
}
|
||||
|
||||
quit:
|
||||
/* Cleanup and termination code. */
|
||||
|
||||
/* Wait until all output has been sent to the client. */
|
||||
@ -649,3 +592,233 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg)
|
||||
packet_disconnect("wait returned status %04x.", wait_status);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
void
|
||||
server_loop2(void)
|
||||
{
|
||||
fd_set readset, writeset;
|
||||
int had_channel = 0;
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
debug("Entering interactive session for SSH2.");
|
||||
|
||||
signal(SIGCHLD, sigchld_handler2);
|
||||
child_terminated = 0;
|
||||
connection_in = packet_get_connection_in();
|
||||
connection_out = packet_get_connection_out();
|
||||
max_fd = connection_in;
|
||||
if (connection_out > max_fd)
|
||||
max_fd = connection_out;
|
||||
server_init_dispatch();
|
||||
|
||||
for (;;) {
|
||||
process_buffered_input_packets();
|
||||
if (!had_channel && channel_still_open())
|
||||
had_channel = 1;
|
||||
if (had_channel && !channel_still_open()) {
|
||||
debug("!channel_still_open.");
|
||||
break;
|
||||
}
|
||||
if (packet_not_very_much_data_to_write())
|
||||
channel_output_poll();
|
||||
wait_until_can_do_something(&readset, &writeset, 0);
|
||||
if (child_terminated) {
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
child_terminated = 0;
|
||||
}
|
||||
channel_after_select(&readset, &writeset);
|
||||
process_input(&readset);
|
||||
process_output(&writeset);
|
||||
}
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
channel_stop_listening();
|
||||
}
|
||||
|
||||
void
|
||||
server_input_stdin_data(int type, int plen)
|
||||
{
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
|
||||
/* Stdin data from the client. Append it to the buffer. */
|
||||
/* Ignore any data if the client has closed stdin. */
|
||||
if (fdin == -1)
|
||||
return;
|
||||
data = packet_get_string(&data_len);
|
||||
packet_integrity_check(plen, (4 + data_len), type);
|
||||
buffer_append(&stdin_buffer, data, data_len);
|
||||
memset(data, 0, data_len);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
void
|
||||
server_input_eof(int type, int plen)
|
||||
{
|
||||
/*
|
||||
* 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(plen, 0, type);
|
||||
stdin_eof = 1;
|
||||
}
|
||||
|
||||
void
|
||||
server_input_window_size(int type, int plen)
|
||||
{
|
||||
int row = packet_get_int();
|
||||
int col = packet_get_int();
|
||||
int xpixel = packet_get_int();
|
||||
int ypixel = packet_get_int();
|
||||
|
||||
debug("Window change received.");
|
||||
packet_integrity_check(plen, 4 * 4, type);
|
||||
if (fdin != -1)
|
||||
pty_change_window_size(fdin, row, col, xpixel, ypixel);
|
||||
}
|
||||
|
||||
int
|
||||
input_direct_tcpip(void)
|
||||
{
|
||||
int sock;
|
||||
char *target, *originator;
|
||||
int target_port, originator_port;
|
||||
|
||||
target = packet_get_string(NULL);
|
||||
target_port = packet_get_int();
|
||||
originator = packet_get_string(NULL);
|
||||
originator_port = packet_get_int();
|
||||
packet_done();
|
||||
/* XXX check permission */
|
||||
sock = channel_connect_to(target, target_port);
|
||||
xfree(target);
|
||||
xfree(originator);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
|
||||
sock, sock, -1, 4*1024, 32*1024, 0, xstrdup("direct-tcpip"));
|
||||
}
|
||||
|
||||
void
|
||||
server_input_channel_open(int type, int plen)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
char *ctype;
|
||||
int id;
|
||||
unsigned int len;
|
||||
int rchan;
|
||||
int rmaxpack;
|
||||
int rwindow;
|
||||
|
||||
ctype = packet_get_string(&len);
|
||||
rchan = packet_get_int();
|
||||
rwindow = packet_get_int();
|
||||
rmaxpack = packet_get_int();
|
||||
|
||||
debug("channel_input_open: ctype %s rchan %d win %d max %d",
|
||||
ctype, rchan, rwindow, rmaxpack);
|
||||
|
||||
if (strcmp(ctype, "session") == 0) {
|
||||
debug("open session");
|
||||
packet_done();
|
||||
/*
|
||||
* A server session has no fd to read or write
|
||||
* until a CHANNEL_REQUEST for a shell is made,
|
||||
* so we set the type to SSH_CHANNEL_LARVAL.
|
||||
* Additionally, a callback for handling all
|
||||
* CHANNEL_REQUEST messages is registered.
|
||||
*/
|
||||
id = channel_new(ctype, SSH_CHANNEL_LARVAL,
|
||||
-1, -1, -1, 0, 32*1024, 0, xstrdup("server-session"));
|
||||
if (session_open(id) == 1) {
|
||||
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
|
||||
session_input_channel_req, (void *)0);
|
||||
channel_register_cleanup(id, session_close_by_channel);
|
||||
c = channel_lookup(id);
|
||||
} else {
|
||||
debug("session open failed, free channel %d", id);
|
||||
channel_free(id);
|
||||
}
|
||||
} else if (strcmp(ctype, "direct-tcpip") == 0) {
|
||||
debug("open direct-tcpip");
|
||||
id = input_direct_tcpip();
|
||||
if (id >= 0)
|
||||
c = channel_lookup(id);
|
||||
}
|
||||
if (c != NULL) {
|
||||
debug("confirm %s", ctype);
|
||||
c->remote_id = rchan;
|
||||
c->remote_window = rwindow;
|
||||
c->remote_maxpacket = rmaxpack;
|
||||
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
packet_send();
|
||||
} else {
|
||||
debug("failure %s", ctype);
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(rchan);
|
||||
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
|
||||
packet_put_cstring("bla bla");
|
||||
packet_put_cstring("");
|
||||
packet_send();
|
||||
}
|
||||
xfree(ctype);
|
||||
}
|
||||
|
||||
void
|
||||
server_init_dispatch_20()
|
||||
{
|
||||
debug("server_init_dispatch_20");
|
||||
dispatch_init(&dispatch_protocol_error);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
|
||||
}
|
||||
void
|
||||
server_init_dispatch_13()
|
||||
{
|
||||
debug("server_init_dispatch_13");
|
||||
dispatch_init(NULL);
|
||||
dispatch_set(SSH_CMSG_EOF, &server_input_eof);
|
||||
dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data);
|
||||
dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
|
||||
}
|
||||
void
|
||||
server_init_dispatch_15()
|
||||
{
|
||||
server_init_dispatch_13();
|
||||
debug("server_init_dispatch_15");
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
|
||||
}
|
||||
void
|
||||
server_init_dispatch()
|
||||
{
|
||||
if (compat20)
|
||||
server_init_dispatch_20();
|
||||
else if (compat13)
|
||||
server_init_dispatch_13();
|
||||
else
|
||||
server_init_dispatch_15();
|
||||
}
|
||||
|
1516
crypto/openssh/session.c
Normal file
1516
crypto/openssh/session.c
Normal file
File diff suppressed because it is too large
Load Diff
14
crypto/openssh/session.h
Normal file
14
crypto/openssh/session.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef SESSION_H
|
||||
#define SESSION_H
|
||||
|
||||
/* SSH1 */
|
||||
void do_authenticated(struct passwd * pw);
|
||||
|
||||
/* SSH2 */
|
||||
void do_authenticated2(void);
|
||||
int session_open(int id);
|
||||
void session_input_channel_req(int id, void *arg);
|
||||
void session_close_by_pid(pid_t pid, int status);
|
||||
void session_close_by_channel(int id, void *arg);
|
||||
|
||||
#endif
|
@ -9,28 +9,28 @@
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: ssh-add.1,v 1.11 2000/03/23 21:11:38 aaron Exp $
|
||||
.\" $Id: ssh-add.1,v 1.13 2000/05/03 18:04:38 markus Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH-ADD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh-add
|
||||
.Nd adds identities for the authentication agent
|
||||
.Nd adds RSA identities for the authentication agent
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-add
|
||||
.Op Fl lLdD
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
adds identities to the authentication agent,
|
||||
adds RSA identities to the authentication agent,
|
||||
.Xr ssh-agent 1 .
|
||||
When run without arguments, it adds the file
|
||||
.Pa $HOME/.ssh/identity .
|
||||
Alternative file names can be given on the command line.
|
||||
If any file requires a passphrase,
|
||||
.Nm
|
||||
asks for the passphrase from the user.
|
||||
asks for the passphrase from the user.
|
||||
The Passphrase it is read from the user's tty.
|
||||
.Pp
|
||||
The authentication agent must be running and must be an ancestor of
|
||||
@ -108,7 +108,7 @@ external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5.
|
||||
.It
|
||||
contains added support for
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
|
@ -7,30 +7,35 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh-add.c,v 1.15 1999/12/02 20:05:40 markus Exp $");
|
||||
RCSID("$Id: ssh-add.c,v 1.16 2000/04/26 20:56:29 markus Exp $");
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "authfd.h"
|
||||
#include "fingerprint.h"
|
||||
#include "key.h"
|
||||
#include "authfile.h"
|
||||
|
||||
void
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
Key *public;
|
||||
char *comment;
|
||||
|
||||
key = RSA_new();
|
||||
if (!load_public_key(filename, key, &comment)) {
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ssh_remove_identity(ac, key))
|
||||
if (ssh_remove_identity(ac, public->rsa))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
key_free(public);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
@ -85,20 +90,19 @@ ssh_askpass(char *askpass, char *msg)
|
||||
void
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
RSA *public_key;
|
||||
Key *public;
|
||||
Key *private;
|
||||
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();
|
||||
if (!load_public_key(filename, public_key, &saved_comment)) {
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &saved_comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
RSA_free(public_key);
|
||||
key_free(public);
|
||||
|
||||
if (!interactive && getenv("DISPLAY")) {
|
||||
if (getenv(SSH_ASKPASS_ENV))
|
||||
@ -108,7 +112,8 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
||||
}
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
success = load_private_key(filename, "", key, &comment);
|
||||
private = key_new(KEY_RSA);
|
||||
success = load_private_key(filename, "", private, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %.200s\n", filename);
|
||||
if (!interactive && askpass == NULL) {
|
||||
@ -129,7 +134,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
success = load_private_key(filename, pass, key, &comment);
|
||||
success = load_private_key(filename, pass, private, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
@ -139,11 +144,11 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
||||
}
|
||||
xfree(saved_comment);
|
||||
|
||||
if (ssh_add_identity(ac, key, comment))
|
||||
if (ssh_add_identity(ac, private->rsa, comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: ssh-agent.1,v 1.10 2000/03/23 21:10:10 aaron Exp $
|
||||
.\" $OpenBSD: ssh-agent.1,v 1.12 2000/05/03 18:04:39 markus Exp $
|
||||
.\"
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
@ -18,16 +18,16 @@
|
||||
.Nm ssh-agent
|
||||
.Nd authentication agent
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-agent
|
||||
.Nm ssh-agent
|
||||
.Op Fl c Li | Fl s
|
||||
.Op Fl k
|
||||
.Oo
|
||||
.Ar command
|
||||
.Op Ar args ...
|
||||
.Oc
|
||||
.Sh DESCRIPTION
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a program to hold authentication private keys.
|
||||
is a program to hold private keys used for RSA authentication.
|
||||
The idea is that
|
||||
.Nm
|
||||
is started in the beginning of an X-session or a login session, and
|
||||
@ -64,12 +64,12 @@ When the command dies, so does the agent.
|
||||
The agent initially does not have any private keys.
|
||||
Keys are added using
|
||||
.Xr ssh-add 1 .
|
||||
When executed without arguments,
|
||||
When executed without arguments,
|
||||
.Xr ssh-add 1
|
||||
adds the
|
||||
adds the
|
||||
.Pa $HOME/.ssh/identity
|
||||
file.
|
||||
If the identity has a passphrase,
|
||||
If the identity has a passphrase,
|
||||
.Xr ssh-add 1
|
||||
asks for the passphrase (using a small X11 application if running
|
||||
under X11, or from the terminal if running without X).
|
||||
@ -152,7 +152,7 @@ external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5.
|
||||
.It
|
||||
contains added support for
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
|
@ -9,7 +9,7 @@
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: ssh-keygen.1,v 1.12 2000/03/23 21:10:10 aaron Exp $
|
||||
.\" $Id: ssh-keygen.1,v 1.18 2000/05/08 17:26:04 hugh Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH-KEYGEN 1
|
||||
@ -19,7 +19,7 @@
|
||||
.Nd authentication key generation
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh-keygen
|
||||
.Op Fl q
|
||||
.Op Fl dq
|
||||
.Op Fl b Ar bits
|
||||
.Op Fl N Ar new_passphrase
|
||||
.Op Fl C Ar comment
|
||||
@ -30,6 +30,15 @@
|
||||
.Op Fl N Ar new_passphrase
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl x
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl X
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl y
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl c
|
||||
.Op Fl P Ar passphrase
|
||||
.Op Fl C Ar comment
|
||||
@ -37,15 +46,27 @@
|
||||
.Nm ssh-keygen
|
||||
.Fl l
|
||||
.Op Fl f Ar keyfile
|
||||
.Sh DESCRIPTION
|
||||
.Nm ssh-keygen
|
||||
.Fl R
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
generates and manages authentication keys for
|
||||
generates and manages authentication keys for
|
||||
.Xr ssh 1 .
|
||||
.Nm
|
||||
defaults to generating an RSA key for use by protocols 1.3 and 1.5;
|
||||
specifying the
|
||||
.Fl d
|
||||
flag will create a DSA key instead for use by protocol 2.0.
|
||||
.Pp
|
||||
Normally each user wishing to use SSH
|
||||
with RSA authentication runs this once to create the authentication
|
||||
with RSA or DSA authentication runs this once to create the authentication
|
||||
key in
|
||||
.Pa $HOME/.ssh/identity .
|
||||
Additionally, the system administrator may use this to generate host keys.
|
||||
.Pa $HOME/.ssh/identity
|
||||
or
|
||||
.Pa $HOME/.ssh/id_dsa .
|
||||
Additionally, the system administrator may use this to generate host keys,
|
||||
as seen in
|
||||
.Pa /etc/rc .
|
||||
.Pp
|
||||
Normally this program generates the key and asks for a file in which
|
||||
to store the private key.
|
||||
@ -69,7 +90,7 @@ If the passphrase is
|
||||
lost or forgotten, you will have to generate a new key and copy the
|
||||
corresponding public key to other machines.
|
||||
.Pp
|
||||
There is also a comment field in the key file that is only for
|
||||
For RSA, there is also a comment field in the key file that is only for
|
||||
convenience to the user to help identify the key.
|
||||
The comment can tell what the key is for, or whatever is useful.
|
||||
The comment is initialized to
|
||||
@ -78,6 +99,9 @@ when the key is created, but can be changed using the
|
||||
.Fl c
|
||||
option.
|
||||
.Pp
|
||||
After a key is generated, instructions below detail where the keys
|
||||
should be placed to be activated.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl b Ar bits
|
||||
@ -112,6 +136,19 @@ Provides the new comment.
|
||||
Provides the new passphrase.
|
||||
.It Fl P Ar passphrase
|
||||
Provides the (old) passphrase.
|
||||
.It Fl R
|
||||
If RSA support is functional, immediately exits with code 0. If RSA
|
||||
support is not functional, exits with code 1. This flag will be
|
||||
removed once the RSA patent expires.
|
||||
.It Fl x
|
||||
This option will read a private
|
||||
OpenSSH DSA format file and print a SSH2-compatible public key to stdout.
|
||||
.It Fl X
|
||||
This option will read a
|
||||
SSH2-compatible public key file and print an OpenSSH DSA compatible public key to stdout.
|
||||
.It Fl y
|
||||
This option will read a private
|
||||
OpenSSH DSA format file and print an OpenSSH DSA public key to stdout.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
@ -124,6 +161,8 @@ used to encrypt the private part of this file using 3DES.
|
||||
This file is not automatically accessed by
|
||||
.Nm
|
||||
but it is offered as the default file for the private key.
|
||||
.Xr sshd 8
|
||||
will read this file when a login attempt is made.
|
||||
.It Pa $HOME/.ssh/identity.pub
|
||||
Contains the public key for authentication.
|
||||
The contents of this file should be added to
|
||||
@ -131,6 +170,24 @@ The contents of this file should be added to
|
||||
on all machines
|
||||
where you wish to log in using RSA authentication.
|
||||
There is no need to keep the contents of this file secret.
|
||||
.It Pa $HOME/.ssh/id_dsa
|
||||
Contains the DSA authentication identity of the user.
|
||||
This file should not be readable by anyone but the user.
|
||||
It is possible to
|
||||
specify a passphrase when generating the key; that passphrase will be
|
||||
used to encrypt the private part of this file using 3DES.
|
||||
This file is not automatically accessed by
|
||||
.Nm
|
||||
but it is offered as the default file for the private key.
|
||||
.Xr sshd 8
|
||||
will read this file when a login attempt is made.
|
||||
.It Pa $HOME/.ssh/id_dsa.pub
|
||||
Contains the public key for authentication.
|
||||
The contents of this file should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
on all machines
|
||||
where you wish to log in using DSA authentication.
|
||||
There is no need to keep the contents of this file secret.
|
||||
.Sh AUTHOR
|
||||
Tatu Ylonen <ylo@cs.hut.fi>
|
||||
.Pp
|
||||
@ -150,7 +207,7 @@ external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5.
|
||||
.It
|
||||
contains added support for
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
|
@ -7,20 +7,23 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh-keygen.c,v 1.17 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$Id: ssh-keygen.c,v 1.25 2000/05/08 18:23:07 markus Exp $");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "fingerprint.h"
|
||||
#include "key.h"
|
||||
#include "rsa.h"
|
||||
#include "dsa.h"
|
||||
#include "authfile.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
/* Generated private key. */
|
||||
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/DSA key. This value can be changed on the command line. */
|
||||
int bits = 1024;
|
||||
|
||||
/*
|
||||
@ -53,15 +56,24 @@ char *identity_new_passphrase = NULL;
|
||||
/* This is set to the new comment if given on the command line. */
|
||||
char *identity_comment = NULL;
|
||||
|
||||
/* Dump public key file in format used by real and the original SSH 2 */
|
||||
int convert_to_ssh2 = 0;
|
||||
int convert_from_ssh2 = 0;
|
||||
int print_public = 0;
|
||||
int dsa_mode = 0;
|
||||
|
||||
/* argv0 */
|
||||
extern char *__progname;
|
||||
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
void
|
||||
ask_filename(struct passwd *pw, const char *prompt)
|
||||
{
|
||||
char buf[1024];
|
||||
snprintf(identity_file, sizeof(identity_file), "%s/%s",
|
||||
pw->pw_dir, SSH_CLIENT_IDENTITY);
|
||||
pw->pw_dir,
|
||||
dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
|
||||
printf("%s (%s): ", prompt, identity_file);
|
||||
fflush(stdout);
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL)
|
||||
@ -73,12 +85,148 @@ ask_filename(struct passwd *pw, const char *prompt)
|
||||
have_identity = 1;
|
||||
}
|
||||
|
||||
int
|
||||
try_load_key(char *filename, Key *k)
|
||||
{
|
||||
int success = 1;
|
||||
if (!load_private_key(filename, "", k, NULL)) {
|
||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
||||
if (!load_private_key(filename, pass, k, NULL)) {
|
||||
success = 0;
|
||||
}
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
|
||||
|
||||
void
|
||||
do_convert_to_ssh2(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int len;
|
||||
unsigned char *blob;
|
||||
struct stat st;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
k = key_new(KEY_DSA);
|
||||
if (!try_load_key(identity_file, k)) {
|
||||
fprintf(stderr, "load failed\n");
|
||||
exit(1);
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
|
||||
fprintf(stdout,
|
||||
"Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
|
||||
BN_num_bits(k->dsa->p),
|
||||
pw->pw_name, hostname);
|
||||
dump_base64(stdout, blob, len);
|
||||
fprintf(stdout, SSH_COM_MAGIC_END "\n");
|
||||
key_free(k);
|
||||
xfree(blob);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
do_convert_from_ssh2(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int blen;
|
||||
char line[1024], *p;
|
||||
char blob[8096];
|
||||
char encoded[8096];
|
||||
struct stat st;
|
||||
int escaped = 0;
|
||||
FILE *fp;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fp = fopen(identity_file, "r");
|
||||
if (fp == NULL) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
encoded[0] = '\0';
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (!(p = strchr(line, '\n'))) {
|
||||
fprintf(stderr, "input line too long.\n");
|
||||
exit(1);
|
||||
}
|
||||
if (p > line && p[-1] == '\\')
|
||||
escaped++;
|
||||
if (strncmp(line, "----", 4) == 0 ||
|
||||
strstr(line, ": ") != NULL) {
|
||||
fprintf(stderr, "ignore: %s", line);
|
||||
continue;
|
||||
}
|
||||
if (escaped) {
|
||||
escaped--;
|
||||
fprintf(stderr, "escaped: %s", line);
|
||||
continue;
|
||||
}
|
||||
*p = '\0';
|
||||
strlcat(encoded, line, sizeof(encoded));
|
||||
}
|
||||
blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
|
||||
if (blen < 0) {
|
||||
fprintf(stderr, "uudecode failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
k = dsa_key_from_blob(blob, blen);
|
||||
if (!key_write(k, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
key_free(k);
|
||||
fprintf(stdout, "\n");
|
||||
fclose(fp);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
do_print_public(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int len;
|
||||
unsigned char *blob;
|
||||
struct stat st;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
k = key_new(KEY_DSA);
|
||||
if (!try_load_key(identity_file, k)) {
|
||||
fprintf(stderr, "load failed\n");
|
||||
exit(1);
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
if (!key_write(k, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
key_free(k);
|
||||
xfree(blob);
|
||||
fprintf(stdout, "\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
do_fingerprint(struct passwd *pw)
|
||||
{
|
||||
FILE *f;
|
||||
BIGNUM *e, *n;
|
||||
RSA *public_key;
|
||||
Key *public;
|
||||
char *comment = NULL, *cp, *ep, line[16*1024];
|
||||
int i, skip = 0, num = 1, invalid = 1;
|
||||
unsigned int ignore;
|
||||
@ -90,17 +238,16 @@ do_fingerprint(struct passwd *pw)
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
public_key = RSA_new();
|
||||
if (load_public_key(identity_file, public_key, &comment)) {
|
||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
||||
fingerprint(public_key->e, public_key->n),
|
||||
comment);
|
||||
RSA_free(public_key);
|
||||
public = key_new(KEY_RSA);
|
||||
if (load_public_key(identity_file, public, &comment)) {
|
||||
printf("%d %s %s\n", BN_num_bits(public->rsa->n),
|
||||
key_fingerprint(public), comment);
|
||||
key_free(public);
|
||||
exit(0);
|
||||
}
|
||||
RSA_free(public_key);
|
||||
key_free(public);
|
||||
|
||||
/* XXX */
|
||||
f = fopen(identity_file, "r");
|
||||
if (f != NULL) {
|
||||
n = BN_new();
|
||||
@ -168,7 +315,9 @@ do_change_passphrase(struct passwd *pw)
|
||||
char *comment;
|
||||
char *old_passphrase, *passphrase1, *passphrase2;
|
||||
struct stat st;
|
||||
RSA *private_key;
|
||||
Key *private;
|
||||
Key *public;
|
||||
int type = dsa_mode ? KEY_DSA : KEY_RSA;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
@ -176,22 +325,26 @@ do_change_passphrase(struct passwd *pw)
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
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);
|
||||
|
||||
if (type == KEY_RSA) {
|
||||
/* XXX this works currently only for RSA */
|
||||
public = key_new(type);
|
||||
if (!load_public_key(identity_file, public, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
/* Clear the public key since we are just about to load the whole file. */
|
||||
key_free(public);
|
||||
}
|
||||
/* Clear the public key since we are just about to load the whole file. */
|
||||
RSA_free(public_key);
|
||||
|
||||
/* Try to load the file with empty passphrase. */
|
||||
private_key = RSA_new();
|
||||
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
||||
private = key_new(type);
|
||||
if (!load_private_key(identity_file, "", private, &comment)) {
|
||||
if (identity_passphrase)
|
||||
old_passphrase = xstrdup(identity_passphrase);
|
||||
else
|
||||
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
|
||||
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
|
||||
if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
|
||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||
xfree(old_passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
@ -226,19 +379,19 @@ do_change_passphrase(struct passwd *pw)
|
||||
}
|
||||
|
||||
/* Save the file using the new passphrase. */
|
||||
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
|
||||
if (!save_private_key(identity_file, passphrase1, private, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the passphrase and the copy of the key in memory. */
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
RSA_free(private_key); /* Destroys contents */
|
||||
key_free(private); /* Destroys contents */
|
||||
xfree(comment);
|
||||
|
||||
printf("Your identification has been saved with the new passphrase.\n");
|
||||
@ -252,11 +405,11 @@ void
|
||||
do_change_comment(struct passwd *pw)
|
||||
{
|
||||
char new_comment[1024], *comment;
|
||||
RSA *private_key;
|
||||
Key *private;
|
||||
Key *public;
|
||||
char *passphrase;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
char *tmpbuf;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
@ -268,14 +421,14 @@ do_change_comment(struct passwd *pw)
|
||||
* 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)) {
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(identity_file, public, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
private_key = RSA_new();
|
||||
|
||||
if (load_private_key(identity_file, "", private_key, &comment))
|
||||
private = key_new(KEY_RSA);
|
||||
if (load_private_key(identity_file, "", private, &comment))
|
||||
passphrase = xstrdup("");
|
||||
else {
|
||||
if (identity_passphrase)
|
||||
@ -285,7 +438,7 @@ do_change_comment(struct passwd *pw)
|
||||
else
|
||||
passphrase = read_passphrase("Enter passphrase: ", 1);
|
||||
/* Try to load using the passphrase. */
|
||||
if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
|
||||
if (!load_private_key(identity_file, passphrase, private, &comment)) {
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
@ -301,7 +454,7 @@ do_change_comment(struct passwd *pw)
|
||||
fflush(stdout);
|
||||
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
exit(1);
|
||||
}
|
||||
if (strchr(new_comment, '\n'))
|
||||
@ -309,18 +462,18 @@ do_change_comment(struct passwd *pw)
|
||||
}
|
||||
|
||||
/* Save the file using the new passphrase. */
|
||||
if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
|
||||
if (!save_private_key(identity_file, passphrase, private, new_comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
|
||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||
f = fopen(identity_file, "w");
|
||||
@ -328,13 +481,10 @@ do_change_comment(struct passwd *pw)
|
||||
printf("Could not save your public key in %s\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
||||
tmpbuf = BN_bn2dec(public_key->e);
|
||||
fprintf(f, "%s ", tmpbuf);
|
||||
free(tmpbuf);
|
||||
tmpbuf = BN_bn2dec(public_key->n);
|
||||
fprintf(f, "%s %s\n", tmpbuf, new_comment);
|
||||
free(tmpbuf);
|
||||
if (!key_write(public, f))
|
||||
fprintf(stderr, "write key failed");
|
||||
key_free(public);
|
||||
fprintf(f, " %s\n", new_comment);
|
||||
fclose(f);
|
||||
|
||||
xfree(comment);
|
||||
@ -346,8 +496,7 @@ do_change_comment(struct passwd *pw)
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
printf("ssh-keygen version %s\n", SSH_VERSION);
|
||||
printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
|
||||
printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -359,29 +508,28 @@ main(int ac, char **av)
|
||||
{
|
||||
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
|
||||
struct passwd *pw;
|
||||
char *tmpbuf;
|
||||
int opt;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
Key *private;
|
||||
Key *public;
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
/* we need this for the home * directory. */
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
printf("You don't exist, go away!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
perror("gethostname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
|
||||
while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bits = atoi(optarg);
|
||||
@ -424,6 +572,29 @@ main(int ac, char **av)
|
||||
quiet = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (rsa_alive() == 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
convert_to_ssh2 = 1;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
convert_from_ssh2 = 1;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
print_public = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dsa_mode = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@ -437,22 +608,44 @@ main(int ac, char **av)
|
||||
printf("Can only have one of -p and -c.\n");
|
||||
usage();
|
||||
}
|
||||
/* check if RSA support is needed and exists */
|
||||
if (dsa_mode == 0 && rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
if (print_fingerprint)
|
||||
do_fingerprint(pw);
|
||||
if (change_passphrase)
|
||||
do_change_passphrase(pw);
|
||||
if (change_comment)
|
||||
do_change_comment(pw);
|
||||
if (convert_to_ssh2)
|
||||
do_convert_to_ssh2(pw);
|
||||
if (convert_from_ssh2)
|
||||
do_convert_from_ssh2(pw);
|
||||
if (print_public)
|
||||
do_print_public(pw);
|
||||
|
||||
arc4random_stir();
|
||||
|
||||
if (quiet)
|
||||
rsa_set_verbose(0);
|
||||
|
||||
/* Generate the rsa key pair. */
|
||||
private_key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
rsa_generate_key(private_key, public_key, bits);
|
||||
if (dsa_mode != 0) {
|
||||
if (!quiet)
|
||||
printf("Generating DSA parameter and key.\n");
|
||||
public = private = dsa_generate_key(bits);
|
||||
if (private == NULL) {
|
||||
fprintf(stderr, "dsa_generate_keys failed");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if (quiet)
|
||||
rsa_set_verbose(0);
|
||||
/* Generate the rsa key pair. */
|
||||
public = key_new(KEY_RSA);
|
||||
private = key_new(KEY_RSA);
|
||||
rsa_generate_key(private->rsa, public->rsa, bits);
|
||||
}
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which to save the key");
|
||||
@ -504,18 +697,14 @@ main(int ac, char **av)
|
||||
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);
|
||||
}
|
||||
/* Create default commend field for the passphrase. */
|
||||
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
|
||||
}
|
||||
|
||||
/* Save the key with the given passphrase and comment. */
|
||||
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
|
||||
if (!save_private_key(identity_file, passphrase1, private, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
exit(1);
|
||||
@ -525,7 +714,9 @@ main(int ac, char **av)
|
||||
xfree(passphrase1);
|
||||
|
||||
/* Clear the private key and the random number generator. */
|
||||
RSA_free(private_key);
|
||||
if (private != public) {
|
||||
key_free(private);
|
||||
}
|
||||
arc4random_stir();
|
||||
|
||||
if (!quiet)
|
||||
@ -537,21 +728,18 @@ main(int ac, char **av)
|
||||
printf("Could not save your public key in %s\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
||||
tmpbuf = BN_bn2dec(public_key->e);
|
||||
fprintf(f, "%s ", tmpbuf);
|
||||
free(tmpbuf);
|
||||
tmpbuf = BN_bn2dec(public_key->n);
|
||||
fprintf(f, "%s %s\n", tmpbuf, comment);
|
||||
free(tmpbuf);
|
||||
if (!key_write(public, f))
|
||||
fprintf(stderr, "write key failed");
|
||||
fprintf(f, " %s\n", comment);
|
||||
fclose(f);
|
||||
|
||||
if (!quiet) {
|
||||
printf("Your public key has been saved in %s.\n", identity_file);
|
||||
printf("Your public key has been saved in %s.\n",
|
||||
identity_file);
|
||||
printf("The key fingerprint is:\n");
|
||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
||||
fingerprint(public_key->e, public_key->n),
|
||||
comment);
|
||||
printf("%s %s\n", key_fingerprint(public), comment);
|
||||
}
|
||||
|
||||
key_free(public);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ MAN= ssh.1
|
||||
LINKS= ${BINDIR}/ssh ${BINDIR}/slogin
|
||||
MLINKS= ssh.1 slogin.1
|
||||
|
||||
SRCS= ssh.c sshconnect.c log-client.c readconf.c clientloop.c
|
||||
SRCS= ssh.c log-client.c readconf.c clientloop.c \
|
||||
sshconnect.c sshconnect1.c sshconnect2.c
|
||||
|
||||
.include <bsd.own.mk> # for AFS
|
||||
|
||||
|
106
crypto/openssh/ssh2.h
Normal file
106
crypto/openssh/ssh2.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* draft-ietf-secsh-architecture-04.txt
|
||||
*
|
||||
* Transport layer protocol:
|
||||
*
|
||||
* 1-19 Transport layer generic (e.g. disconnect, ignore, debug,
|
||||
* etc)
|
||||
* 20-29 Algorithm negotiation
|
||||
* 30-49 Key exchange method specific (numbers can be reused for
|
||||
* different authentication methods)
|
||||
*
|
||||
* User authentication protocol:
|
||||
*
|
||||
* 50-59 User authentication generic
|
||||
* 60-79 User authentication method specific (numbers can be reused
|
||||
* for different authentication methods)
|
||||
*
|
||||
* Connection protocol:
|
||||
*
|
||||
* 80-89 Connection protocol generic
|
||||
* 90-127 Channel related messages
|
||||
*
|
||||
* Reserved for client protocols:
|
||||
*
|
||||
* 128-191 Reserved
|
||||
*
|
||||
* Local extensions:
|
||||
*
|
||||
* 192-255 Local extensions
|
||||
*/
|
||||
|
||||
/* transport layer: generic */
|
||||
|
||||
#define SSH2_MSG_DISCONNECT 1
|
||||
#define SSH2_MSG_IGNORE 2
|
||||
#define SSH2_MSG_UNIMPLEMENTED 3
|
||||
#define SSH2_MSG_DEBUG 4
|
||||
#define SSH2_MSG_SERVICE_REQUEST 5
|
||||
#define SSH2_MSG_SERVICE_ACCEPT 6
|
||||
|
||||
/* transport layer: alg negotiation */
|
||||
|
||||
#define SSH2_MSG_KEXINIT 20
|
||||
#define SSH2_MSG_NEWKEYS 21
|
||||
|
||||
/* transport layer: kex specific messages, can be reused */
|
||||
|
||||
#define SSH2_MSG_KEXDH_INIT 30
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
|
||||
/* user authentication: generic */
|
||||
|
||||
#define SSH2_MSG_USERAUTH_REQUEST 50
|
||||
#define SSH2_MSG_USERAUTH_FAILURE 51
|
||||
#define SSH2_MSG_USERAUTH_SUCCESS 52
|
||||
#define SSH2_MSG_USERAUTH_BANNER 53
|
||||
|
||||
/* user authentication: method specific, can be reused */
|
||||
|
||||
#define SSH2_MSG_USERAUTH_PK_OK 60
|
||||
#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
|
||||
#define SSH2_MSG_USERAUTH_INFO_REQUEST 60
|
||||
#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
|
||||
|
||||
/* connection protocol: generic */
|
||||
|
||||
#define SSH2_MSG_GLOBAL_REQUEST 80
|
||||
#define SSH2_MSG_REQUEST_SUCCESS 81
|
||||
#define SSH2_MSG_REQUEST_FAILURE 82
|
||||
|
||||
/* channel related messages */
|
||||
|
||||
#define SSH2_MSG_CHANNEL_OPEN 90
|
||||
#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
|
||||
#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
|
||||
#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
|
||||
#define SSH2_MSG_CHANNEL_DATA 94
|
||||
#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
|
||||
#define SSH2_MSG_CHANNEL_EOF 96
|
||||
#define SSH2_MSG_CHANNEL_CLOSE 97
|
||||
#define SSH2_MSG_CHANNEL_REQUEST 98
|
||||
#define SSH2_MSG_CHANNEL_SUCCESS 99
|
||||
#define SSH2_MSG_CHANNEL_FAILURE 100
|
||||
|
||||
/* disconnect reason code */
|
||||
|
||||
#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
|
||||
#define SSH2_DISCONNECT_PROTOCOL_ERROR 2
|
||||
#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3
|
||||
#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
|
||||
#define SSH2_DISCONNECT_MAC_ERROR 5
|
||||
#define SSH2_DISCONNECT_COMPRESSION_ERROR 6
|
||||
#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7
|
||||
#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
|
||||
#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
|
||||
#define SSH2_DISCONNECT_CONNECTION_LOST 10
|
||||
#define SSH2_DISCONNECT_BY_APPLICATION 11
|
||||
|
||||
/* misc */
|
||||
|
||||
#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1
|
||||
#define SSH2_OPEN_CONNECT_FAILED 2
|
||||
#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3
|
||||
#define SSH2_OPEN_RESOURCE_SHORTAGE 4
|
||||
|
||||
#define SSH2_EXTENDED_DATA_STDERR 1
|
16
crypto/openssh/sshconnect.h
Normal file
16
crypto/openssh/sshconnect.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef SSHCONNECT_H
|
||||
#define SSHCONNECT_H
|
||||
|
||||
void
|
||||
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||
const char *user_hostfile, const char *system_hostfile);
|
||||
|
||||
void ssh_kex(char *host, struct sockaddr *hostaddr);
|
||||
void
|
||||
ssh_userauth(const char* local_user, const char* server_user, char *host,
|
||||
int host_key_valid, RSA *own_host_key);
|
||||
|
||||
void ssh_kex2(char *host, struct sockaddr *hostaddr);
|
||||
void ssh_userauth2(const char *server_user, char *host);
|
||||
|
||||
#endif
|
1024
crypto/openssh/sshconnect1.c
Normal file
1024
crypto/openssh/sshconnect1.c
Normal file
File diff suppressed because it is too large
Load Diff
474
crypto/openssh/sshconnect2.c
Normal file
474
crypto/openssh/sshconnect2.c
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Copyright (c) 2000 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("$OpenBSD: sshconnect2.c,v 1.10 2000/05/08 17:42:25 markus Exp $");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
#include "uidswap.h"
|
||||
#include "compat.h"
|
||||
#include "readconf.h"
|
||||
#include "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "kex.h"
|
||||
#include "myproposal.h"
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "sshconnect.h"
|
||||
#include "authfile.h"
|
||||
|
||||
/* import */
|
||||
extern char *client_version_string;
|
||||
extern char *server_version_string;
|
||||
extern Options options;
|
||||
|
||||
/*
|
||||
* SSH2 key exchange
|
||||
*/
|
||||
|
||||
unsigned char *session_id2 = NULL;
|
||||
int session_id2_len = 0;
|
||||
|
||||
void
|
||||
ssh_kex2(char *host, struct sockaddr *hostaddr)
|
||||
{
|
||||
Kex *kex;
|
||||
char *cprop[PROPOSAL_MAX];
|
||||
char *sprop[PROPOSAL_MAX];
|
||||
Buffer *client_kexinit;
|
||||
Buffer *server_kexinit;
|
||||
int payload_len, dlen;
|
||||
unsigned int klen, kout;
|
||||
char *ptr;
|
||||
char *signature = NULL;
|
||||
unsigned int slen;
|
||||
char *server_host_key_blob = NULL;
|
||||
Key *server_host_key;
|
||||
unsigned int sbloblen;
|
||||
DH *dh;
|
||||
BIGNUM *dh_server_pub = 0;
|
||||
BIGNUM *shared_secret = 0;
|
||||
int i;
|
||||
unsigned char *kbuf;
|
||||
unsigned char *hash;
|
||||
|
||||
/* KEXINIT */
|
||||
|
||||
debug("Sending KEX init.");
|
||||
if (options.ciphers != NULL) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
|
||||
} else if (options.cipher == SSH_CIPHER_3DES) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] =
|
||||
cipher_name(SSH_CIPHER_3DES_CBC);
|
||||
} else if (options.cipher == SSH_CIPHER_BLOWFISH) {
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] =
|
||||
cipher_name(SSH_CIPHER_BLOWFISH_CBC);
|
||||
}
|
||||
if (options.compression) {
|
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
|
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
|
||||
} else {
|
||||
myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
|
||||
myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
|
||||
}
|
||||
for (i = 0; i < PROPOSAL_MAX; i++)
|
||||
cprop[i] = xstrdup(myproposal[i]);
|
||||
|
||||
client_kexinit = kex_init(cprop);
|
||||
packet_start(SSH2_MSG_KEXINIT);
|
||||
packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
debug("done");
|
||||
|
||||
packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
|
||||
|
||||
/* save payload for session_id */
|
||||
server_kexinit = xmalloc(sizeof(*server_kexinit));
|
||||
buffer_init(server_kexinit);
|
||||
ptr = packet_get_raw(&payload_len);
|
||||
buffer_append(server_kexinit, ptr, payload_len);
|
||||
|
||||
/* skip cookie */
|
||||
for (i = 0; i < 16; i++)
|
||||
(void) packet_get_char();
|
||||
/* kex init proposal strings */
|
||||
for (i = 0; i < PROPOSAL_MAX; i++) {
|
||||
sprop[i] = packet_get_string(NULL);
|
||||
debug("got kexinit string: %s", sprop[i]);
|
||||
}
|
||||
i = (int) packet_get_char();
|
||||
debug("first kex follow == %d", i);
|
||||
i = packet_get_int();
|
||||
debug("reserved == %d", i);
|
||||
packet_done();
|
||||
|
||||
debug("done read kexinit");
|
||||
kex = kex_choose_conf(cprop, sprop, 0);
|
||||
|
||||
/* KEXDH */
|
||||
|
||||
debug("Sending SSH2_MSG_KEXDH_INIT.");
|
||||
|
||||
/* generate and send 'e', client DH public key */
|
||||
dh = dh_new_group1();
|
||||
packet_start(SSH2_MSG_KEXDH_INIT);
|
||||
packet_put_bignum2(dh->pub_key);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "\np= ");
|
||||
bignum_print(dh->p);
|
||||
fprintf(stderr, "\ng= ");
|
||||
bignum_print(dh->g);
|
||||
fprintf(stderr, "\npub= ");
|
||||
bignum_print(dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
DHparams_print_fp(stderr, dh);
|
||||
#endif
|
||||
|
||||
debug("Wait SSH2_MSG_KEXDH_REPLY.");
|
||||
|
||||
packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
|
||||
|
||||
debug("Got SSH2_MSG_KEXDH_REPLY.");
|
||||
|
||||
/* key, cert */
|
||||
server_host_key_blob = packet_get_string(&sbloblen);
|
||||
server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
|
||||
if (server_host_key == NULL)
|
||||
fatal("cannot decode server_host_key_blob");
|
||||
|
||||
check_host_key(host, hostaddr, server_host_key,
|
||||
options.user_hostfile2, options.system_hostfile2);
|
||||
|
||||
/* DH paramter f, server public DH key */
|
||||
dh_server_pub = BN_new();
|
||||
if (dh_server_pub == NULL)
|
||||
fatal("dh_server_pub == NULL");
|
||||
packet_get_bignum2(dh_server_pub, &dlen);
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "\ndh_server_pub= ");
|
||||
bignum_print(dh_server_pub);
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_server_pub));
|
||||
#endif
|
||||
|
||||
/* signed H */
|
||||
signature = packet_get_string(&slen);
|
||||
packet_done();
|
||||
|
||||
if (!dh_pub_is_valid(dh, dh_server_pub))
|
||||
packet_disconnect("bad server public DH value");
|
||||
|
||||
klen = DH_size(dh);
|
||||
kbuf = xmalloc(klen);
|
||||
kout = DH_compute_key(kbuf, dh_server_pub, dh);
|
||||
#ifdef DEBUG_KEXDH
|
||||
debug("shared secret: len %d/%d", klen, kout);
|
||||
fprintf(stderr, "shared secret == ");
|
||||
for (i = 0; i< kout; i++)
|
||||
fprintf(stderr, "%02x", (kbuf[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
shared_secret = BN_new();
|
||||
|
||||
BN_bin2bn(kbuf, kout, shared_secret);
|
||||
memset(kbuf, 0, klen);
|
||||
xfree(kbuf);
|
||||
|
||||
/* calc and verify H */
|
||||
hash = kex_hash(
|
||||
client_version_string,
|
||||
server_version_string,
|
||||
buffer_ptr(client_kexinit), buffer_len(client_kexinit),
|
||||
buffer_ptr(server_kexinit), buffer_len(server_kexinit),
|
||||
server_host_key_blob, sbloblen,
|
||||
dh->pub_key,
|
||||
dh_server_pub,
|
||||
shared_secret
|
||||
);
|
||||
xfree(server_host_key_blob);
|
||||
buffer_free(client_kexinit);
|
||||
buffer_free(server_kexinit);
|
||||
xfree(client_kexinit);
|
||||
xfree(server_kexinit);
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "hash == ");
|
||||
for (i = 0; i< 20; i++)
|
||||
fprintf(stderr, "%02x", (hash[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
|
||||
fatal("dsa_verify failed for server_host_key");
|
||||
key_free(server_host_key);
|
||||
|
||||
kex_derive_keys(kex, hash, shared_secret);
|
||||
packet_set_kex(kex);
|
||||
|
||||
/* have keys, free DH */
|
||||
DH_free(dh);
|
||||
|
||||
/* save session id */
|
||||
session_id2_len = 20;
|
||||
session_id2 = xmalloc(session_id2_len);
|
||||
memcpy(session_id2, hash, session_id2_len);
|
||||
|
||||
debug("Wait SSH2_MSG_NEWKEYS.");
|
||||
packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
|
||||
packet_done();
|
||||
debug("GOT SSH2_MSG_NEWKEYS.");
|
||||
|
||||
debug("send SSH2_MSG_NEWKEYS.");
|
||||
packet_start(SSH2_MSG_NEWKEYS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
debug("done: send SSH2_MSG_NEWKEYS.");
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
/* send 1st encrypted/maced/compressed message */
|
||||
packet_start(SSH2_MSG_IGNORE);
|
||||
packet_put_cstring("markus");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
#endif
|
||||
debug("done: KEX2.");
|
||||
}
|
||||
/*
|
||||
* Authenticate user
|
||||
*/
|
||||
int
|
||||
ssh2_try_passwd(const char *server_user, const char *host, const char *service)
|
||||
{
|
||||
static int attempt = 0;
|
||||
char prompt[80];
|
||||
char *password;
|
||||
|
||||
if (attempt++ > options.number_of_password_prompts)
|
||||
return 0;
|
||||
|
||||
snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
|
||||
server_user, host);
|
||||
password = read_passphrase(prompt, 0);
|
||||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_cstring(server_user);
|
||||
packet_put_cstring(service);
|
||||
packet_put_cstring("password");
|
||||
packet_put_char(0);
|
||||
packet_put_cstring(password);
|
||||
memset(password, 0, strlen(password));
|
||||
xfree(password);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ssh2_try_pubkey(char *filename,
|
||||
const char *server_user, const char *host, const char *service)
|
||||
{
|
||||
Buffer b;
|
||||
Key *k;
|
||||
unsigned char *blob, *signature;
|
||||
int bloblen, slen;
|
||||
struct stat st;
|
||||
|
||||
if (stat(filename, &st) != 0) {
|
||||
debug("key does not exist: %s", filename);
|
||||
return 0;
|
||||
}
|
||||
debug("try pubkey: %s", filename);
|
||||
|
||||
k = key_new(KEY_DSA);
|
||||
if (!load_private_key(filename, "", k, NULL)) {
|
||||
int success = 0;
|
||||
char *passphrase;
|
||||
char prompt[300];
|
||||
snprintf(prompt, sizeof prompt,
|
||||
"Enter passphrase for DSA key '%.100s': ",
|
||||
filename);
|
||||
passphrase = read_passphrase(prompt, 0);
|
||||
success = load_private_key(filename, passphrase, k, NULL);
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
if (!success)
|
||||
return 0;
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &bloblen);
|
||||
|
||||
/* data to be signed */
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, session_id2, session_id2_len);
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, server_user);
|
||||
buffer_put_cstring(&b,
|
||||
datafellows & SSH_BUG_PUBKEYAUTH ?
|
||||
"ssh-userauth" :
|
||||
service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, 1);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, blob, bloblen);
|
||||
|
||||
/* generate signature */
|
||||
dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
|
||||
key_free(k);
|
||||
#ifdef DEBUG_DSS
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
if (datafellows & SSH_BUG_PUBKEYAUTH) {
|
||||
/* e.g. ssh-2.0.13: data-to-be-signed != data-on-the-wire */
|
||||
buffer_clear(&b);
|
||||
buffer_append(&b, session_id2, session_id2_len);
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, server_user);
|
||||
buffer_put_cstring(&b, service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, 1);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
buffer_put_string(&b, blob, bloblen);
|
||||
}
|
||||
xfree(blob);
|
||||
/* append signature */
|
||||
buffer_put_string(&b, signature, slen);
|
||||
xfree(signature);
|
||||
|
||||
/* skip session id and packet type */
|
||||
if (buffer_len(&b) < session_id2_len + 1)
|
||||
fatal("ssh2_try_pubkey: internal error");
|
||||
buffer_consume(&b, session_id2_len + 1);
|
||||
|
||||
/* put remaining data from buffer into packet */
|
||||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_raw(buffer_ptr(&b), buffer_len(&b));
|
||||
buffer_free(&b);
|
||||
|
||||
/* send */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ssh_userauth2(const char *server_user, char *host)
|
||||
{
|
||||
int type;
|
||||
int plen;
|
||||
int sent;
|
||||
unsigned int dlen;
|
||||
int partial;
|
||||
int i = 0;
|
||||
char *auths;
|
||||
char *service = "ssh-connection"; /* service name */
|
||||
|
||||
debug("send SSH2_MSG_SERVICE_REQUEST");
|
||||
packet_start(SSH2_MSG_SERVICE_REQUEST);
|
||||
packet_put_cstring("ssh-userauth");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
type = packet_read(&plen);
|
||||
if (type != SSH2_MSG_SERVICE_ACCEPT) {
|
||||
fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
|
||||
}
|
||||
if (packet_remaining() > 0) {
|
||||
char *reply = packet_get_string(&plen);
|
||||
debug("service_accept: %s", reply);
|
||||
xfree(reply);
|
||||
} else {
|
||||
/* payload empty for ssh-2.0.13 ?? */
|
||||
debug("buggy server: service_accept w/o service");
|
||||
}
|
||||
packet_done();
|
||||
debug("got SSH2_MSG_SERVICE_ACCEPT");
|
||||
|
||||
/* INITIAL request for auth */
|
||||
packet_start(SSH2_MSG_USERAUTH_REQUEST);
|
||||
packet_put_cstring(server_user);
|
||||
packet_put_cstring(service);
|
||||
packet_put_cstring("none");
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
for (;;) {
|
||||
sent = 0;
|
||||
type = packet_read(&plen);
|
||||
if (type == SSH2_MSG_USERAUTH_SUCCESS)
|
||||
break;
|
||||
if (type != SSH2_MSG_USERAUTH_FAILURE)
|
||||
fatal("access denied: %d", type);
|
||||
/* SSH2_MSG_USERAUTH_FAILURE means: try again */
|
||||
auths = packet_get_string(&dlen);
|
||||
debug("authentications that can continue: %s", auths);
|
||||
partial = packet_get_char();
|
||||
packet_done();
|
||||
if (partial)
|
||||
debug("partial success");
|
||||
if (options.dsa_authentication &&
|
||||
strstr(auths, "publickey") != NULL) {
|
||||
while (i < options.num_identity_files2) {
|
||||
sent = ssh2_try_pubkey(
|
||||
options.identity_files2[i++],
|
||||
server_user, host, service);
|
||||
if (sent)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sent) {
|
||||
if (options.password_authentication &&
|
||||
!options.batch_mode &&
|
||||
strstr(auths, "password") != NULL) {
|
||||
sent = ssh2_try_passwd(server_user, host, service);
|
||||
}
|
||||
}
|
||||
if (!sent)
|
||||
fatal("Permission denied (%s).", auths);
|
||||
xfree(auths);
|
||||
}
|
||||
packet_done();
|
||||
debug("ssh-userauth2 successfull");
|
||||
}
|
@ -7,7 +7,8 @@ BINDIR= /usr/sbin
|
||||
MAN= sshd.8
|
||||
|
||||
SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \
|
||||
pty.c log-server.c login.c servconf.c serverloop.c
|
||||
pty.c log-server.c login.c servconf.c serverloop.c \
|
||||
auth.c auth1.c auth2.c session.c
|
||||
|
||||
.include <bsd.own.mk> # for KERBEROS and AFS
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
|
||||
RCSID("$Id: ttymodes.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
@ -23,7 +23,7 @@ RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
|
||||
* Converts POSIX speed_t to a baud rate. The values of the
|
||||
* constants for speed_t are not themselves portable.
|
||||
*/
|
||||
static int
|
||||
static int
|
||||
speed_to_baud(speed_t speed)
|
||||
{
|
||||
switch (speed) {
|
||||
@ -112,7 +112,7 @@ speed_to_baud(speed_t speed)
|
||||
/*
|
||||
* Converts a numeric baud rate to a POSIX speed_t.
|
||||
*/
|
||||
static speed_t
|
||||
static speed_t
|
||||
baud_to_speed(int baud)
|
||||
{
|
||||
switch (baud) {
|
||||
@ -203,7 +203,7 @@ baud_to_speed(int baud)
|
||||
* in a portable manner, and appends the modes to a packet
|
||||
* being constructed.
|
||||
*/
|
||||
void
|
||||
void
|
||||
tty_make_modes(int fd)
|
||||
{
|
||||
struct termios tio;
|
||||
@ -247,7 +247,7 @@ tty_make_modes(int fd)
|
||||
* Decodes terminal modes for the terminal referenced by fd in a portable
|
||||
* manner from a packet being read.
|
||||
*/
|
||||
void
|
||||
void
|
||||
tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
{
|
||||
struct termios tio;
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* ttymodes.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Tue Mar 21 15:42:09 1995 ylo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: ttymodes.h,v 1.6 1999/11/24 19:53:54 markus Exp $"); */
|
||||
/* RCSID("$Id: ttymodes.h,v 1.7 2000/04/14 10:30:34 markus 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).
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: uidswap.c,v 1.5 1999/11/24 19:53:54 markus Exp $");
|
||||
RCSID("$Id: uidswap.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "uidswap.h"
|
||||
@ -34,7 +34,7 @@ static uid_t saved_euid = 0;
|
||||
* Temporarily changes to the given uid. If the effective user
|
||||
* id is not root, this does nothing. This call cannot be nested.
|
||||
*/
|
||||
void
|
||||
void
|
||||
temporarily_use_uid(uid_t uid)
|
||||
{
|
||||
#ifdef SAVED_IDS_WORK_WITH_SETEUID
|
||||
@ -58,7 +58,7 @@ temporarily_use_uid(uid_t uid)
|
||||
/*
|
||||
* Restores to the original uid.
|
||||
*/
|
||||
void
|
||||
void
|
||||
restore_uid()
|
||||
{
|
||||
#ifdef SAVED_IDS_WORK_WITH_SETEUID
|
||||
@ -79,7 +79,7 @@ restore_uid()
|
||||
* Permanently sets all uids to the given uid. This cannot be
|
||||
* called while temporarily_use_uid is effective.
|
||||
*/
|
||||
void
|
||||
void
|
||||
permanently_set_uid(uid_t uid)
|
||||
{
|
||||
if (setuid(uid) < 0)
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* uidswap.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Sep 9 01:43:15 1995 ylo
|
||||
* Last modified: Sat Sep 9 02:34:04 1995 ylo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UIDSWAP_H
|
||||
|
50
crypto/openssh/uuencode.c
Normal file
50
crypto/openssh/uuencode.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <resolv.h>
|
||||
|
||||
int
|
||||
uuencode(unsigned char *src, unsigned int srclength,
|
||||
char *target, size_t targsize)
|
||||
{
|
||||
return __b64_ntop(src, srclength, target, targsize);
|
||||
}
|
||||
|
||||
int
|
||||
uudecode(const char *src, unsigned char *target, size_t targsize)
|
||||
{
|
||||
int len;
|
||||
char *encoded, *p;
|
||||
|
||||
/* copy the 'readonly' source */
|
||||
encoded = xstrdup(src);
|
||||
/* skip whitespace and data */
|
||||
for (p = encoded; *p == ' ' || *p == '\t'; p++)
|
||||
;
|
||||
for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
|
||||
;
|
||||
/* and remote trailing whitespace because __b64_pton needs this */
|
||||
*p = '\0';
|
||||
len = __b64_pton(encoded, target, targsize);
|
||||
xfree(encoded);
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
dump_base64(FILE *fp, unsigned char *data, int len)
|
||||
{
|
||||
unsigned char *buf = xmalloc(2*len);
|
||||
int i, n;
|
||||
n = uuencode(data, len, buf, 2*len);
|
||||
for (i = 0; i < n; i++) {
|
||||
fprintf(fp, "%c", buf[i]);
|
||||
if (i % 70 == 69)
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
if (i % 70 != 69)
|
||||
fprintf(fp, "\n");
|
||||
xfree(buf);
|
||||
}
|
6
crypto/openssh/uuencode.h
Normal file
6
crypto/openssh/uuencode.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef UUENCODE_H
|
||||
#define UUENCODE_H
|
||||
int uuencode(unsigned char *src, unsigned int srclength, char *target, size_t targsize);
|
||||
int uudecode(const char *src, unsigned char *target, size_t targsize);
|
||||
void dump_base64(FILE *fp, unsigned char *data, int len);
|
||||
#endif
|
@ -1 +1 @@
|
||||
#define SSH_VERSION "OpenSSH-1.2.3"
|
||||
#define SSH_VERSION "OpenSSH-2.1"
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: xmalloc.c,v 1.5 1999/11/24 00:26:04 deraadt Exp $");
|
||||
RCSID("$Id: xmalloc.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
@ -34,7 +34,7 @@ xrealloc(void *ptr, size_t new_size)
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
xfree(void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* xmalloc.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Mon Mar 20 22:09:17 1995 ylo
|
||||
*
|
||||
*
|
||||
* Versions of malloc and friends that check their results, and never return
|
||||
* failure (they call fatal if they encounter an error).
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: xmalloc.h,v 1.2 1999/11/24 00:26:04 deraadt Exp $"); */
|
||||
/* RCSID("$Id: xmalloc.h,v 1.3 2000/04/14 10:30:34 markus Exp $"); */
|
||||
|
||||
#ifndef XMALLOC_H
|
||||
#define XMALLOC_H
|
||||
|
Loading…
Reference in New Issue
Block a user