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
|
||||
- Merge fix from OpenBSD CVS
|
||||
[ssh-agent.c]
|
||||
|
@ -31,11 +31,11 @@ LDFLAGS=-L. @LDFLAGS@
|
||||
|
||||
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
|
||||
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:
|
||||
1) generate server key:
|
||||
$ umask 077
|
||||
$ openssl dsaparam 1024 -out dsa1024.pem
|
||||
$ openssl gendsa -out /etc/ssh_dsa_key dsa1024.pem -rand /dev/arandom
|
||||
$ ssh-keygen -d -f /etc/ssh_host_dsa_key -N ''
|
||||
2) enable ssh2:
|
||||
server: add 'Protocol 2,1' to /etc/sshd_config
|
||||
client: ssh -o 'Protocol 2,1', or add to .ssh/config
|
||||
3) interop w/ ssh.com dsa-keys:
|
||||
ssh-keygen -f /key/from/ssh.com -X >> ~/.ssh/authorized_keys2
|
||||
and vice versa
|
||||
ssh-keygen -f /privatekey/from/openssh -x > ~/.ssh2/mykey.pub
|
||||
echo Key mykey.pub >> ~/.ssh2/authorization
|
||||
|
||||
works:
|
||||
secsh-transport: works w/o rekey
|
||||
@ -22,7 +25,7 @@ works:
|
||||
key database in ~/.ssh/known_hosts with bits == 0 hack
|
||||
dss: signature works, keygen w/ openssl
|
||||
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)
|
||||
todo:
|
||||
re-keying
|
||||
@ -38,4 +41,4 @@ todo:
|
||||
sftp
|
||||
|
||||
-markus
|
||||
$Date: 2000/04/12 07:45:43 $
|
||||
$Date: 2000/04/27 13:42:58 $
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#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 "packet.h"
|
||||
@ -185,6 +185,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
}
|
||||
}
|
||||
if (fail) {
|
||||
fclose(f);
|
||||
log(buf);
|
||||
packet_send_debug(buf);
|
||||
restore_uid();
|
||||
|
686
auth.c
686
auth.c
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#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 "rsa.h"
|
||||
@ -40,7 +40,7 @@ extern char *forced_command;
|
||||
* If the user's shell is not executable, false will be returned.
|
||||
* Otherwise true is returned.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
allowed_user(struct passwd * pw)
|
||||
{
|
||||
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... */
|
||||
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 *
|
||||
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
|
||||
|
||||
|
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"
|
||||
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/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "cipher.h"
|
||||
#include "ssh.h"
|
||||
#include "key.h"
|
||||
|
||||
/* Version identification string for identity files. */
|
||||
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||
@ -35,8 +41,8 @@ RCSID("$Id: authfile.c,v 1.11 2000/04/16 02:31:49 damien Exp $");
|
||||
*/
|
||||
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
RSA *key, const char *comment)
|
||||
save_private_key_rsa(const char *filename, const char *passphrase,
|
||||
RSA *key, const char *comment)
|
||||
{
|
||||
Buffer buffer, encrypted;
|
||||
char buf[100], *cp;
|
||||
@ -128,6 +134,63 @@ save_private_key(const char *filename, const char *passphrase,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* save DSA key in OpenSSL PEM format */
|
||||
|
||||
int
|
||||
save_private_key_dsa(const char *filename, const char *passphrase,
|
||||
DSA *dsa, const char *comment)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
int success = 1;
|
||||
int len = strlen(passphrase);
|
||||
|
||||
if (len > 0 && len <= 4) {
|
||||
error("passphrase too short: %d bytes", len);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
debug("open %s failed", filename);
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "w");
|
||||
if (fp == NULL ) {
|
||||
debug("fdopen %s failed", filename);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (len > 0) {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
|
||||
(char *)passphrase, strlen(passphrase), NULL, NULL))
|
||||
success = 0;
|
||||
} else {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
|
||||
NULL, 0, NULL, NULL))
|
||||
success = 0;
|
||||
}
|
||||
fclose(fp);
|
||||
return success;
|
||||
}
|
||||
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
const char *comment)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return save_private_key_rsa(filename, passphrase, key->rsa, comment);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
return save_private_key_dsa(filename, passphrase, key->dsa, comment);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file. Returns 0 if an error was
|
||||
* encountered (the file does not exist or is not readable), and non-zero
|
||||
@ -135,8 +198,7 @@ save_private_key(const char *filename, const char *passphrase,
|
||||
*/
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return)
|
||||
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
|
||||
{
|
||||
int fd, i;
|
||||
off_t len;
|
||||
@ -154,7 +216,7 @@ load_public_key(const char *filename, RSA * pub,
|
||||
|
||||
if (read(fd, cp, (size_t) len) != (size_t) len) {
|
||||
debug("Read from key file %.200s failed: %.100s", filename,
|
||||
strerror(errno));
|
||||
strerror(errno));
|
||||
buffer_free(&buffer);
|
||||
close(fd);
|
||||
return 0;
|
||||
@ -183,9 +245,13 @@ load_public_key(const char *filename, RSA * pub,
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
pub->n = BN_new();
|
||||
/* XXX alloc */
|
||||
if (pub->n == NULL)
|
||||
pub->n = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->n);
|
||||
pub->e = BN_new();
|
||||
/* XXX alloc */
|
||||
if (pub->e == NULL)
|
||||
pub->e = BN_new();
|
||||
buffer_get_bignum(&buffer, pub->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
@ -196,6 +262,20 @@ load_public_key(const char *filename, RSA * pub,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_public_key(const char *filename, Key * key, char **comment_return)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return load_public_key_rsa(filename, key->rsa, comment_return);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
* (file does not exist or is not readable, or passphrase is bad). This
|
||||
@ -204,35 +284,17 @@ load_public_key(const char *filename, RSA * pub,
|
||||
*/
|
||||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
RSA * prv, char **comment_return)
|
||||
load_private_key_rsa(int fd, const char *filename,
|
||||
const char *passphrase, RSA * prv, char **comment_return)
|
||||
{
|
||||
int fd, i, check1, check2, cipher_type;
|
||||
int i, check1, check2, cipher_type;
|
||||
off_t len;
|
||||
Buffer buffer, decrypted;
|
||||
char *cp;
|
||||
CipherContext cipher;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *aux;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* check owner and modes */
|
||||
if (fstat(fd, &st) < 0 ||
|
||||
(st.st_uid != 0 && 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);
|
||||
lseek(fd, (off_t) 0, SEEK_SET);
|
||||
|
||||
@ -309,7 +371,9 @@ load_private_key(const char *filename, const char *passphrase,
|
||||
buffer_free(&decrypted);
|
||||
fail:
|
||||
BN_clear_free(prv->n);
|
||||
prv->n = NULL;
|
||||
BN_clear_free(prv->e);
|
||||
prv->e = NULL;
|
||||
if (comment_return)
|
||||
xfree(*comment_return);
|
||||
return 0;
|
||||
@ -343,3 +407,87 @@ fail:
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
|
||||
{
|
||||
DSA *dsa;
|
||||
BIO *in;
|
||||
FILE *fp;
|
||||
|
||||
in = BIO_new(BIO_s_file());
|
||||
if (in == NULL) {
|
||||
error("BIO_new failed");
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "r");
|
||||
if (fp == NULL) {
|
||||
error("fdopen failed");
|
||||
return 0;
|
||||
}
|
||||
BIO_set_fp(in, fp, BIO_NOCLOSE);
|
||||
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
|
||||
if (dsa == NULL) {
|
||||
debug("PEM_read_bio_DSAPrivateKey failed");
|
||||
} else {
|
||||
/* replace k->dsa with loaded key */
|
||||
DSA_free(k->dsa);
|
||||
k->dsa = dsa;
|
||||
}
|
||||
BIO_free(in);
|
||||
fclose(fp);
|
||||
if (comment_return)
|
||||
*comment_return = xstrdup("dsa w/o comment");
|
||||
debug("read DSA private key done");
|
||||
#ifdef DEBUG_DSS
|
||||
DSA_print_fp(stderr, dsa, 8);
|
||||
#endif
|
||||
return dsa != NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
char **comment_return)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* check owner and modes */
|
||||
if (fstat(fd, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_mode & 077) != 0) {
|
||||
close(fd);
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("Bad ownership or mode(0%3.3o) for '%s'.",
|
||||
st.st_mode & 0777, filename);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
return 0;
|
||||
}
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
if (key->rsa->e != NULL) {
|
||||
BN_clear_free(key->rsa->e);
|
||||
key->rsa->e = NULL;
|
||||
}
|
||||
if (key->rsa->n != NULL) {
|
||||
BN_clear_free(key->rsa->n);
|
||||
key->rsa->n = NULL;
|
||||
}
|
||||
ret = load_private_key_rsa(fd, filename, passphrase,
|
||||
key->rsa, comment_return);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
ret = load_private_key_dsa(fd, passphrase, key, comment_return);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
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"
|
||||
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 "packet.h"
|
||||
@ -44,7 +44,6 @@ enable_compat20(void)
|
||||
{
|
||||
verbose("Enabling compatibility mode for protocol 2.0");
|
||||
compat20 = 1;
|
||||
packet_set_ssh2_format();
|
||||
}
|
||||
void
|
||||
enable_compat13(void)
|
||||
|
78
dsa.c
78
dsa.c
@ -28,7 +28,7 @@
|
||||
*/
|
||||
|
||||
#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 "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 "kex.h"
|
||||
#include "key.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#define INTBLOB_LEN 20
|
||||
#define SIGBLOB_LEN (2*INTBLOB_LEN)
|
||||
|
||||
Key *
|
||||
dsa_serverkey_from_blob(
|
||||
char *serverhostkey, int serverhostkeylen)
|
||||
dsa_key_from_blob(
|
||||
char *blob, int blen)
|
||||
{
|
||||
Buffer b;
|
||||
char *ktype;
|
||||
@ -61,14 +62,17 @@ dsa_serverkey_from_blob(
|
||||
DSA *dsa;
|
||||
Key *key;
|
||||
|
||||
#ifdef DEBUG_DSS
|
||||
dump_base64(blob, blen);
|
||||
#endif
|
||||
/* fetch & parse DSA/DSS pubkey */
|
||||
key = key_new(KEY_DSA);
|
||||
dsa = key->dsa;
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, serverhostkey, serverhostkeylen);
|
||||
buffer_append(&b, blob, blen);
|
||||
ktype = buffer_get_string(&b, NULL);
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
@ -78,7 +82,7 @@ dsa_serverkey_from_blob(
|
||||
buffer_get_bignum2(&b, dsa->pub_key);
|
||||
rlen = buffer_len(&b);
|
||||
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);
|
||||
|
||||
debug("keytype %s", ktype);
|
||||
@ -87,37 +91,8 @@ dsa_serverkey_from_blob(
|
||||
#endif
|
||||
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
|
||||
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;
|
||||
int len;
|
||||
@ -146,7 +121,7 @@ int
|
||||
dsa_sign(
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *hash, int hlen)
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
unsigned char *digest;
|
||||
unsigned char *ret;
|
||||
@ -165,10 +140,13 @@ dsa_sign(
|
||||
}
|
||||
digest = xmalloc(evp_md->md_size);
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, hash, hlen);
|
||||
EVP_DigestUpdate(&md, data, datalen);
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
|
||||
if (sig == NULL) {
|
||||
fatal("dsa_sign: cannot sign");
|
||||
}
|
||||
|
||||
rlen = BN_num_bytes(sig->r);
|
||||
slen = BN_num_bytes(sig->s);
|
||||
@ -212,7 +190,7 @@ int
|
||||
dsa_verify(
|
||||
Key *key,
|
||||
unsigned char *signature, int signaturelen,
|
||||
unsigned char *hash, int hlen)
|
||||
unsigned char *data, int datalen)
|
||||
{
|
||||
Buffer b;
|
||||
unsigned char *digest;
|
||||
@ -269,10 +247,10 @@ dsa_verify(
|
||||
xfree(sigblob);
|
||||
}
|
||||
|
||||
/* sha1 the signed data (== session_id == hash) */
|
||||
/* sha1 the data */
|
||||
digest = xmalloc(evp_md->md_size);
|
||||
EVP_DigestInit(&md, evp_md);
|
||||
EVP_DigestUpdate(&md, hash, hlen);
|
||||
EVP_DigestUpdate(&md, data, datalen);
|
||||
EVP_DigestFinal(&md, digest, NULL);
|
||||
|
||||
ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
|
||||
@ -296,3 +274,21 @@ dsa_verify(
|
||||
debug("dsa_verify: signature %s", txt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Key *
|
||||
dsa_generate_key(unsigned int bits)
|
||||
{
|
||||
DSA *dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
|
||||
Key *k;
|
||||
if (dsa == NULL) {
|
||||
fatal("DSA_generate_parameters failed");
|
||||
}
|
||||
if (!DSA_generate_key(dsa)) {
|
||||
fatal("DSA_generate_keys failed");
|
||||
}
|
||||
|
||||
k = key_new(KEY_EMPTY);
|
||||
k->type = KEY_DSA;
|
||||
k->dsa = dsa;
|
||||
return k;
|
||||
}
|
||||
|
12
dsa.h
12
dsa.h
@ -1,20 +1,22 @@
|
||||
#ifndef DSA_H
|
||||
#define DSA_H
|
||||
|
||||
Key *dsa_serverkey_from_blob(char *serverhostkey, int serverhostkeylen);
|
||||
Key *dsa_get_serverkey(char *filename);
|
||||
int dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
|
||||
Key *dsa_key_from_blob(char *blob, int blen);
|
||||
int dsa_make_key_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
|
||||
|
||||
int
|
||||
dsa_sign(
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *hash, int hlen);
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
int
|
||||
dsa_verify(
|
||||
Key *key,
|
||||
unsigned char *signature, int signaturelen,
|
||||
unsigned char *hash, int hlen);
|
||||
unsigned char *data, int datalen);
|
||||
|
||||
Key *
|
||||
dsa_generate_key(unsigned int bits);
|
||||
|
||||
#endif
|
||||
|
23
hostfile.c
23
hostfile.c
@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#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 "match.h"
|
||||
@ -39,13 +39,8 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
|
||||
if (!key_read(ret, bits, &cp))
|
||||
bits = key_read(ret, &cp);
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
@ -182,24 +177,18 @@ add_host_to_hostfile(const char *filename, const char *host, Key *key)
|
||||
{
|
||||
FILE *f;
|
||||
int success = 0;
|
||||
|
||||
if (key == NULL)
|
||||
return 1;
|
||||
|
||||
/* Open the file for appending. */
|
||||
return 1; /* XXX ? */
|
||||
f = fopen(filename, "a");
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
fprintf(f, "%s ", host);
|
||||
if (key_write(key, f)) {
|
||||
fprintf(f, "\n");
|
||||
success = 1;
|
||||
} else {
|
||||
error("add_host_to_hostfile: saving key failed");
|
||||
error("add_host_to_hostfile: saving key in %s failed", filename);
|
||||
}
|
||||
|
||||
/* Close the file. */
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
return success;
|
||||
}
|
||||
|
107
key.c
107
key.c
@ -38,6 +38,10 @@
|
||||
#include <openssl/evp.h>
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#define SSH_DSS "ssh-dss"
|
||||
|
||||
Key *
|
||||
key_new(int type)
|
||||
@ -47,6 +51,8 @@ key_new(int type)
|
||||
DSA *dsa;
|
||||
k = xmalloc(sizeof(*k));
|
||||
k->type = type;
|
||||
k->dsa = NULL;
|
||||
k->rsa = NULL;
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
rsa = RSA_new();
|
||||
@ -63,8 +69,6 @@ key_new(int type)
|
||||
k->dsa = dsa;
|
||||
break;
|
||||
case KEY_EMPTY:
|
||||
k->dsa = NULL;
|
||||
k->rsa = NULL;
|
||||
break;
|
||||
default:
|
||||
fatal("key_new: bad key type %d", k->type);
|
||||
@ -111,7 +115,7 @@ key_equal(Key *a, Key *b)
|
||||
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
|
||||
break;
|
||||
default:
|
||||
fatal("key_free: bad key type %d", a->type);
|
||||
fatal("key_equal: bad key type %d", a->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -127,46 +131,37 @@ char *
|
||||
key_fingerprint(Key *k)
|
||||
{
|
||||
static char retval[80];
|
||||
unsigned char *buf = NULL;
|
||||
unsigned char *blob = NULL;
|
||||
int len = 0;
|
||||
int nlen, elen, plen, qlen, glen, publen;
|
||||
int nlen, elen;
|
||||
|
||||
switch (k->type) {
|
||||
case KEY_RSA:
|
||||
nlen = BN_num_bytes(k->rsa->n);
|
||||
elen = BN_num_bytes(k->rsa->e);
|
||||
len = nlen + elen;
|
||||
buf = xmalloc(len);
|
||||
BN_bn2bin(k->rsa->n, buf);
|
||||
BN_bn2bin(k->rsa->e, buf + nlen);
|
||||
blob = xmalloc(len);
|
||||
BN_bn2bin(k->rsa->n, blob);
|
||||
BN_bn2bin(k->rsa->e, blob + nlen);
|
||||
break;
|
||||
case KEY_DSA:
|
||||
plen = BN_num_bytes(k->dsa->p);
|
||||
qlen = BN_num_bytes(k->dsa->q);
|
||||
glen = BN_num_bytes(k->dsa->g);
|
||||
publen = BN_num_bytes(k->dsa->pub_key);
|
||||
len = qlen + qlen + glen + publen;
|
||||
buf = xmalloc(len);
|
||||
BN_bn2bin(k->dsa->p, buf);
|
||||
BN_bn2bin(k->dsa->q, buf + plen);
|
||||
BN_bn2bin(k->dsa->g, buf + plen + qlen);
|
||||
BN_bn2bin(k->dsa->pub_key , buf + plen + qlen + glen);
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
break;
|
||||
default:
|
||||
fatal("key_fingerprint: bad key type %d", k->type);
|
||||
break;
|
||||
}
|
||||
if (buf != NULL) {
|
||||
if (blob != NULL) {
|
||||
unsigned char d[16];
|
||||
EVP_MD_CTX md;
|
||||
EVP_DigestInit(&md, EVP_md5());
|
||||
EVP_DigestUpdate(&md, buf, len);
|
||||
EVP_DigestUpdate(&md, blob, len);
|
||||
EVP_DigestFinal(&md, d, NULL);
|
||||
snprintf(retval, sizeof(retval), FPRINT,
|
||||
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
|
||||
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
|
||||
memset(buf, 0, len);
|
||||
xfree(buf);
|
||||
memset(blob, 0, len);
|
||||
xfree(blob);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@ -226,13 +221,27 @@ write_bignum(FILE *f, BIGNUM *num)
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
int
|
||||
key_read(Key *ret, unsigned int bits, char **cpp)
|
||||
unsigned int
|
||||
key_read(Key *ret, char **cpp)
|
||||
{
|
||||
Key *k;
|
||||
unsigned int bits = 0;
|
||||
char *cp;
|
||||
int len, n;
|
||||
unsigned char *blob;
|
||||
|
||||
cp = *cpp;
|
||||
|
||||
switch(ret->type) {
|
||||
case KEY_RSA:
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
*cpp = cp;
|
||||
/* Get public exponent, public modulus. */
|
||||
if (!read_bignum(cpp, ret->rsa->e))
|
||||
return 0;
|
||||
@ -240,22 +249,32 @@ key_read(Key *ret, unsigned int bits, char **cpp)
|
||||
return 0;
|
||||
break;
|
||||
case KEY_DSA:
|
||||
if (bits != 0)
|
||||
if (strncmp(cp, SSH_DSS " ", 7) != 0)
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->p))
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->q))
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->g))
|
||||
return 0;
|
||||
if (!read_bignum(cpp, ret->dsa->pub_key))
|
||||
cp += 7;
|
||||
len = 2*strlen(cp);
|
||||
blob = xmalloc(len);
|
||||
n = uudecode(cp, blob, len);
|
||||
k = dsa_key_from_blob(blob, n);
|
||||
if (k == NULL)
|
||||
return 0;
|
||||
xfree(blob);
|
||||
if (ret->dsa != NULL)
|
||||
DSA_free(ret->dsa);
|
||||
ret->dsa = k->dsa;
|
||||
k->dsa = NULL;
|
||||
key_free(k);
|
||||
bits = BN_num_bits(ret->dsa->p);
|
||||
cp = strchr(cp, '=');
|
||||
if (cp == NULL)
|
||||
return 0;
|
||||
*cpp = cp + 1;
|
||||
break;
|
||||
default:
|
||||
fatal("bad key type: %d", ret->type);
|
||||
fatal("key_read: bad key type: %d", ret->type);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
return bits;
|
||||
}
|
||||
int
|
||||
key_write(Key *key, FILE *f)
|
||||
@ -274,17 +293,15 @@ key_write(Key *key, FILE *f)
|
||||
error("key_write: failed for RSA key");
|
||||
}
|
||||
} else if (key->type == KEY_DSA && key->dsa != NULL) {
|
||||
/* bits == 0 means DSA key */
|
||||
bits = 0;
|
||||
fprintf(f, "%u", bits);
|
||||
if (write_bignum(f, key->dsa->p) &&
|
||||
write_bignum(f, key->dsa->q) &&
|
||||
write_bignum(f, key->dsa->g) &&
|
||||
write_bignum(f, key->dsa->pub_key)) {
|
||||
success = 1;
|
||||
} else {
|
||||
error("key_write: failed for DSA key");
|
||||
}
|
||||
int len, n;
|
||||
unsigned char *blob, *uu;
|
||||
dsa_make_key_blob(key, &blob, &len);
|
||||
uu = xmalloc(2*len);
|
||||
n = uuencode(blob, len, uu);
|
||||
fprintf(f, "%s %s", SSH_DSS, uu);
|
||||
xfree(blob);
|
||||
xfree(uu);
|
||||
success = 1;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
3
key.h
3
key.h
@ -18,6 +18,7 @@ void key_free(Key *k);
|
||||
int key_equal(Key *a, Key *b);
|
||||
char *key_fingerprint(Key *k);
|
||||
int key_write(Key *key, FILE *f);
|
||||
int key_read(Key *key, unsigned int bits, char **cpp);
|
||||
unsigned int
|
||||
key_read(Key *key, char **cpp);
|
||||
|
||||
#endif
|
||||
|
96
radix.c
96
radix.c
@ -1,109 +1,15 @@
|
||||
/*
|
||||
* radix.c
|
||||
*
|
||||
* base-64 encoding pinched from lynx2-7-2, who pinched it from rpem.
|
||||
* Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991
|
||||
* and placed in the public domain.
|
||||
*
|
||||
* Dug Song <dugsong@UMICH.EDU>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
#ifdef AFS
|
||||
#include <krb.h>
|
||||
|
||||
char six2pr[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
unsigned char pr2six[256];
|
||||
|
||||
int
|
||||
uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
|
||||
{
|
||||
/* ENC is the basic 1 character encoding function to make a char printing */
|
||||
#define ENC(c) six2pr[c]
|
||||
|
||||
register char *outptr = bufcoded;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < nbytes; i += 3) {
|
||||
*(outptr++) = ENC(*bufin >> 2); /* c1 */
|
||||
*(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /* c2 */
|
||||
*(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /* c3 */
|
||||
*(outptr++) = ENC(bufin[2] & 077); /* c4 */
|
||||
bufin += 3;
|
||||
}
|
||||
if (i == nbytes + 1) {
|
||||
outptr[-1] = '=';
|
||||
} else if (i == nbytes + 2) {
|
||||
outptr[-1] = '=';
|
||||
outptr[-2] = '=';
|
||||
}
|
||||
*outptr = '\0';
|
||||
return (outptr - bufcoded);
|
||||
}
|
||||
|
||||
int
|
||||
uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize)
|
||||
{
|
||||
/* single character decode */
|
||||
#define DEC(c) pr2six[(unsigned char)c]
|
||||
#define MAXVAL 63
|
||||
|
||||
static int first = 1;
|
||||
int nbytesdecoded, j;
|
||||
const char *bufin = bufcoded;
|
||||
register unsigned char *bufout = bufplain;
|
||||
register int nprbytes;
|
||||
|
||||
/* If this is the first call, initialize the mapping table. */
|
||||
if (first) {
|
||||
first = 0;
|
||||
for (j = 0; j < 256; j++)
|
||||
pr2six[j] = MAXVAL + 1;
|
||||
for (j = 0; j < 64; j++)
|
||||
pr2six[(unsigned char) six2pr[j]] = (unsigned char) j;
|
||||
}
|
||||
/* Strip leading whitespace. */
|
||||
while (*bufcoded == ' ' || *bufcoded == '\t')
|
||||
bufcoded++;
|
||||
|
||||
/*
|
||||
* Figure out how many characters are in the input buffer. If this
|
||||
* would decode into more bytes than would fit into the output
|
||||
* buffer, adjust the number of input bytes downwards.
|
||||
*/
|
||||
bufin = bufcoded;
|
||||
while (DEC(*(bufin++)) <= MAXVAL);
|
||||
nprbytes = bufin - bufcoded - 1;
|
||||
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
|
||||
if (nbytesdecoded > outbufsize)
|
||||
nprbytes = (outbufsize * 4) / 3;
|
||||
|
||||
bufin = bufcoded;
|
||||
|
||||
while (nprbytes > 0) {
|
||||
*(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2);
|
||||
*(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3]));
|
||||
bufin += 4;
|
||||
nprbytes -= 4;
|
||||
}
|
||||
if (nprbytes & 03) {
|
||||
if (DEC(bufin[-2]) > MAXVAL)
|
||||
nbytesdecoded -= 2;
|
||||
else
|
||||
nbytesdecoded -= 1;
|
||||
}
|
||||
return (nbytesdecoded);
|
||||
}
|
||||
|
||||
typedef unsigned char my_u_char;
|
||||
typedef unsigned int my_u_int32_t;
|
||||
typedef unsigned short my_u_short;
|
||||
|
45
readconf.c
45
readconf.c
@ -14,7 +14,7 @@
|
||||
*/
|
||||
|
||||
#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 "cipher.h"
|
||||
@ -104,7 +104,8 @@ typedef enum {
|
||||
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
||||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2
|
||||
} OpCodes;
|
||||
|
||||
/* Textual representations of the tokens. */
|
||||
@ -131,6 +132,7 @@ static struct {
|
||||
{ "fallbacktorsh", oFallBackToRsh },
|
||||
{ "usersh", oUseRsh },
|
||||
{ "identityfile", oIdentityFile },
|
||||
{ "identityfile2", oIdentityFile2 },
|
||||
{ "hostname", oHostName },
|
||||
{ "proxycommand", oProxyCommand },
|
||||
{ "port", oPort },
|
||||
@ -145,6 +147,8 @@ static struct {
|
||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
|
||||
{ "userknownhostsfile2", oUserKnownHostsFile2 },
|
||||
{ "connectionattempts", oConnectionAttempts },
|
||||
{ "batchmode", oBatchMode },
|
||||
{ "checkhostip", oCheckHostIP },
|
||||
@ -368,14 +372,22 @@ parse_flag:
|
||||
goto parse_int;
|
||||
|
||||
case oIdentityFile:
|
||||
case oIdentityFile2:
|
||||
cp = strtok(NULL, WHITESPACE);
|
||||
if (!cp)
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep) {
|
||||
if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES)
|
||||
intptr = (opcode == oIdentityFile) ?
|
||||
&options->num_identity_files :
|
||||
&options->num_identity_files2;
|
||||
if (*intptr >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
||||
options->identity_files[options->num_identity_files++] = xstrdup(cp);
|
||||
charptr = (opcode == oIdentityFile) ?
|
||||
&options->identity_files[*intptr] :
|
||||
&options->identity_files2[*intptr];
|
||||
*charptr = xstrdup(cp);
|
||||
*intptr = *intptr + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -397,6 +409,14 @@ parse_string:
|
||||
charptr = &options->user_hostfile;
|
||||
goto parse_string;
|
||||
|
||||
case oGlobalKnownHostsFile2:
|
||||
charptr = &options->system_hostfile2;
|
||||
goto parse_string;
|
||||
|
||||
case oUserKnownHostsFile2:
|
||||
charptr = &options->user_hostfile2;
|
||||
goto parse_string;
|
||||
|
||||
case oHostName:
|
||||
charptr = &options->hostname;
|
||||
goto parse_string;
|
||||
@ -642,12 +662,15 @@ initialize_options(Options * options)
|
||||
options->ciphers = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->num_identity_files = 0;
|
||||
options->num_identity_files2 = 0;
|
||||
options->hostname = NULL;
|
||||
options->proxy_command = NULL;
|
||||
options->user = NULL;
|
||||
options->escape_char = -1;
|
||||
options->system_hostfile = NULL;
|
||||
options->user_hostfile = NULL;
|
||||
options->system_hostfile2 = NULL;
|
||||
options->user_hostfile2 = NULL;
|
||||
options->num_local_forwards = 0;
|
||||
options->num_remote_forwards = 0;
|
||||
options->log_level = (LogLevel) - 1;
|
||||
@ -715,19 +738,31 @@ fill_default_options(Options * options)
|
||||
if (options->cipher == -1)
|
||||
options->cipher = SSH_CIPHER_NOT_SET;
|
||||
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) {
|
||||
options->identity_files[0] =
|
||||
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
|
||||
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
|
||||
options->num_identity_files = 1;
|
||||
}
|
||||
#if 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)
|
||||
options->escape_char = '~';
|
||||
if (options->system_hostfile == NULL)
|
||||
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
|
||||
if (options->user_hostfile == NULL)
|
||||
options->user_hostfile = SSH_USER_HOSTFILE;
|
||||
if (options->system_hostfile2 == NULL)
|
||||
options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
|
||||
if (options->user_hostfile2 == NULL)
|
||||
options->user_hostfile2 = SSH_USER_HOSTFILE2;
|
||||
if (options->log_level == (LogLevel) - 1)
|
||||
options->log_level = SYSLOG_LEVEL_INFO;
|
||||
/* options->proxy_command should not be set by default */
|
||||
|
@ -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
|
||||
#define READCONF_H
|
||||
@ -73,9 +73,13 @@ typedef struct {
|
||||
|
||||
char *system_hostfile;/* Path for /etc/ssh_known_hosts. */
|
||||
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
|
||||
char *system_hostfile2;
|
||||
char *user_hostfile2;
|
||||
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
int num_identity_files2; /* DSA identities. */
|
||||
char *identity_files[SSH_MAX_IDENTITY_FILES];
|
||||
char *identity_files2[SSH_MAX_IDENTITY_FILES];
|
||||
|
||||
/* Local TCP/IP forward requests. */
|
||||
int num_local_forwards;
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
#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 "servconf.h"
|
||||
@ -143,7 +143,7 @@ fill_default_server_options(ServerOptions *options)
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||||
options->protocol = SSH_PROTO_1;
|
||||
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
|
||||
}
|
||||
|
||||
#define WHITESPACE " \t\r\n"
|
||||
|
@ -733,7 +733,7 @@ server_input_channel_open(int type, int plen)
|
||||
rwindow = 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);
|
||||
|
||||
if (strcmp(ctype, "session") == 0) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
@ -1474,6 +1474,5 @@ do_authenticated2(void)
|
||||
* authentication.
|
||||
*/
|
||||
alarm(0);
|
||||
log("do_authenticated2");
|
||||
server_loop2();
|
||||
}
|
||||
|
37
ssh-add.c
37
ssh-add.c
@ -7,13 +7,18 @@
|
||||
*/
|
||||
|
||||
#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 "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "authfd.h"
|
||||
#include "fingerprint.h"
|
||||
#include "key.h"
|
||||
#include "authfile.h"
|
||||
|
||||
#ifdef HAVE___PROGNAME
|
||||
extern char *__progname;
|
||||
@ -24,19 +29,19 @@ const char *__progname = "ssh-add";
|
||||
void
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
Key *public;
|
||||
char *comment;
|
||||
|
||||
key = RSA_new();
|
||||
if (!load_public_key(filename, key, &comment)) {
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ssh_remove_identity(ac, key))
|
||||
if (ssh_remove_identity(ac, public->rsa))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not remove identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
key_free(public);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
@ -91,20 +96,19 @@ ssh_askpass(char *askpass, char *msg)
|
||||
void
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
RSA *key;
|
||||
RSA *public_key;
|
||||
Key *public;
|
||||
Key *private;
|
||||
char *saved_comment, *comment, *askpass = NULL;
|
||||
char buf[1024], msg[1024];
|
||||
int success;
|
||||
int interactive = isatty(STDIN_FILENO);
|
||||
|
||||
key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(filename, public_key, &saved_comment)) {
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &saved_comment)) {
|
||||
printf("Bad key file %s: %s\n", filename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
RSA_free(public_key);
|
||||
key_free(public);
|
||||
|
||||
if (!interactive && getenv("DISPLAY")) {
|
||||
if (getenv(SSH_ASKPASS_ENV))
|
||||
@ -114,7 +118,8 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
||||
}
|
||||
|
||||
/* At first, try empty passphrase */
|
||||
success = load_private_key(filename, "", key, &comment);
|
||||
private = key_new(KEY_RSA);
|
||||
success = load_private_key(filename, "", private, &comment);
|
||||
if (!success) {
|
||||
printf("Need passphrase for %.200s\n", filename);
|
||||
if (!interactive && askpass == NULL) {
|
||||
@ -135,7 +140,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
success = load_private_key(filename, pass, key, &comment);
|
||||
success = load_private_key(filename, pass, private, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
@ -145,11 +150,11 @@ add_file(AuthenticationConnection *ac, const char *filename)
|
||||
}
|
||||
xfree(saved_comment);
|
||||
|
||||
if (ssh_add_identity(ac, key, comment))
|
||||
if (ssh_add_identity(ac, private->rsa, comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
RSA_free(key);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
.\"
|
||||
.\" 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
|
||||
.Dt SSH-KEYGEN 1
|
||||
@ -37,6 +37,8 @@
|
||||
.Nm ssh-keygen
|
||||
.Fl l
|
||||
.Op Fl f Ar keyfile
|
||||
.Nm ssh-keygen
|
||||
.Fl R
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
generates and manages authentication keys for
|
||||
@ -112,6 +114,10 @@ Provides the new comment.
|
||||
Provides the new passphrase.
|
||||
.It Fl P Ar passphrase
|
||||
Provides the (old) passphrase.
|
||||
.It Fl R
|
||||
If RSA support is functional, immediately exits with code 0. If RSA
|
||||
support is not functional, exits with code 1. This flag will be
|
||||
removed once the RSA patent expires.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
|
350
ssh-keygen.c
350
ssh-keygen.c
@ -7,20 +7,23 @@
|
||||
*/
|
||||
|
||||
#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 "xmalloc.h"
|
||||
#include "fingerprint.h"
|
||||
#include "key.h"
|
||||
#include "rsa.h"
|
||||
#include "dsa.h"
|
||||
#include "authfile.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
/* Generated private key. */
|
||||
RSA *private_key;
|
||||
|
||||
/* Generated public key. */
|
||||
RSA *public_key;
|
||||
|
||||
/* Number of bits in the RSA key. This value can be changed on the command line. */
|
||||
/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */
|
||||
int bits = 1024;
|
||||
|
||||
/*
|
||||
@ -53,6 +56,12 @@ char *identity_new_passphrase = NULL;
|
||||
/* This is set to the new comment if given on the command line. */
|
||||
char *identity_comment = NULL;
|
||||
|
||||
/* Dump public key file in format used by real and the original SSH 2 */
|
||||
int convert_to_ssh2 = 0;
|
||||
int convert_from_ssh2 = 0;
|
||||
int print_public = 0;
|
||||
int dsa_mode = 0;
|
||||
|
||||
/* argv0 */
|
||||
#ifdef HAVE___PROGNAME
|
||||
extern char *__progname;
|
||||
@ -60,6 +69,8 @@ extern char *__progname;
|
||||
const char *__progname = "ssh-keygen";
|
||||
#endif /* HAVE___PROGNAME */
|
||||
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
void
|
||||
ask_filename(struct passwd *pw, const char *prompt)
|
||||
{
|
||||
@ -77,12 +88,140 @@ ask_filename(struct passwd *pw, const char *prompt)
|
||||
have_identity = 1;
|
||||
}
|
||||
|
||||
int
|
||||
try_load_key(char *filename, Key *k)
|
||||
{
|
||||
int success = 1;
|
||||
if (!load_private_key(filename, "", k, NULL)) {
|
||||
char *pass = read_passphrase("Enter passphrase: ", 1);
|
||||
if (!load_private_key(filename, pass, k, NULL)) {
|
||||
success = 0;
|
||||
}
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
|
||||
#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----"
|
||||
|
||||
void
|
||||
do_convert_to_ssh2(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int len;
|
||||
unsigned char *blob;
|
||||
struct stat st;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
if (stat(identity_file, &st) < 0) {
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
k = key_new(KEY_DSA);
|
||||
if (!try_load_key(identity_file, k)) {
|
||||
fprintf(stderr, "load failed\n");
|
||||
exit(1);
|
||||
}
|
||||
dsa_make_key_blob(k, &blob, &len);
|
||||
fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
|
||||
fprintf(stdout,
|
||||
"Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
|
||||
BN_num_bits(k->dsa->p),
|
||||
pw->pw_name, hostname);
|
||||
dump_base64(stdout, blob, len);
|
||||
fprintf(stdout, SSH_COM_MAGIC_END "\n");
|
||||
key_free(k);
|
||||
xfree(blob);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
do_convert_from_ssh2(struct passwd *pw)
|
||||
{
|
||||
Key *k;
|
||||
int blen;
|
||||
char line[1024], *p;
|
||||
char blob[8096];
|
||||
char encoded[8096];
|
||||
struct stat st;
|
||||
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
|
||||
do_fingerprint(struct passwd *pw)
|
||||
{
|
||||
FILE *f;
|
||||
BIGNUM *e, *n;
|
||||
RSA *public_key;
|
||||
Key *public;
|
||||
char *comment = NULL, *cp, *ep, line[16*1024];
|
||||
int i, skip = 0, num = 1, invalid = 1;
|
||||
unsigned int ignore;
|
||||
@ -94,17 +233,16 @@ do_fingerprint(struct passwd *pw)
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
public_key = RSA_new();
|
||||
if (load_public_key(identity_file, public_key, &comment)) {
|
||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
||||
fingerprint(public_key->e, public_key->n),
|
||||
comment);
|
||||
RSA_free(public_key);
|
||||
public = key_new(KEY_RSA);
|
||||
if (load_public_key(identity_file, public, &comment)) {
|
||||
printf("%d %s %s\n", BN_num_bits(public->rsa->n),
|
||||
key_fingerprint(public), comment);
|
||||
key_free(public);
|
||||
exit(0);
|
||||
}
|
||||
RSA_free(public_key);
|
||||
key_free(public);
|
||||
|
||||
/* XXX */
|
||||
f = fopen(identity_file, "r");
|
||||
if (f != NULL) {
|
||||
n = BN_new();
|
||||
@ -172,7 +310,9 @@ do_change_passphrase(struct passwd *pw)
|
||||
char *comment;
|
||||
char *old_passphrase, *passphrase1, *passphrase2;
|
||||
struct stat st;
|
||||
RSA *private_key;
|
||||
Key *private;
|
||||
Key *public;
|
||||
int type = dsa_mode ? KEY_DSA : KEY_RSA;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
@ -180,22 +320,26 @@ do_change_passphrase(struct passwd *pw)
|
||||
perror(identity_file);
|
||||
exit(1);
|
||||
}
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
|
||||
if (type == KEY_RSA) {
|
||||
/* XXX this works currently only for RSA */
|
||||
public = key_new(type);
|
||||
if (!load_public_key(identity_file, public, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
/* Clear the public key since we are just about to load the whole file. */
|
||||
key_free(public);
|
||||
}
|
||||
/* Clear the public key since we are just about to load the whole file. */
|
||||
RSA_free(public_key);
|
||||
|
||||
/* Try to load the file with empty passphrase. */
|
||||
private_key = RSA_new();
|
||||
if (!load_private_key(identity_file, "", private_key, &comment)) {
|
||||
private = key_new(type);
|
||||
if (!load_private_key(identity_file, "", private, &comment)) {
|
||||
if (identity_passphrase)
|
||||
old_passphrase = xstrdup(identity_passphrase);
|
||||
else
|
||||
old_passphrase = read_passphrase("Enter old passphrase: ", 1);
|
||||
if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
|
||||
if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
|
||||
memset(old_passphrase, 0, strlen(old_passphrase));
|
||||
xfree(old_passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
@ -230,19 +374,19 @@ do_change_passphrase(struct passwd *pw)
|
||||
}
|
||||
|
||||
/* Save the file using the new passphrase. */
|
||||
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
|
||||
if (!save_private_key(identity_file, passphrase1, private, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
/* Destroy the passphrase and the copy of the key in memory. */
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
RSA_free(private_key); /* Destroys contents */
|
||||
key_free(private); /* Destroys contents */
|
||||
xfree(comment);
|
||||
|
||||
printf("Your identification has been saved with the new passphrase.\n");
|
||||
@ -256,11 +400,11 @@ void
|
||||
do_change_comment(struct passwd *pw)
|
||||
{
|
||||
char new_comment[1024], *comment;
|
||||
RSA *private_key;
|
||||
Key *private;
|
||||
Key *public;
|
||||
char *passphrase;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
char *tmpbuf;
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which the key is");
|
||||
@ -272,14 +416,14 @@ do_change_comment(struct passwd *pw)
|
||||
* Try to load the public key from the file the verify that it is
|
||||
* readable and of the proper format.
|
||||
*/
|
||||
public_key = RSA_new();
|
||||
if (!load_public_key(identity_file, public_key, NULL)) {
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(identity_file, public, NULL)) {
|
||||
printf("%s is not a valid key file.\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
private_key = RSA_new();
|
||||
|
||||
if (load_private_key(identity_file, "", private_key, &comment))
|
||||
private = key_new(KEY_RSA);
|
||||
if (load_private_key(identity_file, "", private, &comment))
|
||||
passphrase = xstrdup("");
|
||||
else {
|
||||
if (identity_passphrase)
|
||||
@ -289,7 +433,7 @@ do_change_comment(struct passwd *pw)
|
||||
else
|
||||
passphrase = read_passphrase("Enter passphrase: ", 1);
|
||||
/* Try to load using the passphrase. */
|
||||
if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
|
||||
if (!load_private_key(identity_file, passphrase, private, &comment)) {
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
printf("Bad passphrase.\n");
|
||||
@ -305,7 +449,7 @@ do_change_comment(struct passwd *pw)
|
||||
fflush(stdout);
|
||||
if (!fgets(new_comment, sizeof(new_comment), stdin)) {
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
exit(1);
|
||||
}
|
||||
if (strchr(new_comment, '\n'))
|
||||
@ -313,18 +457,18 @@ do_change_comment(struct passwd *pw)
|
||||
}
|
||||
|
||||
/* Save the file using the new passphrase. */
|
||||
if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
|
||||
if (!save_private_key(identity_file, passphrase, private, new_comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
xfree(comment);
|
||||
exit(1);
|
||||
}
|
||||
memset(passphrase, 0, strlen(passphrase));
|
||||
xfree(passphrase);
|
||||
RSA_free(private_key);
|
||||
key_free(private);
|
||||
|
||||
strlcat(identity_file, ".pub", sizeof(identity_file));
|
||||
f = fopen(identity_file, "w");
|
||||
@ -332,13 +476,10 @@ do_change_comment(struct passwd *pw)
|
||||
printf("Could not save your public key in %s\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
||||
tmpbuf = BN_bn2dec(public_key->e);
|
||||
fprintf(f, "%s ", tmpbuf);
|
||||
free(tmpbuf);
|
||||
tmpbuf = BN_bn2dec(public_key->n);
|
||||
fprintf(f, "%s %s\n", tmpbuf, new_comment);
|
||||
free(tmpbuf);
|
||||
if (!key_write(public, f))
|
||||
fprintf(stderr, "write key failed");
|
||||
key_free(public);
|
||||
fprintf(f, " %s\n", new_comment);
|
||||
fclose(f);
|
||||
|
||||
xfree(comment);
|
||||
@ -351,7 +492,7 @@ void
|
||||
usage(void)
|
||||
{
|
||||
printf("ssh-keygen version %s\n", SSH_VERSION);
|
||||
printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
|
||||
printf("Usage: %s [-b bits] [-p] [-c] [-l] [-x] [-X] [-y] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -363,29 +504,28 @@ main(int ac, char **av)
|
||||
{
|
||||
char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
|
||||
struct passwd *pw;
|
||||
char *tmpbuf;
|
||||
int opt;
|
||||
struct stat st;
|
||||
FILE *f;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
Key *private;
|
||||
Key *public;
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
/* we need this for the home * directory. */
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
printf("You don't exist, go away!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
perror("gethostname");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
|
||||
while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bits = atoi(optarg);
|
||||
@ -428,6 +568,29 @@ main(int ac, char **av)
|
||||
quiet = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (rsa_alive() == 0)
|
||||
exit(1);
|
||||
else
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
convert_to_ssh2 = 1;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
convert_from_ssh2 = 1;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
print_public = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dsa_mode = 1;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@ -441,22 +604,44 @@ main(int ac, char **av)
|
||||
printf("Can only have one of -p and -c.\n");
|
||||
usage();
|
||||
}
|
||||
/* check if RSA support is needed and exists */
|
||||
if (dsa_mode == 0 && rsa_alive() == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
if (print_fingerprint)
|
||||
do_fingerprint(pw);
|
||||
if (change_passphrase)
|
||||
do_change_passphrase(pw);
|
||||
if (change_comment)
|
||||
do_change_comment(pw);
|
||||
if (convert_to_ssh2)
|
||||
do_convert_to_ssh2(pw);
|
||||
if (convert_from_ssh2)
|
||||
do_convert_from_ssh2(pw);
|
||||
if (print_public)
|
||||
do_print_public(pw);
|
||||
|
||||
arc4random_stir();
|
||||
|
||||
if (quiet)
|
||||
rsa_set_verbose(0);
|
||||
|
||||
/* Generate the rsa key pair. */
|
||||
private_key = RSA_new();
|
||||
public_key = RSA_new();
|
||||
rsa_generate_key(private_key, public_key, bits);
|
||||
if (dsa_mode != 0) {
|
||||
if (!quiet)
|
||||
printf("Generating DSA parameter and key.\n");
|
||||
public = private = dsa_generate_key(bits);
|
||||
if (private == NULL) {
|
||||
fprintf(stderr, "dsa_generate_keys failed");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if (quiet)
|
||||
rsa_set_verbose(0);
|
||||
/* Generate the rsa key pair. */
|
||||
public = key_new(KEY_RSA);
|
||||
private = key_new(KEY_RSA);
|
||||
rsa_generate_key(private->rsa, public->rsa, bits);
|
||||
}
|
||||
|
||||
if (!have_identity)
|
||||
ask_filename(pw, "Enter file in which to save the key");
|
||||
@ -509,17 +694,13 @@ passphrase_again:
|
||||
strlcpy(comment, identity_comment, sizeof(comment));
|
||||
} else {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Save the key with the given passphrase and comment. */
|
||||
if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
|
||||
if (!save_private_key(identity_file, passphrase1, private, comment)) {
|
||||
printf("Saving the key failed: %s: %s.\n",
|
||||
identity_file, strerror(errno));
|
||||
identity_file, strerror(errno));
|
||||
memset(passphrase1, 0, strlen(passphrase1));
|
||||
xfree(passphrase1);
|
||||
exit(1);
|
||||
@ -529,7 +710,9 @@ passphrase_again:
|
||||
xfree(passphrase1);
|
||||
|
||||
/* Clear the private key and the random number generator. */
|
||||
RSA_free(private_key);
|
||||
if (private != public) {
|
||||
key_free(private);
|
||||
}
|
||||
arc4random_stir();
|
||||
|
||||
if (!quiet)
|
||||
@ -541,21 +724,18 @@ passphrase_again:
|
||||
printf("Could not save your public key in %s\n", identity_file);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d ", BN_num_bits(public_key->n));
|
||||
tmpbuf = BN_bn2dec(public_key->e);
|
||||
fprintf(f, "%s ", tmpbuf);
|
||||
free(tmpbuf);
|
||||
tmpbuf = BN_bn2dec(public_key->n);
|
||||
fprintf(f, "%s %s\n", tmpbuf, comment);
|
||||
free(tmpbuf);
|
||||
if (!key_write(public, f))
|
||||
fprintf(stderr, "write key failed");
|
||||
fprintf(f, " %s\n", comment);
|
||||
fclose(f);
|
||||
|
||||
if (!quiet) {
|
||||
printf("Your public key has been saved in %s.\n", identity_file);
|
||||
printf("Your public key has been saved in %s.\n",
|
||||
identity_file);
|
||||
printf("The key fingerprint is:\n");
|
||||
printf("%d %s %s\n", BN_num_bits(public_key->n),
|
||||
fingerprint(public_key->e, public_key->n),
|
||||
comment);
|
||||
printf("%s %s\n", key_fingerprint(public), comment);
|
||||
}
|
||||
|
||||
key_free(public);
|
||||
exit(0);
|
||||
}
|
||||
|
65
ssh.c
65
ssh.c
@ -11,7 +11,11 @@
|
||||
*/
|
||||
|
||||
#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 "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 "compat.h"
|
||||
#include "channels.h"
|
||||
#include "key.h"
|
||||
#include "authfile.h"
|
||||
|
||||
#ifdef HAVE___PROGNAME
|
||||
extern char *__progname;
|
||||
@ -358,10 +364,16 @@ main(int ac, char **av)
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
exit(1);
|
||||
if (ciphers_valid(optarg)) {
|
||||
/* SSH2 only */
|
||||
options.ciphers = xstrdup(optarg);
|
||||
} else {
|
||||
/* SSH1 only */
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
@ -417,16 +429,11 @@ main(int ac, char **av)
|
||||
if (!host)
|
||||
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. */
|
||||
buffer_init(&command);
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -496,6 +503,20 @@ main(int ac, char **av)
|
||||
/* reinit */
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
||||
|
||||
/* check if RSA support exists */
|
||||
if ((options.protocol & SSH_PROTO_1) &&
|
||||
rsa_alive() == 0) {
|
||||
log("%s: no RSA support in libssl and libcrypto. See ssl(8).",
|
||||
__progname);
|
||||
log("Disabling protocol version 1");
|
||||
options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
|
||||
}
|
||||
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
|
||||
fprintf(stderr, "%s: No protocol version available.\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (options.user == NULL)
|
||||
options.user = xstrdup(pw->pw_name);
|
||||
|
||||
@ -562,9 +583,12 @@ main(int ac, char **av)
|
||||
* authentication. This must be done before releasing extra
|
||||
* privileges, because the file is only readable by root.
|
||||
*/
|
||||
if (ok) {
|
||||
if (ok && (options.protocol & SSH_PROTO_1)) {
|
||||
Key k;
|
||||
host_private_key = RSA_new();
|
||||
if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
|
||||
k.type = KEY_RSA;
|
||||
k.rsa = host_private_key;
|
||||
if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
|
||||
host_private_key_loaded = 1;
|
||||
}
|
||||
/*
|
||||
@ -610,15 +634,22 @@ main(int ac, char **av)
|
||||
exit(1);
|
||||
}
|
||||
/* Expand ~ in options.identity_files. */
|
||||
/* XXX mem-leaks */
|
||||
for (i = 0; i < options.num_identity_files; i++)
|
||||
options.identity_files[i] =
|
||||
tilde_expand_filename(options.identity_files[i], original_real_uid);
|
||||
|
||||
for (i = 0; i < options.num_identity_files2; i++)
|
||||
options.identity_files2[i] =
|
||||
tilde_expand_filename(options.identity_files2[i], original_real_uid);
|
||||
/* Expand ~ in known host file names. */
|
||||
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
|
||||
original_real_uid);
|
||||
original_real_uid);
|
||||
options.user_hostfile = tilde_expand_filename(options.user_hostfile,
|
||||
original_real_uid);
|
||||
original_real_uid);
|
||||
options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2,
|
||||
original_real_uid);
|
||||
options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2,
|
||||
original_real_uid);
|
||||
|
||||
/* Log into the remote system. This never returns if the login fails. */
|
||||
ssh_login(host_private_key_loaded, host_private_key,
|
||||
|
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
|
||||
#define SSH_H
|
||||
@ -88,6 +88,7 @@
|
||||
* world-readable.
|
||||
*/
|
||||
#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts"
|
||||
#define SSH_SYSTEM_HOSTFILE2 ETCDIR "/ssh_known_hosts2"
|
||||
|
||||
/*
|
||||
* Of these, ssh_host_key must be readable only by root, whereas ssh_config
|
||||
@ -96,7 +97,7 @@
|
||||
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
|
||||
#define SERVER_CONFIG_FILE ETCDIR "/sshd_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
|
||||
#define SSH_PROGRAM "/usr/bin/ssh"
|
||||
@ -128,6 +129,7 @@
|
||||
* contain anything particularly secret.
|
||||
*/
|
||||
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
|
||||
#define SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
|
||||
|
||||
/*
|
||||
* Name of the default file containing client-side authentication key. This
|
||||
@ -152,6 +154,7 @@
|
||||
* running as root.)
|
||||
*/
|
||||
#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys"
|
||||
#define SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2"
|
||||
|
||||
/*
|
||||
* Per-user and system-wide ssh "rc" files. These files are executed with
|
||||
@ -407,36 +410,6 @@ int auth_rsa_challenge_dialog(RSA *pk);
|
||||
*/
|
||||
char *read_passphrase(const char *prompt, int from_stdin);
|
||||
|
||||
/*
|
||||
* Saves the authentication (private) key in a file, encrypting it with
|
||||
* passphrase. The identification of the file (lowest 64 bits of n) will
|
||||
* precede the key to provide identification of the key without needing a
|
||||
* passphrase.
|
||||
*/
|
||||
int
|
||||
save_private_key(const char *filename, const char *passphrase,
|
||||
RSA * private_key, const char *comment);
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file (public key and comment). Returns 0
|
||||
* if an error occurred; zero if the public key was successfully read. The
|
||||
* comment of the key is returned in comment_return if it is non-NULL; the
|
||||
* caller must free the value with xfree.
|
||||
*/
|
||||
int
|
||||
load_public_key(const char *filename, RSA * pub,
|
||||
char **comment_return);
|
||||
|
||||
/*
|
||||
* Loads the private key from the file. Returns 0 if an error is encountered
|
||||
* (file does not exist or is not readable, or passphrase is bad). This
|
||||
* initializes the private key. The comment of the key is returned in
|
||||
* comment_return if it is non-NULL; the caller must free the value with
|
||||
* xfree.
|
||||
*/
|
||||
int
|
||||
load_private_key(const char *filename, const char *passphrase,
|
||||
RSA * private_key, char **comment_return);
|
||||
|
||||
/*------------ Definitions for logging. -----------------------*/
|
||||
|
||||
|
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"
|
||||
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 "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 "myproposal.h"
|
||||
#include "authfile.h"
|
||||
|
||||
#ifdef LIBWRAP
|
||||
#include <tcpd.h>
|
||||
@ -112,8 +113,9 @@ char *server_version_string = NULL;
|
||||
* not very useful. Currently, memory locking is not implemented.
|
||||
*/
|
||||
struct {
|
||||
RSA *private_key; /* Private part of server key. */
|
||||
RSA *private_key; /* Private part of empheral server key. */
|
||||
RSA *host_key; /* Private part of host key. */
|
||||
Key *dsa_host_key; /* Private DSA host key. */
|
||||
} sensitive_data;
|
||||
|
||||
/*
|
||||
@ -132,6 +134,10 @@ RSA *public_key;
|
||||
/* session identifier, used by RSA-auth */
|
||||
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. */
|
||||
void do_ssh1_kex();
|
||||
void do_ssh2_kex();
|
||||
@ -224,6 +230,7 @@ grace_alarm_handler(int sig)
|
||||
* Thus there should be no concurrency control/asynchronous execution
|
||||
* problems.
|
||||
*/
|
||||
/* XXX do we really want this work to be done in a signal handler ? -m */
|
||||
void
|
||||
key_regeneration_alarm(int sig)
|
||||
{
|
||||
@ -344,6 +351,13 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
||||
mismatch = 0;
|
||||
switch(remote_major) {
|
||||
case 1:
|
||||
if (remote_minor == 99) {
|
||||
if (options.protocol & SSH_PROTO_2)
|
||||
enable_compat20();
|
||||
else
|
||||
mismatch = 1;
|
||||
break;
|
||||
}
|
||||
if (!(options.protocol & SSH_PROTO_1)) {
|
||||
mismatch = 1;
|
||||
break;
|
||||
@ -355,12 +369,6 @@ sshd_exchange_identification(int sock_in, int sock_out)
|
||||
/* note that this disables agent-forwarding */
|
||||
enable_compat13();
|
||||
}
|
||||
if (remote_minor == 99) {
|
||||
if (options.protocol & SSH_PROTO_2)
|
||||
enable_compat20();
|
||||
else
|
||||
mismatch = 1;
|
||||
}
|
||||
break;
|
||||
case 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);
|
||||
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;
|
||||
pid_t pid;
|
||||
socklen_t fromlen;
|
||||
int silentrsa = 0;
|
||||
int silent = 0;
|
||||
fd_set *fdset;
|
||||
struct sockaddr_storage from;
|
||||
const char *remote_ip;
|
||||
int remote_port;
|
||||
char *comment;
|
||||
FILE *f;
|
||||
struct linger linger;
|
||||
struct addrinfo *ai;
|
||||
@ -441,7 +462,7 @@ main(int ac, char **av)
|
||||
inetd_flag = 1;
|
||||
break;
|
||||
case 'Q':
|
||||
silentrsa = 1;
|
||||
silent = 1;
|
||||
break;
|
||||
case 'q':
|
||||
options.log_level = SYSLOG_LEVEL_QUIET;
|
||||
@ -497,27 +518,14 @@ main(int ac, char **av)
|
||||
log_init(av0,
|
||||
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
|
||||
options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
|
||||
!inetd_flag);
|
||||
!silent && !inetd_flag);
|
||||
|
||||
/* check if RSA support exists */
|
||||
if (rsa_alive() == 0) {
|
||||
if (silentrsa == 0)
|
||||
printf("sshd: no RSA support in libssl and libcrypto -- exiting. See ssl(8)\n");
|
||||
log("no RSA support in libssl and libcrypto -- exiting. See ssl(8)");
|
||||
exit(1);
|
||||
}
|
||||
/* Read server configuration options from the configuration file. */
|
||||
read_server_config(&options, config_file_name);
|
||||
|
||||
/* Fill in default values for those options not explicitly set. */
|
||||
fill_default_server_options(&options);
|
||||
|
||||
/* Check certain values for sanity. */
|
||||
if (options.server_key_bits < 512 ||
|
||||
options.server_key_bits > 32768) {
|
||||
fprintf(stderr, "Bad server key size.\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Check that there are no remaining arguments. */
|
||||
if (optind < ac) {
|
||||
fprintf(stderr, "Extra argument %s.\n", av[optind]);
|
||||
@ -526,26 +534,79 @@ main(int ac, char **av)
|
||||
|
||||
debug("sshd version %.100s", SSH_VERSION);
|
||||
|
||||
sensitive_data.host_key = RSA_new();
|
||||
errno = 0;
|
||||
/* Load the host key. It must have empty passphrase. */
|
||||
if (!load_private_key(options.host_key_file, "",
|
||||
sensitive_data.host_key, &comment)) {
|
||||
error("Could not load host key: %.200s: %.100s",
|
||||
options.host_key_file, strerror(errno));
|
||||
sensitive_data.dsa_host_key = NULL;
|
||||
sensitive_data.host_key = NULL;
|
||||
|
||||
/* check if RSA support exists */
|
||||
if ((options.protocol & SSH_PROTO_1) &&
|
||||
rsa_alive() == 0) {
|
||||
log("no RSA support in libssl and libcrypto. See ssl(8)");
|
||||
log("Disabling protocol version 1");
|
||||
options.protocol &= ~SSH_PROTO_1;
|
||||
}
|
||||
/* Load the RSA/DSA host key. It must have empty passphrase. */
|
||||
if (options.protocol & SSH_PROTO_1) {
|
||||
Key k;
|
||||
sensitive_data.host_key = RSA_new();
|
||||
k.type = KEY_RSA;
|
||||
k.rsa = sensitive_data.host_key;
|
||||
errno = 0;
|
||||
if (!load_private_key(options.host_key_file, "", &k, NULL)) {
|
||||
error("Could not load host key: %.200s: %.100s",
|
||||
options.host_key_file, strerror(errno));
|
||||
log("Disabling protocol version 1");
|
||||
options.protocol &= ~SSH_PROTO_1;
|
||||
}
|
||||
k.rsa = NULL;
|
||||
}
|
||||
if (options.protocol & SSH_PROTO_2) {
|
||||
sensitive_data.dsa_host_key = key_new(KEY_DSA);
|
||||
if (!load_private_key(options.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);
|
||||
}
|
||||
xfree(comment);
|
||||
|
||||
/* Initialize the log (it is reinitialized below in case we
|
||||
forked). */
|
||||
/* Check certain values for sanity. */
|
||||
if (options.protocol & SSH_PROTO_1) {
|
||||
if (options.server_key_bits < 512 ||
|
||||
options.server_key_bits > 32768) {
|
||||
fprintf(stderr, "Bad server key size.\n");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* Check that server and host key lengths differ sufficiently. This
|
||||
* is necessary to make double encryption work with rsaref. Oh, I
|
||||
* hate software patents. I dont know if this can go? Niels
|
||||
*/
|
||||
if (options.server_key_bits >
|
||||
BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
|
||||
options.server_key_bits <
|
||||
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
|
||||
options.server_key_bits =
|
||||
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
|
||||
debug("Forcing server key to %d bits to make it differ from host key.",
|
||||
options.server_key_bits);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the log (it is reinitialized below in case we forked). */
|
||||
if (debug_flag && !inetd_flag)
|
||||
log_stderr = 1;
|
||||
log_init(av0, options.log_level, options.log_facility, log_stderr);
|
||||
|
||||
/* If not in debugging mode, and not started from inetd,
|
||||
disconnect from the controlling terminal, and fork. The
|
||||
original process exits. */
|
||||
/*
|
||||
* If not in debugging mode, and not started from inetd, disconnect
|
||||
* from the controlling terminal, and fork. The original process
|
||||
* exits.
|
||||
*/
|
||||
if (!debug_flag && !inetd_flag) {
|
||||
#ifdef TIOCNOTTY
|
||||
int fd;
|
||||
@ -565,18 +626,6 @@ main(int ac, char **av)
|
||||
/* Reinitialize the log (because of the fork above). */
|
||||
log_init(av0, options.log_level, options.log_facility, log_stderr);
|
||||
|
||||
/* Check that server and host key lengths differ sufficiently.
|
||||
This is necessary to make double encryption work with rsaref.
|
||||
Oh, I hate software patents. I dont know if this can go? Niels */
|
||||
if (options.server_key_bits >
|
||||
BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&
|
||||
options.server_key_bits <
|
||||
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {
|
||||
options.server_key_bits =
|
||||
BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;
|
||||
debug("Forcing server key to %d bits to make it differ from host key.",
|
||||
options.server_key_bits);
|
||||
}
|
||||
/* Do not display messages to stdout in RSA code. */
|
||||
rsa_set_verbose(0);
|
||||
|
||||
@ -594,20 +643,22 @@ main(int ac, char **av)
|
||||
s2 = dup(s1);
|
||||
sock_in = dup(0);
|
||||
sock_out = dup(1);
|
||||
/* We intentionally do not close the descriptors 0, 1, and 2
|
||||
as our code for setting the descriptors won\'t work
|
||||
if ttyfd happens to be one of those. */
|
||||
/*
|
||||
* We intentionally do not close the descriptors 0, 1, and 2
|
||||
* as our code for setting the descriptors won\'t work if
|
||||
* ttyfd happens to be one of those.
|
||||
*/
|
||||
debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);
|
||||
|
||||
public_key = RSA_new();
|
||||
sensitive_data.private_key = RSA_new();
|
||||
|
||||
/* XXX check options.protocol */
|
||||
log("Generating %d bit RSA key.", options.server_key_bits);
|
||||
rsa_generate_key(sensitive_data.private_key, public_key,
|
||||
options.server_key_bits);
|
||||
arc4random_stir();
|
||||
log("RSA key generation complete.");
|
||||
if (options.protocol & SSH_PROTO_1) {
|
||||
public_key = RSA_new();
|
||||
sensitive_data.private_key = RSA_new();
|
||||
log("Generating %d bit RSA key.", options.server_key_bits);
|
||||
rsa_generate_key(sensitive_data.private_key, public_key,
|
||||
options.server_key_bits);
|
||||
arc4random_stir();
|
||||
log("RSA key generation complete.");
|
||||
}
|
||||
} else {
|
||||
for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
|
||||
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
|
||||
@ -684,19 +735,20 @@ main(int ac, char **av)
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
if (options.protocol & SSH_PROTO_1) {
|
||||
public_key = RSA_new();
|
||||
sensitive_data.private_key = RSA_new();
|
||||
|
||||
public_key = RSA_new();
|
||||
sensitive_data.private_key = RSA_new();
|
||||
log("Generating %d bit RSA key.", options.server_key_bits);
|
||||
rsa_generate_key(sensitive_data.private_key, public_key,
|
||||
options.server_key_bits);
|
||||
arc4random_stir();
|
||||
log("RSA key generation complete.");
|
||||
|
||||
log("Generating %d bit RSA key.", options.server_key_bits);
|
||||
rsa_generate_key(sensitive_data.private_key, public_key,
|
||||
options.server_key_bits);
|
||||
arc4random_stir();
|
||||
log("RSA key generation complete.");
|
||||
|
||||
/* Schedule server key regeneration alarm. */
|
||||
signal(SIGALRM, key_regeneration_alarm);
|
||||
alarm(options.key_regeneration_time);
|
||||
/* Schedule server key regeneration alarm. */
|
||||
signal(SIGALRM, key_regeneration_alarm);
|
||||
alarm(options.key_regeneration_time);
|
||||
}
|
||||
|
||||
/* Arrange to restart on SIGHUP. The handler needs listen_sock. */
|
||||
signal(SIGHUP, sighup_handler);
|
||||
@ -1069,9 +1121,7 @@ do_ssh1_kex()
|
||||
sensitive_data.private_key->n);
|
||||
|
||||
/* Destroy the private and public keys. They will no longer be needed. */
|
||||
RSA_free(public_key);
|
||||
RSA_free(sensitive_data.private_key);
|
||||
RSA_free(sensitive_data.host_key);
|
||||
destroy_sensitive_data();
|
||||
|
||||
/*
|
||||
* Extract session key from the decrypted integer. The key is in the
|
||||
@ -1130,7 +1180,6 @@ do_ssh2_kex()
|
||||
unsigned char *kbuf;
|
||||
unsigned char *hash;
|
||||
Kex *kex;
|
||||
Key *server_host_key;
|
||||
char *cprop[PROPOSAL_MAX];
|
||||
char *sprop[PROPOSAL_MAX];
|
||||
|
||||
@ -1231,8 +1280,8 @@ do_ssh2_kex()
|
||||
memset(kbuf, 0, klen);
|
||||
xfree(kbuf);
|
||||
|
||||
server_host_key = dsa_get_serverkey(options.dsa_key_file);
|
||||
dsa_make_serverkey_blob(server_host_key, &server_host_key_blob, &sbloblen);
|
||||
/* XXX precompute? */
|
||||
dsa_make_key_blob(sensitive_data.dsa_host_key, &server_host_key_blob, &sbloblen);
|
||||
|
||||
/* calc H */ /* XXX depends on 'kex' */
|
||||
hash = kex_hash(
|
||||
@ -1255,10 +1304,17 @@ do_ssh2_kex()
|
||||
fprintf(stderr, "%02x", (hash[i])&0xff);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
/* save session id := H */
|
||||
/* XXX hashlen depends on KEX */
|
||||
session_id2_len = 20;
|
||||
session_id2 = xmalloc(session_id2_len);
|
||||
memcpy(session_id2, hash, session_id2_len);
|
||||
|
||||
/* sign H */
|
||||
dsa_sign(server_host_key, &signature, &slen, hash, 20);
|
||||
/* hashlen depends on KEX */
|
||||
key_free(server_host_key);
|
||||
/* XXX hashlen depends on KEX */
|
||||
dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20);
|
||||
|
||||
destroy_sensitive_data();
|
||||
|
||||
/* send server hostkey, DH pubkey 'f' and singed H */
|
||||
packet_start(SSH2_MSG_KEXDH_REPLY);
|
||||
@ -1267,6 +1323,7 @@ do_ssh2_kex()
|
||||
packet_put_string((char *)signature, slen);
|
||||
packet_send();
|
||||
xfree(signature);
|
||||
xfree(server_host_key_blob);
|
||||
packet_write_wait();
|
||||
|
||||
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