mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-28 08:14:24 +02:00
- Merge big update to OpenSSH-2.0 from OpenBSD CVS
[README.openssh2] - interop w/ F-secure windows client - sync documentation - ssh_host_dsa_key not ssh_dsa_key [auth-rsa.c] - missing fclose [auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c] [readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c] [sshd.c uuencode.c uuencode.h authfile.h] - add DSA pubkey auth and other SSH2 fixes. use ssh-keygen -[xX] for trading keys with the real and the original SSH, directly from the people who invented the SSH protocol. [auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h] [sshconnect1.c sshconnect2.c] - split auth/sshconnect in one file per protocol version [sshconnect2.c] - remove debug [uuencode.c] - add trailing = [version.h] - OpenSSH-2.0 [ssh-keygen.1 ssh-keygen.c] - add -R flag: exit code indicates if RSA is alive [sshd.c] - remove unused silent if -Q is specified [ssh.h] - host key becomes /etc/ssh_host_dsa_key [readconf.c servconf.c ] - ssh/sshd default to proto 1 and 2 [uuencode.c] - remove debug [auth2.c ssh-keygen.c sshconnect2.c sshd.c] - xfree DSA blobs [auth2.c serverloop.c session.c] - cleanup logging for sshd/2, respect PasswordAuth no [sshconnect2.c] - less debug, respect .ssh/config [README.openssh2 channels.c channels.h] - clientloop.c session.c ssh.c - support for x11-fwding, client+server
This commit is contained in:
parent
8117111a3c
commit
eba71bab9b
44
ChangeLog
44
ChangeLog
@ -1,3 +1,47 @@
|
|||||||
|
20000429
|
||||||
|
- Merge big update to OpenSSH-2.0 from OpenBSD CVS
|
||||||
|
[README.openssh2]
|
||||||
|
- interop w/ F-secure windows client
|
||||||
|
- sync documentation
|
||||||
|
- ssh_host_dsa_key not ssh_dsa_key
|
||||||
|
[auth-rsa.c]
|
||||||
|
- missing fclose
|
||||||
|
[auth.c authfile.c compat.c dsa.c dsa.h hostfile.c key.c key.h radix.c]
|
||||||
|
[readconf.c readconf.h ssh-add.c ssh-keygen.c ssh.c ssh.h sshconnect.c]
|
||||||
|
[sshd.c uuencode.c uuencode.h authfile.h]
|
||||||
|
- add DSA pubkey auth and other SSH2 fixes. use ssh-keygen -[xX]
|
||||||
|
for trading keys with the real and the original SSH, directly from the
|
||||||
|
people who invented the SSH protocol.
|
||||||
|
[auth.c auth.h authfile.c sshconnect.c auth1.c auth2.c sshconnect.h]
|
||||||
|
[sshconnect1.c sshconnect2.c]
|
||||||
|
- split auth/sshconnect in one file per protocol version
|
||||||
|
[sshconnect2.c]
|
||||||
|
- remove debug
|
||||||
|
[uuencode.c]
|
||||||
|
- add trailing =
|
||||||
|
[version.h]
|
||||||
|
- OpenSSH-2.0
|
||||||
|
[ssh-keygen.1 ssh-keygen.c]
|
||||||
|
- add -R flag: exit code indicates if RSA is alive
|
||||||
|
[sshd.c]
|
||||||
|
- remove unused
|
||||||
|
silent if -Q is specified
|
||||||
|
[ssh.h]
|
||||||
|
- host key becomes /etc/ssh_host_dsa_key
|
||||||
|
[readconf.c servconf.c ]
|
||||||
|
- ssh/sshd default to proto 1 and 2
|
||||||
|
[uuencode.c]
|
||||||
|
- remove debug
|
||||||
|
[auth2.c ssh-keygen.c sshconnect2.c sshd.c]
|
||||||
|
- xfree DSA blobs
|
||||||
|
[auth2.c serverloop.c session.c]
|
||||||
|
- cleanup logging for sshd/2, respect PasswordAuth no
|
||||||
|
[sshconnect2.c]
|
||||||
|
- less debug, respect .ssh/config
|
||||||
|
[README.openssh2 channels.c channels.h]
|
||||||
|
- clientloop.c session.c ssh.c
|
||||||
|
- support for x11-fwding, client+server
|
||||||
|
|
||||||
20000421
|
20000421
|
||||||
- Merge fix from OpenBSD CVS
|
- Merge fix from OpenBSD CVS
|
||||||
[ssh-agent.c]
|
[ssh-agent.c]
|
||||||
|
@ -31,11 +31,11 @@ LDFLAGS=-L. @LDFLAGS@
|
|||||||
|
|
||||||
TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
|
TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
|
||||||
|
|
||||||
LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o
|
LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o
|
||||||
|
|
||||||
SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o
|
SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o clientloop.o
|
||||||
|
|
||||||
SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o auth.o
|
SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o session.o
|
||||||
|
|
||||||
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8
|
TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8
|
||||||
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0
|
CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
$Id: README.openssh2,v 1.3 2000/04/12 07:45:43 markus Exp $
|
$Id: README.openssh2,v 1.6 2000/04/27 13:42:58 provos Exp $
|
||||||
|
|
||||||
howto:
|
howto:
|
||||||
1) generate server key:
|
1) generate server key:
|
||||||
$ umask 077
|
$ ssh-keygen -d -f /etc/ssh_host_dsa_key -N ''
|
||||||
$ openssl dsaparam 1024 -out dsa1024.pem
|
|
||||||
$ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
|
|
||||||
2) enable ssh2:
|
2) enable ssh2:
|
||||||
server: add 'Protocol 2,1' to /etc/sshd_config
|
server: add 'Protocol 2,1' to /etc/sshd_config
|
||||||
client: ssh -o 'Protocol 2,1', or add to .ssh/config
|
client: ssh -o 'Protocol 2,1', or add to .ssh/config
|
||||||
|
3) 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:
|
works:
|
||||||
secsh-transport: works w/o rekey
|
secsh-transport: works w/o rekey
|
||||||
@ -22,7 +25,7 @@ works:
|
|||||||
key database in ~/.ssh/known_hosts with bits == 0 hack
|
key database in ~/.ssh/known_hosts with bits == 0 hack
|
||||||
dss: signature works, keygen w/ openssl
|
dss: signature works, keygen w/ openssl
|
||||||
client interops w/ sshd2, lshd
|
client interops w/ sshd2, lshd
|
||||||
server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT
|
server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT, F-Secure SSH Client 4.0
|
||||||
server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
|
server supports multiple concurrent sessions (e.g. with SSH.com Windows client)
|
||||||
todo:
|
todo:
|
||||||
re-keying
|
re-keying
|
||||||
@ -38,4 +41,4 @@ todo:
|
|||||||
sftp
|
sftp
|
||||||
|
|
||||||
-markus
|
-markus
|
||||||
$Date: 2000/04/12 07:45:43 $
|
$Date: 2000/04/27 13:42:58 $
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: auth-rsa.c,v 1.17 2000/04/16 02:31:49 damien Exp $");
|
RCSID("$Id: auth-rsa.c,v 1.18 2000/04/29 13:57:09 damien Exp $");
|
||||||
|
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@ -185,6 +185,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fail) {
|
if (fail) {
|
||||||
|
fclose(f);
|
||||||
log(buf);
|
log(buf);
|
||||||
packet_send_debug(buf);
|
packet_send_debug(buf);
|
||||||
restore_uid();
|
restore_uid();
|
||||||
|
686
auth.c
686
auth.c
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: auth.c,v 1.4 2000/04/14 10:30:29 markus Exp $");
|
RCSID("$OpenBSD: auth.c,v 1.6 2000/04/26 21:28:31 markus Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -40,7 +40,7 @@ extern char *forced_command;
|
|||||||
* If the user's shell is not executable, false will be returned.
|
* If the user's shell is not executable, false will be returned.
|
||||||
* Otherwise true is returned.
|
* Otherwise true is returned.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
allowed_user(struct passwd * pw)
|
allowed_user(struct passwd * pw)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -118,685 +118,3 @@ allowed_user(struct passwd * pw)
|
|||||||
/* We found no reason not to let this user try to log on... */
|
/* We found no reason not to let this user try to log on... */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define AUTH_FAIL_MAX 6
|
|
||||||
#define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)
|
|
||||||
#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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());
|
|
||||||
|
|
||||||
#ifdef WITH_AIXAUTHENTICATE
|
|
||||||
if (strncmp(get_authname(type),"password",
|
|
||||||
strlen(get_authname(type))) == 0)
|
|
||||||
loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
|
|
||||||
#endif /* WITH_AIXAUTHENTICATE */
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
#ifndef SKEY
|
|
||||||
(void)packet_read(&plen);
|
|
||||||
#else /* SKEY */
|
|
||||||
int type = packet_read(&plen);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 = NULL, *password = NULL;
|
|
||||||
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);
|
|
||||||
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))
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
#ifdef USE_PAM
|
|
||||||
/* Do PAM auth with password */
|
|
||||||
authenticated = auth_pam_password(pw, password);
|
|
||||||
#else /* USE_PAM */
|
|
||||||
/* Try authentication with the password. */
|
|
||||||
authenticated = auth_password(pw, password);
|
|
||||||
#endif /* USE_PAM */
|
|
||||||
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);
|
|
||||||
|
|
||||||
#ifdef USE_PAM
|
|
||||||
if (authenticated) {
|
|
||||||
if (!do_pam_account(pw->pw_name, client_user)) {
|
|
||||||
if (client_user != NULL) {
|
|
||||||
xfree(client_user);
|
|
||||||
client_user = NULL;
|
|
||||||
}
|
|
||||||
do_fake_authloop1(pw->pw_name);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else /* USE_PAM */
|
|
||||||
if (authenticated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif /* USE_PAM */
|
|
||||||
|
|
||||||
if (client_user != NULL) {
|
|
||||||
xfree(client_user);
|
|
||||||
client_user = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
#ifdef WITH_AIXAUTHENTICATE
|
|
||||||
char *loginmsg;
|
|
||||||
#endif /* WITH_AIXAUTHENTICATE */
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
#ifdef USE_PAM
|
|
||||||
start_pam(pw);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
#ifdef USE_PAM
|
|
||||||
auth_pam_password(pw, "")) {
|
|
||||||
#else /* USE_PAM */
|
|
||||||
auth_password(pw, "")) {
|
|
||||||
#endif /* USE_PAM */
|
|
||||||
/* 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. */
|
|
||||||
#ifdef WITH_AIXAUTHENTICATE
|
|
||||||
loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
|
|
||||||
#endif /* WITH_AIXAUTHENTICATE */
|
|
||||||
packet_start(SSH_SMSG_SUCCESS);
|
|
||||||
packet_send();
|
|
||||||
packet_write_wait();
|
|
||||||
|
|
||||||
/* Perform session preparation. */
|
|
||||||
do_authenticated(pw);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void input_service_request(int type, int plen);
|
|
||||||
void input_userauth_request(int type, int plen);
|
|
||||||
void ssh2_pty_cleanup(void);
|
|
||||||
|
|
||||||
typedef struct Authctxt Authctxt;
|
|
||||||
struct Authctxt {
|
|
||||||
char *user;
|
|
||||||
char *service;
|
|
||||||
struct passwd pw;
|
|
||||||
int valid;
|
|
||||||
};
|
|
||||||
static Authctxt *authctxt = NULL;
|
|
||||||
static int userauth_success = 0;
|
|
||||||
|
|
||||||
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: bad user %s", u);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#ifdef USE_PAM
|
|
||||||
start_pam(pw);
|
|
||||||
#endif
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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 int try = 0;
|
|
||||||
unsigned int len;
|
|
||||||
int c, authenticated = 0;
|
|
||||||
char *user, *service, *method;
|
|
||||||
struct passwd *pw;
|
|
||||||
|
|
||||||
if (++try == AUTH_FAIL_MAX)
|
|
||||||
packet_disconnect("too many failed userauth_requests");
|
|
||||||
|
|
||||||
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 && try == 1) {
|
|
||||||
packet_done();
|
|
||||||
#ifdef USE_PAM
|
|
||||||
/* Do PAM auth with password */
|
|
||||||
authenticated = auth_pam_password(pw, "");
|
|
||||||
#else /* USE_PAM */
|
|
||||||
/* Try authentication with the password. */
|
|
||||||
authenticated = auth_password(pw, "");
|
|
||||||
#endif /* USE_PAM */
|
|
||||||
} else if (strcmp(method, "password") == 0) {
|
|
||||||
char *password;
|
|
||||||
c = packet_get_char();
|
|
||||||
if (c)
|
|
||||||
debug("password change not supported");
|
|
||||||
password = packet_get_string(&len);
|
|
||||||
packet_done();
|
|
||||||
#ifdef USE_PAM
|
|
||||||
/* Do PAM auth with password */
|
|
||||||
authenticated = auth_pam_password(pw, password);
|
|
||||||
#else /* USE_PAM */
|
|
||||||
/* Try authentication with the password. */
|
|
||||||
authenticated = auth_password(pw, password);
|
|
||||||
#endif /* USE_PAM */
|
|
||||||
memset(password, 0, len);
|
|
||||||
xfree(password);
|
|
||||||
} else if (strcmp(method, "publickey") == 0) {
|
|
||||||
/* XXX TODO */
|
|
||||||
char *pkalg, *pkblob, *sig;
|
|
||||||
int have_sig = packet_get_char();
|
|
||||||
pkalg = packet_get_string(&len);
|
|
||||||
pkblob = packet_get_string(&len);
|
|
||||||
if (have_sig) {
|
|
||||||
sig = packet_get_string(&len);
|
|
||||||
/* test for correct signature */
|
|
||||||
packet_done();
|
|
||||||
xfree(sig);
|
|
||||||
} else {
|
|
||||||
packet_done();
|
|
||||||
/* test whether pkalg/pkblob are acceptable */
|
|
||||||
}
|
|
||||||
xfree(pkalg);
|
|
||||||
xfree(pkblob);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* XXX check if other auth methods are needed */
|
|
||||||
if (authenticated) {
|
|
||||||
/* turn off userauth */
|
|
||||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
|
|
||||||
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
|
|
||||||
packet_send();
|
|
||||||
packet_write_wait();
|
|
||||||
log("userauth success for %s", user);
|
|
||||||
/* now we can break out */
|
|
||||||
userauth_success = 1;
|
|
||||||
} else {
|
|
||||||
packet_start(SSH2_MSG_USERAUTH_FAILURE);
|
|
||||||
packet_put_cstring("password");
|
|
||||||
packet_put_char(0); /* partial success */
|
|
||||||
packet_send();
|
|
||||||
packet_write_wait();
|
|
||||||
}
|
|
||||||
xfree(service);
|
|
||||||
xfree(user);
|
|
||||||
xfree(method);
|
|
||||||
}
|
|
||||||
void
|
|
||||||
do_authentication2()
|
|
||||||
{
|
|
||||||
dispatch_init(&protocol_error);
|
|
||||||
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
|
||||||
dispatch_run(DISPATCH_BLOCK, &userauth_success);
|
|
||||||
do_authenticated2();
|
|
||||||
}
|
|
||||||
|
7
auth.h
7
auth.h
@ -7,4 +7,11 @@ void do_authentication2(void);
|
|||||||
struct passwd *
|
struct passwd *
|
||||||
auth_get_user(void);
|
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
|
#endif
|
||||||
|
|
||||||
|
512
auth1.c
Normal file
512
auth1.c
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
* All rights reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
RCSID("$OpenBSD: auth1.c,v 1.1 2000/04/26 21:28:32 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());
|
||||||
|
|
||||||
|
#ifdef WITH_AIXAUTHENTICATE
|
||||||
|
if (strncmp(get_authname(type),"password",
|
||||||
|
strlen(get_authname(type))) == 0)
|
||||||
|
loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
|
||||||
|
#endif /* WITH_AIXAUTHENTICATE */
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
#ifndef SKEY
|
||||||
|
(void)packet_read(&plen);
|
||||||
|
#else /* SKEY */
|
||||||
|
int type = packet_read(&plen);
|
||||||
|
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 = NULL, *password = NULL;
|
||||||
|
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);
|
||||||
|
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))
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifdef USE_PAM
|
||||||
|
/* Do PAM auth with password */
|
||||||
|
authenticated = auth_pam_password(pw, password);
|
||||||
|
#else /* USE_PAM */
|
||||||
|
/* Try authentication with the password. */
|
||||||
|
authenticated = auth_password(pw, password);
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifdef USE_PAM
|
||||||
|
if (authenticated) {
|
||||||
|
if (!do_pam_account(pw->pw_name, client_user)) {
|
||||||
|
if (client_user != NULL) {
|
||||||
|
xfree(client_user);
|
||||||
|
client_user = NULL;
|
||||||
|
}
|
||||||
|
do_fake_authloop1(pw->pw_name);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else /* USE_PAM */
|
||||||
|
if (authenticated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
|
||||||
|
if (client_user != NULL) {
|
||||||
|
xfree(client_user);
|
||||||
|
client_user = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
#ifdef WITH_AIXAUTHENTICATE
|
||||||
|
char *loginmsg;
|
||||||
|
#endif /* WITH_AIXAUTHENTICATE */
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
#ifdef USE_PAM
|
||||||
|
start_pam(pw);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
#ifdef USE_PAM
|
||||||
|
auth_pam_password(pw, "")) {
|
||||||
|
#else /* USE_PAM */
|
||||||
|
auth_password(pw, "")) {
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
/* 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. */
|
||||||
|
#ifdef WITH_AIXAUTHENTICATE
|
||||||
|
loginsuccess(user,get_canonical_hostname(),"ssh",&loginmsg);
|
||||||
|
#endif /* WITH_AIXAUTHENTICATE */
|
||||||
|
packet_start(SSH_SMSG_SUCCESS);
|
||||||
|
packet_send();
|
||||||
|
packet_write_wait();
|
||||||
|
|
||||||
|
/* Perform session preparation. */
|
||||||
|
do_authenticated(pw);
|
||||||
|
}
|
459
auth2.c
Normal file
459
auth2.c
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
/*
|
||||||
|
* 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.3 2000/04/27 15:23:02 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()
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_PAM
|
||||||
|
if (authenticated && !do_pam_account(pw->pw_name, NULL))
|
||||||
|
authenticated = 0;
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
|
||||||
|
/* XXX todo: check if multiple auth methods are needed */
|
||||||
|
if (authenticated == 1) {
|
||||||
|
authmsg = "Accepted";
|
||||||
|
/* 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) {
|
||||||
|
authmsg = "Failed";
|
||||||
|
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();
|
||||||
|
} else {
|
||||||
|
authmsg = "Postponed";
|
||||||
|
}
|
||||||
|
/* Raise logging level */
|
||||||
|
if (authenticated == 1||
|
||||||
|
attempt == AUTH_FAIL_LOG ||
|
||||||
|
strcmp(method, "password") == 0)
|
||||||
|
authlog = log;
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
xfree(service);
|
||||||
|
xfree(user);
|
||||||
|
xfree(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ssh2_auth_none(struct passwd *pw)
|
||||||
|
{
|
||||||
|
packet_done();
|
||||||
|
#ifdef USE_PAM
|
||||||
|
return auth_pam_password(pw, "");
|
||||||
|
#else /* USE_PAM */
|
||||||
|
return auth_password(pw, "");
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
}
|
||||||
|
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 &&
|
||||||
|
#ifdef USE_PAM
|
||||||
|
auth_pam_password(pw, password) == 1)
|
||||||
|
#else /* USE_PAM */
|
||||||
|
auth_password(pw, password) == 1)
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
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.rsa_authentication == 0) {
|
||||||
|
debug("pubkey auth disabled");
|
||||||
|
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 ? */
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#ifdef USE_PAM
|
||||||
|
start_pam(pw);
|
||||||
|
#endif
|
||||||
|
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;
|
||||||
|
}
|
206
authfile.c
206
authfile.c
@ -15,14 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: authfile.c,v 1.11 2000/04/16 02:31:49 damien Exp $");
|
RCSID("$Id: authfile.c,v 1.12 2000/04/29 13:57:10 damien Exp $");
|
||||||
|
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "bufaux.h"
|
#include "bufaux.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "key.h"
|
||||||
|
|
||||||
/* Version identification string for identity files. */
|
/* Version identification string for identity files. */
|
||||||
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||||
@ -35,8 +41,8 @@ RCSID("$Id: authfile.c,v 1.11 2000/04/16 02:31:49 damien Exp $");
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
save_private_key(const char *filename, const char *passphrase,
|
save_private_key_rsa(const char *filename, const char *passphrase,
|
||||||
RSA *key, const char *comment)
|
RSA *key, const char *comment)
|
||||||
{
|
{
|
||||||
Buffer buffer, encrypted;
|
Buffer buffer, encrypted;
|
||||||
char buf[100], *cp;
|
char buf[100], *cp;
|
||||||
@ -128,6 +134,63 @@ save_private_key(const char *filename, const char *passphrase,
|
|||||||
return 1;
|
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
|
* 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
|
* 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
|
int
|
||||||
load_public_key(const char *filename, RSA * pub,
|
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
|
||||||
char **comment_return)
|
|
||||||
{
|
{
|
||||||
int fd, i;
|
int fd, i;
|
||||||
off_t len;
|
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) {
|
if (read(fd, cp, (size_t) len) != (size_t) len) {
|
||||||
debug("Read from key file %.200s failed: %.100s", filename,
|
debug("Read from key file %.200s failed: %.100s", filename,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
buffer_free(&buffer);
|
buffer_free(&buffer);
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
@ -183,9 +245,13 @@ load_public_key(const char *filename, RSA * pub,
|
|||||||
|
|
||||||
/* Read the public key from the buffer. */
|
/* Read the public key from the buffer. */
|
||||||
buffer_get_int(&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);
|
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);
|
buffer_get_bignum(&buffer, pub->e);
|
||||||
if (comment_return)
|
if (comment_return)
|
||||||
*comment_return = buffer_get_string(&buffer, NULL);
|
*comment_return = buffer_get_string(&buffer, NULL);
|
||||||
@ -196,6 +262,20 @@ load_public_key(const char *filename, RSA * pub,
|
|||||||
return 1;
|
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
|
* 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
|
* (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
|
int
|
||||||
load_private_key(const char *filename, const char *passphrase,
|
load_private_key_rsa(int fd, const char *filename,
|
||||||
RSA * prv, char **comment_return)
|
const char *passphrase, RSA * prv, char **comment_return)
|
||||||
{
|
{
|
||||||
int fd, i, check1, check2, cipher_type;
|
int i, check1, check2, cipher_type;
|
||||||
off_t len;
|
off_t len;
|
||||||
Buffer buffer, decrypted;
|
Buffer buffer, decrypted;
|
||||||
char *cp;
|
char *cp;
|
||||||
CipherContext cipher;
|
CipherContext cipher;
|
||||||
BN_CTX *ctx;
|
BN_CTX *ctx;
|
||||||
BIGNUM *aux;
|
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 && getuid() != 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);
|
len = lseek(fd, (off_t) 0, SEEK_END);
|
||||||
lseek(fd, (off_t) 0, SEEK_SET);
|
lseek(fd, (off_t) 0, SEEK_SET);
|
||||||
|
|
||||||
@ -309,7 +371,9 @@ load_private_key(const char *filename, const char *passphrase,
|
|||||||
buffer_free(&decrypted);
|
buffer_free(&decrypted);
|
||||||
fail:
|
fail:
|
||||||
BN_clear_free(prv->n);
|
BN_clear_free(prv->n);
|
||||||
|
prv->n = NULL;
|
||||||
BN_clear_free(prv->e);
|
BN_clear_free(prv->e);
|
||||||
|
prv->e = NULL;
|
||||||
if (comment_return)
|
if (comment_return)
|
||||||
xfree(*comment_return);
|
xfree(*comment_return);
|
||||||
return 0;
|
return 0;
|
||||||
@ -343,3 +407,87 @@ fail:
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
|
||||||
|
{
|
||||||
|
DSA *dsa;
|
||||||
|
BIO *in;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
in = BIO_new(BIO_s_file());
|
||||||
|
if (in == NULL) {
|
||||||
|
error("BIO_new failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fp = fdopen(fd, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
error("fdopen failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BIO_set_fp(in, fp, BIO_NOCLOSE);
|
||||||
|
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
|
||||||
|
if (dsa == NULL) {
|
||||||
|
debug("PEM_read_bio_DSAPrivateKey failed");
|
||||||
|
} else {
|
||||||
|
/* replace k->dsa with loaded key */
|
||||||
|
DSA_free(k->dsa);
|
||||||
|
k->dsa = dsa;
|
||||||
|
}
|
||||||
|
BIO_free(in);
|
||||||
|
fclose(fp);
|
||||||
|
if (comment_return)
|
||||||
|
*comment_return = xstrdup("dsa w/o comment");
|
||||||
|
debug("read DSA private key done");
|
||||||
|
#ifdef DEBUG_DSS
|
||||||
|
DSA_print_fp(stderr, dsa, 8);
|
||||||
|
#endif
|
||||||
|
return dsa != NULL ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
load_private_key(const char *filename, const char *passphrase, Key *key,
|
||||||
|
char **comment_return)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int ret = 0;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* check owner and modes */
|
||||||
|
if (fstat(fd, &st) < 0 ||
|
||||||
|
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||||
|
(st.st_mode & 077) != 0) {
|
||||||
|
close(fd);
|
||||||
|
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||||
|
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
|
||||||
|
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||||
|
error("Bad ownership or mode(0%3.3o) for '%s'.",
|
||||||
|
st.st_mode & 0777, filename);
|
||||||
|
error("It is recommended that your private key files are NOT accessible by others.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
switch (key->type) {
|
||||||
|
case KEY_RSA:
|
||||||
|
if (key->rsa->e != NULL) {
|
||||||
|
BN_clear_free(key->rsa->e);
|
||||||
|
key->rsa->e = NULL;
|
||||||
|
}
|
||||||
|
if (key->rsa->n != NULL) {
|
||||||
|
BN_clear_free(key->rsa->n);
|
||||||
|
key->rsa->n = NULL;
|
||||||
|
}
|
||||||
|
ret = load_private_key_rsa(fd, filename, passphrase,
|
||||||
|
key->rsa, comment_return);
|
||||||
|
break;
|
||||||
|
case KEY_DSA:
|
||||||
|
ret = load_private_key_dsa(fd, passphrase, key, comment_return);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
36
authfile.h
Normal file
36
authfile.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef AUTHFILE_H
|
||||||
|
#define AUTHFILE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Saves the authentication (private) key in a file, encrypting it with
|
||||||
|
* passphrase.
|
||||||
|
* For RSA keys: The identification of the file (lowest 64 bits of n)
|
||||||
|
* will precede the key to provide identification of the key without
|
||||||
|
* needing a passphrase.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
save_private_key(const char *filename, const char *passphrase,
|
||||||
|
Key * private_key, const char *comment);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads the public part of the key file (public key and comment). Returns 0
|
||||||
|
* if an error occurred; zero if the public key was successfully read. The
|
||||||
|
* comment of the key is returned in comment_return if it is non-NULL; the
|
||||||
|
* caller must free the value with xfree.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
load_public_key(const char *filename, Key * pub,
|
||||||
|
char **comment_return);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||||
|
* (file does not exist or is not readable, or passphrase is bad). This
|
||||||
|
* initializes the private key. The comment of the key is returned in
|
||||||
|
* comment_return if it is non-NULL; the caller must free the value with
|
||||||
|
* xfree.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
load_private_key(const char *filename, const char *passphrase,
|
||||||
|
Key * private_key, char **comment_return);
|
||||||
|
|
||||||
|
#endif
|
3
compat.c
3
compat.c
@ -28,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: compat.c,v 1.8 2000/04/16 01:18:42 damien Exp $");
|
RCSID("$Id: compat.c,v 1.9 2000/04/29 13:57:10 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
@ -44,7 +44,6 @@ enable_compat20(void)
|
|||||||
{
|
{
|
||||||
verbose("Enabling compatibility mode for protocol 2.0");
|
verbose("Enabling compatibility mode for protocol 2.0");
|
||||||
compat20 = 1;
|
compat20 = 1;
|
||||||
packet_set_ssh2_format();
|
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
enable_compat13(void)
|
enable_compat13(void)
|
||||||
|
78
dsa.c
78
dsa.c
@ -28,7 +28,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
|
RCSID("$Id: dsa.c,v 1.5 2000/04/26 20:56:29 markus Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
@ -47,13 +47,14 @@ RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
|
|||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include "kex.h"
|
#include "kex.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "uuencode.h"
|
||||||
|
|
||||||
#define INTBLOB_LEN 20
|
#define INTBLOB_LEN 20
|
||||||
#define SIGBLOB_LEN (2*INTBLOB_LEN)
|
#define SIGBLOB_LEN (2*INTBLOB_LEN)
|
||||||
|
|
||||||
Key *
|
Key *
|
||||||
dsa_serverkey_from_blob(
|
dsa_key_from_blob(
|
||||||
char *serverhostkey, int serverhostkeylen)
|
char *blob, int blen)
|
||||||
{
|
{
|
||||||
Buffer b;
|
Buffer b;
|
||||||
char *ktype;
|
char *ktype;
|
||||||
@ -61,14 +62,17 @@ dsa_serverkey_from_blob(
|
|||||||
DSA *dsa;
|
DSA *dsa;
|
||||||
Key *key;
|
Key *key;
|
||||||
|
|
||||||
|
#ifdef DEBUG_DSS
|
||||||
|
dump_base64(blob, blen);
|
||||||
|
#endif
|
||||||
/* fetch & parse DSA/DSS pubkey */
|
/* fetch & parse DSA/DSS pubkey */
|
||||||
key = key_new(KEY_DSA);
|
key = key_new(KEY_DSA);
|
||||||
dsa = key->dsa;
|
dsa = key->dsa;
|
||||||
buffer_init(&b);
|
buffer_init(&b);
|
||||||
buffer_append(&b, serverhostkey, serverhostkeylen);
|
buffer_append(&b, blob, blen);
|
||||||
ktype = buffer_get_string(&b, NULL);
|
ktype = buffer_get_string(&b, NULL);
|
||||||
if (strcmp(KEX_DSS, ktype) != 0) {
|
if (strcmp(KEX_DSS, ktype) != 0) {
|
||||||
error("dsa_serverkey_from_blob: cannot handle type %s", ktype);
|
error("dsa_key_from_blob: cannot handle type %s", ktype);
|
||||||
key_free(key);
|
key_free(key);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -78,7 +82,7 @@ dsa_serverkey_from_blob(
|
|||||||
buffer_get_bignum2(&b, dsa->pub_key);
|
buffer_get_bignum2(&b, dsa->pub_key);
|
||||||
rlen = buffer_len(&b);
|
rlen = buffer_len(&b);
|
||||||
if(rlen != 0)
|
if(rlen != 0)
|
||||||
error("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen);
|
error("dsa_key_from_blob: remaining bytes in key blob %d", rlen);
|
||||||
buffer_free(&b);
|
buffer_free(&b);
|
||||||
|
|
||||||
debug("keytype %s", ktype);
|
debug("keytype %s", ktype);
|
||||||
@ -87,37 +91,8 @@ dsa_serverkey_from_blob(
|
|||||||
#endif
|
#endif
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
DSA *
|
|
||||||
dsa_load_private(char *filename)
|
|
||||||
{
|
|
||||||
DSA *dsa;
|
|
||||||
BIO *in;
|
|
||||||
|
|
||||||
in = BIO_new(BIO_s_file());
|
|
||||||
if (in == NULL)
|
|
||||||
fatal("BIO_new failed");
|
|
||||||
if (BIO_read_filename(in, filename) <= 0)
|
|
||||||
fatal("BIO_read failed %s: %s", filename, strerror(errno));
|
|
||||||
fprintf(stderr, "read DSA private key\n");
|
|
||||||
dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
|
|
||||||
if (dsa == NULL)
|
|
||||||
fatal("PEM_read_bio_DSAPrivateKey failed %s", filename);
|
|
||||||
BIO_free(in);
|
|
||||||
return dsa;
|
|
||||||
}
|
|
||||||
Key *
|
|
||||||
dsa_get_serverkey(char *filename)
|
|
||||||
{
|
|
||||||
Key *k = key_new(KEY_EMPTY);
|
|
||||||
k->type = KEY_DSA;
|
|
||||||
k->dsa = dsa_load_private(filename);
|
|
||||||
#ifdef DEBUG_DSS
|
|
||||||
DSA_print_fp(stderr, dsa, 8);
|
|
||||||
#endif
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
int
|
int
|
||||||
dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
|
dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
|
||||||
{
|
{
|
||||||
Buffer b;
|
Buffer b;
|
||||||
int len;
|
int len;
|
||||||
@ -146,7 +121,7 @@ int
|
|||||||
dsa_sign(
|
dsa_sign(
|
||||||
Key *key,
|
Key *key,
|
||||||
unsigned char **sigp, int *lenp,
|
unsigned char **sigp, int *lenp,
|
||||||
unsigned char *hash, int hlen)
|
unsigned char *data, int datalen)
|
||||||
{
|
{
|
||||||
unsigned char *digest;
|
unsigned char *digest;
|
||||||
unsigned char *ret;
|
unsigned char *ret;
|
||||||
@ -165,10 +140,13 @@ dsa_sign(
|
|||||||
}
|
}
|
||||||
digest = xmalloc(evp_md->md_size);
|
digest = xmalloc(evp_md->md_size);
|
||||||
EVP_DigestInit(&md, evp_md);
|
EVP_DigestInit(&md, evp_md);
|
||||||
EVP_DigestUpdate(&md, hash, hlen);
|
EVP_DigestUpdate(&md, data, datalen);
|
||||||
EVP_DigestFinal(&md, digest, NULL);
|
EVP_DigestFinal(&md, digest, NULL);
|
||||||
|
|
||||||
sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
|
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);
|
rlen = BN_num_bytes(sig->r);
|
||||||
slen = BN_num_bytes(sig->s);
|
slen = BN_num_bytes(sig->s);
|
||||||
@ -212,7 +190,7 @@ int
|
|||||||
dsa_verify(
|
dsa_verify(
|
||||||
Key *key,
|
Key *key,
|
||||||
unsigned char *signature, int signaturelen,
|
unsigned char *signature, int signaturelen,
|
||||||
unsigned char *hash, int hlen)
|
unsigned char *data, int datalen)
|
||||||
{
|
{
|
||||||
Buffer b;
|
Buffer b;
|
||||||
unsigned char *digest;
|
unsigned char *digest;
|
||||||
@ -269,10 +247,10 @@ dsa_verify(
|
|||||||
xfree(sigblob);
|
xfree(sigblob);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sha1 the signed data (== session_id == hash) */
|
/* sha1 the data */
|
||||||
digest = xmalloc(evp_md->md_size);
|
digest = xmalloc(evp_md->md_size);
|
||||||
EVP_DigestInit(&md, evp_md);
|
EVP_DigestInit(&md, evp_md);
|
||||||
EVP_DigestUpdate(&md, hash, hlen);
|
EVP_DigestUpdate(&md, data, datalen);
|
||||||
EVP_DigestFinal(&md, digest, NULL);
|
EVP_DigestFinal(&md, digest, NULL);
|
||||||
|
|
||||||
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
|
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
|
||||||
@ -296,3 +274,21 @@ dsa_verify(
|
|||||||
debug("dsa_verify: signature %s", txt);
|
debug("dsa_verify: signature %s", txt);
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
12
dsa.h
12
dsa.h
@ -1,20 +1,22 @@
|
|||||||
#ifndef DSA_H
|
#ifndef DSA_H
|
||||||
#define DSA_H
|
#define DSA_H
|
||||||
|
|
||||||
Key *dsa_serverkey_from_blob(char *serverhostkey, int serverhostkeylen);
|
Key *dsa_key_from_blob(char *blob, int blen);
|
||||||
Key *dsa_get_serverkey(char *filename);
|
int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
|
||||||
int dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
dsa_sign(
|
dsa_sign(
|
||||||
Key *key,
|
Key *key,
|
||||||
unsigned char **sigp, int *lenp,
|
unsigned char **sigp, int *lenp,
|
||||||
unsigned char *hash, int hlen);
|
unsigned char *data, int datalen);
|
||||||
|
|
||||||
int
|
int
|
||||||
dsa_verify(
|
dsa_verify(
|
||||||
Key *key,
|
Key *key,
|
||||||
unsigned char *signature, int signaturelen,
|
unsigned char *signature, int signaturelen,
|
||||||
unsigned char *hash, int hlen);
|
unsigned char *data, int datalen);
|
||||||
|
|
||||||
|
Key *
|
||||||
|
dsa_generate_key(unsigned int bits);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
23
hostfile.c
23
hostfile.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: hostfile.c,v 1.16 2000/04/14 10:30:31 markus Exp $");
|
RCSID("$OpenBSD: hostfile.c,v 1.17 2000/04/26 20:56:29 markus Exp $");
|
||||||
|
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
@ -39,13 +39,8 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
|
|||||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Get number of bits. */
|
bits = key_read(ret, &cp);
|
||||||
if (*cp < '0' || *cp > '9')
|
if (bits == 0)
|
||||||
return 0; /* Bad bit count... */
|
|
||||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
|
||||||
bits = 10 * bits + *cp - '0';
|
|
||||||
|
|
||||||
if (!key_read(ret, bits, &cp))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Skip trailing whitespace. */
|
/* Skip trailing whitespace. */
|
||||||
@ -182,24 +177,18 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
|
|||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int success = 0;
|
int success = 0;
|
||||||
|
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
return 1;
|
return 1; /* XXX ? */
|
||||||
|
|
||||||
/* Open the file for appending. */
|
|
||||||
f = fopen(filename, "a");
|
f = fopen(filename, "a");
|
||||||
if (!f)
|
if (!f)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fprintf(f, "%s ", host);
|
fprintf(f, "%s ", host);
|
||||||
if (key_write(key, f)) {
|
if (key_write(key, f)) {
|
||||||
fprintf(f, "\n");
|
|
||||||
success = 1;
|
success = 1;
|
||||||
} else {
|
} else {
|
||||||
error("add_host_to_hostfile: saving key failed");
|
error("add_host_to_hostfile: saving key in %s failed", filename);
|
||||||
}
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
/* Close the file. */
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
107
key.c
107
key.c
@ -38,6 +38,10 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "dsa.h"
|
||||||
|
#include "uuencode.h"
|
||||||
|
|
||||||
|
#define SSH_DSS "ssh-dss"
|
||||||
|
|
||||||
Key *
|
Key *
|
||||||
key_new(int type)
|
key_new(int type)
|
||||||
@ -47,6 +51,8 @@ key_new(int type)
|
|||||||
DSA *dsa;
|
DSA *dsa;
|
||||||
k = xmalloc(sizeof(*k));
|
k = xmalloc(sizeof(*k));
|
||||||
k->type = type;
|
k->type = type;
|
||||||
|
k->dsa = NULL;
|
||||||
|
k->rsa = NULL;
|
||||||
switch (k->type) {
|
switch (k->type) {
|
||||||
case KEY_RSA:
|
case KEY_RSA:
|
||||||
rsa = RSA_new();
|
rsa = RSA_new();
|
||||||
@ -63,8 +69,6 @@ key_new(int type)
|
|||||||
k->dsa = dsa;
|
k->dsa = dsa;
|
||||||
break;
|
break;
|
||||||
case KEY_EMPTY:
|
case KEY_EMPTY:
|
||||||
k->dsa = NULL;
|
|
||||||
k->rsa = NULL;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal("key_new: bad key type %d", k->type);
|
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;
|
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal("key_free: bad key type %d", a->type);
|
fatal("key_equal: bad key type %d", a->type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -127,46 +131,37 @@ char *
|
|||||||
key_fingerprint(Key *k)
|
key_fingerprint(Key *k)
|
||||||
{
|
{
|
||||||
static char retval[80];
|
static char retval[80];
|
||||||
unsigned char *buf = NULL;
|
unsigned char *blob = NULL;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int nlen, elen, plen, qlen, glen, publen;
|
int nlen, elen;
|
||||||
|
|
||||||
switch (k->type) {
|
switch (k->type) {
|
||||||
case KEY_RSA:
|
case KEY_RSA:
|
||||||
nlen = BN_num_bytes(k->rsa->n);
|
nlen = BN_num_bytes(k->rsa->n);
|
||||||
elen = BN_num_bytes(k->rsa->e);
|
elen = BN_num_bytes(k->rsa->e);
|
||||||
len = nlen + elen;
|
len = nlen + elen;
|
||||||
buf = xmalloc(len);
|
blob = xmalloc(len);
|
||||||
BN_bn2bin(k->rsa->n, buf);
|
BN_bn2bin(k->rsa->n, blob);
|
||||||
BN_bn2bin(k->rsa->e, buf + nlen);
|
BN_bn2bin(k->rsa->e, blob + nlen);
|
||||||
break;
|
break;
|
||||||
case KEY_DSA:
|
case KEY_DSA:
|
||||||
plen = BN_num_bytes(k->dsa->p);
|
dsa_make_key_blob(k, &blob, &len);
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal("key_fingerprint: bad key type %d", k->type);
|
fatal("key_fingerprint: bad key type %d", k->type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (buf != NULL) {
|
if (blob != NULL) {
|
||||||
unsigned char d[16];
|
unsigned char d[16];
|
||||||
EVP_MD_CTX md;
|
EVP_MD_CTX md;
|
||||||
EVP_DigestInit(&md, EVP_md5());
|
EVP_DigestInit(&md, EVP_md5());
|
||||||
EVP_DigestUpdate(&md, buf, len);
|
EVP_DigestUpdate(&md, blob, len);
|
||||||
EVP_DigestFinal(&md, d, NULL);
|
EVP_DigestFinal(&md, d, NULL);
|
||||||
snprintf(retval, sizeof(retval), FPRINT,
|
snprintf(retval, sizeof(retval), FPRINT,
|
||||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
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]);
|
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||||
memset(buf, 0, len);
|
memset(blob, 0, len);
|
||||||
xfree(buf);
|
xfree(blob);
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -226,13 +221,27 @@ write_bignum(FILE *f, BIGNUM *num)
|
|||||||
free(buf);
|
free(buf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int
|
unsigned int
|
||||||
key_read(Key *ret, unsigned int bits, char **cpp)
|
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) {
|
switch(ret->type) {
|
||||||
case KEY_RSA:
|
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)
|
if (bits == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
*cpp = cp;
|
||||||
/* Get public exponent, public modulus. */
|
/* Get public exponent, public modulus. */
|
||||||
if (!read_bignum(cpp, ret->rsa->e))
|
if (!read_bignum(cpp, ret->rsa->e))
|
||||||
return 0;
|
return 0;
|
||||||
@ -240,22 +249,32 @@ key_read(Key *ret, unsigned int bits, char **cpp)
|
|||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case KEY_DSA:
|
case KEY_DSA:
|
||||||
if (bits != 0)
|
if (strncmp(cp, SSH_DSS " ", 7) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (!read_bignum(cpp, ret->dsa->p))
|
cp += 7;
|
||||||
return 0;
|
len = 2*strlen(cp);
|
||||||
if (!read_bignum(cpp, ret->dsa->q))
|
blob = xmalloc(len);
|
||||||
return 0;
|
n = uudecode(cp, blob, len);
|
||||||
if (!read_bignum(cpp, ret->dsa->g))
|
k = dsa_key_from_blob(blob, n);
|
||||||
return 0;
|
if (k == NULL)
|
||||||
if (!read_bignum(cpp, ret->dsa->pub_key))
|
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;
|
return 0;
|
||||||
|
*cpp = cp + 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal("bad key type: %d", ret->type);
|
fatal("key_read: bad key type: %d", ret->type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return bits;
|
||||||
}
|
}
|
||||||
int
|
int
|
||||||
key_write(Key *key, FILE *f)
|
key_write(Key *key, FILE *f)
|
||||||
@ -274,17 +293,15 @@ key_write(Key *key, FILE *f)
|
|||||||
error("key_write: failed for RSA key");
|
error("key_write: failed for RSA key");
|
||||||
}
|
}
|
||||||
} else if (key->type == KEY_DSA && key->dsa != NULL) {
|
} else if (key->type == KEY_DSA && key->dsa != NULL) {
|
||||||
/* bits == 0 means DSA key */
|
int len, n;
|
||||||
bits = 0;
|
unsigned char *blob, *uu;
|
||||||
fprintf(f, "%u", bits);
|
dsa_make_key_blob(key, &blob, &len);
|
||||||
if (write_bignum(f, key->dsa->p) &&
|
uu = xmalloc(2*len);
|
||||||
write_bignum(f, key->dsa->q) &&
|
n = uuencode(blob, len, uu);
|
||||||
write_bignum(f, key->dsa->g) &&
|
fprintf(f, "%s %s", SSH_DSS, uu);
|
||||||
write_bignum(f, key->dsa->pub_key)) {
|
xfree(blob);
|
||||||
success = 1;
|
xfree(uu);
|
||||||
} else {
|
success = 1;
|
||||||
error("key_write: failed for DSA key");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
3
key.h
3
key.h
@ -18,6 +18,7 @@ void key_free(Key *k);
|
|||||||
int key_equal(Key *a, Key *b);
|
int key_equal(Key *a, Key *b);
|
||||||
char *key_fingerprint(Key *k);
|
char *key_fingerprint(Key *k);
|
||||||
int key_write(Key *key, FILE *f);
|
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
|
#endif
|
||||||
|
96
radix.c
96
radix.c
@ -1,109 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
* radix.c
|
* 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>
|
* Dug Song <dugsong@UMICH.EDU>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
#include "uuencode.h"
|
||||||
|
|
||||||
#ifdef AFS
|
#ifdef AFS
|
||||||
#include <krb.h>
|
#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 char my_u_char;
|
||||||
typedef unsigned int my_u_int32_t;
|
typedef unsigned int my_u_int32_t;
|
||||||
typedef unsigned short my_u_short;
|
typedef unsigned short my_u_short;
|
||||||
|
45
readconf.c
45
readconf.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: readconf.c,v 1.11 2000/04/16 01:18:44 damien Exp $");
|
RCSID("$Id: readconf.c,v 1.12 2000/04/29 13:57:11 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "cipher.h"
|
#include "cipher.h"
|
||||||
@ -104,7 +104,8 @@ typedef enum {
|
|||||||
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
||||||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
||||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol
|
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
|
||||||
|
oGlobalKnownHostsFile2, oUserKnownHostsFile2
|
||||||
} OpCodes;
|
} OpCodes;
|
||||||
|
|
||||||
/* Textual representations of the tokens. */
|
/* Textual representations of the tokens. */
|
||||||
@ -131,6 +132,7 @@ static struct {
|
|||||||
{ "fallbacktorsh", oFallBackToRsh },
|
{ "fallbacktorsh", oFallBackToRsh },
|
||||||
{ "usersh", oUseRsh },
|
{ "usersh", oUseRsh },
|
||||||
{ "identityfile", oIdentityFile },
|
{ "identityfile", oIdentityFile },
|
||||||
|
{ "identityfile2", oIdentityFile2 },
|
||||||
{ "hostname", oHostName },
|
{ "hostname", oHostName },
|
||||||
{ "proxycommand", oProxyCommand },
|
{ "proxycommand", oProxyCommand },
|
||||||
{ "port", oPort },
|
{ "port", oPort },
|
||||||
@ -145,6 +147,8 @@ static struct {
|
|||||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||||
|
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
|
||||||
|
{ "userknownhostsfile2", oUserKnownHostsFile2 },
|
||||||
{ "connectionattempts", oConnectionAttempts },
|
{ "connectionattempts", oConnectionAttempts },
|
||||||
{ "batchmode", oBatchMode },
|
{ "batchmode", oBatchMode },
|
||||||
{ "checkhostip", oCheckHostIP },
|
{ "checkhostip", oCheckHostIP },
|
||||||
@ -368,14 +372,22 @@ parse_flag:
|
|||||||
goto parse_int;
|
goto parse_int;
|
||||||
|
|
||||||
case oIdentityFile:
|
case oIdentityFile:
|
||||||
|
case oIdentityFile2:
|
||||||
cp = strtok(NULL, WHITESPACE);
|
cp = strtok(NULL, WHITESPACE);
|
||||||
if (!cp)
|
if (!cp)
|
||||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||||
if (*activep) {
|
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).",
|
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
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;
|
break;
|
||||||
|
|
||||||
@ -397,6 +409,14 @@ parse_string:
|
|||||||
charptr = &options->user_hostfile;
|
charptr = &options->user_hostfile;
|
||||||
goto parse_string;
|
goto parse_string;
|
||||||
|
|
||||||
|
case oGlobalKnownHostsFile2:
|
||||||
|
charptr = &options->system_hostfile2;
|
||||||
|
goto parse_string;
|
||||||
|
|
||||||
|
case oUserKnownHostsFile2:
|
||||||
|
charptr = &options->user_hostfile2;
|
||||||
|
goto parse_string;
|
||||||
|
|
||||||
case oHostName:
|
case oHostName:
|
||||||
charptr = &options->hostname;
|
charptr = &options->hostname;
|
||||||
goto parse_string;
|
goto parse_string;
|
||||||
@ -642,12 +662,15 @@ initialize_options(Options * options)
|
|||||||
options->ciphers = NULL;
|
options->ciphers = NULL;
|
||||||
options->protocol = SSH_PROTO_UNKNOWN;
|
options->protocol = SSH_PROTO_UNKNOWN;
|
||||||
options->num_identity_files = 0;
|
options->num_identity_files = 0;
|
||||||
|
options->num_identity_files2 = 0;
|
||||||
options->hostname = NULL;
|
options->hostname = NULL;
|
||||||
options->proxy_command = NULL;
|
options->proxy_command = NULL;
|
||||||
options->user = NULL;
|
options->user = NULL;
|
||||||
options->escape_char = -1;
|
options->escape_char = -1;
|
||||||
options->system_hostfile = NULL;
|
options->system_hostfile = NULL;
|
||||||
options->user_hostfile = NULL;
|
options->user_hostfile = NULL;
|
||||||
|
options->system_hostfile2 = NULL;
|
||||||
|
options->user_hostfile2 = NULL;
|
||||||
options->num_local_forwards = 0;
|
options->num_local_forwards = 0;
|
||||||
options->num_remote_forwards = 0;
|
options->num_remote_forwards = 0;
|
||||||
options->log_level = (LogLevel) - 1;
|
options->log_level = (LogLevel) - 1;
|
||||||
@ -715,19 +738,31 @@ fill_default_options(Options * options)
|
|||||||
if (options->cipher == -1)
|
if (options->cipher == -1)
|
||||||
options->cipher = SSH_CIPHER_NOT_SET;
|
options->cipher = SSH_CIPHER_NOT_SET;
|
||||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||||
options->protocol = SSH_PROTO_1;
|
options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED;
|
||||||
if (options->num_identity_files == 0) {
|
if (options->num_identity_files == 0) {
|
||||||
options->identity_files[0] =
|
options->identity_files[0] =
|
||||||
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
|
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
|
||||||
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
|
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
|
||||||
options->num_identity_files = 1;
|
options->num_identity_files = 1;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
if (options->num_identity_files2 == 0) {
|
||||||
|
options->identity_files2[0] =
|
||||||
|
xmalloc(2 + strlen(SSH2_CLIENT_IDENTITY) + 1);
|
||||||
|
sprintf(options->identity_files2[0], "~/%.100s", SSH2_CLIENT_IDENTITY);
|
||||||
|
options->num_identity_files2 = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (options->escape_char == -1)
|
if (options->escape_char == -1)
|
||||||
options->escape_char = '~';
|
options->escape_char = '~';
|
||||||
if (options->system_hostfile == NULL)
|
if (options->system_hostfile == NULL)
|
||||||
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
|
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
|
||||||
if (options->user_hostfile == NULL)
|
if (options->user_hostfile == NULL)
|
||||||
options->user_hostfile = SSH_USER_HOSTFILE;
|
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)
|
if (options->log_level == (LogLevel) - 1)
|
||||||
options->log_level = SYSLOG_LEVEL_INFO;
|
options->log_level = SYSLOG_LEVEL_INFO;
|
||||||
/* options->proxy_command should not be set by default */
|
/* options->proxy_command should not be set by default */
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: readconf.h,v 1.8 2000/04/16 01:18:44 damien Exp $"); */
|
/* RCSID("$Id: readconf.h,v 1.9 2000/04/29 13:57:11 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef READCONF_H
|
#ifndef READCONF_H
|
||||||
#define READCONF_H
|
#define READCONF_H
|
||||||
@ -73,9 +73,13 @@ typedef struct {
|
|||||||
|
|
||||||
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
|
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
|
||||||
char *user_hostfile; /* Path for $HOME/.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_files; /* Number of files for RSA identities. */
|
||||||
|
int num_identity_files2; /* DSA identities. */
|
||||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||||
|
char *identity_files2[SSH_MAX_IDENTITY_FILES];
|
||||||
|
|
||||||
/* Local TCP/IP forward requests. */
|
/* Local TCP/IP forward requests. */
|
||||||
int num_local_forwards;
|
int num_local_forwards;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: servconf.c,v 1.12 2000/04/16 01:18:45 damien Exp $");
|
RCSID("$Id: servconf.c,v 1.13 2000/04/29 13:57:11 damien Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "servconf.h"
|
#include "servconf.h"
|
||||||
@ -143,7 +143,7 @@ fill_default_server_options(ServerOptions *options)
|
|||||||
if (options->use_login == -1)
|
if (options->use_login == -1)
|
||||||
options->use_login = 0;
|
options->use_login = 0;
|
||||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||||
options->protocol = SSH_PROTO_1;
|
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WHITESPACE " \t\r\n"
|
#define WHITESPACE " \t\r\n"
|
||||||
|
@ -733,7 +733,7 @@ server_input_channel_open(int type, int plen)
|
|||||||
rwindow = packet_get_int();
|
rwindow = packet_get_int();
|
||||||
rmaxpack = packet_get_int();
|
rmaxpack = packet_get_int();
|
||||||
|
|
||||||
log("channel_input_open: ctype %s rchan %d win %d max %d",
|
debug("channel_input_open: ctype %s rchan %d win %d max %d",
|
||||||
ctype, rchan, rwindow, rmaxpack);
|
ctype, rchan, rwindow, rmaxpack);
|
||||||
|
|
||||||
if (strcmp(ctype, "session") == 0) {
|
if (strcmp(ctype, "session") == 0) {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: session.c,v 1.5 2000/04/19 09:24:39 markus Exp $");
|
RCSID("$OpenBSD: session.c,v 1.6 2000/04/27 15:23:02 markus Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -1474,6 +1474,5 @@ do_authenticated2(void)
|
|||||||
* authentication.
|
* authentication.
|
||||||
*/
|
*/
|
||||||
alarm(0);
|
alarm(0);
|
||||||
log("do_authenticated2");
|
|
||||||
server_loop2();
|
server_loop2();
|
||||||
}
|
}
|
||||||
|
37
ssh-add.c
37
ssh-add.c
@ -7,13 +7,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ssh-add.c,v 1.16 1999/12/06 00:47:29 damien Exp $");
|
RCSID("$Id: ssh-add.c,v 1.17 2000/04/29 13:57:12 damien Exp $");
|
||||||
|
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "authfd.h"
|
#include "authfd.h"
|
||||||
#include "fingerprint.h"
|
#include "fingerprint.h"
|
||||||
|
#include "key.h"
|
||||||
|
#include "authfile.h"
|
||||||
|
|
||||||
#ifdef HAVE___PROGNAME
|
#ifdef HAVE___PROGNAME
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
@ -24,19 +29,19 @@ const char *__progname = "ssh-add";
|
|||||||
void
|
void
|
||||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||||
{
|
{
|
||||||
RSA *key;
|
Key *public;
|
||||||
char *comment;
|
char *comment;
|
||||||
|
|
||||||
key = RSA_new();
|
public = key_new(KEY_RSA);
|
||||||
if (!load_public_key(filename, key, &comment)) {
|
if (!load_public_key(filename, public, &comment)) {
|
||||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ssh_remove_identity(ac, key))
|
if (ssh_remove_identity(ac, public->rsa))
|
||||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||||
RSA_free(key);
|
key_free(public);
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,20 +96,19 @@ ssh_askpass(char *askpass, char *msg)
|
|||||||
void
|
void
|
||||||
add_file(AuthenticationConnection *ac, const char *filename)
|
add_file(AuthenticationConnection *ac, const char *filename)
|
||||||
{
|
{
|
||||||
RSA *key;
|
Key *public;
|
||||||
RSA *public_key;
|
Key *private;
|
||||||
char *saved_comment, *comment, *askpass = NULL;
|
char *saved_comment, *comment, *askpass = NULL;
|
||||||
char buf[1024], msg[1024];
|
char buf[1024], msg[1024];
|
||||||
int success;
|
int success;
|
||||||
int interactive = isatty(STDIN_FILENO);
|
int interactive = isatty(STDIN_FILENO);
|
||||||
|
|
||||||
key = RSA_new();
|
public = key_new(KEY_RSA);
|
||||||
public_key = RSA_new();
|
if (!load_public_key(filename, public, &saved_comment)) {
|
||||||
if (!load_public_key(filename, public_key, &saved_comment)) {
|
|
||||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RSA_free(public_key);
|
key_free(public);
|
||||||
|
|
||||||
if (!interactive && getenv("DISPLAY")) {
|
if (!interactive && getenv("DISPLAY")) {
|
||||||
if (getenv(SSH_ASKPASS_ENV))
|
if (getenv(SSH_ASKPASS_ENV))
|
||||||
@ -114,7 +118,8 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* At first, try empty passphrase */
|
/* 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) {
|
if (!success) {
|
||||||
printf("Need passphrase for %.200s\n", filename);
|
printf("Need passphrase for %.200s\n", filename);
|
||||||
if (!interactive && askpass == NULL) {
|
if (!interactive && askpass == NULL) {
|
||||||
@ -135,7 +140,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||||||
xfree(saved_comment);
|
xfree(saved_comment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
success = load_private_key(filename, pass, key, &comment);
|
success = load_private_key(filename, pass, private, &comment);
|
||||||
memset(pass, 0, strlen(pass));
|
memset(pass, 0, strlen(pass));
|
||||||
xfree(pass);
|
xfree(pass);
|
||||||
if (success)
|
if (success)
|
||||||
@ -145,11 +150,11 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
|||||||
}
|
}
|
||||||
xfree(saved_comment);
|
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);
|
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||||
RSA_free(key);
|
key_free(private);
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
.\" Created: Sat Apr 22 23:55:14 1995 ylo
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: ssh-keygen.1,v 1.12 2000/04/20 13:27:27 damien Exp $
|
.\" $Id: ssh-keygen.1,v 1.13 2000/04/29 13:57:12 damien Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd September 25, 1999
|
.Dd September 25, 1999
|
||||||
.Dt SSH-KEYGEN 1
|
.Dt SSH-KEYGEN 1
|
||||||
@ -37,6 +37,8 @@
|
|||||||
.Nm ssh-keygen
|
.Nm ssh-keygen
|
||||||
.Fl l
|
.Fl l
|
||||||
.Op Fl f Ar keyfile
|
.Op Fl f Ar keyfile
|
||||||
|
.Nm ssh-keygen
|
||||||
|
.Fl R
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
generates and manages authentication keys for
|
generates and manages authentication keys for
|
||||||
@ -112,6 +114,10 @@ Provides the new comment.
|
|||||||
Provides the new passphrase.
|
Provides the new passphrase.
|
||||||
.It Fl P Ar passphrase
|
.It Fl P Ar passphrase
|
||||||
Provides the (old) 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.
|
||||||
.El
|
.El
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
|
350
ssh-keygen.c
350
ssh-keygen.c
@ -7,20 +7,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ssh-keygen.c,v 1.13 2000/04/16 01:18:46 damien Exp $");
|
RCSID("$Id: ssh-keygen.c,v 1.14 2000/04/29 13:57:12 damien Exp $");
|
||||||
|
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
|
||||||
#include "rsa.h"
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "fingerprint.h"
|
#include "fingerprint.h"
|
||||||
|
#include "key.h"
|
||||||
|
#include "rsa.h"
|
||||||
|
#include "dsa.h"
|
||||||
|
#include "authfile.h"
|
||||||
|
#include "uuencode.h"
|
||||||
|
|
||||||
/* Generated private key. */
|
/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
|
||||||
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. */
|
|
||||||
int bits = 1024;
|
int bits = 1024;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -53,6 +56,12 @@ char *identity_new_passphrase = NULL;
|
|||||||
/* This is set to the new comment if given on the command line. */
|
/* This is set to the new comment if given on the command line. */
|
||||||
char *identity_comment = NULL;
|
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 */
|
/* argv0 */
|
||||||
#ifdef HAVE___PROGNAME
|
#ifdef HAVE___PROGNAME
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
@ -60,6 +69,8 @@ extern char *__progname;
|
|||||||
const char *__progname = "ssh-keygen";
|
const char *__progname = "ssh-keygen";
|
||||||
#endif /* HAVE___PROGNAME */
|
#endif /* HAVE___PROGNAME */
|
||||||
|
|
||||||
|
char hostname[MAXHOSTNAMELEN];
|
||||||
|
|
||||||
void
|
void
|
||||||
ask_filename(struct passwd *pw, const char *prompt)
|
ask_filename(struct passwd *pw, const char *prompt)
|
||||||
{
|
{
|
||||||
@ -77,12 +88,140 @@ ask_filename(struct passwd *pw, const char *prompt)
|
|||||||
have_identity = 1;
|
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;
|
||||||
|
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 (strncmp(line, "----", 4) == 0 ||
|
||||||
|
strstr(line, ": ") != NULL) {
|
||||||
|
fprintf(stderr, "ignore: %s", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(p = strchr(line, '\n'))) {
|
||||||
|
fprintf(stderr, "input line too long.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
*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
|
void
|
||||||
do_fingerprint(struct passwd *pw)
|
do_fingerprint(struct passwd *pw)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
BIGNUM *e, *n;
|
BIGNUM *e, *n;
|
||||||
RSA *public_key;
|
Key *public;
|
||||||
char *comment = NULL, *cp, *ep, line[16*1024];
|
char *comment = NULL, *cp, *ep, line[16*1024];
|
||||||
int i, skip = 0, num = 1, invalid = 1;
|
int i, skip = 0, num = 1, invalid = 1;
|
||||||
unsigned int ignore;
|
unsigned int ignore;
|
||||||
@ -94,17 +233,16 @@ do_fingerprint(struct passwd *pw)
|
|||||||
perror(identity_file);
|
perror(identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
public = key_new(KEY_RSA);
|
||||||
public_key = RSA_new();
|
if (load_public_key(identity_file, public, &comment)) {
|
||||||
if (load_public_key(identity_file, public_key, &comment)) {
|
printf("%d %s %s\n", BN_num_bits(public->rsa->n),
|
||||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
key_fingerprint(public), comment);
|
||||||
fingerprint(public_key->e, public_key->n),
|
key_free(public);
|
||||||
comment);
|
|
||||||
RSA_free(public_key);
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
RSA_free(public_key);
|
key_free(public);
|
||||||
|
|
||||||
|
/* XXX */
|
||||||
f = fopen(identity_file, "r");
|
f = fopen(identity_file, "r");
|
||||||
if (f != NULL) {
|
if (f != NULL) {
|
||||||
n = BN_new();
|
n = BN_new();
|
||||||
@ -172,7 +310,9 @@ do_change_passphrase(struct passwd *pw)
|
|||||||
char *comment;
|
char *comment;
|
||||||
char *old_passphrase, *passphrase1, *passphrase2;
|
char *old_passphrase, *passphrase1, *passphrase2;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
RSA *private_key;
|
Key *private;
|
||||||
|
Key *public;
|
||||||
|
int type = dsa_mode ? KEY_DSA : KEY_RSA;
|
||||||
|
|
||||||
if (!have_identity)
|
if (!have_identity)
|
||||||
ask_filename(pw, "Enter file in which the key is");
|
ask_filename(pw, "Enter file in which the key is");
|
||||||
@ -180,22 +320,26 @@ do_change_passphrase(struct passwd *pw)
|
|||||||
perror(identity_file);
|
perror(identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
public_key = RSA_new();
|
|
||||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
if (type == KEY_RSA) {
|
||||||
printf("%s is not a valid key file.\n", identity_file);
|
/* XXX this works currently only for RSA */
|
||||||
exit(1);
|
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. */
|
/* Try to load the file with empty passphrase. */
|
||||||
private_key = RSA_new();
|
private = key_new(type);
|
||||||
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
if (!load_private_key(identity_file, "", private, &comment)) {
|
||||||
if (identity_passphrase)
|
if (identity_passphrase)
|
||||||
old_passphrase = xstrdup(identity_passphrase);
|
old_passphrase = xstrdup(identity_passphrase);
|
||||||
else
|
else
|
||||||
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
|
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));
|
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||||
xfree(old_passphrase);
|
xfree(old_passphrase);
|
||||||
printf("Bad passphrase.\n");
|
printf("Bad passphrase.\n");
|
||||||
@ -230,19 +374,19 @@ do_change_passphrase(struct passwd *pw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Save the file using the new passphrase. */
|
/* 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",
|
printf("Saving the key failed: %s: %s.\n",
|
||||||
identity_file, strerror(errno));
|
identity_file, strerror(errno));
|
||||||
memset(passphrase1, 0, strlen(passphrase1));
|
memset(passphrase1, 0, strlen(passphrase1));
|
||||||
xfree(passphrase1);
|
xfree(passphrase1);
|
||||||
RSA_free(private_key);
|
key_free(private);
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Destroy the passphrase and the copy of the key in memory. */
|
/* Destroy the passphrase and the copy of the key in memory. */
|
||||||
memset(passphrase1, 0, strlen(passphrase1));
|
memset(passphrase1, 0, strlen(passphrase1));
|
||||||
xfree(passphrase1);
|
xfree(passphrase1);
|
||||||
RSA_free(private_key); /* Destroys contents */
|
key_free(private); /* Destroys contents */
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
|
|
||||||
printf("Your identification has been saved with the new passphrase.\n");
|
printf("Your identification has been saved with the new passphrase.\n");
|
||||||
@ -256,11 +400,11 @@ void
|
|||||||
do_change_comment(struct passwd *pw)
|
do_change_comment(struct passwd *pw)
|
||||||
{
|
{
|
||||||
char new_comment[1024], *comment;
|
char new_comment[1024], *comment;
|
||||||
RSA *private_key;
|
Key *private;
|
||||||
|
Key *public;
|
||||||
char *passphrase;
|
char *passphrase;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char *tmpbuf;
|
|
||||||
|
|
||||||
if (!have_identity)
|
if (!have_identity)
|
||||||
ask_filename(pw, "Enter file in which the key is");
|
ask_filename(pw, "Enter file in which the key is");
|
||||||
@ -272,14 +416,14 @@ do_change_comment(struct passwd *pw)
|
|||||||
* Try to load the public key from the file the verify that it is
|
* Try to load the public key from the file the verify that it is
|
||||||
* readable and of the proper format.
|
* readable and of the proper format.
|
||||||
*/
|
*/
|
||||||
public_key = RSA_new();
|
public = key_new(KEY_RSA);
|
||||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
if (!load_public_key(identity_file, public, NULL)) {
|
||||||
printf("%s is not a valid key file.\n", identity_file);
|
printf("%s is not a valid key file.\n", identity_file);
|
||||||
exit(1);
|
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("");
|
passphrase = xstrdup("");
|
||||||
else {
|
else {
|
||||||
if (identity_passphrase)
|
if (identity_passphrase)
|
||||||
@ -289,7 +433,7 @@ do_change_comment(struct passwd *pw)
|
|||||||
else
|
else
|
||||||
passphrase = read_passphrase("Enter passphrase: ", 1);
|
passphrase = read_passphrase("Enter passphrase: ", 1);
|
||||||
/* Try to load using the passphrase. */
|
/* 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));
|
memset(passphrase, 0, strlen(passphrase));
|
||||||
xfree(passphrase);
|
xfree(passphrase);
|
||||||
printf("Bad passphrase.\n");
|
printf("Bad passphrase.\n");
|
||||||
@ -305,7 +449,7 @@ do_change_comment(struct passwd *pw)
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
|
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
|
||||||
memset(passphrase, 0, strlen(passphrase));
|
memset(passphrase, 0, strlen(passphrase));
|
||||||
RSA_free(private_key);
|
key_free(private);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (strchr(new_comment, '\n'))
|
if (strchr(new_comment, '\n'))
|
||||||
@ -313,18 +457,18 @@ do_change_comment(struct passwd *pw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Save the file using the new passphrase. */
|
/* 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",
|
printf("Saving the key failed: %s: %s.\n",
|
||||||
identity_file, strerror(errno));
|
identity_file, strerror(errno));
|
||||||
memset(passphrase, 0, strlen(passphrase));
|
memset(passphrase, 0, strlen(passphrase));
|
||||||
xfree(passphrase);
|
xfree(passphrase);
|
||||||
RSA_free(private_key);
|
key_free(private);
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memset(passphrase, 0, strlen(passphrase));
|
memset(passphrase, 0, strlen(passphrase));
|
||||||
xfree(passphrase);
|
xfree(passphrase);
|
||||||
RSA_free(private_key);
|
key_free(private);
|
||||||
|
|
||||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||||
f = fopen(identity_file, "w");
|
f = fopen(identity_file, "w");
|
||||||
@ -332,13 +476,10 @@ do_change_comment(struct passwd *pw)
|
|||||||
printf("Could not save your public key in %s\n", identity_file);
|
printf("Could not save your public key in %s\n", identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
if (!key_write(public, f))
|
||||||
tmpbuf = BN_bn2dec(public_key->e);
|
fprintf(stderr, "write key failed");
|
||||||
fprintf(f, "%s ", tmpbuf);
|
key_free(public);
|
||||||
free(tmpbuf);
|
fprintf(f, " %s\n", new_comment);
|
||||||
tmpbuf = BN_bn2dec(public_key->n);
|
|
||||||
fprintf(f, "%s %s\n", tmpbuf, new_comment);
|
|
||||||
free(tmpbuf);
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
xfree(comment);
|
xfree(comment);
|
||||||
@ -351,7 +492,7 @@ void
|
|||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
printf("ssh-keygen version %s\n", SSH_VERSION);
|
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 [-b bits] [-p] [-c] [-l] [-x] [-X] [-y] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,29 +504,28 @@ main(int ac, char **av)
|
|||||||
{
|
{
|
||||||
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
|
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
char *tmpbuf;
|
|
||||||
int opt;
|
int opt;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char hostname[MAXHOSTNAMELEN];
|
Key *private;
|
||||||
|
Key *public;
|
||||||
extern int optind;
|
extern int optind;
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
|
|
||||||
/* check if RSA support exists */
|
OpenSSL_add_all_algorithms();
|
||||||
if (rsa_alive() == 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
|
||||||
__progname);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
/* we need this for the home * directory. */
|
/* we need this for the home * directory. */
|
||||||
pw = getpwuid(getuid());
|
pw = getpwuid(getuid());
|
||||||
if (!pw) {
|
if (!pw) {
|
||||||
printf("You don't exist, go away!\n");
|
printf("You don't exist, go away!\n");
|
||||||
exit(1);
|
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) {
|
switch (opt) {
|
||||||
case 'b':
|
case 'b':
|
||||||
bits = atoi(optarg);
|
bits = atoi(optarg);
|
||||||
@ -428,6 +568,29 @@ main(int ac, char **av)
|
|||||||
quiet = 1;
|
quiet = 1;
|
||||||
break;
|
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 '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
@ -441,22 +604,44 @@ main(int ac, char **av)
|
|||||||
printf("Can only have one of -p and -c.\n");
|
printf("Can only have one of -p and -c.\n");
|
||||||
usage();
|
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)
|
if (print_fingerprint)
|
||||||
do_fingerprint(pw);
|
do_fingerprint(pw);
|
||||||
if (change_passphrase)
|
if (change_passphrase)
|
||||||
do_change_passphrase(pw);
|
do_change_passphrase(pw);
|
||||||
if (change_comment)
|
if (change_comment)
|
||||||
do_change_comment(pw);
|
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();
|
arc4random_stir();
|
||||||
|
|
||||||
if (quiet)
|
if (dsa_mode != 0) {
|
||||||
rsa_set_verbose(0);
|
if (!quiet)
|
||||||
|
printf("Generating DSA parameter and key.\n");
|
||||||
/* Generate the rsa key pair. */
|
public = private = dsa_generate_key(bits);
|
||||||
private_key = RSA_new();
|
if (private == NULL) {
|
||||||
public_key = RSA_new();
|
fprintf(stderr, "dsa_generate_keys failed");
|
||||||
rsa_generate_key(private_key, public_key, bits);
|
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)
|
if (!have_identity)
|
||||||
ask_filename(pw, "Enter file in which to save the key");
|
ask_filename(pw, "Enter file in which to save the key");
|
||||||
@ -509,17 +694,13 @@ passphrase_again:
|
|||||||
strlcpy(comment, identity_comment, sizeof(comment));
|
strlcpy(comment, identity_comment, sizeof(comment));
|
||||||
} else {
|
} else {
|
||||||
/* Create default commend field for the passphrase. */
|
/* Create default commend field for the passphrase. */
|
||||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
|
||||||
perror("gethostname");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
|
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the key with the given passphrase and comment. */
|
/* 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",
|
printf("Saving the key failed: %s: %s.\n",
|
||||||
identity_file, strerror(errno));
|
identity_file, strerror(errno));
|
||||||
memset(passphrase1, 0, strlen(passphrase1));
|
memset(passphrase1, 0, strlen(passphrase1));
|
||||||
xfree(passphrase1);
|
xfree(passphrase1);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -529,7 +710,9 @@ passphrase_again:
|
|||||||
xfree(passphrase1);
|
xfree(passphrase1);
|
||||||
|
|
||||||
/* Clear the private key and the random number generator. */
|
/* Clear the private key and the random number generator. */
|
||||||
RSA_free(private_key);
|
if (private != public) {
|
||||||
|
key_free(private);
|
||||||
|
}
|
||||||
arc4random_stir();
|
arc4random_stir();
|
||||||
|
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
@ -541,21 +724,18 @@ passphrase_again:
|
|||||||
printf("Could not save your public key in %s\n", identity_file);
|
printf("Could not save your public key in %s\n", identity_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
if (!key_write(public, f))
|
||||||
tmpbuf = BN_bn2dec(public_key->e);
|
fprintf(stderr, "write key failed");
|
||||||
fprintf(f, "%s ", tmpbuf);
|
fprintf(f, " %s\n", comment);
|
||||||
free(tmpbuf);
|
|
||||||
tmpbuf = BN_bn2dec(public_key->n);
|
|
||||||
fprintf(f, "%s %s\n", tmpbuf, comment);
|
|
||||||
free(tmpbuf);
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
if (!quiet) {
|
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("The key fingerprint is:\n");
|
||||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
printf("%s %s\n", key_fingerprint(public), comment);
|
||||||
fingerprint(public_key->e, public_key->n),
|
|
||||||
comment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key_free(public);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
65
ssh.c
65
ssh.c
@ -11,7 +11,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$Id: ssh.c,v 1.26 2000/04/16 01:18:46 damien Exp $");
|
RCSID("$Id: ssh.c,v 1.27 2000/04/29 13:57:12 damien Exp $");
|
||||||
|
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/dsa.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
@ -24,6 +28,8 @@ RCSID("$Id: ssh.c,v 1.26 2000/04/16 01:18:46 damien Exp $");
|
|||||||
#include "ssh2.h"
|
#include "ssh2.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
|
#include "key.h"
|
||||||
|
#include "authfile.h"
|
||||||
|
|
||||||
#ifdef HAVE___PROGNAME
|
#ifdef HAVE___PROGNAME
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
@ -358,10 +364,16 @@ main(int ac, char **av)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
options.cipher = cipher_number(optarg);
|
if (ciphers_valid(optarg)) {
|
||||||
if (options.cipher == -1) {
|
/* SSH2 only */
|
||||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
options.ciphers = xstrdup(optarg);
|
||||||
exit(1);
|
} else {
|
||||||
|
/* SSH1 only */
|
||||||
|
options.cipher = cipher_number(optarg);
|
||||||
|
if (options.cipher == -1) {
|
||||||
|
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
@ -417,16 +429,11 @@ main(int ac, char **av)
|
|||||||
if (!host)
|
if (!host)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
/* Initialize the command to execute on remote host. */
|
/* Initialize the command to execute on remote host. */
|
||||||
buffer_init(&command);
|
buffer_init(&command);
|
||||||
|
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save the command to execute on the remote host in a buffer. There
|
* Save the command to execute on the remote host in a buffer. There
|
||||||
* is no limit on the length of the command, except by the maximum
|
* is no limit on the length of the command, except by the maximum
|
||||||
@ -496,6 +503,20 @@ main(int ac, char **av)
|
|||||||
/* reinit */
|
/* reinit */
|
||||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
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)
|
if (options.user == NULL)
|
||||||
options.user = xstrdup(pw->pw_name);
|
options.user = xstrdup(pw->pw_name);
|
||||||
|
|
||||||
@ -562,9 +583,12 @@ main(int ac, char **av)
|
|||||||
* authentication. This must be done before releasing extra
|
* authentication. This must be done before releasing extra
|
||||||
* privileges, because the file is only readable by root.
|
* 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();
|
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;
|
host_private_key_loaded = 1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -610,15 +634,22 @@ main(int ac, char **av)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* Expand ~ in options.identity_files. */
|
/* Expand ~ in options.identity_files. */
|
||||||
|
/* XXX mem-leaks */
|
||||||
for (i = 0; i < options.num_identity_files; i++)
|
for (i = 0; i < options.num_identity_files; i++)
|
||||||
options.identity_files[i] =
|
options.identity_files[i] =
|
||||||
tilde_expand_filename(options.identity_files[i], original_real_uid);
|
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. */
|
/* Expand ~ in known host file names. */
|
||||||
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
|
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
|
||||||
original_real_uid);
|
original_real_uid);
|
||||||
options.user_hostfile = tilde_expand_filename(options.user_hostfile,
|
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. */
|
/* Log into the remote system. This never returns if the login fails. */
|
||||||
ssh_login(host_private_key_loaded, host_private_key,
|
ssh_login(host_private_key_loaded, host_private_key,
|
||||||
|
37
ssh.h
37
ssh.h
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* RCSID("$Id: ssh.h,v 1.34 2000/04/20 13:12:59 damien Exp $"); */
|
/* RCSID("$Id: ssh.h,v 1.35 2000/04/29 13:57:12 damien Exp $"); */
|
||||||
|
|
||||||
#ifndef SSH_H
|
#ifndef SSH_H
|
||||||
#define SSH_H
|
#define SSH_H
|
||||||
@ -88,6 +88,7 @@
|
|||||||
* world-readable.
|
* world-readable.
|
||||||
*/
|
*/
|
||||||
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
|
#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
|
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
|
||||||
@ -96,7 +97,7 @@
|
|||||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
|
||||||
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
|
||||||
#define DSA_KEY_FILE ETCDIR "/ssh_dsa_key"
|
#define DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
|
||||||
|
|
||||||
#ifndef SSH_PROGRAM
|
#ifndef SSH_PROGRAM
|
||||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||||
@ -128,6 +129,7 @@
|
|||||||
* contain anything particularly secret.
|
* contain anything particularly secret.
|
||||||
*/
|
*/
|
||||||
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
#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
|
* Name of the default file containing client-side authentication key. This
|
||||||
@ -152,6 +154,7 @@
|
|||||||
* running as root.)
|
* running as root.)
|
||||||
*/
|
*/
|
||||||
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
#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
|
* Per-user and system-wide ssh "rc" files. These files are executed with
|
||||||
@ -407,36 +410,6 @@ int auth_rsa_challenge_dialog(RSA *pk);
|
|||||||
*/
|
*/
|
||||||
char *read_passphrase(const char *prompt, int from_stdin);
|
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. -----------------------*/
|
/*------------ Definitions for logging. -----------------------*/
|
||||||
|
|
||||||
|
1358
sshconnect.c
1358
sshconnect.c
File diff suppressed because it is too large
Load Diff
16
sshconnect.h
Normal file
16
sshconnect.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef SSHCONNECT_H
|
||||||
|
#define SSHCONNECT_H
|
||||||
|
|
||||||
|
void
|
||||||
|
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||||
|
const char *user_hostfile, const char *system_hostfile);
|
||||||
|
|
||||||
|
void ssh_kex(char *host, struct sockaddr *hostaddr);
|
||||||
|
void
|
||||||
|
ssh_userauth(const char* local_user, const char* server_user, char *host,
|
||||||
|
int host_key_valid, RSA *own_host_key);
|
||||||
|
|
||||||
|
void ssh_kex2(char *host, struct sockaddr *hostaddr);
|
||||||
|
void ssh_userauth2(const char *server_user, char *host);
|
||||||
|
|
||||||
|
#endif
|
1020
sshconnect1.c
Normal file
1020
sshconnect1.c
Normal file
File diff suppressed because it is too large
Load Diff
449
sshconnect2.c
Normal file
449
sshconnect2.c
Normal file
@ -0,0 +1,449 @@
|
|||||||
|
/*
|
||||||
|
* 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.4 2000/04/27 17:54:01 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_ARCFOUR ||
|
||||||
|
options.cipher == SSH_CIPHER_3DES_CBC ||
|
||||||
|
options.cipher == SSH_CIPHER_CAST128_CBC ||
|
||||||
|
options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
|
||||||
|
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||||
|
myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
char prompt[80];
|
||||||
|
char *password;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, 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);
|
||||||
|
|
||||||
|
/* generate signature */
|
||||||
|
dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
|
||||||
|
key_free(k);
|
||||||
|
#ifdef DEBUG_DSS
|
||||||
|
buffer_dump(&b);
|
||||||
|
#endif
|
||||||
|
/* 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 ?? */
|
||||||
|
log("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.rsa_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");
|
||||||
|
}
|
221
sshd.c
221
sshd.c
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
|
RCSID("$OpenBSD: sshd.c,v 1.111 2000/04/27 08:01:28 markus Exp $");
|
||||||
|
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
@ -40,6 +40,7 @@ RCSID("$OpenBSD: sshd.c,v 1.107 2000/04/19 07:05:50 deraadt Exp $");
|
|||||||
|
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
#include "myproposal.h"
|
#include "myproposal.h"
|
||||||
|
#include "authfile.h"
|
||||||
|
|
||||||
#ifdef LIBWRAP
|
#ifdef LIBWRAP
|
||||||
#include <tcpd.h>
|
#include <tcpd.h>
|
||||||
@ -112,8 +113,9 @@ char *server_version_string = NULL;
|
|||||||
* not very useful. Currently, memory locking is not implemented.
|
* not very useful. Currently, memory locking is not implemented.
|
||||||
*/
|
*/
|
||||||
struct {
|
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. */
|
RSA *host_key; /* Private part of host key. */
|
||||||
|
Key *dsa_host_key; /* Private DSA host key. */
|
||||||
} sensitive_data;
|
} sensitive_data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -132,6 +134,10 @@ RSA *public_key;
|
|||||||
/* session identifier, used by RSA-auth */
|
/* session identifier, used by RSA-auth */
|
||||||
unsigned char session_id[16];
|
unsigned char session_id[16];
|
||||||
|
|
||||||
|
/* same for ssh2 */
|
||||||
|
unsigned char *session_id2 = NULL;
|
||||||
|
int session_id2_len = 0;
|
||||||
|
|
||||||
/* Prototypes for various functions defined later in this file. */
|
/* Prototypes for various functions defined later in this file. */
|
||||||
void do_ssh1_kex();
|
void do_ssh1_kex();
|
||||||
void do_ssh2_kex();
|
void do_ssh2_kex();
|
||||||
@ -224,6 +230,7 @@ grace_alarm_handler(int sig)
|
|||||||
* Thus there should be no concurrency control/asynchronous execution
|
* Thus there should be no concurrency control/asynchronous execution
|
||||||
* problems.
|
* problems.
|
||||||
*/
|
*/
|
||||||
|
/* XXX do we really want this work to be done in a signal handler ? -m */
|
||||||
void
|
void
|
||||||
key_regeneration_alarm(int sig)
|
key_regeneration_alarm(int sig)
|
||||||
{
|
{
|
||||||
@ -344,6 +351,13 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
mismatch = 0;
|
mismatch = 0;
|
||||||
switch(remote_major) {
|
switch(remote_major) {
|
||||||
case 1:
|
case 1:
|
||||||
|
if (remote_minor == 99) {
|
||||||
|
if (options.protocol & SSH_PROTO_2)
|
||||||
|
enable_compat20();
|
||||||
|
else
|
||||||
|
mismatch = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!(options.protocol & SSH_PROTO_1)) {
|
if (!(options.protocol & SSH_PROTO_1)) {
|
||||||
mismatch = 1;
|
mismatch = 1;
|
||||||
break;
|
break;
|
||||||
@ -355,12 +369,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
/* note that this disables agent-forwarding */
|
/* note that this disables agent-forwarding */
|
||||||
enable_compat13();
|
enable_compat13();
|
||||||
}
|
}
|
||||||
if (remote_minor == 99) {
|
|
||||||
if (options.protocol & SSH_PROTO_2)
|
|
||||||
enable_compat20();
|
|
||||||
else
|
|
||||||
mismatch = 1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (options.protocol & SSH_PROTO_2) {
|
if (options.protocol & SSH_PROTO_2) {
|
||||||
@ -386,6 +394,20 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
|||||||
server_version_string, client_version_string);
|
server_version_string, client_version_string);
|
||||||
fatal_cleanup();
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -399,12 +421,11 @@ main(int ac, char **av)
|
|||||||
int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
|
int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
socklen_t fromlen;
|
socklen_t fromlen;
|
||||||
int silentrsa = 0;
|
int silent = 0;
|
||||||
fd_set *fdset;
|
fd_set *fdset;
|
||||||
struct sockaddr_storage from;
|
struct sockaddr_storage from;
|
||||||
const char *remote_ip;
|
const char *remote_ip;
|
||||||
int remote_port;
|
int remote_port;
|
||||||
char *comment;
|
|
||||||
FILE *f;
|
FILE *f;
|
||||||
struct linger linger;
|
struct linger linger;
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai;
|
||||||
@ -441,7 +462,7 @@ main(int ac, char **av)
|
|||||||
inetd_flag = 1;
|
inetd_flag = 1;
|
||||||
break;
|
break;
|
||||||
case 'Q':
|
case 'Q':
|
||||||
silentrsa = 1;
|
silent = 1;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
options.log_level = SYSLOG_LEVEL_QUIET;
|
options.log_level = SYSLOG_LEVEL_QUIET;
|
||||||
@ -497,27 +518,14 @@ main(int ac, char **av)
|
|||||||
log_init(av0,
|
log_init(av0,
|
||||||
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
|
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
|
||||||
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
|
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 configuration options from the configuration file. */
|
||||||
read_server_config(&options, config_file_name);
|
read_server_config(&options, config_file_name);
|
||||||
|
|
||||||
/* Fill in default values for those options not explicitly set. */
|
/* Fill in default values for those options not explicitly set. */
|
||||||
fill_default_server_options(&options);
|
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. */
|
/* Check that there are no remaining arguments. */
|
||||||
if (optind < ac) {
|
if (optind < ac) {
|
||||||
fprintf(stderr, "Extra argument %s.\n", av[optind]);
|
fprintf(stderr, "Extra argument %s.\n", av[optind]);
|
||||||
@ -526,26 +534,79 @@ main(int ac, char **av)
|
|||||||
|
|
||||||
debug("sshd version %.100s", SSH_VERSION);
|
debug("sshd version %.100s", SSH_VERSION);
|
||||||
|
|
||||||
sensitive_data.host_key = RSA_new();
|
sensitive_data.dsa_host_key = NULL;
|
||||||
errno = 0;
|
sensitive_data.host_key = NULL;
|
||||||
/* Load the host key. It must have empty passphrase. */
|
|
||||||
if (!load_private_key(options.host_key_file, "",
|
/* check if RSA support exists */
|
||||||
sensitive_data.host_key, &comment)) {
|
if ((options.protocol & SSH_PROTO_1) &&
|
||||||
error("Could not load host key: %.200s: %.100s",
|
rsa_alive() == 0) {
|
||||||
options.host_key_file, strerror(errno));
|
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.dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) {
|
||||||
|
error("Could not load DSA host key: %.200s", options.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);
|
exit(1);
|
||||||
}
|
}
|
||||||
xfree(comment);
|
|
||||||
|
|
||||||
/* Initialize the log (it is reinitialized below in case we
|
/* Check certain values for sanity. */
|
||||||
forked). */
|
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)
|
if (debug_flag && !inetd_flag)
|
||||||
log_stderr = 1;
|
log_stderr = 1;
|
||||||
log_init(av0, options.log_level, options.log_facility, log_stderr);
|
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
|
* If not in debugging mode, and not started from inetd, disconnect
|
||||||
original process exits. */
|
* from the controlling terminal, and fork. The original process
|
||||||
|
* exits.
|
||||||
|
*/
|
||||||
if (!debug_flag && !inetd_flag) {
|
if (!debug_flag && !inetd_flag) {
|
||||||
#ifdef TIOCNOTTY
|
#ifdef TIOCNOTTY
|
||||||
int fd;
|
int fd;
|
||||||
@ -565,18 +626,6 @@ main(int ac, char **av)
|
|||||||
/* Reinitialize the log (because of the fork above). */
|
/* Reinitialize the log (because of the fork above). */
|
||||||
log_init(av0, options.log_level, options.log_facility, log_stderr);
|
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. */
|
/* Do not display messages to stdout in RSA code. */
|
||||||
rsa_set_verbose(0);
|
rsa_set_verbose(0);
|
||||||
|
|
||||||
@ -594,20 +643,22 @@ main(int ac, char **av)
|
|||||||
s2 = dup(s1);
|
s2 = dup(s1);
|
||||||
sock_in = dup(0);
|
sock_in = dup(0);
|
||||||
sock_out = dup(1);
|
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
|
* We intentionally do not close the descriptors 0, 1, and 2
|
||||||
if ttyfd happens to be one of those. */
|
* 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);
|
debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
|
||||||
|
|
||||||
public_key = RSA_new();
|
if (options.protocol & SSH_PROTO_1) {
|
||||||
sensitive_data.private_key = RSA_new();
|
public_key = RSA_new();
|
||||||
|
sensitive_data.private_key = RSA_new();
|
||||||
/* XXX check options.protocol */
|
log("Generating %d bit RSA key.", options.server_key_bits);
|
||||||
log("Generating %d bit RSA key.", options.server_key_bits);
|
rsa_generate_key(sensitive_data.private_key, public_key,
|
||||||
rsa_generate_key(sensitive_data.private_key, public_key,
|
options.server_key_bits);
|
||||||
options.server_key_bits);
|
arc4random_stir();
|
||||||
arc4random_stir();
|
log("RSA key generation complete.");
|
||||||
log("RSA key generation complete.");
|
}
|
||||||
} else {
|
} else {
|
||||||
for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
|
for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
|
||||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
||||||
@ -684,19 +735,20 @@ main(int ac, char **av)
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options.protocol & SSH_PROTO_1) {
|
||||||
|
public_key = RSA_new();
|
||||||
|
sensitive_data.private_key = RSA_new();
|
||||||
|
|
||||||
public_key = RSA_new();
|
log("Generating %d bit RSA key.", options.server_key_bits);
|
||||||
sensitive_data.private_key = RSA_new();
|
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);
|
/* Schedule server key regeneration alarm. */
|
||||||
rsa_generate_key(sensitive_data.private_key, public_key,
|
signal(SIGALRM, key_regeneration_alarm);
|
||||||
options.server_key_bits);
|
alarm(options.key_regeneration_time);
|
||||||
arc4random_stir();
|
}
|
||||||
log("RSA key generation complete.");
|
|
||||||
|
|
||||||
/* 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. */
|
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */
|
||||||
signal(SIGHUP, sighup_handler);
|
signal(SIGHUP, sighup_handler);
|
||||||
@ -1069,9 +1121,7 @@ do_ssh1_kex()
|
|||||||
sensitive_data.private_key->n);
|
sensitive_data.private_key->n);
|
||||||
|
|
||||||
/* Destroy the private and public keys. They will no longer be needed. */
|
/* Destroy the private and public keys. They will no longer be needed. */
|
||||||
RSA_free(public_key);
|
destroy_sensitive_data();
|
||||||
RSA_free(sensitive_data.private_key);
|
|
||||||
RSA_free(sensitive_data.host_key);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract session key from the decrypted integer. The key is in the
|
* Extract session key from the decrypted integer. The key is in the
|
||||||
@ -1130,7 +1180,6 @@ do_ssh2_kex()
|
|||||||
unsigned char *kbuf;
|
unsigned char *kbuf;
|
||||||
unsigned char *hash;
|
unsigned char *hash;
|
||||||
Kex *kex;
|
Kex *kex;
|
||||||
Key *server_host_key;
|
|
||||||
char *cprop[PROPOSAL_MAX];
|
char *cprop[PROPOSAL_MAX];
|
||||||
char *sprop[PROPOSAL_MAX];
|
char *sprop[PROPOSAL_MAX];
|
||||||
|
|
||||||
@ -1231,8 +1280,8 @@ do_ssh2_kex()
|
|||||||
memset(kbuf, 0, klen);
|
memset(kbuf, 0, klen);
|
||||||
xfree(kbuf);
|
xfree(kbuf);
|
||||||
|
|
||||||
server_host_key = dsa_get_serverkey(options.dsa_key_file);
|
/* XXX precompute? */
|
||||||
dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen);
|
dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen);
|
||||||
|
|
||||||
/* calc H */ /* XXX depends on 'kex' */
|
/* calc H */ /* XXX depends on 'kex' */
|
||||||
hash = kex_hash(
|
hash = kex_hash(
|
||||||
@ -1255,10 +1304,17 @@ do_ssh2_kex()
|
|||||||
fprintf(stderr, "%02x", (hash[i])&0xff);
|
fprintf(stderr, "%02x", (hash[i])&0xff);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
#endif
|
#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 */
|
/* sign H */
|
||||||
dsa_sign(server_host_key, &signature, &slen, hash, 20);
|
/* XXX hashlen depends on KEX */
|
||||||
/* hashlen depends on KEX */
|
dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20);
|
||||||
key_free(server_host_key);
|
|
||||||
|
destroy_sensitive_data();
|
||||||
|
|
||||||
/* send server hostkey, DH pubkey 'f' and singed H */
|
/* send server hostkey, DH pubkey 'f' and singed H */
|
||||||
packet_start(SSH2_MSG_KEXDH_REPLY);
|
packet_start(SSH2_MSG_KEXDH_REPLY);
|
||||||
@ -1267,6 +1323,7 @@ do_ssh2_kex()
|
|||||||
packet_put_string((char *)signature, slen);
|
packet_put_string((char *)signature, slen);
|
||||||
packet_send();
|
packet_send();
|
||||||
xfree(signature);
|
xfree(signature);
|
||||||
|
xfree(server_host_key_blob);
|
||||||
packet_write_wait();
|
packet_write_wait();
|
||||||
|
|
||||||
kex_derive_keys(kex, hash, shared_secret);
|
kex_derive_keys(kex, hash, shared_secret);
|
||||||
|
120
uuencode.c
Normal file
120
uuencode.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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 "xmalloc.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] = '=';
|
||||||
|
} else if (i == nbytes) {
|
||||||
|
*(outptr++) = '=';
|
||||||
|
}
|
||||||
|
*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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dump_base64(FILE *fp, unsigned char *data, int len)
|
||||||
|
{
|
||||||
|
unsigned char *buf = xmalloc(2*len);
|
||||||
|
int i, n;
|
||||||
|
n = uuencode(data, len, buf);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
fprintf(fp, "%c", buf[i]);
|
||||||
|
if (i % 70 == 69)
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
if (i % 70 != 69)
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
xfree(buf);
|
||||||
|
}
|
6
uuencode.h
Normal file
6
uuencode.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef UUENCODE_H
|
||||||
|
#define UUENCODE_H
|
||||||
|
int uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded);
|
||||||
|
int uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize);
|
||||||
|
void dump_base64(FILE *fp, unsigned char *data, int len);
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user