aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/openssh/README.openssh244
-rw-r--r--crypto/openssh/auth-krb4.c10
-rw-r--r--crypto/openssh/auth-passwd.c4
-rw-r--r--crypto/openssh/auth-rh-rsa.c18
-rw-r--r--crypto/openssh/auth-rhosts.c18
-rw-r--r--crypto/openssh/auth-rsa.c22
-rw-r--r--crypto/openssh/auth-skey.c18
-rw-r--r--crypto/openssh/auth.c111
-rw-r--r--crypto/openssh/auth.h17
-rw-r--r--crypto/openssh/auth1.c468
-rw-r--r--crypto/openssh/auth2.c467
-rw-r--r--crypto/openssh/authfd.c30
-rw-r--r--crypto/openssh/authfd.h22
-rw-r--r--crypto/openssh/authfile.c226
-rw-r--r--crypto/openssh/authfile.h36
-rw-r--r--crypto/openssh/bufaux.c75
-rw-r--r--crypto/openssh/bufaux.h15
-rw-r--r--crypto/openssh/buffer.c40
-rw-r--r--crypto/openssh/buffer.h14
-rw-r--r--crypto/openssh/canohost.c20
-rw-r--r--crypto/openssh/channels.c1901
-rw-r--r--crypto/openssh/channels.h210
-rw-r--r--crypto/openssh/cipher.c201
-rw-r--r--crypto/openssh/cipher.h52
-rw-r--r--crypto/openssh/clientloop.c521
-rw-r--r--crypto/openssh/compat.c66
-rw-r--r--crypto/openssh/compat.h18
-rw-r--r--crypto/openssh/compress.c60
-rw-r--r--crypto/openssh/compress.h14
-rw-r--r--crypto/openssh/crc32.h14
-rw-r--r--crypto/openssh/dispatch.c78
-rw-r--r--crypto/openssh/dispatch.h11
-rw-r--r--crypto/openssh/dsa.c300
-rw-r--r--crypto/openssh/dsa.h22
-rw-r--r--crypto/openssh/fingerprint.c4
-rw-r--r--crypto/openssh/getput.h16
-rw-r--r--crypto/openssh/hmac.c59
-rw-r--r--crypto/openssh/hmac.h11
-rw-r--r--crypto/openssh/hostfile.c43
-rw-r--r--crypto/openssh/hostfile.h2
-rw-r--r--crypto/openssh/includes.h12
-rw-r--r--crypto/openssh/kex.c424
-rw-r--r--crypto/openssh/kex.h112
-rw-r--r--crypto/openssh/key.c126
-rw-r--r--crypto/openssh/key.h4
-rw-r--r--crypto/openssh/lib/Makefile2
-rw-r--r--crypto/openssh/log-client.c14
-rw-r--r--crypto/openssh/log-server.c26
-rw-r--r--crypto/openssh/login.c24
-rw-r--r--crypto/openssh/match.c16
-rw-r--r--crypto/openssh/mpaux.c24
-rw-r--r--crypto/openssh/mpaux.h14
-rw-r--r--crypto/openssh/myproposal.h20
-rw-r--r--crypto/openssh/nchan.c405
-rw-r--r--crypto/openssh/nchan.h28
-rw-r--r--crypto/openssh/nchan2.ms64
-rw-r--r--crypto/openssh/packet.c554
-rw-r--r--crypto/openssh/packet.h39
-rw-r--r--crypto/openssh/pty.c22
-rw-r--r--crypto/openssh/pty.h14
-rw-r--r--crypto/openssh/radix.c109
-rw-r--r--crypto/openssh/readconf.c102
-rw-r--r--crypto/openssh/readconf.h29
-rw-r--r--crypto/openssh/readpass.c4
-rw-r--r--crypto/openssh/rsa.c30
-rw-r--r--crypto/openssh/rsa.h18
-rw-r--r--crypto/openssh/scp.16
-rw-r--r--crypto/openssh/scp.c78
-rw-r--r--crypto/openssh/servconf.c132
-rw-r--r--crypto/openssh/servconf.h20
-rw-r--r--crypto/openssh/serverloop.c409
-rw-r--r--crypto/openssh/session.c1516
-rw-r--r--crypto/openssh/session.h14
-rw-r--r--crypto/openssh/ssh-add.112
-rw-r--r--crypto/openssh/ssh-add.c37
-rw-r--r--crypto/openssh/ssh-agent.116
-rw-r--r--crypto/openssh/ssh-agent.c23
-rw-r--r--crypto/openssh/ssh-keygen.175
-rw-r--r--crypto/openssh/ssh-keygen.c364
-rw-r--r--crypto/openssh/ssh.1252
-rw-r--r--crypto/openssh/ssh.c368
-rw-r--r--crypto/openssh/ssh.h250
-rw-r--r--crypto/openssh/ssh/Makefile3
-rw-r--r--crypto/openssh/ssh2.h106
-rw-r--r--crypto/openssh/ssh_config1
-rw-r--r--crypto/openssh/sshconnect.c1170
-rw-r--r--crypto/openssh/sshconnect.h16
-rw-r--r--crypto/openssh/sshconnect1.c1024
-rw-r--r--crypto/openssh/sshconnect2.c474
-rw-r--r--crypto/openssh/sshd.8194
-rw-r--r--crypto/openssh/sshd.c2134
-rw-r--r--crypto/openssh/sshd/Makefile3
-rw-r--r--crypto/openssh/sshd_config1
-rw-r--r--crypto/openssh/ttymodes.c10
-rw-r--r--crypto/openssh/ttymodes.h12
-rw-r--r--crypto/openssh/uidswap.c8
-rw-r--r--crypto/openssh/uidswap.h10
-rw-r--r--crypto/openssh/uuencode.c50
-rw-r--r--crypto/openssh/uuencode.h6
-rw-r--r--crypto/openssh/version.h2
-rw-r--r--crypto/openssh/xmalloc.c4
-rw-r--r--crypto/openssh/xmalloc.h14
102 files changed, 11263 insertions, 5065 deletions
diff --git a/crypto/openssh/README.openssh2 b/crypto/openssh/README.openssh2
new file mode 100644
index 000000000000..12c90aa31690
--- /dev/null
+++ b/crypto/openssh/README.openssh2
@@ -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 $
diff --git a/crypto/openssh/auth-krb4.c b/crypto/openssh/auth-krb4.c
index 7e30646f88db..a26842713aae 100644
--- a/crypto/openssh/auth-krb4.c
+++ b/crypto/openssh/auth-krb4.c
@@ -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_failure:
return 0;
}
-int
+int
auth_afs_token(struct passwd *pw, const char *token_string)
{
CREDENTIALS creds;
diff --git a/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c
index de0f6402d7e2..fea75d925bdf 100644
--- a/crypto/openssh/auth-passwd.c
+++ b/crypto/openssh/auth-passwd.c
@@ -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;
diff --git a/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c
index b7adab7b96be..f251fb9cc3ef 100644
--- a/crypto/openssh/auth-rh-rsa.c
+++ b/crypto/openssh/auth-rh-rsa.c
@@ -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;
diff --git a/crypto/openssh/auth-rhosts.c b/crypto/openssh/auth-rhosts.c
index 843242875aea..3393b86661dd 100644
--- a/crypto/openssh/auth-rhosts.c
+++ b/crypto/openssh/auth-rhosts.c
@@ -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;
diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c
index 3d2e84f1c06a..78d28f0b8c87 100644
--- a/crypto/openssh/auth-rsa.c
+++ b/crypto/openssh/auth-rsa.c
@@ -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. */
diff --git a/crypto/openssh/auth-skey.c b/crypto/openssh/auth-skey.c
index 3610a67eff22..5f3fe9ee1b96 100644
--- a/crypto/openssh/auth-skey.c
+++ b/crypto/openssh/auth-skey.c
@@ -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;
}
diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c
new file mode 100644
index 000000000000..d3425a237a71
--- /dev/null
+++ b/crypto/openssh/auth.c
@@ -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;
+}
diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h
new file mode 100644
index 000000000000..72126e0992d9
--- /dev/null
+++ b/crypto/openssh/auth.h
@@ -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
+
diff --git a/crypto/openssh/auth1.c b/crypto/openssh/auth1.c
new file mode 100644
index 000000000000..38114d8c06eb
--- /dev/null
+++ b/crypto/openssh/auth1.c
@@ -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);
+}
diff --git a/crypto/openssh/auth2.c b/crypto/openssh/auth2.c
new file mode 100644
index 000000000000..3f8c254080de
--- /dev/null
+++ b/crypto/openssh/auth2.c
@@ -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;
+}
diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c
index 6a9ec6bf07bc..77d38e00dd37 100644
--- a/crypto/openssh/authfd.c
+++ b/crypto/openssh/authfd.c
@@ -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 @@ error_cleanup:
* be used by normal applications.
*/
-int
+int
ssh_add_identity(AuthenticationConnection *auth,
RSA * key, const char *comment)
{
@@ -426,7 +426,7 @@ error_cleanup:
* meant to be used by normal applications.
*/
-int
+int
ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
{
Buffer buffer;
@@ -509,7 +509,7 @@ error_cleanup:
* by normal applications.
*/
-int
+int
ssh_remove_all_identities(AuthenticationConnection *auth)
{
Buffer buffer;
diff --git a/crypto/openssh/authfd.h b/crypto/openssh/authfd.h
index 2af4858052fd..fbeea2334dc8 100644
--- a/crypto/openssh/authfd.h
+++ b/crypto/openssh/authfd.h
@@ -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);
diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c
index f619a498408c..92740c48a1c2 100644
--- a/crypto/openssh/authfile.c
+++ b/crypto/openssh/authfile.c
@@ -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 @@ fail:
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;
+}
diff --git a/crypto/openssh/authfile.h b/crypto/openssh/authfile.h
new file mode 100644
index 000000000000..afec27d5433e
--- /dev/null
+++ b/crypto/openssh/authfile.h
@@ -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
diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c
index dddc41f9c69d..922acc4e1146 100644
--- a/crypto/openssh/bufaux.c
+++ b/crypto/openssh/bufaux.c
@@ -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"
@@ -76,9 +78,53 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
}
/*
+ * 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;
diff --git a/crypto/openssh/bufaux.h b/crypto/openssh/bufaux.h
index 124a2656ba59..8ba92f8b5925 100644
--- a/crypto/openssh/bufaux.h
+++ b/crypto/openssh/bufaux.h
@@ -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 */
diff --git a/crypto/openssh/buffer.c b/crypto/openssh/buffer.c
index 65579341b8c7..4d8343322cdf 100644
--- a/crypto/openssh/buffer.c
+++ b/crypto/openssh/buffer.c
@@ -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 @@ restart:
/* 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;
diff --git a/crypto/openssh/buffer.h b/crypto/openssh/buffer.h
index 04efc25221cf..be4fdc3cabd5 100644
--- a/crypto/openssh/buffer.h
+++ b/crypto/openssh/buffer.h
@@ -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
diff --git a/crypto/openssh/canohost.c b/crypto/openssh/canohost.c
index fcf743cd417b..a73f8d0ecf2d 100644
--- a/crypto/openssh/canohost.c
+++ b/crypto/openssh/canohost.c
@@ -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);
diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c
index 62b6a2269531..5bf1e5b7aea7 100644
--- a/crypto/openssh/channels.c
+++ b/crypto/openssh/channels.c
@@ -1,22 +1,23 @@
/*
- *
+ *
* channels.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 16:35:24 1995 ylo
- *
+ *
* This file contains functions for generic socket connection forwarding.
* There is also code for initiating connection forwarding for X11 connections,
* arbitrary tcp/ip connections, and the authentication agent connection.
- *
+ *
+ * SSH2 support added by Markus Friedl.
*/
#include "includes.h"
-RCSID("$Id: channels.c,v 1.39 2000/03/16 20:56:14 markus Exp $");
+RCSID("$Id: channels.c,v 1.57 2000/05/08 17:42:24 markus Exp $");
#include "ssh.h"
#include "packet.h"
@@ -31,12 +32,20 @@ RCSID("$Id: channels.c,v 1.39 2000/03/16 20:56:14 markus Exp $");
#include "nchan.h"
#include "compat.h"
+#include "ssh2.h"
+
/* Maximum number of fake X11 displays to try. */
#define MAX_DISPLAYS 1000
/* Max len of agent socket */
#define MAX_SOCKET_NAME 100
+/* default window/packet sizes for tcp/x11-fwd-channel */
+#define CHAN_TCP_WINDOW_DEFAULT (8*1024)
+#define CHAN_TCP_PACKET_DEFAULT (CHAN_TCP_WINDOW_DEFAULT/2)
+#define CHAN_X11_WINDOW_DEFAULT (4*1024)
+#define CHAN_X11_PACKET_DEFAULT (CHAN_X11_WINDOW_DEFAULT/2)
+
/*
* Pointer to an array containing all allocated channels. The array is
* dynamically extended as needed.
@@ -81,8 +90,9 @@ unsigned int x11_fake_data_len;
* network (which might be behind a firewall).
*/
typedef struct {
- char *host; /* Host name. */
- u_short port; /* Port number. */
+ char *host_to_connect; /* Connect to 'host'. */
+ u_short port_to_connect; /* Connect to 'port'. */
+ u_short listen_port; /* Remote side should listen port number. */
} ForwardPermission;
/* List of all permitted host/port pairs to connect. */
@@ -101,7 +111,7 @@ static int have_hostname_in_open = 0;
/* Sets specific protocol options. */
-void
+void
channel_set_options(int hostname_in_open)
{
have_hostname_in_open = hostname_in_open;
@@ -113,30 +123,92 @@ channel_set_options(int hostname_in_open)
* and the server has no way to know but to trust the client anyway.
*/
-void
+void
channel_permit_all_opens()
{
all_opens_permitted = 1;
}
+/* lookup channel by id */
+
+Channel *
+channel_lookup(int id)
+{
+ Channel *c;
+ if (id < 0 && id > channels_alloc) {
+ log("channel_lookup: %d: bad id", id);
+ return NULL;
+ }
+ c = &channels[id];
+ if (c->type == SSH_CHANNEL_FREE) {
+ log("channel_lookup: %d: bad id: channel free", id);
+ return NULL;
+ }
+ return c;
+}
+
+void
+set_nonblock(int fd)
+{
+ int val;
+ val = fcntl(fd, F_GETFL, 0);
+ if (val < 0) {
+ error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
+ return;
+ }
+ if (val & O_NONBLOCK)
+ return;
+ debug("fd %d setting O_NONBLOCK", fd);
+ val |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, val) == -1)
+ error("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, strerror(errno));
+}
+
+/*
+ * Register filedescriptors for a channel, used when allocating a channel or
+ * when the channel consumer/producer is ready, e.g. shell exec'd
+ */
+
+void
+channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage)
+{
+ /* Update the maximum file descriptor value. */
+ if (rfd > channel_max_fd_value)
+ channel_max_fd_value = rfd;
+ if (wfd > channel_max_fd_value)
+ channel_max_fd_value = wfd;
+ if (efd > channel_max_fd_value)
+ channel_max_fd_value = efd;
+ /* XXX set close-on-exec -markus */
+
+ c->rfd = rfd;
+ c->wfd = wfd;
+ c->sock = (rfd == wfd) ? rfd : -1;
+ c->efd = efd;
+ c->extended_usage = extusage;
+ if (rfd != -1)
+ set_nonblock(rfd);
+ if (wfd != -1)
+ set_nonblock(wfd);
+ if (efd != -1)
+ set_nonblock(efd);
+}
+
/*
* Allocate a new channel object and set its type and socket. This will cause
* remote_name to be freed.
*/
-int
-channel_allocate(int type, int sock, char *remote_name)
+int
+channel_new(char *ctype, int type, int rfd, int wfd, int efd,
+ int window, int maxpack, int extusage, char *remote_name)
{
int i, found;
Channel *c;
- /* Update the maximum file descriptor value. */
- if (sock > channel_max_fd_value)
- channel_max_fd_value = sock;
- /* XXX set close-on-exec -markus */
-
/* Do initial allocation if this is the first call. */
if (channels_alloc == 0) {
+ chan_init();
channels_alloc = 10;
channels = xmalloc(channels_alloc * sizeof(Channel));
for (i = 0; i < channels_alloc; i++)
@@ -167,411 +239,743 @@ channel_allocate(int type, int sock, char *remote_name)
c = &channels[found];
buffer_init(&c->input);
buffer_init(&c->output);
+ buffer_init(&c->extended);
chan_init_iostates(c);
+ channel_register_fds(c, rfd, wfd, efd, extusage);
c->self = found;
c->type = type;
- c->sock = sock;
+ c->ctype = ctype;
+ c->local_window = window;
+ c->local_window_max = window;
+ c->local_consumed = 0;
+ c->local_maxpacket = maxpack;
c->remote_id = -1;
c->remote_name = remote_name;
+ c->remote_window = 0;
+ c->remote_maxpacket = 0;
+ c->cb_fn = NULL;
+ c->cb_arg = NULL;
+ c->cb_event = 0;
+ c->dettach_user = NULL;
debug("channel %d: new [%s]", found, remote_name);
return found;
}
+/* old interface XXX */
+int
+channel_allocate(int type, int sock, char *remote_name)
+{
+ return channel_new("", type, sock, sock, -1, 0, 0, 0, remote_name);
+}
-/* Free the channel and close its socket. */
-void
-channel_free(int channel)
+/* Close all channel fd/socket. */
+
+void
+channel_close_fds(Channel *c)
{
- if (channel < 0 || channel >= channels_alloc ||
- channels[channel].type == SSH_CHANNEL_FREE)
- packet_disconnect("channel free: bad local channel %d", channel);
+ if (c->sock != -1) {
+ close(c->sock);
+ c->sock = -1;
+ }
+ if (c->rfd != -1) {
+ close(c->rfd);
+ c->rfd = -1;
+ }
+ if (c->wfd != -1) {
+ close(c->wfd);
+ c->wfd = -1;
+ }
+ if (c->efd != -1) {
+ close(c->efd);
+ c->efd = -1;
+ }
+}
+
+/* Free the channel and close its fd/socket. */
- if (compat13)
- shutdown(channels[channel].sock, SHUT_RDWR);
- close(channels[channel].sock);
- buffer_free(&channels[channel].input);
- buffer_free(&channels[channel].output);
- channels[channel].type = SSH_CHANNEL_FREE;
- if (channels[channel].remote_name) {
- xfree(channels[channel].remote_name);
- channels[channel].remote_name = NULL;
+void
+channel_free(int id)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL)
+ packet_disconnect("channel free: bad local channel %d", id);
+ debug("channel_free: channel %d: status: %s", id, channel_open_message());
+ if (c->dettach_user != NULL) {
+ debug("channel_free: channel %d: dettaching channel user", id);
+ c->dettach_user(c->self, NULL);
+ }
+ if (c->sock != -1)
+ shutdown(c->sock, SHUT_RDWR);
+ channel_close_fds(c);
+ buffer_free(&c->input);
+ buffer_free(&c->output);
+ buffer_free(&c->extended);
+ c->type = SSH_CHANNEL_FREE;
+ if (c->remote_name) {
+ xfree(c->remote_name);
+ c->remote_name = NULL;
}
}
/*
- * This is called just before select() to add any bits relevant to channels
- * in the select bitmasks.
+ * 'channel_pre*' are called just before select() to add any bits relevant to
+ * channels in the select bitmasks.
+ */
+/*
+ * 'channel_post*': perform any appropriate operations for channels which
+ * have events pending.
*/
+typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);
+chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
+chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
-void
-channel_prepare_select(fd_set * readset, fd_set * writeset)
+void
+channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset)
{
- int i;
- Channel *ch;
- unsigned char *ucp;
- unsigned int proto_len, data_len;
+ FD_SET(c->sock, readset);
+}
- for (i = 0; i < channels_alloc; i++) {
- ch = &channels[i];
-redo:
- switch (ch->type) {
- case SSH_CHANNEL_X11_LISTENER:
- case SSH_CHANNEL_PORT_LISTENER:
- case SSH_CHANNEL_AUTH_SOCKET:
- FD_SET(ch->sock, readset);
- break;
+void
+channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ if (buffer_len(&c->input) < packet_get_maxsize())
+ FD_SET(c->sock, readset);
+ if (buffer_len(&c->output) > 0)
+ FD_SET(c->sock, writeset);
+}
- case SSH_CHANNEL_OPEN:
- if (compat13) {
- if (buffer_len(&ch->input) < packet_get_maxsize())
- FD_SET(ch->sock, readset);
- if (buffer_len(&ch->output) > 0)
- FD_SET(ch->sock, writeset);
- break;
- }
- /* test whether sockets are 'alive' for read/write */
- if (ch->istate == CHAN_INPUT_OPEN)
- if (buffer_len(&ch->input) < packet_get_maxsize())
- FD_SET(ch->sock, readset);
- if (ch->ostate == CHAN_OUTPUT_OPEN ||
- ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- if (buffer_len(&ch->output) > 0) {
- FD_SET(ch->sock, writeset);
- } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
- chan_obuf_empty(ch);
- }
- }
- break;
+void
+channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ /* test whether sockets are 'alive' for read/write */
+ if (c->istate == CHAN_INPUT_OPEN)
+ if (buffer_len(&c->input) < packet_get_maxsize())
+ FD_SET(c->sock, readset);
+ if (c->ostate == CHAN_OUTPUT_OPEN ||
+ c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+ if (buffer_len(&c->output) > 0) {
+ FD_SET(c->sock, writeset);
+ } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+ chan_obuf_empty(c);
+ }
+ }
+}
- case SSH_CHANNEL_INPUT_DRAINING:
- if (!compat13)
- fatal("cannot happen: IN_DRAIN");
- if (buffer_len(&ch->input) == 0) {
- packet_start(SSH_MSG_CHANNEL_CLOSE);
- packet_put_int(ch->remote_id);
- packet_send();
- ch->type = SSH_CHANNEL_CLOSED;
- debug("Closing channel %d after input drain.", ch->self);
- break;
- }
- break;
+void
+channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ if (c->istate == CHAN_INPUT_OPEN &&
+ c->remote_window > 0 &&
+ buffer_len(&c->input) < c->remote_window)
+ FD_SET(c->rfd, readset);
+ if (c->ostate == CHAN_OUTPUT_OPEN ||
+ c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+ if (buffer_len(&c->output) > 0) {
+ FD_SET(c->wfd, writeset);
+ } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
+ chan_obuf_empty(c);
+ }
+ }
+ /** XXX check close conditions, too */
+ if (c->efd != -1) {
+ if (c->extended_usage == CHAN_EXTENDED_WRITE &&
+ buffer_len(&c->extended) > 0)
+ FD_SET(c->efd, writeset);
+ else if (c->extended_usage == CHAN_EXTENDED_READ &&
+ buffer_len(&c->extended) < c->remote_window)
+ FD_SET(c->efd, readset);
+ }
+}
- case SSH_CHANNEL_OUTPUT_DRAINING:
- if (!compat13)
- fatal("cannot happen: OUT_DRAIN");
- if (buffer_len(&ch->output) == 0) {
- channel_free(i);
- break;
- }
- FD_SET(ch->sock, writeset);
- break;
+void
+channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ if (buffer_len(&c->input) == 0) {
+ packet_start(SSH_MSG_CHANNEL_CLOSE);
+ packet_put_int(c->remote_id);
+ packet_send();
+ c->type = SSH_CHANNEL_CLOSED;
+ debug("Closing channel %d after input drain.", c->self);
+ }
+}
- case SSH_CHANNEL_X11_OPEN:
- /*
- * This is a special state for X11 authentication
- * spoofing. An opened X11 connection (when
- * authentication spoofing is being done) remains in
- * this state until the first packet has been
- * completely read. The authentication data in that
- * packet is then substituted by the real data if it
- * matches the fake data, and the channel is put into
- * normal mode.
- */
- /* Check if the fixed size part of the packet is in buffer. */
- if (buffer_len(&ch->output) < 12)
- break;
+void
+channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ if (buffer_len(&c->output) == 0)
+ channel_free(c->self);
+ else
+ FD_SET(c->sock, writeset);
+}
- /* Parse the lengths of variable-length fields. */
- ucp = (unsigned char *) buffer_ptr(&ch->output);
- if (ucp[0] == 0x42) { /* Byte order MSB first. */
- proto_len = 256 * ucp[6] + ucp[7];
- data_len = 256 * ucp[8] + ucp[9];
- } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */
- proto_len = ucp[6] + 256 * ucp[7];
- data_len = ucp[8] + 256 * ucp[9];
- } else {
- debug("Initial X11 packet contains bad byte order byte: 0x%x",
- ucp[0]);
- ch->type = SSH_CHANNEL_OPEN;
- goto reject;
- }
+/*
+ * This is a special state for X11 authentication spoofing. An opened X11
+ * connection (when authentication spoofing is being done) remains in this
+ * state until the first packet has been completely read. The authentication
+ * data in that packet is then substituted by the real data if it matches the
+ * fake data, and the channel is put into normal mode.
+ * XXX All this happens at the client side.
+ */
+int
+x11_open_helper(Channel *c)
+{
+ unsigned char *ucp;
+ unsigned int proto_len, data_len;
- /* Check if the whole packet is in buffer. */
- if (buffer_len(&ch->output) <
- 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
- break;
+ /* Check if the fixed size part of the packet is in buffer. */
+ if (buffer_len(&c->output) < 12)
+ return 0;
+
+ /* Parse the lengths of variable-length fields. */
+ ucp = (unsigned char *) buffer_ptr(&c->output);
+ if (ucp[0] == 0x42) { /* Byte order MSB first. */
+ proto_len = 256 * ucp[6] + ucp[7];
+ data_len = 256 * ucp[8] + ucp[9];
+ } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */
+ proto_len = ucp[6] + 256 * ucp[7];
+ data_len = ucp[8] + 256 * ucp[9];
+ } else {
+ debug("Initial X11 packet contains bad byte order byte: 0x%x",
+ ucp[0]);
+ return -1;
+ }
- /* Check if authentication protocol matches. */
- if (proto_len != strlen(x11_saved_proto) ||
- memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
- debug("X11 connection uses different authentication protocol.");
- ch->type = SSH_CHANNEL_OPEN;
- goto reject;
- }
- /* Check if authentication data matches our fake data. */
- if (data_len != x11_fake_data_len ||
- memcmp(ucp + 12 + ((proto_len + 3) & ~3),
- x11_fake_data, x11_fake_data_len) != 0) {
- debug("X11 auth data does not match fake data.");
- ch->type = SSH_CHANNEL_OPEN;
- goto reject;
- }
- /* Check fake data length */
- if (x11_fake_data_len != x11_saved_data_len) {
- error("X11 fake_data_len %d != saved_data_len %d",
- x11_fake_data_len, x11_saved_data_len);
- ch->type = SSH_CHANNEL_OPEN;
- goto reject;
- }
- /*
- * Received authentication protocol and data match
- * our fake data. Substitute the fake data with real
- * data.
- */
- memcpy(ucp + 12 + ((proto_len + 3) & ~3),
- x11_saved_data, x11_saved_data_len);
+ /* Check if the whole packet is in buffer. */
+ if (buffer_len(&c->output) <
+ 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
+ return 0;
- /* Start normal processing for the channel. */
- ch->type = SSH_CHANNEL_OPEN;
- goto redo;
+ /* Check if authentication protocol matches. */
+ if (proto_len != strlen(x11_saved_proto) ||
+ memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
+ debug("X11 connection uses different authentication protocol.");
+ return -1;
+ }
+ /* Check if authentication data matches our fake data. */
+ if (data_len != x11_fake_data_len ||
+ memcmp(ucp + 12 + ((proto_len + 3) & ~3),
+ x11_fake_data, x11_fake_data_len) != 0) {
+ debug("X11 auth data does not match fake data.");
+ return -1;
+ }
+ /* Check fake data length */
+ if (x11_fake_data_len != x11_saved_data_len) {
+ error("X11 fake_data_len %d != saved_data_len %d",
+ x11_fake_data_len, x11_saved_data_len);
+ return -1;
+ }
+ /*
+ * Received authentication protocol and data match
+ * our fake data. Substitute the fake data with real
+ * data.
+ */
+ memcpy(ucp + 12 + ((proto_len + 3) & ~3),
+ x11_saved_data, x11_saved_data_len);
+ return 1;
+}
- reject:
- /*
- * We have received an X11 connection that has bad
- * authentication information.
- */
- log("X11 connection rejected because of wrong authentication.\r\n");
- buffer_clear(&ch->input);
- buffer_clear(&ch->output);
- if (compat13) {
- close(ch->sock);
- ch->sock = -1;
- ch->type = SSH_CHANNEL_CLOSED;
- packet_start(SSH_MSG_CHANNEL_CLOSE);
- packet_put_int(ch->remote_id);
- packet_send();
+void
+channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ int ret = x11_open_helper(c);
+ if (ret == 1) {
+ /* Start normal processing for the channel. */
+ c->type = SSH_CHANNEL_OPEN;
+ channel_pre_open_13(c, readset, writeset);
+ } else if (ret == -1) {
+ /*
+ * We have received an X11 connection that has bad
+ * authentication information.
+ */
+ log("X11 connection rejected because of wrong authentication.\r\n");
+ buffer_clear(&c->input);
+ buffer_clear(&c->output);
+ close(c->sock);
+ c->sock = -1;
+ c->type = SSH_CHANNEL_CLOSED;
+ packet_start(SSH_MSG_CHANNEL_CLOSE);
+ packet_put_int(c->remote_id);
+ packet_send();
+ }
+}
+
+void
+channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ int ret = x11_open_helper(c);
+ if (ret == 1) {
+ c->type = SSH_CHANNEL_OPEN;
+ if (compat20)
+ channel_pre_open_20(c, readset, writeset);
+ else
+ channel_pre_open_15(c, readset, writeset);
+ } else if (ret == -1) {
+ debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
+ chan_read_failed(c); /** force close? */
+ chan_write_failed(c);
+ debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
+ }
+}
+
+/* This is our fake X11 server socket. */
+void
+channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ struct sockaddr addr;
+ int newsock, newch;
+ socklen_t addrlen;
+ char buf[16384], *remote_hostname;
+ int remote_port;
+
+ if (FD_ISSET(c->sock, readset)) {
+ debug("X11 connection requested.");
+ addrlen = sizeof(addr);
+ newsock = accept(c->sock, &addr, &addrlen);
+ if (newsock < 0) {
+ error("accept: %.100s", strerror(errno));
+ return;
+ }
+ remote_hostname = get_remote_hostname(newsock);
+ remote_port = get_peer_port(newsock);
+ snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
+ remote_hostname, remote_port);
+
+ newch = channel_new("x11",
+ SSH_CHANNEL_OPENING, newsock, newsock, -1,
+ c->local_window_max, c->local_maxpacket,
+ 0, xstrdup(buf));
+ if (compat20) {
+ packet_start(SSH2_MSG_CHANNEL_OPEN);
+ packet_put_cstring("x11");
+ packet_put_int(newch);
+ packet_put_int(c->local_window_max);
+ packet_put_int(c->local_maxpacket);
+ /* originator host and port */
+ packet_put_cstring(remote_hostname);
+ if (datafellows & SSH_BUG_X11FWD) {
+ debug("ssh2 x11 bug compat mode");
} else {
- debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);
- chan_read_failed(ch);
- chan_write_failed(ch);
- debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate);
+ packet_put_int(remote_port);
}
- break;
-
- case SSH_CHANNEL_FREE:
- default:
- continue;
+ packet_send();
+ } else {
+ packet_start(SSH_SMSG_X11_OPEN);
+ packet_put_int(newch);
+ if (have_hostname_in_open)
+ packet_put_string(buf, strlen(buf));
+ packet_send();
}
+ xfree(remote_hostname);
}
}
/*
- * After select, perform any appropriate operations for channels which have
- * events pending.
+ * This socket is listening for connections to a forwarded TCP/IP port.
*/
-
-void
-channel_after_select(fd_set * readset, fd_set * writeset)
+void
+channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
{
struct sockaddr addr;
- int newsock, i, newch, len;
+ int newsock, newch;
socklen_t addrlen;
- Channel *ch;
- char buf[16384], *remote_hostname;
-
- /* Loop over all channels... */
- for (i = 0; i < channels_alloc; i++) {
- ch = &channels[i];
- switch (ch->type) {
- case SSH_CHANNEL_X11_LISTENER:
- /* This is our fake X11 server socket. */
- if (FD_ISSET(ch->sock, readset)) {
- debug("X11 connection requested.");
- addrlen = sizeof(addr);
- newsock = accept(ch->sock, &addr, &addrlen);
- if (newsock < 0) {
- error("accept: %.100s", strerror(errno));
- break;
- }
- remote_hostname = get_remote_hostname(newsock);
- snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",
- remote_hostname, get_peer_port(newsock));
- xfree(remote_hostname);
- newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
- xstrdup(buf));
- packet_start(SSH_SMSG_X11_OPEN);
- packet_put_int(newch);
- if (have_hostname_in_open)
- packet_put_string(buf, strlen(buf));
- packet_send();
+ char buf[1024], *remote_hostname;
+ int remote_port;
+
+ if (FD_ISSET(c->sock, readset)) {
+ debug("Connection to port %d forwarding "
+ "to %.100s port %d requested.",
+ c->listening_port, c->path, c->host_port);
+ addrlen = sizeof(addr);
+ newsock = accept(c->sock, &addr, &addrlen);
+ if (newsock < 0) {
+ error("accept: %.100s", strerror(errno));
+ return;
+ }
+ remote_hostname = get_remote_hostname(newsock);
+ remote_port = get_peer_port(newsock);
+ snprintf(buf, sizeof buf,
+ "listen port %d for %.100s port %d, "
+ "connect from %.200s port %d",
+ c->listening_port, c->path, c->host_port,
+ remote_hostname, remote_port);
+ newch = channel_new("direct-tcpip",
+ SSH_CHANNEL_OPENING, newsock, newsock, -1,
+ c->local_window_max, c->local_maxpacket,
+ 0, xstrdup(buf));
+ if (compat20) {
+ packet_start(SSH2_MSG_CHANNEL_OPEN);
+ packet_put_cstring("direct-tcpip");
+ packet_put_int(newch);
+ packet_put_int(c->local_window_max);
+ packet_put_int(c->local_maxpacket);
+ /* target host and port */
+ packet_put_string(c->path, strlen(c->path));
+ packet_put_int(c->host_port);
+ /* originator host and port */
+ packet_put_cstring(remote_hostname);
+ packet_put_int(remote_port);
+ packet_send();
+ } else {
+ packet_start(SSH_MSG_PORT_OPEN);
+ packet_put_int(newch);
+ packet_put_string(c->path, strlen(c->path));
+ packet_put_int(c->host_port);
+ if (have_hostname_in_open) {
+ packet_put_string(buf, strlen(buf));
}
- break;
+ packet_send();
+ }
+ xfree(remote_hostname);
+ }
+}
- case SSH_CHANNEL_PORT_LISTENER:
- /*
- * This socket is listening for connections to a
- * forwarded TCP/IP port.
- */
- if (FD_ISSET(ch->sock, readset)) {
- debug("Connection to port %d forwarding to %.100s port %d requested.",
- ch->listening_port, ch->path, ch->host_port);
- addrlen = sizeof(addr);
- newsock = accept(ch->sock, &addr, &addrlen);
- if (newsock < 0) {
- error("accept: %.100s", strerror(errno));
- break;
- }
- remote_hostname = get_remote_hostname(newsock);
- snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, connect from %.200s port %d",
- ch->listening_port, ch->path, ch->host_port,
- remote_hostname, get_peer_port(newsock));
- xfree(remote_hostname);
- newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
- xstrdup(buf));
- packet_start(SSH_MSG_PORT_OPEN);
- packet_put_int(newch);
- packet_put_string(ch->path, strlen(ch->path));
- packet_put_int(ch->host_port);
- if (have_hostname_in_open)
- packet_put_string(buf, strlen(buf));
- packet_send();
- }
- break;
+/*
+ * This is the authentication agent socket listening for connections from
+ * clients.
+ */
+void
+channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ struct sockaddr addr;
+ int newsock, newch;
+ socklen_t addrlen;
- case SSH_CHANNEL_AUTH_SOCKET:
- /*
- * This is the authentication agent socket listening
- * for connections from clients.
- */
- if (FD_ISSET(ch->sock, readset)) {
- addrlen = sizeof(addr);
- newsock = accept(ch->sock, &addr, &addrlen);
- if (newsock < 0) {
- error("accept from auth socket: %.100s", strerror(errno));
- break;
- }
- newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
- xstrdup("accepted auth socket"));
- packet_start(SSH_SMSG_AGENT_OPEN);
- packet_put_int(newch);
- packet_send();
- }
- break;
+ if (FD_ISSET(c->sock, readset)) {
+ addrlen = sizeof(addr);
+ newsock = accept(c->sock, &addr, &addrlen);
+ if (newsock < 0) {
+ error("accept from auth socket: %.100s", strerror(errno));
+ return;
+ }
+ newch = channel_allocate(SSH_CHANNEL_OPENING, newsock,
+ xstrdup("accepted auth socket"));
+ packet_start(SSH_SMSG_AGENT_OPEN);
+ packet_put_int(newch);
+ packet_send();
+ }
+}
- case SSH_CHANNEL_OPEN:
- /*
- * This is an open two-way communication channel. It
- * is not of interest to us at this point what kind
- * of data is being transmitted.
- */
+int
+channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ char buf[16*1024];
+ int len;
- /*
- * Read available incoming data and append it to
- * buffer; shutdown socket, if read or write failes
- */
- if (FD_ISSET(ch->sock, readset)) {
- len = read(ch->sock, buf, sizeof(buf));
- if (len <= 0) {
- if (compat13) {
- buffer_consume(&ch->output, buffer_len(&ch->output));
- ch->type = SSH_CHANNEL_INPUT_DRAINING;
- debug("Channel %d status set to input draining.", i);
- } else {
- chan_read_failed(ch);
- }
- break;
- }
- buffer_append(&ch->input, buf, len);
+ if (c->rfd != -1 &&
+ FD_ISSET(c->rfd, readset)) {
+ len = read(c->rfd, buf, sizeof(buf));
+ if (len < 0 && (errno == EINTR || errno == EAGAIN))
+ return 1;
+ if (len <= 0) {
+ debug("channel %d: read<=0 rfd %d len %d",
+ c->self, c->rfd, len);
+ if (compat13) {
+ buffer_consume(&c->output, buffer_len(&c->output));
+ c->type = SSH_CHANNEL_INPUT_DRAINING;
+ debug("Channel %d status set to input draining.", c->self);
+ } else {
+ chan_read_failed(c);
}
- /* Send buffered output data to the socket. */
- if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) {
- len = write(ch->sock, buffer_ptr(&ch->output),
- buffer_len(&ch->output));
- if (len <= 0) {
- if (compat13) {
- buffer_consume(&ch->output, buffer_len(&ch->output));
- debug("Channel %d status set to input draining.", i);
- ch->type = SSH_CHANNEL_INPUT_DRAINING;
- } else {
- chan_write_failed(ch);
- }
- break;
- }
- buffer_consume(&ch->output, len);
+ return -1;
+ }
+ buffer_append(&c->input, buf, len);
+ }
+ return 1;
+}
+int
+channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ int len;
+
+ /* Send buffered output data to the socket. */
+ if (c->wfd != -1 &&
+ FD_ISSET(c->wfd, writeset) &&
+ buffer_len(&c->output) > 0) {
+ len = write(c->wfd, buffer_ptr(&c->output),
+ buffer_len(&c->output));
+ if (len < 0 && (errno == EINTR || errno == EAGAIN))
+ return 1;
+ if (len <= 0) {
+ if (compat13) {
+ buffer_consume(&c->output, buffer_len(&c->output));
+ debug("Channel %d status set to input draining.", c->self);
+ c->type = SSH_CHANNEL_INPUT_DRAINING;
+ } else {
+ chan_write_failed(c);
}
- break;
-
- case SSH_CHANNEL_OUTPUT_DRAINING:
- if (!compat13)
- fatal("cannot happen: OUT_DRAIN");
- /* Send buffered output data to the socket. */
- if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) {
- len = write(ch->sock, buffer_ptr(&ch->output),
- buffer_len(&ch->output));
- if (len <= 0)
- buffer_consume(&ch->output, buffer_len(&ch->output));
- else
- buffer_consume(&ch->output, len);
+ return -1;
+ }
+ buffer_consume(&c->output, len);
+ if (compat20 && len > 0) {
+ c->local_consumed += len;
+ }
+ }
+ return 1;
+}
+int
+channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ char buf[16*1024];
+ int len;
+
+/** XXX handle drain efd, too */
+ if (c->efd != -1) {
+ if (c->extended_usage == CHAN_EXTENDED_WRITE &&
+ FD_ISSET(c->efd, writeset) &&
+ buffer_len(&c->extended) > 0) {
+ len = write(c->efd, buffer_ptr(&c->extended),
+ buffer_len(&c->extended));
+ debug("channel %d: written %d to efd %d",
+ c->self, len, c->efd);
+ if (len > 0) {
+ buffer_consume(&c->extended, len);
+ c->local_consumed += len;
}
- break;
+ } else if (c->extended_usage == CHAN_EXTENDED_READ &&
+ FD_ISSET(c->efd, readset)) {
+ len = read(c->efd, buf, sizeof(buf));
+ debug("channel %d: read %d from efd %d",
+ c->self, len, c->efd);
+ if (len == 0) {
+ debug("channel %d: closing efd %d",
+ c->self, c->efd);
+ close(c->efd);
+ c->efd = -1;
+ } else if (len > 0)
+ buffer_append(&c->extended, buf, len);
+ }
+ }
+ return 1;
+}
+int
+channel_check_window(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
+ c->local_window < c->local_window_max/2 &&
+ c->local_consumed > 0) {
+ packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ packet_put_int(c->remote_id);
+ packet_put_int(c->local_consumed);
+ packet_send();
+ debug("channel %d: window %d sent adjust %d",
+ c->self, c->local_window,
+ c->local_consumed);
+ c->local_window += c->local_consumed;
+ c->local_consumed = 0;
+ }
+ return 1;
+}
- case SSH_CHANNEL_X11_OPEN:
- case SSH_CHANNEL_FREE:
- default:
+void
+channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ channel_handle_rfd(c, readset, writeset);
+ channel_handle_wfd(c, readset, writeset);
+}
+
+void
+channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ channel_handle_rfd(c, readset, writeset);
+ channel_handle_wfd(c, readset, writeset);
+ channel_handle_efd(c, readset, writeset);
+ channel_check_window(c, readset, writeset);
+}
+
+void
+channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ int len;
+ /* Send buffered output data to the socket. */
+ if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
+ len = write(c->sock, buffer_ptr(&c->output),
+ buffer_len(&c->output));
+ if (len <= 0)
+ buffer_consume(&c->output, buffer_len(&c->output));
+ else
+ buffer_consume(&c->output, len);
+ }
+}
+
+void
+channel_handler_init_20(void)
+{
+ channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20;
+ channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
+ channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
+
+ channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2;
+ channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
+ channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
+}
+
+void
+channel_handler_init_13(void)
+{
+ channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13;
+ channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13;
+ channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining;
+ channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining;
+
+ channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1;
+ channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
+ channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
+ channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
+ channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13;
+}
+
+void
+channel_handler_init_15(void)
+{
+ channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_15;
+ channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
+ channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
+ channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
+
+ channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
+ channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
+ channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
+ channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1;
+}
+
+void
+channel_handler_init(void)
+{
+ int i;
+ for(i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
+ channel_pre[i] = NULL;
+ channel_post[i] = NULL;
+ }
+ if (compat20)
+ channel_handler_init_20();
+ else if (compat13)
+ channel_handler_init_13();
+ else
+ channel_handler_init_15();
+}
+
+void
+channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
+{
+ static int did_init = 0;
+ int i;
+ Channel *c;
+
+ if (!did_init) {
+ channel_handler_init();
+ did_init = 1;
+ }
+ for (i = 0; i < channels_alloc; i++) {
+ c = &channels[i];
+ if (c->type == SSH_CHANNEL_FREE)
continue;
- }
+ if (ftab[c->type] == NULL)
+ continue;
+ (*ftab[c->type])(c, readset, writeset);
+ chan_delete_if_full_closed(c);
}
}
+void
+channel_prepare_select(fd_set * readset, fd_set * writeset)
+{
+ channel_handler(channel_pre, readset, writeset);
+}
+
+void
+channel_after_select(fd_set * readset, fd_set * writeset)
+{
+ channel_handler(channel_post, readset, writeset);
+}
+
/* If there is data to send to the connection, send some of it now. */
-void
+void
channel_output_poll()
{
int len, i;
- Channel *ch;
+ Channel *c;
for (i = 0; i < channels_alloc; i++) {
- ch = &channels[i];
+ c = &channels[i];
/* We are only interested in channels that can have buffered incoming data. */
if (compat13) {
- if (ch->type != SSH_CHANNEL_OPEN &&
- ch->type != SSH_CHANNEL_INPUT_DRAINING)
+ if (c->type != SSH_CHANNEL_OPEN &&
+ c->type != SSH_CHANNEL_INPUT_DRAINING)
continue;
} else {
- if (ch->type != SSH_CHANNEL_OPEN)
+ if (c->type != SSH_CHANNEL_OPEN)
continue;
- if (ch->istate != CHAN_INPUT_OPEN &&
- ch->istate != CHAN_INPUT_WAIT_DRAIN)
+ if (c->istate != CHAN_INPUT_OPEN &&
+ c->istate != CHAN_INPUT_WAIT_DRAIN)
continue;
}
+ if (compat20 &&
+ (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
+ debug("channel: %d: no data after CLOSE", c->self);
+ continue;
+ }
/* Get the amount of buffered data for this channel. */
- len = buffer_len(&ch->input);
+ len = buffer_len(&c->input);
if (len > 0) {
/* Send some data for the other side over the secure connection. */
- if (packet_is_interactive()) {
- if (len > 1024)
- len = 512;
+ if (compat20) {
+ if (len > c->remote_window)
+ len = c->remote_window;
+ if (len > c->remote_maxpacket)
+ len = c->remote_maxpacket;
} else {
- /* Keep the packets at reasonable size. */
- if (len > packet_get_maxsize()/2)
- len = packet_get_maxsize()/2;
+ if (packet_is_interactive()) {
+ if (len > 1024)
+ len = 512;
+ } else {
+ /* Keep the packets at reasonable size. */
+ if (len > packet_get_maxsize()/2)
+ len = packet_get_maxsize()/2;
+ }
}
- packet_start(SSH_MSG_CHANNEL_DATA);
- packet_put_int(ch->remote_id);
- packet_put_string(buffer_ptr(&ch->input), len);
- packet_send();
- buffer_consume(&ch->input, len);
- } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) {
+ if (len > 0) {
+ packet_start(compat20 ?
+ SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
+ packet_put_int(c->remote_id);
+ packet_put_string(buffer_ptr(&c->input), len);
+ packet_send();
+ buffer_consume(&c->input, len);
+ c->remote_window -= len;
+ debug("channel %d: send data len %d", c->self, len);
+ }
+ } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
if (compat13)
fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
/*
* input-buffer is empty and read-socket shutdown:
* tell peer, that we will not send more data: send IEOF
*/
- chan_ibuf_empty(ch);
+ chan_ibuf_empty(c);
+ }
+ /* Send extended data, i.e. stderr */
+ if (compat20 &&
+ c->remote_window > 0 &&
+ (len = buffer_len(&c->extended)) > 0 &&
+ c->extended_usage == CHAN_EXTENDED_READ) {
+ if (len > c->remote_window)
+ len = c->remote_window;
+ if (len > c->remote_maxpacket)
+ len = c->remote_maxpacket;
+ packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
+ packet_put_int(c->remote_id);
+ packet_put_int(SSH2_EXTENDED_DATA_STDERR);
+ packet_put_string(buffer_ptr(&c->extended), len);
+ packet_send();
+ buffer_consume(&c->extended, len);
+ c->remote_window -= len;
}
}
}
@@ -582,87 +986,155 @@ channel_output_poll()
* still there.
*/
-void
-channel_input_data(int payload_len)
+void
+channel_input_data(int type, int plen)
{
int id;
char *data;
unsigned int data_len;
- Channel *ch;
+ Channel *c;
/* Get the channel number and verify it. */
id = packet_get_int();
- if (id < 0 || id >= channels_alloc)
+ c = channel_lookup(id);
+ if (c == NULL)
packet_disconnect("Received data for nonexistent channel %d.", id);
- ch = &channels[id];
-
- if (ch->type == SSH_CHANNEL_FREE)
- packet_disconnect("Received data for free channel %d.", ch->self);
/* Ignore any data for non-open channels (might happen on close) */
- if (ch->type != SSH_CHANNEL_OPEN &&
- ch->type != SSH_CHANNEL_X11_OPEN)
+ if (c->type != SSH_CHANNEL_OPEN &&
+ c->type != SSH_CHANNEL_X11_OPEN)
return;
/* same for protocol 1.5 if output end is no longer open */
- if (!compat13 && ch->ostate != CHAN_OUTPUT_OPEN)
+ if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN)
return;
/* Get the data. */
data = packet_get_string(&data_len);
- packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);
- buffer_append(&ch->output, data, data_len);
+ packet_done();
+
+ if (compat20){
+ if (data_len > c->local_maxpacket) {
+ log("channel %d: rcvd big packet %d, maxpack %d",
+ c->self, data_len, c->local_maxpacket);
+ }
+ if (data_len > c->local_window) {
+ log("channel %d: rcvd too much data %d, win %d",
+ c->self, data_len, c->local_window);
+ xfree(data);
+ return;
+ }
+ c->local_window -= data_len;
+ }else{
+ packet_integrity_check(plen, 4 + 4 + data_len, type);
+ }
+ buffer_append(&c->output, data, data_len);
xfree(data);
}
+void
+channel_input_extended_data(int type, int plen)
+{
+ int id;
+ int tcode;
+ char *data;
+ unsigned int data_len;
+ Channel *c;
+
+ /* Get the channel number and verify it. */
+ id = packet_get_int();
+ c = channel_lookup(id);
+
+ if (c == NULL)
+ packet_disconnect("Received extended_data for bad channel %d.", id);
+ if (c->type != SSH_CHANNEL_OPEN) {
+ log("channel %d: ext data for non open", id);
+ return;
+ }
+ tcode = packet_get_int();
+ if (c->efd == -1 ||
+ c->extended_usage != CHAN_EXTENDED_WRITE ||
+ tcode != SSH2_EXTENDED_DATA_STDERR) {
+ log("channel %d: bad ext data", c->self);
+ return;
+ }
+ data = packet_get_string(&data_len);
+ packet_done();
+ if (data_len > c->local_window) {
+ log("channel %d: rcvd too much extended_data %d, win %d",
+ c->self, data_len, c->local_window);
+ xfree(data);
+ return;
+ }
+ debug("channel %d: rcvd ext data %d", c->self, data_len);
+ c->local_window -= data_len;
+ buffer_append(&c->extended, data, data_len);
+ xfree(data);
+}
+
/*
* Returns true if no channel has too much buffered data, and false if one or
* more channel is overfull.
*/
-int
+int
channel_not_very_much_buffered_data()
{
unsigned int i;
- Channel *ch;
+ Channel *c;
for (i = 0; i < channels_alloc; i++) {
- ch = &channels[i];
- if (ch->type == SSH_CHANNEL_OPEN) {
- if (buffer_len(&ch->input) > packet_get_maxsize())
+ c = &channels[i];
+ if (c->type == SSH_CHANNEL_OPEN) {
+ if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
+ debug("channel %d: big input buffer %d",
+ c->self, buffer_len(&c->input));
return 0;
- if (buffer_len(&ch->output) > packet_get_maxsize())
+ }
+ if (buffer_len(&c->output) > packet_get_maxsize()) {
+ debug("channel %d: big output buffer %d",
+ c->self, buffer_len(&c->output));
return 0;
+ }
}
}
return 1;
}
-/* This is called after receiving CHANNEL_CLOSE/IEOF. */
+void
+channel_input_ieof(int type, int plen)
+{
+ int id;
+ Channel *c;
+
+ packet_integrity_check(plen, 4, type);
+
+ id = packet_get_int();
+ c = channel_lookup(id);
+ if (c == NULL)
+ packet_disconnect("Received ieof for nonexistent channel %d.", id);
+ chan_rcvd_ieof(c);
+}
-void
-channel_input_close()
+void
+channel_input_close(int type, int plen)
{
- int channel;
+ int id;
+ Channel *c;
- /* Get the channel number and verify it. */
- channel = packet_get_int();
- if (channel < 0 || channel >= channels_alloc ||
- channels[channel].type == SSH_CHANNEL_FREE)
- packet_disconnect("Received data for nonexistent channel %d.", channel);
-
- if (!compat13) {
- /* proto version 1.5 overloads CLOSE with IEOF */
- chan_rcvd_ieof(&channels[channel]);
- return;
- }
+ packet_integrity_check(plen, 4, type);
+
+ id = packet_get_int();
+ c = channel_lookup(id);
+ if (c == NULL)
+ packet_disconnect("Received close for nonexistent channel %d.", id);
/*
* Send a confirmation that we have closed the channel and no more
* data is coming for it.
*/
packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
- packet_put_int(channels[channel].remote_id);
+ packet_put_int(c->remote_id);
packet_send();
/*
@@ -672,81 +1144,153 @@ channel_input_close()
* no-one to receive the confirmation. The channel gets freed when
* the confirmation arrives.
*/
- if (channels[channel].type != SSH_CHANNEL_CLOSED) {
+ if (c->type != SSH_CHANNEL_CLOSED) {
/*
* Not a closed channel - mark it as draining, which will
* cause it to be freed later.
*/
- buffer_consume(&channels[channel].input,
- buffer_len(&channels[channel].input));
- channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING;
+ buffer_consume(&c->input, buffer_len(&c->input));
+ c->type = SSH_CHANNEL_OUTPUT_DRAINING;
}
}
-/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */
-
-void
-channel_input_close_confirmation()
+/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
+void
+channel_input_oclose(int type, int plen)
{
- int channel;
-
- /* Get the channel number and verify it. */
- channel = packet_get_int();
- if (channel < 0 || channel >= channels_alloc)
- packet_disconnect("Received close confirmation for out-of-range channel %d.",
- channel);
-
- if (!compat13) {
- /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
- chan_rcvd_oclose(&channels[channel]);
- return;
- }
- if (channels[channel].type != SSH_CHANNEL_CLOSED)
- packet_disconnect("Received close confirmation for non-closed channel %d (type %d).",
- channel, channels[channel].type);
-
- /* Free the channel. */
- channel_free(channel);
+ int id = packet_get_int();
+ Channel *c = channel_lookup(id);
+ packet_integrity_check(plen, 4, type);
+ if (c == NULL)
+ packet_disconnect("Received oclose for nonexistent channel %d.", id);
+ chan_rcvd_oclose(c);
}
-/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */
+void
+channel_input_close_confirmation(int type, int plen)
+{
+ int id = packet_get_int();
+ Channel *c = channel_lookup(id);
+
+ packet_done();
+ if (c == NULL)
+ packet_disconnect("Received close confirmation for "
+ "out-of-range channel %d.", id);
+ if (c->type != SSH_CHANNEL_CLOSED)
+ packet_disconnect("Received close confirmation for "
+ "non-closed channel %d (type %d).", id, c->type);
+ channel_free(c->self);
+}
-void
-channel_input_open_confirmation()
+void
+channel_input_open_confirmation(int type, int plen)
{
- int channel, remote_channel;
+ int id, remote_id;
+ Channel *c;
- /* Get the channel number and verify it. */
- channel = packet_get_int();
- if (channel < 0 || channel >= channels_alloc ||
- channels[channel].type != SSH_CHANNEL_OPENING)
- packet_disconnect("Received open confirmation for non-opening channel %d.",
- channel);
+ if (!compat20)
+ packet_integrity_check(plen, 4 + 4, type);
- /* Get remote side's id for this channel. */
- remote_channel = packet_get_int();
+ id = packet_get_int();
+ c = channel_lookup(id);
+ if (c==NULL || c->type != SSH_CHANNEL_OPENING)
+ packet_disconnect("Received open confirmation for "
+ "non-opening channel %d.", id);
+ remote_id = packet_get_int();
/* Record the remote channel number and mark that the channel is now open. */
- channels[channel].remote_id = remote_channel;
- channels[channel].type = SSH_CHANNEL_OPEN;
+ c->remote_id = remote_id;
+ c->type = SSH_CHANNEL_OPEN;
+
+ if (compat20) {
+ c->remote_window = packet_get_int();
+ c->remote_maxpacket = packet_get_int();
+ packet_done();
+ if (c->cb_fn != NULL && c->cb_event == type) {
+ debug("callback start");
+ c->cb_fn(c->self, c->cb_arg);
+ debug("callback done");
+ }
+ debug("channel %d: open confirm rwindow %d rmax %d", c->self,
+ c->remote_window, c->remote_maxpacket);
+ }
+}
+
+void
+channel_input_open_failure(int type, int plen)
+{
+ int id;
+ Channel *c;
+
+ if (!compat20)
+ packet_integrity_check(plen, 4, type);
+
+ id = packet_get_int();
+ c = channel_lookup(id);
+
+ if (c==NULL || c->type != SSH_CHANNEL_OPENING)
+ packet_disconnect("Received open failure for "
+ "non-opening channel %d.", id);
+ if (compat20) {
+ int reason = packet_get_int();
+ char *msg = packet_get_string(NULL);
+ char *lang = packet_get_string(NULL);
+ log("channel_open_failure: %d: reason %d: %s", id, reason, msg);
+ packet_done();
+ xfree(msg);
+ xfree(lang);
+ }
+ /* Free the channel. This will also close the socket. */
+ channel_free(id);
}
-/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */
+void
+channel_input_channel_request(int type, int plen)
+{
+ int id;
+ Channel *c;
+
+ id = packet_get_int();
+ c = channel_lookup(id);
+
+ if (c == NULL ||
+ (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL))
+ packet_disconnect("Received request for "
+ "non-open channel %d.", id);
+ if (c->cb_fn != NULL && c->cb_event == type) {
+ debug("callback start");
+ c->cb_fn(c->self, c->cb_arg);
+ debug("callback done");
+ } else {
+ char *service = packet_get_string(NULL);
+ debug("channel: %d rcvd request for %s", c->self, service);
+debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event);
+ xfree(service);
+ }
+}
-void
-channel_input_open_failure()
+void
+channel_input_window_adjust(int type, int plen)
{
- int channel;
+ Channel *c;
+ int id, adjust;
+
+ if (!compat20)
+ return;
/* Get the channel number and verify it. */
- channel = packet_get_int();
- if (channel < 0 || channel >= channels_alloc ||
- channels[channel].type != SSH_CHANNEL_OPENING)
- packet_disconnect("Received open failure for non-opening channel %d.",
- channel);
+ id = packet_get_int();
+ c = channel_lookup(id);
- /* Free the channel. This will also close the socket. */
- channel_free(channel);
+ if (c == NULL || c->type != SSH_CHANNEL_OPEN) {
+ log("Received window adjust for "
+ "non-open channel %d.", id);
+ return;
+ }
+ adjust = packet_get_int();
+ packet_done();
+ debug("channel %d: rcvd adjust %d", id, adjust);
+ c->remote_window += adjust;
}
/*
@@ -754,7 +1298,7 @@ channel_input_open_failure()
* might have.
*/
-void
+void
channel_stop_listening()
{
int i;
@@ -777,23 +1321,22 @@ channel_stop_listening()
}
/*
- * Closes the sockets of all channels. This is used to close extra file
+ * Closes the sockets/fds of all channels. This is used to close extra file
* descriptors after a fork.
*/
-void
+void
channel_close_all()
{
int i;
- for (i = 0; i < channels_alloc; i++) {
+ for (i = 0; i < channels_alloc; i++)
if (channels[i].type != SSH_CHANNEL_FREE)
- close(channels[i].sock);
- }
+ channel_close_fds(&channels[i]);
}
/* Returns the maximum file descriptor number used by the channels. */
-int
+int
channel_max_fd()
{
return channel_max_fd_value;
@@ -801,7 +1344,7 @@ channel_max_fd()
/* Returns true if any channel is still open. */
-int
+int
channel_still_open()
{
unsigned int i;
@@ -813,6 +1356,10 @@ channel_still_open()
case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_AUTH_SOCKET:
continue;
+ case SSH_CHANNEL_LARVAL:
+ if (!compat20)
+ fatal("cannot happen: SSH_CHANNEL_LARVAL");
+ continue;
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_X11_OPEN:
@@ -854,20 +1401,22 @@ channel_open_message()
case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_AUTH_SOCKET:
continue;
+ case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_INPUT_DRAINING:
case SSH_CHANNEL_OUTPUT_DRAINING:
- snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d)\r\n",
+ snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
c->self, c->remote_name,
c->type, c->remote_id,
c->istate, buffer_len(&c->input),
- c->ostate, buffer_len(&c->output));
+ c->ostate, buffer_len(&c->output),
+ c->rfd, c->wfd);
buffer_append(&buffer, buf, strlen(buf));
continue;
default:
- fatal("channel_still_open: bad channel type %d", c->type);
+ fatal("channel_open_message: bad channel type %d", c->type);
/* NOTREACHED */
}
}
@@ -882,7 +1431,7 @@ channel_open_message()
* channel to host:port from remote side.
*/
-void
+void
channel_request_local_forwarding(u_short port, const char *host,
u_short host_port, int gateway_ports)
{
@@ -946,8 +1495,11 @@ channel_request_local_forwarding(u_short port, const char *host,
continue;
}
/* Allocate a channel number for the socket. */
- ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock,
- xstrdup("port listener"));
+ ch = channel_new(
+ "port listener", SSH_CHANNEL_PORT_LISTENER,
+ sock, sock, -1,
+ CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+ 0, xstrdup("port listener"));
strlcpy(channels[ch].path, host, sizeof(channels[ch].path));
channels[ch].host_port = host_port;
channels[ch].listening_port = port;
@@ -963,32 +1515,41 @@ channel_request_local_forwarding(u_short port, const char *host,
* the secure channel to host:port from local side.
*/
-void
-channel_request_remote_forwarding(u_short port, const char *host,
- u_short remote_port)
+void
+channel_request_remote_forwarding(u_short listen_port, const char *host_to_connect,
+ u_short port_to_connect)
{
int payload_len;
/* Record locally that connection to this host/port is permitted. */
if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("channel_request_remote_forwarding: too many forwards");
- permitted_opens[num_permitted_opens].host = xstrdup(host);
- permitted_opens[num_permitted_opens].port = remote_port;
+ permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
+ permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
+ permitted_opens[num_permitted_opens].listen_port = listen_port;
num_permitted_opens++;
/* Send the forward request to the remote side. */
- packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
- packet_put_int(port);
- packet_put_string(host, strlen(host));
- packet_put_int(remote_port);
- packet_send();
- packet_write_wait();
-
- /*
- * Wait for response from the remote side. It will send a disconnect
- * message on failure, and we will never see it here.
- */
- packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
+ if (compat20) {
+ const char *address_to_bind = "0.0.0.0";
+ packet_start(SSH2_MSG_GLOBAL_REQUEST);
+ packet_put_cstring("tcpip-forward");
+ packet_put_char(0); /* boolean: want reply */
+ packet_put_cstring(address_to_bind);
+ packet_put_int(listen_port);
+ } else {
+ packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
+ packet_put_int(listen_port);
+ packet_put_cstring(host_to_connect);
+ packet_put_int(port_to_connect);
+ packet_send();
+ packet_write_wait();
+ /*
+ * Wait for response from the remote side. It will send a disconnect
+ * message on failure, and we will never see it here.
+ */
+ packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
+ }
}
/*
@@ -997,8 +1558,8 @@ channel_request_remote_forwarding(u_short port, const char *host,
* message if there was an error). This never returns if there was an error.
*/
-void
-channel_input_port_forward_request(int is_root)
+void
+channel_input_port_forward_request(int is_root, int gateway_ports)
{
u_short port, host_port;
char *hostname;
@@ -1017,69 +1578,21 @@ channel_input_port_forward_request(int is_root)
port);
/*
* Initiate forwarding,
- * bind port to localhost only (gateway ports == 0).
*/
- channel_request_local_forwarding(port, hostname, host_port, 0);
+ channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
/* Free the argument string. */
xfree(hostname);
}
-/*
- * This is called after receiving PORT_OPEN message. This attempts to
- * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
- * or CHANNEL_OPEN_FAILURE.
- */
-
-void
-channel_input_port_open(int payload_len)
+/* XXX move to aux.c */
+int
+channel_connect_to(const char *host, u_short host_port)
{
- int remote_channel, sock = 0, newch, i;
- u_short host_port;
- char *host, *originator_string;
- unsigned int host_len, originator_len;
struct addrinfo hints, *ai, *aitop;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
int gaierr;
-
- /* Get remote channel number. */
- remote_channel = packet_get_int();
-
- /* Get host name to connect to. */
- host = packet_get_string(&host_len);
-
- /* Get port to connect to. */
- host_port = packet_get_int();
-
- /* Get remote originator name. */
- if (have_hostname_in_open) {
- originator_string = packet_get_string(&originator_len);
- originator_len += 4; /* size of packet_int */
- } else {
- originator_string = xstrdup("unknown (remote did not supply name)");
- originator_len = 0; /* no originator supplied */
- }
-
- packet_integrity_check(payload_len,
- 4 + 4 + host_len + 4 + originator_len,
- SSH_MSG_PORT_OPEN);
-
- /* Check if opening that port is permitted. */
- if (!all_opens_permitted) {
- /* Go trough all permitted ports. */
- for (i = 0; i < num_permitted_opens; i++)
- if (permitted_opens[i].port == host_port &&
- strcmp(permitted_opens[i].host, host) == 0)
- break;
-
- /* Check if we found the requested port among those permitted. */
- if (i >= num_permitted_opens) {
- /* The port is not permitted. */
- log("Received request to connect to %.100s:%d, but the request was denied.",
- host, host_port);
- goto fail;
- }
- }
+ int sock = -1;
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
@@ -1087,15 +1600,14 @@ channel_input_port_open(int payload_len)
snprintf(strport, sizeof strport, "%d", host_port);
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
error("%.100s: unknown host (%s)", host, gai_strerror(gaierr));
- goto fail;
+ return -1;
}
-
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- error("channel_input_port_open: getnameinfo failed");
+ error("channel_connect_to: getnameinfo failed");
continue;
}
/* Create the socket. */
@@ -1115,37 +1627,81 @@ channel_input_port_open(int payload_len)
}
freeaddrinfo(aitop);
-
if (!ai) {
error("connect %.100s port %d: failed.", host, host_port);
- goto fail;
+ return -1;
}
+ /* success */
+ return sock;
+}
+/*
+ * 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.
+ */
- /* Successful connection. */
+void
+channel_input_port_open(int type, int plen)
+{
+ u_short host_port;
+ char *host, *originator_string;
+ int remote_channel, sock = -1, newch, i, denied;
+ unsigned int host_len, originator_len;
- /* Allocate a channel for this connection. */
- newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);
- channels[newch].remote_id = remote_channel;
+ /* Get remote channel number. */
+ remote_channel = packet_get_int();
- /* Send a confirmation to the remote host. */
- packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(remote_channel);
- packet_put_int(newch);
- packet_send();
+ /* Get host name to connect to. */
+ host = packet_get_string(&host_len);
- /* Free the argument string. */
- xfree(host);
+ /* Get port to connect to. */
+ host_port = packet_get_int();
+
+ /* Get remote originator name. */
+ if (have_hostname_in_open) {
+ originator_string = packet_get_string(&originator_len);
+ originator_len += 4; /* size of packet_int */
+ } else {
+ originator_string = xstrdup("unknown (remote did not supply name)");
+ originator_len = 0; /* no originator supplied */
+ }
- return;
+ packet_integrity_check(plen,
+ 4 + 4 + host_len + 4 + originator_len, SSH_MSG_PORT_OPEN);
-fail:
- /* Free the argument string. */
- xfree(host);
+ /* Check if opening that port is permitted. */
+ denied = 0;
+ if (!all_opens_permitted) {
+ /* Go trough all permitted ports. */
+ for (i = 0; i < num_permitted_opens; i++)
+ if (permitted_opens[i].port_to_connect == host_port &&
+ strcmp(permitted_opens[i].host_to_connect, host) == 0)
+ break;
- /* Send refusal to the remote host. */
- packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(remote_channel);
- packet_send();
+ /* Check if we found the requested port among those permitted. */
+ if (i >= num_permitted_opens) {
+ /* The port is not permitted. */
+ log("Received request to connect to %.100s:%d, but the request was denied.",
+ host, host_port);
+ denied = 1;
+ }
+ }
+ sock = denied ? -1 : channel_connect_to(host, host_port);
+ if (sock > 0) {
+ /* Allocate a channel for this connection. */
+ newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string);
+ channels[newch].remote_id = remote_channel;
+
+ packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+ packet_put_int(remote_channel);
+ packet_put_int(newch);
+ packet_send();
+ } else {
+ packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+ packet_put_int(remote_channel);
+ packet_send();
+ }
+ xfree(host);
}
/*
@@ -1230,8 +1786,10 @@ x11_create_display_inet(int screen_number, int x11_display_offset)
/* Allocate a channel for each socket. */
for (n = 0; n < num_socks; n++) {
sock = socks[n];
- (void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,
- xstrdup("X11 inet listener"));
+ (void) channel_new("x11 listener",
+ SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
+ CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
+ 0, xstrdup("X11 inet listener"));
}
/* Return a suitable value for the DISPLAY environment variable. */
@@ -1271,44 +1829,21 @@ connect_local_xsocket(unsigned int dnr)
return -1;
}
-
-/*
- * 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)
+int
+x11_connect_display(void)
{
- int remote_channel, display_number, sock = 0, newch;
+ int display_number, sock = 0;
const char *display;
- char buf[1024], *cp, *remote_host;
- unsigned int remote_len;
+ char buf[1024], *cp;
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr;
- /* Get remote channel number. */
- remote_channel = packet_get_int();
-
- /* Get remote originator name. */
- if (have_hostname_in_open) {
- remote_host = packet_get_string(&remote_len);
- remote_len += 4;
- } else {
- remote_host = xstrdup("unknown (remote did not supply name)");
- remote_len = 0;
- }
-
- debug("Received X11 open request.");
- packet_integrity_check(payload_len, 4 + remote_len, SSH_SMSG_X11_OPEN);
-
/* Try to open a socket for the local X server. */
display = getenv("DISPLAY");
if (!display) {
error("DISPLAY not set.");
- goto fail;
+ return -1;
}
/*
* Now we decode the value of the DISPLAY variable and make a
@@ -1325,15 +1860,15 @@ x11_input_open(int payload_len)
if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s",
display);
- goto fail;
+ return -1;
}
/* Create a socket. */
sock = connect_local_xsocket(display_number);
if (sock < 0)
- goto fail;
+ return -1;
/* OK, we now have a connection to the display. */
- goto success;
+ return sock;
}
/*
* Connect to an inet socket. The DISPLAY value is supposedly
@@ -1344,14 +1879,14 @@ x11_input_open(int payload_len)
cp = strchr(buf, ':');
if (!cp) {
error("Could not find ':' in DISPLAY: %.100s", display);
- goto fail;
+ return -1;
}
*cp = 0;
/* buf now contains the host name. But first we parse the display number. */
if (sscanf(cp + 1, "%d", &display_number) != 1) {
error("Could not parse display number from DISPLAY: %.100s",
display);
- goto fail;
+ return -1;
}
/* Look up the host address */
@@ -1361,55 +1896,83 @@ x11_input_open(int payload_len)
snprintf(strport, sizeof strport, "%d", 6000 + display_number);
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));
- goto fail;
+ return -1;
}
for (ai = aitop; ai; ai = ai->ai_next) {
/* Create a socket. */
sock = socket(ai->ai_family, SOCK_STREAM, 0);
if (sock < 0) {
debug("socket: %.100s", strerror(errno));
- continue;
- }
- /* Connect it to the display. */
- if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- debug("connect %.100s port %d: %.100s", buf, 6000 + display_number,
- strerror(errno));
- close(sock);
- continue;
+ continue;
+ }
+ /* Connect it to the display. */
+ if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+ debug("connect %.100s port %d: %.100s", buf,
+ 6000 + display_number, strerror(errno));
+ close(sock);
+ continue;
+ }
+ /* Success */
+ break;
}
- /* Success */
- break;
-
- } /* (ai = aitop, ai; ai = ai->ai_next) */
freeaddrinfo(aitop);
if (!ai) {
- error("connect %.100s port %d: %.100s", buf, 6000 + display_number,
+ error("connect %.100s port %d: %.100s", buf, 6000 + display_number,
strerror(errno));
- goto fail;
+ return -1;
}
-success:
- /* We have successfully obtained a connection to the real X display. */
+ return sock;
+}
- /* Allocate a channel for this connection. */
- if (x11_saved_proto == NULL)
- newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host);
- else
- newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host);
- channels[newch].remote_id = remote_channel;
+/*
+ * 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.
+ */
- /* Send a confirmation to the remote host. */
- packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
- packet_put_int(remote_channel);
- packet_put_int(newch);
- packet_send();
+void
+x11_input_open(int type, int plen)
+{
+ int remote_channel, sock = 0, newch;
+ char *remote_host;
+ unsigned int remote_len;
- return;
+ /* Get remote channel number. */
+ remote_channel = packet_get_int();
-fail:
- /* Send refusal to the remote host. */
- packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
- packet_put_int(remote_channel);
- packet_send();
+ /* Get remote originator name. */
+ if (have_hostname_in_open) {
+ remote_host = packet_get_string(&remote_len);
+ remote_len += 4;
+ } else {
+ remote_host = xstrdup("unknown (remote did not supply name)");
+ remote_len = 0;
+ }
+
+ debug("Received X11 open request.");
+ packet_integrity_check(plen, 4 + remote_len, SSH_SMSG_X11_OPEN);
+
+ /* Obtain a connection to the real X display. */
+ sock = x11_connect_display();
+ if (sock == -1) {
+ /* Send refusal to the remote host. */
+ packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+ packet_put_int(remote_channel);
+ packet_send();
+ } else {
+ /* Allocate a channel for this connection. */
+ newch = channel_allocate(
+ (x11_saved_proto == NULL) ?
+ SSH_CHANNEL_OPEN : SSH_CHANNEL_X11_OPEN,
+ sock, remote_host);
+ channels[newch].remote_id = remote_channel;
+
+ /* Send a confirmation to the remote host. */
+ packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+ packet_put_int(remote_channel);
+ packet_put_int(newch);
+ packet_send();
+ }
}
/*
@@ -1417,8 +1980,9 @@ fail:
* data, and enables authentication spoofing.
*/
-void
-x11_request_forwarding_with_spoofing(const char *proto, const char *data)
+void
+x11_request_forwarding_with_spoofing(int client_session_id,
+ const char *proto, const char *data)
{
unsigned int data_len = (unsigned int) strlen(data) / 2;
unsigned int i, value;
@@ -1464,9 +2028,14 @@ x11_request_forwarding_with_spoofing(const char *proto, const char *data)
sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]);
/* Send the request packet. */
- packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
- packet_put_string(proto, strlen(proto));
- packet_put_string(new_data, strlen(new_data));
+ if (compat20) {
+ channel_request_start(client_session_id, "x11-req", 0);
+ packet_put_char(0); /* XXX bool single connection */
+ } else {
+ packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
+ }
+ packet_put_cstring(proto);
+ packet_put_cstring(new_data);
packet_put_int(screen_number);
packet_send();
packet_write_wait();
@@ -1475,7 +2044,7 @@ x11_request_forwarding_with_spoofing(const char *proto, const char *data)
/* Sends a message to the server to request authentication fd forwarding. */
-void
+void
auth_request_forwarding()
{
packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
@@ -1497,7 +2066,7 @@ auth_get_socket_name()
/* removes the agent forwarding socket */
-void
+void
cleanup_socket(void)
{
remove(channel_forwarded_auth_socket_name);
@@ -1509,7 +2078,7 @@ cleanup_socket(void)
* This starts forwarding authentication requests.
*/
-void
+void
auth_input_request_forwarding(struct passwd * pw)
{
int sock, newch;
@@ -1567,12 +2136,14 @@ auth_input_request_forwarding(struct passwd * pw)
/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
-void
-auth_input_open_request()
+void
+auth_input_open_request(int type, int plen)
{
int remch, sock, newch;
char *dummyname;
+ packet_integrity_check(plen, 4, type);
+
/* Read the remote channel number from the message. */
remch = packet_get_int();
@@ -1612,3 +2183,95 @@ auth_input_open_request()
packet_put_int(newch);
packet_send();
}
+
+void
+channel_start_open(int id)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_open: %d: bad id", id);
+ return;
+ }
+ debug("send channel open %d", id);
+ packet_start(SSH2_MSG_CHANNEL_OPEN);
+ packet_put_cstring(c->ctype);
+ packet_put_int(c->self);
+ packet_put_int(c->local_window);
+ packet_put_int(c->local_maxpacket);
+}
+void
+channel_open(int id)
+{
+ /* XXX REMOVE ME */
+ channel_start_open(id);
+ packet_send();
+}
+void
+channel_request(int id, char *service, int wantconfirm)
+{
+ channel_request_start(id, service, wantconfirm);
+ packet_send();
+ debug("channel request %d: %s", id, service) ;
+}
+void
+channel_request_start(int id, char *service, int wantconfirm)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_request: %d: bad id", id);
+ return;
+ }
+ packet_start(SSH2_MSG_CHANNEL_REQUEST);
+ packet_put_int(c->remote_id);
+ packet_put_cstring(service);
+ packet_put_char(wantconfirm);
+}
+void
+channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_register_callback: %d: bad id", id);
+ return;
+ }
+ c->cb_event = mtype;
+ c->cb_fn = fn;
+ c->cb_arg = arg;
+}
+void
+channel_register_cleanup(int id, channel_callback_fn *fn)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_register_cleanup: %d: bad id", id);
+ return;
+ }
+ c->dettach_user = fn;
+}
+void
+channel_cancel_cleanup(int id)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL) {
+ log("channel_cancel_cleanup: %d: bad id", id);
+ return;
+ }
+ c->dettach_user = NULL;
+}
+
+void
+channel_set_fds(int id, int rfd, int wfd, int efd, int extusage)
+{
+ Channel *c = channel_lookup(id);
+ if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
+ fatal("channel_activate for non-larval channel %d.", id);
+
+ channel_register_fds(c, rfd, wfd, efd, extusage);
+ c->type = SSH_CHANNEL_OPEN;
+ /* XXX window size? */
+ c->local_window = c->local_window_max = c->local_maxpacket/2;
+ packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ packet_put_int(c->remote_id);
+ packet_put_int(c->local_window);
+ packet_send();
+}
diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h
index 93a7b539b76e..24ae2b8288f8 100644
--- a/crypto/openssh/channels.h
+++ b/crypto/openssh/channels.h
@@ -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
diff --git a/crypto/openssh/cipher.c b/crypto/openssh/cipher.c
index 682a980175c3..bcaff024db26 100644
--- a/crypto/openssh/cipher.c
+++ b/crypto/openssh/cipher.c
@@ -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));
}
diff --git a/crypto/openssh/cipher.h b/crypto/openssh/cipher.h
index a6f458a54de9..197d9541eaf2 100644
--- a/crypto/openssh/cipher.h
+++ b/crypto/openssh/cipher.h
@@ -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);
diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c
index 59dad3d7d308..b4c7b287dfae 100644
--- a/crypto/openssh/clientloop.c
+++ b/crypto/openssh/clientloop.c
@@ -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;
-
- /* Clear the window change indicator. */
- 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();
- }
+ struct winsize ws;
+
+ if (! received_window_change_signal)
+ return;
+ /** XXX race */
+ received_window_change_signal = 0;
+
+ 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,26 +313,36 @@ 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);
+ FD_ZERO(writeset);
- /* 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())
+ 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);
-
- /*
- * 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);
+ }
/* 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;
@@ -776,13 +707,31 @@ 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
* remote host. If escape_char != -1, it is the character used as an escape
* 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);
+}
diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c
index 7e21fd080a81..33e509cb89b2 100644
--- a/crypto/openssh/compat.c
+++ b/crypto/openssh/compat.c
@@ -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;
+}
diff --git a/crypto/openssh/compat.h b/crypto/openssh/compat.h
index 68d5e2bd7921..9308a6df3016 100644
--- a/crypto/openssh/compat.h
+++ b/crypto/openssh/compat.h
@@ -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
diff --git a/crypto/openssh/compress.c b/crypto/openssh/compress.c
index 03e508173969..86ccaa28ae21 100644
--- a/crypto/openssh/compress.c
+++ b/crypto/openssh/compress.c
@@ -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 */
}
}
}
diff --git a/crypto/openssh/compress.h b/crypto/openssh/compress.h
index 4e9c598abf5e..f97561322590 100644
--- a/crypto/openssh/compress.h
+++ b/crypto/openssh/compress.h
@@ -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
diff --git a/crypto/openssh/crc32.h b/crypto/openssh/crc32.h
index 54299fccb114..4176e8a5f7c8 100644
--- a/crypto/openssh/crc32.h
+++ b/crypto/openssh/crc32.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
diff --git a/crypto/openssh/dispatch.c b/crypto/openssh/dispatch.c
new file mode 100644
index 000000000000..9b7def746854
--- /dev/null
+++ b/crypto/openssh/dispatch.c
@@ -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;
+ }
+}
diff --git a/crypto/openssh/dispatch.h b/crypto/openssh/dispatch.h
new file mode 100644
index 000000000000..12084aafe07a
--- /dev/null
+++ b/crypto/openssh/dispatch.h
@@ -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);
diff --git a/crypto/openssh/dsa.c b/crypto/openssh/dsa.c
new file mode 100644
index 000000000000..51d7ff285242
--- /dev/null
+++ b/crypto/openssh/dsa.c
@@ -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;
+}
diff --git a/crypto/openssh/dsa.h b/crypto/openssh/dsa.h
new file mode 100644
index 000000000000..3cece7c1f22b
--- /dev/null
+++ b/crypto/openssh/dsa.h
@@ -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
diff --git a/crypto/openssh/fingerprint.c b/crypto/openssh/fingerprint.c
index c001ca2b86e2..4b0966d91557 100644
--- a/crypto/openssh/fingerprint.c
+++ b/crypto/openssh/fingerprint.c
@@ -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"
diff --git a/crypto/openssh/getput.h b/crypto/openssh/getput.h
index d2e138089a4f..e1aa9bb64b1d 100644
--- a/crypto/openssh/getput.h
+++ b/crypto/openssh/getput.h
@@ -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]))
diff --git a/crypto/openssh/hmac.c b/crypto/openssh/hmac.c
new file mode 100644
index 000000000000..fe53aa47e7c0
--- /dev/null
+++ b/crypto/openssh/hmac.c
@@ -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);
+}
diff --git a/crypto/openssh/hmac.h b/crypto/openssh/hmac.h
new file mode 100644
index 000000000000..fb6802927392
--- /dev/null
+++ b/crypto/openssh/hmac.h
@@ -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
diff --git a/crypto/openssh/hostfile.c b/crypto/openssh/hostfile.c
index eca68da730d4..bac285da50f9 100644
--- a/crypto/openssh/hostfile.c
+++ b/crypto/openssh/hostfile.c
@@ -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;
}
diff --git a/crypto/openssh/hostfile.h b/crypto/openssh/hostfile.h
index 64fe185da9fa..c9bdd7f2e495 100644
--- a/crypto/openssh/hostfile.h
+++ b/crypto/openssh/hostfile.h
@@ -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);
/*
diff --git a/crypto/openssh/includes.h b/crypto/openssh/includes.h
index 68690e3a53f8..ef374dfe808f 100644
--- a/crypto/openssh/includes.h
+++ b/crypto/openssh/includes.h
@@ -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
diff --git a/crypto/openssh/kex.c b/crypto/openssh/kex.c
new file mode 100644
index 000000000000..c10c77ead605
--- /dev/null
+++ b/crypto/openssh/kex.c
@@ -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;
+}
diff --git a/crypto/openssh/kex.h b/crypto/openssh/kex.h
new file mode 100644
index 000000000000..5395ebc3f085
--- /dev/null
+++ b/crypto/openssh/kex.h
@@ -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
diff --git a/crypto/openssh/key.c b/crypto/openssh/key.c
index 6ad35cbac9d9..ae355a3fcdc6 100644
--- a/crypto/openssh/key.c
+++ b/crypto/openssh/key.c
@@ -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)
- return 0;
- if (!read_bignum(cpp, ret->dsa->p))
+ if (strncmp(cp, SSH_DSS " ", 7) != 0)
return 0;
- if (!read_bignum(cpp, ret->dsa->q))
+ 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->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";
+}
diff --git a/crypto/openssh/key.h b/crypto/openssh/key.h
index 70f0c518b8ab..ed3f770b8be9 100644
--- a/crypto/openssh/key.h
+++ b/crypto/openssh/key.h
@@ -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
diff --git a/crypto/openssh/lib/Makefile b/crypto/openssh/lib/Makefile
index 4a9ce1cb0aea..35de105b496d 100644
--- a/crypto/openssh/lib/Makefile
+++ b/crypto/openssh/lib/Makefile
@@ -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
diff --git a/crypto/openssh/log-client.c b/crypto/openssh/log-client.c
index 9e20a313afc4..1e3c162cb37e 100644
--- a/crypto/openssh/log-client.c
+++ b/crypto/openssh/log-client.c
@@ -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"
diff --git a/crypto/openssh/log-server.c b/crypto/openssh/log-server.c
index 124d7fe6b69b..81ba67371f07 100644
--- a/crypto/openssh/log-server.c
+++ b/crypto/openssh/log-server.c
@@ -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();
+ }
}
diff --git a/crypto/openssh/login.c b/crypto/openssh/login.c
index 574a9cc88c6d..8e40784e2cb0 100644
--- a/crypto/openssh/login.c
+++ b/crypto/openssh/login.c
@@ -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))
diff --git a/crypto/openssh/match.c b/crypto/openssh/match.c
index aadcfd6e940b..00dff8a86130 100644
--- a/crypto/openssh/match.c
+++ b/crypto/openssh/match.c
@@ -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 (;;) {
diff --git a/crypto/openssh/mpaux.c b/crypto/openssh/mpaux.c
index 1508650119dc..3442070e41b2 100644
--- a/crypto/openssh/mpaux.c
+++ b/crypto/openssh/mpaux.c
@@ -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);
diff --git a/crypto/openssh/mpaux.h b/crypto/openssh/mpaux.h
index 6b30fe03c4a9..671fc511a929 100644
--- a/crypto/openssh/mpaux.h
+++ b/crypto/openssh/mpaux.h
@@ -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,
diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h
new file mode 100644
index 000000000000..8b24179724f3
--- /dev/null
+++ b/crypto/openssh/myproposal.h
@@ -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
+};
diff --git a/crypto/openssh/nchan.c b/crypto/openssh/nchan.c
index 1f30a7cf2c6b..fd92fe8f653f 100644
--- a/crypto/openssh/nchan.c
+++ b/crypto/openssh/nchan.c
@@ -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);
+ }
+}
-/* helper */
+/*
+ * the same for SSH2
+ */
static void
-chan_shutdown_write(Channel *c)
+chan_rcvd_oclose2(Channel *c)
{
- /* 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: 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_shutdown_read(Channel *c)
+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: 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));
+ 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_delete_if_full_closed(Channel *c)
+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) {
- debug("channel %d: full closed", c->self);
- channel_free(c->self);
+ 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: 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)
+{
+ 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;
+ }
}
diff --git a/crypto/openssh/nchan.h b/crypto/openssh/nchan.h
index 3397be8a54bf..0a2cf35f781f 100644
--- a/crypto/openssh/nchan.h
+++ b/crypto/openssh/nchan.h
@@ -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
diff --git a/crypto/openssh/nchan2.ms b/crypto/openssh/nchan2.ms
new file mode 100644
index 000000000000..1b119d1353bf
--- /dev/null
+++ b/crypto/openssh/nchan2.ms
@@ -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.
diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c
index af54759233b7..5fa76a315b5e 100644
--- a/crypto/openssh/packet.c
+++ b/crypto/openssh/packet.c
@@ -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);
@@ -418,6 +511,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
* be used during the interactive session.
@@ -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 @@ restart:
/* 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 @@ restart:
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 @@ restart:
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 @@ restart:
/* 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) {
diff --git a/crypto/openssh/packet.h b/crypto/openssh/packet.h
index 66a35286d6a5..ac96c505af4b 100644
--- a/crypto/openssh/packet.h
+++ b/crypto/openssh/packet.h
@@ -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 */
diff --git a/crypto/openssh/pty.c b/crypto/openssh/pty.c
index 86da668286b2..430f9e529501 100644
--- a/crypto/openssh/pty.c
+++ b/crypto/openssh/pty.c
@@ -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)
{
diff --git a/crypto/openssh/pty.h b/crypto/openssh/pty.h
index 7d8e09d0d86d..a5f9cb22dcc1 100644
--- a/crypto/openssh/pty.h
+++ b/crypto/openssh/pty.h
@@ -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);
diff --git a/crypto/openssh/radix.c b/crypto/openssh/radix.c
index ea7f5ba2bcac..033773344152 100644
--- a/crypto/openssh/radix.c
+++ b/crypto/openssh/radix.c
@@ -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;
diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c
index e9c8455bf100..2053c67aa2bc 100644
--- a/crypto/openssh/readconf.c
+++ b/crypto/openssh/readconf.c
@@ -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 @@ parse_flag:
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 @@ parse_flag:
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 @@ parse_string:
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 @@ parse_int:
*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 @@ parse_int:
* 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 */
diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h
index 1d22002fa3ff..7ee91571186c 100644
--- a/crypto/openssh/readconf.h
+++ b/crypto/openssh/readconf.h
@@ -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);
diff --git a/crypto/openssh/readpass.c b/crypto/openssh/readpass.c
index deb37cab6349..85d88f804610 100644
--- a/crypto/openssh/readpass.c
+++ b/crypto/openssh/readpass.c
@@ -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;
diff --git a/crypto/openssh/rsa.c b/crypto/openssh/rsa.c
index 955a3f5fd650..002c1cc4f8f0 100644
--- a/crypto/openssh/rsa.c
+++ b/crypto/openssh/rsa.c
@@ -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"
diff --git a/crypto/openssh/rsa.h b/crypto/openssh/rsa.h
index 2e33cee50812..16e319d43129 100644
--- a/crypto/openssh/rsa.h
+++ b/crypto/openssh/rsa.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);
diff --git a/crypto/openssh/scp.1 b/crypto/openssh/scp.1
index 8e93e23d3fd3..51de6c5e8175 100644
--- a/crypto/openssh/scp.1
+++ b/crypto/openssh/scp.1
@@ -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
diff --git a/crypto/openssh/scp.c b/crypto/openssh/scp.c
index 915ef97e7f3c..491a78907fca 100644
--- a/crypto/openssh/scp.c
+++ b/crypto/openssh/scp.c
@@ -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;
}
}
diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c
index 15b326f918d8..57f7050dbb42 100644
--- a/crypto/openssh/servconf.c
+++ b/crypto/openssh/servconf.c
@@ -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 @@ parse_int:
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 @@ parse_flag:
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 @@ parse_flag:
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 @@ parse_flag:
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);
diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h
index dd4caf741bb9..4fa6deea6f55 100644
--- a/crypto/openssh/servconf.h
+++ b/crypto/openssh/servconf.h
@@ -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. */
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c
index a5ecfe97d5d7..9bf31275beaf 100644
--- a/crypto/openssh/serverloop.c
+++ b/crypto/openssh/serverloop.c
@@ -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 @@ retry_select:
* 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 @@ retry_select:
/* 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 @@ retry_select:
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 @@ retry_select:
* 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 @@ quit:
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();
+}
diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c
new file mode 100644
index 000000000000..53d20c59cf25
--- /dev/null
+++ b/crypto/openssh/session.c
@@ -0,0 +1,1516 @@
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ */
+/*
+ * SSH2 support by Markus Friedl.
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: session.c,v 1.12 2000/05/03 18:03:07 markus Exp $");
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "pty.h"
+#include "packet.h"
+#include "buffer.h"
+#include "cipher.h"
+#include "mpaux.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "channels.h"
+#include "nchan.h"
+
+#include "bufaux.h"
+#include "ssh2.h"
+#include "auth.h"
+
+/* types */
+
+#define TTYSZ 64
+typedef struct Session Session;
+struct Session {
+ int used;
+ int self;
+ int extended;
+ struct passwd *pw;
+ pid_t pid;
+ /* tty */
+ char *term;
+ int ptyfd, ttyfd, ptymaster;
+ int row, col, xpixel, ypixel;
+ char tty[TTYSZ];
+ /* X11 */
+ char *display;
+ int screen;
+ char *auth_proto;
+ char *auth_data;
+ int single_connection;
+ /* proto 2 */
+ int chanid;
+};
+
+/* func */
+
+Session *session_new(void);
+void session_set_fds(Session *s, int fdin, int fdout, int fderr);
+void session_pty_cleanup(Session *s);
+void session_proctitle(Session *s);
+void do_exec_pty(Session *s, const char *command, struct passwd * pw);
+void do_exec_no_pty(Session *s, const char *command, struct passwd * pw);
+
+void
+do_child(const char *command, struct passwd * pw, const char *term,
+ const char *display, const char *auth_proto,
+ const char *auth_data, const char *ttyname);
+
+/* import */
+extern ServerOptions options;
+extern char *__progname;
+extern int log_stderr;
+extern int debug_flag;
+
+/* Local Xauthority file. */
+static char *xauthfile;
+
+/* data */
+#define MAX_SESSIONS 10
+Session sessions[MAX_SESSIONS];
+
+/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
+int no_port_forwarding_flag = 0;
+int no_agent_forwarding_flag = 0;
+int no_x11_forwarding_flag = 0;
+int no_pty_flag = 0;
+
+/* RSA authentication "command=" option. */
+char *forced_command = NULL;
+
+/* RSA authentication "environment=" options. */
+struct envstring *custom_environment = NULL;
+
+/*
+ * Remove local Xauthority file.
+ */
+void
+xauthfile_cleanup_proc(void *ignore)
+{
+ debug("xauthfile_cleanup_proc called");
+
+ if (xauthfile != NULL) {
+ char *p;
+ unlink(xauthfile);
+ p = strrchr(xauthfile, '/');
+ if (p != NULL) {
+ *p = '\0';
+ rmdir(xauthfile);
+ }
+ xfree(xauthfile);
+ xauthfile = NULL;
+ }
+}
+
+/*
+ * Function to perform cleanup if we get aborted abnormally (e.g., due to a
+ * dropped connection).
+ */
+void
+pty_cleanup_proc(void *session)
+{
+ Session *s=session;
+ if (s == NULL)
+ fatal("pty_cleanup_proc: no session");
+ debug("pty_cleanup_proc: %s", s->tty);
+
+ if (s->pid != 0) {
+ /* Record that the user has logged out. */
+ record_logout(s->pid, s->tty);
+ }
+
+ /* Release the pseudo-tty. */
+ pty_release(s->tty);
+}
+
+/*
+ * Prepares for an interactive session. This is called after the user has
+ * been successfully authenticated. During this message exchange, pseudo
+ * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
+ * are requested, etc.
+ */
+void
+do_authenticated(struct passwd * pw)
+{
+ Session *s;
+ int type;
+ int compression_level = 0, enable_compression_after_reply = 0;
+ int have_pty = 0;
+ char *command;
+ int n_bytes;
+ int plen;
+ unsigned int proto_len, data_len, dlen;
+
+ /*
+ * Cancel the alarm we set to limit the time taken for
+ * authentication.
+ */
+ alarm(0);
+
+ /*
+ * Inform the channel mechanism that we are the server side and that
+ * the client may request to connect to any port at all. (The user
+ * could do it anyway, and we wouldn\'t know what is permitted except
+ * by the client telling us, so we can equally well trust the client
+ * not to request anything bogus.)
+ */
+ if (!no_port_forwarding_flag)
+ channel_permit_all_opens();
+
+ s = session_new();
+ s->pw = pw;
+
+ /*
+ * We stay in this loop until the client requests to execute a shell
+ * or a command.
+ */
+ for (;;) {
+ int success = 0;
+
+ /* Get a packet from the client. */
+ type = packet_read(&plen);
+
+ /* Process the packet. */
+ switch (type) {
+ case SSH_CMSG_REQUEST_COMPRESSION:
+ packet_integrity_check(plen, 4, type);
+ compression_level = packet_get_int();
+ if (compression_level < 1 || compression_level > 9) {
+ packet_send_debug("Received illegal compression level %d.",
+ compression_level);
+ break;
+ }
+ /* Enable compression after we have responded with SUCCESS. */
+ enable_compression_after_reply = 1;
+ success = 1;
+ break;
+
+ case SSH_CMSG_REQUEST_PTY:
+ if (no_pty_flag) {
+ debug("Allocating a pty not permitted for this authentication.");
+ break;
+ }
+ if (have_pty)
+ packet_disconnect("Protocol error: you already have a pty.");
+
+ debug("Allocating pty.");
+
+ /* Allocate a pty and open it. */
+ if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
+ sizeof(s->tty))) {
+ error("Failed to allocate pty.");
+ break;
+ }
+ fatal_add_cleanup(pty_cleanup_proc, (void *)s);
+ pty_setowner(pw, s->tty);
+
+ /* Get TERM from the packet. Note that the value may be of arbitrary length. */
+ s->term = packet_get_string(&dlen);
+ packet_integrity_check(dlen, strlen(s->term), type);
+ /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
+ /* Remaining bytes */
+ n_bytes = plen - (4 + dlen + 4 * 4);
+
+ if (strcmp(s->term, "") == 0) {
+ xfree(s->term);
+ s->term = NULL;
+ }
+ /* Get window size from the packet. */
+ s->row = packet_get_int();
+ s->col = packet_get_int();
+ s->xpixel = packet_get_int();
+ s->ypixel = packet_get_int();
+ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
+
+ /* Get tty modes from the packet. */
+ tty_parse_modes(s->ttyfd, &n_bytes);
+ packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
+
+ session_proctitle(s);
+
+ /* Indicate that we now have a pty. */
+ success = 1;
+ have_pty = 1;
+ break;
+
+ case SSH_CMSG_X11_REQUEST_FORWARDING:
+ if (!options.x11_forwarding) {
+ packet_send_debug("X11 forwarding disabled in server configuration file.");
+ break;
+ }
+#ifdef XAUTH_PATH
+ if (no_x11_forwarding_flag) {
+ packet_send_debug("X11 forwarding not permitted for this authentication.");
+ break;
+ }
+ debug("Received request for X11 forwarding with auth spoofing.");
+ if (s->display != NULL)
+ packet_disconnect("Protocol error: X11 display already set.");
+
+ s->auth_proto = packet_get_string(&proto_len);
+ s->auth_data = packet_get_string(&data_len);
+ packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
+
+ if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
+ s->screen = packet_get_int();
+ else
+ s->screen = 0;
+ s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
+
+ if (s->display == NULL)
+ break;
+
+ /* Setup to always have a local .Xauthority. */
+ xauthfile = xmalloc(MAXPATHLEN);
+ strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
+ temporarily_use_uid(pw->pw_uid);
+ if (mkdtemp(xauthfile) == NULL) {
+ restore_uid();
+ error("private X11 dir: mkdtemp %s failed: %s",
+ xauthfile, strerror(errno));
+ xfree(xauthfile);
+ xauthfile = NULL;
+ /* XXXX remove listening channels */
+ break;
+ }
+ strlcat(xauthfile, "/cookies", MAXPATHLEN);
+ open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
+ restore_uid();
+ fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
+ success = 1;
+ break;
+#else /* XAUTH_PATH */
+ packet_send_debug("No xauth program; cannot forward with spoofing.");
+ break;
+#endif /* XAUTH_PATH */
+
+ case SSH_CMSG_AGENT_REQUEST_FORWARDING:
+ if (no_agent_forwarding_flag || compat13) {
+ debug("Authentication agent forwarding not permitted for this authentication.");
+ break;
+ }
+ debug("Received authentication agent forwarding request.");
+ auth_input_request_forwarding(pw);
+ success = 1;
+ break;
+
+ case SSH_CMSG_PORT_FORWARD_REQUEST:
+ if (no_port_forwarding_flag) {
+ debug("Port forwarding not permitted for this authentication.");
+ break;
+ }
+ debug("Received TCP/IP port forwarding request.");
+ channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);
+ success = 1;
+ break;
+
+ case SSH_CMSG_MAX_PACKET_SIZE:
+ if (packet_set_maxsize(packet_get_int()) > 0)
+ success = 1;
+ break;
+
+ case SSH_CMSG_EXEC_SHELL:
+ case SSH_CMSG_EXEC_CMD:
+ /* Set interactive/non-interactive mode. */
+ packet_set_interactive(have_pty || s->display != NULL,
+ options.keepalives);
+
+ if (type == SSH_CMSG_EXEC_CMD) {
+ command = packet_get_string(&dlen);
+ debug("Exec command '%.500s'", command);
+ packet_integrity_check(plen, 4 + dlen, type);
+ } else {
+ command = NULL;
+ packet_integrity_check(plen, 0, type);
+ }
+ if (forced_command != NULL) {
+ command = forced_command;
+ debug("Forced command '%.500s'", forced_command);
+ }
+ if (have_pty)
+ do_exec_pty(s, command, pw);
+ else
+ do_exec_no_pty(s, command, pw);
+
+ if (command != NULL)
+ xfree(command);
+ /* Cleanup user's local Xauthority file. */
+ if (xauthfile)
+ xauthfile_cleanup_proc(NULL);
+ return;
+
+ default:
+ /*
+ * Any unknown messages in this phase are ignored,
+ * and a failure message is returned.
+ */
+ log("Unknown packet type received after authentication: %d", type);
+ }
+ packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
+ packet_send();
+ packet_write_wait();
+
+ /* Enable compression now that we have replied if appropriate. */
+ if (enable_compression_after_reply) {
+ enable_compression_after_reply = 0;
+ packet_start_compression(compression_level);
+ }
+ }
+}
+
+/*
+ * This is called to fork and execute a command when we have no tty. This
+ * will call do_child from the child, and server_loop from the parent after
+ * setting up file descriptors and such.
+ */
+void
+do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
+{
+ int pid;
+
+#ifdef USE_PIPES
+ int pin[2], pout[2], perr[2];
+ /* Allocate pipes for communicating with the program. */
+ if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
+ packet_disconnect("Could not create pipes: %.100s",
+ strerror(errno));
+#else /* USE_PIPES */
+ int inout[2], err[2];
+ /* Uses socket pairs to communicate with the program. */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
+ socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
+ packet_disconnect("Could not create socket pairs: %.100s",
+ strerror(errno));
+#endif /* USE_PIPES */
+ if (s == NULL)
+ fatal("do_exec_no_pty: no session");
+
+ session_proctitle(s);
+
+ /* Fork the child. */
+ if ((pid = fork()) == 0) {
+ /* Child. Reinitialize the log since the pid has changed. */
+ log_init(__progname, options.log_level, options.log_facility, log_stderr);
+
+ /*
+ * Create a new session and process group since the 4.4BSD
+ * setlogin() affects the entire process group.
+ */
+ if (setsid() < 0)
+ error("setsid failed: %.100s", strerror(errno));
+
+#ifdef USE_PIPES
+ /*
+ * Redirect stdin. We close the parent side of the socket
+ * pair, and make the child side the standard input.
+ */
+ close(pin[1]);
+ if (dup2(pin[0], 0) < 0)
+ perror("dup2 stdin");
+ close(pin[0]);
+
+ /* Redirect stdout. */
+ close(pout[0]);
+ if (dup2(pout[1], 1) < 0)
+ perror("dup2 stdout");
+ close(pout[1]);
+
+ /* Redirect stderr. */
+ close(perr[0]);
+ if (dup2(perr[1], 2) < 0)
+ perror("dup2 stderr");
+ close(perr[1]);
+#else /* USE_PIPES */
+ /*
+ * Redirect stdin, stdout, and stderr. Stdin and stdout will
+ * use the same socket, as some programs (particularly rdist)
+ * seem to depend on it.
+ */
+ close(inout[1]);
+ close(err[1]);
+ if (dup2(inout[0], 0) < 0) /* stdin */
+ perror("dup2 stdin");
+ if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
+ perror("dup2 stdout");
+ if (dup2(err[0], 2) < 0) /* stderr */
+ perror("dup2 stderr");
+#endif /* USE_PIPES */
+
+ /* Do processing for the child (exec command etc). */
+ do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL);
+ /* NOTREACHED */
+ }
+ if (pid < 0)
+ packet_disconnect("fork failed: %.100s", strerror(errno));
+ s->pid = pid;
+#ifdef USE_PIPES
+ /* We are the parent. Close the child sides of the pipes. */
+ close(pin[0]);
+ close(pout[1]);
+ close(perr[1]);
+
+ if (compat20) {
+ session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1);
+ } else {
+ /* Enter the interactive session. */
+ server_loop(pid, pin[1], pout[0], perr[0]);
+ /* server_loop has closed pin[1], pout[1], and perr[1]. */
+ }
+#else /* USE_PIPES */
+ /* We are the parent. Close the child sides of the socket pairs. */
+ close(inout[0]);
+ close(err[0]);
+
+ /*
+ * Enter the interactive session. Note: server_loop must be able to
+ * handle the case that fdin and fdout are the same.
+ */
+ if (compat20) {
+ session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1);
+ } else {
+ server_loop(pid, inout[1], inout[1], err[1]);
+ /* server_loop has closed inout[1] and err[1]. */
+ }
+#endif /* USE_PIPES */
+}
+
+/*
+ * This is called to fork and execute a command when we have a tty. This
+ * will call do_child from the child, and server_loop from the parent after
+ * setting up file descriptors, controlling tty, updating wtmp, utmp,
+ * lastlog, and other such operations.
+ */
+void
+do_exec_pty(Session *s, const char *command, struct passwd * pw)
+{
+ FILE *f;
+ char buf[100], *time_string;
+ char line[256];
+ const char *hostname;
+ int fdout, ptyfd, ttyfd, ptymaster;
+ int quiet_login;
+ pid_t pid;
+ socklen_t fromlen;
+ struct sockaddr_storage from;
+ struct stat st;
+ time_t last_login_time;
+
+ if (s == NULL)
+ fatal("do_exec_pty: no session");
+ ptyfd = s->ptyfd;
+ ttyfd = s->ttyfd;
+
+ /* Get remote host name. */
+ hostname = get_canonical_hostname();
+
+ /*
+ * Get the time when the user last logged in. Buf will be set to
+ * contain the hostname the last login was from.
+ */
+ if (!options.use_login) {
+ last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
+ buf, sizeof(buf));
+ }
+
+ /* Fork the child. */
+ if ((pid = fork()) == 0) {
+ pid = getpid();
+
+ /* Child. Reinitialize the log because the pid has
+ changed. */
+ log_init(__progname, options.log_level, options.log_facility, log_stderr);
+
+ /* Close the master side of the pseudo tty. */
+ close(ptyfd);
+
+ /* Make the pseudo tty our controlling tty. */
+ pty_make_controlling_tty(&ttyfd, s->tty);
+
+ /* Redirect stdin from the pseudo tty. */
+ if (dup2(ttyfd, fileno(stdin)) < 0)
+ error("dup2 stdin failed: %.100s", strerror(errno));
+
+ /* Redirect stdout to the pseudo tty. */
+ if (dup2(ttyfd, fileno(stdout)) < 0)
+ error("dup2 stdin failed: %.100s", strerror(errno));
+
+ /* Redirect stderr to the pseudo tty. */
+ if (dup2(ttyfd, fileno(stderr)) < 0)
+ error("dup2 stdin failed: %.100s", strerror(errno));
+
+ /* Close the extra descriptor for the pseudo tty. */
+ close(ttyfd);
+
+/* XXXX ? move to do_child() ??*/
+ /*
+ * Get IP address of client. This is needed because we want
+ * to record where the user logged in from. If the
+ * connection is not a socket, let the ip address be 0.0.0.0.
+ */
+ memset(&from, 0, sizeof(from));
+ if (packet_connection_is_on_socket()) {
+ fromlen = sizeof(from);
+ if (getpeername(packet_get_connection_in(),
+ (struct sockaddr *) & from, &fromlen) < 0) {
+ debug("getpeername: %.100s", strerror(errno));
+ fatal_cleanup();
+ }
+ }
+ /* Record that there was a login on that terminal. */
+ record_login(pid, s->tty, pw->pw_name, pw->pw_uid, hostname,
+ (struct sockaddr *)&from);
+
+ /* Check if .hushlogin exists. */
+ snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
+ quiet_login = stat(line, &st) >= 0;
+
+ /*
+ * If the user has logged in before, display the time of last
+ * login. However, don't display anything extra if a command
+ * has been specified (so that ssh can be used to execute
+ * commands on a remote machine without users knowing they
+ * are going to another machine). Login(1) will do this for
+ * us as well, so check if login(1) is used
+ */
+ if (command == NULL && last_login_time != 0 && !quiet_login &&
+ !options.use_login) {
+ /* Convert the date to a string. */
+ time_string = ctime(&last_login_time);
+ /* Remove the trailing newline. */
+ if (strchr(time_string, '\n'))
+ *strchr(time_string, '\n') = 0;
+ /* Display the last login time. Host if displayed
+ if known. */
+ if (strcmp(buf, "") == 0)
+ printf("Last login: %s\r\n", time_string);
+ else
+ printf("Last login: %s from %s\r\n", time_string, buf);
+ }
+ /*
+ * Print /etc/motd unless a command was specified or printing
+ * it was disabled in server options or login(1) will be
+ * used. Note that some machines appear to print it in
+ * /etc/profile or similar.
+ */
+ if (command == NULL && options.print_motd && !quiet_login &&
+ !options.use_login) {
+ /* Print /etc/motd if it exists. */
+ f = fopen("/etc/motd", "r");
+ if (f) {
+ while (fgets(line, sizeof(line), f))
+ fputs(line, stdout);
+ fclose(f);
+ }
+ }
+ /* Do common processing for the child, such as execing the command. */
+ do_child(command, pw, s->term, s->display, s->auth_proto, s->auth_data, s->tty);
+ /* NOTREACHED */
+ }
+ if (pid < 0)
+ packet_disconnect("fork failed: %.100s", strerror(errno));
+ s->pid = pid;
+
+ /* Parent. Close the slave side of the pseudo tty. */
+ close(ttyfd);
+
+ /*
+ * Create another descriptor of the pty master side for use as the
+ * standard input. We could use the original descriptor, but this
+ * simplifies code in server_loop. The descriptor is bidirectional.
+ */
+ fdout = dup(ptyfd);
+ if (fdout < 0)
+ packet_disconnect("dup #1 failed: %.100s", strerror(errno));
+
+ /* we keep a reference to the pty master */
+ ptymaster = dup(ptyfd);
+ if (ptymaster < 0)
+ packet_disconnect("dup #2 failed: %.100s", strerror(errno));
+ s->ptymaster = ptymaster;
+
+ /* Enter interactive session. */
+ if (compat20) {
+ session_set_fds(s, ptyfd, fdout, -1);
+ } else {
+ server_loop(pid, ptyfd, fdout, -1);
+ /* server_loop _has_ closed ptyfd and fdout. */
+ session_pty_cleanup(s);
+ }
+}
+
+/*
+ * Sets the value of the given variable in the environment. If the variable
+ * already exists, its value is overriden.
+ */
+void
+child_set_env(char ***envp, unsigned int *envsizep, const char *name,
+ const char *value)
+{
+ unsigned int i, namelen;
+ char **env;
+
+ /*
+ * Find the slot where the value should be stored. If the variable
+ * already exists, we reuse the slot; otherwise we append a new slot
+ * at the end of the array, expanding if necessary.
+ */
+ env = *envp;
+ namelen = strlen(name);
+ for (i = 0; env[i]; i++)
+ if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
+ break;
+ if (env[i]) {
+ /* Reuse the slot. */
+ xfree(env[i]);
+ } else {
+ /* New variable. Expand if necessary. */
+ if (i >= (*envsizep) - 1) {
+ (*envsizep) += 50;
+ env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
+ }
+ /* Need to set the NULL pointer at end of array beyond the new slot. */
+ env[i + 1] = NULL;
+ }
+
+ /* Allocate space and format the variable in the appropriate slot. */
+ env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
+ snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
+}
+
+/*
+ * Reads environment variables from the given file and adds/overrides them
+ * into the environment. If the file does not exist, this does nothing.
+ * Otherwise, it must consist of empty lines, comments (line starts with '#')
+ * and assignments of the form name=value. No other forms are allowed.
+ */
+void
+read_environment_file(char ***env, unsigned int *envsize,
+ const char *filename)
+{
+ FILE *f;
+ char buf[4096];
+ char *cp, *value;
+
+ f = fopen(filename, "r");
+ if (!f)
+ return;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ if (!*cp || *cp == '#' || *cp == '\n')
+ continue;
+ if (strchr(cp, '\n'))
+ *strchr(cp, '\n') = '\0';
+ value = strchr(cp, '=');
+ if (value == NULL) {
+ fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
+ continue;
+ }
+ /* Replace the equals sign by nul, and advance value to the value string. */
+ *value = '\0';
+ value++;
+ child_set_env(env, envsize, cp, value);
+ }
+ fclose(f);
+}
+
+/*
+ * Performs common processing for the child, such as setting up the
+ * environment, closing extra file descriptors, setting the user and group
+ * ids, and executing the command or shell.
+ */
+void
+do_child(const char *command, struct passwd * pw, const char *term,
+ const char *display, const char *auth_proto,
+ const char *auth_data, const char *ttyname)
+{
+ const char *shell, *cp = NULL;
+ char buf[256];
+ FILE *f;
+ unsigned int envsize, i;
+ char **env;
+ extern char **environ;
+ struct stat st;
+ char *argv[10];
+
+ f = fopen("/etc/nologin", "r");
+ if (f) {
+ /* /etc/nologin exists. Print its contents and exit. */
+ while (fgets(buf, sizeof(buf), f))
+ fputs(buf, stderr);
+ fclose(f);
+ if (pw->pw_uid != 0)
+ exit(254);
+ }
+ /* Set login name in the kernel. */
+ if (setlogin(pw->pw_name) < 0)
+ error("setlogin failed: %s", strerror(errno));
+
+ /* Set uid, gid, and groups. */
+ /* Login(1) does this as well, and it needs uid 0 for the "-h"
+ switch, so we let login(1) to this for us. */
+ if (!options.use_login) {
+ if (getuid() == 0 || geteuid() == 0) {
+ if (setgid(pw->pw_gid) < 0) {
+ perror("setgid");
+ exit(1);
+ }
+ /* Initialize the group list. */
+ if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+ perror("initgroups");
+ exit(1);
+ }
+ endgrent();
+
+ /* Permanently switch to the desired uid. */
+ permanently_set_uid(pw->pw_uid);
+ }
+ if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+ fatal("Failed to set uids to %d.", (int) pw->pw_uid);
+ }
+ /*
+ * Get the shell from the password data. An empty shell field is
+ * legal, and means /bin/sh.
+ */
+ shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
+
+#ifdef AFS
+ /* Try to get AFS tokens for the local cell. */
+ if (k_hasafs()) {
+ char cell[64];
+
+ if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
+ krb_afslog(cell, 0);
+
+ krb_afslog(0, 0);
+ }
+#endif /* AFS */
+
+ /* Initialize the environment. */
+ envsize = 100;
+ env = xmalloc(envsize * sizeof(char *));
+ env[0] = NULL;
+
+ if (!options.use_login) {
+ /* Set basic environment. */
+ child_set_env(&env, &envsize, "USER", pw->pw_name);
+ child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
+ child_set_env(&env, &envsize, "HOME", pw->pw_dir);
+ child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
+
+ snprintf(buf, sizeof buf, "%.200s/%.50s",
+ _PATH_MAILDIR, pw->pw_name);
+ child_set_env(&env, &envsize, "MAIL", buf);
+
+ /* Normal systems set SHELL by default. */
+ child_set_env(&env, &envsize, "SHELL", shell);
+ }
+ if (getenv("TZ"))
+ child_set_env(&env, &envsize, "TZ", getenv("TZ"));
+
+ /* Set custom environment options from RSA authentication. */
+ while (custom_environment) {
+ struct envstring *ce = custom_environment;
+ char *s = ce->s;
+ int i;
+ for (i = 0; s[i] != '=' && s[i]; i++);
+ if (s[i] == '=') {
+ s[i] = 0;
+ child_set_env(&env, &envsize, s, s + i + 1);
+ }
+ custom_environment = ce->next;
+ xfree(ce->s);
+ xfree(ce);
+ }
+
+ snprintf(buf, sizeof buf, "%.50s %d %d",
+ get_remote_ipaddr(), get_remote_port(), get_local_port());
+ child_set_env(&env, &envsize, "SSH_CLIENT", buf);
+
+ if (ttyname)
+ child_set_env(&env, &envsize, "SSH_TTY", ttyname);
+ if (term)
+ child_set_env(&env, &envsize, "TERM", term);
+ if (display)
+ child_set_env(&env, &envsize, "DISPLAY", display);
+
+#ifdef KRB4
+ {
+ extern char *ticket;
+
+ if (ticket)
+ child_set_env(&env, &envsize, "KRBTKFILE", ticket);
+ }
+#endif /* KRB4 */
+
+ if (xauthfile)
+ child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
+ if (auth_get_socket_name() != NULL)
+ child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
+ auth_get_socket_name());
+
+ /* read $HOME/.ssh/environment. */
+ if (!options.use_login) {
+ snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
+ read_environment_file(&env, &envsize, buf);
+ }
+ if (debug_flag) {
+ /* dump the environment */
+ fprintf(stderr, "Environment:\n");
+ for (i = 0; env[i]; i++)
+ fprintf(stderr, " %.200s\n", env[i]);
+ }
+ /*
+ * Close the connection descriptors; note that this is the child, and
+ * the server will still have the socket open, and it is important
+ * that we do not shutdown it. Note that the descriptors cannot be
+ * closed before building the environment, as we call
+ * get_remote_ipaddr there.
+ */
+ if (packet_get_connection_in() == packet_get_connection_out())
+ close(packet_get_connection_in());
+ else {
+ close(packet_get_connection_in());
+ close(packet_get_connection_out());
+ }
+ /*
+ * Close all descriptors related to channels. They will still remain
+ * open in the parent.
+ */
+ /* XXX better use close-on-exec? -markus */
+ channel_close_all();
+
+ /*
+ * Close any extra file descriptors. Note that there may still be
+ * descriptors left by system functions. They will be closed later.
+ */
+ endpwent();
+
+ /*
+ * Close any extra open file descriptors so that we don\'t have them
+ * hanging around in clients. Note that we want to do this after
+ * initgroups, because at least on Solaris 2.3 it leaves file
+ * descriptors open.
+ */
+ for (i = 3; i < 64; i++)
+ close(i);
+
+ /* Change current directory to the user\'s home directory. */
+ if (chdir(pw->pw_dir) < 0)
+ fprintf(stderr, "Could not chdir to home directory %s: %s\n",
+ pw->pw_dir, strerror(errno));
+
+ /*
+ * Must take new environment into use so that .ssh/rc, /etc/sshrc and
+ * xauth are run in the proper environment.
+ */
+ environ = env;
+
+ /*
+ * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
+ * in this order).
+ */
+ if (!options.use_login) {
+ if (stat(SSH_USER_RC, &st) >= 0) {
+ if (debug_flag)
+ fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
+
+ f = popen("/bin/sh " SSH_USER_RC, "w");
+ if (f) {
+ if (auth_proto != NULL && auth_data != NULL)
+ fprintf(f, "%s %s\n", auth_proto, auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
+ } else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
+ if (debug_flag)
+ fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
+
+ f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
+ if (f) {
+ if (auth_proto != NULL && auth_data != NULL)
+ fprintf(f, "%s %s\n", auth_proto, auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
+ }
+#ifdef XAUTH_PATH
+ else {
+ /* Add authority data to .Xauthority if appropriate. */
+ if (auth_proto != NULL && auth_data != NULL) {
+ if (debug_flag)
+ fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
+ XAUTH_PATH, display, auth_proto, auth_data);
+
+ f = popen(XAUTH_PATH " -q -", "w");
+ if (f) {
+ fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data);
+ pclose(f);
+ } else
+ fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH);
+ }
+ }
+#endif /* XAUTH_PATH */
+
+ /* Get the last component of the shell name. */
+ cp = strrchr(shell, '/');
+ if (cp)
+ cp++;
+ else
+ cp = shell;
+ }
+ /*
+ * If we have no command, execute the shell. In this case, the shell
+ * name to be passed in argv[0] is preceded by '-' to indicate that
+ * this is a login shell.
+ */
+ if (!command) {
+ if (!options.use_login) {
+ char buf[256];
+
+ /*
+ * Check for mail if we have a tty and it was enabled
+ * in server options.
+ */
+ if (ttyname && options.check_mail) {
+ char *mailbox;
+ struct stat mailstat;
+ mailbox = getenv("MAIL");
+ if (mailbox != NULL) {
+ if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0)
+ printf("No mail.\n");
+ else if (mailstat.st_mtime < mailstat.st_atime)
+ printf("You have mail.\n");
+ else
+ printf("You have new mail.\n");
+ }
+ }
+ /* Start the shell. Set initial character to '-'. */
+ buf[0] = '-';
+ strncpy(buf + 1, cp, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = 0;
+
+ /* Execute the shell. */
+ argv[0] = buf;
+ argv[1] = NULL;
+ execve(shell, argv, env);
+
+ /* Executing the shell failed. */
+ perror(shell);
+ exit(1);
+
+ } else {
+ /* Launch login(1). */
+
+ execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(),
+ "-p", "-f", "--", pw->pw_name, NULL);
+
+ /* Login couldn't be executed, die. */
+
+ perror("login");
+ exit(1);
+ }
+ }
+ /*
+ * Execute the command using the user's shell. This uses the -c
+ * option to execute the command.
+ */
+ argv[0] = (char *) cp;
+ argv[1] = "-c";
+ argv[2] = (char *) command;
+ argv[3] = NULL;
+ execve(shell, argv, env);
+ perror(shell);
+ exit(1);
+}
+
+Session *
+session_new(void)
+{
+ int i;
+ static int did_init = 0;
+ if (!did_init) {
+ debug("session_new: init");
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ sessions[i].used = 0;
+ sessions[i].self = i;
+ }
+ did_init = 1;
+ }
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ if (! s->used) {
+ s->pid = 0;
+ s->extended = 0;
+ s->chanid = -1;
+ s->ptyfd = -1;
+ s->ttyfd = -1;
+ s->term = NULL;
+ s->pw = NULL;
+ s->display = NULL;
+ s->screen = 0;
+ s->auth_data = NULL;
+ s->auth_proto = NULL;
+ s->used = 1;
+ s->pw = NULL;
+ debug("session_new: session %d", i);
+ return s;
+ }
+ }
+ return NULL;
+}
+
+void
+session_dump(void)
+{
+ int i;
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ debug("dump: used %d session %d %p channel %d pid %d",
+ s->used,
+ s->self,
+ s,
+ s->chanid,
+ s->pid);
+ }
+}
+
+int
+session_open(int chanid)
+{
+ Session *s = session_new();
+ debug("session_open: channel %d", chanid);
+ if (s == NULL) {
+ error("no more sessions");
+ return 0;
+ }
+ s->pw = auth_get_user();
+ if (s->pw == NULL)
+ fatal("no user for session %i", s->self);
+ debug("session_open: session %d: link with channel %d", s->self, chanid);
+ s->chanid = chanid;
+ return 1;
+}
+
+Session *
+session_by_channel(int id)
+{
+ int i;
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ if (s->used && s->chanid == id) {
+ debug("session_by_channel: session %d channel %d", i, id);
+ return s;
+ }
+ }
+ debug("session_by_channel: unknown channel %d", id);
+ session_dump();
+ return NULL;
+}
+
+Session *
+session_by_pid(pid_t pid)
+{
+ int i;
+ debug("session_by_pid: pid %d", pid);
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ if (s->used && s->pid == pid)
+ return s;
+ }
+ error("session_by_pid: unknown pid %d", pid);
+ session_dump();
+ return NULL;
+}
+
+int
+session_window_change_req(Session *s)
+{
+ s->col = packet_get_int();
+ s->row = packet_get_int();
+ s->xpixel = packet_get_int();
+ s->ypixel = packet_get_int();
+ packet_done();
+ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
+ return 1;
+}
+
+int
+session_pty_req(Session *s)
+{
+ unsigned int len;
+ char *term_modes; /* encoded terminal modes */
+
+ if (s->ttyfd != -1)
+ return 0;
+ s->term = packet_get_string(&len);
+ s->col = packet_get_int();
+ s->row = packet_get_int();
+ s->xpixel = packet_get_int();
+ s->ypixel = packet_get_int();
+ term_modes = packet_get_string(&len);
+ packet_done();
+
+ if (strcmp(s->term, "") == 0) {
+ xfree(s->term);
+ s->term = NULL;
+ }
+ /* Allocate a pty and open it. */
+ if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
+ xfree(s->term);
+ s->term = NULL;
+ s->ptyfd = -1;
+ s->ttyfd = -1;
+ error("session_pty_req: session %d alloc failed", s->self);
+ xfree(term_modes);
+ return 0;
+ }
+ debug("session_pty_req: session %d alloc %s", s->self, s->tty);
+ /*
+ * Add a cleanup function to clear the utmp entry and record logout
+ * time in case we call fatal() (e.g., the connection gets closed).
+ */
+ fatal_add_cleanup(pty_cleanup_proc, (void *)s);
+ pty_setowner(s->pw, s->tty);
+ /* Get window size from the packet. */
+ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
+
+ session_proctitle(s);
+
+ /* XXX parse and set terminal modes */
+ xfree(term_modes);
+ return 1;
+}
+
+int
+session_subsystem_req(Session *s)
+{
+ unsigned int len;
+ int success = 0;
+ char *subsys = packet_get_string(&len);
+
+ packet_done();
+ log("subsystem request for %s", subsys);
+
+ xfree(subsys);
+ return success;
+}
+
+int
+session_x11_req(Session *s)
+{
+ if (!options.x11_forwarding) {
+ debug("X11 forwarding disabled in server configuration file.");
+ return 0;
+ }
+ if (xauthfile != NULL) {
+ debug("X11 fwd already started.");
+ return 0;
+ }
+
+ debug("Received request for X11 forwarding with auth spoofing.");
+ if (s->display != NULL)
+ packet_disconnect("Protocol error: X11 display already set.");
+
+ s->single_connection = packet_get_char();
+ s->auth_proto = packet_get_string(NULL);
+ s->auth_data = packet_get_string(NULL);
+ s->screen = packet_get_int();
+ packet_done();
+
+ s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
+ if (s->display == NULL) {
+ xfree(s->auth_proto);
+ xfree(s->auth_data);
+ return 0;
+ }
+ xauthfile = xmalloc(MAXPATHLEN);
+ strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
+ temporarily_use_uid(s->pw->pw_uid);
+ if (mkdtemp(xauthfile) == NULL) {
+ restore_uid();
+ error("private X11 dir: mkdtemp %s failed: %s",
+ xauthfile, strerror(errno));
+ xfree(xauthfile);
+ xauthfile = NULL;
+ xfree(s->auth_proto);
+ xfree(s->auth_data);
+ /* XXXX remove listening channels */
+ return 0;
+ }
+ strlcat(xauthfile, "/cookies", MAXPATHLEN);
+ open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
+ restore_uid();
+ fatal_add_cleanup(xauthfile_cleanup_proc, s);
+ return 1;
+}
+
+void
+session_input_channel_req(int id, void *arg)
+{
+ unsigned int len;
+ int reply;
+ int success = 0;
+ char *rtype;
+ Session *s;
+ Channel *c;
+
+ rtype = packet_get_string(&len);
+ reply = packet_get_char();
+
+ s = session_by_channel(id);
+ if (s == NULL)
+ fatal("session_input_channel_req: channel %d: no session", id);
+ c = channel_lookup(id);
+ if (c == NULL)
+ fatal("session_input_channel_req: channel %d: bad channel", id);
+
+ debug("session_input_channel_req: session %d channel %d request %s reply %d",
+ s->self, id, rtype, reply);
+
+ /*
+ * a session is in LARVAL state until a shell
+ * or programm is executed
+ */
+ if (c->type == SSH_CHANNEL_LARVAL) {
+ if (strcmp(rtype, "shell") == 0) {
+ packet_done();
+ s->extended = 1;
+ if (s->ttyfd == -1)
+ do_exec_no_pty(s, NULL, s->pw);
+ else
+ do_exec_pty(s, NULL, s->pw);
+ success = 1;
+ } else if (strcmp(rtype, "exec") == 0) {
+ char *command = packet_get_string(&len);
+ packet_done();
+ s->extended = 1;
+ if (s->ttyfd == -1)
+ do_exec_no_pty(s, command, s->pw);
+ else
+ do_exec_pty(s, command, s->pw);
+ xfree(command);
+ success = 1;
+ } else if (strcmp(rtype, "pty-req") == 0) {
+ success = session_pty_req(s);
+ } else if (strcmp(rtype, "x11-req") == 0) {
+ success = session_x11_req(s);
+ } else if (strcmp(rtype, "subsystem") == 0) {
+ success = session_subsystem_req(s);
+ }
+ }
+ if (strcmp(rtype, "window-change") == 0) {
+ success = session_window_change_req(s);
+ }
+
+ if (reply) {
+ packet_start(success ?
+ SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+ packet_put_int(c->remote_id);
+ packet_send();
+ }
+ xfree(rtype);
+}
+
+void
+session_set_fds(Session *s, int fdin, int fdout, int fderr)
+{
+ if (!compat20)
+ fatal("session_set_fds: called for proto != 2.0");
+ /*
+ * now that have a child and a pipe to the child,
+ * we can activate our channel and register the fd's
+ */
+ if (s->chanid == -1)
+ fatal("no channel for session %d", s->self);
+ channel_set_fds(s->chanid,
+ fdout, fdin, fderr,
+ fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ);
+}
+
+void
+session_pty_cleanup(Session *s)
+{
+ if (s == NULL || s->ttyfd == -1)
+ return;
+
+ debug("session_pty_cleanup: session %i release %s", s->self, s->tty);
+
+ /* Cancel the cleanup function. */
+ fatal_remove_cleanup(pty_cleanup_proc, (void *)s);
+
+ /* Record that the user has logged out. */
+ record_logout(s->pid, s->tty);
+
+ /* Release the pseudo-tty. */
+ pty_release(s->tty);
+
+ /*
+ * Close the server side of the socket pairs. We must do this after
+ * the pty cleanup, so that another process doesn't get this pty
+ * while we're still cleaning up.
+ */
+ if (close(s->ptymaster) < 0)
+ error("close(s->ptymaster): %s", strerror(errno));
+}
+
+void
+session_exit_message(Session *s, int status)
+{
+ Channel *c;
+ if (s == NULL)
+ fatal("session_close: no session");
+ c = channel_lookup(s->chanid);
+ if (c == NULL)
+ fatal("session_close: session %d: no channel %d",
+ s->self, s->chanid);
+ debug("session_exit_message: session %d channel %d pid %d",
+ s->self, s->chanid, s->pid);
+
+ if (WIFEXITED(status)) {
+ channel_request_start(s->chanid,
+ "exit-status", 0);
+ packet_put_int(WEXITSTATUS(status));
+ packet_send();
+ } else if (WIFSIGNALED(status)) {
+ channel_request_start(s->chanid,
+ "exit-signal", 0);
+ packet_put_int(WTERMSIG(status));
+ packet_put_char(WCOREDUMP(status));
+ packet_put_cstring("");
+ packet_put_cstring("");
+ packet_send();
+ } else {
+ /* Some weird exit cause. Just exit. */
+ packet_disconnect("wait returned status %04x.", status);
+ }
+
+ /* disconnect channel */
+ debug("session_exit_message: release channel %d", s->chanid);
+ channel_cancel_cleanup(s->chanid);
+ /*
+ * emulate a write failure with 'chan_write_failed', nobody will be
+ * interested in data we write.
+ * Note that we must not call 'chan_read_failed', since there could
+ * be some more data waiting in the pipe.
+ */
+ if (c->ostate != CHAN_OUTPUT_CLOSED)
+ chan_write_failed(c);
+ s->chanid = -1;
+}
+
+void
+session_free(Session *s)
+{
+ debug("session_free: session %d pid %d", s->self, s->pid);
+ if (s->term)
+ xfree(s->term);
+ if (s->display)
+ xfree(s->display);
+ if (s->auth_data)
+ xfree(s->auth_data);
+ if (s->auth_proto)
+ xfree(s->auth_proto);
+ s->used = 0;
+}
+
+void
+session_close(Session *s)
+{
+ session_pty_cleanup(s);
+ session_free(s);
+ session_proctitle(s);
+}
+
+void
+session_close_by_pid(pid_t pid, int status)
+{
+ Session *s = session_by_pid(pid);
+ if (s == NULL) {
+ debug("session_close_by_pid: no session for pid %d", s->pid);
+ return;
+ }
+ if (s->chanid != -1)
+ session_exit_message(s, status);
+ session_close(s);
+}
+
+/*
+ * this is called when a channel dies before
+ * the session 'child' itself dies
+ */
+void
+session_close_by_channel(int id, void *arg)
+{
+ Session *s = session_by_channel(id);
+ if (s == NULL) {
+ debug("session_close_by_channel: no session for channel %d", id);
+ return;
+ }
+ /* disconnect channel */
+ channel_cancel_cleanup(s->chanid);
+ s->chanid = -1;
+
+ debug("session_close_by_channel: channel %d kill %d", id, s->pid);
+ if (s->pid == 0) {
+ /* close session immediately */
+ session_close(s);
+ } else {
+ /* notify child, delay session cleanup */
+ if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
+ error("session_close_by_channel: kill %d: %s",
+ s->pid, strerror(errno));
+ }
+}
+
+char *
+session_tty_list(void)
+{
+ static char buf[1024];
+ int i;
+ buf[0] = '\0';
+ for(i = 0; i < MAX_SESSIONS; i++) {
+ Session *s = &sessions[i];
+ if (s->used && s->ttyfd != -1) {
+ if (buf[0] != '\0')
+ strlcat(buf, ",", sizeof buf);
+ strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf);
+ }
+ }
+ if (buf[0] == '\0')
+ strlcpy(buf, "notty", sizeof buf);
+ return buf;
+}
+
+void
+session_proctitle(Session *s)
+{
+ if (s->pw == NULL)
+ error("no user for session %d", s->self);
+ else
+ setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
+}
+
+void
+do_authenticated2(void)
+{
+ /*
+ * Cancel the alarm we set to limit the time taken for
+ * authentication.
+ */
+ alarm(0);
+ server_loop2();
+ if (xauthfile)
+ xauthfile_cleanup_proc(NULL);
+}
diff --git a/crypto/openssh/session.h b/crypto/openssh/session.h
new file mode 100644
index 000000000000..a3427bcb0888
--- /dev/null
+++ b/crypto/openssh/session.h
@@ -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
diff --git a/crypto/openssh/ssh-add.1 b/crypto/openssh/ssh-add.1
index 8d1486b52dbd..10363956f8b9 100644
--- a/crypto/openssh/ssh-add.1
+++ b/crypto/openssh/ssh-add.1
@@ -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
diff --git a/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c
index 78e152043045..b7a385c171d4 100644
--- a/crypto/openssh/ssh-add.c
+++ b/crypto/openssh/ssh-add.c
@@ -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);
}
diff --git a/crypto/openssh/ssh-agent.1 b/crypto/openssh/ssh-agent.1
index 7029b60dcc47..9f7299d3719e 100644
--- a/crypto/openssh/ssh-agent.1
+++ b/crypto/openssh/ssh-agent.1
@@ -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
diff --git a/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c
index 393fdf017456..18f1315fc4dd 100644
--- a/crypto/openssh/ssh-agent.c
+++ b/crypto/openssh/ssh-agent.c
@@ -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);
diff --git a/crypto/openssh/ssh-keygen.1 b/crypto/openssh/ssh-keygen.1
index 90361643c7b3..ea81532e9879 100644
--- a/crypto/openssh/ssh-keygen.1
+++ b/crypto/openssh/ssh-keygen.1
@@ -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
diff --git a/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c
index 29a967dbf485..9129c70a8ec8 100644
--- a/crypto/openssh/ssh-keygen.c
+++ b/crypto/openssh/ssh-keygen.c
@@ -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 @@ passphrase_again:
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 @@ passphrase_again:
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 @@ passphrase_again:
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);
}
diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1
index b2bd31c0cbde..77c39806071c 100644
--- a/crypto/openssh/ssh.1
+++ b/crypto/openssh/ssh.1
@@ -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 ,
diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c
index c5652eaa67e7..0ab3f9fb058a 100644
--- a/crypto/openssh/ssh.c
+++ b/crypto/openssh/ssh.c
@@ -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);
+ return client_loop(have_tty, tty_flag ? options.escape_char : -1);
+}
- /* Close the connection to the remote host. */
- packet_close();
+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);
- /* Exit with the status returned by the program on the remote side. */
- exit(exit_status);
+ return client_loop(tty_flag, tty_flag ? options.escape_char : -1);
}
diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h
index 78f95f89d859..0762c964ca26 100644
--- a/crypto/openssh/ssh.h
+++ b/crypto/openssh/ssh.h
@@ -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 */
diff --git a/crypto/openssh/ssh/Makefile b/crypto/openssh/ssh/Makefile
index b21445506f1b..a87d5dce0a44 100644
--- a/crypto/openssh/ssh/Makefile
+++ b/crypto/openssh/ssh/Makefile
@@ -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
diff --git a/crypto/openssh/ssh2.h b/crypto/openssh/ssh2.h
new file mode 100644
index 000000000000..cf684bacf969
--- /dev/null
+++ b/crypto/openssh/ssh2.h
@@ -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
diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config
index 9fb064deb964..6ecb0efde3f8 100644
--- a/crypto/openssh/ssh_config
+++ b/crypto/openssh/ssh_config
@@ -26,5 +26,6 @@
# StrictHostKeyChecking no
# IdentityFile ~/.ssh/identity
# Port 22
+# Protocol 2,1
# Cipher blowfish
# EscapeChar ~
diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c
index 07277986949e..80beac30680a 100644
--- a/crypto/openssh/sshconnect.c
+++ b/crypto/openssh/sshconnect.c
@@ -8,31 +8,26 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.58 2000/03/23 22:15:33 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.72 2000/05/04 09:50:22 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
-#include <ssl/bn.h>
#include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
+#include "buffer.h"
#include "packet.h"
-#include "authfd.h"
-#include "cipher.h"
-#include "mpaux.h"
#include "uidswap.h"
#include "compat.h"
#include "readconf.h"
-
-#include <ssl/rsa.h>
-#include <ssl/dsa.h>
-#include <ssl/md5.h>
#include "key.h"
+#include "sshconnect.h"
#include "hostfile.h"
-/* Session id for the current session. */
-unsigned char session_id[16];
-
-/* authentications supported by server */
-unsigned int supported_authentications;
+char *client_version_string = NULL;
+char *server_version_string = NULL;
extern Options options;
extern char *__progname;
@@ -48,7 +43,7 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
const char *cp;
char *command_string;
int pin[2], pout[2];
- int pid;
+ pid_t pid;
char strport[NI_MAXSERV];
/* Convert the port number into a string. */
@@ -229,7 +224,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
debug("Trying again...");
/* Loop through addresses for this host, and try each one in
- sequence until the connection succeeds. */
+ sequence until the connection succeeds. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
@@ -243,7 +238,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
host, ntop, strport);
/* Create a socket for connecting. */
- sock = ssh_create_socket(original_real_uid,
+ sock = ssh_create_socket(original_real_uid,
!anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
ai->ai_family);
if (sock < 0)
@@ -302,651 +297,19 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
return 1;
}
-/*
- * Checks if the user has an authentication agent, and if so, tries to
- * authenticate using the agent.
- */
-int
-try_agent_authentication()
-{
- int status, type;
- char *comment;
- AuthenticationConnection *auth;
- unsigned char response[16];
- unsigned int i;
- BIGNUM *e, *n, *challenge;
-
- /* Get connection to the agent. */
- auth = ssh_get_authentication_connection();
- if (!auth)
- return 0;
-
- e = BN_new();
- n = BN_new();
- challenge = BN_new();
-
- /* Loop through identities served by the agent. */
- for (status = ssh_get_first_identity(auth, e, n, &comment);
- status;
- status = ssh_get_next_identity(auth, e, n, &comment)) {
- int plen, clen;
-
- /* Try this identity. */
- debug("Trying RSA authentication via agent with '%.100s'", comment);
- xfree(comment);
-
- /* Tell the server that we are willing to authenticate using this key. */
- packet_start(SSH_CMSG_AUTH_RSA);
- packet_put_bignum(n);
- packet_send();
- packet_write_wait();
-
- /* Wait for server's response. */
- type = packet_read(&plen);
-
- /* The server sends failure if it doesn\'t like our key or
- does not support RSA authentication. */
- if (type == SSH_SMSG_FAILURE) {
- debug("Server refused our key.");
- continue;
- }
- /* Otherwise it should have sent a challenge. */
- if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
- packet_disconnect("Protocol error during RSA authentication: %d",
- type);
-
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
-
- debug("Received RSA challenge from server.");
-
- /* Ask the agent to decrypt the challenge. */
- if (!ssh_decrypt_challenge(auth, e, n, challenge,
- session_id, 1, response)) {
- /* The agent failed to authenticate this identifier although it
- advertised it supports this. Just return a wrong value. */
- log("Authentication agent failed to decrypt challenge.");
- memset(response, 0, sizeof(response));
- }
- debug("Sending response to RSA challenge.");
-
- /* Send the decrypted challenge back to the server. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(response[i]);
- packet_send();
- packet_write_wait();
-
- /* Wait for response from the server. */
- type = packet_read(&plen);
-
- /* The server returns success if it accepted the authentication. */
- if (type == SSH_SMSG_SUCCESS) {
- debug("RSA authentication accepted by server.");
- BN_clear_free(e);
- BN_clear_free(n);
- BN_clear_free(challenge);
- return 1;
- }
- /* Otherwise it should return failure. */
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error waiting RSA auth response: %d",
- type);
- }
-
- BN_clear_free(e);
- BN_clear_free(n);
- BN_clear_free(challenge);
-
- debug("RSA authentication using agent refused.");
- return 0;
-}
-
-/*
- * Computes the proper response to a RSA challenge, and sends the response to
- * the server.
- */
-void
-respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
-{
- unsigned char buf[32], response[16];
- MD5_CTX md;
- int i, len;
-
- /* Decrypt the challenge using the private key. */
- rsa_private_decrypt(challenge, challenge, prv);
-
- /* Compute the response. */
- /* The response is MD5 of decrypted challenge plus session id. */
- len = BN_num_bytes(challenge);
- if (len <= 0 || len > sizeof(buf))
- packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
- len);
-
- memset(buf, 0, sizeof(buf));
- BN_bn2bin(challenge, buf + sizeof(buf) - len);
- MD5_Init(&md);
- MD5_Update(&md, buf, 32);
- MD5_Update(&md, session_id, 16);
- MD5_Final(response, &md);
-
- debug("Sending response to host key RSA challenge.");
-
- /* Send the response back to the server. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(response[i]);
- packet_send();
- packet_write_wait();
-
- memset(buf, 0, sizeof(buf));
- memset(response, 0, sizeof(response));
- memset(&md, 0, sizeof(md));
-}
-
-/*
- * Checks if the user has authentication file, and if so, tries to authenticate
- * the user using it.
- */
-int
-try_rsa_authentication(const char *authfile)
-{
- BIGNUM *challenge;
- RSA *private_key;
- RSA *public_key;
- char *passphrase, *comment;
- int type, i;
- int plen, clen;
-
- /* Try to load identification for the authentication key. */
- public_key = RSA_new();
- if (!load_public_key(authfile, public_key, &comment)) {
- RSA_free(public_key);
- /* Could not load it. Fail. */
- return 0;
- }
- debug("Trying RSA authentication with key '%.100s'", comment);
-
- /* Tell the server that we are willing to authenticate using this key. */
- packet_start(SSH_CMSG_AUTH_RSA);
- packet_put_bignum(public_key->n);
- packet_send();
- packet_write_wait();
-
- /* We no longer need the public key. */
- RSA_free(public_key);
-
- /* Wait for server's response. */
- type = packet_read(&plen);
-
- /*
- * The server responds with failure if it doesn\'t like our key or
- * doesn\'t support RSA authentication.
- */
- if (type == SSH_SMSG_FAILURE) {
- debug("Server refused our key.");
- xfree(comment);
- return 0;
- }
- /* Otherwise, the server should respond with a challenge. */
- if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
- packet_disconnect("Protocol error during RSA authentication: %d", type);
-
- /* Get the challenge from the packet. */
- challenge = BN_new();
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
-
- debug("Received RSA challenge from server.");
-
- private_key = RSA_new();
- /*
- * Load the private key. Try first with empty passphrase; if it
- * fails, ask for a passphrase.
- */
- if (!load_private_key(authfile, "", private_key, NULL)) {
- char buf[300];
- snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
- comment);
- if (!options.batch_mode)
- passphrase = read_passphrase(buf, 0);
- else {
- debug("Will not query passphrase for %.100s in batch mode.",
- comment);
- passphrase = xstrdup("");
- }
-
- /* Load the authentication file using the pasphrase. */
- if (!load_private_key(authfile, passphrase, private_key, NULL)) {
- memset(passphrase, 0, strlen(passphrase));
- xfree(passphrase);
- error("Bad passphrase.");
-
- /* Send a dummy response packet to avoid protocol error. */
- packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
- for (i = 0; i < 16; i++)
- packet_put_char(0);
- packet_send();
- packet_write_wait();
-
- /* Expect the server to reject it... */
- packet_read_expect(&plen, SSH_SMSG_FAILURE);
- xfree(comment);
- return 0;
- }
- /* Destroy the passphrase. */
- memset(passphrase, 0, strlen(passphrase));
- xfree(passphrase);
- }
- /* We no longer need the comment. */
- xfree(comment);
-
- /* Compute and send a response to the challenge. */
- respond_to_rsa_challenge(challenge, private_key);
-
- /* Destroy the private key. */
- RSA_free(private_key);
-
- /* We no longer need the challenge. */
- BN_clear_free(challenge);
-
- /* Wait for response from the server. */
- type = packet_read(&plen);
- if (type == SSH_SMSG_SUCCESS) {
- debug("RSA authentication accepted by server.");
- return 1;
- }
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error waiting RSA auth response: %d", type);
- debug("RSA authentication refused.");
- return 0;
-}
-
-/*
- * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
- * authentication and RSA host authentication.
- */
-int
-try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
-{
- int type;
- BIGNUM *challenge;
- int plen, clen;
-
- debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
-
- /* Tell the server that we are willing to authenticate using this key. */
- packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
- packet_put_string(local_user, strlen(local_user));
- packet_put_int(BN_num_bits(host_key->n));
- packet_put_bignum(host_key->e);
- packet_put_bignum(host_key->n);
- packet_send();
- packet_write_wait();
-
- /* Wait for server's response. */
- type = packet_read(&plen);
-
- /* The server responds with failure if it doesn't admit our
- .rhosts authentication or doesn't know our host key. */
- if (type == SSH_SMSG_FAILURE) {
- debug("Server refused our rhosts authentication or host key.");
- return 0;
- }
- /* Otherwise, the server should respond with a challenge. */
- if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
- packet_disconnect("Protocol error during RSA authentication: %d", type);
-
- /* Get the challenge from the packet. */
- challenge = BN_new();
- packet_get_bignum(challenge, &clen);
-
- packet_integrity_check(plen, clen, type);
-
- debug("Received RSA challenge for host key from server.");
-
- /* Compute a response to the challenge. */
- respond_to_rsa_challenge(challenge, host_key);
-
- /* We no longer need the challenge. */
- BN_clear_free(challenge);
-
- /* Wait for response from the server. */
- type = packet_read(&plen);
- if (type == SSH_SMSG_SUCCESS) {
- debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
- return 1;
- }
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error waiting RSA auth response: %d", type);
- debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
- return 0;
-}
-
-#ifdef KRB4
-int
-try_kerberos_authentication()
+char *
+chop(char *s)
{
- KTEXT_ST auth; /* Kerberos data */
- char *reply;
- char inst[INST_SZ];
- char *realm;
- CREDENTIALS cred;
- int r, type, plen;
- socklen_t slen;
- Key_schedule schedule;
- u_long checksum, cksum;
- MSG_DAT msg_data;
- struct sockaddr_in local, foreign;
- struct stat st;
-
- /* Don't do anything if we don't have any tickets. */
- if (stat(tkt_string(), &st) < 0)
- return 0;
-
- strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
-
- realm = (char *) krb_realmofhost(get_canonical_hostname());
- if (!realm) {
- debug("Kerberos V4: no realm for %s", get_canonical_hostname());
- return 0;
- }
- /* This can really be anything. */
- checksum = (u_long) getpid();
-
- r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
- if (r != KSUCCESS) {
- debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
- return 0;
- }
- /* Get session key to decrypt the server's reply with. */
- r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
- if (r != KSUCCESS) {
- debug("get_cred failed: %s", krb_err_txt[r]);
- return 0;
- }
- des_key_sched((des_cblock *) cred.session, schedule);
-
- /* Send authentication info to server. */
- packet_start(SSH_CMSG_AUTH_KERBEROS);
- packet_put_string((char *) auth.dat, auth.length);
- packet_send();
- packet_write_wait();
-
- /* Zero the buffer. */
- (void) memset(auth.dat, 0, MAX_KTXT_LEN);
-
- slen = sizeof(local);
- memset(&local, 0, sizeof(local));
- if (getsockname(packet_get_connection_in(),
- (struct sockaddr *) & local, &slen) < 0)
- debug("getsockname failed: %s", strerror(errno));
-
- slen = sizeof(foreign);
- memset(&foreign, 0, sizeof(foreign));
- if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & foreign, &slen) < 0) {
- debug("getpeername failed: %s", strerror(errno));
- fatal_cleanup();
- }
- /* Get server reply. */
- type = packet_read(&plen);
- switch (type) {
- case SSH_SMSG_FAILURE:
- /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
- debug("Kerberos V4 authentication failed.");
- return 0;
- break;
-
- case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
- /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
- debug("Kerberos V4 authentication accepted.");
-
- /* Get server's response. */
- reply = packet_get_string((unsigned int *) &auth.length);
- memcpy(auth.dat, reply, auth.length);
- xfree(reply);
-
- packet_integrity_check(plen, 4 + auth.length, type);
-
- /*
- * If his response isn't properly encrypted with the session
- * key, and the decrypted checksum fails to match, he's
- * bogus. Bail out.
- */
- r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
- &foreign, &local, &msg_data);
- if (r != KSUCCESS) {
- debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
- packet_disconnect("Kerberos V4 challenge failed!");
+ char *t = s;
+ while (*t) {
+ if(*t == '\n' || *t == '\r') {
+ *t = '\0';
+ return s;
}
- /* Fetch the (incremented) checksum that we supplied in the request. */
- (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum));
- cksum = ntohl(cksum);
-
- /* If it matches, we're golden. */
- if (cksum == checksum + 1) {
- debug("Kerberos V4 challenge successful.");
- return 1;
- } else
- packet_disconnect("Kerberos V4 challenge failed!");
- break;
-
- default:
- packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
- }
- return 0;
-}
-
-#endif /* KRB4 */
-
-#ifdef AFS
-int
-send_kerberos_tgt()
-{
- CREDENTIALS *creds;
- char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
- int r, type, plen;
- char buffer[8192];
- struct stat st;
-
- /* Don't do anything if we don't have any tickets. */
- if (stat(tkt_string(), &st) < 0)
- return 0;
-
- creds = xmalloc(sizeof(*creds));
-
- if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
- debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]);
- return 0;
- }
- if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
- debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
- return 0;
- }
- if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
- debug("Kerberos V4 ticket expired: %s", TKT_FILE);
- return 0;
- }
- creds_to_radix(creds, (unsigned char *)buffer);
- xfree(creds);
-
- packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
- packet_put_string(buffer, strlen(buffer));
- packet_send();
- packet_write_wait();
-
- type = packet_read(&plen);
-
- if (type == SSH_SMSG_FAILURE)
- debug("Kerberos TGT for realm %s rejected.", prealm);
- else if (type != SSH_SMSG_SUCCESS)
- packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
-
- return 1;
-}
-
-void
-send_afs_tokens(void)
-{
- CREDENTIALS creds;
- struct ViceIoctl parms;
- struct ClearToken ct;
- int i, type, len, plen;
- char buf[2048], *p, *server_cell;
- char buffer[8192];
-
- /* Move over ktc_GetToken, here's something leaner. */
- for (i = 0; i < 100; i++) { /* just in case */
- parms.in = (char *) &i;
- parms.in_size = sizeof(i);
- parms.out = buf;
- parms.out_size = sizeof(buf);
- if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0)
- break;
- p = buf;
-
- /* Get secret token. */
- memcpy(&creds.ticket_st.length, p, sizeof(unsigned int));
- if (creds.ticket_st.length > MAX_KTXT_LEN)
- break;
- p += sizeof(unsigned int);
- memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
- p += creds.ticket_st.length;
-
- /* Get clear token. */
- memcpy(&len, p, sizeof(len));
- if (len != sizeof(struct ClearToken))
- break;
- p += sizeof(len);
- memcpy(&ct, p, len);
- p += len;
- p += sizeof(len); /* primary flag */
- server_cell = p;
-
- /* Flesh out our credentials. */
- strlcpy(creds.service, "afs", sizeof creds.service);
- creds.instance[0] = '\0';
- strlcpy(creds.realm, server_cell, REALM_SZ);
- memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
- creds.issue_date = ct.BeginTimestamp;
- creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
- creds.kvno = ct.AuthHandle;
- snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
- creds.pinst[0] = '\0';
-
- /* Encode token, ship it off. */
- if (!creds_to_radix(&creds, (unsigned char*) buffer))
- break;
- packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
- packet_put_string(buffer, strlen(buffer));
- packet_send();
- packet_write_wait();
-
- /* Roger, Roger. Clearance, Clarence. What's your vector,
- Victor? */
- type = packet_read(&plen);
-
- if (type == SSH_SMSG_FAILURE)
- debug("AFS token for cell %s rejected.", server_cell);
- else if (type != SSH_SMSG_SUCCESS)
- packet_disconnect("Protocol error on AFS token response: %d", type);
- }
-}
-
-#endif /* AFS */
-
-/*
- * Tries to authenticate with any string-based challenge/response system.
- * Note that the client code is not tied to s/key or TIS.
- */
-int
-try_skey_authentication()
-{
- int type, i;
- int payload_len;
- unsigned int clen;
- char *challenge, *response;
-
- debug("Doing skey authentication.");
-
- /* request a challenge */
- packet_start(SSH_CMSG_AUTH_TIS);
- packet_send();
- packet_write_wait();
-
- type = packet_read(&payload_len);
- if (type != SSH_SMSG_FAILURE &&
- type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
- packet_disconnect("Protocol error: got %d in response "
- "to skey-auth", type);
- }
- if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
- debug("No challenge for skey authentication.");
- return 0;
- }
- challenge = packet_get_string(&clen);
- packet_integrity_check(payload_len, (4 + clen), type);
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! "
- "Reponse will be transmitted in clear text.");
- fprintf(stderr, "%s\n", challenge);
- xfree(challenge);
- fflush(stderr);
- for (i = 0; i < options.number_of_password_prompts; i++) {
- if (i != 0)
- error("Permission denied, please try again.");
- response = read_passphrase("Response: ", 0);
- packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
- packet_put_string(response, strlen(response));
- memset(response, 0, strlen(response));
- xfree(response);
- packet_send();
- packet_write_wait();
- type = packet_read(&payload_len);
- if (type == SSH_SMSG_SUCCESS)
- return 1;
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response "
- "to skey-auth-reponse", type);
+ t++;
}
- /* failure */
- return 0;
-}
+ return s;
-/*
- * Tries to authenticate with plain passwd authentication.
- */
-int
-try_password_authentication(char *prompt)
-{
- int type, i, payload_len;
- char *password;
-
- debug("Doing password authentication.");
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
- for (i = 0; i < options.number_of_password_prompts; i++) {
- if (i != 0)
- error("Permission denied, please try again.");
- password = read_passphrase(prompt, 0);
- packet_start(SSH_CMSG_AUTH_PASSWORD);
- packet_put_string(password, strlen(password));
- memset(password, 0, strlen(password));
- xfree(password);
- packet_send();
- packet_write_wait();
-
- type = packet_read(&payload_len);
- if (type == SSH_SMSG_SUCCESS)
- return 1;
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to passwd auth", type);
- }
- /* failure */
- return 0;
}
/*
@@ -957,7 +320,7 @@ void
ssh_exchange_identification()
{
char buf[256], remote_version[256]; /* must be same size! */
- int remote_major, remote_minor, i;
+ int remote_major, remote_minor, i, mismatch;
int connection_in = packet_get_connection_in();
int connection_out = packet_get_connection_out();
@@ -971,7 +334,7 @@ ssh_exchange_identification()
if (buf[i] == '\r') {
buf[i] = '\n';
buf[i + 1] = 0;
- break;
+ continue; /**XXX wait for \n */
}
if (buf[i] == '\n') {
buf[i + 1] = 0;
@@ -979,49 +342,73 @@ ssh_exchange_identification()
}
}
buf[sizeof(buf) - 1] = 0;
+ server_version_string = xstrdup(buf);
/*
* Check that the versions match. In future this might accept
* several versions and set appropriate flags to handle them.
*/
- if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
- remote_version) != 3)
+ if (sscanf(server_version_string, "SSH-%d.%d-%[^\n]\n",
+ &remote_major, &remote_minor, remote_version) != 3)
fatal("Bad remote protocol version identification: '%.100s'", buf);
debug("Remote protocol version %d.%d, remote software version %.100s",
remote_major, remote_minor, remote_version);
- /* Check if the remote protocol version is too old. */
- if (remote_major == 1 && remote_minor < 3)
- fatal("Remote machine has too old SSH software version.");
+ compat_datafellows(remote_version);
+ mismatch = 0;
- /* We speak 1.3, too. */
- if (remote_major == 1 && remote_minor == 3) {
- enable_compat13();
- if (options.forward_agent) {
- log("Agent forwarding disabled for protocol 1.3");
- options.forward_agent = 0;
+ switch(remote_major) {
+ case 1:
+ if (remote_minor == 99 &&
+ (options.protocol & SSH_PROTO_2) &&
+ !(options.protocol & SSH_PROTO_1_PREFERRED)) {
+ enable_compat20();
+ break;
+ }
+ if (!(options.protocol & SSH_PROTO_1)) {
+ mismatch = 1;
+ break;
+ }
+ if (remote_minor < 3) {
+ fatal("Remote machine has too old SSH software version.");
+ } else if (remote_minor == 3) {
+ /* We speak 1.3, too. */
+ enable_compat13();
+ if (options.forward_agent) {
+ log("Agent forwarding disabled for protocol 1.3");
+ options.forward_agent = 0;
+ }
+ }
+ break;
+ case 2:
+ if (options.protocol & SSH_PROTO_2) {
+ enable_compat20();
+ break;
}
+ /* FALLTHROUGH */
+ default:
+ mismatch = 1;
+ break;
}
-#if 0
- /*
- * Removed for now, to permit compatibility with latter versions. The
- * server will reject our version and disconnect if it doesn't
- * support it.
- */
- if (remote_major != PROTOCOL_MAJOR)
+ if (mismatch)
fatal("Protocol major versions differ: %d vs. %d",
- PROTOCOL_MAJOR, remote_major);
-#endif
-
+ (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+ remote_major);
+ if (compat20)
+ packet_set_ssh2_format();
/* Send our own protocol version identification. */
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
- PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
+ compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+ compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1,
+ SSH_VERSION);
if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
fatal("write: %.100s", strerror(errno));
+ client_version_string = xstrdup(buf);
+ chop(client_version_string);
+ chop(server_version_string);
+ debug("Local version string %.100s", client_version_string);
}
-int ssh_cipher_default = SSH_CIPHER_3DES;
-
int
read_yes_or_no(const char *prompt, int defval)
{
@@ -1070,9 +457,11 @@ read_yes_or_no(const char *prompt, int defval)
*/
void
-check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
+check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
+ const char *user_hostfile, const char *system_hostfile)
{
Key *file_key;
+ char *type = key_type(host_key);
char *ip = NULL;
char hostline[1000], *hostp;
HostStatus host_status;
@@ -1088,6 +477,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
* essentially disables host authentication for localhost; however,
* this is probably not a real problem.
*/
+ /** hostaddr == 0! */
switch (hostaddr->sa_family) {
case AF_INET:
local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
@@ -1128,19 +518,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
* Check if the host key is present in the user\'s list of known
* hosts or in the systemwide list.
*/
- host_status = check_host_in_hostfile(options.user_hostfile, host, host_key, file_key);
+ host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key);
if (host_status == HOST_NEW)
- host_status = check_host_in_hostfile(options.system_hostfile, host, host_key, file_key);
+ host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key);
/*
* Also perform check for the ip address, skip the check if we are
* localhost or the hostname was an ip address to begin with
*/
if (options.check_host_ip && !local && strcmp(host, ip)) {
Key *ip_key = key_new(host_key->type);
- ip_status = check_host_in_hostfile(options.user_hostfile, ip, host_key, ip_key);
+ ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
if (ip_status == HOST_NEW)
- ip_status = check_host_in_hostfile(options.system_hostfile, ip, host_key, ip_key);
+ ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key);
if (host_status == HOST_CHANGED &&
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
host_ip_differ = 1;
@@ -1154,18 +544,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
switch (host_status) {
case HOST_OK:
/* The host is known and the key matches. */
- debug("Host '%.200s' is known and matches the host key.", host);
+ debug("Host '%.200s' is known and matches the %s host key.",
+ host, type);
if (options.check_host_ip) {
if (ip_status == HOST_NEW) {
- if (!add_host_to_hostfile(options.user_hostfile, ip, host_key))
- log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).",
- ip, options.user_hostfile);
+ if (!add_host_to_hostfile(user_hostfile, ip, host_key))
+ log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).",
+ type, ip, user_hostfile);
else
- log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.",
- ip);
+ log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.",
+ type, ip);
} else if (ip_status != HOST_OK)
- log("Warning: the host key for '%.200s' differs from the key for the IP address '%.30s'",
- host, ip);
+ log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'",
+ type, host, ip);
}
break;
case HOST_NEW:
@@ -1173,16 +564,16 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
if (options.strict_host_key_checking == 1) {
/* User has requested strict host key checking. We will not add the host key
automatically. The only alternative left is to abort. */
- fatal("No host key is known for %.200s and you have requested strict checking.", host);
+ fatal("No %s host key is known for %.200s and you have requested strict checking.", type, host);
} else if (options.strict_host_key_checking == 2) {
/* The default */
char prompt[1024];
char *fp = key_fingerprint(host_key);
snprintf(prompt, sizeof(prompt),
"The authenticity of host '%.200s' can't be established.\n"
- "Key fingerprint is %s.\n"
+ "%s key fingerprint is %s.\n"
"Are you sure you want to continue connecting (yes/no)? ",
- host, fp);
+ host, type, fp);
if (!read_yes_or_no(prompt, -1))
fatal("Aborted by user!\n");
}
@@ -1193,12 +584,12 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
hostp = host;
/* If not in strict mode, add the key automatically to the local known_hosts file. */
- if (!add_host_to_hostfile(options.user_hostfile, hostp, host_key))
+ if (!add_host_to_hostfile(user_hostfile, hostp, host_key))
log("Failed to add the host to the list of known hosts (%.500s).",
- options.user_hostfile);
+ user_hostfile);
else
- log("Warning: Permanently added '%.200s' to the list of known hosts.",
- hostp);
+ log("Warning: Permanently added '%.200s' (%s) to the list of known hosts.",
+ hostp, type);
break;
case HOST_CHANGED:
if (options.check_host_ip && host_ip_differ) {
@@ -1212,7 +603,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
- error("The host key for %s has changed,", host);
+ error("The %s host key for %s has changed,", type, host);
error("and the key for the according IP address %s", ip);
error("%s. This could either mean that", msg);
error("DNS SPOOFING is happening or the IP address for the host");
@@ -1224,17 +615,17 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
- error("It is also possible that the host key has just been changed.");
+ error("It is also possible that the %s host key has just been changed.", type);
error("Please contact your system administrator.");
error("Add correct host key in %.100s to get rid of this message.",
- options.user_hostfile);
+ user_hostfile);
/*
* If strict host key checking is in use, the user will have
* to edit the key manually and we can only abort.
*/
if (options.strict_host_key_checking)
- fatal("Host key for %.200s has changed and you have requested strict checking.", host);
+ fatal("%s host key for %.200s has changed and you have requested strict checking.", type, host);
/*
* If strict host key checking has not been requested, allow
@@ -1261,349 +652,8 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
if (options.check_host_ip)
xfree(ip);
}
-void
-check_rsa_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key)
-{
- Key k;
- k.type = KEY_RSA;
- k.rsa = host_key;
- check_host_key(host, hostaddr, &k);
-}
-
-/*
- * SSH1 key exchange
- */
-void
-ssh_kex(char *host, struct sockaddr *hostaddr)
-{
- int i;
- BIGNUM *key;
- RSA *host_key;
- RSA *public_key;
- int bits, rbits;
- unsigned char session_key[SSH_SESSION_KEY_LENGTH];
- unsigned char cookie[8];
- unsigned int supported_ciphers;
- unsigned int server_flags, client_flags;
- int payload_len, clen, sum_len = 0;
- u_int32_t rand = 0;
-
- debug("Waiting for server public key.");
-
- /* Wait for a public key packet from the server. */
- packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
-
- /* Get cookie from the packet. */
- for (i = 0; i < 8; i++)
- cookie[i] = packet_get_char();
-
- /* Get the public key. */
- public_key = RSA_new();
- bits = packet_get_int();/* bits */
- public_key->e = BN_new();
- packet_get_bignum(public_key->e, &clen);
- sum_len += clen;
- public_key->n = BN_new();
- packet_get_bignum(public_key->n, &clen);
- sum_len += clen;
-
- rbits = BN_num_bits(public_key->n);
- if (bits != rbits) {
- log("Warning: Server lies about size of server public key: "
- "actual size is %d bits vs. announced %d.", rbits, bits);
- log("Warning: This may be due to an old implementation of ssh.");
- }
- /* Get the host key. */
- host_key = RSA_new();
- bits = packet_get_int();/* bits */
- host_key->e = BN_new();
- packet_get_bignum(host_key->e, &clen);
- sum_len += clen;
- host_key->n = BN_new();
- packet_get_bignum(host_key->n, &clen);
- sum_len += clen;
-
- rbits = BN_num_bits(host_key->n);
- if (bits != rbits) {
- log("Warning: Server lies about size of server host key: "
- "actual size is %d bits vs. announced %d.", rbits, bits);
- log("Warning: This may be due to an old implementation of ssh.");
- }
-
- /* Get protocol flags. */
- server_flags = packet_get_int();
- packet_set_protocol_flags(server_flags);
-
- supported_ciphers = packet_get_int();
- supported_authentications = packet_get_int();
-
- debug("Received server public key (%d bits) and host key (%d bits).",
- BN_num_bits(public_key->n), BN_num_bits(host_key->n));
-
- packet_integrity_check(payload_len,
- 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
- SSH_SMSG_PUBLIC_KEY);
-
- check_rsa_host_key(host, hostaddr, host_key);
-
- client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
-
- compute_session_id(session_id, cookie, host_key->n, public_key->n);
-
- /* Generate a session key. */
- arc4random_stir();
-
- /*
- * Generate an encryption key for the session. The key is a 256 bit
- * random number, interpreted as a 32-byte key, with the least
- * significant 8 bits being the first byte of the key.
- */
- for (i = 0; i < 32; i++) {
- if (i % 4 == 0)
- rand = arc4random();
- session_key[i] = rand & 0xff;
- rand >>= 8;
- }
-
- /*
- * According to the protocol spec, the first byte of the session key
- * is the highest byte of the integer. The session key is xored with
- * the first 16 bytes of the session id.
- */
- key = BN_new();
- BN_set_word(key, 0);
- for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
- BN_lshift(key, key, 8);
- if (i < 16)
- BN_add_word(key, session_key[i] ^ session_id[i]);
- else
- BN_add_word(key, session_key[i]);
- }
-
- /*
- * Encrypt the integer using the public key and host key of the
- * server (key with smaller modulus first).
- */
- if (BN_cmp(public_key->n, host_key->n) < 0) {
- /* Public key has smaller modulus. */
- if (BN_num_bits(host_key->n) <
- BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
- fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
- "SSH_KEY_BITS_RESERVED %d",
- BN_num_bits(host_key->n),
- BN_num_bits(public_key->n),
- SSH_KEY_BITS_RESERVED);
- }
- rsa_public_encrypt(key, key, public_key);
- rsa_public_encrypt(key, key, host_key);
- } else {
- /* Host key has smaller modulus (or they are equal). */
- if (BN_num_bits(public_key->n) <
- BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
- fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
- "SSH_KEY_BITS_RESERVED %d",
- BN_num_bits(public_key->n),
- BN_num_bits(host_key->n),
- SSH_KEY_BITS_RESERVED);
- }
- rsa_public_encrypt(key, key, host_key);
- rsa_public_encrypt(key, key, public_key);
- }
-
- /* Destroy the public keys since we no longer need them. */
- RSA_free(public_key);
- RSA_free(host_key);
-
- if (options.cipher == SSH_CIPHER_NOT_SET) {
- if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default))
- options.cipher = ssh_cipher_default;
- else {
- debug("Cipher %s not supported, using %.100s instead.",
- cipher_name(ssh_cipher_default),
- cipher_name(SSH_FALLBACK_CIPHER));
- options.cipher = SSH_FALLBACK_CIPHER;
- }
- }
- /* Check that the selected cipher is supported. */
- if (!(supported_ciphers & (1 << options.cipher)))
- fatal("Selected cipher type %.100s not supported by server.",
- cipher_name(options.cipher));
-
- debug("Encryption type: %.100s", cipher_name(options.cipher));
-
- /* Send the encrypted session key to the server. */
- packet_start(SSH_CMSG_SESSION_KEY);
- packet_put_char(options.cipher);
-
- /* Send the cookie back to the server. */
- for (i = 0; i < 8; i++)
- packet_put_char(cookie[i]);
-
- /* Send and destroy the encrypted encryption key integer. */
- packet_put_bignum(key);
- BN_clear_free(key);
-
- /* Send protocol flags. */
- packet_put_int(client_flags);
-
- /* Send the packet now. */
- packet_send();
- packet_write_wait();
-
- debug("Sent encrypted session key.");
-
- /* Set the encryption key. */
- packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
-
- /* We will no longer need the session key here. Destroy any extra copies. */
- memset(session_key, 0, sizeof(session_key));
-
- /*
- * Expect a success message from the server. Note that this message
- * will be received in encrypted form.
- */
- packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
-
- debug("Received encrypted confirmation.");
-}
/*
- * Authenticate user
- */
-void
-ssh_userauth(int host_key_valid, RSA *own_host_key,
- uid_t original_real_uid, char *host)
-{
- int i, type;
- int payload_len;
- struct passwd *pw;
- const char *server_user, *local_user;
-
- /* Get local user name. Use it as server user if no user name was given. */
- pw = getpwuid(original_real_uid);
- if (!pw)
- fatal("User id %d not found from user database.", original_real_uid);
- local_user = xstrdup(pw->pw_name);
- server_user = options.user ? options.user : local_user;
-
- /* Send the name of the user to log in as on the server. */
- packet_start(SSH_CMSG_USER);
- packet_put_string(server_user, strlen(server_user));
- packet_send();
- packet_write_wait();
-
- /*
- * The server should respond with success if no authentication is
- * needed (the user has no password). Otherwise the server responds
- * with failure.
- */
- type = packet_read(&payload_len);
-
- /* check whether the connection was accepted without authentication. */
- if (type == SSH_SMSG_SUCCESS)
- return;
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
- type);
-
-#ifdef AFS
- /* Try Kerberos tgt passing if the server supports it. */
- if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
- options.kerberos_tgt_passing) {
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
- (void) send_kerberos_tgt();
- }
- /* Try AFS token passing if the server supports it. */
- if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
- options.afs_token_passing && k_hasafs()) {
- if (options.cipher == SSH_CIPHER_NONE)
- log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
- send_afs_tokens();
- }
-#endif /* AFS */
-
-#ifdef KRB4
- if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
- options.kerberos_authentication) {
- debug("Trying Kerberos authentication.");
- if (try_kerberos_authentication()) {
- /* The server should respond with success or failure. */
- type = packet_read(&payload_len);
- if (type == SSH_SMSG_SUCCESS)
- return;
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
- }
- }
-#endif /* KRB4 */
-
- /*
- * Use rhosts authentication if running in privileged socket and we
- * do not wish to remain anonymous.
- */
- if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
- options.rhosts_authentication) {
- debug("Trying rhosts authentication.");
- packet_start(SSH_CMSG_AUTH_RHOSTS);
- packet_put_string(local_user, strlen(local_user));
- packet_send();
- packet_write_wait();
-
- /* The server should respond with success or failure. */
- type = packet_read(&payload_len);
- if (type == SSH_SMSG_SUCCESS)
- return;
- if (type != SSH_SMSG_FAILURE)
- packet_disconnect("Protocol error: got %d in response to rhosts auth",
- type);
- }
- /*
- * Try .rhosts or /etc/hosts.equiv authentication with RSA host
- * authentication.
- */
- if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
- options.rhosts_rsa_authentication && host_key_valid) {
- if (try_rhosts_rsa_authentication(local_user, own_host_key))
- return;
- }
- /* Try RSA authentication if the server supports it. */
- if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
- options.rsa_authentication) {
- /*
- * Try RSA authentication using the authentication agent. The
- * agent is tried first because no passphrase is needed for
- * it, whereas identity files may require passphrases.
- */
- if (try_agent_authentication())
- return;
-
- /* Try RSA authentication for each identity. */
- for (i = 0; i < options.num_identity_files; i++)
- if (try_rsa_authentication(options.identity_files[i]))
- return;
- }
- /* Try skey authentication if the server supports it. */
- if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
- options.skey_authentication && !options.batch_mode) {
- if (try_skey_authentication())
- return;
- }
- /* Try password authentication if the server supports it. */
- if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
- options.password_authentication && !options.batch_mode) {
- char prompt[80];
-
- snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
- server_user, host);
- if (try_password_authentication(prompt))
- return;
- }
- /* All authentication methods have failed. Exit with an error message. */
- fatal("Permission denied.");
- /* NOTREACHED */
-}
-/*
* Starts a dialog with the server, and authenticates the current user on the
* server. This does not need any extra privileges. The basic connection
* to the server must already have been established before this is called.
@@ -1614,7 +664,16 @@ void
ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
struct sockaddr *hostaddr, uid_t original_real_uid)
{
+ struct passwd *pw;
char *host, *cp;
+ char *server_user, *local_user;
+
+ /* Get local user name. Use it as server user if no user name was given. */
+ pw = getpwuid(original_real_uid);
+ if (!pw)
+ fatal("User id %d not found from user database.", original_real_uid);
+ local_user = xstrdup(pw->pw_name);
+ server_user = options.user ? options.user : local_user;
/* Convert the user-supplied hostname into all lowercase. */
host = xstrdup(orighost);
@@ -1628,12 +687,13 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
/* Put the connection into non-blocking mode. */
packet_set_nonblocking();
- supported_authentications = 0;
/* key exchange */
- ssh_kex(host, hostaddr);
- if (supported_authentications == 0)
- fatal("supported_authentications == 0.");
-
/* authenticate user */
- ssh_userauth(host_key_valid, own_host_key, original_real_uid, host);
+ if (compat20) {
+ ssh_kex2(host, hostaddr);
+ ssh_userauth2(server_user, host);
+ } else {
+ ssh_kex(host, hostaddr);
+ ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key);
+ }
}
diff --git a/crypto/openssh/sshconnect.h b/crypto/openssh/sshconnect.h
new file mode 100644
index 000000000000..13d395fd634d
--- /dev/null
+++ b/crypto/openssh/sshconnect.h
@@ -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
diff --git a/crypto/openssh/sshconnect1.c b/crypto/openssh/sshconnect1.c
new file mode 100644
index 000000000000..4360d7283d86
--- /dev/null
+++ b/crypto/openssh/sshconnect1.c
@@ -0,0 +1,1024 @@
+/*
+ * 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 22:15:47 1995 ylo
+ * Code to connect to a remote host, and to perform the client side of the
+ * login (authentication) dialog.
+ *
+ */
+
+#include "includes.h"
+RCSID("$OpenBSD: sshconnect1.c,v 1.3 2000/05/08 17:12:16 markus Exp $");
+
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh.h"
+#include "buffer.h"
+#include "packet.h"
+#include "authfd.h"
+#include "cipher.h"
+#include "mpaux.h"
+#include "uidswap.h"
+#include "readconf.h"
+#include "key.h"
+#include "sshconnect.h"
+#include "authfile.h"
+
+/* Session id for the current session. */
+unsigned char session_id[16];
+unsigned int supported_authentications = 0;
+
+extern Options options;
+extern char *__progname;
+
+/*
+ * Checks if the user has an authentication agent, and if so, tries to
+ * authenticate using the agent.
+ */
+int
+try_agent_authentication()
+{
+ int status, type;
+ char *comment;
+ AuthenticationConnection *auth;
+ unsigned char response[16];
+ unsigned int i;
+ BIGNUM *e, *n, *challenge;
+
+ /* Get connection to the agent. */
+ auth = ssh_get_authentication_connection();
+ if (!auth)
+ return 0;
+
+ e = BN_new();
+ n = BN_new();
+ challenge = BN_new();
+
+ /* Loop through identities served by the agent. */
+ for (status = ssh_get_first_identity(auth, e, n, &comment);
+ status;
+ status = ssh_get_next_identity(auth, e, n, &comment)) {
+ int plen, clen;
+
+ /* Try this identity. */
+ debug("Trying RSA authentication via agent with '%.100s'", comment);
+ xfree(comment);
+
+ /* Tell the server that we are willing to authenticate using this key. */
+ packet_start(SSH_CMSG_AUTH_RSA);
+ packet_put_bignum(n);
+ packet_send();
+ packet_write_wait();
+
+ /* Wait for server's response. */
+ type = packet_read(&plen);
+
+ /* The server sends failure if it doesn\'t like our key or
+ does not support RSA authentication. */
+ if (type == SSH_SMSG_FAILURE) {
+ debug("Server refused our key.");
+ continue;
+ }
+ /* Otherwise it should have sent a challenge. */
+ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+ packet_disconnect("Protocol error during RSA authentication: %d",
+ type);
+
+ packet_get_bignum(challenge, &clen);
+
+ packet_integrity_check(plen, clen, type);
+
+ debug("Received RSA challenge from server.");
+
+ /* Ask the agent to decrypt the challenge. */
+ if (!ssh_decrypt_challenge(auth, e, n, challenge,
+ session_id, 1, response)) {
+ /* The agent failed to authenticate this identifier although it
+ advertised it supports this. Just return a wrong value. */
+ log("Authentication agent failed to decrypt challenge.");
+ memset(response, 0, sizeof(response));
+ }
+ debug("Sending response to RSA challenge.");
+
+ /* Send the decrypted challenge back to the server. */
+ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ packet_put_char(response[i]);
+ packet_send();
+ packet_write_wait();
+
+ /* Wait for response from the server. */
+ type = packet_read(&plen);
+
+ /* The server returns success if it accepted the authentication. */
+ if (type == SSH_SMSG_SUCCESS) {
+ debug("RSA authentication accepted by server.");
+ BN_clear_free(e);
+ BN_clear_free(n);
+ BN_clear_free(challenge);
+ return 1;
+ }
+ /* Otherwise it should return failure. */
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error waiting RSA auth response: %d",
+ type);
+ }
+
+ BN_clear_free(e);
+ BN_clear_free(n);
+ BN_clear_free(challenge);
+
+ debug("RSA authentication using agent refused.");
+ return 0;
+}
+
+/*
+ * Computes the proper response to a RSA challenge, and sends the response to
+ * the server.
+ */
+void
+respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
+{
+ unsigned char buf[32], response[16];
+ MD5_CTX md;
+ int i, len;
+
+ /* Decrypt the challenge using the private key. */
+ rsa_private_decrypt(challenge, challenge, prv);
+
+ /* Compute the response. */
+ /* The response is MD5 of decrypted challenge plus session id. */
+ len = BN_num_bytes(challenge);
+ if (len <= 0 || len > sizeof(buf))
+ packet_disconnect("respond_to_rsa_challenge: bad challenge length %d",
+ len);
+
+ memset(buf, 0, sizeof(buf));
+ BN_bn2bin(challenge, buf + sizeof(buf) - len);
+ MD5_Init(&md);
+ MD5_Update(&md, buf, 32);
+ MD5_Update(&md, session_id, 16);
+ MD5_Final(response, &md);
+
+ debug("Sending response to host key RSA challenge.");
+
+ /* Send the response back to the server. */
+ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ packet_put_char(response[i]);
+ packet_send();
+ packet_write_wait();
+
+ memset(buf, 0, sizeof(buf));
+ memset(response, 0, sizeof(response));
+ memset(&md, 0, sizeof(md));
+}
+
+/*
+ * Checks if the user has authentication file, and if so, tries to authenticate
+ * the user using it.
+ */
+int
+try_rsa_authentication(const char *authfile)
+{
+ BIGNUM *challenge;
+ Key *public;
+ Key *private;
+ char *passphrase, *comment;
+ int type, i;
+ int plen, clen;
+
+ /* Try to load identification for the authentication key. */
+ public = key_new(KEY_RSA);
+ if (!load_public_key(authfile, public, &comment)) {
+ key_free(public);
+ /* Could not load it. Fail. */
+ return 0;
+ }
+ debug("Trying RSA authentication with key '%.100s'", comment);
+
+ /* Tell the server that we are willing to authenticate using this key. */
+ packet_start(SSH_CMSG_AUTH_RSA);
+ packet_put_bignum(public->rsa->n);
+ packet_send();
+ packet_write_wait();
+
+ /* We no longer need the public key. */
+ key_free(public);
+
+ /* Wait for server's response. */
+ type = packet_read(&plen);
+
+ /*
+ * The server responds with failure if it doesn\'t like our key or
+ * doesn\'t support RSA authentication.
+ */
+ if (type == SSH_SMSG_FAILURE) {
+ debug("Server refused our key.");
+ xfree(comment);
+ return 0;
+ }
+ /* Otherwise, the server should respond with a challenge. */
+ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+ packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+ /* Get the challenge from the packet. */
+ challenge = BN_new();
+ packet_get_bignum(challenge, &clen);
+
+ packet_integrity_check(plen, clen, type);
+
+ debug("Received RSA challenge from server.");
+
+ private = key_new(KEY_RSA);
+ /*
+ * Load the private key. Try first with empty passphrase; if it
+ * fails, ask for a passphrase.
+ */
+ if (!load_private_key(authfile, "", private, NULL)) {
+ char buf[300];
+ snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
+ comment);
+ if (!options.batch_mode)
+ passphrase = read_passphrase(buf, 0);
+ else {
+ debug("Will not query passphrase for %.100s in batch mode.",
+ comment);
+ passphrase = xstrdup("");
+ }
+
+ /* Load the authentication file using the pasphrase. */
+ if (!load_private_key(authfile, passphrase, private, NULL)) {
+ memset(passphrase, 0, strlen(passphrase));
+ xfree(passphrase);
+ error("Bad passphrase.");
+
+ /* Send a dummy response packet to avoid protocol error. */
+ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE);
+ for (i = 0; i < 16; i++)
+ packet_put_char(0);
+ packet_send();
+ packet_write_wait();
+
+ /* Expect the server to reject it... */
+ packet_read_expect(&plen, SSH_SMSG_FAILURE);
+ xfree(comment);
+ return 0;
+ }
+ /* Destroy the passphrase. */
+ memset(passphrase, 0, strlen(passphrase));
+ xfree(passphrase);
+ }
+ /* We no longer need the comment. */
+ xfree(comment);
+
+ /* Compute and send a response to the challenge. */
+ respond_to_rsa_challenge(challenge, private->rsa);
+
+ /* Destroy the private key. */
+ key_free(private);
+
+ /* We no longer need the challenge. */
+ BN_clear_free(challenge);
+
+ /* Wait for response from the server. */
+ type = packet_read(&plen);
+ if (type == SSH_SMSG_SUCCESS) {
+ debug("RSA authentication accepted by server.");
+ return 1;
+ }
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error waiting RSA auth response: %d", type);
+ debug("RSA authentication refused.");
+ return 0;
+}
+
+/*
+ * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv
+ * authentication and RSA host authentication.
+ */
+int
+try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
+{
+ int type;
+ BIGNUM *challenge;
+ int plen, clen;
+
+ debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
+
+ /* Tell the server that we are willing to authenticate using this key. */
+ packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
+ packet_put_string(local_user, strlen(local_user));
+ packet_put_int(BN_num_bits(host_key->n));
+ packet_put_bignum(host_key->e);
+ packet_put_bignum(host_key->n);
+ packet_send();
+ packet_write_wait();
+
+ /* Wait for server's response. */
+ type = packet_read(&plen);
+
+ /* The server responds with failure if it doesn't admit our
+ .rhosts authentication or doesn't know our host key. */
+ if (type == SSH_SMSG_FAILURE) {
+ debug("Server refused our rhosts authentication or host key.");
+ return 0;
+ }
+ /* Otherwise, the server should respond with a challenge. */
+ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE)
+ packet_disconnect("Protocol error during RSA authentication: %d", type);
+
+ /* Get the challenge from the packet. */
+ challenge = BN_new();
+ packet_get_bignum(challenge, &clen);
+
+ packet_integrity_check(plen, clen, type);
+
+ debug("Received RSA challenge for host key from server.");
+
+ /* Compute a response to the challenge. */
+ respond_to_rsa_challenge(challenge, host_key);
+
+ /* We no longer need the challenge. */
+ BN_clear_free(challenge);
+
+ /* Wait for response from the server. */
+ type = packet_read(&plen);
+ if (type == SSH_SMSG_SUCCESS) {
+ debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server.");
+ return 1;
+ }
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error waiting RSA auth response: %d", type);
+ debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused.");
+ return 0;
+}
+
+#ifdef KRB4
+int
+try_kerberos_authentication()
+{
+ KTEXT_ST auth; /* Kerberos data */
+ char *reply;
+ char inst[INST_SZ];
+ char *realm;
+ CREDENTIALS cred;
+ int r, type, plen;
+ socklen_t slen;
+ Key_schedule schedule;
+ u_long checksum, cksum;
+ MSG_DAT msg_data;
+ struct sockaddr_in local, foreign;
+ struct stat st;
+
+ /* Don't do anything if we don't have any tickets. */
+ if (stat(tkt_string(), &st) < 0)
+ return 0;
+
+ strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ);
+
+ realm = (char *) krb_realmofhost(get_canonical_hostname());
+ if (!realm) {
+ debug("Kerberos V4: no realm for %s", get_canonical_hostname());
+ return 0;
+ }
+ /* This can really be anything. */
+ checksum = (u_long) getpid();
+
+ r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum);
+ if (r != KSUCCESS) {
+ debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]);
+ return 0;
+ }
+ /* Get session key to decrypt the server's reply with. */
+ r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred);
+ if (r != KSUCCESS) {
+ debug("get_cred failed: %s", krb_err_txt[r]);
+ return 0;
+ }
+ des_key_sched((des_cblock *) cred.session, schedule);
+
+ /* Send authentication info to server. */
+ packet_start(SSH_CMSG_AUTH_KERBEROS);
+ packet_put_string((char *) auth.dat, auth.length);
+ packet_send();
+ packet_write_wait();
+
+ /* Zero the buffer. */
+ (void) memset(auth.dat, 0, MAX_KTXT_LEN);
+
+ slen = sizeof(local);
+ memset(&local, 0, sizeof(local));
+ if (getsockname(packet_get_connection_in(),
+ (struct sockaddr *) & local, &slen) < 0)
+ debug("getsockname failed: %s", strerror(errno));
+
+ slen = sizeof(foreign);
+ memset(&foreign, 0, sizeof(foreign));
+ if (getpeername(packet_get_connection_in(),
+ (struct sockaddr *) & foreign, &slen) < 0) {
+ debug("getpeername failed: %s", strerror(errno));
+ fatal_cleanup();
+ }
+ /* Get server reply. */
+ type = packet_read(&plen);
+ switch (type) {
+ case SSH_SMSG_FAILURE:
+ /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */
+ debug("Kerberos V4 authentication failed.");
+ return 0;
+ break;
+
+ case SSH_SMSG_AUTH_KERBEROS_RESPONSE:
+ /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */
+ debug("Kerberos V4 authentication accepted.");
+
+ /* Get server's response. */
+ reply = packet_get_string((unsigned int *) &auth.length);
+ memcpy(auth.dat, reply, auth.length);
+ xfree(reply);
+
+ packet_integrity_check(plen, 4 + auth.length, type);
+
+ /*
+ * If his response isn't properly encrypted with the session
+ * key, and the decrypted checksum fails to match, he's
+ * bogus. Bail out.
+ */
+ r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session,
+ &foreign, &local, &msg_data);
+ if (r != KSUCCESS) {
+ debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]);
+ packet_disconnect("Kerberos V4 challenge failed!");
+ }
+ /* Fetch the (incremented) checksum that we supplied in the request. */
+ (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum));
+ cksum = ntohl(cksum);
+
+ /* If it matches, we're golden. */
+ if (cksum == checksum + 1) {
+ debug("Kerberos V4 challenge successful.");
+ return 1;
+ } else
+ packet_disconnect("Kerberos V4 challenge failed!");
+ break;
+
+ default:
+ packet_disconnect("Protocol error on Kerberos V4 response: %d", type);
+ }
+ return 0;
+}
+
+#endif /* KRB4 */
+
+#ifdef AFS
+int
+send_kerberos_tgt()
+{
+ CREDENTIALS *creds;
+ char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
+ int r, type, plen;
+ char buffer[8192];
+ struct stat st;
+
+ /* Don't do anything if we don't have any tickets. */
+ if (stat(tkt_string(), &st) < 0)
+ return 0;
+
+ creds = xmalloc(sizeof(*creds));
+
+ if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) {
+ debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]);
+ return 0;
+ }
+ if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) {
+ debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]);
+ return 0;
+ }
+ if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) {
+ debug("Kerberos V4 ticket expired: %s", TKT_FILE);
+ return 0;
+ }
+ creds_to_radix(creds, (unsigned char *)buffer, sizeof buffer);
+ xfree(creds);
+
+ packet_start(SSH_CMSG_HAVE_KERBEROS_TGT);
+ packet_put_string(buffer, strlen(buffer));
+ packet_send();
+ packet_write_wait();
+
+ type = packet_read(&plen);
+
+ if (type == SSH_SMSG_FAILURE)
+ debug("Kerberos TGT for realm %s rejected.", prealm);
+ else if (type != SSH_SMSG_SUCCESS)
+ packet_disconnect("Protocol error on Kerberos TGT response: %d", type);
+
+ return 1;
+}
+
+void
+send_afs_tokens(void)
+{
+ CREDENTIALS creds;
+ struct ViceIoctl parms;
+ struct ClearToken ct;
+ int i, type, len, plen;
+ char buf[2048], *p, *server_cell;
+ char buffer[8192];
+
+ /* Move over ktc_GetToken, here's something leaner. */
+ for (i = 0; i < 100; i++) { /* just in case */
+ parms.in = (char *) &i;
+ parms.in_size = sizeof(i);
+ parms.out = buf;
+ parms.out_size = sizeof(buf);
+ if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0)
+ break;
+ p = buf;
+
+ /* Get secret token. */
+ memcpy(&creds.ticket_st.length, p, sizeof(unsigned int));
+ if (creds.ticket_st.length > MAX_KTXT_LEN)
+ break;
+ p += sizeof(unsigned int);
+ memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
+ p += creds.ticket_st.length;
+
+ /* Get clear token. */
+ memcpy(&len, p, sizeof(len));
+ if (len != sizeof(struct ClearToken))
+ break;
+ p += sizeof(len);
+ memcpy(&ct, p, len);
+ p += len;
+ p += sizeof(len); /* primary flag */
+ server_cell = p;
+
+ /* Flesh out our credentials. */
+ strlcpy(creds.service, "afs", sizeof creds.service);
+ creds.instance[0] = '\0';
+ strlcpy(creds.realm, server_cell, REALM_SZ);
+ memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ);
+ creds.issue_date = ct.BeginTimestamp;
+ creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp);
+ creds.kvno = ct.AuthHandle;
+ snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId);
+ creds.pinst[0] = '\0';
+
+ /* Encode token, ship it off. */
+ if (creds_to_radix(&creds, (unsigned char*) buffer, sizeof buffer) <= 0)
+ break;
+ packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
+ packet_put_string(buffer, strlen(buffer));
+ packet_send();
+ packet_write_wait();
+
+ /* Roger, Roger. Clearance, Clarence. What's your vector,
+ Victor? */
+ type = packet_read(&plen);
+
+ if (type == SSH_SMSG_FAILURE)
+ debug("AFS token for cell %s rejected.", server_cell);
+ else if (type != SSH_SMSG_SUCCESS)
+ packet_disconnect("Protocol error on AFS token response: %d", type);
+ }
+}
+
+#endif /* AFS */
+
+/*
+ * Tries to authenticate with any string-based challenge/response system.
+ * Note that the client code is not tied to s/key or TIS.
+ */
+int
+try_skey_authentication()
+{
+ int type, i;
+ int payload_len;
+ unsigned int clen;
+ char *challenge, *response;
+
+ debug("Doing skey authentication.");
+
+ /* request a challenge */
+ packet_start(SSH_CMSG_AUTH_TIS);
+ packet_send();
+ packet_write_wait();
+
+ type = packet_read(&payload_len);
+ if (type != SSH_SMSG_FAILURE &&
+ type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+ packet_disconnect("Protocol error: got %d in response "
+ "to skey-auth", type);
+ }
+ if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
+ debug("No challenge for skey authentication.");
+ return 0;
+ }
+ challenge = packet_get_string(&clen);
+ packet_integrity_check(payload_len, (4 + clen), type);
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! "
+ "Reponse will be transmitted in clear text.");
+ fprintf(stderr, "%s\n", challenge);
+ xfree(challenge);
+ fflush(stderr);
+ for (i = 0; i < options.number_of_password_prompts; i++) {
+ if (i != 0)
+ error("Permission denied, please try again.");
+ response = read_passphrase("Response: ", 0);
+ packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
+ packet_put_string(response, strlen(response));
+ memset(response, 0, strlen(response));
+ xfree(response);
+ packet_send();
+ packet_write_wait();
+ type = packet_read(&payload_len);
+ if (type == SSH_SMSG_SUCCESS)
+ return 1;
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error: got %d in response "
+ "to skey-auth-reponse", type);
+ }
+ /* failure */
+ return 0;
+}
+
+/*
+ * Tries to authenticate with plain passwd authentication.
+ */
+int
+try_password_authentication(char *prompt)
+{
+ int type, i, payload_len;
+ char *password;
+
+ debug("Doing password authentication.");
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
+ for (i = 0; i < options.number_of_password_prompts; i++) {
+ if (i != 0)
+ error("Permission denied, please try again.");
+ password = read_passphrase(prompt, 0);
+ packet_start(SSH_CMSG_AUTH_PASSWORD);
+ packet_put_string(password, strlen(password));
+ memset(password, 0, strlen(password));
+ xfree(password);
+ packet_send();
+ packet_write_wait();
+
+ type = packet_read(&payload_len);
+ if (type == SSH_SMSG_SUCCESS)
+ return 1;
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error: got %d in response to passwd auth", type);
+ }
+ /* failure */
+ return 0;
+}
+
+/*
+ * SSH1 key exchange
+ */
+void
+ssh_kex(char *host, struct sockaddr *hostaddr)
+{
+ int i;
+ BIGNUM *key;
+ RSA *host_key;
+ RSA *public_key;
+ Key k;
+ int bits, rbits;
+ int ssh_cipher_default = SSH_CIPHER_3DES;
+ unsigned char session_key[SSH_SESSION_KEY_LENGTH];
+ unsigned char cookie[8];
+ unsigned int supported_ciphers;
+ unsigned int server_flags, client_flags;
+ int payload_len, clen, sum_len = 0;
+ u_int32_t rand = 0;
+
+ debug("Waiting for server public key.");
+
+ /* Wait for a public key packet from the server. */
+ packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY);
+
+ /* Get cookie from the packet. */
+ for (i = 0; i < 8; i++)
+ cookie[i] = packet_get_char();
+
+ /* Get the public key. */
+ public_key = RSA_new();
+ bits = packet_get_int();/* bits */
+ public_key->e = BN_new();
+ packet_get_bignum(public_key->e, &clen);
+ sum_len += clen;
+ public_key->n = BN_new();
+ packet_get_bignum(public_key->n, &clen);
+ sum_len += clen;
+
+ rbits = BN_num_bits(public_key->n);
+ if (bits != rbits) {
+ log("Warning: Server lies about size of server public key: "
+ "actual size is %d bits vs. announced %d.", rbits, bits);
+ log("Warning: This may be due to an old implementation of ssh.");
+ }
+ /* Get the host key. */
+ host_key = RSA_new();
+ bits = packet_get_int();/* bits */
+ host_key->e = BN_new();
+ packet_get_bignum(host_key->e, &clen);
+ sum_len += clen;
+ host_key->n = BN_new();
+ packet_get_bignum(host_key->n, &clen);
+ sum_len += clen;
+
+ rbits = BN_num_bits(host_key->n);
+ if (bits != rbits) {
+ log("Warning: Server lies about size of server host key: "
+ "actual size is %d bits vs. announced %d.", rbits, bits);
+ log("Warning: This may be due to an old implementation of ssh.");
+ }
+
+ /* Get protocol flags. */
+ server_flags = packet_get_int();
+ packet_set_protocol_flags(server_flags);
+
+ supported_ciphers = packet_get_int();
+ supported_authentications = packet_get_int();
+
+ debug("Received server public key (%d bits) and host key (%d bits).",
+ BN_num_bits(public_key->n), BN_num_bits(host_key->n));
+
+ packet_integrity_check(payload_len,
+ 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
+ SSH_SMSG_PUBLIC_KEY);
+ k.type = KEY_RSA;
+ k.rsa = host_key;
+ check_host_key(host, hostaddr, &k,
+ options.user_hostfile, options.system_hostfile);
+
+ client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
+
+ compute_session_id(session_id, cookie, host_key->n, public_key->n);
+
+ /* Generate a session key. */
+ arc4random_stir();
+
+ /*
+ * Generate an encryption key for the session. The key is a 256 bit
+ * random number, interpreted as a 32-byte key, with the least
+ * significant 8 bits being the first byte of the key.
+ */
+ for (i = 0; i < 32; i++) {
+ if (i % 4 == 0)
+ rand = arc4random();
+ session_key[i] = rand & 0xff;
+ rand >>= 8;
+ }
+
+ /*
+ * According to the protocol spec, the first byte of the session key
+ * is the highest byte of the integer. The session key is xored with
+ * the first 16 bytes of the session id.
+ */
+ key = BN_new();
+ BN_set_word(key, 0);
+ for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+ BN_lshift(key, key, 8);
+ if (i < 16)
+ BN_add_word(key, session_key[i] ^ session_id[i]);
+ else
+ BN_add_word(key, session_key[i]);
+ }
+
+ /*
+ * Encrypt the integer using the public key and host key of the
+ * server (key with smaller modulus first).
+ */
+ if (BN_cmp(public_key->n, host_key->n) < 0) {
+ /* Public key has smaller modulus. */
+ if (BN_num_bits(host_key->n) <
+ BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) {
+ fatal("respond_to_rsa_challenge: host_key %d < public_key %d + "
+ "SSH_KEY_BITS_RESERVED %d",
+ BN_num_bits(host_key->n),
+ BN_num_bits(public_key->n),
+ SSH_KEY_BITS_RESERVED);
+ }
+ rsa_public_encrypt(key, key, public_key);
+ rsa_public_encrypt(key, key, host_key);
+ } else {
+ /* Host key has smaller modulus (or they are equal). */
+ if (BN_num_bits(public_key->n) <
+ BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) {
+ fatal("respond_to_rsa_challenge: public_key %d < host_key %d + "
+ "SSH_KEY_BITS_RESERVED %d",
+ BN_num_bits(public_key->n),
+ BN_num_bits(host_key->n),
+ SSH_KEY_BITS_RESERVED);
+ }
+ rsa_public_encrypt(key, key, host_key);
+ rsa_public_encrypt(key, key, public_key);
+ }
+
+ /* Destroy the public keys since we no longer need them. */
+ RSA_free(public_key);
+ RSA_free(host_key);
+
+ if (options.cipher == SSH_CIPHER_ILLEGAL) {
+ log("No valid SSH1 cipher, using %.100s instead.",
+ cipher_name(SSH_FALLBACK_CIPHER));
+ options.cipher = SSH_FALLBACK_CIPHER;
+ } else if (options.cipher == SSH_CIPHER_NOT_SET) {
+ if (cipher_mask1() & supported_ciphers & (1 << ssh_cipher_default))
+ options.cipher = ssh_cipher_default;
+ else {
+ debug("Cipher %s not supported, using %.100s instead.",
+ cipher_name(ssh_cipher_default),
+ cipher_name(SSH_FALLBACK_CIPHER));
+ options.cipher = SSH_FALLBACK_CIPHER;
+ }
+ }
+ /* Check that the selected cipher is supported. */
+ if (!(supported_ciphers & (1 << options.cipher)))
+ fatal("Selected cipher type %.100s not supported by server.",
+ cipher_name(options.cipher));
+
+ debug("Encryption type: %.100s", cipher_name(options.cipher));
+
+ /* Send the encrypted session key to the server. */
+ packet_start(SSH_CMSG_SESSION_KEY);
+ packet_put_char(options.cipher);
+
+ /* Send the cookie back to the server. */
+ for (i = 0; i < 8; i++)
+ packet_put_char(cookie[i]);
+
+ /* Send and destroy the encrypted encryption key integer. */
+ packet_put_bignum(key);
+ BN_clear_free(key);
+
+ /* Send protocol flags. */
+ packet_put_int(client_flags);
+
+ /* Send the packet now. */
+ packet_send();
+ packet_write_wait();
+
+ debug("Sent encrypted session key.");
+
+ /* Set the encryption key. */
+ packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher);
+
+ /* We will no longer need the session key here. Destroy any extra copies. */
+ memset(session_key, 0, sizeof(session_key));
+
+ /*
+ * Expect a success message from the server. Note that this message
+ * will be received in encrypted form.
+ */
+ packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
+
+ debug("Received encrypted confirmation.");
+}
+
+/*
+ * Authenticate user
+ */
+void
+ssh_userauth(
+ const char* local_user,
+ const char* server_user,
+ char *host,
+ int host_key_valid, RSA *own_host_key)
+{
+ int i, type;
+ int payload_len;
+
+ if (supported_authentications == 0)
+ fatal("ssh_userauth: server supports no auth methods");
+
+ /* Send the name of the user to log in as on the server. */
+ packet_start(SSH_CMSG_USER);
+ packet_put_string(server_user, strlen(server_user));
+ packet_send();
+ packet_write_wait();
+
+ /*
+ * The server should respond with success if no authentication is
+ * needed (the user has no password). Otherwise the server responds
+ * with failure.
+ */
+ type = packet_read(&payload_len);
+
+ /* check whether the connection was accepted without authentication. */
+ if (type == SSH_SMSG_SUCCESS)
+ return;
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER",
+ type);
+
+#ifdef AFS
+ /* Try Kerberos tgt passing if the server supports it. */
+ if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) &&
+ options.kerberos_tgt_passing) {
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!");
+ (void) send_kerberos_tgt();
+ }
+ /* Try AFS token passing if the server supports it. */
+ if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) &&
+ options.afs_token_passing && k_hasafs()) {
+ if (options.cipher == SSH_CIPHER_NONE)
+ log("WARNING: Encryption is disabled! Token will be transmitted in the clear!");
+ send_afs_tokens();
+ }
+#endif /* AFS */
+
+#ifdef KRB4
+ if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
+ options.kerberos_authentication) {
+ debug("Trying Kerberos authentication.");
+ if (try_kerberos_authentication()) {
+ /* The server should respond with success or failure. */
+ type = packet_read(&payload_len);
+ if (type == SSH_SMSG_SUCCESS)
+ return;
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
+ }
+ }
+#endif /* KRB4 */
+
+ /*
+ * Use rhosts authentication if running in privileged socket and we
+ * do not wish to remain anonymous.
+ */
+ if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) &&
+ options.rhosts_authentication) {
+ debug("Trying rhosts authentication.");
+ packet_start(SSH_CMSG_AUTH_RHOSTS);
+ packet_put_string(local_user, strlen(local_user));
+ packet_send();
+ packet_write_wait();
+
+ /* The server should respond with success or failure. */
+ type = packet_read(&payload_len);
+ if (type == SSH_SMSG_SUCCESS)
+ return;
+ if (type != SSH_SMSG_FAILURE)
+ packet_disconnect("Protocol error: got %d in response to rhosts auth",
+ type);
+ }
+ /*
+ * Try .rhosts or /etc/hosts.equiv authentication with RSA host
+ * authentication.
+ */
+ if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
+ options.rhosts_rsa_authentication && host_key_valid) {
+ if (try_rhosts_rsa_authentication(local_user, own_host_key))
+ return;
+ }
+ /* Try RSA authentication if the server supports it. */
+ if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
+ options.rsa_authentication) {
+ /*
+ * Try RSA authentication using the authentication agent. The
+ * agent is tried first because no passphrase is needed for
+ * it, whereas identity files may require passphrases.
+ */
+ if (try_agent_authentication())
+ return;
+
+ /* Try RSA authentication for each identity. */
+ for (i = 0; i < options.num_identity_files; i++)
+ if (try_rsa_authentication(options.identity_files[i]))
+ return;
+ }
+ /* Try skey authentication if the server supports it. */
+ if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
+ options.skey_authentication && !options.batch_mode) {
+ if (try_skey_authentication())
+ return;
+ }
+ /* Try password authentication if the server supports it. */
+ if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) &&
+ options.password_authentication && !options.batch_mode) {
+ char prompt[80];
+
+ snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
+ server_user, host);
+ if (try_password_authentication(prompt))
+ return;
+ }
+ /* All authentication methods have failed. Exit with an error message. */
+ fatal("Permission denied.");
+ /* NOTREACHED */
+}
diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c
new file mode 100644
index 000000000000..99ffb2c478d4
--- /dev/null
+++ b/crypto/openssh/sshconnect2.c
@@ -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");
+}
diff --git a/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8
index 24b1a352bfe6..3fb255af05f4 100644
--- a/crypto/openssh/sshd.8
+++ b/crypto/openssh/sshd.8
@@ -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 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
+disables protocol 2.0 if this file is group/world-accessible.
.It Cm HostKey
-Specifies the file containing the private host key (default
-.Pa /etc/ssh_host_key ) .
+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
-does not start if this file is group/world-accessible.
+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
diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c
index 6a5625394ffa..0d62320a1183 100644
--- a/crypto/openssh/sshd.c
+++ b/crypto/openssh/sshd.c
@@ -8,22 +8,39 @@
* information to/from the application to the user client over an encrypted
* connection. This can also handle forwarding of X11, TCP/IP, and authentication
* agent connections.
+ *
+ * SSH2 implementation,
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
*/
#include "includes.h"
-RCSID("$OpenBSD: sshd.c,v 1.94 2000/03/23 22:15:34 markus Exp $");
+RCSID("$OpenBSD: sshd.c,v 1.115 2000/05/03 10:21:49 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 "uidswap.h"
#include "compat.h"
+#include "buffer.h"
+
+#include "ssh2.h"
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/hmac.h>
+#include "kex.h"
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include "key.h"
+#include "dsa.h"
+
+#include "auth.h"
+#include "myproposal.h"
+#include "authfile.h"
#ifdef LIBWRAP
#include <tcpd.h>
@@ -36,16 +53,13 @@ int deny_severity = LOG_WARNING;
#define O_NOCTTY 0
#endif
-/* Local Xauthority file. */
-static char *xauthfile = NULL;
-
/* Server configuration options. */
ServerOptions options;
/* Name of the server configuration file. */
char *config_file_name = SERVER_CONFIG_FILE;
-/*
+/*
* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
* Default value is AF_UNSPEC means both IPv4 and IPv6.
*/
@@ -84,21 +98,7 @@ int num_listen_socks = 0;
* sshd will skip the version-number exchange
*/
char *client_version_string = NULL;
-
-/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
-int no_port_forwarding_flag = 0;
-int no_agent_forwarding_flag = 0;
-int no_x11_forwarding_flag = 0;
-int no_pty_flag = 0;
-
-/* RSA authentication "command=" option. */
-char *forced_command = NULL;
-
-/* RSA authentication "environment=" options. */
-struct envstring *custom_environment = NULL;
-
-/* Session id for the current session. */
-unsigned char session_id[16];
+char *server_version_string = NULL;
/*
* Any really sensitive data in the application is contained in this
@@ -109,8 +109,9 @@ unsigned char session_id[16];
* not very useful. Currently, memory locking is not implemented.
*/
struct {
- RSA *private_key; /* Private part of server key. */
+ RSA *private_key; /* Private part of empheral server key. */
RSA *host_key; /* Private part of host key. */
+ Key *dsa_host_key; /* Private DSA host key. */
} sensitive_data;
/*
@@ -126,43 +127,16 @@ int received_sighup = 0;
the private key. */
RSA *public_key;
-/* Prototypes for various functions defined later in this file. */
-void do_ssh_kex();
-void do_authentication();
-void do_authloop(struct passwd * pw);
-void do_fake_authloop(char *user);
-void do_authenticated(struct passwd * pw);
-void do_exec_pty(const char *command, int ptyfd, int ttyfd,
- const char *ttyname, struct passwd * pw, const char *term,
- const char *display, const char *auth_proto,
- const char *auth_data);
-void do_exec_no_pty(const char *command, struct passwd * pw,
- const char *display, const char *auth_proto,
- const char *auth_data);
-void do_child(const char *command, struct passwd * pw, const char *term,
- const char *display, const char *auth_proto,
- const char *auth_data, const char *ttyname);
+/* session identifier, used by RSA-auth */
+unsigned char session_id[16];
-/*
- * Remove local Xauthority file.
- */
-void
-xauthfile_cleanup_proc(void *ignore)
-{
- debug("xauthfile_cleanup_proc called");
-
- if (xauthfile != NULL) {
- char *p;
- unlink(xauthfile);
- p = strrchr(xauthfile, '/');
- if (p != NULL) {
- *p = '\0';
- rmdir(xauthfile);
- }
- xfree(xauthfile);
- xauthfile = NULL;
- }
-}
+/* same for ssh2 */
+unsigned char *session_id2 = NULL;
+int session_id2_len = 0;
+
+/* Prototypes for various functions defined later in this file. */
+void do_ssh1_kex();
+void do_ssh2_kex();
/*
* Close all listening sockets
@@ -181,7 +155,7 @@ close_listen_socks(void)
* the effect is to reread the configuration file (and to regenerate
* the server key).
*/
-void
+void
sighup_handler(int sig)
{
received_sighup = 1;
@@ -192,7 +166,7 @@ sighup_handler(int sig)
* Called from the main program after receiving SIGHUP.
* Restarts the server.
*/
-void
+void
sighup_restart()
{
log("Received SIGHUP; restarting.");
@@ -207,11 +181,12 @@ sighup_restart()
* These close the listen socket; not closing it seems to cause "Address
* already in use" problems on some machines, which is inconvenient.
*/
-void
+void
sigterm_handler(int sig)
{
log("Received signal %d; terminating.", sig);
close_listen_socks();
+ unlink(options.pid_file);
exit(255);
}
@@ -219,7 +194,7 @@ sigterm_handler(int sig)
* SIGCHLD handler. This is called whenever a child dies. This will then
* reap any zombies left by exited c.
*/
-void
+void
main_sigchld_handler(int sig)
{
int save_errno = errno;
@@ -235,7 +210,7 @@ main_sigchld_handler(int sig)
/*
* Signal handler for the alarm after the login grace period has expired.
*/
-void
+void
grace_alarm_handler(int sig)
{
/* Close the connection. */
@@ -246,42 +221,14 @@ grace_alarm_handler(int sig)
}
/*
- * 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;
-}
-
-/*
* Signal handler for the key regeneration alarm. Note that this
* alarm only occurs in the daemon waiting for connections, and it does not
* do anything with the private key or random state before forking.
* Thus there should be no concurrency control/asynchronous execution
* problems.
*/
-void
+/* XXX do we really want this work to be done in a signal handler ? -m */
+void
key_regeneration_alarm(int sig)
{
int save_errno = errno;
@@ -311,6 +258,155 @@ key_regeneration_alarm(int sig)
errno = save_errno;
}
+char *
+chop(char *s)
+{
+ char *t = s;
+ while (*t) {
+ if(*t == '\n' || *t == '\r') {
+ *t = '\0';
+ return s;
+ }
+ t++;
+ }
+ return s;
+
+}
+
+void
+sshd_exchange_identification(int sock_in, int sock_out)
+{
+ int i, mismatch;
+ int remote_major, remote_minor;
+ int major, minor;
+ char *s;
+ char buf[256]; /* Must not be larger than remote_version. */
+ char remote_version[256]; /* Must be at least as big as buf. */
+
+ if ((options.protocol & SSH_PROTO_1) &&
+ (options.protocol & SSH_PROTO_2)) {
+ major = PROTOCOL_MAJOR_1;
+ minor = 99;
+ } else if (options.protocol & SSH_PROTO_2) {
+ major = PROTOCOL_MAJOR_2;
+ minor = PROTOCOL_MINOR_2;
+ } else {
+ major = PROTOCOL_MAJOR_1;
+ minor = PROTOCOL_MINOR_1;
+ }
+ snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
+ server_version_string = xstrdup(buf);
+
+ if (client_version_string == NULL) {
+ /* Send our protocol version identification. */
+ if (atomicio(write, sock_out, server_version_string, strlen(server_version_string))
+ != strlen(server_version_string)) {
+ log("Could not write ident string to %s.", get_remote_ipaddr());
+ fatal_cleanup();
+ }
+
+ /* Read other side\'s version identification. */
+ for (i = 0; i < sizeof(buf) - 1; i++) {
+ if (read(sock_in, &buf[i], 1) != 1) {
+ log("Did not receive ident string from %s.", get_remote_ipaddr());
+ fatal_cleanup();
+ }
+ if (buf[i] == '\r') {
+ buf[i] = '\n';
+ buf[i + 1] = 0;
+ continue;
+ }
+ if (buf[i] == '\n') {
+ /* buf[i] == '\n' */
+ buf[i + 1] = 0;
+ break;
+ }
+ }
+ buf[sizeof(buf) - 1] = 0;
+ client_version_string = xstrdup(buf);
+ }
+
+ /*
+ * Check that the versions match. In future this might accept
+ * several versions and set appropriate flags to handle them.
+ */
+ if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n",
+ &remote_major, &remote_minor, remote_version) != 3) {
+ s = "Protocol mismatch.\n";
+ (void) atomicio(write, sock_out, s, strlen(s));
+ close(sock_in);
+ close(sock_out);
+ log("Bad protocol version identification '%.100s' from %s",
+ client_version_string, get_remote_ipaddr());
+ fatal_cleanup();
+ }
+ debug("Client protocol version %d.%d; client software version %.100s",
+ remote_major, remote_minor, remote_version);
+
+ compat_datafellows(remote_version);
+
+ mismatch = 0;
+ switch(remote_major) {
+ case 1:
+ if (remote_minor == 99) {
+ if (options.protocol & SSH_PROTO_2)
+ enable_compat20();
+ else
+ mismatch = 1;
+ break;
+ }
+ if (!(options.protocol & SSH_PROTO_1)) {
+ mismatch = 1;
+ break;
+ }
+ if (remote_minor < 3) {
+ packet_disconnect("Your ssh version is too old and"
+ "is no longer supported. Please install a newer version.");
+ } else if (remote_minor == 3) {
+ /* note that this disables agent-forwarding */
+ enable_compat13();
+ }
+ break;
+ case 2:
+ if (options.protocol & SSH_PROTO_2) {
+ enable_compat20();
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ mismatch = 1;
+ break;
+ }
+ chop(server_version_string);
+ chop(client_version_string);
+ debug("Local version string %.200s", server_version_string);
+
+ if (mismatch) {
+ s = "Protocol major versions differ.\n";
+ (void) atomicio(write, sock_out, s, strlen(s));
+ close(sock_in);
+ close(sock_out);
+ log("Protocol major versions differ for %s: %.200s vs. %.200s",
+ get_remote_ipaddr(),
+ server_version_string, client_version_string);
+ fatal_cleanup();
+ }
+ if (compat20)
+ packet_set_ssh2_format();
+}
+
+
+void
+destroy_sensitive_data(void)
+{
+ /* Destroy the private and public keys. They will no longer be needed. */
+ RSA_free(public_key);
+ RSA_free(sensitive_data.private_key);
+ RSA_free(sensitive_data.host_key);
+ if (sensitive_data.dsa_host_key != NULL)
+ key_free(sensitive_data.dsa_host_key);
+}
+
/*
* Main program for the daemon.
*/
@@ -319,17 +415,14 @@ main(int ac, char **av)
{
extern char *optarg;
extern int optind;
- int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, pid, on = 1;
+ int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
+ pid_t pid;
socklen_t fromlen;
- int remote_major, remote_minor;
- int silentrsa = 0;
+ int silent = 0;
fd_set *fdset;
struct sockaddr_storage from;
- char buf[100]; /* Must not be larger than remote_version. */
- char remote_version[100]; /* Must be at least as big as buf. */
const char *remote_ip;
int remote_port;
- char *comment;
FILE *f;
struct linger linger;
struct addrinfo *ai;
@@ -366,7 +459,7 @@ main(int ac, char **av)
inetd_flag = 1;
break;
case 'Q':
- silentrsa = 1;
+ silent = 1;
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
@@ -422,27 +515,14 @@ main(int ac, char **av)
log_init(av0,
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
- !inetd_flag);
+ !silent && !inetd_flag);
- /* check if RSA support exists */
- if (rsa_alive() == 0) {
- if (silentrsa == 0)
- printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
- log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
- exit(1);
- }
/* Read server configuration options from the configuration file. */
read_server_config(&options, config_file_name);
/* Fill in default values for those options not explicitly set. */
fill_default_server_options(&options);
- /* Check certain values for sanity. */
- if (options.server_key_bits < 512 ||
- options.server_key_bits > 32768) {
- fprintf(stderr, "Bad server key size.\n");
- exit(1);
- }
/* Check that there are no remaining arguments. */
if (optind < ac) {
fprintf(stderr, "Extra argument %s.\n", av[optind]);
@@ -451,26 +531,80 @@ main(int ac, char **av)
debug("sshd version %.100s", SSH_VERSION);
- sensitive_data.host_key = RSA_new();
- errno = 0;
- /* Load the host key. It must have empty passphrase. */
- if (!load_private_key(options.host_key_file, "",
- sensitive_data.host_key, &comment)) {
- error("Could not load host key: %.200s: %.100s",
- options.host_key_file, strerror(errno));
+ sensitive_data.dsa_host_key = NULL;
+ sensitive_data.host_key = NULL;
+
+ /* check if RSA support exists */
+ if ((options.protocol & SSH_PROTO_1) &&
+ rsa_alive() == 0) {
+ log("no RSA support in libssl and libcrypto. See ssl(8)");
+ log("Disabling protocol version 1");
+ options.protocol &= ~SSH_PROTO_1;
+ }
+ /* Load the RSA/DSA host key. It must have empty passphrase. */
+ if (options.protocol & SSH_PROTO_1) {
+ Key k;
+ sensitive_data.host_key = RSA_new();
+ k.type = KEY_RSA;
+ k.rsa = sensitive_data.host_key;
+ errno = 0;
+ if (!load_private_key(options.host_key_file, "", &k, NULL)) {
+ error("Could not load host key: %.200s: %.100s",
+ options.host_key_file, strerror(errno));
+ log("Disabling protocol version 1");
+ options.protocol &= ~SSH_PROTO_1;
+ }
+ k.rsa = NULL;
+ }
+ if (options.protocol & SSH_PROTO_2) {
+ sensitive_data.dsa_host_key = key_new(KEY_DSA);
+ if (!load_private_key(options.host_dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) {
+
+ error("Could not load DSA host key: %.200s", options.host_dsa_key_file);
+ log("Disabling protocol version 2");
+ options.protocol &= ~SSH_PROTO_2;
+ }
+ }
+ if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
+ if (silent == 0)
+ fprintf(stderr, "sshd: no hostkeys available -- exiting.\n");
+ log("sshd: no hostkeys available -- exiting.\n");
exit(1);
}
- xfree(comment);
- /* Initialize the log (it is reinitialized below in case we
- forked). */
+ /* Check certain values for sanity. */
+ if (options.protocol & SSH_PROTO_1) {
+ if (options.server_key_bits < 512 ||
+ options.server_key_bits > 32768) {
+ fprintf(stderr, "Bad server key size.\n");
+ exit(1);
+ }
+ /*
+ * Check that server and host key lengths differ sufficiently. This
+ * is necessary to make double encryption work with rsaref. Oh, I
+ * hate software patents. I dont know if this can go? Niels
+ */
+ if (options.server_key_bits >
+ BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
+ options.server_key_bits <
+ BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
+ options.server_key_bits =
+ BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
+ debug("Forcing server key to %d bits to make it differ from host key.",
+ options.server_key_bits);
+ }
+ }
+
+ /* Initialize the log (it is reinitialized below in case we forked). */
if (debug_flag && !inetd_flag)
log_stderr = 1;
log_init(av0, options.log_level, options.log_facility, log_stderr);
- /* If not in debugging mode, and not started from inetd,
- disconnect from the controlling terminal, and fork. The
- original process exits. */
+ /*
+ * If not in debugging mode, and not started from inetd, disconnect
+ * from the controlling terminal, and fork. The original process
+ * exits.
+ */
if (!debug_flag && !inetd_flag) {
#ifdef TIOCNOTTY
int fd;
@@ -490,18 +624,6 @@ main(int ac, char **av)
/* Reinitialize the log (because of the fork above). */
log_init(av0, options.log_level, options.log_facility, log_stderr);
- /* Check that server and host key lengths differ sufficiently.
- This is necessary to make double encryption work with rsaref.
- Oh, I hate software patents. I dont know if this can go? Niels */
- if (options.server_key_bits >
- BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
- options.server_key_bits <
- BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
- options.server_key_bits =
- BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
- debug("Forcing server key to %d bits to make it differ from host key.",
- options.server_key_bits);
- }
/* Do not display messages to stdout in RSA code. */
rsa_set_verbose(0);
@@ -519,19 +641,22 @@ main(int ac, char **av)
s2 = dup(s1);
sock_in = dup(0);
sock_out = dup(1);
- /* We intentionally do not close the descriptors 0, 1, and 2
- as our code for setting the descriptors won\'t work
- if ttyfd happens to be one of those. */
+ /*
+ * We intentionally do not close the descriptors 0, 1, and 2
+ * as our code for setting the descriptors won\'t work if
+ * ttyfd happens to be one of those.
+ */
debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
- public_key = RSA_new();
- sensitive_data.private_key = RSA_new();
-
- log("Generating %d bit RSA key.", options.server_key_bits);
- rsa_generate_key(sensitive_data.private_key, public_key,
- options.server_key_bits);
- arc4random_stir();
- log("RSA key generation complete.");
+ if (options.protocol & SSH_PROTO_1) {
+ public_key = RSA_new();
+ sensitive_data.private_key = RSA_new();
+ log("Generating %d bit RSA key.", options.server_key_bits);
+ rsa_generate_key(sensitive_data.private_key, public_key,
+ options.server_key_bits);
+ arc4random_stir();
+ log("RSA key generation complete.");
+ }
} else {
for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
@@ -601,25 +726,26 @@ main(int ac, char **av)
* fail if there already is a daemon, and this will
* overwrite any old pid in the file.
*/
- f = fopen(SSH_DAEMON_PID_FILE, "w");
+ f = fopen(options.pid_file, "w");
if (f) {
fprintf(f, "%u\n", (unsigned int) getpid());
fclose(f);
}
}
+ if (options.protocol & SSH_PROTO_1) {
+ public_key = RSA_new();
+ sensitive_data.private_key = RSA_new();
- public_key = RSA_new();
- sensitive_data.private_key = RSA_new();
-
- log("Generating %d bit RSA key.", options.server_key_bits);
- rsa_generate_key(sensitive_data.private_key, public_key,
- options.server_key_bits);
- arc4random_stir();
- log("RSA key generation complete.");
+ log("Generating %d bit RSA key.", options.server_key_bits);
+ rsa_generate_key(sensitive_data.private_key, public_key,
+ options.server_key_bits);
+ arc4random_stir();
+ log("RSA key generation complete.");
- /* Schedule server key regeneration alarm. */
- signal(SIGALRM, key_regeneration_alarm);
- alarm(options.key_regeneration_time);
+ /* Schedule server key regeneration alarm. */
+ signal(SIGALRM, key_regeneration_alarm);
+ alarm(options.key_regeneration_time);
+ }
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */
signal(SIGHUP, sighup_handler);
@@ -634,8 +760,8 @@ main(int ac, char **av)
for (i = 0; i < num_listen_socks; i++)
if (listen_socks[i] > maxfd)
maxfd = listen_socks[i];
- fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
- fdset = (fd_set *)xmalloc(fdsetsz);
+ fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
+ fdset = (fd_set *)xmalloc(fdsetsz);
/*
* Stay listening for connections until the system crashes or
@@ -789,73 +915,7 @@ main(int ac, char **av)
if (!debug_flag)
alarm(options.login_grace_time);
- if (client_version_string != NULL) {
- /* we are exec'ed by sshd2, so skip exchange of protocol version */
- strlcpy(buf, client_version_string, sizeof(buf));
- } else {
- /* Send our protocol version identification. */
- snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
- PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
- if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf)) {
- log("Could not write ident string to %s.", remote_ip);
- fatal_cleanup();
- }
-
- /* Read other side\'s version identification. */
- for (i = 0; i < sizeof(buf) - 1; i++) {
- if (read(sock_in, &buf[i], 1) != 1) {
- log("Did not receive ident string from %s.", remote_ip);
- fatal_cleanup();
- }
- if (buf[i] == '\r') {
- buf[i] = '\n';
- buf[i + 1] = 0;
- break;
- }
- if (buf[i] == '\n') {
- /* buf[i] == '\n' */
- buf[i + 1] = 0;
- break;
- }
- }
- buf[sizeof(buf) - 1] = 0;
- }
-
- /*
- * Check that the versions match. In future this might accept
- * several versions and set appropriate flags to handle them.
- */
- if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor,
- remote_version) != 3) {
- char *s = "Protocol mismatch.\n";
-
- (void) atomicio(write, sock_out, s, strlen(s));
- close(sock_in);
- close(sock_out);
- log("Bad protocol version identification '%.100s' from %s",
- buf, remote_ip);
- fatal_cleanup();
- }
- debug("Client protocol version %d.%d; client software version %.100s",
- remote_major, remote_minor, remote_version);
- if (remote_major != PROTOCOL_MAJOR) {
- char *s = "Protocol major versions differ.\n";
-
- (void) atomicio(write, sock_out, s, strlen(s));
- close(sock_in);
- close(sock_out);
- log("Protocol major versions differ for %s: %d vs. %d",
- remote_ip, PROTOCOL_MAJOR, remote_major);
- fatal_cleanup();
- }
- /* Check that the client has sufficiently high software version. */
- if (remote_major == 1 && remote_minor < 3)
- packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version.");
-
- if (remote_major == 1 && remote_minor == 3) {
- /* note that this disables agent-forwarding */
- enable_compat13();
- }
+ sshd_exchange_identification(sock_in, sock_out);
/*
* Check that the connection comes from a privileged port. Rhosts-
* and Rhosts-RSA-Authentication only make sense from priviledged
@@ -879,10 +939,14 @@ main(int ac, char **av)
packet_set_nonblocking();
/* perform the key exchange */
- do_ssh_kex();
-
/* authenticate user and start session */
- do_authentication();
+ if (compat20) {
+ do_ssh2_kex();
+ do_authentication2();
+ } else {
+ do_ssh1_kex();
+ do_authentication();
+ }
#ifdef KRB4
/* Cleanup user's ticket cache file. */
@@ -890,10 +954,6 @@ main(int ac, char **av)
(void) dest_tkt();
#endif /* KRB4 */
- /* Cleanup user's local Xauthority file. */
- if (xauthfile)
- xauthfile_cleanup_proc(NULL);
-
/* The connection has been terminated. */
verbose("Closing connection to %.100s", remote_ip);
packet_close();
@@ -904,7 +964,7 @@ main(int ac, char **av)
* SSH1 key exchange
*/
void
-do_ssh_kex()
+do_ssh1_kex()
{
int i, len;
int plen, slen;
@@ -953,7 +1013,7 @@ do_ssh_kex()
packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN);
/* Declare which ciphers we support. */
- packet_put_int(cipher_mask());
+ packet_put_int(cipher_mask1());
/* Declare supported authentication types. */
auth_mask = 0;
@@ -994,7 +1054,7 @@ do_ssh_kex()
/* Get cipher type and check whether we accept this. */
cipher_type = packet_get_char();
- if (!(cipher_mask() & (1 << cipher_type)))
+ if (!(cipher_mask() & (1 << cipher_type)))
packet_disconnect("Warning: client selects unsupported cipher.");
/* Get check bytes from the packet. These must match those we
@@ -1053,9 +1113,7 @@ do_ssh_kex()
sensitive_data.private_key->n);
/* Destroy the private and public keys. They will no longer be needed. */
- RSA_free(public_key);
- RSA_free(sensitive_data.private_key);
- RSA_free(sensitive_data.host_key);
+ destroy_sensitive_data();
/*
* Extract session key from the decrypted integer. The key is in the
@@ -1092,1462 +1150,196 @@ do_ssh_kex()
packet_write_wait();
}
-
/*
- * 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.
- */
-static 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;
-}
-
-/*
- * Performs authentication of an incoming connection. Session key has already
- * been exchanged and encryption is enabled.
+ * SSH2 key exchange: diffie-hellman-group1-sha1
*/
void
-do_authentication()
+do_ssh2_kex()
{
- 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_authloop(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.");
+ Buffer *server_kexinit;
+ Buffer *client_kexinit;
+ int payload_len, dlen;
+ int slen;
+ unsigned int klen, kout;
+ char *ptr;
+ unsigned char *signature = NULL;
+ unsigned char *server_host_key_blob = NULL;
+ unsigned int sbloblen;
+ DH *dh;
+ BIGNUM *dh_client_pub = 0;
+ BIGNUM *shared_secret = 0;
+ int i;
+ unsigned char *kbuf;
+ unsigned char *hash;
+ Kex *kex;
+ char *cprop[PROPOSAL_MAX];
+ char *sprop[PROPOSAL_MAX];
- debug("Attempting authentication for %.100s.", pw->pw_name);
+/* KEXINIT */
- /* 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);
+ if (options.ciphers != NULL) {
+ myproposal[PROPOSAL_ENC_ALGS_CTOS] =
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
}
- /* The user has been authenticated and accepted. */
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-
- /* Perform session preparation. */
- do_authenticated(pw);
-}
+ debug("Sending KEX init.");
-#define AUTH_FAIL_MAX 6
-#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
-#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
-
-/*
- * 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);
+ for (i = 0; i < PROPOSAL_MAX; i++)
+ sprop[i] = xstrdup(myproposal[i]);
+ server_kexinit = kex_init(sprop);
+ packet_start(SSH2_MSG_KEXINIT);
+ packet_put_raw(buffer_ptr(server_kexinit), buffer_len(server_kexinit));
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);
+ debug("done");
- /* 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 */
+ packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
- 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);
+ /*
+ * save raw KEXINIT payload in buffer. this is used during
+ * computation of the session_id and the session keys.
+ */
+ client_kexinit = xmalloc(sizeof(*client_kexinit));
+ buffer_init(client_kexinit);
+ ptr = packet_get_raw(&payload_len);
+ buffer_append(client_kexinit, ptr, payload_len);
- snprintf(user, sizeof user, " ruser %s", client_user);
- xfree(client_user);
- break;
+ /* skip cookie */
+ for (i = 0; i < 16; i++)
+ (void) packet_get_char();
+ /* save kex init proposal strings */
+ for (i = 0; i < PROPOSAL_MAX; i++) {
+ cprop[i] = packet_get_string(NULL);
+ debug("got kexinit string: %s", cprop[i]);
+ }
- 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))
- error("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;
+ i = (int) packet_get_char();
+ debug("first kex follow == %d", i);
+ i = packet_get_int();
+ debug("reserved == %d", i);
- 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;
+ debug("done read kexinit");
+ kex = kex_choose_conf(cprop, sprop, 1);
- 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);
+/* KEXDH */
- /* Try authentication with the password. */
- authenticated = auth_password(pw, password);
+ debug("Wait SSH2_MSG_KEXDH_INIT.");
+ packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT);
- memset(password, 0, strlen(password));
- xfree(password);
- break;
+ /* key, cert */
+ dh_client_pub = BN_new();
+ if (dh_client_pub == NULL)
+ fatal("dh_client_pub == NULL");
+ packet_get_bignum2(dh_client_pub, &dlen);
-#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;
+#ifdef DEBUG_KEXDH
+ fprintf(stderr, "\ndh_client_pub= ");
+ bignum_print(dh_client_pub);
+ fprintf(stderr, "\n");
+ debug("bits %d", BN_num_bits(dh_client_pub));
#endif
- default:
- /*
- * Any unknown messages will be ignored (and failure
- * returned) during authentication.
- */
- log("Unknown message during authentication: type %d", type);
- break;
- }
+ /* generate DH key */
+ dh = dh_new_group1(); /* XXX depends on 'kex' */
+
+#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");
+#endif
+ if (!dh_pub_is_valid(dh, dh_client_pub))
+ packet_disconnect("bad client public DH value");
+
+ klen = DH_size(dh);
+ kbuf = xmalloc(klen);
+ kout = DH_compute_key(kbuf, dh_client_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);
+
+ /* XXX precompute? */
+ dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen);
+
+ /* calc H */ /* XXX depends on 'kex' */
+ 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),
+ (char *)server_host_key_blob, sbloblen,
+ dh_client_pub,
+ dh->pub_key,
+ shared_secret
+ );
+ 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
+ /* save session id := H */
+ /* XXX hashlen depends on KEX */
+ session_id2_len = 20;
+ session_id2 = xmalloc(session_id2_len);
+ memcpy(session_id2, hash, session_id2_len);
+
+ /* sign H */
+ /* XXX hashlen depends on KEX */
+ dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20);
+
+ destroy_sensitive_data();
+
+ /* send server hostkey, DH pubkey 'f' and singed H */
+ packet_start(SSH2_MSG_KEXDH_REPLY);
+ packet_put_string((char *)server_host_key_blob, sbloblen);
+ packet_put_bignum2(dh->pub_key); /* f */
+ packet_put_string((char *)signature, slen);
+ packet_send();
+ xfree(signature);
+ xfree(server_host_key_blob);
+ packet_write_wait();
- /*
- * 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());
- }
- }
+ kex_derive_keys(kex, hash, shared_secret);
+ packet_set_kex(kex);
- /* 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();
- }
-}
+ /* have keys, free DH */
+ DH_free(dh);
-/*
- * The user does not exist or access is denied,
- * but fake indication that authentication is needed.
- */
-void
-do_fake_authloop(char *user)
-{
- int attempt = 0;
+ debug("send SSH2_MSG_NEWKEYS.");
+ packet_start(SSH2_MSG_NEWKEYS);
+ packet_send();
+ packet_write_wait();
+ debug("done: send SSH2_MSG_NEWKEYS.");
- log("Faking authloop for illegal user %.200s from %.200s port %d",
- user,
- get_remote_ipaddr(),
- get_remote_port());
+ debug("Wait SSH2_MSG_NEWKEYS.");
+ packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
+ debug("GOT SSH2_MSG_NEWKEYS.");
- /* Indicate that authentication is needed. */
- packet_start(SSH_SMSG_FAILURE);
+#ifdef DEBUG_KEXDH
+ /* send 1st encrypted/maced/compressed message */
+ packet_start(SSH2_MSG_IGNORE);
+ packet_put_cstring("markus");
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;
- /* Try to send a fake s/key challenge. */
- if (options.skey_authentication == 1 &&
- (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
- password = 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();
-}
-
-struct pty_cleanup_context {
- const char *ttyname;
- int pid;
-};
-
-/*
- * Function to perform cleanup if we get aborted abnormally (e.g., due to a
- * dropped connection).
- */
-void
-pty_cleanup_proc(void *context)
-{
- struct pty_cleanup_context *cu = context;
-
- debug("pty_cleanup_proc called");
-
- /* Record that the user has logged out. */
- record_logout(cu->pid, cu->ttyname);
-
- /* Release the pseudo-tty. */
- pty_release(cu->ttyname);
-}
-
-/* simple cleanup: chown tty slave back to root */
-static void
-pty_release_proc(void *tty)
-{
- char *ttyname = tty;
- pty_release(ttyname);
-}
-
-/*
- * Prepares for an interactive session. This is called after the user has
- * been successfully authenticated. During this message exchange, pseudo
- * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
- * are requested, etc.
- */
-void
-do_authenticated(struct passwd * pw)
-{
- int type;
- int compression_level = 0, enable_compression_after_reply = 0;
- int have_pty = 0, ptyfd = -1, ttyfd = -1;
- int row, col, xpixel, ypixel, screen;
- char ttyname[64];
- char *command, *term = NULL, *display = NULL, *proto = NULL, *data = NULL;
- int plen;
- unsigned int dlen;
- int n_bytes;
-
- /*
- * Cancel the alarm we set to limit the time taken for
- * authentication.
- */
- alarm(0);
-
- /*
- * Inform the channel mechanism that we are the server side and that
- * the client may request to connect to any port at all. (The user
- * could do it anyway, and we wouldn\'t know what is permitted except
- * by the client telling us, so we can equally well trust the client
- * not to request anything bogus.)
- */
- if (!no_port_forwarding_flag)
- channel_permit_all_opens();
-
- /*
- * We stay in this loop until the client requests to execute a shell
- * or a command.
- */
- while (1) {
-
- /* Get a packet from the client. */
- type = packet_read(&plen);
-
- /* Process the packet. */
- switch (type) {
- case SSH_CMSG_REQUEST_COMPRESSION:
- packet_integrity_check(plen, 4, type);
- compression_level = packet_get_int();
- if (compression_level < 1 || compression_level > 9) {
- packet_send_debug("Received illegal compression level %d.",
- compression_level);
- goto fail;
- }
- /* Enable compression after we have responded with SUCCESS. */
- enable_compression_after_reply = 1;
- break;
-
- case SSH_CMSG_REQUEST_PTY:
- if (no_pty_flag) {
- debug("Allocating a pty not permitted for this authentication.");
- goto fail;
- }
- if (have_pty)
- packet_disconnect("Protocol error: you already have a pty.");
-
- debug("Allocating pty.");
-
- /* Allocate a pty and open it. */
- if (!pty_allocate(&ptyfd, &ttyfd, ttyname,
- sizeof(ttyname))) {
- error("Failed to allocate pty.");
- goto fail;
- }
- fatal_add_cleanup(pty_release_proc, (void *)ttyname);
- pty_setowner(pw, ttyname);
-
- /* Get TERM from the packet. Note that the value may be of arbitrary length. */
- term = packet_get_string(&dlen);
- packet_integrity_check(dlen, strlen(term), type);
-
- /* Remaining bytes */
- n_bytes = plen - (4 + dlen + 4 * 4);
-
- if (strcmp(term, "") == 0) {
- xfree(term);
- term = NULL;
- }
-
- /* Get window size from the packet. */
- row = packet_get_int();
- col = packet_get_int();
- xpixel = packet_get_int();
- ypixel = packet_get_int();
- pty_change_window_size(ptyfd, row, col, xpixel, ypixel);
-
- /* Get tty modes from the packet. */
- tty_parse_modes(ttyfd, &n_bytes);
- packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
-
- /* Indicate that we now have a pty. */
- have_pty = 1;
- break;
-
- case SSH_CMSG_X11_REQUEST_FORWARDING:
- if (!options.x11_forwarding) {
- packet_send_debug("X11 forwarding disabled in server configuration file.");
- goto fail;
- }
-#ifdef XAUTH_PATH
- if (no_x11_forwarding_flag) {
- packet_send_debug("X11 forwarding not permitted for this authentication.");
- goto fail;
- }
- debug("Received request for X11 forwarding with auth spoofing.");
- if (display)
- packet_disconnect("Protocol error: X11 display already set.");
- {
- unsigned int proto_len, data_len;
- proto = packet_get_string(&proto_len);
- data = packet_get_string(&data_len);
- packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
- }
- if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
- screen = packet_get_int();
- else
- screen = 0;
- display = x11_create_display_inet(screen, options.x11_display_offset);
- if (!display)
- goto fail;
-
- /* Setup to always have a local .Xauthority. */
- xauthfile = xmalloc(MAXPATHLEN);
- strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
- temporarily_use_uid(pw->pw_uid);
- if (mkdtemp(xauthfile) == NULL) {
- restore_uid();
- error("private X11 dir: mkdtemp %s failed: %s",
- xauthfile, strerror(errno));
- xfree(xauthfile);
- xauthfile = NULL;
- goto fail;
- }
- strlcat(xauthfile, "/cookies", MAXPATHLEN);
- open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
- restore_uid();
- fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
- break;
-#else /* XAUTH_PATH */
- packet_send_debug("No xauth program; cannot forward with spoofing.");
- goto fail;
-#endif /* XAUTH_PATH */
-
- case SSH_CMSG_AGENT_REQUEST_FORWARDING:
- if (no_agent_forwarding_flag || compat13) {
- debug("Authentication agent forwarding not permitted for this authentication.");
- goto fail;
- }
- debug("Received authentication agent forwarding request.");
- auth_input_request_forwarding(pw);
- break;
-
- case SSH_CMSG_PORT_FORWARD_REQUEST:
- if (no_port_forwarding_flag) {
- debug("Port forwarding not permitted for this authentication.");
- goto fail;
- }
- debug("Received TCP/IP port forwarding request.");
- channel_input_port_forward_request(pw->pw_uid == 0);
- break;
-
- case SSH_CMSG_MAX_PACKET_SIZE:
- if (packet_set_maxsize(packet_get_int()) < 0)
- goto fail;
- break;
-
- case SSH_CMSG_EXEC_SHELL:
- /* Set interactive/non-interactive mode. */
- packet_set_interactive(have_pty || display != NULL,
- options.keepalives);
-
- if (forced_command != NULL)
- goto do_forced_command;
- debug("Forking shell.");
- packet_integrity_check(plen, 0, type);
- if (have_pty)
- do_exec_pty(NULL, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
- else
- do_exec_no_pty(NULL, pw, display, proto, data);
- return;
-
- case SSH_CMSG_EXEC_CMD:
- /* Set interactive/non-interactive mode. */
- packet_set_interactive(have_pty || display != NULL,
- options.keepalives);
-
- if (forced_command != NULL)
- goto do_forced_command;
- /* Get command from the packet. */
- {
- unsigned int dlen;
- command = packet_get_string(&dlen);
- debug("Executing command '%.500s'", command);
- packet_integrity_check(plen, 4 + dlen, type);
- }
- if (have_pty)
- do_exec_pty(command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
- else
- do_exec_no_pty(command, pw, display, proto, data);
- xfree(command);
- return;
-
- default:
- /*
- * Any unknown messages in this phase are ignored,
- * and a failure message is returned.
- */
- log("Unknown packet type received after authentication: %d", type);
- goto fail;
- }
-
- /* The request was successfully processed. */
- packet_start(SSH_SMSG_SUCCESS);
- packet_send();
- packet_write_wait();
-
- /* Enable compression now that we have replied if appropriate. */
- if (enable_compression_after_reply) {
- enable_compression_after_reply = 0;
- packet_start_compression(compression_level);
- }
- continue;
-
-fail:
- /* The request failed. */
- packet_start(SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
- continue;
-
-do_forced_command:
- /*
- * There is a forced command specified for this login.
- * Execute it.
- */
- debug("Executing forced command: %.900s", forced_command);
- if (have_pty)
- do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, proto, data);
- else
- do_exec_no_pty(forced_command, pw, display, proto, data);
- return;
- }
-}
-
-/*
- * This is called to fork and execute a command when we have no tty. This
- * will call do_child from the child, and server_loop from the parent after
- * setting up file descriptors and such.
- */
-void
-do_exec_no_pty(const char *command, struct passwd * pw,
- const char *display, const char *auth_proto,
- const char *auth_data)
-{
- int pid;
-
-#ifdef USE_PIPES
- int pin[2], pout[2], perr[2];
- /* Allocate pipes for communicating with the program. */
- if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
- packet_disconnect("Could not create pipes: %.100s",
- strerror(errno));
-#else /* USE_PIPES */
- int inout[2], err[2];
- /* Uses socket pairs to communicate with the program. */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
- socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
- packet_disconnect("Could not create socket pairs: %.100s",
- strerror(errno));
-#endif /* USE_PIPES */
-
- setproctitle("%s@notty", pw->pw_name);
-
- /* Fork the child. */
- if ((pid = fork()) == 0) {
- /* Child. Reinitialize the log since the pid has changed. */
- log_init(av0, options.log_level, options.log_facility, log_stderr);
-
- /*
- * Create a new session and process group since the 4.4BSD
- * setlogin() affects the entire process group.
- */
- if (setsid() < 0)
- error("setsid failed: %.100s", strerror(errno));
-
-#ifdef USE_PIPES
- /*
- * Redirect stdin. We close the parent side of the socket
- * pair, and make the child side the standard input.
- */
- close(pin[1]);
- if (dup2(pin[0], 0) < 0)
- perror("dup2 stdin");
- close(pin[0]);
-
- /* Redirect stdout. */
- close(pout[0]);
- if (dup2(pout[1], 1) < 0)
- perror("dup2 stdout");
- close(pout[1]);
-
- /* Redirect stderr. */
- close(perr[0]);
- if (dup2(perr[1], 2) < 0)
- perror("dup2 stderr");
- close(perr[1]);
-#else /* USE_PIPES */
- /*
- * Redirect stdin, stdout, and stderr. Stdin and stdout will
- * use the same socket, as some programs (particularly rdist)
- * seem to depend on it.
- */
- close(inout[1]);
- close(err[1]);
- if (dup2(inout[0], 0) < 0) /* stdin */
- perror("dup2 stdin");
- if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
- perror("dup2 stdout");
- if (dup2(err[0], 2) < 0) /* stderr */
- perror("dup2 stderr");
-#endif /* USE_PIPES */
-
- /* Do processing for the child (exec command etc). */
- do_child(command, pw, NULL, display, auth_proto, auth_data, NULL);
- /* NOTREACHED */
- }
- if (pid < 0)
- packet_disconnect("fork failed: %.100s", strerror(errno));
-#ifdef USE_PIPES
- /* We are the parent. Close the child sides of the pipes. */
- close(pin[0]);
- close(pout[1]);
- close(perr[1]);
-
- /* Enter the interactive session. */
- server_loop(pid, pin[1], pout[0], perr[0]);
- /* server_loop has closed pin[1], pout[1], and perr[1]. */
-#else /* USE_PIPES */
- /* We are the parent. Close the child sides of the socket pairs. */
- close(inout[0]);
- close(err[0]);
-
- /*
- * Enter the interactive session. Note: server_loop must be able to
- * handle the case that fdin and fdout are the same.
- */
- server_loop(pid, inout[1], inout[1], err[1]);
- /* server_loop has closed inout[1] and err[1]. */
-#endif /* USE_PIPES */
-}
-
-/*
- * This is called to fork and execute a command when we have a tty. This
- * will call do_child from the child, and server_loop from the parent after
- * setting up file descriptors, controlling tty, updating wtmp, utmp,
- * lastlog, and other such operations.
- */
-void
-do_exec_pty(const char *command, int ptyfd, int ttyfd,
- const char *ttyname, struct passwd * pw, const char *term,
- const char *display, const char *auth_proto,
- const char *auth_data)
-{
- int pid, fdout;
- int ptymaster;
- const char *hostname;
- time_t last_login_time;
- char buf[100], *time_string;
- FILE *f;
- char line[256];
- struct stat st;
- int quiet_login;
- struct sockaddr_storage from;
- socklen_t fromlen;
- struct pty_cleanup_context cleanup_context;
-
- /* Get remote host name. */
- hostname = get_canonical_hostname();
-
- /*
- * Get the time when the user last logged in. Buf will be set to
- * contain the hostname the last login was from.
- */
- if (!options.use_login) {
- last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
- buf, sizeof(buf));
- }
- setproctitle("%s@%s", pw->pw_name, strrchr(ttyname, '/') + 1);
-
- /* Fork the child. */
- if ((pid = fork()) == 0) {
- pid = getpid();
-
- /* Child. Reinitialize the log because the pid has
- changed. */
- log_init(av0, options.log_level, options.log_facility, log_stderr);
-
- /* Close the master side of the pseudo tty. */
- close(ptyfd);
-
- /* Make the pseudo tty our controlling tty. */
- pty_make_controlling_tty(&ttyfd, ttyname);
-
- /* Redirect stdin from the pseudo tty. */
- if (dup2(ttyfd, fileno(stdin)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Redirect stdout to the pseudo tty. */
- if (dup2(ttyfd, fileno(stdout)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Redirect stderr to the pseudo tty. */
- if (dup2(ttyfd, fileno(stderr)) < 0)
- error("dup2 stdin failed: %.100s", strerror(errno));
-
- /* Close the extra descriptor for the pseudo tty. */
- close(ttyfd);
-
- /*
- * Get IP address of client. This is needed because we want
- * to record where the user logged in from. If the
- * connection is not a socket, let the ip address be 0.0.0.0.
- */
- memset(&from, 0, sizeof(from));
- if (packet_get_connection_in() == packet_get_connection_out()) {
- fromlen = sizeof(from);
- if (getpeername(packet_get_connection_in(),
- (struct sockaddr *) & from, &fromlen) < 0) {
- debug("getpeername: %.100s", strerror(errno));
- fatal_cleanup();
- }
- }
- /* Record that there was a login on that terminal. */
- record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
- (struct sockaddr *)&from);
-
- /* Check if .hushlogin exists. */
- snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
- quiet_login = stat(line, &st) >= 0;
-
- /*
- * If the user has logged in before, display the time of last
- * login. However, don't display anything extra if a command
- * has been specified (so that ssh can be used to execute
- * commands on a remote machine without users knowing they
- * are going to another machine). Login(1) will do this for
- * us as well, so check if login(1) is used
- */
- if (command == NULL && last_login_time != 0 && !quiet_login &&
- !options.use_login) {
- /* Convert the date to a string. */
- time_string = ctime(&last_login_time);
- /* Remove the trailing newline. */
- if (strchr(time_string, '\n'))
- *strchr(time_string, '\n') = 0;
- /* Display the last login time. Host if displayed
- if known. */
- if (strcmp(buf, "") == 0)
- printf("Last login: %s\r\n", time_string);
- else
- printf("Last login: %s from %s\r\n", time_string, buf);
- }
- /*
- * Print /etc/motd unless a command was specified or printing
- * it was disabled in server options or login(1) will be
- * used. Note that some machines appear to print it in
- * /etc/profile or similar.
- */
- if (command == NULL && options.print_motd && !quiet_login &&
- !options.use_login) {
- /* Print /etc/motd if it exists. */
- f = fopen("/etc/motd", "r");
- if (f) {
- while (fgets(line, sizeof(line), f))
- fputs(line, stdout);
- fclose(f);
- }
- }
- /* Do common processing for the child, such as execing the command. */
- do_child(command, pw, term, display, auth_proto, auth_data, ttyname);
- /* NOTREACHED */
- }
- if (pid < 0)
- packet_disconnect("fork failed: %.100s", strerror(errno));
- /* Parent. Close the slave side of the pseudo tty. */
- close(ttyfd);
-
- /*
- * Add a cleanup function to clear the utmp entry and record logout
- * time in case we call fatal() (e.g., the connection gets closed).
- */
- cleanup_context.pid = pid;
- cleanup_context.ttyname = ttyname;
- fatal_add_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
- fatal_remove_cleanup(pty_release_proc, (void *) ttyname);
-
- /*
- * Create another descriptor of the pty master side for use as the
- * standard input. We could use the original descriptor, but this
- * simplifies code in server_loop. The descriptor is bidirectional.
- */
- fdout = dup(ptyfd);
- if (fdout < 0)
- packet_disconnect("dup #1 failed: %.100s", strerror(errno));
-
- /* we keep a reference to the pty master */
- ptymaster = dup(ptyfd);
- if (ptymaster < 0)
- packet_disconnect("dup #2 failed: %.100s", strerror(errno));
-
- /* Enter interactive session. */
- server_loop(pid, ptyfd, fdout, -1);
- /* server_loop _has_ closed ptyfd and fdout. */
-
- /* Cancel the cleanup function. */
- fatal_remove_cleanup(pty_cleanup_proc, (void *) &cleanup_context);
-
- /* Record that the user has logged out. */
- record_logout(pid, ttyname);
-
- /* Release the pseudo-tty. */
- pty_release(ttyname);
-
- /*
- * Close the server side of the socket pairs. We must do this after
- * the pty cleanup, so that another process doesn't get this pty
- * while we're still cleaning up.
- */
- if (close(ptymaster) < 0)
- error("close(ptymaster): %s", strerror(errno));
-}
-
-/*
- * Sets the value of the given variable in the environment. If the variable
- * already exists, its value is overriden.
- */
-void
-child_set_env(char ***envp, unsigned int *envsizep, const char *name,
- const char *value)
-{
- unsigned int i, namelen;
- char **env;
-
- /*
- * Find the slot where the value should be stored. If the variable
- * already exists, we reuse the slot; otherwise we append a new slot
- * at the end of the array, expanding if necessary.
- */
- env = *envp;
- namelen = strlen(name);
- for (i = 0; env[i]; i++)
- if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
- break;
- if (env[i]) {
- /* Reuse the slot. */
- xfree(env[i]);
- } else {
- /* New variable. Expand if necessary. */
- if (i >= (*envsizep) - 1) {
- (*envsizep) += 50;
- env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
- }
- /* Need to set the NULL pointer at end of array beyond the new slot. */
- env[i + 1] = NULL;
- }
-
- /* Allocate space and format the variable in the appropriate slot. */
- env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
- snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
-}
-
-/*
- * Reads environment variables from the given file and adds/overrides them
- * into the environment. If the file does not exist, this does nothing.
- * Otherwise, it must consist of empty lines, comments (line starts with '#')
- * and assignments of the form name=value. No other forms are allowed.
- */
-void
-read_environment_file(char ***env, unsigned int *envsize,
- const char *filename)
-{
- FILE *f;
- char buf[4096];
- char *cp, *value;
-
- f = fopen(filename, "r");
- if (!f)
- return;
-
- while (fgets(buf, sizeof(buf), f)) {
- for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
- ;
- if (!*cp || *cp == '#' || *cp == '\n')
- continue;
- if (strchr(cp, '\n'))
- *strchr(cp, '\n') = '\0';
- value = strchr(cp, '=');
- if (value == NULL) {
- fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
- continue;
- }
- /* Replace the equals sign by nul, and advance value to the value string. */
- *value = '\0';
- value++;
- child_set_env(env, envsize, cp, value);
- }
- fclose(f);
-}
-
-/*
- * Performs common processing for the child, such as setting up the
- * environment, closing extra file descriptors, setting the user and group
- * ids, and executing the command or shell.
- */
-void
-do_child(const char *command, struct passwd * pw, const char *term,
- const char *display, const char *auth_proto,
- const char *auth_data, const char *ttyname)
-{
- const char *shell, *cp = NULL;
- char buf[256];
- FILE *f;
- unsigned int envsize, i;
- char **env;
- extern char **environ;
- struct stat st;
- char *argv[10];
-
- f = fopen("/etc/nologin", "r");
- if (f) {
- /* /etc/nologin exists. Print its contents and exit. */
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stderr);
- fclose(f);
- if (pw->pw_uid != 0)
- exit(254);
- }
- /* Set login name in the kernel. */
- if (setlogin(pw->pw_name) < 0)
- error("setlogin failed: %s", strerror(errno));
-
- /* Set uid, gid, and groups. */
- /* Login(1) does this as well, and it needs uid 0 for the "-h"
- switch, so we let login(1) to this for us. */
- if (!options.use_login) {
- if (getuid() == 0 || geteuid() == 0) {
- if (setgid(pw->pw_gid) < 0) {
- perror("setgid");
- exit(1);
- }
- /* Initialize the group list. */
- if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
- perror("initgroups");
- exit(1);
- }
- endgrent();
-
- /* Permanently switch to the desired uid. */
- permanently_set_uid(pw->pw_uid);
- }
- if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
- fatal("Failed to set uids to %d.", (int) pw->pw_uid);
- }
- /*
- * Get the shell from the password data. An empty shell field is
- * legal, and means /bin/sh.
- */
- shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
-
-#ifdef AFS
- /* Try to get AFS tokens for the local cell. */
- if (k_hasafs()) {
- char cell[64];
-
- if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
- krb_afslog(cell, 0);
-
- krb_afslog(0, 0);
- }
-#endif /* AFS */
-
- /* Initialize the environment. */
- envsize = 100;
- env = xmalloc(envsize * sizeof(char *));
- env[0] = NULL;
-
- if (!options.use_login) {
- /* Set basic environment. */
- child_set_env(&env, &envsize, "USER", pw->pw_name);
- child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
- child_set_env(&env, &envsize, "HOME", pw->pw_dir);
- child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
-
- snprintf(buf, sizeof buf, "%.200s/%.50s",
- _PATH_MAILDIR, pw->pw_name);
- child_set_env(&env, &envsize, "MAIL", buf);
-
- /* Normal systems set SHELL by default. */
- child_set_env(&env, &envsize, "SHELL", shell);
- }
- if (getenv("TZ"))
- child_set_env(&env, &envsize, "TZ", getenv("TZ"));
-
- /* Set custom environment options from RSA authentication. */
- while (custom_environment) {
- struct envstring *ce = custom_environment;
- char *s = ce->s;
- int i;
- for (i = 0; s[i] != '=' && s[i]; i++);
- if (s[i] == '=') {
- s[i] = 0;
- child_set_env(&env, &envsize, s, s + i + 1);
- }
- custom_environment = ce->next;
- xfree(ce->s);
- xfree(ce);
- }
-
- snprintf(buf, sizeof buf, "%.50s %d %d",
- get_remote_ipaddr(), get_remote_port(), get_local_port());
- child_set_env(&env, &envsize, "SSH_CLIENT", buf);
-
- if (ttyname)
- child_set_env(&env, &envsize, "SSH_TTY", ttyname);
- if (term)
- child_set_env(&env, &envsize, "TERM", term);
- if (display)
- child_set_env(&env, &envsize, "DISPLAY", display);
-
-#ifdef KRB4
- {
- extern char *ticket;
-
- if (ticket)
- child_set_env(&env, &envsize, "KRBTKFILE", ticket);
- }
-#endif /* KRB4 */
-
- if (xauthfile)
- child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
- if (auth_get_socket_name() != NULL)
- child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
- auth_get_socket_name());
-
- /* read $HOME/.ssh/environment. */
- if (!options.use_login) {
- snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
- read_environment_file(&env, &envsize, buf);
- }
- if (debug_flag) {
- /* dump the environment */
- fprintf(stderr, "Environment:\n");
- for (i = 0; env[i]; i++)
- fprintf(stderr, " %.200s\n", env[i]);
- }
- /*
- * Close the connection descriptors; note that this is the child, and
- * the server will still have the socket open, and it is important
- * that we do not shutdown it. Note that the descriptors cannot be
- * closed before building the environment, as we call
- * get_remote_ipaddr there.
- */
- if (packet_get_connection_in() == packet_get_connection_out())
- close(packet_get_connection_in());
- else {
- close(packet_get_connection_in());
- close(packet_get_connection_out());
- }
- /*
- * Close all descriptors related to channels. They will still remain
- * open in the parent.
- */
- /* XXX better use close-on-exec? -markus */
- channel_close_all();
-
- /*
- * Close any extra file descriptors. Note that there may still be
- * descriptors left by system functions. They will be closed later.
- */
- endpwent();
-
- /*
- * Close any extra open file descriptors so that we don\'t have them
- * hanging around in clients. Note that we want to do this after
- * initgroups, because at least on Solaris 2.3 it leaves file
- * descriptors open.
- */
- for (i = 3; i < 64; i++)
- close(i);
-
- /* Change current directory to the user\'s home directory. */
- if (chdir(pw->pw_dir) < 0)
- fprintf(stderr, "Could not chdir to home directory %s: %s\n",
- pw->pw_dir, strerror(errno));
-
- /*
- * Must take new environment into use so that .ssh/rc, /etc/sshrc and
- * xauth are run in the proper environment.
- */
- environ = env;
-
- /*
- * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
- * in this order).
- */
- if (!options.use_login) {
- if (stat(SSH_USER_RC, &st) >= 0) {
- if (debug_flag)
- fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
-
- f = popen("/bin/sh " SSH_USER_RC, "w");
- if (f) {
- if (auth_proto != NULL && auth_data != NULL)
- fprintf(f, "%s %s\n", auth_proto, auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
- } else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
- if (debug_flag)
- fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
-
- f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
- if (f) {
- if (auth_proto != NULL && auth_data != NULL)
- fprintf(f, "%s %s\n", auth_proto, auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
- }
-#ifdef XAUTH_PATH
- else {
- /* Add authority data to .Xauthority if appropriate. */
- if (auth_proto != NULL && auth_data != NULL) {
- if (debug_flag)
- fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
- XAUTH_PATH, display, auth_proto, auth_data);
-
- f = popen(XAUTH_PATH " -q -", "w");
- if (f) {
- fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data);
- pclose(f);
- } else
- fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH);
- }
- }
-#endif /* XAUTH_PATH */
-
- /* Get the last component of the shell name. */
- cp = strrchr(shell, '/');
- if (cp)
- cp++;
- else
- cp = shell;
- }
- /*
- * If we have no command, execute the shell. In this case, the shell
- * name to be passed in argv[0] is preceded by '-' to indicate that
- * this is a login shell.
- */
- if (!command) {
- if (!options.use_login) {
- char buf[256];
-
- /*
- * Check for mail if we have a tty and it was enabled
- * in server options.
- */
- if (ttyname && options.check_mail) {
- char *mailbox;
- struct stat mailstat;
- mailbox = getenv("MAIL");
- if (mailbox != NULL) {
- if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0)
- printf("No mail.\n");
- else if (mailstat.st_mtime < mailstat.st_atime)
- printf("You have mail.\n");
- else
- printf("You have new mail.\n");
- }
- }
- /* Start the shell. Set initial character to '-'. */
- buf[0] = '-';
- strncpy(buf + 1, cp, sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = 0;
-
- /* Execute the shell. */
- argv[0] = buf;
- argv[1] = NULL;
- execve(shell, argv, env);
-
- /* Executing the shell failed. */
- perror(shell);
- exit(1);
-
- } else {
- /* Launch login(1). */
-
- execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(),
- "-p", "-f", "--", pw->pw_name, NULL);
-
- /* Login couldn't be executed, die. */
-
- perror("login");
- exit(1);
- }
- }
- /*
- * Execute the command using the user's shell. This uses the -c
- * option to execute the command.
- */
- argv[0] = (char *) cp;
- argv[1] = "-c";
- argv[2] = (char *) command;
- argv[3] = NULL;
- execve(shell, argv, env);
- perror(shell);
- exit(1);
+ debug("done: KEX2.");
}
diff --git a/crypto/openssh/sshd/Makefile b/crypto/openssh/sshd/Makefile
index 3815b5a302b9..f74a03253756 100644
--- a/crypto/openssh/sshd/Makefile
+++ b/crypto/openssh/sshd/Makefile
@@ -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
diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config
index 0d4038420774..0366ee48542e 100644
--- a/crypto/openssh/sshd_config
+++ b/crypto/openssh/sshd_config
@@ -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
diff --git a/crypto/openssh/ttymodes.c b/crypto/openssh/ttymodes.c
index 309885efb4cd..25f501349424 100644
--- a/crypto/openssh/ttymodes.c
+++ b/crypto/openssh/ttymodes.c
@@ -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;
diff --git a/crypto/openssh/ttymodes.h b/crypto/openssh/ttymodes.h
index 433ff73efa86..f8243f61f875 100644
--- a/crypto/openssh/ttymodes.h
+++ b/crypto/openssh/ttymodes.h
@@ -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).
diff --git a/crypto/openssh/uidswap.c b/crypto/openssh/uidswap.c
index aebff0c73c88..20f04cf9bdc2 100644
--- a/crypto/openssh/uidswap.c
+++ b/crypto/openssh/uidswap.c
@@ -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)
diff --git a/crypto/openssh/uidswap.h b/crypto/openssh/uidswap.h
index 4755710dea9b..c08a37004616 100644
--- a/crypto/openssh/uidswap.h
+++ b/crypto/openssh/uidswap.h
@@ -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
diff --git a/crypto/openssh/uuencode.c b/crypto/openssh/uuencode.c
new file mode 100644
index 000000000000..fc84d5a5830b
--- /dev/null
+++ b/crypto/openssh/uuencode.c
@@ -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);
+}
diff --git a/crypto/openssh/uuencode.h b/crypto/openssh/uuencode.h
new file mode 100644
index 000000000000..c92c62744cc2
--- /dev/null
+++ b/crypto/openssh/uuencode.h
@@ -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
diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h
index fe2e876ea87c..d577644d61e7 100644
--- a/crypto/openssh/version.h
+++ b/crypto/openssh/version.h
@@ -1 +1 @@
-#define SSH_VERSION "OpenSSH-1.2.3"
+#define SSH_VERSION "OpenSSH-2.1"
diff --git a/crypto/openssh/xmalloc.c b/crypto/openssh/xmalloc.c
index afcdbd97cab6..31550991a2be 100644
--- a/crypto/openssh/xmalloc.c
+++ b/crypto/openssh/xmalloc.c
@@ -8,7 +8,7 @@
*/
#include "includes.h"
-RCSID("$Id: xmalloc.c,v 1.5 1999/11/24 00:26:04 deraadt Exp $");
+RCSID("$Id: xmalloc.c,v 1.6 2000/04/14 10:30:34 markus Exp $");
#include "ssh.h"
@@ -34,7 +34,7 @@ xrealloc(void *ptr, size_t new_size)
return new_ptr;
}
-void
+void
xfree(void *ptr)
{
if (ptr == NULL)
diff --git a/crypto/openssh/xmalloc.h b/crypto/openssh/xmalloc.h
index ec49eb1af494..31291ea4ace5 100644
--- a/crypto/openssh/xmalloc.h
+++ b/crypto/openssh/xmalloc.h
@@ -1,20 +1,20 @@
/*
- *
+ *
* xmalloc.h
- *
+ *
* Author: Tatu Ylonen <ylo@cs.hut.fi>
- *
+ *
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
- *
+ *
* Created: Mon Mar 20 22:09:17 1995 ylo
- *
+ *
* Versions of malloc and friends that check their results, and never return
* failure (they call fatal if they encounter an error).
- *
+ *
*/
-/* RCSID("$Id: xmalloc.h,v 1.2 1999/11/24 00:26:04 deraadt Exp $"); */
+/* RCSID("$Id: xmalloc.h,v 1.3 2000/04/14 10:30:34 markus Exp $"); */
#ifndef XMALLOC_H
#define XMALLOC_H