Initial import of OpenSSH v2.1.
This commit is contained in:
parent
a8f6863aa6
commit
a04a10f891
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor-crypto/openssh/dist/; revision=60573 svn path=/vendor-crypto/openssh/2.1/; revision=60575; tag=vendor/openssh/2.1
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 $
|
@ -19,7 +19,7 @@ extern ServerOptions options;
|
||||
* return 1 on success, 0 on failure, -1 if krb4 is not available
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
auth_krb4_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
AUTH_DAT adata;
|
||||
@ -135,7 +135,7 @@ krb4_cleanup_proc(void *ignore)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
krb4_init(uid_t uid)
|
||||
{
|
||||
static int cleanup_registered = 0;
|
||||
@ -179,7 +179,7 @@ krb4_init(uid_t uid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
auth_krb4(const char *server_user, KTEXT auth, char **client)
|
||||
{
|
||||
AUTH_DAT adat = {0};
|
||||
@ -252,7 +252,7 @@ auth_krb4(const char *server_user, KTEXT auth, char **client)
|
||||
#endif /* KRB4 */
|
||||
|
||||
#ifdef AFS
|
||||
int
|
||||
int
|
||||
auth_kerberos_tgt(struct passwd *pw, const char *string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
@ -307,7 +307,7 @@ auth_kerberos_tgt(struct passwd *pw, const char *string)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
auth_afs_token(struct passwd *pw, const char *token_string)
|
||||
{
|
||||
CREDENTIALS creds;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-passwd.c,v 1.14 1999/12/29 12:47:46 markus Exp $");
|
||||
RCSID("$Id: auth-passwd.c,v 1.15 2000/04/14 10:30:29 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
@ -19,7 +19,7 @@ RCSID("$Id: auth-passwd.c,v 1.14 1999/12/29 12:47:46 markus Exp $");
|
||||
* Tries to authenticate the user using password. Returns true if
|
||||
* authentication succeeds.
|
||||
*/
|
||||
int
|
||||
int
|
||||
auth_password(struct passwd * pw, const char *password)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
|
@ -1,21 +1,21 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* auth-rh-rsa.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sun May 7 03:08:06 1995 ylo
|
||||
*
|
||||
*
|
||||
* Rhosts or /etc/hosts.equiv authentication combined with RSA host
|
||||
* authentication.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rh-rsa.c,v 1.11 2000/03/23 22:15:33 markus Exp $");
|
||||
RCSID("$Id: auth-rh-rsa.c,v 1.13 2000/04/14 10:30:29 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
@ -23,8 +23,8 @@ RCSID("$Id: auth-rh-rsa.c,v 1.11 2000/03/23 22:15:33 markus Exp $");
|
||||
#include "uidswap.h"
|
||||
#include "servconf.h"
|
||||
|
||||
#include <ssl/rsa.h>
|
||||
#include <ssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "key.h"
|
||||
#include "hostfile.h"
|
||||
|
||||
@ -33,7 +33,7 @@ RCSID("$Id: auth-rh-rsa.c,v 1.11 2000/03/23 22:15:33 markus Exp $");
|
||||
* its host key. Returns true if authentication succeeds.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key)
|
||||
{
|
||||
extern ServerOptions options;
|
||||
|
@ -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,22 +1,22 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* auth-rsa.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 27 01:46:52 1995 ylo
|
||||
*
|
||||
*
|
||||
* RSA-based authentication. This code determines whether to admit a login
|
||||
* based on RSA authentication. This file also contains functions to check
|
||||
* validity of the host key.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: auth-rsa.c,v 1.19 2000/03/23 22:15:33 markus Exp $");
|
||||
RCSID("$Id: auth-rsa.c,v 1.23 2000/04/29 18:11:51 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "packet.h"
|
||||
@ -27,8 +27,8 @@ RCSID("$Id: auth-rsa.c,v 1.19 2000/03/23 22:15:33 markus Exp $");
|
||||
#include "match.h"
|
||||
#include "servconf.h"
|
||||
|
||||
#include <ssl/rsa.h>
|
||||
#include <ssl/md5.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
/* Flags that may be set in authorized_keys options. */
|
||||
extern int no_port_forwarding_flag;
|
||||
@ -185,6 +185,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
fclose(f);
|
||||
log(buf);
|
||||
packet_send_debug(buf);
|
||||
restore_uid();
|
||||
@ -238,7 +239,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
packet_send_debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
continue;
|
||||
}
|
||||
/* cp now points to the comment part. */
|
||||
@ -255,7 +256,6 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
|
||||
/* We have found the desired key. */
|
||||
|
||||
|
||||
/* Perform the challenge-response dialog for this key. */
|
||||
if (!auth_rsa_challenge_dialog(pk)) {
|
||||
/* Wrong response. */
|
||||
|
@ -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,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* authfd.c
|
||||
*
|
||||
*
|
||||
* 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:30:28 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for connecting the local authentication agent.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
|
||||
RCSID("$Id: authfd.c,v 1.19 2000/04/29 18:11:52 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
@ -24,7 +24,7 @@ RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include <ssl/rsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
/* Returns the number of the authentication fd, or -1 if there is none. */
|
||||
|
||||
@ -64,7 +64,7 @@ ssh_get_authentication_socket()
|
||||
* ssh_get_authentication_socket().
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
ssh_close_authentication_socket(int sock)
|
||||
{
|
||||
if (getenv(SSH_AUTHSOCKET_ENV_NAME))
|
||||
@ -108,7 +108,7 @@ ssh_get_authentication_connection()
|
||||
* memory.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
ssh_close_authentication_connection(AuthenticationConnection *ac)
|
||||
{
|
||||
buffer_free(&ac->packet);
|
||||
@ -217,8 +217,8 @@ ssh_get_next_identity(AuthenticationConnection *auth,
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: identity keysize mismatch: actual %d, announced %u",
|
||||
BN_num_bits(n), bits);
|
||||
log("Warning: identity keysize mismatch: actual %d, announced %u",
|
||||
BN_num_bits(n), bits);
|
||||
|
||||
/* Decrement the number of remaining entries. */
|
||||
auth->howmany--;
|
||||
@ -338,7 +338,7 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
* be used by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
ssh_add_identity(AuthenticationConnection *auth,
|
||||
RSA * key, const char *comment)
|
||||
{
|
||||
@ -426,7 +426,7 @@ ssh_add_identity(AuthenticationConnection *auth,
|
||||
* meant to be used by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||
{
|
||||
Buffer buffer;
|
||||
@ -509,7 +509,7 @@ ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
|
||||
* by normal applications.
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
ssh_remove_all_identities(AuthenticationConnection *auth)
|
||||
{
|
||||
Buffer buffer;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -1,28 +1,34 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* authfile.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 27 03:52:05 1995 ylo
|
||||
*
|
||||
*
|
||||
* This file contains functions for reading and writing identity files, and
|
||||
* for reading the passphrase from the user.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: authfile.c,v 1.11 1999/12/06 19:11:15 deraadt Exp $");
|
||||
RCSID("$Id: authfile.c,v 1.16 2000/04/26 21:28:32 markus Exp $");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "cipher.h"
|
||||
#include "ssh.h"
|
||||
#include "key.h"
|
||||
|
||||
/* Version identification string for identity files. */
|
||||
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||
@ -35,8 +41,8 @@ RCSID("$Id: authfile.c,v 1.11 1999/12/06 19:11:15 deraadt Exp $");
|
||||
*/
|
||||
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
RSA *key, const char *comment)
|
||||
save_private_key_rsa(const char *filename, const char *passphrase,
|
||||
RSA *key, const char *comment)
|
||||
{
|
||||
Buffer buffer, encrypted;
|
||||
char buf[100], *cp;
|
||||
@ -101,7 +107,7 @@ save_private_key(const char *filename, const char *passphrase,
|
||||
/* Allocate space for the private part of the key in the buffer. */
|
||||
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase);
|
||||
cipher_encrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
@ -128,6 +134,63 @@ save_private_key(const char *filename, const char *passphrase,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* save DSA key in OpenSSL PEM format */
|
||||
|
||||
int
|
||||
save_private_key_dsa(const char *filename, const char *passphrase,
|
||||
DSA *dsa, const char *comment)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
int success = 1;
|
||||
int len = strlen(passphrase);
|
||||
|
||||
if (len > 0 && len <= 4) {
|
||||
error("passphrase too short: %d bytes", len);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
debug("open %s failed", filename);
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "w");
|
||||
if (fp == NULL ) {
|
||||
debug("fdopen %s failed", filename);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (len > 0) {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
|
||||
(char *)passphrase, strlen(passphrase), NULL, NULL))
|
||||
success = 0;
|
||||
} else {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
|
||||
NULL, 0, NULL, NULL))
|
||||
success = 0;
|
||||
}
|
||||
fclose(fp);
|
||||
return success;
|
||||
}
|
||||
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
const char *comment)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return save_private_key_rsa(filename, passphrase, key->rsa, comment);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return save_private_key_dsa(filename, passphrase, key->dsa, comment);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file. Returns 0 if an error was
|
||||
* encountered (the file does not exist or is not readable), and non-zero
|
||||
@ -135,8 +198,7 @@ save_private_key(const char *filename, const char *passphrase,
|
||||
*/
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return)
|
||||
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
|
||||
{
|
||||
int fd, i;
|
||||
off_t len;
|
||||
@ -154,7 +216,7 @@ load_public_key(const char *filename, RSA * pub,
|
||||
|
||||
if (read(fd, cp, (size_t) len) != (size_t) len) {
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
strerror(errno));
|
||||
buffer_free(&buffer);
|
||||
close(fd);
|
||||
return 0;
|
||||
@ -183,9 +245,13 @@ load_public_key(const char *filename, RSA * pub,
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
pub->n = BN_new();
|
||||
/* XXX alloc */
|
||||
if (pub->n == NULL)
|
||||
pub->n = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->n);
|
||||
pub->e = BN_new();
|
||||
/* XXX alloc */
|
||||
if (pub->e == NULL)
|
||||
pub->e = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
@ -196,6 +262,20 @@ load_public_key(const char *filename, RSA * pub,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, Key * key, char **comment_return)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return load_public_key_rsa(filename, key->rsa, comment_return);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -204,35 +284,17 @@ load_public_key(const char *filename, RSA * pub,
|
||||
*/
|
||||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
RSA * prv, char **comment_return)
|
||||
load_private_key_rsa(int fd, const char *filename,
|
||||
const char *passphrase, RSA * prv, char **comment_return)
|
||||
{
|
||||
int fd, i, check1, check2, cipher_type;
|
||||
int i, check1, check2, cipher_type;
|
||||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* check owner and modes */
|
||||
if (fstat(fd, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_mode & 077) != 0) {
|
||||
close(fd);
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("Bad ownership or mode(0%3.3o) for '%s'.",
|
||||
st.st_mode & 0777, filename);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
return 0;
|
||||
}
|
||||
len = lseek(fd, (off_t) 0, SEEK_END);
|
||||
lseek(fd, (off_t) 0, SEEK_SET);
|
||||
|
||||
@ -280,7 +342,7 @@ load_private_key(const char *filename, const char *passphrase,
|
||||
xfree(buffer_get_string(&buffer, NULL));
|
||||
|
||||
/* Check that it is a supported cipher. */
|
||||
if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
|
||||
if (((cipher_mask1() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
|
||||
(1 << cipher_type)) == 0) {
|
||||
debug("Unsupported cipher %.100s used in key file %.200s.",
|
||||
cipher_name(cipher_type), filename);
|
||||
@ -292,7 +354,7 @@ load_private_key(const char *filename, const char *passphrase,
|
||||
buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
|
||||
cipher_set_key_string(&cipher, cipher_type, passphrase);
|
||||
cipher_decrypt(&cipher, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer),
|
||||
buffer_len(&buffer));
|
||||
@ -309,7 +371,9 @@ load_private_key(const char *filename, const char *passphrase,
|
||||
buffer_free(&decrypted);
|
||||
fail:
|
||||
BN_clear_free(prv->n);
|
||||
prv->n = NULL;
|
||||
BN_clear_free(prv->e);
|
||||
prv->e = NULL;
|
||||
if (comment_return)
|
||||
xfree(*comment_return);
|
||||
return 0;
|
||||
@ -343,3 +407,87 @@ load_private_key(const char *filename, const char *passphrase,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
|
||||
{
|
||||
DSA *dsa;
|
||||
BIO *in;
|
||||
FILE *fp;
|
||||
|
||||
in = BIO_new(BIO_s_file());
|
||||
if (in == NULL) {
|
||||
error("BIO_new failed");
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "r");
|
||||
if (fp == NULL) {
|
||||
error("fdopen failed");
|
||||
return 0;
|
||||
}
|
||||
BIO_set_fp(in, fp, BIO_NOCLOSE);
|
||||
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
|
||||
if (dsa == NULL) {
|
||||
debug("PEM_read_bio_DSAPrivateKey failed");
|
||||
} else {
|
||||
/* replace k->dsa with loaded key */
|
||||
DSA_free(k->dsa);
|
||||
k->dsa = dsa;
|
||||
}
|
||||
BIO_free(in);
|
||||
fclose(fp);
|
||||
if (comment_return)
|
||||
*comment_return = xstrdup("dsa w/o comment");
|
||||
debug("read DSA private key done");
|
||||
#ifdef DEBUG_DSS
|
||||
DSA_print_fp(stderr, dsa, 8);
|
||||
#endif
|
||||
return dsa != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
char **comment_return)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* check owner and modes */
|
||||
if (fstat(fd, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_mode & 077) != 0) {
|
||||
close(fd);
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("Bad ownership or mode(0%3.3o) for '%s'.",
|
||||
st.st_mode & 0777, filename);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
return 0;
|
||||
}
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
if (key->rsa->e != NULL) {
|
||||
BN_clear_free(key->rsa->e);
|
||||
key->rsa->e = NULL;
|
||||
}
|
||||
if (key->rsa->n != NULL) {
|
||||
BN_clear_free(key->rsa->n);
|
||||
key->rsa->n = NULL;
|
||||
}
|
||||
ret = load_private_key_rsa(fd, filename, passphrase,
|
||||
key->rsa, comment_return);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
ret = load_private_key_dsa(fd, passphrase, key, comment_return);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
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,24 +1,26 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* bufaux.c
|
||||
*
|
||||
*
|
||||
* 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:24:47 1995 ylo
|
||||
*
|
||||
*
|
||||
* Auxiliary functions for storing and retrieving various data types to/from
|
||||
* Buffers.
|
||||
*
|
||||
* SSH2 packet format added by Markus Friedl
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: bufaux.c,v 1.8 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$Id: bufaux.c,v 1.11 2000/04/14 10:30:30 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include <ssl/bn.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
@ -75,10 +77,54 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
return 2 + bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores an BIGNUM in the buffer in SSH2 format.
|
||||
*/
|
||||
void
|
||||
buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bytes = BN_num_bytes(value) + 1;
|
||||
unsigned char *buf = xmalloc(bytes);
|
||||
int oi;
|
||||
int hasnohigh = 0;
|
||||
buf[0] = '\0';
|
||||
/* Get the value of in binary */
|
||||
oi = BN_bn2bin(value, buf+1);
|
||||
if (oi != bytes-1)
|
||||
fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
|
||||
oi, bytes);
|
||||
hasnohigh = (buf[1] & 0x80) ? 0 : 1;
|
||||
if (value->neg) {
|
||||
/**XXX should be two's-complement */
|
||||
int i, carry;
|
||||
unsigned char *uc = buf;
|
||||
log("negativ!");
|
||||
for(i = bytes-1, carry = 1; i>=0; i--) {
|
||||
uc[i] ^= 0xff;
|
||||
if(carry)
|
||||
carry = !++uc[i];
|
||||
}
|
||||
}
|
||||
buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
|
||||
memset(buf, 0, bytes);
|
||||
xfree(buf);
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
/**XXX should be two's-complement */
|
||||
int len;
|
||||
unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len);
|
||||
BN_bin2bn(bin, len, value);
|
||||
xfree(bin);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an integer from the buffer (4 bytes, msb first).
|
||||
*/
|
||||
unsigned int
|
||||
unsigned int
|
||||
buffer_get_int(Buffer *buffer)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
@ -89,7 +135,7 @@ buffer_get_int(Buffer *buffer)
|
||||
/*
|
||||
* Stores an integer in the buffer in 4 bytes, msb first.
|
||||
*/
|
||||
void
|
||||
void
|
||||
buffer_put_int(Buffer *buffer, unsigned int value)
|
||||
{
|
||||
char buf[4];
|
||||
@ -129,17 +175,22 @@ buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
|
||||
/*
|
||||
* Stores and arbitrary binary string in the buffer.
|
||||
*/
|
||||
void
|
||||
void
|
||||
buffer_put_string(Buffer *buffer, const void *buf, unsigned int len)
|
||||
{
|
||||
buffer_put_int(buffer, len);
|
||||
buffer_append(buffer, buf, len);
|
||||
}
|
||||
void
|
||||
buffer_put_cstring(Buffer *buffer, const char *s)
|
||||
{
|
||||
buffer_put_string(buffer, s, strlen(s));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a character from the buffer (0 - 255).
|
||||
*/
|
||||
int
|
||||
int
|
||||
buffer_get_char(Buffer *buffer)
|
||||
{
|
||||
char ch;
|
||||
@ -150,7 +201,7 @@ buffer_get_char(Buffer *buffer)
|
||||
/*
|
||||
* Stores a character in the buffer.
|
||||
*/
|
||||
void
|
||||
void
|
||||
buffer_put_char(Buffer *buffer, int value)
|
||||
{
|
||||
char ch = value;
|
||||
|
@ -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,26 +1,29 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* cipher.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Apr 19 17:41:39 1995 ylo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: cipher.c,v 1.20 2000/03/22 09:55:10 markus Exp $");
|
||||
RCSID("$Id: cipher.c,v 1.26 2000/04/14 10:30:30 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <ssl/md5.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
/*
|
||||
* What kind of tripple DES are these 2 routines?
|
||||
* This is used by SSH1:
|
||||
*
|
||||
* What kind of triple DES are these 2 routines?
|
||||
*
|
||||
* Why is there a redundant initialization vector?
|
||||
*
|
||||
@ -75,7 +78,7 @@ SSH_3CBC_DECRYPT(des_key_schedule ks1,
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH uses a variation on Blowfish, all bytes must be swapped before
|
||||
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
|
||||
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
|
||||
*/
|
||||
static void
|
||||
@ -116,7 +119,12 @@ static char *cipher_names[] =
|
||||
"3des",
|
||||
"tss",
|
||||
"rc4",
|
||||
"blowfish"
|
||||
"blowfish",
|
||||
"reserved",
|
||||
"blowfish-cbc",
|
||||
"3des-cbc",
|
||||
"arcfour",
|
||||
"cast128-cbc"
|
||||
};
|
||||
|
||||
/*
|
||||
@ -125,14 +133,29 @@ static char *cipher_names[] =
|
||||
* supported cipher.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
unsigned int
|
||||
cipher_mask1()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
return mask;
|
||||
}
|
||||
unsigned int
|
||||
cipher_mask2()
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH_CBC;
|
||||
mask |= 1 << SSH_CIPHER_3DES_CBC;
|
||||
mask |= 1 << SSH_CIPHER_ARCFOUR;
|
||||
mask |= 1 << SSH_CIPHER_CAST128_CBC;
|
||||
return mask;
|
||||
}
|
||||
unsigned int
|
||||
cipher_mask()
|
||||
{
|
||||
return cipher_mask1() | cipher_mask2();
|
||||
}
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
|
||||
@ -141,10 +164,34 @@ cipher_name(int cipher)
|
||||
{
|
||||
if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) ||
|
||||
cipher_names[cipher] == NULL)
|
||||
fatal("cipher_name: bad cipher number: %d", cipher);
|
||||
fatal("cipher_name: bad cipher name: %d", cipher);
|
||||
return cipher_names[cipher];
|
||||
}
|
||||
|
||||
/* Returns 1 if the name of the ciphers are valid. */
|
||||
|
||||
#define CIPHER_SEP ","
|
||||
int
|
||||
ciphers_valid(const char *names)
|
||||
{
|
||||
char *ciphers;
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
if (strcmp(names, "") == 0)
|
||||
return 0;
|
||||
ciphers = xstrdup(names);
|
||||
for ((p = strtok(ciphers, CIPHER_SEP)); p; (p = strtok(NULL, CIPHER_SEP))) {
|
||||
i = cipher_number(p);
|
||||
if (i == -1 || !(cipher_mask2() & (1 << i))) {
|
||||
xfree(ciphers);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
xfree(ciphers);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the name of the cipher. Returns the number of the corresponding
|
||||
* cipher, or -1 on error.
|
||||
@ -166,9 +213,8 @@ cipher_number(const char *name)
|
||||
* passphrase and using the resulting 16 bytes as the key.
|
||||
*/
|
||||
|
||||
void
|
||||
cipher_set_key_string(CipherContext *context, int cipher,
|
||||
const char *passphrase, int for_encryption)
|
||||
void
|
||||
cipher_set_key_string(CipherContext *context, int cipher, const char *passphrase)
|
||||
{
|
||||
MD5_CTX md;
|
||||
unsigned char digest[16];
|
||||
@ -177,7 +223,7 @@ cipher_set_key_string(CipherContext *context, int cipher,
|
||||
MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase));
|
||||
MD5_Final(digest, &md);
|
||||
|
||||
cipher_set_key(context, cipher, digest, 16, for_encryption);
|
||||
cipher_set_key(context, cipher, digest, 16);
|
||||
|
||||
memset(digest, 0, sizeof(digest));
|
||||
memset(&md, 0, sizeof(md));
|
||||
@ -185,9 +231,9 @@ cipher_set_key_string(CipherContext *context, int cipher,
|
||||
|
||||
/* Selects the cipher to use and sets the key. */
|
||||
|
||||
void
|
||||
cipher_set_key(CipherContext *context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption)
|
||||
void
|
||||
cipher_set_key(CipherContext *context, int cipher, const unsigned char *key,
|
||||
int keylen)
|
||||
{
|
||||
unsigned char padded[32];
|
||||
|
||||
@ -227,19 +273,86 @@ cipher_set_key(CipherContext *context, int cipher,
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for blowfish.", keylen);
|
||||
BF_set_key(&context->u.bf.key, keylen, padded);
|
||||
memset(context->u.bf.iv, 0, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
fatal("cipher_set_key: illegal cipher: %s", cipher_name(cipher));
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
memset(padded, 0, sizeof(padded));
|
||||
}
|
||||
|
||||
void
|
||||
cipher_set_key_iv(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen,
|
||||
const unsigned char *iv, int ivlen)
|
||||
{
|
||||
/* Set cipher type. */
|
||||
context->type = cipher;
|
||||
|
||||
/* Initialize the initialization vector. */
|
||||
switch (cipher) {
|
||||
case SSH_CIPHER_NONE:
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES:
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
fatal("cipher_set_key_iv: illegal cipher: %s", cipher_name(cipher));
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
if (keylen < 24)
|
||||
error("Key length %d is insufficient for 3des-cbc.", keylen);
|
||||
des_set_key((void *) key, context->u.des3.key1);
|
||||
des_set_key((void *) (key+8), context->u.des3.key2);
|
||||
des_set_key((void *) (key+16), context->u.des3.key3);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for 3des-cbc.", ivlen);
|
||||
memcpy(context->u.des3.iv3, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for blowfish.", keylen);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for blowfish.", ivlen);
|
||||
BF_set_key(&context->u.bf.key, keylen, (unsigned char *)key);
|
||||
memcpy(context->u.bf.iv, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for arcfour.", keylen);
|
||||
RC4_set_key(&context->u.rc4, keylen, (unsigned char *)key);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
if (keylen < 16)
|
||||
error("Key length %d is insufficient for cast128.", keylen);
|
||||
if (ivlen < 8)
|
||||
error("IV length %d is insufficient for cast128.", ivlen);
|
||||
CAST_set_key(&context->u.cast.key, keylen, (unsigned char *) key);
|
||||
memcpy(context->u.cast.iv, (char *)iv, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher));
|
||||
}
|
||||
}
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
|
||||
void
|
||||
void
|
||||
cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
@ -261,11 +374,32 @@ cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
swap_bytes(src, dest, len);
|
||||
BF_cbc_encrypt(dest, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
BF_cbc_encrypt((void *)src, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_ENCRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
context->u.des3.key1, context->u.des3.key2,
|
||||
context->u.des3.key3, &context->u.des3.iv3, DES_ENCRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
CAST_cbc_encrypt(src, dest, len,
|
||||
&context->u.cast.key, context->u.cast.iv, CAST_ENCRYPT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
@ -273,7 +407,7 @@ cipher_encrypt(CipherContext *context, unsigned char *dest,
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
|
||||
void
|
||||
void
|
||||
cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len)
|
||||
{
|
||||
@ -300,6 +434,27 @@ cipher_decrypt(CipherContext *context, unsigned char *dest,
|
||||
swap_bytes(dest, dest, len);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_BLOWFISH_CBC:
|
||||
BF_cbc_encrypt((void *) src, dest, len,
|
||||
&context->u.bf.key, context->u.bf.iv,
|
||||
BF_DECRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_3DES_CBC:
|
||||
des_ede3_cbc_encrypt(src, dest, len,
|
||||
context->u.des3.key1, context->u.des3.key2,
|
||||
context->u.des3.key3, &context->u.des3.iv3, DES_DECRYPT);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_ARCFOUR:
|
||||
RC4(&context->u.rc4, len, (unsigned char *)src, dest);
|
||||
break;
|
||||
|
||||
case SSH_CIPHER_CAST128_CBC:
|
||||
CAST_cbc_encrypt(src, dest, len,
|
||||
&context->u.cast.key, context->u.cast.iv, CAST_DECRYPT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type));
|
||||
}
|
||||
|
@ -1,26 +1,29 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* cipher.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Wed Apr 19 16:50:42 1995 ylo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: cipher.h,v 1.11 2000/03/22 09:55:10 markus Exp $"); */
|
||||
/* RCSID("$Id: cipher.h,v 1.17 2000/05/08 17:12:15 markus Exp $"); */
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
|
||||
#include <ssl/des.h>
|
||||
#include <ssl/blowfish.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/rc4.h>
|
||||
#include <openssl/cast.h>
|
||||
|
||||
/* Cipher types. New types can be added, but old types should not be removed
|
||||
for compatibility. The maximum allowed value is 31. */
|
||||
#define SSH_CIPHER_ILLEGAL -2 /* No valid cipher selected. */
|
||||
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
|
||||
#define SSH_CIPHER_NONE 0 /* no encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
|
||||
@ -29,6 +32,13 @@
|
||||
#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
|
||||
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
#define SSH_CIPHER_RESERVED 7
|
||||
|
||||
/* these ciphers are used in SSH2: */
|
||||
#define SSH_CIPHER_BLOWFISH_CBC 8
|
||||
#define SSH_CIPHER_3DES_CBC 9
|
||||
#define SSH_CIPHER_ARCFOUR 10 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_CAST128_CBC 11
|
||||
|
||||
typedef struct {
|
||||
unsigned int type;
|
||||
@ -44,6 +54,11 @@ typedef struct {
|
||||
struct bf_key_st key;
|
||||
unsigned char iv[8];
|
||||
} bf;
|
||||
struct {
|
||||
CAST_KEY key;
|
||||
unsigned char iv[8];
|
||||
} cast;
|
||||
RC4_KEY rc4;
|
||||
} u;
|
||||
} CipherContext;
|
||||
/*
|
||||
@ -52,6 +67,8 @@ typedef struct {
|
||||
* supported cipher.
|
||||
*/
|
||||
unsigned int cipher_mask();
|
||||
unsigned int cipher_mask1();
|
||||
unsigned int cipher_mask2();
|
||||
|
||||
/* Returns the name of the cipher. */
|
||||
const char *cipher_name(int cipher);
|
||||
@ -62,29 +79,36 @@ const char *cipher_name(int cipher);
|
||||
*/
|
||||
int cipher_number(const char *name);
|
||||
|
||||
/* returns 1 if all ciphers are supported (ssh2 only) */
|
||||
int ciphers_valid(const char *names);
|
||||
|
||||
/*
|
||||
* Selects the cipher to use and sets the key. If for_encryption is true,
|
||||
* the key is setup for encryption; otherwise it is setup for decryption.
|
||||
*/
|
||||
void
|
||||
void
|
||||
cipher_set_key(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen, int for_encryption);
|
||||
const unsigned char *key, int keylen);
|
||||
void
|
||||
cipher_set_key_iv(CipherContext * context, int cipher,
|
||||
const unsigned char *key, int keylen,
|
||||
const unsigned char *iv, int ivlen);
|
||||
|
||||
/*
|
||||
* Sets key for the cipher by computing the MD5 checksum of the passphrase,
|
||||
* and using the resulting 16 bytes as the key.
|
||||
*/
|
||||
void
|
||||
void
|
||||
cipher_set_key_string(CipherContext * context, int cipher,
|
||||
const char *passphrase, int for_encryption);
|
||||
const char *passphrase);
|
||||
|
||||
/* Encrypts data using the cipher. */
|
||||
void
|
||||
void
|
||||
cipher_encrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
/* Decrypts data using the cipher. */
|
||||
void
|
||||
void
|
||||
cipher_decrypt(CipherContext * context, unsigned char *dest,
|
||||
const unsigned char *src, unsigned int len);
|
||||
|
||||
|
@ -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
|
@ -28,11 +28,11 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: fingerprint.c,v 1.5 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$Id: fingerprint.c,v 1.6 2000/04/12 09:39:10 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include <ssl/md5.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
|
@ -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
|
@ -1,26 +1,26 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* hostfile.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 29 07:10:56 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for manipulating the known hosts files.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: hostfile.c,v 1.14 2000/03/23 22:15:33 markus Exp $");
|
||||
RCSID("$OpenBSD: hostfile.c,v 1.18 2000/04/29 18:11:52 markus Exp $");
|
||||
|
||||
#include "packet.h"
|
||||
#include "match.h"
|
||||
#include "ssh.h"
|
||||
#include <ssl/rsa.h>
|
||||
#include <ssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "key.h"
|
||||
#include "hostfile.h"
|
||||
|
||||
@ -39,13 +39,8 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
|
||||
if (!key_read(ret, bits, &cp))
|
||||
bits = key_read(ret, &cp);
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
@ -75,10 +70,10 @@ hostfile_check_key(int bits, Key *key, const char *host, const char *filename, i
|
||||
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL)
|
||||
return 1;
|
||||
if (bits != BN_num_bits(key->rsa->n)) {
|
||||
error("Warning: %s, line %d: keysize mismatch for host %s: "
|
||||
log("Warning: %s, line %d: keysize mismatch for host %s: "
|
||||
"actual %d vs. announced %d.",
|
||||
filename, linenum, host, BN_num_bits(key->rsa->n), bits);
|
||||
error("Warning: replace %d with %d in %s, line %d.",
|
||||
log("Warning: replace %d with %d in %s, line %d.",
|
||||
bits, BN_num_bits(key->rsa->n), filename, linenum);
|
||||
}
|
||||
return 1;
|
||||
@ -182,24 +177,18 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
|
||||
{
|
||||
FILE *f;
|
||||
int success = 0;
|
||||
|
||||
if (key == NULL)
|
||||
return 1;
|
||||
|
||||
/* Open the file for appending. */
|
||||
return 1; /* XXX ? */
|
||||
f = fopen(filename, "a");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
fprintf(f, "%s ", host);
|
||||
if (key_write(key, f)) {
|
||||
fprintf(f, "\n");
|
||||
success = 1;
|
||||
} else {
|
||||
error("add_host_to_hostfile: saving key failed");
|
||||
error("add_host_to_hostfile: saving key in %s failed", filename);
|
||||
}
|
||||
|
||||
/* Close the file. */
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
return success;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -1,16 +1,16 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* includes.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Thu Mar 23 16:29:37 1995 ylo
|
||||
*
|
||||
*
|
||||
* This file includes most of the needed system headers.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
|
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
|
@ -33,11 +33,15 @@
|
||||
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include <ssl/rsa.h>
|
||||
#include <ssl/dsa.h>
|
||||
#include <ssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#define SSH_DSS "ssh-dss"
|
||||
|
||||
Key *
|
||||
key_new(int type)
|
||||
@ -47,6 +51,8 @@ key_new(int type)
|
||||
DSA *dsa;
|
||||
k = xmalloc(sizeof(*k));
|
||||
k->type = type;
|
||||
k->dsa = NULL;
|
||||
k->rsa = NULL;
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
rsa = RSA_new();
|
||||
@ -63,8 +69,6 @@ key_new(int type)
|
||||
k->dsa = dsa;
|
||||
break;
|
||||
case KEY_EMPTY:
|
||||
k->dsa = NULL;
|
||||
k->rsa = NULL;
|
||||
break;
|
||||
default:
|
||||
fatal("key_new: bad key type %d", k->type);
|
||||
@ -111,7 +115,7 @@ key_equal(Key *a, Key *b)
|
||||
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
|
||||
break;
|
||||
default:
|
||||
fatal("key_free: bad key type %d", a->type);
|
||||
fatal("key_equal: bad key type %d", a->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -127,46 +131,37 @@ char *
|
||||
key_fingerprint(Key *k)
|
||||
{
|
||||
static char retval[80];
|
||||
unsigned char *buf = NULL;
|
||||
unsigned char *blob = NULL;
|
||||
int len = 0;
|
||||
int nlen, elen, plen, qlen, glen, publen;
|
||||
int nlen, elen;
|
||||
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
nlen = BN_num_bytes(k->rsa->n);
|
||||
elen = BN_num_bytes(k->rsa->e);
|
||||
len = nlen + elen;
|
||||
buf = xmalloc(len);
|
||||
BN_bn2bin(k->rsa->n, buf);
|
||||
BN_bn2bin(k->rsa->e, buf + nlen);
|
||||
blob = xmalloc(len);
|
||||
BN_bn2bin(k->rsa->n, blob);
|
||||
BN_bn2bin(k->rsa->e, blob + nlen);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
plen = BN_num_bytes(k->dsa->p);
|
||||
qlen = BN_num_bytes(k->dsa->q);
|
||||
glen = BN_num_bytes(k->dsa->g);
|
||||
publen = BN_num_bytes(k->dsa->pub_key);
|
||||
len = qlen + qlen + glen + publen;
|
||||
buf = xmalloc(len);
|
||||
BN_bn2bin(k->dsa->p, buf);
|
||||
BN_bn2bin(k->dsa->q, buf + plen);
|
||||
BN_bn2bin(k->dsa->g, buf + plen + qlen);
|
||||
BN_bn2bin(k->dsa->pub_key , buf + plen + qlen + glen);
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
break;
|
||||
default:
|
||||
fatal("key_fingerprint: bad key type %d", k->type);
|
||||
break;
|
||||
}
|
||||
if (buf != NULL) {
|
||||
if (blob != NULL) {
|
||||
unsigned char d[16];
|
||||
EVP_MD_CTX md;
|
||||
EVP_DigestInit(&md, EVP_md5());
|
||||
EVP_DigestUpdate(&md, buf, len);
|
||||
EVP_DigestUpdate(&md, blob, len);
|
||||
EVP_DigestFinal(&md, d, NULL);
|
||||
snprintf(retval, sizeof(retval), FPRINT,
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
||||
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
memset(buf, 0, len);
|
||||
xfree(buf);
|
||||
memset(blob, 0, len);
|
||||
xfree(blob);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@ -226,13 +221,27 @@ write_bignum(FILE *f, BIGNUM *num)
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
int
|
||||
key_read(Key *ret, unsigned int bits, char **cpp)
|
||||
unsigned int
|
||||
key_read(Key *ret, char **cpp)
|
||||
{
|
||||
Key *k;
|
||||
unsigned int bits = 0;
|
||||
char *cp;
|
||||
int len, n;
|
||||
unsigned char *blob;
|
||||
|
||||
cp = *cpp;
|
||||
|
||||
switch(ret->type) {
|
||||
case KEY_RSA:
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
*cpp = cp;
|
||||
/* Get public exponent, public modulus. */
|
||||
if (!read_bignum(cpp, ret->rsa->e))
|
||||
return 0;
|
||||
@ -240,22 +249,36 @@ key_read(Key *ret, unsigned int bits, char **cpp)
|
||||
return 0;
|
||||
break;
|
||||
case KEY_DSA:
|
||||
if (bits != 0)
|
||||
if (strncmp(cp, SSH_DSS " ", 7) != 0)
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->p))
|
||||
cp += 7;
|
||||
len = 2*strlen(cp);
|
||||
blob = xmalloc(len);
|
||||
n = uudecode(cp, blob, len);
|
||||
if (n < 0) {
|
||||
error("uudecode %s failed", cp);
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->q))
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->g))
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->pub_key))
|
||||
}
|
||||
k = dsa_key_from_blob(blob, n);
|
||||
if (k == NULL)
|
||||
return 0;
|
||||
xfree(blob);
|
||||
if (ret->dsa != NULL)
|
||||
DSA_free(ret->dsa);
|
||||
ret->dsa = k->dsa;
|
||||
k->dsa = NULL;
|
||||
key_free(k);
|
||||
bits = BN_num_bits(ret->dsa->p);
|
||||
cp = strchr(cp, '=');
|
||||
if (cp == NULL)
|
||||
return 0;
|
||||
*cpp = cp + 1;
|
||||
break;
|
||||
default:
|
||||
fatal("bad key type: %d", ret->type);
|
||||
fatal("key_read: bad key type: %d", ret->type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
return bits;
|
||||
}
|
||||
int
|
||||
key_write(Key *key, FILE *f)
|
||||
@ -274,17 +297,30 @@ key_write(Key *key, FILE *f)
|
||||
error("key_write: failed for RSA key");
|
||||
}
|
||||
} else if (key->type == KEY_DSA && key->dsa != NULL) {
|
||||
/* bits == 0 means DSA key */
|
||||
bits = 0;
|
||||
fprintf(f, "%u", bits);
|
||||
if (write_bignum(f, key->dsa->p) &&
|
||||
write_bignum(f, key->dsa->q) &&
|
||||
write_bignum(f, key->dsa->g) &&
|
||||
write_bignum(f, key->dsa->pub_key)) {
|
||||
int len, n;
|
||||
unsigned char *blob, *uu;
|
||||
dsa_make_key_blob(key, &blob, &len);
|
||||
uu = xmalloc(2*len);
|
||||
n = uuencode(blob, len, uu, 2*len);
|
||||
if (n > 0) {
|
||||
fprintf(f, "%s %s", SSH_DSS, uu);
|
||||
success = 1;
|
||||
} else {
|
||||
error("key_write: failed for DSA key");
|
||||
}
|
||||
xfree(blob);
|
||||
xfree(uu);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
char *
|
||||
key_type(Key *k)
|
||||
{
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
return "RSA";
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return "DSA";
|
||||
break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
@ -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,24 +1,24 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* login.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 24 14:51:08 1995 ylo
|
||||
*
|
||||
*
|
||||
* This file performs some of the things login(1) normally does. We cannot
|
||||
* easily use something like login -p -h host -f user, because there are
|
||||
* several different logins around, and it is hard to determined what kind of
|
||||
* login the current system has. Also, we want to be able to execute commands
|
||||
* on a tty.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: login.c,v 1.11 2000/01/04 00:07:59 markus Exp $");
|
||||
RCSID("$Id: login.c,v 1.13 2000/04/19 07:05:49 deraadt Exp $");
|
||||
|
||||
#include <util.h>
|
||||
#include <utmp.h>
|
||||
@ -35,7 +35,7 @@ RCSID("$Id: login.c,v 1.11 2000/01/04 00:07:59 markus Exp $");
|
||||
* is found). The name of the host used last time is returned in buf.
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
unsigned long
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize)
|
||||
{
|
||||
@ -67,8 +67,8 @@ get_last_login_time(uid_t uid, const char *logname,
|
||||
* were more standardized.
|
||||
*/
|
||||
|
||||
void
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
void
|
||||
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr * addr)
|
||||
{
|
||||
int fd;
|
||||
@ -115,8 +115,8 @@ record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
|
||||
/* Records that the user has logged out. */
|
||||
|
||||
void
|
||||
record_logout(int pid, const char *ttyname)
|
||||
void
|
||||
record_logout(pid_t pid, const char *ttyname)
|
||||
{
|
||||
const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
|
||||
if (logout(line))
|
||||
|
@ -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,33 +1,33 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* mpaux.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 16 04:29:30 1995 ylo
|
||||
*
|
||||
*
|
||||
* This file contains various auxiliary functions related to multiple
|
||||
* precision integers.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: mpaux.c,v 1.9 1999/12/08 22:37:42 markus Exp $");
|
||||
RCSID("$Id: mpaux.c,v 1.12 2000/04/14 10:30:32 markus Exp $");
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "getput.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include <ssl/md5.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
BIGNUM* host_key_n,
|
||||
BIGNUM* session_key_n)
|
||||
unsigned char cookie[8],
|
||||
BIGNUM* host_key_n,
|
||||
BIGNUM* session_key_n)
|
||||
{
|
||||
unsigned int host_key_bytes = BN_num_bytes(host_key_n);
|
||||
unsigned int session_key_bytes = BN_num_bytes(session_key_n);
|
||||
|
@ -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,24 +1,24 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* packet.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 02:02:14 1995 ylo
|
||||
*
|
||||
*
|
||||
* Interface for the packet protocol functions.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: packet.h,v 1.10 2000/03/16 20:56:14 markus Exp $"); */
|
||||
/* RCSID("$Id: packet.h,v 1.15 2000/04/14 10:30:32 markus Exp $"); */
|
||||
|
||||
#ifndef PACKET_H
|
||||
#define PACKET_H
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
/*
|
||||
* Sets the socket used for communication. Disables encryption until
|
||||
@ -47,7 +47,7 @@ void packet_close(void);
|
||||
* key is used for both sending and reception. However, both directions are
|
||||
* encrypted independently of each other. Cipher types are defined in ssh.h.
|
||||
*/
|
||||
void
|
||||
void
|
||||
packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
|
||||
int cipher_type);
|
||||
|
||||
@ -83,9 +83,12 @@ void packet_put_int(unsigned int value);
|
||||
|
||||
/* Appends an arbitrary precision integer to packet data. */
|
||||
void packet_put_bignum(BIGNUM * value);
|
||||
void packet_put_bignum2(BIGNUM * value);
|
||||
|
||||
/* Appends a string to packet data. */
|
||||
void packet_put_string(const char *buf, unsigned int len);
|
||||
void packet_put_cstring(const char *str);
|
||||
void packet_put_raw(const char *buf, unsigned int len);
|
||||
|
||||
/*
|
||||
* Finalizes and sends the packet. If the encryption key has been set,
|
||||
@ -129,6 +132,8 @@ unsigned int packet_get_int(void);
|
||||
* must have been initialized before this call.
|
||||
*/
|
||||
void packet_get_bignum(BIGNUM * value, int *length_ptr);
|
||||
void packet_get_bignum2(BIGNUM * value, int *length_ptr);
|
||||
char *packet_get_raw(int *length_ptr);
|
||||
|
||||
/*
|
||||
* Returns a string from the packet data. The string is allocated using
|
||||
@ -191,8 +196,24 @@ do { \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define packet_done() \
|
||||
do { \
|
||||
int _len = packet_remaining(); \
|
||||
if (_len > 0) { \
|
||||
log("Packet integrity error (%d bytes remaining) at %s:%d", \
|
||||
_len ,__FILE__, __LINE__); \
|
||||
packet_disconnect("Packet integrity error."); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* remote host is connected via a socket/ipv4 */
|
||||
int packet_connection_is_on_socket(void);
|
||||
int packet_connection_is_ipv4(void);
|
||||
|
||||
/* enable SSH2 packet format */
|
||||
void packet_set_ssh2_format(void);
|
||||
|
||||
/* returns remaining payload bytes */
|
||||
int packet_remaining(void);
|
||||
|
||||
#endif /* PACKET_H */
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* pty.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 04:37:25 1995 ylo
|
||||
*
|
||||
*
|
||||
* Allocating a pseudo-terminal, and making it the controlling tty.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: pty.c,v 1.12 2000/02/15 16:52:58 markus Exp $");
|
||||
RCSID("$Id: pty.c,v 1.13 2000/04/14 10:30:32 markus Exp $");
|
||||
|
||||
#include <util.h>
|
||||
#include "pty.h"
|
||||
@ -36,7 +36,7 @@ RCSID("$Id: pty.c,v 1.12 2000/02/15 16:52:58 markus Exp $");
|
||||
* returned (the buffer must be able to hold at least 64 characters).
|
||||
*/
|
||||
|
||||
int
|
||||
int
|
||||
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
|
||||
{
|
||||
#if defined(HAVE_OPENPTY) || defined(BSD4_4)
|
||||
@ -174,7 +174,7 @@ pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
|
||||
|
||||
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
|
||||
|
||||
void
|
||||
void
|
||||
pty_release(const char *ttyname)
|
||||
{
|
||||
if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
|
||||
@ -185,7 +185,7 @@ pty_release(const char *ttyname)
|
||||
|
||||
/* Makes the tty the processes controlling tty and sets it to sane modes. */
|
||||
|
||||
void
|
||||
void
|
||||
pty_make_controlling_tty(int *ttyfd, const char *ttyname)
|
||||
{
|
||||
int fd;
|
||||
@ -238,7 +238,7 @@ 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,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;
|
||||
|
@ -1,25 +1,27 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* readconf.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Apr 22 00:03:10 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for reading the configuration files.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: readconf.c,v 1.23 2000/02/28 19:51:58 markus Exp $");
|
||||
RCSID("$Id: readconf.c,v 1.31 2000/05/08 17:12:15 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "cipher.h"
|
||||
#include "readconf.h"
|
||||
#include "match.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.h"
|
||||
|
||||
/* Format of the configuration file:
|
||||
|
||||
@ -102,7 +104,8 @@ typedef enum {
|
||||
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
||||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
||||
oUsePrivilegedPort, oLogLevel
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication
|
||||
} OpCodes;
|
||||
|
||||
/* Textual representations of the tokens. */
|
||||
@ -118,6 +121,7 @@ static struct {
|
||||
{ "rhostsauthentication", oRhostsAuthentication },
|
||||
{ "passwordauthentication", oPasswordAuthentication },
|
||||
{ "rsaauthentication", oRSAAuthentication },
|
||||
{ "dsaauthentication", oDSAAuthentication },
|
||||
{ "skeyauthentication", oSkeyAuthentication },
|
||||
#ifdef KRB4
|
||||
{ "kerberosauthentication", oKerberosAuthentication },
|
||||
@ -129,10 +133,13 @@ static struct {
|
||||
{ "fallbacktorsh", oFallBackToRsh },
|
||||
{ "usersh", oUseRsh },
|
||||
{ "identityfile", oIdentityFile },
|
||||
{ "identityfile2", oIdentityFile2 },
|
||||
{ "hostname", oHostName },
|
||||
{ "proxycommand", oProxyCommand },
|
||||
{ "port", oPort },
|
||||
{ "cipher", oCipher },
|
||||
{ "ciphers", oCiphers },
|
||||
{ "protocol", oProtocol },
|
||||
{ "remoteforward", oRemoteForward },
|
||||
{ "localforward", oLocalForward },
|
||||
{ "user", oUser },
|
||||
@ -141,6 +148,8 @@ static struct {
|
||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
|
||||
{ "userknownhostsfile2", oUserKnownHostsFile2 },
|
||||
{ "connectionattempts", oConnectionAttempts },
|
||||
{ "batchmode", oBatchMode },
|
||||
{ "checkhostip", oCheckHostIP },
|
||||
@ -163,7 +172,7 @@ static struct {
|
||||
* error.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
add_local_forward(Options *options, u_short port, const char *host,
|
||||
u_short host_port)
|
||||
{
|
||||
@ -184,7 +193,7 @@ add_local_forward(Options *options, u_short port, const char *host,
|
||||
* an error.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
add_remote_forward(Options *options, u_short port, const char *host,
|
||||
u_short host_port)
|
||||
{
|
||||
@ -203,7 +212,7 @@ add_remote_forward(Options *options, u_short port, const char *host,
|
||||
* returns if the token is not known.
|
||||
*/
|
||||
|
||||
static OpCodes
|
||||
static OpCodes
|
||||
parse_token(const char *cp, const char *filename, int linenum)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -282,6 +291,10 @@ process_config_line(Options *options, const char *host,
|
||||
intptr = &options->password_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oDSAAuthentication:
|
||||
intptr = &options->dsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oRSAAuthentication:
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
@ -364,14 +377,22 @@ process_config_line(Options *options, const char *host,
|
||||
goto parse_int;
|
||||
|
||||
case oIdentityFile:
|
||||
case oIdentityFile2:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep) {
|
||||
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
|
||||
intptr = (opcode == oIdentityFile) ?
|
||||
&options->num_identity_files :
|
||||
&options->num_identity_files2;
|
||||
if (*intptr >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
||||
options->identity_files[options->num_identity_files++] = xstrdup(cp);
|
||||
charptr = (opcode == oIdentityFile) ?
|
||||
&options->identity_files[*intptr] :
|
||||
&options->identity_files2[*intptr];
|
||||
*charptr = xstrdup(cp);
|
||||
*intptr = *intptr + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -393,6 +414,14 @@ process_config_line(Options *options, const char *host,
|
||||
charptr = &options->user_hostfile;
|
||||
goto parse_string;
|
||||
|
||||
case oGlobalKnownHostsFile2:
|
||||
charptr = &options->system_hostfile2;
|
||||
goto parse_string;
|
||||
|
||||
case oUserKnownHostsFile2:
|
||||
charptr = &options->user_hostfile2;
|
||||
goto parse_string;
|
||||
|
||||
case oHostName:
|
||||
charptr = &options->hostname;
|
||||
goto parse_string;
|
||||
@ -443,6 +472,26 @@ process_config_line(Options *options, const char *host,
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oCiphers:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!ciphers_valid(cp))
|
||||
fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*activep && options->ciphers == NULL)
|
||||
options->ciphers = xstrdup(cp);
|
||||
break;
|
||||
|
||||
case oProtocol:
|
||||
intptr = &options->protocol;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = proto_spec(cp);
|
||||
if (value == SSH_PROTO_UNKNOWN)
|
||||
fatal("%.200s line %d: Bad protocol spec '%s'.",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*activep && *intptr == SSH_PROTO_UNKNOWN)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
case oLogLevel:
|
||||
intptr = (int *) &options->log_level;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
@ -543,7 +592,7 @@ process_config_line(Options *options, const char *host,
|
||||
* there is an error. If the file does not exist, this returns immediately.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
read_config_file(const char *filename, const char *host, Options *options)
|
||||
{
|
||||
FILE *f;
|
||||
@ -583,7 +632,7 @@ read_config_file(const char *filename, const char *host, Options *options)
|
||||
* system config file. Last, fill_default_options is called.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
initialize_options(Options * options)
|
||||
{
|
||||
memset(options, 'X', sizeof(*options));
|
||||
@ -593,6 +642,7 @@ initialize_options(Options * options)
|
||||
options->use_privileged_port = -1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
options->dsa_authentication = -1;
|
||||
options->skey_authentication = -1;
|
||||
#ifdef KRB4
|
||||
options->kerberos_authentication = -1;
|
||||
@ -615,13 +665,18 @@ initialize_options(Options * options)
|
||||
options->connection_attempts = -1;
|
||||
options->number_of_password_prompts = -1;
|
||||
options->cipher = -1;
|
||||
options->ciphers = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->num_identity_files = 0;
|
||||
options->num_identity_files2 = 0;
|
||||
options->hostname = NULL;
|
||||
options->proxy_command = NULL;
|
||||
options->user = NULL;
|
||||
options->escape_char = -1;
|
||||
options->system_hostfile = NULL;
|
||||
options->user_hostfile = NULL;
|
||||
options->system_hostfile2 = NULL;
|
||||
options->user_hostfile2 = NULL;
|
||||
options->num_local_forwards = 0;
|
||||
options->num_remote_forwards = 0;
|
||||
options->log_level = (LogLevel) - 1;
|
||||
@ -632,7 +687,7 @@ initialize_options(Options * options)
|
||||
* options for which no value has been specified with their default values.
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
fill_default_options(Options * options)
|
||||
{
|
||||
if (options->forward_agent == -1)
|
||||
@ -647,6 +702,8 @@ fill_default_options(Options * options)
|
||||
options->rhosts_authentication = 1;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
if (options->dsa_authentication == -1)
|
||||
options->dsa_authentication = 1;
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 0;
|
||||
#ifdef KRB4
|
||||
@ -688,18 +745,31 @@ fill_default_options(Options * options)
|
||||
/* Selected in ssh_login(). */
|
||||
if (options->cipher == -1)
|
||||
options->cipher = SSH_CIPHER_NOT_SET;
|
||||
/* options->ciphers, default set in myproposals.h */
|
||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||
options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
|
||||
if (options->num_identity_files == 0) {
|
||||
options->identity_files[0] =
|
||||
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
|
||||
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
|
||||
options->num_identity_files = 1;
|
||||
}
|
||||
if (options->num_identity_files2 == 0) {
|
||||
options->identity_files2[0] =
|
||||
xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
|
||||
sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
|
||||
options->num_identity_files2 = 1;
|
||||
}
|
||||
if (options->escape_char == -1)
|
||||
options->escape_char = '~';
|
||||
if (options->system_hostfile == NULL)
|
||||
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
|
||||
if (options->user_hostfile == NULL)
|
||||
options->user_hostfile = SSH_USER_HOSTFILE;
|
||||
if (options->system_hostfile2 == NULL)
|
||||
options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
|
||||
if (options->user_hostfile2 == NULL)
|
||||
options->user_hostfile2 = SSH_USER_HOSTFILE2;
|
||||
if (options->log_level == (LogLevel) - 1)
|
||||
options->log_level = SYSLOG_LEVEL_INFO;
|
||||
/* options->proxy_command should not be set by default */
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* readconf.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Sat Apr 22 00:25:29 1995 ylo
|
||||
*
|
||||
*
|
||||
* Functions for reading the configuration file.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: readconf.h,v 1.13 1999/12/01 13:59:15 markus Exp $"); */
|
||||
/* RCSID("$Id: readconf.h,v 1.18 2000/05/08 17:12:15 markus Exp $"); */
|
||||
|
||||
#ifndef READCONF_H
|
||||
#define READCONF_H
|
||||
@ -36,6 +36,7 @@ typedef struct {
|
||||
int rhosts_rsa_authentication; /* Try rhosts with RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* Try RSA authentication. */
|
||||
int dsa_authentication; /* Try DSA authentication. */
|
||||
int skey_authentication; /* Try S/Key or TIS authentication. */
|
||||
#ifdef KRB4
|
||||
int kerberos_authentication; /* Try Kerberos
|
||||
@ -64,6 +65,8 @@ typedef struct {
|
||||
int number_of_password_prompts; /* Max number of password
|
||||
* prompts. */
|
||||
int cipher; /* Cipher to use. */
|
||||
char *ciphers; /* SSH2 ciphers in order of preference. */
|
||||
int protocol; /* Protocol in order of preference. */
|
||||
char *hostname; /* Real host to connect. */
|
||||
char *proxy_command; /* Proxy command for connecting the host. */
|
||||
char *user; /* User to log in as. */
|
||||
@ -71,9 +74,13 @@ typedef struct {
|
||||
|
||||
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
|
||||
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
|
||||
char *system_hostfile2;
|
||||
char *user_hostfile2;
|
||||
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
int num_identity_files2; /* DSA identities. */
|
||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||
char *identity_files2[SSH_MAX_IDENTITY_FILES];
|
||||
|
||||
/* Local TCP/IP forward requests. */
|
||||
int num_local_forwards;
|
||||
@ -104,7 +111,7 @@ void fill_default_options(Options * options);
|
||||
* only sets those values that have not already been set. Returns 0 for legal
|
||||
* options
|
||||
*/
|
||||
int
|
||||
int
|
||||
process_config_line(Options * options, const char *host,
|
||||
char *line, const char *filename, int linenum,
|
||||
int *activep);
|
||||
@ -114,7 +121,7 @@ process_config_line(Options * options, const char *host,
|
||||
* should already be initialized before this call. This never returns if
|
||||
* there is an error. If the file does not exist, this returns immediately.
|
||||
*/
|
||||
void
|
||||
void
|
||||
read_config_file(const char *filename, const char *host,
|
||||
Options * options);
|
||||
|
||||
@ -122,7 +129,7 @@ read_config_file(const char *filename, const char *host,
|
||||
* Adds a local TCP/IP port forward to options. Never returns if there is an
|
||||
* error.
|
||||
*/
|
||||
void
|
||||
void
|
||||
add_local_forward(Options * options, u_short port, const char *host,
|
||||
u_short host_port);
|
||||
|
||||
@ -130,7 +137,7 @@ add_local_forward(Options * options, u_short port, const char *host,
|
||||
* Adds a remote TCP/IP port forward to options. Never returns if there is
|
||||
* an error.
|
||||
*/
|
||||
void
|
||||
void
|
||||
add_remote_forward(Options * options, u_short port, const char *host,
|
||||
u_short host_port);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1,41 +1,41 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* rsa.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 3 22:07:06 1995 ylo
|
||||
*
|
||||
*
|
||||
* Description of the RSA algorithm can be found e.g. from the following sources:
|
||||
*
|
||||
*
|
||||
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994.
|
||||
*
|
||||
*
|
||||
* Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to
|
||||
* Computer Security. Prentice-Hall, 1989.
|
||||
*
|
||||
*
|
||||
* Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill,
|
||||
* 1994.
|
||||
*
|
||||
*
|
||||
* R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications
|
||||
* System and Method. US Patent 4,405,829, 1983.
|
||||
*
|
||||
*
|
||||
* Hans Riesel: Prime Numbers and Computer Methods for Factorization.
|
||||
* Birkhauser, 1994.
|
||||
*
|
||||
*
|
||||
* The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995.
|
||||
*
|
||||
*
|
||||
* RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included
|
||||
* below:
|
||||
*
|
||||
*
|
||||
* [gone - had to be deleted - what a pity]
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: rsa.c,v 1.13 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$Id: rsa.c,v 1.14 2000/04/14 10:30:32 markus Exp $");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
|
@ -1,25 +1,25 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* rsa.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 3 22:01:06 1995 ylo
|
||||
*
|
||||
*
|
||||
* RSA key generation, encryption and decryption.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: rsa.h,v 1.4 1999/11/24 19:53:50 markus Exp $"); */
|
||||
/* RCSID("$Id: rsa.h,v 1.6 2000/04/14 10:30:32 markus Exp $"); */
|
||||
|
||||
#ifndef RSA_H
|
||||
#define RSA_H
|
||||
|
||||
#include <ssl/bn.h>
|
||||
#include <ssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
||||
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,30 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* servconf.c
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Mon Aug 21 15:48:58 1995 ylo
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: servconf.c,v 1.31 2000/03/07 20:40:41 markus Exp $");
|
||||
RCSID("$Id: servconf.c,v 1.40 2000/05/08 17:12:15 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "servconf.h"
|
||||
#include "xmalloc.h"
|
||||
#include "compat.h"
|
||||
|
||||
/* add listen address */
|
||||
void add_listen_addr(ServerOptions *options, char *addr);
|
||||
|
||||
/* Initializes the server options to their default values. */
|
||||
|
||||
void
|
||||
void
|
||||
initialize_server_options(ServerOptions *options)
|
||||
{
|
||||
memset(options, 0, sizeof(*options));
|
||||
@ -31,6 +32,8 @@ initialize_server_options(ServerOptions *options)
|
||||
options->ports_from_cmdline = 0;
|
||||
options->listen_addrs = NULL;
|
||||
options->host_key_file = NULL;
|
||||
options->host_dsa_key_file = NULL;
|
||||
options->pid_file = NULL;
|
||||
options->server_key_bits = -1;
|
||||
options->login_grace_time = -1;
|
||||
options->key_regeneration_time = -1;
|
||||
@ -48,6 +51,7 @@ initialize_server_options(ServerOptions *options)
|
||||
options->rhosts_authentication = -1;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
options->dsa_authentication = -1;
|
||||
#ifdef KRB4
|
||||
options->kerberos_authentication = -1;
|
||||
options->kerberos_or_local_passwd = -1;
|
||||
@ -67,9 +71,12 @@ initialize_server_options(ServerOptions *options)
|
||||
options->num_deny_users = 0;
|
||||
options->num_allow_groups = 0;
|
||||
options->num_deny_groups = 0;
|
||||
options->ciphers = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->gateway_ports = -1;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
fill_default_server_options(ServerOptions *options)
|
||||
{
|
||||
if (options->num_ports == 0)
|
||||
@ -78,6 +85,10 @@ fill_default_server_options(ServerOptions *options)
|
||||
add_listen_addr(options, NULL);
|
||||
if (options->host_key_file == NULL)
|
||||
options->host_key_file = HOST_KEY_FILE;
|
||||
if (options->host_dsa_key_file == NULL)
|
||||
options->host_dsa_key_file = HOST_DSA_KEY_FILE;
|
||||
if (options->pid_file == NULL)
|
||||
options->pid_file = SSH_DAEMON_PID_FILE;
|
||||
if (options->server_key_bits == -1)
|
||||
options->server_key_bits = 768;
|
||||
if (options->login_grace_time == -1)
|
||||
@ -112,6 +123,8 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->rhosts_rsa_authentication = 0;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
if (options->dsa_authentication == -1)
|
||||
options->dsa_authentication = 1;
|
||||
#ifdef KRB4
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = (access(KEYFILE, R_OK) == 0);
|
||||
@ -136,6 +149,10 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->permit_empty_passwd = 0;
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
|
||||
if (options->gateway_ports == -1)
|
||||
options->gateway_ports = 0;
|
||||
}
|
||||
|
||||
#define WHITESPACE " \t\r\n"
|
||||
@ -159,7 +176,8 @@ typedef enum {
|
||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||
sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||
sIgnoreUserKnownHosts
|
||||
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
|
||||
sGatewayPorts, sDSAAuthentication
|
||||
} ServerOpCodes;
|
||||
|
||||
/* Textual representation of the tokens. */
|
||||
@ -169,6 +187,8 @@ static struct {
|
||||
} keywords[] = {
|
||||
{ "port", sPort },
|
||||
{ "hostkey", sHostKeyFile },
|
||||
{ "hostdsakey", sHostDSAKeyFile },
|
||||
{ "pidfile", sPidFile },
|
||||
{ "serverkeybits", sServerKeyBits },
|
||||
{ "logingracetime", sLoginGraceTime },
|
||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||
@ -178,6 +198,7 @@ static struct {
|
||||
{ "rhostsauthentication", sRhostsAuthentication },
|
||||
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
|
||||
{ "rsaauthentication", sRSAAuthentication },
|
||||
{ "dsaauthentication", sDSAAuthentication },
|
||||
#ifdef KRB4
|
||||
{ "kerberosauthentication", sKerberosAuthentication },
|
||||
{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
|
||||
@ -207,6 +228,9 @@ static struct {
|
||||
{ "denyusers", sDenyUsers },
|
||||
{ "allowgroups", sAllowGroups },
|
||||
{ "denygroups", sDenyGroups },
|
||||
{ "ciphers", sCiphers },
|
||||
{ "protocol", sProtocol },
|
||||
{ "gatewayports", sGatewayPorts },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@ -215,7 +239,7 @@ static struct {
|
||||
* returns if the token is not known.
|
||||
*/
|
||||
|
||||
static ServerOpCodes
|
||||
static ServerOpCodes
|
||||
parse_token(const char *cp, const char *filename,
|
||||
int linenum)
|
||||
{
|
||||
@ -233,7 +257,7 @@ parse_token(const char *cp, const char *filename,
|
||||
/*
|
||||
* add listen address
|
||||
*/
|
||||
void
|
||||
void
|
||||
add_listen_addr(ServerOptions *options, char *addr)
|
||||
{
|
||||
extern int IPv4or6;
|
||||
@ -263,7 +287,7 @@ add_listen_addr(ServerOptions *options, char *addr)
|
||||
|
||||
/* Reads the server configuration file. */
|
||||
|
||||
void
|
||||
void
|
||||
read_server_config(ServerOptions *options, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
@ -299,7 +323,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
"ListenAdress.\n", filename, linenum);
|
||||
if (options->num_ports >= MAX_PORTS)
|
||||
fatal("%s line %d: too many ports.\n",
|
||||
filename, linenum);
|
||||
filename, linenum);
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%s line %d: missing port number.\n",
|
||||
@ -338,11 +362,25 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
break;
|
||||
|
||||
case sHostKeyFile:
|
||||
charptr = &options->host_key_file;
|
||||
case sHostDSAKeyFile:
|
||||
charptr = (opcode == sHostKeyFile ) ?
|
||||
&options->host_key_file : &options->host_dsa_key_file;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
filename, linenum);
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
*charptr = tilde_expand_filename(cp, getuid());
|
||||
break;
|
||||
|
||||
case sPidFile:
|
||||
charptr = &options->pid_file;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
@ -416,6 +454,10 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sDSAAuthentication:
|
||||
intptr = &options->dsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef KRB4
|
||||
case sKerberosAuthentication:
|
||||
intptr = &options->kerberos_authentication;
|
||||
@ -482,13 +524,17 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
intptr = &options->use_login;
|
||||
goto parse_flag;
|
||||
|
||||
case sGatewayPorts:
|
||||
intptr = &options->gateway_ports;
|
||||
goto parse_flag;
|
||||
|
||||
case sLogFacility:
|
||||
intptr = (int *) &options->log_facility;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = log_facility_number(cp);
|
||||
if (value == (SyslogFacility) - 1)
|
||||
fatal("%.200s line %d: unsupported log facility '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (SyslogFacility) value;
|
||||
break;
|
||||
@ -499,55 +545,67 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
value = log_level_number(cp);
|
||||
if (value == (LogLevel) - 1)
|
||||
fatal("%.200s line %d: unsupported log level '%s'\n",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
break;
|
||||
|
||||
case sAllowUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_allow_users >= MAX_ALLOW_USERS) {
|
||||
fprintf(stderr, "%s line %d: too many allow users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (options->num_allow_users >= MAX_ALLOW_USERS)
|
||||
fatal("%s line %d: too many allow users.\n",
|
||||
filename, linenum);
|
||||
options->allow_users[options->num_allow_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyUsers:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_deny_users >= MAX_DENY_USERS) {
|
||||
fprintf(stderr, "%s line %d: too many deny users.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (options->num_deny_users >= MAX_DENY_USERS)
|
||||
fatal( "%s line %d: too many deny users.\n",
|
||||
filename, linenum);
|
||||
options->deny_users[options->num_deny_users++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sAllowGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) {
|
||||
fprintf(stderr, "%s line %d: too many allow groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
|
||||
fatal("%s line %d: too many allow groups.\n",
|
||||
filename, linenum);
|
||||
options->allow_groups[options->num_allow_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sDenyGroups:
|
||||
while ((cp = strtok(NULL, WHITESPACE))) {
|
||||
if (options->num_deny_groups >= MAX_DENY_GROUPS) {
|
||||
fprintf(stderr, "%s line %d: too many deny groups.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (options->num_deny_groups >= MAX_DENY_GROUPS)
|
||||
fatal("%s line %d: too many deny groups.\n",
|
||||
filename, linenum);
|
||||
options->deny_groups[options->num_deny_groups++] = xstrdup(cp);
|
||||
}
|
||||
break;
|
||||
|
||||
case sCiphers:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!ciphers_valid(cp))
|
||||
fatal("%s line %d: Bad SSH2 cipher spec '%s'.",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (options->ciphers == NULL)
|
||||
options->ciphers = xstrdup(cp);
|
||||
break;
|
||||
|
||||
case sProtocol:
|
||||
intptr = &options->protocol;
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
value = proto_spec(cp);
|
||||
if (value == SSH_PROTO_UNKNOWN)
|
||||
fatal("%s line %d: Bad protocol spec '%s'.",
|
||||
filename, linenum, cp ? cp : "<NONE>");
|
||||
if (*intptr == SSH_PROTO_UNKNOWN)
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
|
||||
filename, linenum, cp, opcode);
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* servconf.h
|
||||
*
|
||||
*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
*
|
||||
* Created: Mon Aug 21 15:35:03 1995 ylo
|
||||
*
|
||||
*
|
||||
* Definitions for server configuration data and for the functions reading it.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: servconf.h,v 1.15 2000/01/04 00:08:00 markus Exp $"); */
|
||||
/* RCSID("$Id: servconf.h,v 1.22 2000/05/06 17:45:37 markus Exp $"); */
|
||||
|
||||
#ifndef SERVCONF_H
|
||||
#define SERVCONF_H
|
||||
@ -32,6 +32,8 @@ typedef struct {
|
||||
char *listen_addr; /* Address on which the server listens. */
|
||||
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
|
||||
char *host_key_file; /* File containing host key. */
|
||||
char *host_dsa_key_file; /* File containing dsa host key. */
|
||||
char *pid_file; /* Where to put our pid */
|
||||
int server_key_bits;/* Size of the server key. */
|
||||
int login_grace_time; /* Disconnect if no auth in this time
|
||||
* (sec). */
|
||||
@ -47,6 +49,9 @@ typedef struct {
|
||||
* searching at */
|
||||
int strict_modes; /* If true, require string home dir modes. */
|
||||
int keepalives; /* If true, set SO_KEEPALIVE. */
|
||||
char *ciphers; /* Ciphers in order of preference. */
|
||||
int protocol; /* Protocol in order of preference. */
|
||||
int gateway_ports; /* If true, allow remote connects to forwarded ports. */
|
||||
SyslogFacility log_facility; /* Facility for system logging. */
|
||||
LogLevel log_level; /* Level for system logging. */
|
||||
int rhosts_authentication; /* If true, permit rhosts
|
||||
@ -54,6 +59,7 @@ typedef struct {
|
||||
int rhosts_rsa_authentication; /* If true, permit rhosts RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* If true, permit RSA authentication. */
|
||||
int dsa_authentication; /* If true, permit DSA authentication. */
|
||||
#ifdef KRB4
|
||||
int kerberos_authentication; /* If true, permit Kerberos
|
||||
* authentication. */
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-agent.c,v 1.26 2000/03/16 20:56:14 markus Exp $ */
|
||||
/* $OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: ssh-agent.c,v 1.26 2000/03/16 20:56:14 markus Exp $");
|
||||
RCSID("$OpenBSD: ssh-agent.c,v 1.31 2000/04/29 18:11:52 markus Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
@ -21,7 +21,7 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.26 2000/03/16 20:56:14 markus Exp $");
|
||||
#include "getput.h"
|
||||
#include "mpaux.h"
|
||||
|
||||
#include <ssl/md5.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
@ -46,7 +46,7 @@ Identity *identities = NULL;
|
||||
int max_fd = 0;
|
||||
|
||||
/* pid of shell == parent of agent */
|
||||
int parent_pid = -1;
|
||||
pid_t parent_pid = -1;
|
||||
|
||||
/* pathname and directory for AUTH_SOCKET */
|
||||
char socket_name[1024];
|
||||
@ -174,7 +174,7 @@ process_remove_identity(SocketEntry *e)
|
||||
buffer_get_bignum(&e->input, n);
|
||||
|
||||
if (bits != BN_num_bits(n))
|
||||
error("Warning: identity keysize mismatch: actual %d, announced %d",
|
||||
log("Warning: identity keysize mismatch: actual %d, announced %d",
|
||||
BN_num_bits(n), bits);
|
||||
|
||||
/* Check if we have the key. */
|
||||
@ -403,7 +403,7 @@ prepare_select(fd_set *readset, fd_set *writeset)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
after_select(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -436,6 +436,8 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
shutdown(sockets[i].fd, SHUT_RDWR);
|
||||
close(sockets[i].fd);
|
||||
sockets[i].type = AUTH_UNUSED;
|
||||
buffer_free(&sockets[i].input);
|
||||
buffer_free(&sockets[i].output);
|
||||
break;
|
||||
}
|
||||
buffer_consume(&sockets[i].output, len);
|
||||
@ -446,6 +448,8 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
shutdown(sockets[i].fd, SHUT_RDWR);
|
||||
close(sockets[i].fd);
|
||||
sockets[i].type = AUTH_UNUSED;
|
||||
buffer_free(&sockets[i].input);
|
||||
buffer_free(&sockets[i].output);
|
||||
break;
|
||||
}
|
||||
buffer_append(&sockets[i].input, buf, len);
|
||||
@ -460,7 +464,7 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
void
|
||||
check_parent_exists(int sig)
|
||||
{
|
||||
if (kill(parent_pid, 0) < 0) {
|
||||
if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
|
||||
/* printf("Parent has died - Authentication agent exiting.\n"); */
|
||||
exit(1);
|
||||
}
|
||||
@ -546,6 +550,7 @@ main(int ac, char **av)
|
||||
}
|
||||
pid = atoi(pidstr);
|
||||
if (pid < 1) { /* XXX PID_MAX check too */
|
||||
/* Yes, PID_MAX check please */
|
||||
fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
|
||||
SSH_AGENTPID_ENV_NAME, pidstr);
|
||||
exit(1);
|
||||
@ -637,8 +642,8 @@ main(int ac, char **av)
|
||||
}
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, cleanup_exit);
|
||||
signal(SIGTERM, cleanup_exit);
|
||||
signal(SIGHUP, cleanup_exit);
|
||||
signal(SIGTERM, cleanup_exit);
|
||||
while (1) {
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&writeset);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: ssh.1,v 1.43 2000/03/24 03:04:46 brad Exp $
|
||||
.\" $Id: ssh.1,v 1.52 2000/05/08 17:21:32 hugh Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH 1
|
||||
@ -24,8 +24,8 @@
|
||||
.Op Ar command
|
||||
.Pp
|
||||
.Nm ssh
|
||||
.Op Fl afgknqtvxCPX46
|
||||
.Op Fl c Ar blowfish | 3des
|
||||
.Op Fl afgknqtvxCPX246
|
||||
.Op Fl c Ar cipher_spec
|
||||
.Op Fl e Ar escape_char
|
||||
.Op Fl i Ar identity_file
|
||||
.Op Fl l Ar login_name
|
||||
@ -49,7 +49,7 @@
|
||||
.Oc
|
||||
.Op Ar hostname | user@hostname
|
||||
.Op Ar command
|
||||
.Sh DESCRIPTION
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
(Secure Shell) is a program for logging into a remote machine and for
|
||||
executing commands on a remote machine.
|
||||
@ -60,10 +60,13 @@ X11 connections and
|
||||
arbitrary TCP/IP ports can also be forwarded over the secure channel.
|
||||
.Pp
|
||||
.Nm
|
||||
connects and logs into the specified
|
||||
connects and logs into the specified
|
||||
.Ar hostname .
|
||||
The user must prove
|
||||
his/her identity to the remote machine using one of several methods.
|
||||
his/her identity to the remote machine using one of several methods
|
||||
depending on the protocol version used:
|
||||
.Pp
|
||||
.Ss SSH protocol version 1
|
||||
.Pp
|
||||
First, if the machine the user logs in from is listed in
|
||||
.Pa /etc/hosts.equiv
|
||||
@ -71,7 +74,7 @@ or
|
||||
.Pa /etc/shosts.equiv
|
||||
on the remote machine, and the user names are
|
||||
the same on both sides, the user is immediately permitted to log in.
|
||||
Second, if
|
||||
Second, if
|
||||
.Pa \&.rhosts
|
||||
or
|
||||
.Pa \&.shosts
|
||||
@ -88,13 +91,13 @@ or
|
||||
.Pa hosts.equiv
|
||||
method combined with RSA-based host authentication.
|
||||
It means that if the login would be permitted by
|
||||
.Pa \&.rhosts ,
|
||||
.Pa \&.shosts ,
|
||||
.Pa $HOME/.rhosts ,
|
||||
.Pa $HOME/.shosts ,
|
||||
.Pa /etc/hosts.equiv ,
|
||||
or
|
||||
.Pa /etc/shosts.equiv ,
|
||||
and if additionally the server can verify the client's
|
||||
host key (see
|
||||
host key (see
|
||||
.Pa /etc/ssh_known_hosts
|
||||
and
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
@ -105,21 +108,21 @@ This authentication method closes security holes due to IP
|
||||
spoofing, DNS spoofing and routing spoofing.
|
||||
[Note to the administrator:
|
||||
.Pa /etc/hosts.equiv ,
|
||||
.Pa \&.rhosts ,
|
||||
.Pa $HOME/.rhosts ,
|
||||
and the rlogin/rsh protocol in general, are inherently insecure and should be
|
||||
disabled if security is desired.]
|
||||
.Pp
|
||||
As a third authentication method,
|
||||
As a third authentication method,
|
||||
.Nm
|
||||
supports RSA based authentication.
|
||||
The scheme is based on public-key cryptography: there are cryptosystems
|
||||
where encryption and decryption are done using separate keys, and it
|
||||
is not possible to derive the decryption key from the encryption key.
|
||||
RSA is one such system.
|
||||
The idea is that each user creates a public/private
|
||||
The idea is that each user creates a public/private
|
||||
key pair for authentication purposes.
|
||||
The server knows the public key, and only the user knows the private key.
|
||||
The file
|
||||
The file
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
lists the public keys that are permitted for logging
|
||||
in.
|
||||
@ -142,19 +145,19 @@ key but without disclosing it to the server.
|
||||
implements the RSA authentication protocol automatically.
|
||||
The user creates his/her RSA key pair by running
|
||||
.Xr ssh-keygen 1 .
|
||||
This stores the private key in
|
||||
.Pa \&.ssh/identity
|
||||
This stores the private key in
|
||||
.Pa $HOME/.ssh/identity
|
||||
and the public key in
|
||||
.Pa \&.ssh/identity.pub
|
||||
.Pa $HOME/.ssh/identity.pub
|
||||
in the user's home directory.
|
||||
The user should then copy the
|
||||
.Pa identity.pub
|
||||
to
|
||||
.Pa \&.ssh/authorized_keys
|
||||
in his/her home directory on the remote machine (the
|
||||
to
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
in his/her home directory on the remote machine (the
|
||||
.Pa authorized_keys
|
||||
file corresponds to the conventional
|
||||
.Pa \&.rhosts
|
||||
file corresponds to the conventional
|
||||
.Pa $HOME/.rhosts
|
||||
file, and has one key
|
||||
per line, though the lines can be very long).
|
||||
After this, the user can log in without giving the password.
|
||||
@ -167,13 +170,45 @@ See
|
||||
.Xr ssh-agent 1
|
||||
for more information.
|
||||
.Pp
|
||||
If other authentication methods fail,
|
||||
If other authentication methods fail,
|
||||
.Nm
|
||||
prompts the user for a password.
|
||||
The password is sent to the remote
|
||||
host for checking; however, since all communications are encrypted,
|
||||
the password cannot be seen by someone listening on the network.
|
||||
.Pp
|
||||
.Ss SSH protocol version 2
|
||||
.Pp
|
||||
When a user connects using the protocol version 2
|
||||
different authentication methods are available:
|
||||
At first, the client attempts to authenticate using the public key method.
|
||||
If this method fails password authentication is tried.
|
||||
.Pp
|
||||
The public key method is similar to RSA authentication described
|
||||
in the previous section except that the DSA algorithm is used
|
||||
instead of the patented RSA algorithm.
|
||||
The client uses his private DSA key
|
||||
.Pa $HOME/.ssh/id_dsa
|
||||
to sign the session identifier and sends the result to the server.
|
||||
The server checks whether the matching public key is listed in
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
and grants access if both the key is found and the signature is correct.
|
||||
The session identifier is derived from a shared Diffie-Hellman value
|
||||
and is only known to the client and the server.
|
||||
.Pp
|
||||
If public key authentication fails or is not available a password
|
||||
can be sent encrypted to the remote host for proving the user's identity.
|
||||
This protocol 2 implementation does not yet support Kerberos or
|
||||
S/Key authentication.
|
||||
.Pp
|
||||
Protocol 2 provides additional mechanisms for confidentiality
|
||||
(the traffic is encrypted using 3DES, Blowfish, CAST128 or Arcfour)
|
||||
and integrity (hmac-sha1, hmac-md5).
|
||||
Note that protocol 1 lacks a strong mechanism for ensuring the
|
||||
integrity of the connection.
|
||||
.Pp
|
||||
.Ss Login session and remote execution
|
||||
.Pp
|
||||
When the user's identity has been accepted by the server, the server
|
||||
either executes the given command, or logs into the machine and gives
|
||||
the user a normal shell on the remote machine.
|
||||
@ -188,7 +223,7 @@ and suspend
|
||||
with
|
||||
.Ic ~^Z .
|
||||
All forwarded connections can be listed with
|
||||
.Ic ~#
|
||||
.Ic ~#
|
||||
and if
|
||||
the session blocks waiting for forwarded X11 or TCP/IP
|
||||
connections to terminate, it can be backgrounded with
|
||||
@ -219,6 +254,8 @@ The exit status of the remote program is returned as the exit status
|
||||
of
|
||||
.Nm ssh .
|
||||
.Pp
|
||||
.Ss X11 and TCP forwarding
|
||||
.Pp
|
||||
If the user is using X11 (the
|
||||
.Ev DISPLAY
|
||||
environment variable is set), the connection to the X11 display is
|
||||
@ -232,7 +269,7 @@ Forwarding of X11 connections can be
|
||||
configured on the command line or in configuration files.
|
||||
.Pp
|
||||
The
|
||||
.Ev DISPLAY
|
||||
.Ev DISPLAY
|
||||
value set by
|
||||
.Nm
|
||||
will point to the server machine, but with a display number greater
|
||||
@ -262,15 +299,22 @@ be specified either on command line or in a configuration file.
|
||||
One possible application of TCP/IP forwarding is a secure connection to an
|
||||
electronic purse; another is going trough firewalls.
|
||||
.Pp
|
||||
.Ss Server authentication
|
||||
.Pp
|
||||
.Nm
|
||||
automatically maintains and checks a database containing RSA-based
|
||||
automatically maintains and checks a database containing
|
||||
identifications for all hosts it has ever been used with.
|
||||
The database is stored in
|
||||
.Pa \&.ssh/known_hosts
|
||||
RSA host keys are stored in
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
and
|
||||
DSA host keys are stored in
|
||||
.Pa $HOME/.ssh/known_hosts2
|
||||
in the user's home directory.
|
||||
Additionally, the file
|
||||
Additionally, the files
|
||||
.Pa /etc/ssh_known_hosts
|
||||
is automatically checked for known hosts.
|
||||
and
|
||||
.Pa /etc/ssh_known_hosts2
|
||||
are automatically checked for known hosts.
|
||||
Any new hosts are automatically added to the user's file.
|
||||
If a host's identification
|
||||
ever changes,
|
||||
@ -290,18 +334,23 @@ host key is not known or has changed.
|
||||
Disables forwarding of the authentication agent connection.
|
||||
This may also be specified on a per-host basis in the configuration file.
|
||||
.It Fl c Ar blowfish|3des
|
||||
Selects the cipher to use for encrypting the session.
|
||||
Selects the cipher to use for encrypting the session.
|
||||
.Ar 3des
|
||||
is used by default.
|
||||
It is believed to be secure.
|
||||
It is believed to be secure.
|
||||
.Ar 3des
|
||||
(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
|
||||
It is presumably more secure than the
|
||||
.Ar des
|
||||
cipher which is no longer supported in ssh.
|
||||
cipher which is no longer supported in
|
||||
.Nm ssh .
|
||||
.Ar blowfish
|
||||
is a fast block cipher, it appears very secure and is much faster than
|
||||
.Ar 3des .
|
||||
.It Fl c Ar "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
|
||||
Additionally, for protocol version 2 a comma-separated list of ciphers can
|
||||
be specified in order of preference. Protocol version 2 supports
|
||||
3DES, Blowfish and CAST128 in CBC mode and Arcfour.
|
||||
.It Fl e Ar ch|^ch|none
|
||||
Sets the escape character for sessions with a pty (default:
|
||||
.Ql ~ ) .
|
||||
@ -322,7 +371,7 @@ This is useful if
|
||||
.Nm
|
||||
is going to ask for passwords or passphrases, but the user
|
||||
wants it in the background.
|
||||
This implies
|
||||
This implies
|
||||
.Fl n .
|
||||
The recommended way to start X11 programs at a remote site is with
|
||||
something like
|
||||
@ -330,10 +379,10 @@ something like
|
||||
.It Fl g
|
||||
Allows remote hosts to connect to local forwarded ports.
|
||||
.It Fl i Ar identity_file
|
||||
Selects the file from which the identity (private key) for
|
||||
Selects the file from which the identity (private key) for
|
||||
RSA authentication is read.
|
||||
Default is
|
||||
.Pa \&.ssh/identity
|
||||
Default is
|
||||
.Pa $HOME/.ssh/identity
|
||||
in the user's home directory.
|
||||
Identity files may also be specified on
|
||||
a per-host basis in the configuration file.
|
||||
@ -455,6 +504,10 @@ from the local machine.
|
||||
Port forwardings can also be specified in the configuration file.
|
||||
Privileged ports can be forwarded only when
|
||||
logging in as root on the remote machine.
|
||||
.It Fl 2
|
||||
Forces
|
||||
.Nm
|
||||
to try protocol version 2 only.
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
@ -548,6 +601,12 @@ and
|
||||
are supported.
|
||||
The default is
|
||||
.Dq 3des .
|
||||
.It Cm Ciphers
|
||||
Specifies the ciphers allowed for protocol version 2
|
||||
in order of preference.
|
||||
Multiple ciphers must be comma-separated.
|
||||
The default is
|
||||
.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc .
|
||||
.It Cm Compression
|
||||
Specifies whether to use compression.
|
||||
The argument must be
|
||||
@ -565,6 +624,15 @@ Specifies the number of tries (one per second) to make before falling
|
||||
back to rsh or exiting.
|
||||
The argument must be an integer.
|
||||
This may be useful in scripts if the connection sometimes fails.
|
||||
.It Cm DSAAuthentication
|
||||
Specifies whether to try DSA authentication.
|
||||
The argument to this keyword must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
DSA authentication will only be
|
||||
attempted if a DSA identity file exists.
|
||||
Note that this option applies to protocol version 2 only.
|
||||
.It Cm EscapeChar
|
||||
Sets the escape character (default:
|
||||
.Ql ~ ) .
|
||||
@ -577,12 +645,12 @@ followed by a letter, or
|
||||
to disable the escape
|
||||
character entirely (making the connection transparent for binary
|
||||
data).
|
||||
.It Cm FallBackToRsh
|
||||
.It Cm FallBackToRsh
|
||||
Specifies that if connecting via
|
||||
.Nm
|
||||
fails due to a connection refused error (there is no
|
||||
.Xr sshd 8
|
||||
listening on the remote host),
|
||||
listening on the remote host),
|
||||
.Xr rsh 1
|
||||
should automatically be used instead (after a suitable warning about
|
||||
the session being unencrypted).
|
||||
@ -599,10 +667,10 @@ or
|
||||
.Dq no .
|
||||
.It Cm ForwardX11
|
||||
Specifies whether X11 connections will be automatically redirected
|
||||
over the secure channel and
|
||||
over the secure channel and
|
||||
.Ev DISPLAY
|
||||
set.
|
||||
The argument must be
|
||||
The argument must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
@ -618,7 +686,7 @@ or
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm GlobalKnownHostsFile
|
||||
Specifies a file to use instead of
|
||||
Specifies a file to use instead of
|
||||
.Pa /etc/ssh_known_hosts .
|
||||
.It Cm HostName
|
||||
Specifies the real host name to log into.
|
||||
@ -630,7 +698,7 @@ specifications).
|
||||
.It Cm IdentityFile
|
||||
Specifies the file from which the user's RSA authentication identity
|
||||
is read (default
|
||||
.Pa .ssh/identity
|
||||
.Pa $HOME/.ssh/identity
|
||||
in the user's home directory).
|
||||
Additionally, any identities represented by the authentication agent
|
||||
will be used for authentication.
|
||||
@ -639,6 +707,16 @@ syntax to refer to a user's home directory.
|
||||
It is possible to have
|
||||
multiple identity files specified in configuration files; all these
|
||||
identities will be tried in sequence.
|
||||
.It Cm IdentityFile2
|
||||
Specifies the file from which the user's DSA authentication identity
|
||||
is read (default
|
||||
.Pa $HOME/.ssh/id_dsa
|
||||
in the user's home directory).
|
||||
The file name may use the tilde
|
||||
syntax to refer to a user's home directory.
|
||||
It is possible to have
|
||||
multiple identity files specified in configuration files; all these
|
||||
identities will be tried in sequence.
|
||||
.It Cm KeepAlive
|
||||
Specifies whether the system should send keepalive messages to the
|
||||
other side.
|
||||
@ -694,9 +772,25 @@ The argument to this keyword must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
Note that this option applies to both protocol version 1 and 2.
|
||||
.It Cm Port
|
||||
Specifies the port number to connect on the remote host.
|
||||
Default is 22.
|
||||
.It Cm Protocol
|
||||
Specifies the protocol versions
|
||||
.Nm
|
||||
should support in order of preference.
|
||||
The possible values are
|
||||
.Dq 1
|
||||
and
|
||||
.Dq 2 .
|
||||
Multiple versions must be comma-separated.
|
||||
The default is
|
||||
.Dq 1,2 .
|
||||
This means that
|
||||
.Nm
|
||||
tries version 1 and falls back to version 2
|
||||
if version 1 is not available.
|
||||
.It Cm ProxyCommand
|
||||
Specifies the command to use to connect to the server.
|
||||
The command
|
||||
@ -761,6 +855,7 @@ or
|
||||
RSA authentication will only be
|
||||
attempted if the identity file exists, or an authentication agent is
|
||||
running.
|
||||
Note that this option applies to protocol version 1 only.
|
||||
.It Cm SkeyAuthentication
|
||||
Specifies whether to use
|
||||
.Xr skey 1
|
||||
@ -773,14 +868,18 @@ The default is
|
||||
.Dq no .
|
||||
.It Cm StrictHostKeyChecking
|
||||
If this flag is set to
|
||||
.Dq yes ,
|
||||
.Dq yes ,
|
||||
.Nm
|
||||
ssh will never automatically add host keys to the
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
file, and refuses to connect hosts whose host key has changed.
|
||||
and
|
||||
.Pa $HOME/.ssh/known_hosts2
|
||||
files, and refuses to connect hosts whose host key has changed.
|
||||
This provides maximum protection against trojan horse attacks.
|
||||
However, it can be somewhat annoying if you don't have good
|
||||
.Pa /etc/ssh_known_hosts
|
||||
and
|
||||
.Pa /etc/ssh_known_hosts2
|
||||
files installed and frequently
|
||||
connect new hosts.
|
||||
Basically this option forces the user to manually
|
||||
@ -839,7 +938,7 @@ will normally set the following environment variables:
|
||||
The
|
||||
.Ev DISPLAY
|
||||
variable indicates the location of the X11 server.
|
||||
It is automatically set by
|
||||
It is automatically set by
|
||||
.Nm
|
||||
to point to a value of the form
|
||||
.Dq hostname:n
|
||||
@ -885,10 +984,10 @@ on to new connections).
|
||||
Set to the name of the user logging in.
|
||||
.El
|
||||
.Pp
|
||||
Additionally,
|
||||
Additionally,
|
||||
.Nm
|
||||
reads
|
||||
.Pa $HOME/.ssh/environment ,
|
||||
reads
|
||||
.Pa $HOME/.ssh/environment ,
|
||||
and adds lines of the format
|
||||
.Dq VARNAME=value
|
||||
to the environment.
|
||||
@ -900,28 +999,36 @@ in
|
||||
.Pa /etc/ssh_known_hosts ) .
|
||||
See
|
||||
.Xr sshd 8 .
|
||||
.It Pa $HOME/.ssh/identity
|
||||
Contains the RSA authentication identity of the user.
|
||||
This file
|
||||
contains sensitive data and should be readable by the user but not
|
||||
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa
|
||||
Contains the RSA and the DSA authentication identity of the user.
|
||||
These files
|
||||
contain sensitive data and should be readable by the user but not
|
||||
accessible by others (read/write/execute).
|
||||
Note that
|
||||
.Nm
|
||||
ignores this file if it is accessible by others.
|
||||
ignores a private key file if it is accessible by others.
|
||||
It is possible to specify a passphrase when
|
||||
generating the key; the passphrase will be used to encrypt the
|
||||
sensitive part of this file using 3DES.
|
||||
.It Pa $HOME/.ssh/identity.pub
|
||||
.It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub
|
||||
Contains the public key for authentication (public part of the
|
||||
identity file in human-readable form).
|
||||
The contents of this file should be added to
|
||||
The contents of the
|
||||
.Pa $HOME/.ssh/identity.pub
|
||||
file should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
on all machines
|
||||
where you wish to log in using RSA authentication.
|
||||
This file is not
|
||||
The contents of the
|
||||
.Pa $HOME/.ssh/id_dsa.pub
|
||||
file should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
on all machines
|
||||
where you wish to log in using DSA authentication.
|
||||
These files are not
|
||||
sensitive and can (but need not) be readable by anyone.
|
||||
This file is
|
||||
never used automatically and is not necessary; it is only provided for
|
||||
These files are
|
||||
never used automatically and are not necessary; they is only provided for
|
||||
the convenience of the user.
|
||||
.It Pa $HOME/.ssh/config
|
||||
This is the per-user configuration file.
|
||||
@ -943,9 +1050,17 @@ modulus, public exponent, modulus, and comment fields, separated by
|
||||
spaces).
|
||||
This file is not highly sensitive, but the recommended
|
||||
permissions are read/write for the user, and not accessible by others.
|
||||
.It Pa /etc/ssh_known_hosts
|
||||
.It Pa $HOME/.ssh/authorized_keys2
|
||||
Lists the DSA keys that can be used for logging in as this user.
|
||||
This file is not highly sensitive, but the recommended
|
||||
permissions are read/write for the user, and not accessible by others.
|
||||
.It Pa /etc/ssh_known_hosts, /etc/ssh_known_hosts2
|
||||
Systemwide list of known host keys.
|
||||
This file should be prepared by the
|
||||
.Pa /etc/ssh_known_hosts
|
||||
contains RSA and
|
||||
.Pa /etc/ssh_known_hosts2
|
||||
contains DSA keys.
|
||||
These files should be prepared by the
|
||||
system administrator to contain the public host keys of all machines in the
|
||||
organization.
|
||||
This file should be world-readable.
|
||||
@ -1004,7 +1119,7 @@ you can store it in
|
||||
.Pa $HOME/.ssh/known_hosts .
|
||||
The easiest way to do this is to
|
||||
connect back to the client from the server machine using ssh; this
|
||||
will automatically add the host key inxi
|
||||
will automatically add the host key to
|
||||
.Pa $HOME/.ssh/known_hosts .
|
||||
.It Pa $HOME/.shosts
|
||||
This file is used exactly the same way as
|
||||
@ -1031,7 +1146,7 @@ Additionally, successful RSA host authentication is normally
|
||||
required.
|
||||
This file should only be writable by root.
|
||||
.It Pa /etc/shosts.equiv
|
||||
This file is processed exactly as
|
||||
This file is processed exactly as
|
||||
.Pa /etc/hosts.equiv .
|
||||
This file may be useful to permit logins using
|
||||
.Nm
|
||||
@ -1048,7 +1163,7 @@ Commands in this file are executed by
|
||||
.Nm
|
||||
when the user logs in just before the user's shell (or command) is
|
||||
started.
|
||||
See the
|
||||
See the
|
||||
.Xr sshd 8
|
||||
manual page for more information.
|
||||
.It Pa $HOME/.ssh/environment
|
||||
@ -1065,6 +1180,7 @@ but with bugs removed and newer features re-added.
|
||||
Rapidly after the
|
||||
1.2.12 release, newer versions of the original ssh bore successively
|
||||
more restrictive licenses, and thus demand for a free version was born.
|
||||
.Pp
|
||||
This version of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
@ -1074,10 +1190,10 @@ directly removed from the source code; any licensed or patented components
|
||||
are chosen from
|
||||
external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5, making it compatible with
|
||||
all other ssh protocol 1 clients and servers.
|
||||
has been updated to support SSH protocol 1.5 and 2, making it compatible with
|
||||
all other SSH clients and servers.
|
||||
.It
|
||||
contains added support for
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
@ -1091,6 +1207,8 @@ are required for proper operation.
|
||||
.Pp
|
||||
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
|
||||
Niels Provos, Theo de Raadt, and Dug Song.
|
||||
.Pp
|
||||
The support for SSH protocol 2 was written by Markus Friedl.
|
||||
.Sh SEE ALSO
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
|
@ -11,7 +11,11 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$Id: ssh.c,v 1.43 2000/03/23 21:52:02 markus Exp $");
|
||||
RCSID("$Id: ssh.c,v 1.51 2000/05/08 17:12:15 markus Exp $");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
@ -21,6 +25,14 @@ RCSID("$Id: ssh.c,v 1.43 2000/03/23 21:52:02 markus Exp $");
|
||||
#include "readconf.h"
|
||||
#include "uidswap.h"
|
||||
|
||||
#include "ssh2.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "key.h"
|
||||
#include "authfile.h"
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
|
||||
Default value is AF_UNSPEC means both IPv4 and IPv6. */
|
||||
int IPv4or6 = AF_UNSPEC;
|
||||
@ -28,8 +40,13 @@ int IPv4or6 = AF_UNSPEC;
|
||||
/* Flag indicating whether debug mode is on. This can be set on the command line. */
|
||||
int debug_flag = 0;
|
||||
|
||||
/* Flag indicating whether a tty should be allocated */
|
||||
int tty_flag = 0;
|
||||
|
||||
/* don't exec a shell */
|
||||
int no_shell_flag = 0;
|
||||
int no_tty_flag = 0;
|
||||
|
||||
/*
|
||||
* Flag indicating that nothing should be read from stdin. This can be set
|
||||
* on the command line.
|
||||
@ -79,6 +96,9 @@ RSA *host_private_key = NULL;
|
||||
/* Original real UID. */
|
||||
uid_t original_real_uid;
|
||||
|
||||
/* command to be executed */
|
||||
Buffer command;
|
||||
|
||||
/* Prints a help message to the user. This function never returns. */
|
||||
|
||||
void
|
||||
@ -93,9 +113,9 @@ usage()
|
||||
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
|
||||
#endif /* AFS */
|
||||
fprintf(stderr, " -x Disable X11 connection forwarding.\n");
|
||||
fprintf(stderr, " -X Enable X11 connection forwarding.\n");
|
||||
fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n");
|
||||
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
|
||||
fprintf(stderr, " -T Do not allocate a tty.\n");
|
||||
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
|
||||
fprintf(stderr, " -V Display version number only.\n");
|
||||
fprintf(stderr, " -P Don't allocate a privileged port.\n");
|
||||
@ -112,9 +132,11 @@ usage()
|
||||
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0);
|
||||
fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
|
||||
fprintf(stderr, " -C Enable compression.\n");
|
||||
fprintf(stderr, " -N Do not execute a shell or command.\n");
|
||||
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
|
||||
fprintf(stderr, " -4 Use IPv4 only.\n");
|
||||
fprintf(stderr, " -6 Use IPv6 only.\n");
|
||||
fprintf(stderr, " -2 Force protocol version 2.\n");
|
||||
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -157,23 +179,22 @@ rsh_connect(char *host, char *user, Buffer * command)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ssh_session(void);
|
||||
int ssh_session2(void);
|
||||
|
||||
/*
|
||||
* Main program for the ssh client.
|
||||
*/
|
||||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
int i, opt, optind, type, exit_status, ok, authfd;
|
||||
int i, opt, optind, exit_status, ok;
|
||||
u_short fwd_port, fwd_host_port;
|
||||
char *optarg, *cp, buf[256];
|
||||
Buffer command;
|
||||
struct winsize ws;
|
||||
struct stat st;
|
||||
struct passwd *pw, pwcopy;
|
||||
int interactive = 0, dummy;
|
||||
int have_pty = 0;
|
||||
int dummy;
|
||||
uid_t original_effective_uid;
|
||||
int plen;
|
||||
|
||||
/*
|
||||
* Save the original real uid. It will be needed later (uid-swapping
|
||||
@ -229,8 +250,8 @@ main(int ac, char **av)
|
||||
if (host)
|
||||
break;
|
||||
if ((cp = strchr(av[optind], '@'))) {
|
||||
if(cp == av[optind])
|
||||
usage();
|
||||
if(cp == av[optind])
|
||||
usage();
|
||||
options.user = av[optind];
|
||||
*cp = '\0';
|
||||
host = ++cp;
|
||||
@ -254,39 +275,34 @@ main(int ac, char **av)
|
||||
optarg = NULL;
|
||||
}
|
||||
switch (opt) {
|
||||
case '2':
|
||||
options.protocol = SSH_PROTO_2;
|
||||
break;
|
||||
case '4':
|
||||
IPv4or6 = AF_INET;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
IPv4or6 = AF_INET6;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
stdin_null_flag = 1;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
fork_after_authentication_flag = 1;
|
||||
stdin_null_flag = 1;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
options.forward_x11 = 0;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
options.forward_x11 = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
options.gateway_ports = 1;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
options.use_privileged_port = 0;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
options.forward_agent = 0;
|
||||
break;
|
||||
@ -308,26 +324,24 @@ main(int ac, char **av)
|
||||
options.identity_files[options.num_identity_files++] =
|
||||
xstrdup(optarg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tty_flag = 1;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
|
||||
SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
|
||||
fprintf(stderr, "Compiled with SSL.\n");
|
||||
fprintf(stderr, "SSH Version %s, protocol versions %d.%d/%d.%d.\n",
|
||||
SSH_VERSION,
|
||||
PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
|
||||
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
|
||||
fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay());
|
||||
if (opt == 'V')
|
||||
exit(0);
|
||||
debug_flag = 1;
|
||||
options.log_level = SYSLOG_LEVEL_DEBUG;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
options.log_level = SYSLOG_LEVEL_QUIET;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (optarg[0] == '^' && optarg[2] == 0 &&
|
||||
(unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128)
|
||||
@ -341,23 +355,26 @@ main(int ac, char **av)
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
exit(1);
|
||||
if (ciphers_valid(optarg)) {
|
||||
/* SSH2 only */
|
||||
options.ciphers = xstrdup(optarg);
|
||||
options.cipher = SSH_CIPHER_ILLEGAL;
|
||||
} else {
|
||||
/* SSH1 only */
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
options.port = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
options.user = optarg;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
|
||||
&fwd_host_port) != 3 &&
|
||||
@ -369,7 +386,6 @@ main(int ac, char **av)
|
||||
}
|
||||
add_remote_forward(&options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
|
||||
&fwd_host_port) != 3 &&
|
||||
@ -381,18 +397,22 @@ main(int ac, char **av)
|
||||
}
|
||||
add_local_forward(&options, fwd_port, buf, fwd_host_port);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
options.compression = 1;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
no_shell_flag = 1;
|
||||
no_tty_flag = 1;
|
||||
break;
|
||||
case 'T':
|
||||
no_tty_flag = 1;
|
||||
break;
|
||||
case 'o':
|
||||
dummy = 1;
|
||||
if (process_config_line(&options, host ? host : "", optarg,
|
||||
"command-line", 0, &dummy) != 0)
|
||||
exit(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
@ -402,15 +422,8 @@ main(int ac, char **av)
|
||||
if (!host)
|
||||
usage();
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
extern char *__progname;
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
/* Initialize the command to execute on remote host. */
|
||||
buffer_init(&command);
|
||||
|
||||
@ -446,6 +459,10 @@ main(int ac, char **av)
|
||||
fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
|
||||
tty_flag = 0;
|
||||
}
|
||||
/* force */
|
||||
if (no_tty_flag)
|
||||
tty_flag = 0;
|
||||
|
||||
/* Get user data. */
|
||||
pw = getpwuid(original_real_uid);
|
||||
if (!pw) {
|
||||
@ -479,6 +496,20 @@ main(int ac, char **av)
|
||||
/* reinit */
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
||||
|
||||
/* check if RSA support exists */
|
||||
if ((options.protocol & SSH_PROTO_1) &&
|
||||
rsa_alive() == 0) {
|
||||
log("%s: no RSA support in libssl and libcrypto. See ssl(8).",
|
||||
__progname);
|
||||
log("Disabling protocol version 1");
|
||||
options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
|
||||
}
|
||||
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
|
||||
fprintf(stderr, "%s: No protocol version available.\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options.user == NULL)
|
||||
options.user = xstrdup(pw->pw_name);
|
||||
|
||||
@ -545,9 +576,12 @@ main(int ac, char **av)
|
||||
* authentication. This must be done before releasing extra
|
||||
* privileges, because the file is only readable by root.
|
||||
*/
|
||||
if (ok) {
|
||||
if (ok && (options.protocol & SSH_PROTO_1)) {
|
||||
Key k;
|
||||
host_private_key = RSA_new();
|
||||
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
|
||||
k.type = KEY_RSA;
|
||||
k.rsa = host_private_key;
|
||||
if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
|
||||
host_private_key_loaded = 1;
|
||||
}
|
||||
/*
|
||||
@ -593,15 +627,22 @@ main(int ac, char **av)
|
||||
exit(1);
|
||||
}
|
||||
/* Expand ~ in options.identity_files. */
|
||||
/* XXX mem-leaks */
|
||||
for (i = 0; i < options.num_identity_files; i++)
|
||||
options.identity_files[i] =
|
||||
tilde_expand_filename(options.identity_files[i], original_real_uid);
|
||||
|
||||
for (i = 0; i < options.num_identity_files2; i++)
|
||||
options.identity_files2[i] =
|
||||
tilde_expand_filename(options.identity_files2[i], original_real_uid);
|
||||
/* Expand ~ in known host file names. */
|
||||
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
|
||||
original_real_uid);
|
||||
original_real_uid);
|
||||
options.user_hostfile = tilde_expand_filename(options.user_hostfile,
|
||||
original_real_uid);
|
||||
original_real_uid);
|
||||
options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2,
|
||||
original_real_uid);
|
||||
options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2,
|
||||
original_real_uid);
|
||||
|
||||
/* Log into the remote system. This never returns if the login fails. */
|
||||
ssh_login(host_private_key_loaded, host_private_key,
|
||||
@ -611,6 +652,62 @@ main(int ac, char **av)
|
||||
if (host_private_key_loaded)
|
||||
RSA_free(host_private_key); /* Destroys contents safely */
|
||||
|
||||
exit_status = compat20 ? ssh_session2() : ssh_session();
|
||||
packet_close();
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
void
|
||||
x11_get_proto(char *proto, int proto_len, char *data, int data_len)
|
||||
{
|
||||
char line[512];
|
||||
FILE *f;
|
||||
int got_data = 0, i;
|
||||
|
||||
#ifdef XAUTH_PATH
|
||||
/* Try to get Xauthority information for the display. */
|
||||
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
|
||||
XAUTH_PATH, getenv("DISPLAY"));
|
||||
f = popen(line, "r");
|
||||
if (f && fgets(line, sizeof(line), f) &&
|
||||
sscanf(line, "%*s %s %s", proto, data) == 2)
|
||||
got_data = 1;
|
||||
if (f)
|
||||
pclose(f);
|
||||
#endif /* XAUTH_PATH */
|
||||
/*
|
||||
* If we didn't get authentication data, just make up some
|
||||
* data. The forwarding code will check the validity of the
|
||||
* response anyway, and substitute this data. The X11
|
||||
* server, however, will ignore this fake data and use
|
||||
* whatever authentication mechanisms it was using otherwise
|
||||
* for the local connection.
|
||||
*/
|
||||
if (!got_data) {
|
||||
u_int32_t rand = 0;
|
||||
|
||||
strlcpy(proto, "MIT-MAGIC-COOKIE-1", proto_len);
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
snprintf(data + 2 * i, data_len - 2 * i, "%02x", rand & 0xff);
|
||||
rand >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ssh_session(void)
|
||||
{
|
||||
int type;
|
||||
int i;
|
||||
int plen;
|
||||
int interactive = 0;
|
||||
int have_tty = 0;
|
||||
struct winsize ws;
|
||||
int authfd;
|
||||
char *cp;
|
||||
|
||||
/* Enable compression if requested. */
|
||||
if (options.compression) {
|
||||
debug("Requesting compression at level %d.", options.compression_level);
|
||||
@ -664,7 +761,7 @@ main(int ac, char **av)
|
||||
type = packet_read(&plen);
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
interactive = 1;
|
||||
have_pty = 1;
|
||||
have_tty = 1;
|
||||
} else if (type == SSH_SMSG_FAILURE)
|
||||
log("Warning: Remote host failed or refused to allocate a pseudo tty.");
|
||||
else
|
||||
@ -672,56 +769,22 @@ main(int ac, char **av)
|
||||
}
|
||||
/* Request X11 forwarding if enabled and DISPLAY is set. */
|
||||
if (options.forward_x11 && getenv("DISPLAY") != NULL) {
|
||||
char line[512], proto[512], data[512];
|
||||
FILE *f;
|
||||
int forwarded = 0, got_data = 0, i;
|
||||
|
||||
#ifdef XAUTH_PATH
|
||||
/* Try to get Xauthority information for the display. */
|
||||
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null",
|
||||
XAUTH_PATH, getenv("DISPLAY"));
|
||||
f = popen(line, "r");
|
||||
if (f && fgets(line, sizeof(line), f) &&
|
||||
sscanf(line, "%*s %s %s", proto, data) == 2)
|
||||
got_data = 1;
|
||||
if (f)
|
||||
pclose(f);
|
||||
#endif /* XAUTH_PATH */
|
||||
/*
|
||||
* If we didn't get authentication data, just make up some
|
||||
* data. The forwarding code will check the validity of the
|
||||
* response anyway, and substitute this data. The X11
|
||||
* server, however, will ignore this fake data and use
|
||||
* whatever authentication mechanisms it was using otherwise
|
||||
* for the local connection.
|
||||
*/
|
||||
if (!got_data) {
|
||||
u_int32_t rand = 0;
|
||||
|
||||
strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i % 4 == 0)
|
||||
rand = arc4random();
|
||||
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
|
||||
rand >>= 8;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Got local authentication reasonable information. Request
|
||||
* forwarding with authentication spoofing.
|
||||
*/
|
||||
char proto[512], data[512];
|
||||
/* Get reasonable local authentication information. */
|
||||
x11_get_proto(proto, sizeof proto, data, sizeof data);
|
||||
/* Request forwarding with authentication spoofing. */
|
||||
debug("Requesting X11 forwarding with authentication spoofing.");
|
||||
x11_request_forwarding_with_spoofing(proto, data);
|
||||
x11_request_forwarding_with_spoofing(0, proto, data);
|
||||
|
||||
/* Read response from the server. */
|
||||
type = packet_read(&plen);
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
forwarded = 1;
|
||||
interactive = 1;
|
||||
} else if (type == SSH_SMSG_FAILURE)
|
||||
} else if (type == SSH_SMSG_FAILURE) {
|
||||
log("Warning: Remote host denied X11 forwarding.");
|
||||
else
|
||||
} else {
|
||||
packet_disconnect("Protocol error waiting for X11 forwarding");
|
||||
}
|
||||
}
|
||||
/* Tell the packet module whether this is an interactive session. */
|
||||
packet_set_interactive(interactive, options.keepalives);
|
||||
@ -751,7 +814,7 @@ main(int ac, char **av)
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port);
|
||||
channel_request_local_forwarding(options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port,
|
||||
options.gateway_ports);
|
||||
}
|
||||
@ -764,11 +827,11 @@ main(int ac, char **av)
|
||||
options.remote_forwards[i].host_port);
|
||||
channel_request_remote_forwarding(options.remote_forwards[i].port,
|
||||
options.remote_forwards[i].host,
|
||||
options.remote_forwards[i].host_port);
|
||||
options.remote_forwards[i].host_port);
|
||||
}
|
||||
|
||||
/* If requested, let ssh continue in the background. */
|
||||
if (fork_after_authentication_flag)
|
||||
if (fork_after_authentication_flag)
|
||||
if (daemon(1, 1) < 0)
|
||||
fatal("daemon() failed: %.200s", strerror(errno));
|
||||
|
||||
@ -793,11 +856,114 @@ main(int ac, char **av)
|
||||
}
|
||||
|
||||
/* Enter the interactive session. */
|
||||
exit_status = client_loop(have_pty, tty_flag ? options.escape_char : -1);
|
||||
|
||||
/* Close the connection to the remote host. */
|
||||
packet_close();
|
||||
|
||||
/* Exit with the status returned by the program on the remote side. */
|
||||
exit(exit_status);
|
||||
return client_loop(have_tty, tty_flag ? options.escape_char : -1);
|
||||
}
|
||||
|
||||
void
|
||||
init_local_fwd(void)
|
||||
{
|
||||
int i;
|
||||
/* Initiate local TCP/IP port forwardings. */
|
||||
for (i = 0; i < options.num_local_forwards; i++) {
|
||||
debug("Connections to local port %d forwarded to remote address %.200s:%d",
|
||||
options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port);
|
||||
channel_request_local_forwarding(options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port,
|
||||
options.gateway_ports);
|
||||
}
|
||||
}
|
||||
|
||||
extern void client_set_session_ident(int id);
|
||||
|
||||
void
|
||||
client_init(int id, void *arg)
|
||||
{
|
||||
int len;
|
||||
debug("client_init id %d arg %d", id, (int)arg);
|
||||
|
||||
if (no_shell_flag)
|
||||
goto done;
|
||||
|
||||
if (tty_flag) {
|
||||
struct winsize ws;
|
||||
char *cp;
|
||||
cp = getenv("TERM");
|
||||
if (!cp)
|
||||
cp = "";
|
||||
/* Store window size in the packet. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
|
||||
channel_request_start(id, "pty-req", 0);
|
||||
packet_put_cstring(cp);
|
||||
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_put_cstring(""); /* XXX: encode terminal modes */
|
||||
packet_send();
|
||||
/* XXX wait for reply */
|
||||
}
|
||||
if (options.forward_x11 &&
|
||||
getenv("DISPLAY") != NULL) {
|
||||
char proto[512], data[512];
|
||||
/* Get reasonable local authentication information. */
|
||||
x11_get_proto(proto, sizeof proto, data, sizeof data);
|
||||
/* Request forwarding with authentication spoofing. */
|
||||
debug("Requesting X11 forwarding with authentication spoofing.");
|
||||
x11_request_forwarding_with_spoofing(id, proto, data);
|
||||
/* XXX wait for reply */
|
||||
}
|
||||
|
||||
len = buffer_len(&command);
|
||||
if (len > 0) {
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
debug("Sending command: %.*s", len, buffer_ptr(&command));
|
||||
channel_request_start(id, "exec", 0);
|
||||
packet_put_string(buffer_ptr(&command), len);
|
||||
packet_send();
|
||||
} else {
|
||||
channel_request(id, "shell", 0);
|
||||
}
|
||||
/* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
|
||||
done:
|
||||
/* register different callback, etc. XXX */
|
||||
client_set_session_ident(id);
|
||||
}
|
||||
|
||||
int
|
||||
ssh_session2(void)
|
||||
{
|
||||
int window, packetmax, id;
|
||||
int in = dup(STDIN_FILENO);
|
||||
int out = dup(STDOUT_FILENO);
|
||||
int err = dup(STDERR_FILENO);
|
||||
|
||||
if (in < 0 || out < 0 || err < 0)
|
||||
fatal("dump in/out/err failed");
|
||||
|
||||
/* should be pre-session */
|
||||
init_local_fwd();
|
||||
|
||||
window = 32*1024;
|
||||
if (tty_flag) {
|
||||
packetmax = window/8;
|
||||
} else {
|
||||
window *= 2;
|
||||
packetmax = window/2;
|
||||
}
|
||||
|
||||
id = channel_new(
|
||||
"session", SSH_CHANNEL_OPENING, in, out, err,
|
||||
window, packetmax, CHAN_EXTENDED_WRITE, xstrdup("client-session"));
|
||||
|
||||
|
||||
channel_open(id);
|
||||
channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0);
|
||||
|
||||
return client_loop(tty_flag, tty_flag ? options.escape_char : -1);
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* ssh.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 17:09:37 1995 ylo
|
||||
*
|
||||
*
|
||||
* Generic header file for ssh.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* RCSID("$Id: ssh.h,v 1.34 2000/03/23 22:15:33 markus Exp $"); */
|
||||
/* RCSID("$Id: ssh.h,v 1.45 2000/05/08 17:12:16 markus Exp $"); */
|
||||
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
@ -22,6 +22,7 @@
|
||||
#include "cipher.h"
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* The default cipher used if IDEA is not supported by the remote host. It is
|
||||
* recommended that this be one of the mandatory ciphers (DES, 3DES), though
|
||||
* that is not required.
|
||||
@ -46,14 +47,16 @@
|
||||
/*
|
||||
* Major protocol version. Different version indicates major incompatiblity
|
||||
* that prevents communication.
|
||||
*/
|
||||
#define PROTOCOL_MAJOR 1
|
||||
|
||||
/*
|
||||
*
|
||||
* Minor protocol version. Different version indicates minor incompatibility
|
||||
* that does not prevent interoperation.
|
||||
*/
|
||||
#define PROTOCOL_MINOR 5
|
||||
#define PROTOCOL_MAJOR_1 1
|
||||
#define PROTOCOL_MINOR_1 5
|
||||
|
||||
/* We support both SSH1 and SSH2 */
|
||||
#define PROTOCOL_MAJOR_2 2
|
||||
#define PROTOCOL_MINOR_2 0
|
||||
|
||||
/*
|
||||
* Name for the service. The port named by this service overrides the
|
||||
@ -69,6 +72,7 @@
|
||||
* world-readable.
|
||||
*/
|
||||
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
|
||||
#define SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
|
||||
|
||||
/*
|
||||
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
|
||||
@ -77,6 +81,7 @@
|
||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
||||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||
#define HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
|
||||
|
||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||
|
||||
@ -98,12 +103,14 @@
|
||||
* contain anything particularly secret.
|
||||
*/
|
||||
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
||||
#define SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
|
||||
|
||||
/*
|
||||
* Name of the default file containing client-side authentication key. This
|
||||
* file should only be readable by the user him/herself.
|
||||
*/
|
||||
#define SSH_CLIENT_IDENTITY ".ssh/identity"
|
||||
#define SSH_CLIENT_ID_DSA ".ssh/id_dsa"
|
||||
|
||||
/*
|
||||
* Configuration file in user\'s home directory. This file need not be
|
||||
@ -122,6 +129,7 @@
|
||||
* running as root.)
|
||||
*/
|
||||
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
||||
#define SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
|
||||
|
||||
/*
|
||||
* Per-user and system-wide ssh "rc" files. These files are executed with
|
||||
@ -251,7 +259,7 @@
|
||||
* information is not available. This must be called before record_login.
|
||||
* The host from which the user logged in is stored in buf.
|
||||
*/
|
||||
unsigned long
|
||||
unsigned long
|
||||
get_last_login_time(uid_t uid, const char *logname,
|
||||
char *buf, unsigned int bufsize);
|
||||
|
||||
@ -259,15 +267,15 @@ get_last_login_time(uid_t uid, const char *logname,
|
||||
* Records that the user has logged in. This does many things normally done
|
||||
* by login(1).
|
||||
*/
|
||||
void
|
||||
record_login(int pid, const char *ttyname, const char *user, uid_t uid,
|
||||
void
|
||||
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
|
||||
const char *host, struct sockaddr *addr);
|
||||
|
||||
/*
|
||||
* Records that the user has logged out. This does many thigs normally done
|
||||
* by login(1) or init.
|
||||
*/
|
||||
void record_logout(int pid, const char *ttyname);
|
||||
void record_logout(pid_t pid, const char *ttyname);
|
||||
|
||||
/*------------ definitions for sshconnect.c ----------*/
|
||||
|
||||
@ -280,7 +288,7 @@ void record_logout(int pid, const char *ttyname);
|
||||
* and zero on failure. If the connection is successful, this calls
|
||||
* packet_set_connection for the connection.
|
||||
*/
|
||||
int
|
||||
int
|
||||
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
u_short port, int connection_attempts,
|
||||
int anonymous, uid_t original_real_uid,
|
||||
@ -295,7 +303,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
* references from the packet module).
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
ssh_login(int host_key_valid, RSA * host_key, const char *host,
|
||||
struct sockaddr * hostaddr, uid_t original_real_uid);
|
||||
|
||||
@ -312,7 +320,7 @@ int auth_rhosts(struct passwd * pw, const char *client_user);
|
||||
* Tries to authenticate the user using the .rhosts file and the host using
|
||||
* its host key. Returns true if authentication succeeds.
|
||||
*/
|
||||
int
|
||||
int
|
||||
auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
|
||||
|
||||
/*
|
||||
@ -375,36 +383,6 @@ int auth_rsa_challenge_dialog(RSA *pk);
|
||||
*/
|
||||
char *read_passphrase(const char *prompt, int from_stdin);
|
||||
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase. The identification of the file (lowest 64 bits of n) will
|
||||
* precede the key to provide identification of the key without needing a
|
||||
* passphrase.
|
||||
*/
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
RSA * private_key, const char *comment);
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file (public key and comment). Returns 0
|
||||
* if an error occurred; zero if the public key was successfully read. The
|
||||
* comment of the key is returned in comment_return if it is non-NULL; the
|
||||
* caller must free the value with xfree.
|
||||
*/
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return);
|
||||
|
||||
/*
|
||||
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
* (file does not exist or is not readable, or passphrase is bad). This
|
||||
* initializes the private key. The comment of the key is returned in
|
||||
* comment_return if it is non-NULL; the caller must free the value with
|
||||
* xfree.
|
||||
*/
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
RSA * private_key, char **comment_return);
|
||||
|
||||
/*------------ Definitions for logging. -----------------------*/
|
||||
|
||||
@ -461,174 +439,7 @@ void fatal_add_cleanup(void (*proc) (void *context), void *context);
|
||||
/* Removes a cleanup function to be called at fatal(). */
|
||||
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
|
||||
|
||||
/*---------------- definitions for channels ------------------*/
|
||||
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* This is called when a packet of type CHANNEL_DATA has just been received.
|
||||
* The message type has already been consumed, but channel number and data is
|
||||
* still there.
|
||||
*/
|
||||
void channel_input_data(int payload_len);
|
||||
|
||||
/* Returns true if no channel has too much buffered data. */
|
||||
int channel_not_very_much_buffered_data(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_CLOSE. */
|
||||
void channel_input_close(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */
|
||||
void channel_input_close_confirmation(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
|
||||
void channel_input_open_confirmation(void);
|
||||
|
||||
/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
|
||||
void channel_input_open_failure(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);
|
||||
|
||||
/*
|
||||
* This is called after receiving PORT_OPEN message. This attempts to
|
||||
* connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
|
||||
* or CHANNEL_OPEN_FAILURE.
|
||||
*/
|
||||
void channel_input_port_open(int payload_len);
|
||||
|
||||
/*
|
||||
* Creates a port for X11 connections, and starts listening for it. Returns
|
||||
* the display name, or NULL if an error was encountered.
|
||||
*/
|
||||
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 payload_len);
|
||||
|
||||
/*
|
||||
* 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(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(void);
|
||||
|
||||
/*
|
||||
* Returns true if the given string matches the pattern (which may contain ?
|
||||
* and * as wildcards), and zero if it does not match.
|
||||
*/
|
||||
int match_pattern(const char *s, const char *pattern);
|
||||
/* ---- misc */
|
||||
|
||||
/*
|
||||
* Expands tildes in the file name. Returns data allocated by xmalloc.
|
||||
@ -643,7 +454,8 @@ char *tilde_expand_filename(const char *filename, uid_t my_uid);
|
||||
* (of the child program), and reads from stdout and stderr (of the child
|
||||
* program).
|
||||
*/
|
||||
void server_loop(int pid, int fdin, int fdout, int fderr);
|
||||
void server_loop(pid_t pid, int fdin, int fdout, int fderr);
|
||||
void server_loop2(void);
|
||||
|
||||
/* Client side main loop for the interactive session. */
|
||||
int client_loop(int have_pty, int escape_char);
|
||||
@ -678,7 +490,7 @@ int auth_krb4_password(struct passwd * pw, const char *password);
|
||||
int auth_kerberos_tgt(struct passwd * pw, const char *string);
|
||||
int auth_afs_token(struct passwd * pw, const char *token_string);
|
||||
|
||||
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf);
|
||||
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf, size_t buflen);
|
||||
int radix_to_creds(const char *buf, CREDENTIALS * creds);
|
||||
#endif /* AFS */
|
||||
|
||||
|
@ -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
|
@ -26,5 +26,6 @@
|
||||
# StrictHostKeyChecking no
|
||||
# IdentityFile ~/.ssh/identity
|
||||
# Port 22
|
||||
# Protocol 2,1
|
||||
# Cipher blowfish
|
||||
# EscapeChar ~
|
||||
|
File diff suppressed because it is too large
Load Diff
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");
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
.\"
|
||||
.\" Created: Sat Apr 22 21:55:14 1995 ylo
|
||||
.\"
|
||||
.\" $Id: sshd.8,v 1.37 2000/03/24 03:04:46 brad Exp $
|
||||
.\" $Id: sshd.8,v 1.51 2000/05/08 17:42:31 hugh Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SSHD 8
|
||||
@ -27,11 +27,11 @@
|
||||
.Op Fl k Ar key_gen_time
|
||||
.Op Fl p Ar port
|
||||
.Op Fl V Ar client_protocol_id
|
||||
.Sh DESCRIPTION
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
(Secure Shell Daemon) is the daemon program for
|
||||
(Secure Shell Daemon) is the daemon program for
|
||||
.Xr ssh 1 .
|
||||
Together these programs replace rlogin and rsh programs, and
|
||||
Together these programs replace rlogin and rsh, and
|
||||
provide secure encrypted communications between two untrusted hosts
|
||||
over an insecure network.
|
||||
The programs are intended to be as easy to
|
||||
@ -39,16 +39,21 @@ install and use as possible.
|
||||
.Pp
|
||||
.Nm
|
||||
is the daemon that listens for connections from clients.
|
||||
It is normally started at boot from
|
||||
It is normally started at boot from
|
||||
.Pa /etc/rc .
|
||||
It forks a new
|
||||
daemon for each incoming connection.
|
||||
The forked daemons handle
|
||||
key exchange, encryption, authentication, command execution,
|
||||
and data exchange.
|
||||
.Pp
|
||||
This implementation of
|
||||
.Nm
|
||||
supports both SSH protocol version 1 and 2 simultaneously.
|
||||
.Nm
|
||||
works as follows.
|
||||
.Pp
|
||||
.Ss SSH protocol version 1
|
||||
.Pp
|
||||
Each host has a host-specific RSA key
|
||||
(normally 1024 bits) used to identify the host.
|
||||
Additionally, when
|
||||
@ -56,20 +61,20 @@ the daemon starts, it generates a server RSA key (normally 768 bits).
|
||||
This key is normally regenerated every hour if it has been used, and
|
||||
is never stored on disk.
|
||||
.Pp
|
||||
Whenever a client connects the daemon, the daemon sends its host
|
||||
and server public keys to the client.
|
||||
Whenever a client connects the daemon responds with its public
|
||||
host and server keys.
|
||||
The client compares the
|
||||
host key against its own database to verify that it has not changed.
|
||||
RSA host key against its own database to verify that it has not changed.
|
||||
The client then generates a 256 bit random number.
|
||||
It encrypts this
|
||||
random number using both the host key and the server key, and sends
|
||||
the encrypted number to the server.
|
||||
Both sides then start to use this
|
||||
Both sides then use this
|
||||
random number as a session key which is used to encrypt all further
|
||||
communications in the session.
|
||||
The rest of the session is encrypted
|
||||
using a conventional cipher, currently Blowfish and 3DES, with 3DES
|
||||
being is used by default.
|
||||
using a conventional cipher, currently Blowfish or 3DES, with 3DES
|
||||
being used by default.
|
||||
The client selects the encryption algorithm
|
||||
to use from those offered by the server.
|
||||
.Pp
|
||||
@ -95,7 +100,29 @@ are disabled (thus completely disabling
|
||||
.Xr rlogin 1
|
||||
and
|
||||
.Xr rsh 1
|
||||
into that machine).
|
||||
into the machine).
|
||||
.Pp
|
||||
.Ss SSH protocol version 2
|
||||
.Pp
|
||||
Version 2 works similar:
|
||||
Each host has a host-specific DSA key used to identify the host.
|
||||
However, when the daemon starts, it does not generate a server key.
|
||||
Forward security is provided through a Diffie-Hellman key agreement.
|
||||
This key agreement results in a shared session key.
|
||||
The rest of the session is encrypted
|
||||
using a symmetric cipher, currently
|
||||
Blowfish, 3DES or CAST128 in CBC mode or Arcfour.
|
||||
The client selects the encryption algorithm
|
||||
to use from those offered by the server.
|
||||
Additionally, session integrity is provided
|
||||
through a cryptographic message authentication code
|
||||
(hmac-sha1 or hmac-md5).
|
||||
.Pp
|
||||
Protocol version 2 provides a public key based
|
||||
user authentication method (DSAAuthentication)
|
||||
and conventional password authentication.
|
||||
.Pp
|
||||
.Ss Command execution and data forwarding
|
||||
.Pp
|
||||
If the client successfully authenticates itself, a dialog for
|
||||
preparing the session is entered.
|
||||
@ -148,7 +175,7 @@ If the client fails to authenticate the user within
|
||||
this many seconds, the server disconnects and exits.
|
||||
A value of zero indicates no limit.
|
||||
.It Fl h Ar host_key_file
|
||||
Specifies the file from which the host key is read (default
|
||||
Specifies the file from which the RSA host key is read (default
|
||||
.Pa /etc/ssh_host_key ) .
|
||||
This option must be given if
|
||||
.Nm
|
||||
@ -157,7 +184,7 @@ host file is normally not readable by anyone but root).
|
||||
.It Fl i
|
||||
Specifies that
|
||||
.Nm
|
||||
is being run from inetd.
|
||||
is being run from inetd.
|
||||
.Nm
|
||||
is normally not run
|
||||
from inetd because it needs to generate the server key before it can
|
||||
@ -188,9 +215,9 @@ authentication, and termination of each connection is logged.
|
||||
Do not print an error message if RSA support is missing.
|
||||
.It Fl V Ar client_protocol_id
|
||||
SSH2 compatibility mode.
|
||||
When this options is specified
|
||||
When this option is specified
|
||||
.Nm
|
||||
assumes the client has sent the given version string
|
||||
assumes the client has sent the supplied version string
|
||||
and skips the
|
||||
Protocol Version Identification Exchange.
|
||||
.It Fl 4
|
||||
@ -204,7 +231,7 @@ to use IPv6 addresses only.
|
||||
.El
|
||||
.Sh CONFIGURATION FILE
|
||||
.Nm
|
||||
reads configuration data from
|
||||
reads configuration data from
|
||||
.Pa /etc/sshd_config
|
||||
(or the file specified with
|
||||
.Fl f
|
||||
@ -246,6 +273,11 @@ wildcards in the patterns.
|
||||
Only user names are valid, a numerical user ID isn't recognized.
|
||||
By default login is allowed regardless of the user name.
|
||||
.Pp
|
||||
.It Cm Ciphers
|
||||
Specifies the ciphers allowed for protocol version 2.
|
||||
Multiple ciphers must be comma-separated.
|
||||
The default is
|
||||
.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc .
|
||||
.It Cm CheckMail
|
||||
Specifies whether
|
||||
.Nm
|
||||
@ -275,23 +307,45 @@ and
|
||||
can be used as wildcards in the patterns.
|
||||
Only user names are valid, a numerical user ID isn't recognized.
|
||||
By default login is allowed regardless of the user name.
|
||||
.It Cm HostKey
|
||||
Specifies the file containing the private host key (default
|
||||
.Pa /etc/ssh_host_key ) .
|
||||
.It Cm DSAAuthentication
|
||||
Specifies whether DSA authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to protocol version 2 only.
|
||||
.It Cm GatewayPorts
|
||||
Specifies whether remote hosts are allowed to connect to ports
|
||||
forwarded for the client.
|
||||
The argument must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm HostDsaKey
|
||||
Specifies the file containing the private DSA host key (default
|
||||
.Pa /etc/ssh_host_dsa_key )
|
||||
used by SSH protocol 2.0.
|
||||
Note that
|
||||
.Nm
|
||||
does not start if this file is group/world-accessible.
|
||||
disables protocol 2.0 if this file is group/world-accessible.
|
||||
.It Cm HostKey
|
||||
Specifies the file containing the private RSA host key (default
|
||||
.Pa /etc/ssh_host_key )
|
||||
used by SSH protocols 1.3 and 1.5.
|
||||
Note that
|
||||
.Nm
|
||||
disables protocols 1.3 and 1.5 if this file is group/world-accessible.
|
||||
.It Cm IgnoreRhosts
|
||||
Specifies that
|
||||
.Pa .rhosts
|
||||
and
|
||||
and
|
||||
.Pa .shosts
|
||||
files will not be used in authentication.
|
||||
.Pa /etc/hosts.equiv
|
||||
and
|
||||
.Pa /etc/shosts.equiv
|
||||
.Pa /etc/shosts.equiv
|
||||
are still used.
|
||||
The default is
|
||||
The default is
|
||||
.Dq yes .
|
||||
.It Cm IgnoreUserKnownHosts
|
||||
Specifies whether
|
||||
@ -310,7 +364,7 @@ of the machines will be properly noticed.
|
||||
However, this means that
|
||||
connections will die if the route is down temporarily, and some people
|
||||
find it annoying.
|
||||
On the other hand, if keepalives are not send,
|
||||
On the other hand, if keepalives are not sent,
|
||||
sessions may hang indefinitely on the server, leaving
|
||||
.Dq ghost
|
||||
users and consuming server resources.
|
||||
@ -342,7 +396,7 @@ Default is
|
||||
.Dq yes .
|
||||
.It Cm KerberosTgtPassing
|
||||
Specifies whether a Kerberos TGT may be forwarded to the server.
|
||||
Default is
|
||||
Default is
|
||||
.Dq no ,
|
||||
as this only works when the Kerberos KDC is actually an AFS kaserver.
|
||||
.It Cm KerberosTicketCleanup
|
||||
@ -385,6 +439,7 @@ and is not recommended.
|
||||
Specifies whether password authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to both protocol version 1 and 2.
|
||||
.It Cm PermitEmptyPasswords
|
||||
When password authentication is allowed, it specifies whether the
|
||||
server allows login to accounts with empty password strings.
|
||||
@ -410,6 +465,12 @@ option has been
|
||||
specified will be allowed regardless of the value of this setting
|
||||
(which may be useful for taking remote backups even if root login is
|
||||
normally not allowed).
|
||||
.It Cm PidFile
|
||||
Specifies the file that contains the process identifier of the
|
||||
.Nm
|
||||
daemon.
|
||||
The default is
|
||||
.Pa /var/run/sshd.pid .
|
||||
.It Cm Port
|
||||
Specifies the port number that
|
||||
.Nm
|
||||
@ -419,7 +480,7 @@ Multiple options of this type are permitted.
|
||||
.It Cm PrintMotd
|
||||
Specifies whether
|
||||
.Nm
|
||||
should print
|
||||
should print
|
||||
.Pa /etc/motd
|
||||
when a user logs in interactively.
|
||||
(On some systems it is also printed by the shell,
|
||||
@ -427,6 +488,17 @@ when a user logs in interactively.
|
||||
or equivalent.)
|
||||
The default is
|
||||
.Dq yes .
|
||||
.It Cm Protocol
|
||||
Specifies the protocol versions
|
||||
.Nm
|
||||
should support.
|
||||
The possible values are
|
||||
.Dq 1
|
||||
and
|
||||
.Dq 2 .
|
||||
Multiple versions must be comma-separated.
|
||||
The default is
|
||||
.Dq 1 .
|
||||
.It Cm RandomSeed
|
||||
Obsolete.
|
||||
Random number generation uses other techniques.
|
||||
@ -449,12 +521,13 @@ The default is
|
||||
Specifies whether pure RSA authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to protocol version 1 only.
|
||||
.It Cm ServerKeyBits
|
||||
Defines the number of bits in the server key.
|
||||
The minimum value is 512, and the default is 768.
|
||||
.It Cm SkeyAuthentication
|
||||
Specifies whether
|
||||
.Xr skey 1
|
||||
.Xr skey 1
|
||||
authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
@ -504,12 +577,12 @@ does the following:
|
||||
.Bl -enum -offset indent
|
||||
.It
|
||||
If the login is on a tty, and no command has been specified,
|
||||
prints last login time and
|
||||
prints last login time and
|
||||
.Pa /etc/motd
|
||||
(unless prevented in the configuration file or by
|
||||
.Pa $HOME/.hushlogin ;
|
||||
see the
|
||||
.Sx FILES
|
||||
.Sx FILES
|
||||
section).
|
||||
.It
|
||||
If the login is on a tty, records login time.
|
||||
@ -543,10 +616,14 @@ authentication protocol and cookie in standard input.
|
||||
Runs user's shell or command.
|
||||
.El
|
||||
.Sh AUTHORIZED_KEYS FILE FORMAT
|
||||
The
|
||||
The
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
file lists the RSA keys that are
|
||||
permitted for RSA authentication.
|
||||
permitted for RSA authentication in SSH protocols 1.3 and 1.5
|
||||
Similarly, the
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
file lists the DSA keys that are
|
||||
permitted for DSA authentication in SSH protocol 2.0.
|
||||
Each line of the file contains one
|
||||
key (empty lines and lines starting with a
|
||||
.Ql #
|
||||
@ -602,8 +679,8 @@ A quote may be included in the command by quoting it with a backslash.
|
||||
This option might be useful
|
||||
to restrict certain RSA keys to perform just a specific operation.
|
||||
An example might be a key that permits remote backups but nothing else.
|
||||
Notice that the client may specify TCP/IP and/or X11
|
||||
forwardings unless they are explicitly prohibited.
|
||||
Note that the client may specify TCP/IP and/or X11
|
||||
forwarding unless they are explicitly prohibited.
|
||||
.It Cm environment="NAME=value"
|
||||
Specifies that the string is to be added to the environment when
|
||||
logging in using this key.
|
||||
@ -632,10 +709,12 @@ from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula
|
||||
.Pp
|
||||
command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi
|
||||
.Sh SSH_KNOWN_HOSTS FILE FORMAT
|
||||
The
|
||||
.Pa /etc/ssh_known_hosts
|
||||
and
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
The
|
||||
.Pa /etc/ssh_known_hosts ,
|
||||
.Pa /etc/ssh_known_hosts2 ,
|
||||
.Pa $HOME/.ssh/known_hosts ,
|
||||
and
|
||||
.Pa $HOME/.ssh/known_hosts2
|
||||
files contain host public keys for all known hosts.
|
||||
The global file should
|
||||
be prepared by the administrator (optional), and the per-user file is
|
||||
@ -656,7 +735,7 @@ to indicate negation: if the host name matches a negated
|
||||
pattern, it is not accepted (by that line) even if it matched another
|
||||
pattern on the line.
|
||||
.Pp
|
||||
Bits, exponent, and modulus are taken directly from the host key; they
|
||||
Bits, exponent, and modulus are taken directly from the RSA host key; they
|
||||
can be obtained, e.g., from
|
||||
.Pa /etc/ssh_host_key.pub .
|
||||
The optional comment field continues to the end of the line, and is not used.
|
||||
@ -679,7 +758,7 @@ accepted if valid information can be found from either file.
|
||||
Note that the lines in these files are typically hundreds of characters
|
||||
long, and you definitely don't want to type in the host keys by hand.
|
||||
Rather, generate them by a script
|
||||
or by taking
|
||||
or by taking
|
||||
.Pa /etc/ssh_host_key.pub
|
||||
and adding the host names at the front.
|
||||
.Ss Examples
|
||||
@ -722,6 +801,21 @@ it being world-readable if the user's home directory resides on an NFS
|
||||
volume).
|
||||
It is recommended that it not be accessible by others.
|
||||
The format of this file is described above.
|
||||
Users will place the contents of their
|
||||
.Pa identity.pub
|
||||
files into this file, as described in
|
||||
.Xr ssh-keygen 1 .
|
||||
.It Pa $HOME/.ssh/authorized_keys2
|
||||
Lists the DSA keys that can be used to log into the user's account.
|
||||
This file must be readable by root (which may on some machines imply
|
||||
it being world-readable if the user's home directory resides on an NFS
|
||||
volume).
|
||||
It is recommended that it not be accessible by others.
|
||||
The format of this file is described above.
|
||||
Users will place the contents of their
|
||||
.Pa id_dsa.pub
|
||||
files into this file, as described in
|
||||
.Xr ssh-keygen 1 .
|
||||
.It Pa "/etc/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
|
||||
These files are consulted when using rhosts with RSA host
|
||||
authentication to check the public key of the host.
|
||||
@ -734,7 +828,7 @@ should be world-readable, and
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
can but need not be world-readable.
|
||||
.It Pa /etc/nologin
|
||||
If this file exists,
|
||||
If this file exists,
|
||||
.Nm
|
||||
refuses to let anyone except root log in.
|
||||
The contents of the file
|
||||
@ -853,6 +947,7 @@ but with bugs removed and newer features re-added.
|
||||
Rapidly after the
|
||||
1.2.12 release, newer versions of the original ssh bore successively
|
||||
more restrictive licenses, and thus demand for a free version was born.
|
||||
.Pp
|
||||
This version of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
@ -862,10 +957,10 @@ directly removed from the source code; any licensed or patented components
|
||||
are chosen from
|
||||
external libraries.
|
||||
.It
|
||||
has been updated to support ssh protocol 1.5, making it compatible with
|
||||
all other ssh protocol 1 clients and servers.
|
||||
has been updated to support SSH protocol 1.5 and 2, making it compatible with
|
||||
all other SSH clients and servers.
|
||||
.It
|
||||
contains added support for
|
||||
contains added support for
|
||||
.Xr kerberos 8
|
||||
authentication and ticket passing.
|
||||
.It
|
||||
@ -876,12 +971,17 @@ supports one-time password authentication with
|
||||
The libraries described in
|
||||
.Xr ssl 8
|
||||
are required for proper operation.
|
||||
.Pp
|
||||
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
|
||||
Niels Provos, Theo de Raadt, and Dug Song.
|
||||
.Pp
|
||||
The support for SSH protocol 2 was written by Markus Friedl.
|
||||
.Sh SEE ALSO
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr scp 1 ,
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr ssl 8
|
||||
.Xr ssl 8 ,
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
# This is ssh server systemwide configuration file.
|
||||
|
||||
Port 22
|
||||
#Protocol 2,1
|
||||
#ListenAddress 0.0.0.0
|
||||
#ListenAddress ::
|
||||
HostKey /etc/ssh_host_key
|
||||
|
@ -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"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user