Commit d6dcb8fb authored by Balázs Scheidler's avatar Balázs Scheidler Committed by Niels Möller
Browse files

Merged bazsi's patch:

* src/lshd.c (do_read_key): Moved key reading to spki.c. (Bazsi)

* src/spki.c (parse_dsa_private_key): Moved from lshd.c. (Bazsi)
(parse_private_key): New function (Bazsi).
(do_spki_parse_key): New function (Bazsi).
(make_spki_parse_key): New function (Bazsi).
(read_spki_key_file): New function (Bazsi).

* src/server_publickey.c (do_authenticate): Changed the handling
of PEER_SSH_DSS_KLUDGE. (Bazsi)

* src/server_keyexchange.c (do_init_server_dh): Handle
PEER_SSH_DSS_KLUDGE. (Bazsi)

* src/publickey_crypto.c (make_keypair): Added type argument. (Bazsi)

* src/publickey_crypto.h (keypair): Added type attribute. (Bazsi)

* src/lsh.c (main_options): Added identity argument. (Bazsi)

* src/keyexchange.c (do_handle_kexinit): Don't use
ATOM_SSH_DSS_KLUDGE. (Bazsi)

* src/exception.h (EXC_IO_OPEN_READ): New exception type. (Bazsi)

* src/connection_commands.c (do_line): Fixed detection of ssh2.

* src/client_keyexchange.c (dh_client): Added hostkey_algorithm
attribute. (Bazsi)
(do_handle_dh_reply): Handle the dss kludge here. (Bazsi)
(do_init_client_dh): Don't use ATOM_SSH_DSS_KLUDGE. (Bazsi)

* src/atoms.in: Removed ssh-dss-kludge. (Bazsi)

* src/lshd.c (main): Deal with pid files after forking and
daemonization, to get the right pid.

Rev: src/atoms.in:1.7
Rev: src/client.c:1.80
Rev: src/client_keyexchange.c:1.35
Rev: src/client_userauth.c:1.20
Rev: src/connection_commands.c:1.16
Rev: src/exception.h:1.12
Rev: src/keyexchange.c:1.57
Rev: src/lookup_verifier.h:1.2
Rev: src/lsh.c:1.79
Rev: src/lshd.c:1.71
Rev: src/publickey_crypto.c:1.35
Rev: src/publickey_crypto.h:1.25
Rev: src/server_keyexchange.c:1.34
Rev: src/server_publickey.c:1.4
Rev: src/spki.c:1.4
Rev: src/spki.h:1.3
Rev: src/userauth.h:1.16
parent 865d9b90
......@@ -56,7 +56,6 @@ diffie-hellman-group1-sha1 REQUIRED
# Key and certificate types
ssh-dss REQUIRED sign Simple DSS
ssh-dss-kludge HACK sign Simple DSS in old ssh2 style
x509v3 RECOMMENDED sign X.509 certificates
spki OPTIONAL sign SPKI certificates
pgp OPTIONAL sign OpenPGP certificates
......
......@@ -410,6 +410,11 @@ do_client_io(struct command *s UNUSED,
channel->send = do_send;
session->in->super.read = make_channel_read_data(channel);
/* FIXME: Perhaps there is some way to arrange that channel.c calls
* the CHANNEL_SEND method instead? */
if (session->super.send_window_size)
session->in->super.want_read = 1;
session->in->super.close_callback
= make_channel_read_close_callback(channel);
......
......@@ -59,6 +59,7 @@
(super packet_handler)
(vars
(dh struct diffie_hellman_instance)
(hostkey_algorithm . UINT32)
(verifier object lookup_verifier)
(install object install_keys)))
*/
......@@ -82,6 +83,14 @@ do_handle_dh_reply(struct packet_handler *c,
v = LOOKUP_VERIFIER(closure->verifier, NULL, closure->dh.server_key);
#if DATAFELLOWS_WORKAROUNDS
if (closure->hostkey_algorithm == ATOM_SSH_DSS &&
(connection->peer_flags & PEER_SSH_DSS_KLUDGE))
{
v = make_dsa_verifier_kludge(v);
}
#endif
if (!v)
/* FIXME: Use a more appropriate error code? */
{
......@@ -160,14 +169,6 @@ do_init_client_dh(struct keyexchange_algorithm *c,
CHECK_SUBTYPE(ssh_connection, connection);
CHECK_SUBTYPE(signature_algorithm, ignored);
/* FIXME: Use this value to choose a verifier function */
if ( (hostkey_algorithm_atom != ATOM_SSH_DSS )
#if DATAFELLOWS_WORKAROUNDS
&& (hostkey_algorithm_atom != ATOM_SSH_DSS_KLUDGE)
#endif
)
fatal("Internal error\n");
/* Initialize */
dh->super.handler = do_handle_dh_reply;
init_diffie_hellman_instance(closure->dh, &dh->dh, connection);
......@@ -175,8 +176,15 @@ do_init_client_dh(struct keyexchange_algorithm *c,
{
CAST_SUBTYPE(lookup_verifier, v,
ALIST_GET(closure->verifiers, hostkey_algorithm_atom));
assert(v);
/* FIXME: We should make sure that we never advertise hostkey
* algorithms for which we have no verifiers. */
if (!v)
{
fatal("No verifier for the '%a' hostkey algorithm.\n", hostkey_algorithm_atom);
}
dh->verifier = v;
dh->hostkey_algorithm = hostkey_algorithm_atom;
}
dh->install = make_install_new_keys(0, algorithms);
......
......@@ -4,7 +4,7 @@
/* lsh, an implementation of the ssh protocol
*
* Copyright (C) 1998 Niels Mller
* Copyright (C) 1999 Niels Mller, Balazs Scheidler
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -50,38 +50,12 @@
* from the start, we ask the user for a password and attempt to log
* in using that. */
static struct packet_handler *make_banner_handler(void);
/* Forward declaration */
struct client_userauth;
#include "client_userauth.c.x"
/* GABA:
(class
(name client_userauth)
(super command)
(vars
(username string) ; Remote user name to authenticate as.
(service_name simple int) ; Service we want to access .
; FIXME: Keys to try
))
*/
/* GABA:
(class
(name success_handler)
(super packet_handler)
(vars
(c object command_continuation)))
*/
/* GABA:
(class
(name failure_handler)
(super packet_handler)
(vars
(e object exception_handler)
(userauth object client_userauth)))
*/
static struct packet_handler *make_banner_handler(void);
static struct lsh_string *format_userauth_password(struct lsh_string *name,
int service,
......@@ -97,30 +71,107 @@ static struct lsh_string *format_userauth_password(struct lsh_string *name,
passwd);
}
/* GABA:
(class
(name client_userauth_method)
(vars
; set up message handlers
(setup method void "struct ssh_connection *connection")
; send authentication request
(send method void "struct client_userauth *userauth"
"struct ssh_connection *connection")
; clean up message handlers
(cleanup method void "struct ssh_connection *connection")))
*/
#define CLIENT_USERAUTH_SETUP(m, c) ((m->setup) ? ((m)->setup(m, c)) : (void) 0)
#define CLIENT_USERAUTH_SEND(m, u, c) ((m->send) ? ((m)->send(m, u, c)) : (void) 0)
#define CLIENT_USERAUTH_CLEANUP(m, c) ((m->cleanup) ? ((m)->cleanup(m, c)) : (void) 0)
#define MAX_PASSWD 100
static void
send_passwd(struct client_userauth *userauth,
struct ssh_connection *connection)
do_send_password(struct client_userauth_method *self UNUSED,
struct client_userauth *userauth,
struct ssh_connection *connection)
{
struct lsh_string *passwd
= read_password(MAX_PASSWD,
ssh_format("Password for %lS: ",
userauth->username), 1);
ssh_format("Password for %lS: ",
userauth->username), 1);
if (!passwd)
{
/* FIXME: What to do now??? */
fatal("read_password failed!?\n");
}
C_WRITE(connection,
format_userauth_password(local_to_utf8(userauth->username, 0),
userauth->service_name,
local_to_utf8(passwd, 1),
1));
format_userauth_password(local_to_utf8(userauth->username, 0),
userauth->service_name,
local_to_utf8(passwd, 1),
1));
}
struct client_userauth_method *
make_client_password_auth(void)
{
NEW(client_userauth_method, self);
self->send = do_send_password;
return self;
}
/* GABA:
(class
(name client_publickey_method)
(super client_userauth_method)
(vars
(dummy . int)))
*/
struct client_userauth_method *
make_client_publickey_auth(void)
{
NEW(client_publickey_method, self);
return &self->super;
}
/* GABA:
(class
(name client_userauth)
(super command)
(vars
(username string) ; Remote user name to authenticate as.
(service_name simple int) ; Service we want to access .
(current_method simple int)
(methods object alist) ; authentication methods
; FIXME: Keys to try
))
*/
/* GABA:
(class
(name success_handler)
(super packet_handler)
(vars
(c object command_continuation)
(userauth object client_userauth)))
*/
/* GABA:
(class
(name failure_handler)
(super packet_handler)
(vars
(e object exception_handler)
(userauth object client_userauth)))
*/
static void
do_userauth_success(struct packet_handler *c,
struct ssh_connection *connection,
......@@ -137,6 +188,9 @@ do_userauth_success(struct packet_handler *c,
&& (msg_number == SSH_MSG_USERAUTH_SUCCESS)
&& parse_eod(&buffer))
{
CAST(client_userauth_method, method,
ALIST_GET(closure->userauth->methods,
closure->userauth->current_method));
werror("User authentication successful.\n");
lsh_string_free(packet);
......@@ -144,6 +198,8 @@ do_userauth_success(struct packet_handler *c,
connection->dispatch[SSH_MSG_USERAUTH_SUCCESS] = connection->fail;
connection->dispatch[SSH_MSG_USERAUTH_FAILURE] = connection->fail;
connection->dispatch[SSH_MSG_USERAUTH_BANNER] = connection->fail;
CLIENT_USERAUTH_CLEANUP(method, connection);
COMMAND_RETURN(closure->c, connection);
}
......@@ -190,13 +246,31 @@ do_userauth_failure(struct packet_handler *c,
"indicating partial success.\n");
for(i = 0; i < LIST_LENGTH(methods); i++)
if (LIST(methods)[i] == ATOM_PASSWORD)
{
/* Try again */
KILL(methods);
send_passwd(closure->userauth, connection);
return;
}
{
CAST(client_userauth_method, method,
ALIST_GET(closure->userauth->methods,
LIST(methods)[i]));
CAST(client_userauth_method, old_method,
ALIST_GET(closure->userauth->methods,
closure->userauth->current_method));
if (method)
{
if (old_method != method)
{
closure->userauth->current_method = LIST(methods)[i];
CLIENT_USERAUTH_CLEANUP(old_method, connection);
CLIENT_USERAUTH_SETUP(method, connection);
CLIENT_USERAUTH_SEND(method, closure->userauth, connection);
KILL(methods);
return;
}
else
{
/* no need to cleanup & setup */
CLIENT_USERAUTH_SEND(method, closure->userauth, connection);
}
}
}
/* No methods that we can use */
KILL(methods);
......@@ -244,11 +318,13 @@ do_userauth_banner(struct packet_handler *closure,
}
static struct packet_handler *
make_success_handler(struct command_continuation *c)
make_success_handler(struct client_userauth *userauth,
struct command_continuation *c)
{
NEW(success_handler, self);
self->super.handler = do_userauth_success;
self->userauth = userauth;
self->c = c;
return &self->super;
......@@ -284,26 +360,39 @@ do_client_userauth(struct command *s,
{
CAST(client_userauth, self, s);
CAST(ssh_connection, connection, x);
struct client_userauth_method *m;
connection->dispatch[SSH_MSG_USERAUTH_SUCCESS]
= make_success_handler(c);
= make_success_handler(self, c);
connection->dispatch[SSH_MSG_USERAUTH_FAILURE]
= make_failure_handler(self, e);
connection->dispatch[SSH_MSG_USERAUTH_BANNER]
= make_banner_handler();
m = ALIST_GET(self->methods, self->current_method);
if (m)
{
CLIENT_USERAUTH_SETUP(m, connection);
CLIENT_USERAUTH_SEND(m, self, connection);
}
#if 0
/* Pass e on? */
return send_passwd(self, connection);
#endif
}
struct command *make_client_userauth(struct lsh_string *username,
int service_name)
int service_name,
int first_method,
struct alist *methods)
{
NEW(client_userauth, self);
self->super.call = do_client_userauth;
self->username = username;
self->service_name = service_name;
self->current_method = first_method;
self->methods = methods;
return &self->super;
}
......@@ -171,7 +171,7 @@ do_line(struct line_handler **h,
#endif /* WITH_SSH1_FALLBACK */
#if DATAFELLOWS_WORKAROUNDS
if ( (swver_len > 6) && !memcmp(swver, "2.0.", 4)
if ( (swver_len >= 6) && !memcmp(swver, "2.0.", 4)
/* FIXME: Perhaps do a numerical comparison here? */
&& (memcmp(swver + 4, "13", 2) <= 0) )
{
......
......@@ -86,7 +86,8 @@ void exception_raise(struct exception_handler *e,
#define EXC_IO_READ 0x2004
#define EXC_IO_WRITE 0x2005
#define EXC_IO_OPEN_WRITE 0x2006
#define EXC_IO_LISTEN 0x2007
#define EXC_IO_OPEN_READ 0x2007
#define EXC_IO_LISTEN 0x2008
/* Authorization errors */
#define EXC_AUTH 0x4000
......
......@@ -269,6 +269,7 @@ do_handle_kexinit(struct packet_handler *c,
= select_algorithm(connection->kexinits[0]->server_hostkey_algorithms,
connection->kexinits[1]->server_hostkey_algorithms);
#if 0
#if DATAFELLOWS_WORKAROUNDS
if ( (hostkey_algorithm_atom == ATOM_SSH_DSS)
&& (connection->peer_flags & PEER_SSH_DSS_KLUDGE))
......@@ -276,7 +277,8 @@ do_handle_kexinit(struct packet_handler *c,
hostkey_algorithm_atom = ATOM_SSH_DSS_KLUDGE;
}
#endif /* DATAFELLOWS_WORKAROUNDS */
#endif
for(i = 0; i<KEX_PARAMETERS; i++)
{
parameters[i]
......
......@@ -48,7 +48,8 @@
(name lookup_verifier)
(vars
(lookup method (object verifier)
"struct lsh_string *keyholder" "struct lsh_string *key")))
"struct lsh_string *keyholder"
"struct lsh_string *key")))
*/
#define LOOKUP_VERIFIER(l, kh, key) ((l)->lookup((l), (kh), (key)))
......
......@@ -41,6 +41,7 @@
#include "randomness.h"
#include "service.h"
#include "ssh.h"
#include "spki.h"
#include "tcpforward_commands.h"
#include "tty.h"
#include "userauth.h"
......@@ -219,6 +220,7 @@ main_options[] =
/* Name, key, arg-name, flags, doc, group */
{ "port", 'p', "Port", 0, "Connect to this port.", 0 },
{ "user", 'l', "User name", 0, "Login as this user.", 0 },
{ "identity", 'i', "Identity key", 0, "Use this key to authenticate.", 0 },
{ NULL, 0, NULL, 0, "Actions:", 0 },
{ "forward-local-port", 'L', "local-port:target-host:target-port", 0, "", 0 },
{ "forward-remote-port", 'R', "remote-port:target-host:target-port", 0, "", 0 },
......@@ -255,6 +257,7 @@ main_options[] =
(remote object address_info)
(user . "char *")
(identity . "char *")
; -1 means default behaviour
(with_pty . int)
......@@ -282,6 +285,12 @@ make_options(struct alist *algorithms, struct io_backend *backend,
self->not = 0;
self->remote = NULL;
self->user = getenv("LOGNAME");
/* FIXME: Default should be ~/.lsh/identity. But we also need some *
* option to disable public key authenticaation, and perhaps also
* for using several key files. */
self->identity = NULL;
self->port = "ssh";
self->with_pty = -1;
......@@ -434,6 +443,9 @@ main_argp_parser(int key, char *arg, struct argp_state *state)
case 'l':
self->user = arg;
break;
case 'i':
self->identity = arg;
break;
case 'L':
{
......@@ -599,6 +611,7 @@ int main(int argc, char **argv)
struct alist *algorithms;
struct make_kexinit *make_kexinit;
struct alist *lookup_table; /* Alist of signature-algorithm -> lookup_verifier */
struct alist *identity_keys = NULL;
/* int in, out, err; */
......@@ -624,10 +637,6 @@ int main(int argc, char **argv)
/* No randomness is needed for verifying signatures */
lookup_table = make_alist(1
#if DATAFELLOWS_WORKAROUNDS
+1,
ATOM_SSH_DSS_KLUDGE, make_fake_host_db(make_dsa_kludge_algorithm(NULL))
#endif
, ATOM_SSH_DSS, make_fake_host_db(make_dsa_algorithm(NULL)),
-1);
......@@ -642,6 +651,18 @@ int main(int argc, char **argv)
argp_parse(&main_argp, argc, argv, ARGP_IN_ORDER, NULL, options);
if (options->identity)
{
#if 0
identity_keys = make_alist(0, -1);
if (!read_spki_key_file(options->identity, identity_keys, r, &ignore_exception_handler))
{
KILL(identity_keys);
identity_keys = NULL;
}
#endif
}
make_kexinit
= make_simple_kexinit(r,
make_int_list(1, ATOM_DIFFIE_HELLMAN_GROUP1_SHA1,
......@@ -663,7 +684,10 @@ int main(int argc, char **argv)
NULL),
make_request_service(ATOM_SSH_USERAUTH),
make_client_userauth(ssh_format("%lz", options->user),
ATOM_SSH_CONNECTION),
ATOM_SSH_CONNECTION,
ATOM_PASSWORD,
make_alist(1,
ATOM_PASSWORD, make_client_password_auth(), -1)),
queue_to_list(&options->actions));
CAST_SUBTYPE(command, client_connect, o);
......
......@@ -46,6 +46,8 @@
#include "server_session.h"
#include "server_userauth.h"
#include "sexp.h"
#include "sexp_commands.h"
#include "spki.h"
#include "ssh.h"
#include "tcpforward.h"
#include "tcpforward_commands.h"
......@@ -262,140 +264,6 @@ main_argp =
NULL, NULL
};
/* FIXME: We should have some more general functions for reading
* private keys. */
/* GABA:
(class
(name read_key)
(super command_continuation)
(vars
(random object randomness)
;; Maps hostkey algorithm to a keyinfo structure
(keys object alist)))
*/
static void do_read_key(struct command_continuation *s,
struct lsh_object *a)
{
CAST(read_key, closure, s);
CAST_SUBTYPE(sexp, private, a);
struct sexp_iterator *i;
struct sexp *e;
mpz_t p, q, g, y, x;
if (!sexp_check_type(private, "private-key", &i))
{
werror("lshd: Host key file does not contain a private key.");
return;
}
e = SEXP_GET(i);
if (! (e && sexp_check_type(e, "dsa", &i)))
{
werror("lshd: Unknown key type (only dsa is supported)\n");
return;
}
mpz_init(p);
mpz_init(q);
mpz_init(g);
mpz_init(y);
mpz_init(x);
if (sexp_get_un(i, "p", p)
&& sexp_get_un(i, "q", q)
&& sexp_get_un(i, "g", g)
&& sexp_get_un(i, "y", y)
&& sexp_get_un(i, "x", x)
&& !SEXP_GET(i))
{
/* Test key */
mpz_t tmp;
struct lsh_string *s;
mpz_init_set(tmp, g);
mpz_powm(tmp, tmp, x, p);
if (mpz_cmp(tmp, y))
{
werror("lshd: Host key doesn't work.\n");
mpz_clear(tmp);
}
else
{
struct lsh_string *public
= ssh_format("%a%n%n%n%n", ATOM_SSH_DSS, p, q, g, y);
struct signer *private;
s = ssh_format("%n", x);
private = MAKE_SIGNER(make_dsa_algorithm(closure->random),
public->length, public->data,
s->length, s->data);
assert(private);
lsh_string_free(s);
/* FIXME: Check if we already have a key for this algorithm,
* and warn about multiple keys. */
ALIST_SET(closure->keys, ATOM_SSH_DSS,
make_keypair(public, private));
#if DATAFELLOWS_WORKAROUNDS
ALIST_SET(closure->keys, ATOM_SSH_DSS_KLUDGE,
make_keypair(public,
make_dsa_signer_kludge(private)));
#endif /* DATAFELLOWS_WORKAROUNDS */
debug("lshd: Using (public) hostkey:\n"
" p=%xn\n"
" q=%xn\n"
" g=%xn\n"
" y=%xn\n",
p, q, g, y);
}
}
/* Cleanup */
mpz_clear(p);
mpz_clear(q);
mpz_clear(g);
mpz_clear(y);
mpz_clear(x);
}
static int read_host_key(const char *name,
struct alist *keys,
struct randomness *r)
{
int fd = open(name, O_RDONLY);
if (fd < 0)
{
werror("lshd: Could not open %z (errno = %i): %z\n",
name, errno, STRERROR(errno));
return 0;
}
else
{
int res;
NEW(read_key, handler);
handler->super.c = do_read_key;
handler->random = r;
handler->keys = keys;
res = blocking_read(fd,
make_read_sexp(SEXP_TRANSPORT, 1,
&handler->super, &ignore_exception_handler));
close(fd);
KILL(handler);