Fix conflicts for OpenSSH 2.9.

This commit is contained in:
Brian Feldman 2001-05-04 04:14:23 +00:00
parent 3ed16d1511
commit ca3176e7c8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76262
49 changed files with 5819 additions and 4457 deletions

View File

@ -24,6 +24,7 @@
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $"); RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
RCSID("$FreeBSD$");
#include "auth.h" #include "auth.h"
#include "log.h" #include "log.h"
@ -69,14 +70,14 @@ verify_response(Authctxt *authctxt, char *response)
} }
#else #else
#ifdef SKEY #ifdef SKEY
#include <skey.h> #include <opie.h>
char * char *
get_challenge(Authctxt *authctxt, char *devs) get_challenge(Authctxt *authctxt, char *devs)
{ {
static char challenge[1024]; static char challenge[1024];
struct skey skey; struct opie opie;
if (skeychallenge(&skey, authctxt->user, challenge) == -1) if (opiechallenge(&opie, authctxt->user, challenge) == -1)
return NULL; return NULL;
strlcat(challenge, "\nS/Key Password: ", sizeof challenge); strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
return challenge; return challenge;
@ -85,8 +86,8 @@ int
verify_response(Authctxt *authctxt, char *response) verify_response(Authctxt *authctxt, char *response)
{ {
return (authctxt->valid && return (authctxt->valid &&
skey_haskey(authctxt->pw->pw_name) == 0 && opie_haskey(authctxt->pw->pw_name) == 0 &&
skey_passcheck(authctxt->pw->pw_name, response) != -1); opie_passverify(authctxt->pw->pw_name, response) != -1);
} }
#else #else
/* not available */ /* not available */

View File

@ -23,13 +23,20 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.23 2001/01/22 08:15:00 markus Exp $");
RCSID("$FreeBSD$");
#include "ssh.h"
#include "ssh1.h"
#include "packet.h" #include "packet.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "log.h"
#include "servconf.h" #include "servconf.h"
#include "auth.h"
RCSID("$OpenBSD: auth-krb4.c,v 1.19 2000/10/03 18:03:02 markus Exp $"); #ifdef AFS
RCSID("$FreeBSD$"); #include "radix.h"
#endif
#ifdef KRB4 #ifdef KRB4
char *ticket = NULL; char *ticket = NULL;
@ -47,7 +54,7 @@ auth_krb4_password(struct passwd * pw, const char *password)
AUTH_DAT adata; AUTH_DAT adata;
KTEXT_ST tkt; KTEXT_ST tkt;
struct hostent *hp; struct hostent *hp;
unsigned long faddr; u_long faddr;
char localhost[MAXHOSTNAMELEN]; char localhost[MAXHOSTNAMELEN];
char phost[INST_SZ]; char phost[INST_SZ];
char realm[REALM_SZ]; char realm[REALM_SZ];

View File

@ -11,30 +11,7 @@
* incompatible with the protocol description in the RFC file, it must be * incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
* *
*
* Copyright (c) 1999 Dug Song. All rights reserved. * Copyright (c) 1999 Dug Song. 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.
*
* 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.
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -59,39 +36,41 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth-passwd.c,v 1.18 2000/10/03 18:03:03 markus Exp $"); RCSID("$OpenBSD: auth-passwd.c,v 1.22 2001/03/20 18:57:04 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "ssh.h"
#include "servconf.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
extern ServerOptions options;
/* /*
* Tries to authenticate the user using password. Returns true if * Tries to authenticate the user using password. Returns true if
* authentication succeeds. * authentication succeeds.
*/ */
int int
auth_password(struct passwd * pw, const char *password) auth_password(Authctxt *authctxt, const char *password)
{ {
extern ServerOptions options; struct passwd * pw = authctxt->pw;
char *encrypted_password; char *encrypted_password;
/* deny if no user. */ /* deny if no user. */
if (pw == NULL) if (pw == NULL)
return 0; return 0;
if (pw->pw_uid == 0 && options.permit_root_login == 2) if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
return 0; return 0;
if (*password == '\0' && options.permit_empty_passwd == 0) if (*password == '\0' && options.permit_empty_passwd == 0)
return 0; return 0;
#ifdef BSD_AUTH
#ifdef SKEY_VIA_PASSWD_IS_DISABLED if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
if (options.skey_authentication == 1) { (char *)password) == 0)
int ret = auth_skey_password(pw, password); return 0;
if (ret == 1 || ret == 0) else
return ret; return 1;
/* Fall back to ordinary passwd authentication. */
}
#endif #endif
#ifdef KRB5 #ifdef KRB5
if (options.kerberos_authentication == 1) { if (options.kerberos_authentication == 1) {

View File

@ -13,19 +13,20 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth-rh-rsa.c,v 1.17 2000/10/03 18:03:03 markus Exp $"); RCSID("$OpenBSD: auth-rh-rsa.c,v 1.23 2001/04/06 21:00:04 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "uidswap.h" #include "uidswap.h"
#include "log.h"
#include "servconf.h" #include "servconf.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "key.h" #include "key.h"
#include "hostfile.h" #include "hostfile.h"
#include "pathnames.h"
#include "auth.h"
#include "tildexpand.h"
#include "canohost.h"
/* /*
* Tries to authenticate the user using the .rhosts file and the host using * Tries to authenticate the user using the .rhosts file and the host using
@ -49,26 +50,27 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
if (!auth_rhosts(pw, client_user)) if (!auth_rhosts(pw, client_user))
return 0; return 0;
canonical_hostname = get_canonical_hostname(); canonical_hostname = get_canonical_hostname(
options.reverse_mapping_check);
debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname);
/* wrap the RSA key into a 'generic' key */ /* wrap the RSA key into a 'generic' key */
client_key = key_new(KEY_RSA); client_key = key_new(KEY_RSA1);
BN_copy(client_key->rsa->e, client_host_key->e); BN_copy(client_key->rsa->e, client_host_key->e);
BN_copy(client_key->rsa->n, client_host_key->n); BN_copy(client_key->rsa->n, client_host_key->n);
found = key_new(KEY_RSA); found = key_new(KEY_RSA1);
/* Check if we know the host and its host key. */ /* Check if we know the host and its host key. */
host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE, canonical_hostname,
client_key, found); client_key, found, NULL);
/* Check user host file unless ignored. */ /* Check user host file unless ignored. */
if (host_status != HOST_OK && !options.ignore_user_known_hosts) { if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
struct stat st; struct stat st;
char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid); char *user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
/* /*
* Check file permissions of SSH_USER_HOSTFILE, auth_rsa() * Check file permissions of _PATH_SSH_USER_HOSTFILE, auth_rsa()
* did already check pw->pw_dir, but there is a race XXX * did already check pw->pw_dir, but there is a race XXX
*/ */
if (options.strict_modes && if (options.strict_modes &&
@ -79,9 +81,9 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
pw->pw_name, user_hostfile); pw->pw_name, user_hostfile);
} else { } else {
/* XXX race between stat and the following open() */ /* XXX race between stat and the following open() */
temporarily_use_uid(pw->pw_uid); temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile, canonical_hostname, host_status = check_host_in_hostfile(user_hostfile, canonical_hostname,
client_key, found); client_key, found, NULL);
restore_uid(); restore_uid();
} }
xfree(user_hostfile); xfree(user_hostfile);

View File

@ -14,22 +14,24 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth-rsa.c,v 1.32 2000/10/14 12:19:45 markus Exp $"); RCSID("$OpenBSD: auth-rsa.c,v 1.40 2001/04/06 21:00:07 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "rsa.h"
#include "packet.h"
#include "xmalloc.h"
#include "ssh.h"
#include "mpaux.h"
#include "uidswap.h"
#include "match.h"
#include "servconf.h"
#include "auth-options.h"
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/md5.h> #include <openssl/md5.h>
#include "rsa.h"
#include "packet.h"
#include "xmalloc.h"
#include "ssh1.h"
#include "mpaux.h"
#include "uidswap.h"
#include "match.h"
#include "auth-options.h"
#include "pathnames.h"
#include "log.h"
#include "servconf.h"
#include "auth.h"
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
@ -38,7 +40,7 @@ extern ServerOptions options;
* Session identifier that is used to bind key exchange and authentication * Session identifier that is used to bind key exchange and authentication
* responses to a particular session. * responses to a particular session.
*/ */
extern unsigned char session_id[16]; extern u_char session_id[16];
/* /*
* The .ssh/authorized_keys file contains public keys, one per line, in the * The .ssh/authorized_keys file contains public keys, one per line, in the
@ -61,9 +63,9 @@ auth_rsa_challenge_dialog(RSA *pk)
{ {
BIGNUM *challenge, *encrypted_challenge; BIGNUM *challenge, *encrypted_challenge;
BN_CTX *ctx; BN_CTX *ctx;
unsigned char buf[32], mdbuf[16], response[16]; u_char buf[32], mdbuf[16], response[16];
MD5_CTX md; MD5_CTX md;
unsigned int i; u_int i;
int plen, len; int plen, len;
encrypted_challenge = BN_new(); encrypted_challenge = BN_new();
@ -121,11 +123,11 @@ auth_rsa_challenge_dialog(RSA *pk)
int int
auth_rsa(struct passwd *pw, BIGNUM *client_n) auth_rsa(struct passwd *pw, BIGNUM *client_n)
{ {
char line[8192], file[1024]; char line[8192], file[MAXPATHLEN];
int authenticated; int authenticated;
unsigned int bits; u_int bits;
FILE *f; FILE *f;
unsigned long linenum = 0; u_long linenum = 0;
struct stat st; struct stat st;
RSA *pk; RSA *pk;
@ -134,11 +136,11 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
return 0; return 0;
/* Temporarily use the user's uid. */ /* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid); temporarily_use_uid(pw);
/* The authorized keys. */ /* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
SSH_USER_PERMITTED_KEYS); _PATH_SSH_USER_PERMITTED_KEYS);
/* Fail quietly if file does not exist */ /* Fail quietly if file does not exist */
if (stat(file, &st) < 0) { if (stat(file, &st) < 0) {
@ -166,10 +168,10 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
"bad ownership or modes for '%s'.", pw->pw_name, file); "bad ownership or modes for '%s'.", pw->pw_name, file);
fail = 1; fail = 1;
} else { } else {
/* Check path to SSH_USER_PERMITTED_KEYS */ /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i; int i;
static const char *check[] = { static const char *check[] = {
"", SSH_USER_DIR, NULL "", _PATH_SSH_USER_DIR, NULL
}; };
for (i = 0; check[i]; i++) { for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]); snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]);
@ -185,8 +187,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
} }
if (fail) { if (fail) {
fclose(f); fclose(f);
log("%s",buf); log("%s", buf);
packet_send_debug("%s",buf); packet_send_debug("%s", buf);
restore_uid(); restore_uid();
return 0; return 0;
} }
@ -232,19 +234,13 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
} }
} else } else
options = NULL; options = NULL;
/*
* If our options do not allow this key to be used,
* do not send challenge.
*/
if (!auth_parse_options(pw, options, linenum))
continue;
/* Parse the key from the line. */ /* Parse the key from the line. */
if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) { if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
debug("%.100s, line %lu: bad key syntax", debug("%.100s, line %lu: bad key syntax",
SSH_USER_PERMITTED_KEYS, linenum); file, linenum);
packet_send_debug("%.100s, line %lu: bad key syntax", packet_send_debug("%.100s, line %lu: bad key syntax",
SSH_USER_PERMITTED_KEYS, linenum); file, linenum);
continue; continue;
} }
/* cp now points to the comment part. */ /* cp now points to the comment part. */
@ -260,6 +256,12 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
file, linenum, BN_num_bits(pk->n), bits); file, linenum, BN_num_bits(pk->n), bits);
/* We have found the desired key. */ /* We have found the desired key. */
/*
* If our options do not allow this key to be used,
* do not send challenge.
*/
if (!auth_parse_options(pw, options, file, linenum))
continue;
/* Perform the challenge-response dialog for this key. */ /* Perform the challenge-response dialog for this key. */
if (!auth_rsa_challenge_dialog(pk)) { if (!auth_rsa_challenge_dialog(pk)) {

View File

@ -1,15 +1,5 @@
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 2000 Markus Friedl. All rights reserved.
* All rights reserved
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -33,35 +23,27 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth.c,v 1.11 2000/10/11 20:27:23 markus Exp $"); RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h"
#include "ssh.h"
#include "pty.h"
#include "packet.h"
#include "buffer.h"
#include "mpaux.h"
#include "servconf.h"
#include "compat.h"
#include "channels.h"
#include "match.h" #include "match.h"
#include "groupaccess.h"
#include "bufaux.h" #include "log.h"
#include "ssh2.h" #include "servconf.h"
#include "auth.h" #include "auth.h"
#include "session.h" #include "auth-options.h"
#include "canohost.h"
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
/* /*
* Check if the user is allowed to log in via ssh. If user is listed in * Check if the user is allowed to log in via ssh. If user is listed
* DenyUsers or user's primary group is listed in DenyGroups, false will * in DenyUsers or one of user's groups is listed in DenyGroups, false
* be returned. If AllowUsers isn't empty and user isn't listed there, or * will be returned. If AllowUsers isn't empty and user isn't listed
* if AllowGroups isn't empty and user isn't listed there, false will be * there, or if AllowGroups isn't empty and one of user's groups isn't
* returned. * listed there, false will be returned.
* If the user's shell is not executable, false will be returned. * If the user's shell is not executable, false will be returned.
* Otherwise true is returned. * Otherwise true is returned.
*/ */
@ -69,12 +51,11 @@ int
allowed_user(struct passwd * pw) allowed_user(struct passwd * pw)
{ {
struct stat st; struct stat st;
struct group *grp;
char *shell; char *shell;
int i; int i;
/* Shouldn't be called if pw is NULL, but better safe than sorry... */ /* Shouldn't be called if pw is NULL, but better safe than sorry... */
if (!pw) if (!pw || !pw->pw_name)
return 0; return 0;
/* /*
@ -91,16 +72,12 @@ allowed_user(struct passwd * pw)
/* Return false if user is listed in DenyUsers */ /* Return false if user is listed in DenyUsers */
if (options.num_deny_users > 0) { if (options.num_deny_users > 0) {
if (!pw->pw_name)
return 0;
for (i = 0; i < options.num_deny_users; i++) for (i = 0; i < options.num_deny_users; i++)
if (match_pattern(pw->pw_name, options.deny_users[i])) if (match_pattern(pw->pw_name, options.deny_users[i]))
return 0; return 0;
} }
/* Return false if AllowUsers isn't empty and user isn't listed there */ /* Return false if AllowUsers isn't empty and user isn't listed there */
if (options.num_allow_users > 0) { if (options.num_allow_users > 0) {
if (!pw->pw_name)
return 0;
for (i = 0; i < options.num_allow_users; i++) for (i = 0; i < options.num_allow_users; i++)
if (match_pattern(pw->pw_name, options.allow_users[i])) if (match_pattern(pw->pw_name, options.allow_users[i]))
break; break;
@ -108,36 +85,91 @@ allowed_user(struct passwd * pw)
if (i >= options.num_allow_users) if (i >= options.num_allow_users)
return 0; return 0;
} }
/* Get the primary group name if we need it. Return false if it fails */
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
grp = getgrgid(pw->pw_gid); /* Get the user's group access list (primary and supplementary) */
if (!grp) if (ga_init(pw->pw_name, pw->pw_gid) == 0)
return 0; return 0;
/* Return false if user's group is listed in DenyGroups */ /* Return false if one of user's groups is listed in DenyGroups */
if (options.num_deny_groups > 0) { if (options.num_deny_groups > 0)
if (!grp->gr_name) if (ga_match(options.deny_groups,
options.num_deny_groups)) {
ga_free();
return 0; return 0;
for (i = 0; i < options.num_deny_groups; i++) }
if (match_pattern(grp->gr_name, options.deny_groups[i]))
return 0;
}
/* /*
* Return false if AllowGroups isn't empty and user's group * Return false if AllowGroups isn't empty and one of user's groups
* isn't listed there * isn't listed there
*/ */
if (options.num_allow_groups > 0) { if (options.num_allow_groups > 0)
if (!grp->gr_name) if (!ga_match(options.allow_groups,
options.num_allow_groups)) {
ga_free();
return 0; return 0;
for (i = 0; i < options.num_allow_groups; i++) }
if (match_pattern(grp->gr_name, options.allow_groups[i])) ga_free();
break;
/* i < options.num_allow_groups iff we break for
loop */
if (i >= options.num_allow_groups)
return 0;
}
} }
/* We found no reason not to let this user try to log on... */ /* We found no reason not to let this user try to log on... */
return 1; return 1;
} }
Authctxt *
authctxt_new(void)
{
Authctxt *authctxt = xmalloc(sizeof(*authctxt));
memset(authctxt, 0, sizeof(*authctxt));
return authctxt;
}
void
auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
{
void (*authlog) (const char *fmt,...) = verbose;
char *authmsg;
/* Raise logging level */
if (authenticated == 1 ||
!authctxt->valid ||
authctxt->failures >= AUTH_FAIL_LOG ||
strcmp(method, "password") == 0)
authlog = log;
if (authctxt->postponed)
authmsg = "Postponed";
else
authmsg = authenticated ? "Accepted" : "Failed";
authlog("%s %s for %s%.100s from %.200s port %d%s",
authmsg,
method,
authctxt->valid ? "" : "illegal user ",
authctxt->valid && authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user,
get_remote_ipaddr(),
get_remote_port(),
info);
}
/*
* Check whether root logins are disallowed.
*/
int
auth_root_allowed(char *method)
{
switch (options.permit_root_login) {
case PERMIT_YES:
return 1;
break;
case PERMIT_NO_PASSWD:
if (strcmp(method, "password") != 0)
return 1;
break;
case PERMIT_FORCED_ONLY:
if (forced_command) {
log("Root login accepted for forced command.");
return 1;
}
break;
}
log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
return 0;
}

View File

@ -22,6 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $ * $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $
* $FreeBSD$
*/ */
#ifndef AUTH_H #ifndef AUTH_H
#define AUTH_H #define AUTH_H
@ -96,6 +97,15 @@ int auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n);
*/ */
int auth_rsa_challenge_dialog(RSA *pk); int auth_rsa_challenge_dialog(RSA *pk);
#ifdef KRB5
#include <krb5.h>
int auth_krb5(); /* XXX Doplnit prototypy */
int auth_krb5_tgt();
int krb5_init();
void krb5_cleanup_proc(void *ignore);
int auth_krb5_password(struct passwd *pw, const char *password);
#endif /* KRB5 */
#ifdef KRB4 #ifdef KRB4
#include <krb.h> #include <krb.h>
/* /*

View File

@ -10,19 +10,23 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth1.c,v 1.6 2000/10/11 20:27:23 markus Exp $"); RCSID("$OpenBSD: auth1.c,v 1.22 2001/03/23 12:02:49 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "ssh1.h"
#include "packet.h" #include "packet.h"
#include "buffer.h" #include "buffer.h"
#include "mpaux.h" #include "mpaux.h"
#include "log.h"
#include "servconf.h" #include "servconf.h"
#include "compat.h" #include "compat.h"
#include "auth.h" #include "auth.h"
#include "auth-pam.h"
#include "session.h" #include "session.h"
#include "canohost.h"
#include "misc.h"
#include <login_cap.h> #include <login_cap.h>
#include <security/pam_appl.h> #include <security/pam_appl.h>
@ -34,7 +38,6 @@ Also is used as an indication of succesful krb5 authentization. */
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
extern char *forced_command;
/* /*
* convert ssh auth msg type into description * convert ssh auth msg type into description
@ -52,13 +55,12 @@ get_authname(int type)
return "rhosts-rsa"; return "rhosts-rsa";
case SSH_CMSG_AUTH_RHOSTS: case SSH_CMSG_AUTH_RHOSTS:
return "rhosts"; return "rhosts";
case SSH_CMSG_AUTH_TIS:
case SSH_CMSG_AUTH_TIS_RESPONSE:
return "challenge-response";
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
case SSH_CMSG_AUTH_KERBEROS: case SSH_CMSG_AUTH_KERBEROS:
return "kerberos"; return "kerberos";
#endif
#ifdef SKEY
case SSH_CMSG_AUTH_TIS_RESPONSE:
return "s/key";
#endif #endif
} }
snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
@ -66,26 +68,23 @@ get_authname(int type)
} }
/* /*
* read packets and try to authenticate local user 'luser'. * read packets, try to authenticate the user and
* return if authentication is successfull. not that pw == NULL * return only if authentication is successful
* if the user does not exists or is not allowed to login.
* each auth method has to 'fake' authentication for nonexisting
* users.
*/ */
void void
do_authloop(struct passwd * pw, char *luser) do_authloop(Authctxt *authctxt)
{ {
int authenticated = 0; int authenticated = 0;
int attempt = 0; u_int bits;
unsigned int bits;
RSA *client_host_key; RSA *client_host_key;
BIGNUM *n; BIGNUM *n;
char *client_user, *password; char *client_user, *password;
char user[1024]; char info[1024];
unsigned int dlen; u_int dlen;
int plen, nlen, elen; int plen, nlen, elen;
unsigned int ulen; u_int ulen;
int type = 0; int type = 0;
struct passwd *pw = authctxt->pw;
void (*authlog) (const char *fmt,...) = verbose; void (*authlog) (const char *fmt,...) = verbose;
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
login_cap_t *lc; login_cap_t *lc;
@ -96,7 +95,7 @@ do_authloop(struct passwd * pw, char *luser)
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS) #if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip; const char *from_host, *from_ip;
from_host = get_canonical_hostname(); from_host = get_canonical_hostname(options.reverse_mapping_check);
from_ip = get_remote_ipaddr(); from_ip = get_remote_ipaddr();
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */ #endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
#if 0 #if 0
@ -113,6 +112,24 @@ do_authloop(struct passwd * pw, char *luser)
#endif /* KRB5 */ #endif /* KRB5 */
#endif #endif
debug("Attempting authentication for %s%.100s.",
authctxt->valid ? "" : "illegal user ", authctxt->user);
/* If the user has no password, accept authentication immediately. */
if (options.password_authentication &&
#if defined(KRB4) || defined(KRB5)
(!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
#endif
#ifdef USE_PAM
auth_pam_password(authctxt, "")
#else
auth_password(authctxt, "")
#endif
) {
auth_log(authctxt, 1, "without authentication", "");
return;
}
/* Indicate that authentication is needed. */ /* Indicate that authentication is needed. */
packet_start(SSH_SMSG_FAILURE); packet_start(SSH_SMSG_FAILURE);
packet_send(); packet_send();
@ -120,11 +137,11 @@ do_authloop(struct passwd * pw, char *luser)
client_user = NULL; client_user = NULL;
for (attempt = 1;; attempt++) { for (;;) {
/* default to fail */ /* default to fail */
authenticated = 0; authenticated = 0;
strlcpy(user, "", sizeof user); info[0] = '\0';
/* Get a packet from the client. */ /* Get a packet from the client. */
type = packet_read(&plen); type = packet_read(&plen);
@ -143,7 +160,7 @@ do_authloop(struct passwd * pw, char *luser)
char *tgt = packet_get_string(&dlen); char *tgt = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type); packet_integrity_check(plen, 4 + dlen, type);
if (!auth_krb4_tgt(pw, tgt)) if (!auth_krb4_tgt(pw, tgt))
verbose("Kerberos v4 tgt REFUSED for %s", luser); verbose("Kerberos v4 tgt REFUSED for %.100ss", authctxt->user);
xfree(tgt); xfree(tgt);
} }
continue; continue;
@ -157,7 +174,7 @@ do_authloop(struct passwd * pw, char *luser)
char *token_string = packet_get_string(&dlen); char *token_string = packet_get_string(&dlen);
packet_integrity_check(plen, 4 + dlen, type); packet_integrity_check(plen, 4 + dlen, type);
if (!auth_afs_token(pw, token_string)) if (!auth_afs_token(pw, token_string))
verbose("AFS token REFUSED for %.100s", luser); verbose("AFS token REFUSED for %.100s", authctxt->user);
xfree(token_string); xfree(token_string);
} }
continue; continue;
@ -166,35 +183,36 @@ do_authloop(struct passwd * pw, char *luser)
case SSH_CMSG_AUTH_KERBEROS: case SSH_CMSG_AUTH_KERBEROS:
if (!options.kerberos_authentication) { if (!options.kerberos_authentication) {
verbose("Kerberos authentication disabled."); verbose("Kerberos authentication disabled.");
} else { break;
unsigned int length; } else {
char *kdata = packet_get_string(&length); /* Try Kerberos authentication. */
packet_integrity_check(plen, 4 + length, type); KTEXT_ST auth;
char *tkt_user = NULL;
char *kdata = packet_get_string((u_int *) &auth.length);
packet_integrity_check(plen, 4 + auth.length, type);
/* 4 == KRB_PROT_VERSION */ if (!authctxt->valid) {
if (kdata[0] == 4) { /* Do nothing. */
#ifndef KRB4 } else if (kdata[0] == 4) { /* 4 == KRB_PROT_VERSION */
verbose("Kerberos v4 authentication disabled."); #ifdef KRB4
#else
char *tkt_user = NULL;
KTEXT_ST auth;
auth.length = length;
if (auth.length < MAX_KTXT_LEN) if (auth.length < MAX_KTXT_LEN)
memcpy(auth.dat, kdata, auth.length); memcpy(auth.dat, kdata, auth.length);
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user); authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
if (authenticated) { if (authenticated) {
snprintf(user, sizeof user, " tktuser %s", tkt_user); snprintf(info, sizeof info,
" tktuser %.100s", tkt_user);
xfree(tkt_user); xfree(tkt_user);
} }
#endif /* KRB4 */ #else
verbose("Kerberos v4 authentication disabled.");
#endif /* KRB4 */
} else { } else {
#ifndef KRB5 #ifndef KRB5
verbose("Kerberos v5 authentication disabled."); verbose("Kerberos v5 authentication disabled.");
#else #else
krb5_data k5data; krb5_data k5data;
k5data.length = length; k5data.length = auth.length;
k5data.data = kdata; k5data.data = kdata;
#if 0 #if 0
if (krb5_init_context(&ssh_context)) { if (krb5_init_context(&ssh_context)) {
@ -235,7 +253,7 @@ do_authloop(struct passwd * pw, char *luser)
/* Try to authenticate using /etc/hosts.equiv and .rhosts. */ /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
authenticated = auth_rhosts(pw, client_user); authenticated = auth_rhosts(pw, client_user);
snprintf(user, sizeof user, " ruser %s", client_user); snprintf(info, sizeof info, " ruser %.100s", client_user);
break; break;
case SSH_CMSG_AUTH_RHOSTS_RSA: case SSH_CMSG_AUTH_RHOSTS_RSA:
@ -270,7 +288,7 @@ do_authloop(struct passwd * pw, char *luser)
authenticated = auth_rhosts_rsa(pw, client_user, client_host_key); authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
RSA_free(client_host_key); RSA_free(client_host_key);
snprintf(user, sizeof user, " ruser %s", client_user); snprintf(info, sizeof info, " ruser %.100s", client_user);
break; break;
case SSH_CMSG_AUTH_RSA: case SSH_CMSG_AUTH_RSA:
@ -301,10 +319,10 @@ do_authloop(struct passwd * pw, char *luser)
#ifdef USE_PAM #ifdef USE_PAM
/* Do PAM auth with password */ /* Do PAM auth with password */
authenticated = auth_pam_password(pw, password); authenticated = auth_pam_password(authctxt, password);
#else /* !USE_PAM */ #else /* !USE_PAM */
/* Try authentication with the password. */ /* Try authentication with the password. */
authenticated = auth_password(pw, password); authenticated = auth_password(authctxt, password);
#endif /* USE_PAM */ #endif /* USE_PAM */
memset(password, 0, strlen(password)); memset(password, 0, strlen(password));
@ -347,18 +365,12 @@ do_authloop(struct passwd * pw, char *luser)
#elif defined(SKEY) #elif defined(SKEY)
case SSH_CMSG_AUTH_TIS: case SSH_CMSG_AUTH_TIS:
debug("rcvd SSH_CMSG_AUTH_TIS"); debug("rcvd SSH_CMSG_AUTH_TIS");
if (options.skey_authentication == 1) { if (options.challenge_reponse_authentication == 1) {
char *skeyinfo = pw ? opie_keyinfo(pw->pw_name) : char *challenge = get_challenge(authctxt, authctxt->style);
NULL; if (challenge != NULL) {
if (skeyinfo == NULL) { debug("sending challenge '%s'", challenge);
debug("generating fake skeyinfo for %.100s.", luser);
skeyinfo = skey_fake_keyinfo(luser);
}
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_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
packet_put_cstring(skeyinfo); packet_put_cstring(challenge);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
continue; continue;
@ -367,13 +379,12 @@ do_authloop(struct passwd * pw, char *luser)
break; break;
case SSH_CMSG_AUTH_TIS_RESPONSE: case SSH_CMSG_AUTH_TIS_RESPONSE:
debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
if (options.skey_authentication == 1) { if (options.challenge_reponse_authentication == 1) {
char *response = packet_get_string(&dlen); char *response = packet_get_string(&dlen);
debug("skey response == '%s'", response); debug("got response '%s'", response);
packet_integrity_check(plen, 4 + dlen, type); packet_integrity_check(plen, 4 + dlen, type);
authenticated = (pw != NULL && authenticated = verify_response(authctxt, response);
opie_haskey(pw->pw_name) == 0 && memset(response, 'r', dlen);
opie_passverify(pw->pw_name, response) != -1);
xfree(response); xfree(response);
} }
break; break;
@ -417,23 +428,6 @@ do_authloop(struct passwd * pw, char *luser)
log("Unknown message during authentication: type %d", type); log("Unknown message during authentication: type %d", type);
break; break;
} }
if (authenticated && pw == NULL)
fatal("internal error: authenticated for pw == NULL");
/*
* 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->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());
}
}
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
if (pw != NULL) { if (pw != NULL) {
@ -461,28 +455,28 @@ do_authloop(struct passwd * pw, char *luser)
packet_disconnect("Sorry, you are not allowed to connect."); packet_disconnect("Sorry, you are not allowed to connect.");
} }
#endif /* LOGIN_ACCESS */ #endif /* LOGIN_ACCESS */
#ifdef BSD_AUTH
if (authctxt->as) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
#endif
if (!authctxt->valid && authenticated)
fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
/* Special handling for root */
if (authenticated && authctxt->pw->pw_uid == 0 &&
!auth_root_allowed(get_authname(type)))
authenticated = 0;
if (pw != NULL && pw->pw_uid == 0) if (pw != NULL && pw->pw_uid == 0)
log("ROOT LOGIN as '%.100s' from %.100s", log("ROOT LOGIN as '%.100s' from %.100s",
pw->pw_name, get_canonical_hostname()); pw->pw_name,
get_canonical_hostname(options.reverse_mapping_check));
/* Raise logging level */ /* Log before sending the reply */
if (authenticated || auth_log(authctxt, authenticated, get_authname(type), info);
attempt == AUTH_FAIL_LOG ||
type == SSH_CMSG_AUTH_PASSWORD)
authlog = log;
authlog("%s %s for %s%.100s from %.200s port %d%s",
authenticated ? "Accepted" : "Failed",
get_authname(type),
pw ? "" : "illegal user ",
pw && pw->pw_uid == 0 ? "ROOT" : luser,
get_remote_ipaddr(),
get_remote_port(),
user);
if (authenticated)
return;
#ifdef USE_PAM #ifdef USE_PAM
if (authenticated && !do_pam_account(pw->pw_name, client_user)) if (authenticated && !do_pam_account(pw->pw_name, client_user))
@ -494,10 +488,12 @@ do_authloop(struct passwd * pw, char *luser)
client_user = NULL; client_user = NULL;
} }
if (attempt > AUTH_FAIL_MAX) if (authenticated)
packet_disconnect(AUTH_FAIL_MSG, luser); return;
if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
/* Send a message indicating that the authentication attempt failed. */
packet_start(SSH_SMSG_FAILURE); packet_start(SSH_SMSG_FAILURE);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
@ -511,10 +507,11 @@ do_authloop(struct passwd * pw, char *luser)
void void
do_authentication() do_authentication()
{ {
struct passwd *pw, pwcopy; Authctxt *authctxt;
struct passwd *pw;
int plen; int plen;
unsigned int ulen; u_int ulen;
char *user; char *user, *style = NULL;
/* Get the name of the user that we wish to log in as. */ /* Get the name of the user that we wish to log in as. */
packet_read_expect(&plen, SSH_CMSG_USER); packet_read_expect(&plen, SSH_CMSG_USER);
@ -523,39 +520,30 @@ do_authentication()
user = packet_get_string(&ulen); user = packet_get_string(&ulen);
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
setproctitle("%s", user); if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
#ifdef AFS authctxt = authctxt_new();
/* If machine has AFS, set process authentication group. */ authctxt->user = user;
if (k_hasafs()) { authctxt->style = style;
k_setpag();
k_unlog();
}
#endif /* AFS */
/* Verify that the user is a valid user. */ /* Verify that the user is a valid user. */
pw = getpwnam(user); pw = getpwnam(user);
if (pw && allowed_user(pw)) { if (pw && allowed_user(pw)) {
/* Take a copy of the returned structure. */ authctxt->valid = 1;
memset(&pwcopy, 0, sizeof(pwcopy)); pw = pwcopy(pw);
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_class = xstrdup(pw->pw_class);
pwcopy.pw_dir = xstrdup(pw->pw_dir);
pwcopy.pw_shell = xstrdup(pw->pw_shell);
pwcopy.pw_expire = pw->pw_expire;
pwcopy.pw_change = pw->pw_change;
pw = &pwcopy;
} else { } else {
debug("do_authentication: illegal user %s", user);
pw = NULL; pw = NULL;
} }
authctxt->pw = pw;
#ifdef USE_PAM #ifdef USE_PAM
if (pw != NULL) if (pw != NULL)
start_pam(pw); start_pam(pw);
#endif #endif
setproctitle("%s", pw ? user : "unknown");
/* /*
* If we are not running as root, the user must have the same uid as * If we are not running as root, the user must have the same uid as
* the server. * the server.
@ -563,33 +551,11 @@ do_authentication()
if (getuid() != 0 && pw && pw->pw_uid != getuid()) if (getuid() != 0 && pw && pw->pw_uid != getuid())
packet_disconnect("Cannot change user when server not running as root."); packet_disconnect("Cannot change user when server not running as root.");
debug("Attempting authentication for %s%.100s.", pw ? "" : "illegal user ", user); /*
* Loop until the user has been authenticated or the connection is
/* If the user has no password, accept authentication immediately. */ * closed, do_authloop() returns only if authentication is successful
if (options.password_authentication && */
#ifdef KRB5 do_authloop(authctxt);
!options.kerberos_authentication &&
#endif /* KRB5 */
#ifdef KRB4
(!options.kerberos_authentication || options.krb4_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.",
user, 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, user);
}
if (pw == NULL)
fatal("internal error, authentication successfull for user '%.100s'", user);
/* The user has been authenticated and accepted. */ /* The user has been authenticated and accepted. */
packet_start(SSH_SMSG_SUCCESS); packet_start(SSH_SMSG_SUCCESS);
@ -597,5 +563,5 @@ do_authentication()
packet_write_wait(); packet_write_wait();
/* Perform session preparation. */ /* Perform session preparation. */
do_authenticated(pw); do_authenticated(authctxt);
} }

View File

@ -23,34 +23,35 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $"); RCSID("$OpenBSD: auth2.c,v 1.56 2001/04/19 00:05:11 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include "ssh2.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "sshpty.h"
#include "pty.h"
#include "packet.h" #include "packet.h"
#include "buffer.h" #include "buffer.h"
#include "log.h"
#include "servconf.h" #include "servconf.h"
#include "compat.h" #include "compat.h"
#include "channels.h" #include "channels.h"
#include "bufaux.h" #include "bufaux.h"
#include "ssh2.h"
#include "auth.h" #include "auth.h"
#include "session.h" #include "session.h"
#include "dispatch.h" #include "dispatch.h"
#include "auth.h"
#include "key.h" #include "key.h"
#include "cipher.h"
#include "kex.h" #include "kex.h"
#include "pathnames.h"
#include "dsa.h"
#include "uidswap.h" #include "uidswap.h"
#include "auth-options.h" #include "auth-options.h"
#include "misc.h"
#include "hostfile.h"
#include "canohost.h"
#include "tildexpand.h"
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
#include <login_cap.h> #include <login_cap.h>
@ -58,7 +59,7 @@ RCSID("$FreeBSD$");
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
extern unsigned char *session_id2; extern u_char *session_id2;
extern int session_id2_len; extern int session_id2_len;
static Authctxt *x_authctxt = NULL; static Authctxt *x_authctxt = NULL;
@ -77,17 +78,21 @@ void input_service_request(int type, int plen, void *ctxt);
void input_userauth_request(int type, int plen, void *ctxt); void input_userauth_request(int type, int plen, void *ctxt);
void protocol_error(int type, int plen, void *ctxt); void protocol_error(int type, int plen, void *ctxt);
/* helper */ /* helper */
Authmethod *authmethod_lookup(const char *name); Authmethod *authmethod_lookup(const char *name);
struct passwd *pwcopy(struct passwd *pw);
int user_dsa_key_allowed(struct passwd *pw, Key *key);
char *authmethods_get(void); char *authmethods_get(void);
int user_key_allowed(struct passwd *pw, Key *key);
int
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
Key *key);
/* auth */ /* auth */
void userauth_banner(void);
void userauth_reply(Authctxt *authctxt, int authenticated);
int userauth_none(Authctxt *authctxt); int userauth_none(Authctxt *authctxt);
int userauth_passwd(Authctxt *authctxt); int userauth_passwd(Authctxt *authctxt);
int userauth_pubkey(Authctxt *authctxt); int userauth_pubkey(Authctxt *authctxt);
int userauth_hostbased(Authctxt *authctxt);
int userauth_kbdint(Authctxt *authctxt); int userauth_kbdint(Authctxt *authctxt);
Authmethod authmethods[] = { Authmethod authmethods[] = {
@ -96,13 +101,16 @@ Authmethod authmethods[] = {
&one}, &one},
{"publickey", {"publickey",
userauth_pubkey, userauth_pubkey,
&options.dsa_authentication}, &options.pubkey_authentication},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication},
{"password", {"password",
userauth_passwd, userauth_passwd,
&options.password_authentication}, &options.password_authentication},
{"keyboard-interactive",
userauth_kbdint,
&options.kbd_interactive_authentication},
{"hostbased",
userauth_hostbased,
&options.hostbased_authentication},
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
@ -113,21 +121,22 @@ Authmethod authmethods[] = {
void void
do_authentication2() do_authentication2()
{ {
Authctxt *authctxt = xmalloc(sizeof(*authctxt)); Authctxt *authctxt = authctxt_new();
memset(authctxt, 'a', sizeof(*authctxt));
authctxt->valid = 0;
authctxt->attempt = 0;
authctxt->success = 0;
x_authctxt = authctxt; /*XXX*/ x_authctxt = authctxt; /*XXX*/
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
/* turn off kerberos, not supported by SSH2 */ /* turn off kerberos, not supported by SSH2 */
options.kerberos_authentication = 0; options.kerberos_authentication = 0;
#endif #endif
/* challenge-reponse is implemented via keyboard interactive */
if (options.challenge_reponse_authentication)
options.kbd_interactive_authentication = 1;
dispatch_init(&protocol_error); dispatch_init(&protocol_error);
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
do_authenticated2(); do_authenticated(authctxt);
} }
void void
@ -144,7 +153,7 @@ void
input_service_request(int type, int plen, void *ctxt) input_service_request(int type, int plen, void *ctxt)
{ {
Authctxt *authctxt = ctxt; Authctxt *authctxt = ctxt;
unsigned int len; u_int len;
int accept = 0; int accept = 0;
char *service = packet_get_string(&len); char *service = packet_get_string(&len);
packet_done(); packet_done();
@ -178,33 +187,33 @@ input_userauth_request(int type, int plen, void *ctxt)
{ {
Authctxt *authctxt = ctxt; Authctxt *authctxt = ctxt;
Authmethod *m = NULL; Authmethod *m = NULL;
char *user, *service, *method, *style = NULL;
int authenticated = 0; int authenticated = 0;
char *user, *service, *method, *authmsg = NULL;
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
login_cap_t *lc; login_cap_t *lc;
#endif /* HAVE_LOGIN_CAP */ #endif /* HAVE_LOGIN_CAP */
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS) #if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
const char *from_host, *from_ip; const char *from_host, *from_ip;
from_host = get_canonical_hostname(); from_host = get_canonical_hostname(options.reverse_mapping_check);
from_ip = get_remote_ipaddr(); from_ip = get_remote_ipaddr();
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */ #endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
if (authctxt == NULL) if (authctxt == NULL)
fatal("input_userauth_request: no authctxt"); fatal("input_userauth_request: no authctxt");
if (authctxt->attempt++ >= AUTH_FAIL_MAX)
packet_disconnect("too many failed userauth_requests");
user = packet_get_string(NULL); user = packet_get_string(NULL);
service = packet_get_string(NULL); service = packet_get_string(NULL);
method = packet_get_string(NULL); method = packet_get_string(NULL);
debug("userauth-request for user %s service %s method %s", user, service, method); debug("userauth-request for user %s service %s method %s", user, service, method);
debug("attempt #%d", authctxt->attempt); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
if (authctxt->attempt == 1) { if ((style = strchr(user, ':')) != NULL)
*style++ = 0;
if (authctxt->attempt++ == 0) {
/* setup auth context */ /* setup auth context */
struct passwd *pw = NULL; struct passwd *pw = NULL;
setproctitle("%s", user);
pw = getpwnam(user); pw = getpwnam(user);
if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) { if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
authctxt->pw = pwcopy(pw); authctxt->pw = pwcopy(pw);
@ -217,12 +226,14 @@ input_userauth_request(int type, int plen, void *ctxt)
log("input_userauth_request: illegal user %s", user); log("input_userauth_request: illegal user %s", user);
authctxt->pw = NULL; authctxt->pw = NULL;
} }
setproctitle("%s", pw ? user : "unknown");
authctxt->user = xstrdup(user); authctxt->user = xstrdup(user);
authctxt->service = xstrdup(service); authctxt->service = xstrdup(service);
authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
} else if (authctxt->valid) { } else if (authctxt->valid) {
if (strcmp(user, authctxt->user) != 0 || if (strcmp(user, authctxt->user) != 0 ||
strcmp(service, authctxt->service) != 0) { strcmp(service, authctxt->service) != 0) {
log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)", log("input_userauth_request: mismatch: (%s,%s)!=(%s,%s)",
user, service, authctxt->user, authctxt->service); user, service, authctxt->user, authctxt->service);
authctxt->valid = 0; authctxt->valid = 0;
} }
@ -255,79 +266,88 @@ input_userauth_request(int type, int plen, void *ctxt)
packet_disconnect("Sorry, you are not allowed to connect."); packet_disconnect("Sorry, you are not allowed to connect.");
} }
#endif /* LOGIN_ACCESS */ #endif /* LOGIN_ACCESS */
/* reset state */
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
authctxt->postponed = 0;
#ifdef BSD_AUTH
if (authctxt->as) {
auth_close(authctxt->as);
authctxt->as = NULL;
}
#endif
/* try to authenticate user */
m = authmethod_lookup(method); m = authmethod_lookup(method);
if (m != NULL) { if (m != NULL) {
debug2("input_userauth_request: try method %s", method); debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(authctxt); authenticated = m->userauth(authctxt);
} else {
debug2("input_userauth_request: unsupported method %s", method);
} }
if (!authctxt->valid && authenticated == 1) {
log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
authenticated = 0;
}
/* Special handling for root */
if (authenticated == 1 &&
authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
authenticated = 0;
log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
}
#ifdef USE_PAM #ifdef USE_PAM
if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL)) if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL))
authenticated = 0; authenticated = 0;
#endif /* USE_PAM */ #endif /* USE_PAM */
userauth_finish(authctxt, authenticated, method);
/* Log before sending the reply */
userauth_log(authctxt, authenticated, method);
userauth_reply(authctxt, authenticated);
xfree(service); xfree(service);
xfree(user); xfree(user);
xfree(method); xfree(method);
} }
void void
userauth_log(Authctxt *authctxt, int authenticated, char *method) userauth_finish(Authctxt *authctxt, int authenticated, char *method)
{ {
void (*authlog) (const char *fmt,...) = verbose; if (!authctxt->valid && authenticated)
char *user = NULL, *authmsg = NULL; fatal("INTERNAL ERROR: authenticated invalid user %s",
authctxt->user);
/* Raise logging level */ /* Special handling for root */
if (authenticated == 1 || if (authenticated && authctxt->pw->pw_uid == 0 &&
!authctxt->valid || !auth_root_allowed(method))
authctxt->attempt >= AUTH_FAIL_LOG || authenticated = 0;
strcmp(method, "password") == 0)
authlog = log;
if (authenticated == 1) { /* Log before sending the reply */
authmsg = "Accepted"; auth_log(authctxt, authenticated, method, " ssh2");
} else if (authenticated == 0) {
authmsg = "Failed";
} else {
authmsg = "Postponed";
}
if (authctxt->valid) { if (!authctxt->postponed)
user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user; userauth_reply(authctxt, authenticated);
} else {
user = "NOUSER";
}
authlog("%s %s for %.200s from %.200s port %d ssh2",
authmsg,
method,
user,
get_remote_ipaddr(),
get_remote_port());
} }
void void
userauth_banner(void)
{
struct stat st;
char *banner = NULL;
off_t len, n;
int fd;
if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
return;
if ((fd = open(options.banner, O_RDONLY)) < 0)
return;
if (fstat(fd, &st) < 0)
goto done;
len = st.st_size;
banner = xmalloc(len + 1);
if ((n = read(fd, banner, len)) < 0)
goto done;
banner[n] = '\0';
packet_start(SSH2_MSG_USERAUTH_BANNER);
packet_put_cstring(banner);
packet_put_cstring(""); /* language, unused */
packet_send();
debug("userauth_banner: sent");
done:
if (banner)
xfree(banner);
close(fd);
return;
}
void
userauth_reply(Authctxt *authctxt, int authenticated) userauth_reply(Authctxt *authctxt, int authenticated)
{ {
char *methods;
/* XXX todo: check if multiple auth methods are needed */ /* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) { if (authenticated == 1) {
/* turn off userauth */ /* turn off userauth */
@ -337,16 +357,16 @@ userauth_reply(Authctxt *authctxt, int authenticated)
packet_write_wait(); packet_write_wait();
/* now we can break out */ /* now we can break out */
authctxt->success = 1; authctxt->success = 1;
} else if (authenticated == 0) { } else {
char *methods = authmethods_get(); if (authctxt->failures++ > AUTH_FAIL_MAX)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods); packet_put_cstring(methods);
packet_put_char(0); /* XXX partial success, unused */ packet_put_char(0); /* XXX partial success, unused */
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
xfree(methods); xfree(methods);
} else {
/* do nothing, we did already send a reply */
} }
} }
@ -358,10 +378,11 @@ userauth_none(Authctxt *authctxt)
if (m != NULL) if (m != NULL)
m->enabled = NULL; m->enabled = NULL;
packet_done(); packet_done();
userauth_banner();
#ifdef USE_PAM #ifdef USE_PAM
return authctxt->valid ? auth_pam_password(authctxt->pw, "") : 0; return authctxt->valid ? auth_pam_password(authctxt, "") : 0;
#else /* !USE_PAM */ #else /* !USE_PAM */
return authctxt->valid ? auth_password(authctxt->pw, "") : 0; return authctxt->valid ? auth_password(authctxt, "") : 0;
#endif /* USE_PAM */ #endif /* USE_PAM */
} }
@ -371,7 +392,7 @@ userauth_passwd(Authctxt *authctxt)
char *password; char *password;
int authenticated = 0; int authenticated = 0;
int change; int change;
unsigned int len; u_int len;
change = packet_get_char(); change = packet_get_char();
if (change) if (change)
log("password change not supported"); log("password change not supported");
@ -379,9 +400,9 @@ userauth_passwd(Authctxt *authctxt)
packet_done(); packet_done();
if (authctxt->valid && if (authctxt->valid &&
#ifdef USE_PAM #ifdef USE_PAM
auth_pam_password(authctxt->pw, password) == 1 auth_pam_password(authctxt, password) == 1
#else #else
auth_password(authctxt->pw, password) == 1 auth_password(authctxt, password) == 1
#endif #endif
) )
authenticated = 1; authenticated = 1;
@ -402,11 +423,10 @@ userauth_kbdint(Authctxt *authctxt)
packet_done(); packet_done();
debug("keyboard-interactive language %s devs %s", lang, devs); debug("keyboard-interactive language %s devs %s", lang, devs);
#ifdef SKEY
/* XXX hardcoded, we should look at devs */ if (options.challenge_reponse_authentication)
if (options.skey_authentication != 0) authenticated = auth2_challenge(authctxt, devs);
authenticated = auth2_skey(authctxt);
#endif
xfree(lang); xfree(lang);
xfree(devs); xfree(devs);
return authenticated; return authenticated;
@ -418,8 +438,8 @@ userauth_pubkey(Authctxt *authctxt)
Buffer b; Buffer b;
Key *key; Key *key;
char *pkalg, *pkblob, *sig; char *pkalg, *pkblob, *sig;
unsigned int alen, blen, slen; u_int alen, blen, slen;
int have_sig; int have_sig, pktype;
int authenticated = 0; int authenticated = 0;
if (!authctxt->valid) { if (!authctxt->valid) {
@ -427,14 +447,28 @@ userauth_pubkey(Authctxt *authctxt)
return 0; return 0;
} }
have_sig = packet_get_char(); have_sig = packet_get_char();
pkalg = packet_get_string(&alen); if (datafellows & SSH_BUG_PKAUTH) {
if (strcmp(pkalg, KEX_DSS) != 0) { debug2("userauth_pubkey: SSH_BUG_PKAUTH");
log("bad pkalg %s", pkalg); /*XXX*/ /* no explicit pkalg given */
pkblob = packet_get_string(&blen);
buffer_init(&b);
buffer_append(&b, pkblob, blen);
/* so we have to extract the pkalg from the pkblob */
pkalg = buffer_get_string(&b, &alen);
buffer_free(&b);
} else {
pkalg = packet_get_string(&alen);
pkblob = packet_get_string(&blen);
}
pktype = key_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
xfree(pkalg); xfree(pkalg);
xfree(pkblob);
return 0; return 0;
} }
pkblob = packet_get_string(&blen); key = key_from_blob(pkblob, blen);
key = dsa_key_from_blob(pkblob, blen);
if (key != NULL) { if (key != NULL) {
if (have_sig) { if (have_sig) {
sig = packet_get_string(&slen); sig = packet_get_string(&slen);
@ -449,19 +483,23 @@ userauth_pubkey(Authctxt *authctxt)
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user); buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b, buffer_put_cstring(&b,
datafellows & SSH_BUG_PUBKEYAUTH ? datafellows & SSH_BUG_PKSERVICE ?
"ssh-userauth" : "ssh-userauth" :
authctxt->service); authctxt->service);
buffer_put_cstring(&b, "publickey"); if (datafellows & SSH_BUG_PKAUTH) {
buffer_put_char(&b, have_sig); buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, KEX_DSS); } else {
buffer_put_cstring(&b, "publickey");
buffer_put_char(&b, have_sig);
buffer_put_cstring(&b, pkalg);
}
buffer_put_string(&b, pkblob, blen); buffer_put_string(&b, pkblob, blen);
#ifdef DEBUG_DSS #ifdef DEBUG_PK
buffer_dump(&b); buffer_dump(&b);
#endif #endif
/* test for correct signature */ /* test for correct signature */
if (user_dsa_key_allowed(authctxt->pw, key) && if (user_key_allowed(authctxt->pw, key) &&
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1; authenticated = 1;
buffer_clear(&b); buffer_clear(&b);
xfree(sig); xfree(sig);
@ -477,24 +515,100 @@ userauth_pubkey(Authctxt *authctxt)
* if a user is not allowed to login. is this an * if a user is not allowed to login. is this an
* issue? -markus * issue? -markus
*/ */
if (user_dsa_key_allowed(authctxt->pw, key)) { if (user_key_allowed(authctxt->pw, key)) {
packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_start(SSH2_MSG_USERAUTH_PK_OK);
packet_put_string(pkalg, alen); packet_put_string(pkalg, alen);
packet_put_string(pkblob, blen); packet_put_string(pkblob, blen);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
authenticated = -1; authctxt->postponed = 1;
} }
} }
if (authenticated != 1) if (authenticated != 1)
auth_clear_options(); auth_clear_options();
key_free(key); key_free(key);
} }
debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
xfree(pkalg); xfree(pkalg);
xfree(pkblob); xfree(pkblob);
return authenticated; return authenticated;
} }
int
userauth_hostbased(Authctxt *authctxt)
{
Buffer b;
Key *key;
char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
u_int alen, blen, slen;
int pktype;
int authenticated = 0;
if (!authctxt->valid) {
debug2("userauth_hostbased: disabled because of invalid user");
return 0;
}
pkalg = packet_get_string(&alen);
pkblob = packet_get_string(&blen);
chost = packet_get_string(NULL);
cuser = packet_get_string(NULL);
sig = packet_get_string(&slen);
debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
cuser, chost, pkalg, slen);
#ifdef DEBUG_PK
debug("signature:");
buffer_init(&b);
buffer_append(&b, sig, slen);
buffer_dump(&b);
buffer_free(&b);
#endif
pktype = key_type_from_name(pkalg);
if (pktype == KEY_UNSPEC) {
/* this is perfectly legal */
log("userauth_hostbased: unsupported "
"public key algorithm: %s", pkalg);
goto done;
}
key = key_from_blob(pkblob, blen);
if (key == NULL) {
debug("userauth_hostbased: cannot decode key: %s", pkalg);
goto done;
}
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
authctxt->service;
buffer_init(&b);
buffer_put_string(&b, session_id2, session_id2_len);
/* reconstruct packet */
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
buffer_put_cstring(&b, authctxt->user);
buffer_put_cstring(&b, service);
buffer_put_cstring(&b, "hostbased");
buffer_put_string(&b, pkalg, alen);
buffer_put_string(&b, pkblob, blen);
buffer_put_cstring(&b, chost);
buffer_put_cstring(&b, cuser);
#ifdef DEBUG_PK
buffer_dump(&b);
#endif
/* test for allowed key and correct signature */
if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
authenticated = 1;
buffer_clear(&b);
key_free(key);
done:
debug2("userauth_hostbased: authenticated %d", authenticated);
xfree(pkalg);
xfree(pkblob);
xfree(cuser);
xfree(chost);
xfree(sig);
return authenticated;
}
/* get current user */ /* get current user */
struct passwd* struct passwd*
@ -509,7 +623,7 @@ char *
authmethods_get(void) authmethods_get(void)
{ {
Authmethod *method = NULL; Authmethod *method = NULL;
unsigned int size = 0; u_int size = 0;
char *list; char *list;
for (method = authmethods; method->name != NULL; method++) { for (method = authmethods; method->name != NULL; method++) {
@ -553,13 +667,12 @@ authmethod_lookup(const char *name)
/* return 1 if user allows given key */ /* return 1 if user allows given key */
int int
user_dsa_key_allowed(struct passwd *pw, Key *key) user_key_allowed(struct passwd *pw, Key *key)
{ {
char line[8192], file[1024]; char line[8192], file[MAXPATHLEN];
int found_key = 0; int found_key = 0;
unsigned int bits = -1;
FILE *f; FILE *f;
unsigned long linenum = 0; u_long linenum = 0;
struct stat st; struct stat st;
Key *found; Key *found;
@ -567,11 +680,11 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
return 0; return 0;
/* Temporarily use the user's uid. */ /* Temporarily use the user's uid. */
temporarily_use_uid(pw->pw_uid); temporarily_use_uid(pw);
/* The authorized keys. */ /* The authorized keys. */
snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
SSH_USER_PERMITTED_KEYS2); _PATH_SSH_USER_PERMITTED_KEYS2);
/* Fail quietly if file does not exist */ /* Fail quietly if file does not exist */
if (stat(file, &st) < 0) { if (stat(file, &st) < 0) {
@ -599,10 +712,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
key_type(key), pw->pw_name, file); key_type(key), pw->pw_name, file);
fail = 1; fail = 1;
} else { } else {
/* Check path to SSH_USER_PERMITTED_KEYS */ /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
int i; int i;
static const char *check[] = { static const char *check[] = {
"", SSH_USER_DIR, NULL "", _PATH_SSH_USER_DIR, NULL
}; };
for (i = 0; check[i]; i++) { for (i = 0; check[i]; i++) {
snprintf(line, sizeof line, "%.500s/%.100s", snprintf(line, sizeof line, "%.500s/%.100s",
@ -621,7 +734,7 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
} }
if (fail) { if (fail) {
fclose(f); fclose(f);
log("%s",buf); log("%s", buf);
restore_uid(); restore_uid();
return 0; return 0;
} }
@ -638,10 +751,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
if (!*cp || *cp == '\n' || *cp == '#') if (!*cp || *cp == '\n' || *cp == '#')
continue; continue;
bits = key_read(found, &cp); if (key_read(found, &cp) == -1) {
if (bits == 0) {
/* no key? check if there are options for this key */ /* no key? check if there are options for this key */
int quoted = 0; int quoted = 0;
debug2("user_key_allowed: check options: '%s'", cp);
options = cp; options = cp;
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
if (*cp == '\\' && cp[1] == '"') if (*cp == '\\' && cp[1] == '"')
@ -652,14 +765,14 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
/* Skip remaining whitespace. */ /* Skip remaining whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++) for (; *cp == ' ' || *cp == '\t'; cp++)
; ;
bits = key_read(found, &cp); if (key_read(found, &cp) == -1) {
if (bits == 0) { debug2("user_key_allowed: advance: '%s'", cp);
/* still no key? advance to next line*/ /* still no key? advance to next line*/
continue; continue;
} }
} }
if (key_equal(found, key) && if (key_equal(found, key) &&
auth_parse_options(pw, options, linenum) == 1) { auth_parse_options(pw, options, file, linenum) == 1) {
found_key = 1; found_key = 1;
debug("matching key found: file %s, line %ld", debug("matching key found: file %s, line %ld",
file, linenum); file, linenum);
@ -669,22 +782,73 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
restore_uid(); restore_uid();
fclose(f); fclose(f);
key_free(found); key_free(found);
if (!found_key)
debug2("key not found");
return found_key; return found_key;
} }
struct passwd * /* return 1 if given hostkey is allowed */
pwcopy(struct passwd *pw) int
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
Key *key)
{ {
struct passwd *copy = xmalloc(sizeof(*copy)); Key *found;
memset(copy, 0, sizeof(*copy)); const char *resolvedname, *ipaddr, *lookup;
copy->pw_name = xstrdup(pw->pw_name); struct stat st;
copy->pw_passwd = xstrdup(pw->pw_passwd); char *user_hostfile;
copy->pw_uid = pw->pw_uid; int host_status, len;
copy->pw_gid = pw->pw_gid;
copy->pw_class = xstrdup(pw->pw_class); resolvedname = get_canonical_hostname(options.reverse_mapping_check);
copy->pw_dir = xstrdup(pw->pw_dir); ipaddr = get_remote_ipaddr();
copy->pw_shell = xstrdup(pw->pw_shell);
copy->pw_expire = pw->pw_expire; debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
copy->pw_change = pw->pw_change; chost, resolvedname, ipaddr);
return copy;
if (options.hostbased_uses_name_from_packet_only) {
if (auth_rhosts2(pw, cuser, chost, chost) == 0)
return 0;
lookup = chost;
} else {
if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
debug2("stripping trailing dot from chost %s", chost);
chost[len - 1] = '\0';
}
if (strcasecmp(resolvedname, chost) != 0)
log("userauth_hostbased mismatch: "
"client sends %s, but we resolve %s to %s",
chost, ipaddr, resolvedname);
if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
return 0;
lookup = resolvedname;
}
debug2("userauth_hostbased: access allowed by auth_rhosts2");
/* XXX this is copied from auth-rh-rsa.c and should be shared */
found = key_new(key->type);
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE2, lookup,
key, found, NULL);
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
user_hostfile = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE2,
pw->pw_uid);
if (options.strict_modes &&
(stat(user_hostfile, &st) == 0) &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
(st.st_mode & 022) != 0)) {
log("Hostbased authentication refused for %.100s: "
"bad owner or modes for %.200s",
pw->pw_name, user_hostfile);
} else {
temporarily_use_uid(pw);
host_status = check_host_in_hostfile(user_hostfile,
lookup, key, found, NULL);
restore_uid();
}
xfree(user_hostfile);
}
key_free(found);
debug2("userauth_hostbased: key %s for %s", host_status == HOST_OK ?
"ok" : "not found", lookup);
return (host_status == HOST_OK);
} }

View File

@ -35,24 +35,24 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: authfd.c,v 1.29 2000/10/09 21:51:00 markus Exp $"); RCSID("$OpenBSD: authfd.c,v 1.39 2001/04/05 10:42:48 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/evp.h>
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
#include "buffer.h" #include "buffer.h"
#include "bufaux.h" #include "bufaux.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "getput.h" #include "getput.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include "key.h" #include "key.h"
#include "authfd.h" #include "authfd.h"
#include "cipher.h"
#include "kex.h" #include "kex.h"
#include "dsa.h"
#include "compat.h" #include "compat.h"
#include "log.h"
#include "atomicio.h"
/* helper */ /* helper */
int decode_reply(int type); int decode_reply(int type);
@ -64,7 +64,7 @@ int decode_reply(int type);
/* Returns the number of the authentication fd, or -1 if there is none. */ /* Returns the number of the authentication fd, or -1 if there is none. */
int int
ssh_get_authentication_socket() ssh_get_authentication_socket(void)
{ {
const char *authsocket; const char *authsocket;
int sock, len; int sock, len;
@ -76,7 +76,8 @@ ssh_get_authentication_socket()
sunaddr.sun_family = AF_UNIX; sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1; len = SUN_LEN(&sunaddr)+1;
sunaddr.sun_len = len;
sock = socket(AF_UNIX, SOCK_STREAM, 0); sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) if (sock < 0)
@ -118,6 +119,8 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply
len = 4; len = 4;
while (len > 0) { while (len > 0) {
l = read(auth->fd, buf + 4 - len, len); l = read(auth->fd, buf + 4 - len, len);
if (l == -1 && (errno == EAGAIN || errno == EINTR))
continue;
if (l <= 0) { if (l <= 0) {
error("Error reading response length from authentication socket."); error("Error reading response length from authentication socket.");
return 0; return 0;
@ -137,6 +140,8 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply
if (l > sizeof(buf)) if (l > sizeof(buf))
l = sizeof(buf); l = sizeof(buf);
l = read(auth->fd, buf, l); l = read(auth->fd, buf, l);
if (l == -1 && (errno == EAGAIN || errno == EINTR))
continue;
if (l <= 0) { if (l <= 0) {
error("Error reading response from authentication socket."); error("Error reading response from authentication socket.");
return 0; return 0;
@ -169,7 +174,7 @@ ssh_close_authentication_socket(int sock)
*/ */
AuthenticationConnection * AuthenticationConnection *
ssh_get_authentication_connection() ssh_get_authentication_connection(void)
{ {
AuthenticationConnection *auth; AuthenticationConnection *auth;
int sock; int sock;
@ -208,8 +213,8 @@ ssh_close_authentication_connection(AuthenticationConnection *auth)
* Returns the first authentication identity held by the agent. * Returns the first authentication identity held by the agent.
*/ */
Key * int
ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) ssh_get_num_identities(AuthenticationConnection *auth, int version)
{ {
int type, code1 = 0, code2 = 0; int type, code1 = 0, code2 = 0;
Buffer request; Buffer request;
@ -224,7 +229,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
code2 = SSH2_AGENT_IDENTITIES_ANSWER; code2 = SSH2_AGENT_IDENTITIES_ANSWER;
break; break;
default: default:
return NULL; return 0;
} }
/* /*
@ -237,14 +242,14 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
buffer_clear(&auth->identities); buffer_clear(&auth->identities);
if (ssh_request_reply(auth, &request, &auth->identities) == 0) { if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
buffer_free(&request); buffer_free(&request);
return NULL; return 0;
} }
buffer_free(&request); buffer_free(&request);
/* Get message type, and verify that we got a proper answer. */ /* Get message type, and verify that we got a proper answer. */
type = buffer_get_char(&auth->identities); type = buffer_get_char(&auth->identities);
if (agent_failed(type)) { if (agent_failed(type)) {
return NULL; return 0;
} else if (type != code2) { } else if (type != code2) {
fatal("Bad authentication reply message type: %d", type); fatal("Bad authentication reply message type: %d", type);
} }
@ -252,19 +257,27 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
/* Get the number of entries in the response and check it for sanity. */ /* Get the number of entries in the response and check it for sanity. */
auth->howmany = buffer_get_int(&auth->identities); auth->howmany = buffer_get_int(&auth->identities);
if (auth->howmany > 1024) if (auth->howmany > 1024)
fatal("Too many identities in authentication reply: %d\n", fatal("Too many identities in authentication reply: %d",
auth->howmany); auth->howmany);
/* Return the first entry (if any). */ return auth->howmany;
return ssh_get_next_identity(auth, comment, version); }
Key *
ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
{
/* get number of identities and return the first entry (if any). */
if (ssh_get_num_identities(auth, version) > 0)
return ssh_get_next_identity(auth, comment, version);
return NULL;
} }
Key * Key *
ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
{ {
unsigned int bits; u_int bits;
unsigned char *blob; u_char *blob;
unsigned int blen; u_int blen;
Key *key = NULL; Key *key = NULL;
/* Return failure if no more entries. */ /* Return failure if no more entries. */
@ -277,7 +290,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
*/ */
switch(version){ switch(version){
case 1: case 1:
key = key_new(KEY_RSA); key = key_new(KEY_RSA1);
bits = buffer_get_int(&auth->identities); bits = buffer_get_int(&auth->identities);
buffer_get_bignum(&auth->identities, key->rsa->e); buffer_get_bignum(&auth->identities, key->rsa->e);
buffer_get_bignum(&auth->identities, key->rsa->n); buffer_get_bignum(&auth->identities, key->rsa->n);
@ -289,7 +302,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
case 2: case 2:
blob = buffer_get_string(&auth->identities, &blen); blob = buffer_get_string(&auth->identities, &blen);
*comment = buffer_get_string(&auth->identities, NULL); *comment = buffer_get_string(&auth->identities, NULL);
key = dsa_key_from_blob(blob, blen); key = key_from_blob(blob, blen);
xfree(blob); xfree(blob);
break; break;
default: default:
@ -312,16 +325,16 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
int int
ssh_decrypt_challenge(AuthenticationConnection *auth, ssh_decrypt_challenge(AuthenticationConnection *auth,
Key* key, BIGNUM *challenge, Key* key, BIGNUM *challenge,
unsigned char session_id[16], u_char session_id[16],
unsigned int response_type, u_int response_type,
unsigned char response[16]) u_char response[16])
{ {
Buffer buffer; Buffer buffer;
int success = 0; int success = 0;
int i; int i;
int type; int type;
if (key->type != KEY_RSA) if (key->type != KEY_RSA1)
return 0; return 0;
if (response_type == 0) { if (response_type == 0) {
log("Compatibility with ssh protocol version 1.0 no longer supported."); log("Compatibility with ssh protocol version 1.0 no longer supported.");
@ -363,17 +376,17 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
int int
ssh_agent_sign(AuthenticationConnection *auth, ssh_agent_sign(AuthenticationConnection *auth,
Key *key, Key *key,
unsigned char **sigp, int *lenp, u_char **sigp, int *lenp,
unsigned char *data, int datalen) u_char *data, int datalen)
{ {
extern int datafellows; extern int datafellows;
Buffer msg; Buffer msg;
unsigned char *blob; u_char *blob;
unsigned int blen; u_int blen;
int type, flags = 0; int type, flags = 0;
int ret = -1; int ret = -1;
if (dsa_make_key_blob(key, &blob, &blen) == 0) if (key_to_blob(key, &blob, &blen) == 0)
return -1; return -1;
if (datafellows & SSH_BUG_SIGBLOB) if (datafellows & SSH_BUG_SIGBLOB)
@ -406,7 +419,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
/* Encode key for a message to the agent. */ /* Encode key for a message to the agent. */
void void
ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment) ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
{ {
buffer_clear(b); buffer_clear(b);
buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY); buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
@ -422,17 +435,29 @@ ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
} }
void void
ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment) ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
{ {
buffer_clear(b); buffer_clear(b);
buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY); buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
buffer_put_cstring(b, KEX_DSS); buffer_put_cstring(b, key_ssh_name(key));
buffer_put_bignum2(b, key->p); switch(key->type){
buffer_put_bignum2(b, key->q); case KEY_RSA:
buffer_put_bignum2(b, key->g); buffer_put_bignum2(b, key->rsa->n);
buffer_put_bignum2(b, key->pub_key); buffer_put_bignum2(b, key->rsa->e);
buffer_put_bignum2(b, key->priv_key); buffer_put_bignum2(b, key->rsa->d);
buffer_put_string(b, comment, strlen(comment)); buffer_put_bignum2(b, key->rsa->iqmp);
buffer_put_bignum2(b, key->rsa->p);
buffer_put_bignum2(b, key->rsa->q);
break;
case KEY_DSA:
buffer_put_bignum2(b, key->dsa->p);
buffer_put_bignum2(b, key->dsa->q);
buffer_put_bignum2(b, key->dsa->g);
buffer_put_bignum2(b, key->dsa->pub_key);
buffer_put_bignum2(b, key->dsa->priv_key);
break;
}
buffer_put_cstring(b, comment);
} }
/* /*
@ -449,11 +474,12 @@ ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
buffer_init(&msg); buffer_init(&msg);
switch (key->type) { switch (key->type) {
case KEY_RSA: case KEY_RSA1:
ssh_encode_identity_rsa(&msg, key->rsa, comment); ssh_encode_identity_rsa1(&msg, key->rsa, comment);
break; break;
case KEY_RSA:
case KEY_DSA: case KEY_DSA:
ssh_encode_identity_dsa(&msg, key->dsa, comment); ssh_encode_identity_ssh2(&msg, key, comment);
break; break;
default: default:
buffer_free(&msg); buffer_free(&msg);
@ -479,18 +505,18 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
{ {
Buffer msg; Buffer msg;
int type; int type;
unsigned char *blob; u_char *blob;
unsigned int blen; u_int blen;
buffer_init(&msg); buffer_init(&msg);
if (key->type == KEY_RSA) { if (key->type == KEY_RSA1) {
buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_int(&msg, BN_num_bits(key->rsa->n));
buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->e);
buffer_put_bignum(&msg, key->rsa->n); buffer_put_bignum(&msg, key->rsa->n);
} else if (key->type == KEY_DSA) { } else if (key->type == KEY_DSA || key->type == KEY_RSA) {
dsa_make_key_blob(key, &blob, &blen); key_to_blob(key, &blob, &blen);
buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, blob, blen);
xfree(blob); xfree(blob);
@ -533,7 +559,7 @@ ssh_remove_all_identities(AuthenticationConnection *auth, int version)
return decode_reply(type); return decode_reply(type);
} }
int int
decode_reply(int type) decode_reply(int type)
{ {
switch (type) { switch (type) {

View File

@ -36,23 +36,25 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: authfile.c,v 1.20 2000/10/11 20:27:23 markus Exp $"); RCSID("$OpenBSD: authfile.c,v 1.32 2001/04/18 23:44:51 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/err.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/pem.h>
#include "cipher.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "buffer.h" #include "buffer.h"
#include "bufaux.h" #include "bufaux.h"
#include "ssh.h"
#include "key.h" #include "key.h"
#include "ssh.h"
#include "log.h"
#include "authfile.h"
/* Version identification string for identity files. */ /* Version identification string for SSH v1 identity files. */
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n" static const char authfile_id_string[] =
"SSH PRIVATE KEY FILE FORMAT 1.1\n";
/* /*
* Saves the authentication (private) key in a file, encrypting it with * Saves the authentication (private) key in a file, encrypting it with
@ -62,8 +64,8 @@ RCSID("$FreeBSD$");
*/ */
int int
save_private_key_rsa(const char *filename, const char *passphrase, key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
RSA *key, const char *comment) const char *comment)
{ {
Buffer buffer, encrypted; Buffer buffer, encrypted;
char buf[100], *cp; char buf[100], *cp;
@ -99,10 +101,10 @@ save_private_key_rsa(const char *filename, const char *passphrase,
* will be stored in plain text, and storing them also in encrypted * will be stored in plain text, and storing them also in encrypted
* format would just give known plaintext). * format would just give known plaintext).
*/ */
buffer_put_bignum(&buffer, key->d); buffer_put_bignum(&buffer, key->rsa->d);
buffer_put_bignum(&buffer, key->iqmp); buffer_put_bignum(&buffer, key->rsa->iqmp);
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
/* Pad the part to be encrypted until its size is a multiple of 8. */ /* Pad the part to be encrypted until its size is a multiple of 8. */
while (buffer_len(&buffer) % 8 != 0) while (buffer_len(&buffer) % 8 != 0)
@ -112,9 +114,8 @@ save_private_key_rsa(const char *filename, const char *passphrase,
buffer_init(&encrypted); buffer_init(&encrypted);
/* First store keyfile id string. */ /* First store keyfile id string. */
cp = AUTHFILE_ID_STRING; for (i = 0; authfile_id_string[i]; i++)
for (i = 0; cp[i]; i++) buffer_put_char(&encrypted, authfile_id_string[i]);
buffer_put_char(&encrypted, cp[i]);
buffer_put_char(&encrypted, 0); buffer_put_char(&encrypted, 0);
/* Store cipher type. */ /* Store cipher type. */
@ -122,17 +123,17 @@ save_private_key_rsa(const char *filename, const char *passphrase,
buffer_put_int(&encrypted, 0); /* For future extension */ buffer_put_int(&encrypted, 0); /* For future extension */
/* Store public key. This will be in plain text. */ /* Store public key. This will be in plain text. */
buffer_put_int(&encrypted, BN_num_bits(key->n)); buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
buffer_put_bignum(&encrypted, key->n); buffer_put_bignum(&encrypted, key->rsa->n);
buffer_put_bignum(&encrypted, key->e); buffer_put_bignum(&encrypted, key->rsa->e);
buffer_put_string(&encrypted, comment, strlen(comment)); buffer_put_string(&encrypted, comment, strlen(comment));
/* Allocate space for the private part of the key in the buffer. */ /* Allocate space for the private part of the key in the buffer. */
buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
cipher_set_key_string(&ciphercontext, cipher, passphrase); cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_encrypt(&ciphercontext, (unsigned char *) cp, cipher_encrypt(&ciphercontext, (u_char *) cp,
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer)); (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
memset(&ciphercontext, 0, sizeof(ciphercontext)); memset(&ciphercontext, 0, sizeof(ciphercontext));
/* Destroy temporary data. */ /* Destroy temporary data. */
@ -140,15 +141,17 @@ save_private_key_rsa(const char *filename, const char *passphrase,
buffer_free(&buffer); buffer_free(&buffer);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) if (fd < 0) {
error("open %s failed: %s.", filename, strerror(errno));
return 0; return 0;
}
if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
buffer_len(&encrypted)) { buffer_len(&encrypted)) {
debug("Write to key file %.200s failed: %.100s", filename, error("write to key file %s failed: %s", filename,
strerror(errno)); strerror(errno));
buffer_free(&encrypted); buffer_free(&encrypted);
close(fd); close(fd);
remove(filename); unlink(filename);
return 0; return 0;
} }
close(fd); close(fd);
@ -156,80 +159,168 @@ save_private_key_rsa(const char *filename, const char *passphrase,
return 1; return 1;
} }
/* save DSA key in OpenSSL PEM format */ /* save SSH v2 key in OpenSSL PEM format */
int int
save_private_key_dsa(const char *filename, const char *passphrase, key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
DSA *dsa, const char *comment) const char *comment)
{ {
FILE *fp; FILE *fp;
int fd; int fd;
int success = 1; int success = 0;
int len = strlen(passphrase); int len = strlen(_passphrase);
char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
if (len > 0 && len <= 4) { if (len > 0 && len <= 4) {
error("passphrase too short: %d bytes", len); error("passphrase too short: have %d bytes, need > 4", len);
errno = 0;
return 0; return 0;
} }
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) { if (fd < 0) {
debug("open %s failed", filename); error("open %s failed: %s.", filename, strerror(errno));
return 0; return 0;
} }
fp = fdopen(fd, "w"); fp = fdopen(fd, "w");
if (fp == NULL ) { if (fp == NULL ) {
debug("fdopen %s failed", filename); error("fdopen %s failed: %s.", filename, strerror(errno));
close(fd); close(fd);
return 0; return 0;
} }
if (len > 0) { switch (key->type) {
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(), case KEY_DSA:
(char *)passphrase, strlen(passphrase), NULL, NULL)) success = PEM_write_DSAPrivateKey(fp, key->dsa,
success = 0; cipher, passphrase, len, NULL, NULL);
} else { break;
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL, case KEY_RSA:
NULL, 0, NULL, NULL)) success = PEM_write_RSAPrivateKey(fp, key->rsa,
success = 0; cipher, passphrase, len, NULL, NULL);
break;
} }
fclose(fp); fclose(fp);
return success; return success;
} }
int int
save_private_key(const char *filename, const char *passphrase, Key *key, key_save_private(Key *key, const char *filename, const char *passphrase,
const char *comment) const char *comment)
{ {
switch (key->type) { switch (key->type) {
case KEY_RSA: case KEY_RSA1:
return save_private_key_rsa(filename, passphrase, key->rsa, comment); return key_save_private_rsa1(key, filename, passphrase,
comment);
break; break;
case KEY_DSA: case KEY_DSA:
return save_private_key_dsa(filename, passphrase, key->dsa, comment); case KEY_RSA:
return key_save_private_pem(key, filename, passphrase,
comment);
break; break;
default: default:
break; break;
} }
error("key_save_private: cannot save key type %d", key->type);
return 0; return 0;
} }
/* /*
* Loads the public part of the key file. Returns 0 if an error was * Loads the public part of the ssh v1 key file. Returns NULL if an error was
* encountered (the file does not exist or is not readable), and non-zero * encountered (the file does not exist or is not readable), and the key
* otherwise. * otherwise.
*/ */
int Key *
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) key_load_public_rsa1(int fd, const char *filename, char **commentp)
{ {
int fd, i;
off_t len;
Buffer buffer; Buffer buffer;
Key *pub;
char *cp; char *cp;
int i;
off_t len;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
strerror(errno));
buffer_free(&buffer);
return NULL;
}
/* Check that it is at least big enough to contain the ID string. */
if (len < sizeof(authfile_id_string)) {
debug3("No RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
/*
* Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != authfile_id_string[i]) {
debug3("No RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return NULL;
}
/* Skip cipher type and reserved data. */
(void) buffer_get_char(&buffer); /* cipher type */
(void) buffer_get_int(&buffer); /* reserved */
/* Read the public key from the buffer. */
buffer_get_int(&buffer);
pub = key_new(KEY_RSA1);
buffer_get_bignum(&buffer, pub->rsa->n);
buffer_get_bignum(&buffer, pub->rsa->e);
if (commentp)
*commentp = buffer_get_string(&buffer, NULL);
/* The encrypted private part is not parsed by this function. */
buffer_free(&buffer);
return pub;
}
/* load public key from private-key file, works only for SSH v1 */
Key *
key_load_public_type(int type, const char *filename, char **commentp)
{
Key *pub;
int fd;
if (type == KEY_RSA1) {
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
pub = key_load_public_rsa1(fd, filename, commentp);
close(fd);
return pub;
}
return NULL;
}
/*
* 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.
* Assumes we are called under uid of the owner of the file.
*/
Key *
key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
char **commentp)
{
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
char *cp;
CipherContext ciphercontext;
Cipher *cipher;
BN_CTX *ctx;
BIGNUM *aux;
Key *prv = NULL;
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
len = lseek(fd, (off_t) 0, SEEK_END); len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET); lseek(fd, (off_t) 0, SEEK_SET);
@ -241,127 +332,40 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
strerror(errno)); strerror(errno));
buffer_free(&buffer); buffer_free(&buffer);
close(fd); close(fd);
return 0; return NULL;
} }
close(fd);
/* Check that it is at least big enought to contain the ID string. */ /* Check that it is at least big enough to contain the ID string. */
if (len < strlen(AUTHFILE_ID_STRING) + 1) { if (len < sizeof(authfile_id_string)) {
debug("Bad key file %.200s.", filename); debug3("No RSA1 key file %.200s.", filename);
buffer_free(&buffer);
return 0;
}
/*
* Make sure it begins with the id string. Consume the id string
* from the buffer.
*/
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) {
debug("Bad key file %.200s.", filename);
buffer_free(&buffer);
return 0;
}
/* Skip cipher type and reserved data. */
(void) buffer_get_char(&buffer); /* cipher type */
(void) buffer_get_int(&buffer); /* reserved */
/* Read the public key from the buffer. */
buffer_get_int(&buffer);
/* XXX alloc */
if (pub->n == NULL)
pub->n = BN_new();
buffer_get_bignum(&buffer, pub->n);
/* 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);
/* The encrypted private part is not parsed by this function. */
buffer_free(&buffer);
return 1;
}
/* load public key from private-key file */
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
* initializes the private key.
* Assumes we are called under uid of the owner of the file.
*/
int
load_private_key_rsa(int fd, const char *filename,
const char *passphrase, RSA * prv, char **comment_return)
{
int i, check1, check2, cipher_type;
off_t len;
Buffer buffer, decrypted;
char *cp;
CipherContext ciphercontext;
Cipher *cipher;
BN_CTX *ctx;
BIGNUM *aux;
len = lseek(fd, (off_t) 0, SEEK_END);
lseek(fd, (off_t) 0, SEEK_SET);
buffer_init(&buffer);
buffer_append_space(&buffer, &cp, len);
if (read(fd, cp, (size_t) len) != (size_t) len) {
debug("Read from key file %.200s failed: %.100s", filename,
strerror(errno));
buffer_free(&buffer); buffer_free(&buffer);
close(fd); close(fd);
return 0; return NULL;
}
close(fd);
/* Check that it is at least big enought to contain the ID string. */
if (len < strlen(AUTHFILE_ID_STRING) + 1) {
debug("Bad key file %.200s.", filename);
buffer_free(&buffer);
return 0;
} }
/* /*
* Make sure it begins with the id string. Consume the id string * Make sure it begins with the id string. Consume the id string
* from the buffer. * from the buffer.
*/ */
for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) for (i = 0; i < sizeof(authfile_id_string); i++)
if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { if (buffer_get_char(&buffer) != authfile_id_string[i]) {
debug("Bad key file %.200s.", filename); debug3("No RSA1 key file %.200s.", filename);
buffer_free(&buffer); buffer_free(&buffer);
return 0; close(fd);
return NULL;
} }
/* Read cipher type. */ /* Read cipher type. */
cipher_type = buffer_get_char(&buffer); cipher_type = buffer_get_char(&buffer);
(void) buffer_get_int(&buffer); /* Reserved data. */ (void) buffer_get_int(&buffer); /* Reserved data. */
/* Read the public key from the buffer. */ /* Read the public key from the buffer. */
buffer_get_int(&buffer); buffer_get_int(&buffer);
prv->n = BN_new(); prv = key_new_private(KEY_RSA1);
buffer_get_bignum(&buffer, prv->n);
prv->e = BN_new(); buffer_get_bignum(&buffer, prv->rsa->n);
buffer_get_bignum(&buffer, prv->e); buffer_get_bignum(&buffer, prv->rsa->e);
if (comment_return) if (commentp)
*comment_return = buffer_get_string(&buffer, NULL); *commentp = buffer_get_string(&buffer, NULL);
else else
xfree(buffer_get_string(&buffer, NULL)); xfree(buffer_get_string(&buffer, NULL));
@ -379,8 +383,8 @@ load_private_key_rsa(int fd, const char *filename,
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
cipher_set_key_string(&ciphercontext, cipher, passphrase); cipher_set_key_string(&ciphercontext, cipher, passphrase);
cipher_decrypt(&ciphercontext, (unsigned char *) cp, cipher_decrypt(&ciphercontext, (u_char *) cp,
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer)); (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
memset(&ciphercontext, 0, sizeof(ciphercontext)); memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&buffer); buffer_free(&buffer);
@ -389,138 +393,183 @@ load_private_key_rsa(int fd, const char *filename,
if (check1 != buffer_get_char(&decrypted) || if (check1 != buffer_get_char(&decrypted) ||
check2 != buffer_get_char(&decrypted)) { check2 != buffer_get_char(&decrypted)) {
if (strcmp(passphrase, "") != 0) if (strcmp(passphrase, "") != 0)
debug("Bad passphrase supplied for key file %.200s.", filename); debug("Bad passphrase supplied for key file %.200s.",
filename);
/* Bad passphrase. */ /* Bad passphrase. */
buffer_free(&decrypted); buffer_free(&decrypted);
fail: goto 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;
} }
/* Read the rest of the private key. */ /* Read the rest of the private key. */
prv->d = BN_new(); buffer_get_bignum(&decrypted, prv->rsa->d);
buffer_get_bignum(&decrypted, prv->d); buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
prv->iqmp = BN_new(); /* in SSL and SSH v1 p and q are exchanged */
buffer_get_bignum(&decrypted, prv->iqmp); /* u */ buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
/* in SSL and SSH p and q are exchanged */ buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
prv->q = BN_new();
buffer_get_bignum(&decrypted, prv->q); /* p */
prv->p = BN_new();
buffer_get_bignum(&decrypted, prv->p); /* q */
/* calculate p-1 and q-1 */
ctx = BN_CTX_new(); ctx = BN_CTX_new();
aux = BN_new(); aux = BN_new();
BN_sub(aux, prv->q, BN_value_one()); BN_sub(aux, prv->rsa->q, BN_value_one());
prv->dmq1 = BN_new(); BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
BN_mod(prv->dmq1, prv->d, aux, ctx);
BN_sub(aux, prv->p, BN_value_one()); BN_sub(aux, prv->rsa->p, BN_value_one());
prv->dmp1 = BN_new(); BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
BN_mod(prv->dmp1, prv->d, aux, ctx);
BN_clear_free(aux); BN_clear_free(aux);
BN_CTX_free(ctx); BN_CTX_free(ctx);
buffer_free(&decrypted); buffer_free(&decrypted);
close(fd);
return prv;
return 1; fail:
if (commentp)
xfree(*commentp);
close(fd);
key_free(prv);
return NULL;
} }
int Key *
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return) key_load_private_pem(int fd, int type, const char *passphrase,
char **commentp)
{ {
DSA *dsa;
BIO *in;
FILE *fp; FILE *fp;
EVP_PKEY *pk = NULL;
Key *prv = NULL;
char *name = "<no key>";
in = BIO_new(BIO_s_file());
if (in == NULL) {
error("BIO_new failed");
return 0;
}
fp = fdopen(fd, "r"); fp = fdopen(fd, "r");
if (fp == NULL) { if (fp == NULL) {
error("fdopen failed"); error("fdopen failed: %s", strerror(errno));
return 0; close(fd);
return NULL;
} }
BIO_set_fp(in, fp, BIO_NOCLOSE); pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase); if (pk == NULL) {
if (dsa == NULL) { debug("PEM_read_PrivateKey failed");
debug("PEM_read_bio_DSAPrivateKey failed"); (void)ERR_get_error();
} else { } else if (pk->type == EVP_PKEY_RSA &&
/* replace k->dsa with loaded key */ (type == KEY_UNSPEC||type==KEY_RSA)) {
DSA_free(k->dsa); prv = key_new(KEY_UNSPEC);
k->dsa = dsa; prv->rsa = EVP_PKEY_get1_RSA(pk);
} prv->type = KEY_RSA;
BIO_free(in); name = "rsa w/o comment";
fclose(fp); #ifdef DEBUG_PK
if (comment_return) RSA_print_fp(stderr, prv->rsa, 8);
*comment_return = xstrdup("dsa w/o comment");
debug("read DSA private key done");
#ifdef DEBUG_DSS
DSA_print_fp(stderr, dsa, 8);
#endif #endif
return dsa != NULL ? 1 : 0; } else if (pk->type == EVP_PKEY_DSA &&
(type == KEY_UNSPEC||type==KEY_DSA)) {
prv = key_new(KEY_UNSPEC);
prv->dsa = EVP_PKEY_get1_DSA(pk);
prv->type = KEY_DSA;
name = "dsa w/o comment";
#ifdef DEBUG_PK
DSA_print_fp(stderr, prv->dsa, 8);
#endif
} else {
error("PEM_read_PrivateKey: mismatch or "
"unknown EVP_PKEY save_type %d", pk->save_type);
}
fclose(fp);
if (pk != NULL)
EVP_PKEY_free(pk);
if (prv != NULL && commentp)
*commentp = xstrdup(name);
debug("read PEM private key done: type %s",
prv ? key_type(prv) : "<unknown>");
return prv;
} }
int int
load_private_key(const char *filename, const char *passphrase, Key *key, key_perm_ok(int fd, const char *filename)
char **comment_return)
{ {
int fd;
int ret = 0;
struct stat st; struct stat st;
fd = open(filename, O_RDONLY);
if (fd < 0)
return 0;
/* check owner and modes */ /* check owner and modes */
if (fstat(fd, &st) < 0 || if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != getuid()) || (st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) { (st.st_mode & 077) != 0) {
close(fd); close(fd);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Bad ownership or mode(0%3.3o) for '%s'.", error("Bad ownership or mode(0%3.3o) for '%s'.",
st.st_mode & 0777, filename); st.st_mode & 0777, filename);
error("It is recommended that your private key files are NOT accessible by others."); error("It is recommended that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
return 0; return 0;
} }
switch (key->type) { return 1;
case KEY_RSA: }
if (key->rsa->e != NULL) {
BN_clear_free(key->rsa->e); Key *
key->rsa->e = NULL; key_load_private_type(int type, const char *filename, const char *passphrase,
} char **commentp)
if (key->rsa->n != NULL) { {
BN_clear_free(key->rsa->n); int fd;
key->rsa->n = NULL;
} fd = open(filename, O_RDONLY);
ret = load_private_key_rsa(fd, filename, passphrase, if (fd < 0)
key->rsa, comment_return); return NULL;
if (!key_perm_ok(fd, filename)) {
error("bad permissions: ignore key: %s", filename);
close(fd);
return NULL;
}
switch (type) {
case KEY_RSA1:
return key_load_private_rsa1(fd, filename, passphrase,
commentp);
/* closes fd */
break; break;
case KEY_DSA: case KEY_DSA:
ret = load_private_key_dsa(fd, passphrase, key, comment_return); case KEY_RSA:
case KEY_UNSPEC:
return key_load_private_pem(fd, type, passphrase, commentp);
/* closes fd */
break;
default: default:
close(fd);
break; break;
} }
close(fd); return NULL;
return ret; }
Key *
key_load_private(const char *filename, const char *passphrase,
char **commentp)
{
Key *pub;
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
if (!key_perm_ok(fd, filename)) {
error("bad permissions: ignore key: %s", filename);
close(fd);
return NULL;
}
pub = key_load_public_rsa1(fd, filename, commentp);
lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
if (pub == NULL) {
/* closes fd */
return key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
} else {
/* it's a SSH v1 key if the public key part is readable */
key_free(pub);
/* closes fd */
return key_load_private_rsa1(fd, filename, passphrase, NULL);
}
} }
int int
do_load_public_key(const char *filename, Key *k, char **commentp) key_try_load_public(Key *k, const char *filename, char **commentp)
{ {
FILE *f; FILE *f;
unsigned int bits; char line[4096];
char line[1024];
char *cp; char *cp;
f = fopen(filename, "r"); f = fopen(filename, "r");
@ -538,8 +587,7 @@ do_load_public_key(const char *filename, Key *k, char **commentp)
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
; ;
if (*cp) { if (*cp) {
bits = key_read(k, &cp); if (key_read(k, &cp) == 1) {
if (bits != 0) {
if (commentp) if (commentp)
*commentp=xstrdup(filename); *commentp=xstrdup(filename);
fclose(f); fclose(f);
@ -552,19 +600,23 @@ do_load_public_key(const char *filename, Key *k, char **commentp)
return 0; return 0;
} }
/* load public key from pubkey file */ /* load public key from ssh v1 private or any pubkey file */
int Key *
try_load_public_key(const char *filename, Key *k, char **commentp) key_load_public(const char *filename, char **commentp)
{ {
char pub[MAXPATHLEN]; Key *pub;
char file[MAXPATHLEN];
if (do_load_public_key(filename, k, commentp) == 1) pub = key_load_public_type(KEY_RSA1, filename, commentp);
return 1; if (pub != NULL)
if (strlcpy(pub, filename, sizeof pub) >= MAXPATHLEN) return pub;
return 0; pub = key_new(KEY_UNSPEC);
if (strlcat(pub, ".pub", sizeof pub) >= MAXPATHLEN) if (key_try_load_public(pub, filename, commentp) == 1)
return 0; return pub;
if (do_load_public_key(pub, k, commentp) == 1) if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
return 1; (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
return 0; (key_try_load_public(pub, file, commentp) == 1))
return pub;
key_free(pub);
return NULL;
} }

View File

@ -37,14 +37,14 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: bufaux.c,v 1.13 2000/09/07 20:27:50 deraadt Exp $"); RCSID("$OpenBSD: bufaux.c,v 1.17 2001/01/21 19:05:45 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "ssh.h"
#include <openssl/bn.h> #include <openssl/bn.h>
#include "bufaux.h" #include "bufaux.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "getput.h" #include "getput.h"
#include "log.h"
/* /*
* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
@ -55,7 +55,7 @@ buffer_put_bignum(Buffer *buffer, BIGNUM *value)
{ {
int bits = BN_num_bits(value); int bits = BN_num_bits(value);
int bin_size = (bits + 7) / 8; int bin_size = (bits + 7) / 8;
char unsigned *buf = xmalloc(bin_size); u_char *buf = xmalloc(bin_size);
int oi; int oi;
char msg[2]; char msg[2];
@ -82,7 +82,7 @@ int
buffer_get_bignum(Buffer *buffer, BIGNUM *value) buffer_get_bignum(Buffer *buffer, BIGNUM *value)
{ {
int bits, bytes; int bits, bytes;
unsigned char buf[2], *bin; u_char buf[2], *bin;
/* Get the number for bits. */ /* Get the number for bits. */
buffer_get(buffer, (char *) buf, 2); buffer_get(buffer, (char *) buf, 2);
@ -91,7 +91,7 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
bytes = (bits + 7) / 8; bytes = (bits + 7) / 8;
if (buffer_len(buffer) < bytes) if (buffer_len(buffer) < bytes)
fatal("buffer_get_bignum: input buffer too small"); fatal("buffer_get_bignum: input buffer too small");
bin = (unsigned char*) buffer_ptr(buffer); bin = (u_char *) buffer_ptr(buffer);
BN_bin2bn(bin, bytes, value); BN_bin2bn(bin, bytes, value);
buffer_consume(buffer, bytes); buffer_consume(buffer, bytes);
@ -105,7 +105,7 @@ void
buffer_put_bignum2(Buffer *buffer, BIGNUM *value) buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
{ {
int bytes = BN_num_bytes(value) + 1; int bytes = BN_num_bytes(value) + 1;
unsigned char *buf = xmalloc(bytes); u_char *buf = xmalloc(bytes);
int oi; int oi;
int hasnohigh = 0; int hasnohigh = 0;
buf[0] = '\0'; buf[0] = '\0';
@ -118,7 +118,7 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
if (value->neg) { if (value->neg) {
/**XXX should be two's-complement */ /**XXX should be two's-complement */
int i, carry; int i, carry;
unsigned char *uc = buf; u_char *uc = buf;
log("negativ!"); log("negativ!");
for(i = bytes-1, carry = 1; i>=0; i--) { for(i = bytes-1, carry = 1; i>=0; i--) {
uc[i] ^= 0xff; uc[i] ^= 0xff;
@ -136,7 +136,7 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
{ {
/**XXX should be two's-complement */ /**XXX should be two's-complement */
int len; int len;
unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len); u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
BN_bin2bn(bin, len, value); BN_bin2bn(bin, len, value);
xfree(bin); xfree(bin);
return len; return len;
@ -145,25 +145,41 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
/* /*
* Returns an integer from the buffer (4 bytes, msb first). * Returns an integer from the buffer (4 bytes, msb first).
*/ */
unsigned int u_int
buffer_get_int(Buffer *buffer) buffer_get_int(Buffer *buffer)
{ {
unsigned char buf[4]; u_char buf[4];
buffer_get(buffer, (char *) buf, 4); buffer_get(buffer, (char *) buf, 4);
return GET_32BIT(buf); return GET_32BIT(buf);
} }
u_int64_t
buffer_get_int64(Buffer *buffer)
{
u_char buf[8];
buffer_get(buffer, (char *) buf, 8);
return GET_64BIT(buf);
}
/* /*
* Stores an integer in the buffer in 4 bytes, msb first. * Stores an integer in the buffer in 4 bytes, msb first.
*/ */
void void
buffer_put_int(Buffer *buffer, unsigned int value) buffer_put_int(Buffer *buffer, u_int value)
{ {
char buf[4]; char buf[4];
PUT_32BIT(buf, value); PUT_32BIT(buf, value);
buffer_append(buffer, buf, 4); buffer_append(buffer, buf, 4);
} }
void
buffer_put_int64(Buffer *buffer, u_int64_t value)
{
char buf[8];
PUT_64BIT(buf, value);
buffer_append(buffer, buf, 8);
}
/* /*
* Returns an arbitrary binary string from the buffer. The string cannot * Returns an arbitrary binary string from the buffer. The string cannot
* be longer than 256k. The returned value points to memory allocated * be longer than 256k. The returned value points to memory allocated
@ -173,9 +189,9 @@ buffer_put_int(Buffer *buffer, unsigned int value)
* to the returned string, and is not counted in length. * to the returned string, and is not counted in length.
*/ */
char * char *
buffer_get_string(Buffer *buffer, unsigned int *length_ptr) buffer_get_string(Buffer *buffer, u_int *length_ptr)
{ {
unsigned int len; u_int len;
char *value; char *value;
/* Get the length. */ /* Get the length. */
len = buffer_get_int(buffer); len = buffer_get_int(buffer);
@ -197,7 +213,7 @@ buffer_get_string(Buffer *buffer, unsigned int *length_ptr)
* Stores and arbitrary binary string in the buffer. * Stores and arbitrary binary string in the buffer.
*/ */
void void
buffer_put_string(Buffer *buffer, const void *buf, unsigned int len) buffer_put_string(Buffer *buffer, const void *buf, u_int len)
{ {
buffer_put_int(buffer, len); buffer_put_int(buffer, len);
buffer_append(buffer, buf, len); buffer_append(buffer, buf, len);
@ -216,7 +232,7 @@ buffer_get_char(Buffer *buffer)
{ {
char ch; char ch;
buffer_get(buffer, &ch, 1); buffer_get(buffer, &ch, 1);
return (unsigned char) ch; return (u_char) ch;
} }
/* /*

View File

@ -12,12 +12,15 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: canohost.c,v 1.16 2000/10/21 17:04:22 markus Exp $"); RCSID("$OpenBSD: canohost.c,v 1.26 2001/04/18 14:15:00 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h" #include "log.h"
#include "canohost.h"
void check_ip_options(int socket, char *ipaddr);
/* /*
* Return the canonical name of the host at the other end of the socket. The * Return the canonical name of the host at the other end of the socket. The
@ -25,121 +28,124 @@ RCSID("$FreeBSD$");
*/ */
char * char *
get_remote_hostname(int socket) get_remote_hostname(int socket, int reverse_mapping_check)
{ {
struct sockaddr_storage from; struct sockaddr_storage from;
int i; int i;
socklen_t fromlen; socklen_t fromlen;
struct addrinfo hints, *ai, *aitop; struct addrinfo hints, *ai, *aitop;
char name[MAXHOSTNAMELEN]; char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
/* Get IP address of client. */ /* Get IP address of client. */
fromlen = sizeof(from); fromlen = sizeof(from);
memset(&from, 0, sizeof(from)); memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno)); debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup(); fatal_cleanup();
} }
if (from.ss_family == AF_INET)
check_ip_options(socket, ntop);
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0) NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
debug3("Trying to reverse map address %.100s.", ntop);
/* Map the IP address to a host name. */ /* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
NULL, 0, NI_NAMEREQD) == 0) { NULL, 0, NI_NAMEREQD) != 0) {
/* Got host name. */ /* Host name not found. Use ip address. */
name[sizeof(name) - 1] = '\0'; log("Could not reverse map address %.100s.", ntop);
/* return xstrdup(ntop);
* Convert it to all lowercase (which is expected by the rest
* of this software).
*/
for (i = 0; name[i]; i++)
if (isupper(name[i]))
name[i] = tolower(name[i]);
/*
* Map it back to an IP address and check that the given
* address actually is an address of this host. This is
* necessary because anyone with access to a name server can
* define arbitrary names for an IP address. Mapping from
* name to IP address can be trusted better (but can still be
* fooled if the intruder has access to the name server of
* the domain).
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = from.ss_family;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
strlcpy(name, ntop, sizeof name);
goto check_ip_options;
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (!ai) {
/* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
ntop, name);
strlcpy(name, ntop, sizeof name);
goto check_ip_options;
}
/* Address was found for the host name. We accept the host name. */
} else {
/* Host name not found. Use ascii representation of the address. */
strlcpy(name, ntop, sizeof name);
log("Could not reverse map address %.100s.", name);
} }
check_ip_options: /* Got host name. */
name[sizeof(name) - 1] = '\0';
/* /*
* If IP options are supported, make sure there are none (log and * Convert it to all lowercase (which is expected by the rest
* disconnect them if any are found). Basically we are worried about * of this software).
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts autentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
*/ */
/* IP options -- IPv4 only */ for (i = 0; name[i]; i++)
if (from.ss_family == AF_INET) { if (isupper(name[i]))
unsigned char options[200], *ucp; name[i] = tolower(name[i]);
char text[1024], *cp;
socklen_t option_size;
int ipproto;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL) if (!reverse_mapping_check)
ipproto = ip->p_proto; return xstrdup(name);
else /*
ipproto = IPPROTO_IP; * Map it back to an IP address and check that the given
option_size = sizeof(options); * address actually is an address of this host. This is
if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options, * necessary because anyone with access to a name server can
&option_size) >= 0 && option_size != 0) { * define arbitrary names for an IP address. Mapping from
cp = text; * name to IP address can be trusted better (but can still be
/* Note: "text" buffer must be at least 3x as big as options. */ * fooled if the intruder has access to the name server of
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) * the domain).
sprintf(cp, " %2.2x", *ucp); */
log("Connection from %.100s with IP options:%.800s", memset(&hints, 0, sizeof(hints));
ntop, text); hints.ai_family = from.ss_family;
packet_disconnect("Connection from %.100s with IP options:%.800s", hints.ai_socktype = SOCK_STREAM;
ntop, text); if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
} log("reverse mapping checking getaddrinfo for %.700s "
"failed - POSSIBLE BREAKIN ATTEMPT!", name);
return xstrdup(ntop);
}
/* Look for the address from the list of addresses. */
for (ai = aitop; ai; ai = ai->ai_next) {
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
(strcmp(ntop, ntop2) == 0))
break;
}
freeaddrinfo(aitop);
/* If we reached the end of the list, the address was not there. */
if (!ai) {
/* Address not found for the host name. */
log("Address %.100s maps to %.600s, but this does not "
"map back to the address - POSSIBLE BREAKIN ATTEMPT!",
ntop, name);
return xstrdup(ntop);
} }
return xstrdup(name); return xstrdup(name);
} }
/*
* If IP options are supported, make sure there are none (log and
* disconnect them if any are found). Basically we are worried about
* source routing; it can be used to pretend you are somebody
* (ip-address) you are not. That itself may be "almost acceptable"
* under certain circumstances, but rhosts autentication is useless
* if source routing is accepted. Notice also that if we just dropped
* source routing here, the other side could use IP spoofing to do
* rest of the interaction and could still bypass security. So we
* exit here if we detect any IP options.
*/
/* IPv4 only */
void
check_ip_options(int socket, char *ipaddr)
{
u_char options[200];
char text[sizeof(options) * 3 + 1];
socklen_t option_size;
int i, ipproto;
struct protoent *ip;
if ((ip = getprotobyname("ip")) != NULL)
ipproto = ip->p_proto;
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
if (getsockopt(socket, ipproto, IP_OPTIONS, (void *)options,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
snprintf(text + i*3, sizeof(text) - i*3,
" %2.2x", options[i]);
log("Connection from %.100s with IP options:%.800s",
ipaddr, text);
packet_disconnect("Connection from %.100s with IP options:%.800s",
ipaddr, text);
}
}
/* /*
* Return the canonical name of the host in the other side of the current * Return the canonical name of the host in the other side of the current
* connection. The host name is cached, so it is efficient to call this * connection. The host name is cached, so it is efficient to call this
@ -147,23 +153,87 @@ get_remote_hostname(int socket)
*/ */
const char * const char *
get_canonical_hostname() get_canonical_hostname(int reverse_mapping_check)
{ {
static char *canonical_host_name = NULL; static char *canonical_host_name = NULL;
static int reverse_mapping_checked = 0;
/* Check if we have previously retrieved this same name. */ /* Check if we have previously retrieved name with same option. */
if (canonical_host_name != NULL) if (canonical_host_name != NULL) {
return canonical_host_name; if (reverse_mapping_checked != reverse_mapping_check)
xfree(canonical_host_name);
else
return canonical_host_name;
}
/* Get the real hostname if socket; otherwise return UNKNOWN. */ /* Get the real hostname if socket; otherwise return UNKNOWN. */
if (packet_connection_is_on_socket()) if (packet_connection_is_on_socket())
canonical_host_name = get_remote_hostname(packet_get_connection_in()); canonical_host_name = get_remote_hostname(
packet_get_connection_in(), reverse_mapping_check);
else else
canonical_host_name = xstrdup("UNKNOWN"); canonical_host_name = xstrdup("UNKNOWN");
reverse_mapping_checked = reverse_mapping_check;
return canonical_host_name; return canonical_host_name;
} }
/*
* Returns the remote IP-address of socket as a string. The returned
* string must be freed.
*/
char *
get_socket_address(int socket, int remote, int flags)
{
struct sockaddr_storage addr;
socklen_t addrlen;
char ntop[NI_MAXHOST];
/* Get IP address of client. */
addrlen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
if (remote) {
if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
< 0) {
debug("get_socket_ipaddr: getpeername failed: %.100s",
strerror(errno));
return NULL;
}
} else {
if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
< 0) {
debug("get_socket_ipaddr: getsockname failed: %.100s",
strerror(errno));
return NULL;
}
}
/* Get the address in ascii. */
if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
NULL, 0, flags) != 0) {
error("get_socket_ipaddr: getnameinfo %d failed", flags);
return NULL;
}
return xstrdup(ntop);
}
char *
get_peer_ipaddr(int socket)
{
return get_socket_address(socket, 1, NI_NUMERICHOST);
}
char *
get_local_ipaddr(int socket)
{
return get_socket_address(socket, 0, NI_NUMERICHOST);
}
char *
get_local_name(int socket)
{
return get_socket_address(socket, 0, NI_NAMEREQD);
}
/* /*
* Returns the IP-address of the remote host as a string. The returned * Returns the IP-address of the remote host as a string. The returned
* string must not be freed. * string must not be freed.
@ -173,68 +243,31 @@ const char *
get_remote_ipaddr() get_remote_ipaddr()
{ {
static char *canonical_host_ip = NULL; static char *canonical_host_ip = NULL;
struct sockaddr_storage from;
socklen_t fromlen;
int socket;
char ntop[NI_MAXHOST];
/* Check whether we have chached the name. */ /* Check whether we have cached the ipaddr. */
if (canonical_host_ip != NULL) if (canonical_host_ip == NULL) {
return canonical_host_ip; if (packet_connection_is_on_socket()) {
canonical_host_ip =
/* If not a socket, return UNKNOWN. */ get_peer_ipaddr(packet_get_connection_in());
if (!packet_connection_is_on_socket()) { if (canonical_host_ip == NULL)
canonical_host_ip = xstrdup("UNKNOWN"); fatal_cleanup();
return canonical_host_ip; } else {
/* If not on socket, return UNKNOWN. */
canonical_host_ip = xstrdup("UNKNOWN");
}
} }
/* Get client socket. */
socket = packet_get_connection_in();
/* Get IP address of client. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Get the IP address in ascii. */
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_remote_ipaddr: getnameinfo NI_NUMERICHOST failed");
canonical_host_ip = xstrdup(ntop);
/* Return ip address string. */
return canonical_host_ip; return canonical_host_ip;
} }
/*
* Returns the IP-address of the local host as a string. The returned
* string must be freed.
*/
const char * const char *
get_ipaddr(int socket) get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check)
{ {
static char *canonical_host_ip = NULL; static const char *remote = "";
struct sockaddr_storage from; if (utmp_len > 0)
socklen_t fromlen; remote = get_canonical_hostname(reverse_mapping_check);
char ntop[NI_MAXHOST]; if (utmp_len == 0 || strlen(remote) > utmp_len)
remote = get_remote_ipaddr();
/* Get IP address of server. */ return remote;
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if (getsockname(socket, (struct sockaddr *)&from, &fromlen) < 0) {
debug("getsockname failed: %.100s", strerror(errno));
fatal_cleanup();
}
/* Get the IP address in ascii. */
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0)
fatal("get_local_ipaddr: getnameinfo NI_NUMERICHOST failed");
/* Return ip address string. */
return xstrdup(ntop);
} }
/* Returns the local/remote port for the socket. */ /* Returns the local/remote port for the socket. */

File diff suppressed because it is too large Load Diff

View File

@ -32,12 +32,14 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
/* RCSID("$FreeBSD$"); */ /* RCSID("$FreeBSD$"); */
/* RCSID("$OpenBSD: channels.h,v 1.22 2000/10/27 07:48:22 markus Exp $"); */
#ifndef CHANNELS_H #ifndef CHANNELS_H
#define CHANNELS_H #define CHANNELS_H
#include "buffer.h"
/* Definitions for channel types. */ /* Definitions for channel types. */
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */ #define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */ #define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
@ -50,7 +52,10 @@
#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */ #define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */
#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */ #define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */
#define SSH_CHANNEL_LARVAL 10 /* larval session */ #define SSH_CHANNEL_LARVAL 10 /* larval session */
#define SSH_CHANNEL_MAX_TYPE 11 #define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */
#define SSH_CHANNEL_CONNECTING 12
#define SSH_CHANNEL_DYNAMIC 13
#define SSH_CHANNEL_MAX_TYPE 14
/* /*
* Data structure for channel data. This is iniailized in channel_allocate * Data structure for channel data. This is iniailized in channel_allocate
@ -149,7 +154,6 @@ void channel_input_open_confirmation(int type, int plen, void *ctxt);
void channel_input_open_failure(int type, int plen, void *ctxt); void channel_input_open_failure(int type, int plen, void *ctxt);
void channel_input_port_open(int type, int plen, void *ctxt); void channel_input_port_open(int type, int plen, void *ctxt);
void channel_input_window_adjust(int type, int plen, void *ctxt); void channel_input_window_adjust(int type, int plen, void *ctxt);
void channel_input_open(int type, int plen, void *ctxt);
/* Sets specific protocol options. */ /* Sets specific protocol options. */
void channel_set_options(int hostname_in_open); void channel_set_options(int hostname_in_open);
@ -164,8 +168,13 @@ int channel_allocate(int type, int sock, char *remote_name);
/* Free the channel and close its socket. */ /* Free the channel and close its socket. */
void channel_free(int channel); void channel_free(int channel);
/* Add any bits relevant to channels in select bitmasks. */ /*
void channel_prepare_select(fd_set * readset, fd_set * writeset); * Allocate/update select bitmasks and add any bits relevant to channels in
* select bitmasks.
*/
void
channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
int rekeying);
/* /*
* After select, perform any appropriate operations for channels which have * After select, perform any appropriate operations for channels which have
@ -189,9 +198,6 @@ void channel_stop_listening(void);
*/ */
void channel_close_all(void); void channel_close_all(void);
/* Returns the maximum file descriptor number used by the channels. */
int channel_max_fd(void);
/* Returns true if there is still an open channel over the connection. */ /* Returns true if there is still an open channel over the connection. */
int channel_still_open(void); int channel_still_open(void);
@ -204,12 +210,15 @@ char *channel_open_message(void);
/* /*
* Initiate forwarding of connections to local port "port" through the secure * Initiate forwarding of connections to local port "port" through the secure
* channel to host:port from remote side. This never returns if there was an * channel to host:port from remote side.
* error.
*/ */
void int
channel_request_local_forwarding(u_short port, const char *host, channel_request_local_forwarding(u_short listen_port,
u_short remote_port, int gateway_ports); const char *host_to_connect, u_short port_to_connect, int gateway_ports);
int
channel_request_forwarding(const char *listen_address, u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports,
int remote_fwd);
/* /*
* Initiate forwarding of connections to port "port" on remote host through * Initiate forwarding of connections to port "port" on remote host through
@ -222,12 +231,18 @@ channel_request_remote_forwarding(u_short port, const char *host,
u_short remote_port); u_short remote_port);
/* /*
* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually * Permits opening to any host/port if permitted_opens[] is empty. This is
* called by the server, because the user could connect to any port anyway, * usually called by the server, because the user could connect to any port
* and the server has no way to know but to trust the client anyway. * anyway, and the server has no way to know but to trust the client anyway.
*/ */
void channel_permit_all_opens(void); void channel_permit_all_opens(void);
/* Add host/port to list of allowed targets for port forwarding */
void channel_add_permitted_opens(char *host, int port);
/* Flush list */
void channel_clear_permitted_opens(void);
/* /*
* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
* listening for the port, and sends back a success reply (or disconnect * listening for the port, and sends back a success reply (or disconnect
@ -290,6 +305,9 @@ void auth_input_open_request(int type, int plen, void *ctxt);
/* XXX */ /* XXX */
int channel_connect_to(const char *host, u_short host_port); int channel_connect_to(const char *host, u_short host_port);
int channel_connect_by_listen_adress(u_short listen_port);
int x11_connect_display(void); int x11_connect_display(void);
int channel_find_open(void);
#endif #endif

View File

@ -35,11 +35,12 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: cipher.c,v 1.37 2000/10/23 19:31:54 markus Exp $"); RCSID("$OpenBSD: cipher.c,v 1.43 2001/02/04 15:32:23 stevesk Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "log.h"
#include "cipher.h"
#include <openssl/md5.h> #include <openssl/md5.h>
@ -155,14 +156,9 @@ des3_ssh1_encrypt(CipherContext *cc, u_char *dest, const u_char *src,
memcpy(&iv1, iv2, 8); memcpy(&iv1, iv2, 8);
des_cbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT); des_ncbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
memcpy(&iv1, dest + len - 8, 8); des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_DECRYPT);
memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */
des_cbc_encrypt(dest, dest, len, cc->u.des3.key3, iv3, DES_ENCRYPT);
memcpy(iv3, dest + len - 8, 8);
} }
void void
des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src, des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
@ -174,22 +170,16 @@ des3_ssh1_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
memcpy(&iv1, iv2, 8); memcpy(&iv1, iv2, 8);
des_cbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT); des_ncbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
memcpy(iv3, src + len - 8, 8); des_ncbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
des_ncbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
des_cbc_encrypt(dest, dest, len, cc->u.des3.key2, iv2, DES_ENCRYPT);
memcpy(iv2, dest + len - 8, 8);
des_cbc_encrypt(dest, dest, len, cc->u.des3.key1, &iv1, DES_DECRYPT);
/* memcpy(&iv1, iv2, 8); */
/* Note how iv1 == iv2 on entry and exit. */
} }
/* Blowfish */ /* Blowfish */
void void
blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen) blowfish_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{ {
BF_set_key(&cc->u.bf.key, keylen, (unsigned char *)key); BF_set_key(&cc->u.bf.key, keylen, (u_char *)key);
} }
void void
blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) blowfish_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
@ -219,7 +209,7 @@ blowfish_cbc_decrypt(CipherContext *cc, u_char *dest, const u_char *src,
* and after encryption/decryption. Thus the swap_bytes stuff (yuk). * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
*/ */
static void static void
swap_bytes(const unsigned char *src, unsigned char *dst, int n) swap_bytes(const u_char *src, u_char *dst, int n)
{ {
char c[4]; char c[4];
@ -272,12 +262,12 @@ arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
void void
cast_setkey(CipherContext *cc, const u_char *key, u_int keylen) cast_setkey(CipherContext *cc, const u_char *key, u_int keylen)
{ {
CAST_set_key(&cc->u.cast.key, keylen, (unsigned char *) key); CAST_set_key(&cc->u.cast.key, keylen, (u_char *) key);
} }
void void
cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) cast_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{ {
if (iv == NULL) if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name); fatal("no IV for %s.", cc->cipher->name);
memcpy(cc->u.cast.iv, (char *)iv, 8); memcpy(cc->u.cast.iv, (char *)iv, 8);
} }
@ -306,7 +296,7 @@ rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
void void
rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen) rijndael_setiv(CipherContext *cc, const u_char *iv, u_int ivlen)
{ {
if (iv == NULL) if (iv == NULL)
fatal("no IV for %s.", cc->cipher->name); fatal("no IV for %s.", cc->cipher->name);
memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE); memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
} }
@ -426,15 +416,15 @@ Cipher ciphers[] = {
SSH_CIPHER_SSH2, 16, 32, SSH_CIPHER_SSH2, 16, 32,
rijndael_setkey, rijndael_setiv, rijndael_setkey, rijndael_setiv,
rijndael_cbc_encrypt, rijndael_cbc_decrypt }, rijndael_cbc_encrypt, rijndael_cbc_decrypt },
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL } { NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL, NULL, NULL, NULL }
}; };
/*--*/ /*--*/
unsigned int u_int
cipher_mask_ssh1(int client) cipher_mask_ssh1(int client)
{ {
unsigned int mask = 0; u_int mask = 0;
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
mask |= 1 << SSH_CIPHER_BLOWFISH; mask |= 1 << SSH_CIPHER_BLOWFISH;
if (client) { if (client) {
@ -553,7 +543,7 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
const char *passphrase) const char *passphrase)
{ {
MD5_CTX md; MD5_CTX md;
unsigned char digest[16]; u_char digest[16];
MD5_Init(&md); MD5_Init(&md);
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));

View File

@ -32,8 +32,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* RCSID("$OpenBSD: cipher.h,v 1.22 2000/10/13 18:59:14 markus Exp $"); */ /* RCSID("$OpenBSD: cipher.h,v 1.25 2000/12/19 23:17:56 markus Exp $"); */
/* $FreeBSD$ */ /* RCSID("$FreeBSD$"); */
#ifndef CIPHER_H #ifndef CIPHER_H
#define CIPHER_H #define CIPHER_H
@ -104,7 +104,7 @@ struct Cipher {
void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int); void (*decrypt)(CipherContext *, u_char *, const u_char *, u_int);
}; };
unsigned int cipher_mask_ssh1(int client); u_int cipher_mask_ssh1(int client);
Cipher *cipher_by_name(const char *name); Cipher *cipher_by_name(const char *name);
Cipher *cipher_by_number(int id); Cipher *cipher_by_number(int id);
int cipher_number(const char *name); int cipher_number(const char *name);

View File

@ -24,13 +24,14 @@
#include "includes.h" #include "includes.h"
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
RCSID("$OpenBSD: compat.c,v 1.27 2000/10/31 09:31:58 markus Exp $"); RCSID("$OpenBSD: compat.c,v 1.47 2001/04/18 23:43:25 markus Exp $");
#include <regex.h>
#include "ssh.h"
#include "packet.h" #include "packet.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "compat.h" #include "compat.h"
#include <regex.h> #include "log.h"
int compat13 = 0; int compat13 = 0;
int compat20 = 0; int compat20 = 0;
@ -59,22 +60,55 @@ compat_datafellows(const char *version)
char *pat; char *pat;
int bugs; int bugs;
} check[] = { } check[] = {
{ "^OpenSSH[-_]2\\.3", 0 }, { "^OpenSSH[-_]2\\.[012]",
{ "^OpenSSH[-_]2\\.[012]", SSH_OLD_SESSIONID }, SSH_OLD_SESSIONID|SSH_BUG_BANNER|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.3\\.0", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.3\\.", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY},
{ "^OpenSSH_2\\.5\\.[01]p1",
SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.5\\.[012]",
SSH_OLD_DHGEX|SSH_BUG_NOREKEY },
{ "^OpenSSH_2\\.5\\.3",
SSH_BUG_NOREKEY },
{ "^OpenSSH", 0 },
{ "MindTerm", 0 }, { "MindTerm", 0 },
{ "^2\\.1\\.0 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| { "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID }, SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.1 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE },
{ "^2\\.0\\.1[3-9]", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
SSH_BUG_PKOK|SSH_BUG_RSASIGMD5|
SSH_BUG_HBSERVICE },
{ "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| { "^2\\.0\\.", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
SSH_OLD_SESSIONID| SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD }, SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
{ "^2\\.[23]\\.0 ", SSH_BUG_HMAC}, SSH_BUG_PKAUTH|SSH_BUG_PKOK|
SSH_BUG_RSASIGMD5 },
{ "^2\\.[23]\\.0", SSH_BUG_HMAC|SSH_BUG_RSASIGMD5 },
{ "^2\\.3\\.", SSH_BUG_RSASIGMD5 },
{ "^2\\.[2-9]\\.", 0 }, { "^2\\.[2-9]\\.", 0 },
{ "^2\\.4$", SSH_OLD_SESSIONID}, /* Van Dyke */ { "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */
{ "^3\\.0 SecureCRT", SSH_OLD_SESSIONID}, { "^3\\.0 SecureCRT", SSH_OLD_SESSIONID },
{ "^1\\.7 SecureFX", SSH_OLD_SESSIONID}, { "^1\\.7 SecureFX", SSH_OLD_SESSIONID },
{ "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG}, { "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG },
{ "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG}, { "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG },
{ "^2\\.", SSH_BUG_HMAC}, /* XXX fallback */ { "^1\\.3\\.2", SSH_BUG_IGNOREMSG }, /* f-secure */
{ "^SSH Compatible Server", /* Netscreen */
SSH_BUG_PASSWORDPAD },
{ "^OSU_0", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.[0-4]", SSH_BUG_PASSWORDPAD },
{ "^OSU_1\\.5alpha[1-3]",
SSH_BUG_PASSWORDPAD },
{ "^SSH_Version_Mapper",
SSH_BUG_SCANNER },
{ NULL, 0 } { NULL, 0 }
}; };
/* process table, return first match */ /* process table, return first match */
@ -89,7 +123,7 @@ compat_datafellows(const char *version)
ret = regexec(&reg, version, 0, NULL, 0); ret = regexec(&reg, version, 0, NULL, 0);
regfree(&reg); regfree(&reg);
if (ret == 0) { if (ret == 0) {
debug("match: %s pat %s\n", version, check[i].pat); debug("match: %s pat %s", version, check[i].pat);
datafellows = check[i].bugs; datafellows = check[i].bugs;
return; return;
} }
@ -125,3 +159,33 @@ proto_spec(const char *spec)
xfree(s); xfree(s);
return ret; return ret;
} }
char *
compat_cipher_proposal(char *cipher_prop)
{
char *orig_prop, *fix_ciphers;
char *cp, *tmp;
size_t len;
if (!(datafellows & SSH_BUG_BIGENDIANAES))
return(cipher_prop);
len = strlen(cipher_prop) + 1;
fix_ciphers = xmalloc(len);
*fix_ciphers = '\0';
tmp = orig_prop = xstrdup(cipher_prop);
while((cp = strsep(&tmp, ",")) != NULL) {
if (strncmp(cp, "aes", 3) && strncmp(cp, "rijndael", 8)) {
if (*fix_ciphers)
strlcat(fix_ciphers, ",", len);
strlcat(fix_ciphers, cp, len);
}
}
xfree(orig_prop);
debug2("Original cipher proposal: %s", cipher_prop);
debug2("Compat cipher proposal: %s", fix_ciphers);
if (!*fix_ciphers)
fatal("No available ciphers found.");
return(fix_ciphers);
}

View File

@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/* RCSID("$FreeBSD$"); */ /* RCSID("$FreeBSD$"); */
/* RCSID("$OpenBSD: compat.h,v 1.11 2000/10/14 12:16:56 markus Exp $"); */ /* RCSID("$OpenBSD: compat.h,v 1.23 2001/04/12 19:15:24 markus Exp $"); */
#ifndef COMPAT_H #ifndef COMPAT_H
#define COMPAT_H #define COMPAT_H
@ -32,17 +32,29 @@
#define SSH_PROTO_1_PREFERRED 0x02 #define SSH_PROTO_1_PREFERRED 0x02
#define SSH_PROTO_2 0x04 #define SSH_PROTO_2 0x04
#define SSH_BUG_SIGBLOB 0x01 #define SSH_BUG_SIGBLOB 0x0001
#define SSH_BUG_PUBKEYAUTH 0x02 #define SSH_BUG_PKSERVICE 0x0002
#define SSH_BUG_HMAC 0x04 #define SSH_BUG_HMAC 0x0004
#define SSH_BUG_X11FWD 0x08 #define SSH_BUG_X11FWD 0x0008
#define SSH_OLD_SESSIONID 0x10 #define SSH_OLD_SESSIONID 0x0010
#define SSH_BUG_IGNOREMSG 0x20 #define SSH_BUG_PKAUTH 0x0020
#define SSH_BUG_DEBUG 0x0040
#define SSH_BUG_BANNER 0x0080
#define SSH_BUG_IGNOREMSG 0x0100
#define SSH_BUG_PKOK 0x0200
#define SSH_BUG_PASSWORDPAD 0x0400
#define SSH_BUG_SCANNER 0x0800
#define SSH_BUG_BIGENDIANAES 0x1000
#define SSH_BUG_RSASIGMD5 0x2000
#define SSH_OLD_DHGEX 0x4000
#define SSH_BUG_NOREKEY 0x8000
#define SSH_BUG_HBSERVICE 0x10000
void enable_compat13(void); void enable_compat13(void);
void enable_compat20(void); void enable_compat20(void);
void compat_datafellows(const char *s); void compat_datafellows(const char *s);
int proto_spec(const char *spec); int proto_spec(const char *spec);
char *compat_cipher_proposal(char *cipher_prop);
extern int compat13; extern int compat13;
extern int compat20; extern int compat20;
extern int datafellows; extern int datafellows;

View File

@ -36,16 +36,14 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: hostfile.c,v 1.20 2000/09/07 20:27:51 deraadt Exp $"); RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "match.h" #include "match.h"
#include "ssh.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "key.h" #include "key.h"
#include "hostfile.h" #include "hostfile.h"
#include "log.h"
/* /*
* Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
@ -53,17 +51,15 @@ RCSID("$FreeBSD$");
*/ */
int int
hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
{ {
unsigned int bits;
char *cp; char *cp;
/* Skip leading whitespace. */ /* Skip leading whitespace. */
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
; ;
bits = key_read(ret, &cp); if (key_read(ret, &cp) != 1)
if (bits == 0)
return 0; return 0;
/* Skip trailing whitespace. */ /* Skip trailing whitespace. */
@ -72,14 +68,14 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
/* Return results. */ /* Return results. */
*cpp = cp; *cpp = cp;
*bitsp = bits; *bitsp = key_size(ret);
return 1; return 1;
} }
int int
auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) auth_rsa_read_key(char **cpp, u_int *bitsp, BIGNUM * e, BIGNUM * n)
{ {
Key *k = key_new(KEY_RSA); Key *k = key_new(KEY_RSA1);
int ret = hostfile_read_key(cpp, bitsp, k); int ret = hostfile_read_key(cpp, bitsp, k);
BN_copy(e, k->rsa->e); BN_copy(e, k->rsa->e);
BN_copy(n, k->rsa->n); BN_copy(n, k->rsa->n);
@ -90,7 +86,7 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
int int
hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum)
{ {
if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
return 1; return 1;
if (bits != BN_num_bits(key->rsa->n)) { if (bits != BN_num_bits(key->rsa->n)) {
log("Warning: %s, line %d: keysize mismatch for host %s: " log("Warning: %s, line %d: keysize mismatch for host %s: "
@ -110,15 +106,17 @@ hostfile_check_key(int bits, Key *key, const char *host, const char *filename, i
*/ */
HostStatus HostStatus
check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found) check_host_in_hostfile(const char *filename, const char *host, Key *key,
Key *found, int *numret)
{ {
FILE *f; FILE *f;
char line[8192]; char line[8192];
int linenum = 0; int linenum = 0;
unsigned int kbits, hostlen; u_int kbits;
char *cp, *cp2; char *cp, *cp2;
HostStatus end_return; HostStatus end_return;
debug3("check_host_in_hostfile: filename %s", filename);
if (key == NULL) if (key == NULL)
fatal("no key to look up"); fatal("no key to look up");
/* Open the file containing the list of known hosts. */ /* Open the file containing the list of known hosts. */
@ -126,9 +124,6 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
if (!f) if (!f)
return HOST_NEW; return HOST_NEW;
/* Cache the length of the host name. */
hostlen = strlen(host);
/* /*
* Return value when the loop terminates. This is set to * Return value when the loop terminates. This is set to
* HOST_CHANGED if we have seen a different key for the host and have * HOST_CHANGED if we have seen a different key for the host and have
@ -136,7 +131,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
*/ */
end_return = HOST_NEW; end_return = HOST_NEW;
/* Go trough the file. */ /* Go through the file. */
while (fgets(line, sizeof(line), f)) { while (fgets(line, sizeof(line), f)) {
cp = line; cp = line;
linenum++; linenum++;
@ -152,7 +147,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
; ;
/* Check if the host name matches. */ /* Check if the host name matches. */
if (match_hostname(host, cp, (unsigned int) (cp2 - cp)) != 1) if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1)
continue; continue;
/* Got a match. Skip host name. */ /* Got a match. Skip host name. */
@ -167,9 +162,13 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *fo
if (!hostfile_check_key(kbits, found, host, filename, linenum)) if (!hostfile_check_key(kbits, found, host, filename, linenum))
continue; continue;
if (numret != NULL)
*numret = linenum;
/* Check if the current key is the same as the given key. */ /* Check if the current key is the same as the given key. */
if (key_equal(key, found)) { if (key_equal(key, found)) {
/* Ok, they match. */ /* Ok, they match. */
debug3("check_host_in_hostfile: match line %d", linenum);
fclose(f); fclose(f);
return HOST_OK; return HOST_OK;
} }

View File

@ -1,3 +1,5 @@
/* $OpenBSD: includes.h,v 1.14 2001/01/29 01:58:16 niklas Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland

View File

@ -31,21 +31,21 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "includes.h" #include "includes.h"
#include "ssh.h" RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "dsa.h"
#include "uuencode.h"
RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#define SSH_DSS "ssh-dss" #include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "rsa.h"
#include "ssh-dss.h"
#include "ssh-rsa.h"
#include "uuencode.h"
#include "buffer.h"
#include "bufaux.h"
#include "log.h"
Key * Key *
key_new(int type) key_new(int type)
@ -58,6 +58,7 @@ key_new(int type)
k->dsa = NULL; k->dsa = NULL;
k->rsa = NULL; k->rsa = NULL;
switch (k->type) { switch (k->type) {
case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
rsa = RSA_new(); rsa = RSA_new();
rsa->n = BN_new(); rsa->n = BN_new();
@ -72,7 +73,7 @@ key_new(int type)
dsa->pub_key = BN_new(); dsa->pub_key = BN_new();
k->dsa = dsa; k->dsa = dsa;
break; break;
case KEY_EMPTY: case KEY_UNSPEC:
break; break;
default: default:
fatal("key_new: bad key type %d", k->type); fatal("key_new: bad key type %d", k->type);
@ -80,10 +81,35 @@ key_new(int type)
} }
return k; return k;
} }
Key *
key_new_private(int type)
{
Key *k = key_new(type);
switch (k->type) {
case KEY_RSA1:
case KEY_RSA:
k->rsa->d = BN_new();
k->rsa->iqmp = BN_new();
k->rsa->q = BN_new();
k->rsa->p = BN_new();
k->rsa->dmq1 = BN_new();
k->rsa->dmp1 = BN_new();
break;
case KEY_DSA:
k->dsa->priv_key = BN_new();
break;
case KEY_UNSPEC:
break;
default:
break;
}
return k;
}
void void
key_free(Key *k) key_free(Key *k)
{ {
switch (k->type) { switch (k->type) {
case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
if (k->rsa != NULL) if (k->rsa != NULL)
RSA_free(k->rsa); RSA_free(k->rsa);
@ -94,6 +120,8 @@ key_free(Key *k)
DSA_free(k->dsa); DSA_free(k->dsa);
k->dsa = NULL; k->dsa = NULL;
break; break;
case KEY_UNSPEC:
break;
default: default:
fatal("key_free: bad key type %d", k->type); fatal("key_free: bad key type %d", k->type);
break; break;
@ -106,6 +134,7 @@ key_equal(Key *a, Key *b)
if (a == NULL || b == NULL || a->type != b->type) if (a == NULL || b == NULL || a->type != b->type)
return 0; return 0;
switch (a->type) { switch (a->type) {
case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
return a->rsa != NULL && b->rsa != NULL && return a->rsa != NULL && b->rsa != NULL &&
BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
@ -125,20 +154,31 @@ key_equal(Key *a, Key *b)
return 0; return 0;
} }
/* u_char*
* Generate key fingerprint in ascii format. key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
*/
char *
key_fingerprint(Key *k)
{ {
static char retval[(EVP_MAX_MD_SIZE+1)*3]; EVP_MD *md = NULL;
unsigned char *blob = NULL; EVP_MD_CTX ctx;
u_char *blob = NULL;
u_char *retval = NULL;
int len = 0; int len = 0;
int nlen, elen; int nlen, elen;
*dgst_raw_length = 0;
switch (dgst_type) {
case SSH_FP_MD5:
md = EVP_md5();
break;
case SSH_FP_SHA1:
md = EVP_sha1();
break;
default:
fatal("key_fingerprint_raw: bad digest type %d",
dgst_type);
}
switch (k->type) { switch (k->type) {
case KEY_RSA: case KEY_RSA1:
nlen = BN_num_bytes(k->rsa->n); nlen = BN_num_bytes(k->rsa->n);
elen = BN_num_bytes(k->rsa->e); elen = BN_num_bytes(k->rsa->e);
len = nlen + elen; len = nlen + elen;
@ -147,34 +187,121 @@ key_fingerprint(Key *k)
BN_bn2bin(k->rsa->e, blob + nlen); BN_bn2bin(k->rsa->e, blob + nlen);
break; break;
case KEY_DSA: case KEY_DSA:
dsa_make_key_blob(k, &blob, &len); case KEY_RSA:
key_to_blob(k, &blob, &len);
break;
case KEY_UNSPEC:
return retval;
break; break;
default: default:
fatal("key_fingerprint: bad key type %d", k->type); fatal("key_fingerprint_raw: bad key type %d", k->type);
break; break;
} }
retval[0] = '\0';
if (blob != NULL) { if (blob != NULL) {
int i; retval = xmalloc(EVP_MAX_MD_SIZE);
unsigned char digest[EVP_MAX_MD_SIZE];
EVP_MD *md = EVP_md5();
EVP_MD_CTX ctx;
EVP_DigestInit(&ctx, md); EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, blob, len); EVP_DigestUpdate(&ctx, blob, len);
EVP_DigestFinal(&ctx, digest, NULL); EVP_DigestFinal(&ctx, retval, NULL);
for(i = 0; i < md->md_size; i++) { *dgst_raw_length = md->md_size;
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", digest[i]);
strlcat(retval, hex, sizeof(retval));
}
retval[strlen(retval) - 1] = '\0';
memset(blob, 0, len); memset(blob, 0, len);
xfree(blob); xfree(blob);
} else {
fatal("key_fingerprint_raw: blob is null");
} }
return retval; return retval;
} }
char*
key_fingerprint_hex(u_char* dgst_raw, size_t dgst_raw_len)
{
char *retval;
int i;
retval = xmalloc(dgst_raw_len * 3 + 1);
retval[0] = '\0';
for(i = 0; i < dgst_raw_len; i++) {
char hex[4];
snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
strlcat(retval, hex, dgst_raw_len * 3);
}
retval[(dgst_raw_len * 3) - 1] = '\0';
return retval;
}
char*
key_fingerprint_bubblebabble(u_char* dgst_raw, size_t dgst_raw_len)
{
char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
u_int i, j = 0, rounds, seed = 1;
char *retval;
rounds = (dgst_raw_len / 2) + 1;
retval = xmalloc(sizeof(char) * (rounds*6));
retval[j++] = 'x';
for (i = 0; i < rounds; i++) {
u_int idx0, idx1, idx2, idx3, idx4;
if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
seed) % 6;
idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
(seed / 6)) % 6;
retval[j++] = vowels[idx0];
retval[j++] = consonants[idx1];
retval[j++] = vowels[idx2];
if ((i + 1) < rounds) {
idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
retval[j++] = consonants[idx3];
retval[j++] = '-';
retval[j++] = consonants[idx4];
seed = ((seed * 5) +
((((u_int)(dgst_raw[2 * i])) * 7) +
((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
}
} else {
idx0 = seed % 6;
idx1 = 16;
idx2 = seed / 6;
retval[j++] = vowels[idx0];
retval[j++] = consonants[idx1];
retval[j++] = vowels[idx2];
}
}
retval[j++] = 'x';
retval[j++] = '\0';
return retval;
}
char*
key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
{
char *retval = NULL;
u_char *dgst_raw;
size_t dgst_raw_len;
dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
if (!dgst_raw)
fatal("key_fingerprint: null from key_fingerprint_raw()");
switch(dgst_rep) {
case SSH_FP_HEX:
retval = key_fingerprint_hex(dgst_raw, dgst_raw_len);
break;
case SSH_FP_BUBBLEBABBLE:
retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
break;
default:
fatal("key_fingerprint_ex: bad digest representation %d",
dgst_rep);
break;
}
memset(dgst_raw, 0, dgst_raw_len);
xfree(dgst_raw);
return retval;
}
/* /*
* Reads a multiple-precision integer in decimal from the buffer, and advances * Reads a multiple-precision integer in decimal from the buffer, and advances
* the pointer. The integer must already be initialized. This function is * the pointer. The integer must already be initialized. This function is
@ -227,59 +354,109 @@ write_bignum(FILE *f, BIGNUM *num)
return 0; return 0;
} }
fprintf(f, " %s", buf); fprintf(f, " %s", buf);
free(buf); xfree(buf);
return 1; return 1;
} }
unsigned int
/* returns 1 ok, -1 error, 0 type mismatch */
int
key_read(Key *ret, char **cpp) key_read(Key *ret, char **cpp)
{ {
Key *k; Key *k;
unsigned int bits = 0; int success = -1;
char *cp; char *cp, *space;
int len, n; int len, n, type;
unsigned char *blob; u_int bits;
u_char *blob;
cp = *cpp; cp = *cpp;
switch(ret->type) { switch(ret->type) {
case KEY_RSA: case KEY_RSA1:
/* Get number of bits. */ /* Get number of bits. */
if (*cp < '0' || *cp > '9') if (*cp < '0' || *cp > '9')
return 0; /* Bad bit count... */ return -1; /* Bad bit count... */
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
bits = 10 * bits + *cp - '0'; bits = 10 * bits + *cp - '0';
if (bits == 0) if (bits == 0)
return 0; return -1;
*cpp = cp; *cpp = cp;
/* Get public exponent, public modulus. */ /* Get public exponent, public modulus. */
if (!read_bignum(cpp, ret->rsa->e)) if (!read_bignum(cpp, ret->rsa->e))
return 0; return -1;
if (!read_bignum(cpp, ret->rsa->n)) if (!read_bignum(cpp, ret->rsa->n))
return 0; return -1;
success = 1;
break; break;
case KEY_UNSPEC:
case KEY_RSA:
case KEY_DSA: case KEY_DSA:
if (strncmp(cp, SSH_DSS " ", 7) != 0) space = strchr(cp, ' ');
if (space == NULL) {
debug3("key_read: no space");
return -1;
}
*space = '\0';
type = key_type_from_name(cp);
*space = ' ';
if (type == KEY_UNSPEC) {
debug3("key_read: no key found");
return -1;
}
cp = space+1;
if (*cp == '\0') {
debug3("key_read: short string");
return -1;
}
if (ret->type == KEY_UNSPEC) {
ret->type = type;
} else if (ret->type != type) {
/* is a key, but different type */
debug3("key_read: type mismatch");
return 0; return 0;
cp += 7; }
len = 2*strlen(cp); len = 2*strlen(cp);
blob = xmalloc(len); blob = xmalloc(len);
n = uudecode(cp, blob, len); n = uudecode(cp, blob, len);
if (n < 0) { if (n < 0) {
error("key_read: uudecode %s failed", cp); error("key_read: uudecode %s failed", cp);
return 0; return -1;
} }
k = dsa_key_from_blob(blob, n); k = key_from_blob(blob, n);
if (k == NULL) { if (k == NULL) {
error("key_read: dsa_key_from_blob %s failed", cp); error("key_read: key_from_blob %s failed", cp);
return 0; return -1;
} }
xfree(blob); xfree(blob);
if (ret->dsa != NULL) if (k->type != type) {
DSA_free(ret->dsa); error("key_read: type mismatch: encoding error");
ret->dsa = k->dsa; key_free(k);
k->dsa = NULL; return -1;
}
/*XXXX*/
if (ret->type == KEY_RSA) {
if (ret->rsa != NULL)
RSA_free(ret->rsa);
ret->rsa = k->rsa;
k->rsa = NULL;
success = 1;
#ifdef DEBUG_PK
RSA_print_fp(stderr, ret->rsa, 8);
#endif
} else {
if (ret->dsa != NULL)
DSA_free(ret->dsa);
ret->dsa = k->dsa;
k->dsa = NULL;
success = 1;
#ifdef DEBUG_PK
DSA_print_fp(stderr, ret->dsa, 8);
#endif
}
/*XXXX*/
if (success != 1)
break;
key_free(k); key_free(k);
bits = BN_num_bits(ret->dsa->p);
/* advance cp: skip whitespace and data */ /* advance cp: skip whitespace and data */
while (*cp == ' ' || *cp == '\t') while (*cp == ' ' || *cp == '\t')
cp++; cp++;
@ -291,15 +468,15 @@ key_read(Key *ret, char **cpp)
fatal("key_read: bad key type: %d", ret->type); fatal("key_read: bad key type: %d", ret->type);
break; break;
} }
return bits; return success;
} }
int int
key_write(Key *key, FILE *f) key_write(Key *key, FILE *f)
{ {
int success = 0; int success = 0;
unsigned int bits = 0; u_int bits = 0;
if (key->type == KEY_RSA && key->rsa != NULL) { if (key->type == KEY_RSA1 && key->rsa != NULL) {
/* size of modulus 'n' */ /* size of modulus 'n' */
bits = BN_num_bits(key->rsa->n); bits = BN_num_bits(key->rsa->n);
fprintf(f, "%u", bits); fprintf(f, "%u", bits);
@ -309,14 +486,15 @@ key_write(Key *key, FILE *f)
} else { } else {
error("key_write: failed for RSA key"); error("key_write: failed for RSA key");
} }
} else if (key->type == KEY_DSA && key->dsa != NULL) { } else if ((key->type == KEY_DSA && key->dsa != NULL) ||
(key->type == KEY_RSA && key->rsa != NULL)) {
int len, n; int len, n;
unsigned char *blob, *uu; u_char *blob, *uu;
dsa_make_key_blob(key, &blob, &len); key_to_blob(key, &blob, &len);
uu = xmalloc(2*len); uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len); n = uuencode(blob, len, uu, 2*len);
if (n > 0) { if (n > 0) {
fprintf(f, "%s %s", SSH_DSS, uu); fprintf(f, "%s %s", key_ssh_name(key), uu);
success = 1; success = 1;
} }
xfree(blob); xfree(blob);
@ -328,6 +506,9 @@ char *
key_type(Key *k) key_type(Key *k)
{ {
switch (k->type) { switch (k->type) {
case KEY_RSA1:
return "RSA1";
break;
case KEY_RSA: case KEY_RSA:
return "RSA"; return "RSA";
break; break;
@ -337,9 +518,23 @@ key_type(Key *k)
} }
return "unknown"; return "unknown";
} }
unsigned int char *
key_ssh_name(Key *k)
{
switch (k->type) {
case KEY_RSA:
return "ssh-rsa";
break;
case KEY_DSA:
return "ssh-dss";
break;
}
return "ssh-unknown";
}
u_int
key_size(Key *k){ key_size(Key *k){
switch (k->type) { switch (k->type) {
case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
return BN_num_bits(k->rsa->n); return BN_num_bits(k->rsa->n);
break; break;
@ -349,3 +544,241 @@ key_size(Key *k){
} }
return 0; return 0;
} }
RSA *
rsa_generate_private_key(u_int bits)
{
RSA *private;
private = RSA_generate_key(bits, 35, NULL, NULL);
if (private == NULL)
fatal("rsa_generate_private_key: key generation failed.");
return private;
}
DSA*
dsa_generate_private_key(u_int bits)
{
DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
if (private == NULL)
fatal("dsa_generate_private_key: DSA_generate_parameters failed");
if (!DSA_generate_key(private))
fatal("dsa_generate_private_key: DSA_generate_key failed.");
if (private == NULL)
fatal("dsa_generate_private_key: NULL.");
return private;
}
Key *
key_generate(int type, u_int bits)
{
Key *k = key_new(KEY_UNSPEC);
switch (type) {
case KEY_DSA:
k->dsa = dsa_generate_private_key(bits);
break;
case KEY_RSA:
case KEY_RSA1:
k->rsa = rsa_generate_private_key(bits);
break;
default:
fatal("key_generate: unknown type %d", type);
}
k->type = type;
return k;
}
Key *
key_from_private(Key *k)
{
Key *n = NULL;
switch (k->type) {
case KEY_DSA:
n = key_new(k->type);
BN_copy(n->dsa->p, k->dsa->p);
BN_copy(n->dsa->q, k->dsa->q);
BN_copy(n->dsa->g, k->dsa->g);
BN_copy(n->dsa->pub_key, k->dsa->pub_key);
break;
case KEY_RSA:
case KEY_RSA1:
n = key_new(k->type);
BN_copy(n->rsa->n, k->rsa->n);
BN_copy(n->rsa->e, k->rsa->e);
break;
default:
fatal("key_from_private: unknown type %d", k->type);
break;
}
return n;
}
int
key_type_from_name(char *name)
{
if (strcmp(name, "rsa1") == 0){
return KEY_RSA1;
} else if (strcmp(name, "rsa") == 0){
return KEY_RSA;
} else if (strcmp(name, "dsa") == 0){
return KEY_DSA;
} else if (strcmp(name, "ssh-rsa") == 0){
return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0){
return KEY_DSA;
}
debug2("key_type_from_name: unknown key type '%s'", name);
return KEY_UNSPEC;
}
int
key_names_valid2(const char *names)
{
char *s, *cp, *p;
if (names == NULL || strcmp(names, "") == 0)
return 0;
s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
switch (key_type_from_name(p)) {
case KEY_RSA1:
case KEY_UNSPEC:
xfree(s);
return 0;
}
}
debug3("key names ok: [%s]", names);
xfree(s);
return 1;
}
Key *
key_from_blob(char *blob, int blen)
{
Buffer b;
char *ktype;
int rlen, type;
Key *key = NULL;
#ifdef DEBUG_PK
dump_base64(stderr, blob, blen);
#endif
buffer_init(&b);
buffer_append(&b, blob, blen);
ktype = buffer_get_string(&b, NULL);
type = key_type_from_name(ktype);
switch(type){
case KEY_RSA:
key = key_new(type);
buffer_get_bignum2(&b, key->rsa->e);
buffer_get_bignum2(&b, key->rsa->n);
#ifdef DEBUG_PK
RSA_print_fp(stderr, key->rsa, 8);
#endif
break;
case KEY_DSA:
key = key_new(type);
buffer_get_bignum2(&b, key->dsa->p);
buffer_get_bignum2(&b, key->dsa->q);
buffer_get_bignum2(&b, key->dsa->g);
buffer_get_bignum2(&b, key->dsa->pub_key);
#ifdef DEBUG_PK
DSA_print_fp(stderr, key->dsa, 8);
#endif
break;
case KEY_UNSPEC:
key = key_new(type);
break;
default:
error("key_from_blob: cannot handle type %s", ktype);
break;
}
rlen = buffer_len(&b);
if (key != NULL && rlen != 0)
error("key_from_blob: remaining bytes in key blob %d", rlen);
xfree(ktype);
buffer_free(&b);
return key;
}
int
key_to_blob(Key *key, u_char **blobp, u_int *lenp)
{
Buffer b;
int len;
u_char *buf;
if (key == NULL) {
error("key_to_blob: key == NULL");
return 0;
}
buffer_init(&b);
switch(key->type){
case KEY_DSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->dsa->p);
buffer_put_bignum2(&b, key->dsa->q);
buffer_put_bignum2(&b, key->dsa->g);
buffer_put_bignum2(&b, key->dsa->pub_key);
break;
case KEY_RSA:
buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->rsa->e);
buffer_put_bignum2(&b, key->rsa->n);
break;
default:
error("key_to_blob: illegal key type %d", key->type);
break;
}
len = buffer_len(&b);
buf = xmalloc(len);
memcpy(buf, buffer_ptr(&b), len);
memset(buffer_ptr(&b), 0, len);
buffer_free(&b);
if (lenp != NULL)
*lenp = len;
if (blobp != NULL)
*blobp = buf;
return len;
}
int
key_sign(
Key *key,
u_char **sigp, int *lenp,
u_char *data, int datalen)
{
switch(key->type){
case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen);
break;
case KEY_RSA:
return ssh_rsa_sign(key, sigp, lenp, data, datalen);
break;
default:
error("key_sign: illegal key type %d", key->type);
return -1;
break;
}
}
int
key_verify(
Key *key,
u_char *signature, int signaturelen,
u_char *data, int datalen)
{
switch(key->type){
case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen);
break;
case KEY_RSA:
return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
break;
default:
error("key_verify: illegal key type %d", key->type);
return -1;
break;
}
}

View File

@ -13,7 +13,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: mpaux.c,v 1.14 2000/09/07 20:27:52 deraadt Exp $"); RCSID("$OpenBSD: mpaux.c,v 1.16 2001/02/08 19:30:52 itojun Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
@ -22,16 +22,18 @@ RCSID("$FreeBSD$");
#include <openssl/md5.h> #include <openssl/md5.h>
#include "mpaux.h"
void void
compute_session_id(unsigned char session_id[16], compute_session_id(u_char session_id[16],
unsigned char cookie[8], u_char cookie[8],
BIGNUM* host_key_n, BIGNUM* host_key_n,
BIGNUM* session_key_n) BIGNUM* session_key_n)
{ {
unsigned int host_key_bytes = BN_num_bytes(host_key_n); u_int host_key_bytes = BN_num_bytes(host_key_n);
unsigned int session_key_bytes = BN_num_bytes(session_key_n); u_int session_key_bytes = BN_num_bytes(session_key_n);
unsigned int bytes = host_key_bytes + session_key_bytes; u_int bytes = host_key_bytes + session_key_bytes;
unsigned char *buf = xmalloc(bytes); u_char *buf = xmalloc(bytes);
MD5_CTX md; MD5_CTX md;
BN_bn2bin(host_key_n, buf); BN_bn2bin(host_key_n, buf);

View File

@ -11,8 +11,8 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
*/ */
/* RCSID("$OpenBSD: packet.h,v 1.17 2000/09/07 20:27:52 deraadt Exp $"); */ /* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
/* $FreeBSD$ */ /* RCSID("$FreeBSD$"); */
#ifndef PACKET_H #ifndef PACKET_H
#define PACKET_H #define PACKET_H
@ -47,17 +47,17 @@ void packet_close(void);
* encrypted independently of each other. Cipher types are defined in ssh.h. * encrypted independently of each other. Cipher types are defined in ssh.h.
*/ */
void void
packet_set_encryption_key(const unsigned char *key, unsigned int keylen, packet_set_encryption_key(const u_char *key, u_int keylen,
int cipher_type); int cipher_type);
/* /*
* Sets remote side protocol flags for the current connection. This can be * Sets remote side protocol flags for the current connection. This can be
* called at any time. * called at any time.
*/ */
void packet_set_protocol_flags(unsigned int flags); void packet_set_protocol_flags(u_int flags);
/* Returns the remote protocol flags set earlier by the above function. */ /* Returns the remote protocol flags set earlier by the above function. */
unsigned int packet_get_protocol_flags(void); u_int packet_get_protocol_flags(void);
/* Enables compression in both directions starting from the next packet. */ /* Enables compression in both directions starting from the next packet. */
void packet_start_compression(int level); void packet_start_compression(int level);
@ -66,7 +66,7 @@ void packet_start_compression(int level);
* Informs that the current session is interactive. Sets IP flags for * Informs that the current session is interactive. Sets IP flags for
* optimal performance in interactive use. * optimal performance in interactive use.
*/ */
void packet_set_interactive(int interactive, int keepalives); void packet_set_interactive(int interactive);
/* Returns true if the current connection is interactive. */ /* Returns true if the current connection is interactive. */
int packet_is_interactive(void); int packet_is_interactive(void);
@ -78,16 +78,16 @@ void packet_start(int type);
void packet_put_char(int ch); void packet_put_char(int ch);
/* Appends an integer to the packet data. */ /* Appends an integer to the packet data. */
void packet_put_int(unsigned int value); void packet_put_int(u_int value);
/* Appends an arbitrary precision integer to packet data. */ /* Appends an arbitrary precision integer to packet data. */
void packet_put_bignum(BIGNUM * value); void packet_put_bignum(BIGNUM * value);
void packet_put_bignum2(BIGNUM * value); void packet_put_bignum2(BIGNUM * value);
/* Appends a string to packet data. */ /* Appends a string to packet data. */
void packet_put_string(const char *buf, unsigned int len); void packet_put_string(const char *buf, u_int len);
void packet_put_cstring(const char *str); void packet_put_cstring(const char *str);
void packet_put_raw(const char *buf, unsigned int len); void packet_put_raw(const char *buf, u_int len);
/* /*
* Finalizes and sends the packet. If the encryption key has been set, * Finalizes and sends the packet. If the encryption key has been set,
@ -118,13 +118,13 @@ int packet_read_poll(int *packet_len_ptr);
* Buffers the given amount of input characters. This is intended to be used * Buffers the given amount of input characters. This is intended to be used
* together with packet_read_poll. * together with packet_read_poll.
*/ */
void packet_process_incoming(const char *buf, unsigned int len); void packet_process_incoming(const char *buf, u_int len);
/* Returns a character (0-255) from the packet data. */ /* Returns a character (0-255) from the packet data. */
unsigned int packet_get_char(void); u_int packet_get_char(void);
/* Returns an integer from the packet data. */ /* Returns an integer from the packet data. */
unsigned int packet_get_int(void); u_int packet_get_int(void);
/* /*
* Returns an arbitrary precision integer from the packet data. The integer * Returns an arbitrary precision integer from the packet data. The integer
@ -140,7 +140,7 @@ char *packet_get_raw(int *length_ptr);
* no longer needed. The length_ptr argument may be NULL, or point to an * no longer needed. The length_ptr argument may be NULL, or point to an
* integer into which the length of the string is stored. * integer into which the length of the string is stored.
*/ */
char *packet_get_string(unsigned int *length_ptr); char *packet_get_string(u_int *length_ptr);
/* /*
* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect * Logs the error in syslog using LOG_INFO, constructs and sends a disconnect
@ -179,8 +179,8 @@ extern int max_packet_size;
int packet_set_maxsize(int s); int packet_set_maxsize(int s);
#define packet_get_maxsize() max_packet_size #define packet_get_maxsize() max_packet_size
/* Stores tty modes from the fd into current packet. */ /* Stores tty modes from the fd or tiop into current packet. */
void tty_make_modes(int fd); void tty_make_modes(int fd, struct termios *tiop);
/* Parses tty modes for the fd from the current packet. */ /* Parses tty modes for the fd from the current packet. */
void tty_parse_modes(int fd, int *n_bytes_ptr); void tty_parse_modes(int fd, int *n_bytes_ptr);
@ -215,4 +215,10 @@ void packet_set_ssh2_format(void);
/* returns remaining payload bytes */ /* returns remaining payload bytes */
int packet_remaining(void); int packet_remaining(void);
/* append an ignore message */
void packet_send_ignore(int nbytes);
/* add an ignore message and make sure size (current+ignore) = n*sumlen */
void packet_inject_ignore(int sumlen);
#endif /* PACKET_H */ #endif /* PACKET_H */

View File

@ -1,4 +1,5 @@
/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */ /* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
/* $FreeBSD$ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -12,7 +13,7 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
*/ */
#define ETCDIR "/etc" #define ETCDIR "/etc/ssh"
#define _PATH_SSH_PIDDIR "/var/run" #define _PATH_SSH_PIDDIR "/var/run"
/* /*

View File

@ -12,14 +12,20 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: readconf.c,v 1.49 2000/10/11 20:27:23 markus Exp $"); RCSID("$OpenBSD: readconf.c,v 1.76 2001/04/17 10:53:25 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "ssh.h" #include "ssh.h"
#include "readconf.h"
#include "match.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "compat.h" #include "compat.h"
#include "cipher.h"
#include "pathnames.h"
#include "log.h"
#include "readconf.h"
#include "match.h"
#include "misc.h"
#include "kex.h"
#include "mac.h"
/* Format of the configuration file: /* Format of the configuration file:
@ -69,7 +75,7 @@ RCSID("$FreeBSD$");
# Defaults for various options # Defaults for various options
Host * Host *
ForwardAgent no ForwardAgent no
ForwardX11 yes ForwardX11 no
RhostsAuthentication yes RhostsAuthentication yes
PasswordAuthentication yes PasswordAuthentication yes
RSAAuthentication yes RSAAuthentication yes
@ -90,7 +96,7 @@ typedef enum {
oBadOption, oBadOption,
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication, oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
oSkeyAuthentication, oXAuthLocation, oChallengeResponseAuthentication, oXAuthLocation,
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
oKerberosAuthentication, oKerberosAuthentication,
#endif /* KRB4 */ #endif /* KRB4 */
@ -104,10 +110,12 @@ typedef enum {
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication, oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2, oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication, oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms
} OpCodes; } OpCodes;
/* Textual representations of the tokens. */ /* Textual representations of the tokens. */
@ -126,8 +134,13 @@ static struct {
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
{ "kbdinteractivedevices", oKbdInteractiveDevices }, { "kbdinteractivedevices", oKbdInteractiveDevices },
{ "rsaauthentication", oRSAAuthentication }, { "rsaauthentication", oRSAAuthentication },
{ "dsaauthentication", oDSAAuthentication }, { "pubkeyauthentication", oPubkeyAuthentication },
{ "skeyauthentication", oSkeyAuthentication }, { "dsaauthentication", oPubkeyAuthentication }, /* alias */
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "hostbasedauthentication", oHostbasedAuthentication },
{ "challengeresponseauthentication", oChallengeResponseAuthentication },
{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
{ "kerberosauthentication", oKerberosAuthentication }, { "kerberosauthentication", oKerberosAuthentication },
#endif /* KRB4 || KRB5 */ #endif /* KRB4 || KRB5 */
@ -141,19 +154,20 @@ static struct {
{ "fallbacktorsh", oFallBackToRsh }, { "fallbacktorsh", oFallBackToRsh },
{ "usersh", oUseRsh }, { "usersh", oUseRsh },
{ "identityfile", oIdentityFile }, { "identityfile", oIdentityFile },
{ "identityfile2", oIdentityFile2 }, { "identityfile2", oIdentityFile }, /* alias */
{ "hostname", oHostName }, { "hostname", oHostName },
{ "hostkeyalias", oHostKeyAlias },
{ "proxycommand", oProxyCommand }, { "proxycommand", oProxyCommand },
{ "port", oPort }, { "port", oPort },
{ "cipher", oCipher }, { "cipher", oCipher },
{ "ciphers", oCiphers }, { "ciphers", oCiphers },
{ "macs", oMacs },
{ "protocol", oProtocol }, { "protocol", oProtocol },
{ "remoteforward", oRemoteForward }, { "remoteforward", oRemoteForward },
{ "localforward", oLocalForward }, { "localforward", oLocalForward },
{ "user", oUser }, { "user", oUser },
{ "host", oHost }, { "host", oHost },
{ "escapechar", oEscapeChar }, { "escapechar", oEscapeChar },
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
{ "globalknownhostsfile", oGlobalKnownHostsFile }, { "globalknownhostsfile", oGlobalKnownHostsFile },
{ "userknownhostsfile", oUserKnownHostsFile }, { "userknownhostsfile", oUserKnownHostsFile },
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 }, { "globalknownhostsfile2", oGlobalKnownHostsFile2 },
@ -166,8 +180,10 @@ static struct {
{ "compressionlevel", oCompressionLevel }, { "compressionlevel", oCompressionLevel },
{ "keepalive", oKeepAlives }, { "keepalive", oKeepAlives },
{ "numberofpasswordprompts", oNumberOfPasswordPrompts }, { "numberofpasswordprompts", oNumberOfPasswordPrompts },
{ "tisauthentication", oTISAuthentication },
{ "loglevel", oLogLevel }, { "loglevel", oLogLevel },
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
{ NULL, 0 } { NULL, 0 }
}; };
@ -183,7 +199,7 @@ add_local_forward(Options *options, u_short port, const char *host,
Forward *fwd; Forward *fwd;
extern uid_t original_real_uid; extern uid_t original_real_uid;
if (port < IPPORT_RESERVED && original_real_uid != 0) if (port < IPPORT_RESERVED && original_real_uid != 0)
fatal("Privileged ports can only be forwarded by root.\n"); fatal("Privileged ports can only be forwarded by root.");
if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION); fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->local_forwards[options->num_local_forwards++]; fwd = &options->local_forwards[options->num_local_forwards++];
@ -212,21 +228,20 @@ add_remote_forward(Options *options, u_short port, const char *host,
} }
/* /*
* Returns the number of the token pointed to by cp of length len. Never * Returns the number of the token pointed to by cp or oBadOption.
* returns if the token is not known.
*/ */
static OpCodes static OpCodes
parse_token(const char *cp, const char *filename, int linenum) parse_token(const char *cp, const char *filename, int linenum)
{ {
unsigned int i; u_int i;
for (i = 0; keywords[i].name; i++) for (i = 0; keywords[i].name; i++)
if (strcasecmp(cp, keywords[i].name) == 0) if (strcasecmp(cp, keywords[i].name) == 0)
return keywords[i].opcode; return keywords[i].opcode;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp); filename, linenum, cp);
return oBadOption; return oBadOption;
} }
@ -250,7 +265,7 @@ process_config_line(Options *options, const char *host,
/* Ignore leading whitespace. */ /* Ignore leading whitespace. */
if (*keyword == '\0') if (*keyword == '\0')
keyword = strdelim(&s); keyword = strdelim(&s);
if (!*keyword || *keyword == '\n' || *keyword == '#') if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
return 0; return 0;
opcode = parse_token(keyword, filename, linenum); opcode = parse_token(keyword, filename, linenum);
@ -305,8 +320,8 @@ process_config_line(Options *options, const char *host,
charptr = &options->kbd_interactive_devices; charptr = &options->kbd_interactive_devices;
goto parse_string; goto parse_string;
case oDSAAuthentication: case oPubkeyAuthentication:
intptr = &options->dsa_authentication; intptr = &options->pubkey_authentication;
goto parse_flag; goto parse_flag;
case oRSAAuthentication: case oRSAAuthentication:
@ -317,10 +332,8 @@ process_config_line(Options *options, const char *host,
intptr = &options->rhosts_rsa_authentication; intptr = &options->rhosts_rsa_authentication;
goto parse_flag; goto parse_flag;
case oTISAuthentication: case oHostbasedAuthentication:
/* fallthrough, there is no difference on the client side */ intptr = &options->hostbased_authentication;
case oSkeyAuthentication:
intptr = &options->skey_authentication;
goto parse_flag; goto parse_flag;
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
@ -329,6 +342,10 @@ process_config_line(Options *options, const char *host,
goto parse_flag; goto parse_flag;
#endif /* KRB4 || KRB5 */ #endif /* KRB4 || KRB5 */
case oChallengeResponseAuthentication:
intptr = &options->challenge_reponse_authentication;
goto parse_flag;
#ifdef KRB5 #ifdef KRB5
case oKrb5TgtPassing: case oKrb5TgtPassing:
intptr = &options->krb5_tgt_passing; intptr = &options->krb5_tgt_passing;
@ -365,7 +382,7 @@ process_config_line(Options *options, const char *host,
intptr = &options->strict_host_key_checking; intptr = &options->strict_host_key_checking;
arg = strdelim(&s); arg = strdelim(&s);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no argument.", fatal("%.200s line %d: Missing yes/no/ask argument.",
filename, linenum); filename, linenum);
value = 0; /* To avoid compiler warning... */ value = 0; /* To avoid compiler warning... */
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
@ -397,20 +414,15 @@ process_config_line(Options *options, const char *host,
goto parse_int; goto parse_int;
case oIdentityFile: case oIdentityFile:
case oIdentityFile2:
arg = strdelim(&s); arg = strdelim(&s);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (*activep) { if (*activep) {
intptr = (opcode == oIdentityFile) ? intptr = &options->num_identity_files;
&options->num_identity_files :
&options->num_identity_files2;
if (*intptr >= SSH_MAX_IDENTITY_FILES) if (*intptr >= SSH_MAX_IDENTITY_FILES)
fatal("%.200s line %d: Too many identity files specified (max %d).", fatal("%.200s line %d: Too many identity files specified (max %d).",
filename, linenum, SSH_MAX_IDENTITY_FILES); filename, linenum, SSH_MAX_IDENTITY_FILES);
charptr = (opcode == oIdentityFile) ? charptr = &options->identity_files[*intptr];
&options->identity_files[*intptr] :
&options->identity_files2[*intptr];
*charptr = xstrdup(arg); *charptr = xstrdup(arg);
*intptr = *intptr + 1; *intptr = *intptr + 1;
} }
@ -450,6 +462,14 @@ process_config_line(Options *options, const char *host,
charptr = &options->hostname; charptr = &options->hostname;
goto parse_string; goto parse_string;
case oHostKeyAlias:
charptr = &options->host_key_alias;
goto parse_string;
case oPreferredAuthentications:
charptr = &options->preferred_authentications;
goto parse_string;
case oProxyCommand: case oProxyCommand:
charptr = &options->proxy_command; charptr = &options->proxy_command;
string = xstrdup(""); string = xstrdup("");
@ -509,6 +529,28 @@ process_config_line(Options *options, const char *host,
options->ciphers = xstrdup(arg); options->ciphers = xstrdup(arg);
break; break;
case oMacs:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!mac_valid(arg))
fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->macs == NULL)
options->macs = xstrdup(arg);
break;
case oHostKeyAlgorithms:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum);
if (!key_names_valid2(arg))
fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && options->hostkeyalgorithms == NULL)
options->hostkeyalgorithms = xstrdup(arg);
break;
case oProtocol: case oProtocol:
intptr = &options->protocol; intptr = &options->protocol;
arg = strdelim(&s); arg = strdelim(&s);
@ -527,7 +569,7 @@ process_config_line(Options *options, const char *host,
arg = strdelim(&s); arg = strdelim(&s);
value = log_level_number(arg); value = log_level_number(arg);
if (value == (LogLevel) - 1) if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n", fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*activep && (LogLevel) * intptr == -1) if (*activep && (LogLevel) * intptr == -1)
*intptr = (LogLevel) value; *intptr = (LogLevel) value;
@ -537,10 +579,10 @@ process_config_line(Options *options, const char *host,
arg = strdelim(&s); arg = strdelim(&s);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (arg[0] < '0' || arg[0] > '9') fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.", fatal("%.200s line %d: Badly formatted port number.",
filename, linenum); filename, linenum);
fwd_port = atoi(arg);
arg = strdelim(&s); arg = strdelim(&s);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.", fatal("%.200s line %d: Missing second argument.",
@ -556,10 +598,10 @@ process_config_line(Options *options, const char *host,
arg = strdelim(&s); arg = strdelim(&s);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (arg[0] < '0' || arg[0] > '9') fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.", fatal("%.200s line %d: Badly formatted port number.",
filename, linenum); filename, linenum);
fwd_port = atoi(arg);
arg = strdelim(&s); arg = strdelim(&s);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing second argument.", fatal("%.200s line %d: Missing second argument.",
@ -571,6 +613,18 @@ process_config_line(Options *options, const char *host,
add_local_forward(options, fwd_port, buf, fwd_host_port); add_local_forward(options, fwd_port, buf, fwd_host_port);
break; break;
case oDynamicForward:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
fwd_port = a2port(arg);
if (fwd_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
add_local_forward(options, fwd_port, "socks4", 0);
break;
case oHost: case oHost:
*activep = 0; *activep = 0;
while ((arg = strdelim(&s)) != NULL && *arg != '\0') while ((arg = strdelim(&s)) != NULL && *arg != '\0')
@ -588,10 +642,10 @@ process_config_line(Options *options, const char *host,
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing argument.", filename, linenum); fatal("%.200s line %d: Missing argument.", filename, linenum);
if (arg[0] == '^' && arg[2] == 0 && if (arg[0] == '^' && arg[2] == 0 &&
(unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128) (u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
value = (unsigned char) arg[1] & 31; value = (u_char) arg[1] & 31;
else if (strlen(arg) == 1) else if (strlen(arg) == 1)
value = (unsigned char) arg[0]; value = (u_char) arg[0];
else if (strcmp(arg, "none") == 0) else if (strcmp(arg, "none") == 0)
value = -2; value = -2;
else { else {
@ -609,8 +663,7 @@ process_config_line(Options *options, const char *host,
} }
/* Check that there is no garbage at end of line. */ /* Check that there is no garbage at end of line. */
if ((arg = strdelim(&s)) != NULL && *arg != '\0') if ((arg = strdelim(&s)) != NULL && *arg != '\0') {
{
fatal("%.200s line %d: garbage at end of line; \"%.200s\".", fatal("%.200s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg); filename, linenum, arg);
} }
@ -653,7 +706,7 @@ read_config_file(const char *filename, const char *host, Options *options)
} }
fclose(f); fclose(f);
if (bad_options > 0) if (bad_options > 0)
fatal("%s: terminating, %d bad configuration options\n", fatal("%s: terminating, %d bad configuration options",
filename, bad_options); filename, bad_options);
} }
@ -675,8 +728,8 @@ initialize_options(Options * options)
options->use_privileged_port = -1; options->use_privileged_port = -1;
options->rhosts_authentication = -1; options->rhosts_authentication = -1;
options->rsa_authentication = -1; options->rsa_authentication = -1;
options->dsa_authentication = -1; options->pubkey_authentication = -1;
options->skey_authentication = -1; options->challenge_reponse_authentication = -1;
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
options->kerberos_authentication = -1; options->kerberos_authentication = -1;
#endif #endif
@ -691,6 +744,7 @@ initialize_options(Options * options)
options->kbd_interactive_authentication = -1; options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL; options->kbd_interactive_devices = NULL;
options->rhosts_rsa_authentication = -1; options->rhosts_rsa_authentication = -1;
options->hostbased_authentication = -1;
options->fallback_to_rsh = -1; options->fallback_to_rsh = -1;
options->use_rsh = -1; options->use_rsh = -1;
options->batch_mode = -1; options->batch_mode = -1;
@ -704,10 +758,12 @@ initialize_options(Options * options)
options->number_of_password_prompts = -1; options->number_of_password_prompts = -1;
options->cipher = -1; options->cipher = -1;
options->ciphers = NULL; options->ciphers = NULL;
options->macs = NULL;
options->hostkeyalgorithms = NULL;
options->protocol = SSH_PROTO_UNKNOWN; options->protocol = SSH_PROTO_UNKNOWN;
options->num_identity_files = 0; options->num_identity_files = 0;
options->num_identity_files2 = 0;
options->hostname = NULL; options->hostname = NULL;
options->host_key_alias = NULL;
options->proxy_command = NULL; options->proxy_command = NULL;
options->user = NULL; options->user = NULL;
options->escape_char = -1; options->escape_char = -1;
@ -718,6 +774,7 @@ initialize_options(Options * options)
options->num_local_forwards = 0; options->num_local_forwards = 0;
options->num_remote_forwards = 0; options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1; options->log_level = (LogLevel) - 1;
options->preferred_authentications = NULL;
} }
/* /*
@ -728,6 +785,8 @@ initialize_options(Options * options)
void void
fill_default_options(Options * options) fill_default_options(Options * options)
{ {
int len;
if (options->forward_agent == -1) if (options->forward_agent == -1)
options->forward_agent = 0; options->forward_agent = 0;
if (options->forward_x11 == -1) if (options->forward_x11 == -1)
@ -739,15 +798,15 @@ fill_default_options(Options * options)
if (options->gateway_ports == -1) if (options->gateway_ports == -1)
options->gateway_ports = 0; options->gateway_ports = 0;
if (options->use_privileged_port == -1) if (options->use_privileged_port == -1)
options->use_privileged_port = 1; options->use_privileged_port = 0;
if (options->rhosts_authentication == -1) if (options->rhosts_authentication == -1)
options->rhosts_authentication = 1; options->rhosts_authentication = 1;
if (options->rsa_authentication == -1) if (options->rsa_authentication == -1)
options->rsa_authentication = 1; options->rsa_authentication = 1;
if (options->dsa_authentication == -1) if (options->pubkey_authentication == -1)
options->dsa_authentication = 1; options->pubkey_authentication = 1;
if (options->skey_authentication == -1) if (options->challenge_reponse_authentication == -1)
options->skey_authentication = 0; options->challenge_reponse_authentication = 0;
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
if (options->kerberos_authentication == -1) if (options->kerberos_authentication == -1)
options->kerberos_authentication = 1; options->kerberos_authentication = 1;
@ -765,9 +824,11 @@ fill_default_options(Options * options)
if (options->password_authentication == -1) if (options->password_authentication == -1)
options->password_authentication = 1; options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1) if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0; options->kbd_interactive_authentication = 1;
if (options->rhosts_rsa_authentication == -1) if (options->rhosts_rsa_authentication == -1)
options->rhosts_rsa_authentication = 1; options->rhosts_rsa_authentication = 1;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->fallback_to_rsh == -1) if (options->fallback_to_rsh == -1)
options->fallback_to_rsh = 0; options->fallback_to_rsh = 0;
if (options->use_rsh == -1) if (options->use_rsh == -1)
@ -794,33 +855,47 @@ fill_default_options(Options * options)
if (options->cipher == -1) if (options->cipher == -1)
options->cipher = SSH_CIPHER_NOT_SET; options->cipher = SSH_CIPHER_NOT_SET;
/* options->ciphers, default set in myproposals.h */ /* options->ciphers, default set in myproposals.h */
/* options->macs, default set in myproposals.h */
/* options->hostkeyalgorithms, default set in myproposals.h */
if (options->protocol == SSH_PROTO_UNKNOWN) if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2|SSH_PROTO_1_PREFERRED; options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->num_identity_files == 0) { if (options->num_identity_files == 0) {
options->identity_files[0] = if (options->protocol & SSH_PROTO_1) {
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); options->identity_files[options->num_identity_files] =
options->num_identity_files = 1; xmalloc(len);
} snprintf(options->identity_files[options->num_identity_files++],
if (options->num_identity_files2 == 0) { len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
options->identity_files2[0] = }
xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1); if (options->protocol & SSH_PROTO_2) {
sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA); len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
options->num_identity_files2 = 1; options->identity_files[options->num_identity_files] =
xmalloc(len);
snprintf(options->identity_files[options->num_identity_files++],
len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
options->identity_files[options->num_identity_files] =
xmalloc(len);
snprintf(options->identity_files[options->num_identity_files++],
len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
}
} }
if (options->escape_char == -1) if (options->escape_char == -1)
options->escape_char = '~'; options->escape_char = '~';
if (options->system_hostfile == NULL) if (options->system_hostfile == NULL)
options->system_hostfile = SSH_SYSTEM_HOSTFILE; options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
if (options->user_hostfile == NULL) if (options->user_hostfile == NULL)
options->user_hostfile = SSH_USER_HOSTFILE; options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
if (options->system_hostfile2 == NULL) if (options->system_hostfile2 == NULL)
options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2; options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
if (options->user_hostfile2 == NULL) if (options->user_hostfile2 == NULL)
options->user_hostfile2 = SSH_USER_HOSTFILE2; options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
if (options->log_level == (LogLevel) - 1) if (options->log_level == (LogLevel) - 1)
options->log_level = SYSLOG_LEVEL_INFO; options->log_level = SYSLOG_LEVEL_INFO;
/* options->proxy_command should not be set by default */ /* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */ /* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */ /* options->hostname will be set in the main program if appropriate */
/* options->host_key_alias should not be set by default */
/* options->preferred_authentications will be set in ssh */
} }

View File

@ -11,12 +11,14 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
*/ */
/* RCSID("$OpenBSD: readconf.h,v 1.22 2000/10/11 20:14:39 markus Exp $"); */ /* RCSID("$OpenBSD: readconf.h,v 1.30 2001/04/17 10:53:25 markus Exp $"); */
/* $FreeBSD$ */ /* RCSID("$FreeBSD$"); */
#ifndef READCONF_H #ifndef READCONF_H
#define READCONF_H #define READCONF_H
#include "key.h"
/* Data structure for representing a forwarding request. */ /* Data structure for representing a forwarding request. */
typedef struct { typedef struct {
@ -36,10 +38,13 @@ typedef struct {
int rhosts_rsa_authentication; /* Try rhosts with RSA int rhosts_rsa_authentication; /* Try rhosts with RSA
* authentication. */ * authentication. */
int rsa_authentication; /* Try RSA authentication. */ int rsa_authentication; /* Try RSA authentication. */
int dsa_authentication; /* Try DSA authentication. */ int pubkey_authentication; /* Try ssh2 pubkey authentication. */
int skey_authentication; /* Try S/Key or TIS authentication. */ int hostbased_authentication; /* ssh2's rhosts_rsa */
int challenge_reponse_authentication;
/* Try S/Key or TIS, authentication. */
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* Try Kerberos authentication. */ int kerberos_authentication; /* Try Kerberos
* authentication. */
#endif #endif
#ifdef KRB5 #ifdef KRB5
@ -72,8 +77,11 @@ typedef struct {
* prompts. */ * prompts. */
int cipher; /* Cipher to use. */ int cipher; /* Cipher to use. */
char *ciphers; /* SSH2 ciphers in order of preference. */ char *ciphers; /* SSH2 ciphers in order of preference. */
char *macs; /* SSH2 macs in order of preference. */
char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */
int protocol; /* Protocol in order of preference. */ int protocol; /* Protocol in order of preference. */
char *hostname; /* Real host to connect. */ char *hostname; /* Real host to connect. */
char *host_key_alias; /* hostname alias for .ssh/known_hosts */
char *proxy_command; /* Proxy command for connecting the host. */ char *proxy_command; /* Proxy command for connecting the host. */
char *user; /* User to log in as. */ char *user; /* User to log in as. */
int escape_char; /* Escape character; -2 = none */ int escape_char; /* Escape character; -2 = none */
@ -82,11 +90,11 @@ typedef struct {
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */ char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
char *system_hostfile2; char *system_hostfile2;
char *user_hostfile2; char *user_hostfile2;
char *preferred_authentications;
int num_identity_files; /* Number of files for RSA identities. */ int num_identity_files; /* Number of files for RSA/DSA identities. */
int num_identity_files2; /* DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES]; char *identity_files[SSH_MAX_IDENTITY_FILES];
char *identity_files2[SSH_MAX_IDENTITY_FILES]; Key *identity_keys[SSH_MAX_IDENTITY_FILES];
/* Local TCP/IP forward requests. */ /* Local TCP/IP forward requests. */
int num_local_forwards; int num_local_forwards;

View File

@ -8,7 +8,7 @@
* software must be clearly marked as such, and if the derived work is * software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be * incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
* *
* *
* Copyright (c) 1999 Niels Provos. All rights reserved. * Copyright (c) 1999 Niels Provos. All rights reserved.
* *
@ -60,83 +60,17 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: rsa.c,v 1.16 2000/09/07 20:27:53 deraadt Exp $"); RCSID("$OpenBSD: rsa.c,v 1.22 2001/03/26 23:23:23 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include "rsa.h" #include "rsa.h"
#include "ssh.h" #include "log.h"
#include "xmalloc.h" #include "xmalloc.h"
int rsa_verbose = 1;
int
rsa_alive()
{
RSA *key;
key = RSA_generate_key(32, 3, NULL, NULL);
if (key == NULL)
return (0);
RSA_free(key);
return (1);
}
/*
* Generates RSA public and private keys. This initializes the data
* structures; they should be freed with rsa_clear_private_key and
* rsa_clear_public_key.
*/
void
rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits)
{
RSA *key;
if (rsa_verbose) {
printf("Generating RSA keys: ");
fflush(stdout);
}
key = RSA_generate_key(bits, 35, NULL, NULL);
if (key == NULL)
fatal("rsa_generate_key: key generation failed.");
/* Copy public key parameters */
pub->n = BN_new();
BN_copy(pub->n, key->n);
pub->e = BN_new();
BN_copy(pub->e, key->e);
/* Copy private key parameters */
prv->n = BN_new();
BN_copy(prv->n, key->n);
prv->e = BN_new();
BN_copy(prv->e, key->e);
prv->d = BN_new();
BN_copy(prv->d, key->d);
prv->p = BN_new();
BN_copy(prv->p, key->p);
prv->q = BN_new();
BN_copy(prv->q, key->q);
prv->dmp1 = BN_new();
BN_copy(prv->dmp1, key->dmp1);
prv->dmq1 = BN_new();
BN_copy(prv->dmq1, key->dmq1);
prv->iqmp = BN_new();
BN_copy(prv->iqmp, key->iqmp);
RSA_free(key);
if (rsa_verbose)
printf("Key generation complete.\n");
}
void void
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{ {
unsigned char *inbuf, *outbuf; u_char *inbuf, *outbuf;
int len, ilen, olen; int len, ilen, olen;
if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
@ -151,7 +85,7 @@ rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key,
RSA_PKCS1_PADDING)) <= 0) RSA_PKCS1_PADDING)) <= 0)
fatal("rsa_public_encrypt() failed."); fatal("rsa_public_encrypt() failed");
BN_bin2bn(outbuf, len, out); BN_bin2bn(outbuf, len, out);
@ -164,7 +98,7 @@ rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
int int
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
{ {
unsigned char *inbuf, *outbuf; u_char *inbuf, *outbuf;
int len, ilen, olen; int len, ilen, olen;
olen = BN_num_bytes(key->n); olen = BN_num_bytes(key->n);
@ -187,10 +121,22 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
return len; return len;
} }
/* Set whether to output verbose messages during key generation. */
void void
rsa_set_verbose(int verbose) generate_additional_parameters(RSA *rsa)
{ {
rsa_verbose = verbose; BIGNUM *aux;
BN_CTX *ctx;
/* Generate additional parameters */
aux = BN_new();
ctx = BN_CTX_new();
BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);
BN_sub(aux, rsa->p, BN_value_one());
BN_mod(rsa->dmp1, rsa->d, aux, ctx);
BN_clear_free(aux);
BN_CTX_free(ctx);
} }

View File

@ -11,8 +11,8 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
*/ */
/* RCSID("$OpenBSD: rsa.h,v 1.8 2000/09/07 20:27:53 deraadt Exp $"); */ /* RCSID("$OpenBSD: rsa.h,v 1.11 2001/03/26 23:23:24 markus Exp $"); */
/* $FreeBSD$ */ /* RCSID("$FreeBSD$"); */
#ifndef RSA_H #ifndef RSA_H
#define RSA_H #define RSA_H
@ -20,18 +20,9 @@
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
/* Calls SSL RSA_generate_key, only copies to prv and pub */
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
/*
* Indicates whether the rsa module is permitted to show messages on the
* terminal.
*/
void rsa_set_verbose __P((int verbose));
int rsa_alive __P((void));
void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
void generate_additional_parameters __P((RSA *rsa));
#endif /* RSA_H */ #endif /* RSA_H */

View File

@ -10,16 +10,33 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: servconf.c,v 1.53 2000/10/14 12:12:09 markus Exp $"); RCSID("$OpenBSD: servconf.c,v 1.78 2001/04/15 21:28:35 stevesk Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#ifdef KRB4
#include <krb.h>
#endif
#ifdef AFS
#include <kafs.h>
#endif
#include "ssh.h" #include "ssh.h"
#include "log.h"
#include "servconf.h" #include "servconf.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "compat.h" #include "compat.h"
#include "pathnames.h"
#include "tildexpand.h"
#include "misc.h"
#include "cipher.h"
#include "kex.h"
#include "mac.h"
/* add listen address */ void add_listen_addr(ServerOptions *options, char *addr, u_short port);
void add_listen_addr(ServerOptions *options, char *addr); void add_one_listen_addr(ServerOptions *options, char *addr, u_short port);
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
/* Initializes the server options to their default values. */ /* Initializes the server options to their default values. */
@ -30,16 +47,16 @@ initialize_server_options(ServerOptions *options)
options->num_ports = 0; options->num_ports = 0;
options->ports_from_cmdline = 0; options->ports_from_cmdline = 0;
options->listen_addrs = NULL; options->listen_addrs = NULL;
options->host_key_file = NULL; options->num_host_key_files = 0;
options->host_dsa_key_file = NULL;
options->pid_file = NULL; options->pid_file = NULL;
options->server_key_bits = -1; options->server_key_bits = -1;
options->login_grace_time = -1; options->login_grace_time = -1;
options->key_regeneration_time = -1; options->key_regeneration_time = -1;
options->permit_root_login = -1; options->permit_root_login = PERMIT_NOT_SET;
options->ignore_rhosts = -1; options->ignore_rhosts = -1;
options->ignore_user_known_hosts = -1; options->ignore_user_known_hosts = -1;
options->print_motd = -1; options->print_motd = -1;
options->print_lastlog = -1;
options->check_mail = -1; options->check_mail = -1;
options->x11_forwarding = -1; options->x11_forwarding = -1;
options->x11_display_offset = -1; options->x11_display_offset = -1;
@ -50,8 +67,10 @@ initialize_server_options(ServerOptions *options)
options->log_level = (LogLevel) - 1; options->log_level = (LogLevel) - 1;
options->rhosts_authentication = -1; options->rhosts_authentication = -1;
options->rhosts_rsa_authentication = -1; options->rhosts_rsa_authentication = -1;
options->hostbased_authentication = -1;
options->hostbased_uses_name_from_packet_only = -1;
options->rsa_authentication = -1; options->rsa_authentication = -1;
options->dsa_authentication = -1; options->pubkey_authentication = -1;
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
options->kerberos_authentication = -1; options->kerberos_authentication = -1;
#endif #endif
@ -68,9 +87,7 @@ initialize_server_options(ServerOptions *options)
#endif #endif
options->password_authentication = -1; options->password_authentication = -1;
options->kbd_interactive_authentication = -1; options->kbd_interactive_authentication = -1;
#ifdef SKEY options->challenge_reponse_authentication = -1;
options->skey_authentication = -1;
#endif
options->permit_empty_passwd = -1; options->permit_empty_passwd = -1;
options->use_login = -1; options->use_login = -1;
options->allow_tcp_forwarding = -1; options->allow_tcp_forwarding = -1;
@ -79,6 +96,7 @@ initialize_server_options(ServerOptions *options)
options->num_allow_groups = 0; options->num_allow_groups = 0;
options->num_deny_groups = 0; options->num_deny_groups = 0;
options->ciphers = NULL; options->ciphers = NULL;
options->macs = NULL;
options->protocol = SSH_PROTO_UNKNOWN; options->protocol = SSH_PROTO_UNKNOWN;
options->gateway_ports = -1; options->gateway_ports = -1;
options->connections_per_period = 0; options->connections_per_period = 0;
@ -87,29 +105,38 @@ initialize_server_options(ServerOptions *options)
options->max_startups_begin = -1; options->max_startups_begin = -1;
options->max_startups_rate = -1; options->max_startups_rate = -1;
options->max_startups = -1; options->max_startups = -1;
options->banner = NULL;
options->reverse_mapping_check = -1;
options->client_alive_interval = -1;
options->client_alive_count_max = -1;
} }
void void
fill_default_server_options(ServerOptions *options) fill_default_server_options(ServerOptions *options)
{ {
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->num_host_key_files == 0) {
/* fill default hostkeys for protocols */
if (options->protocol & SSH_PROTO_1)
options->host_key_files[options->num_host_key_files++] = _PATH_HOST_KEY_FILE;
if (options->protocol & SSH_PROTO_2)
options->host_key_files[options->num_host_key_files++] = _PATH_HOST_DSA_KEY_FILE;
}
if (options->num_ports == 0) if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT; options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
if (options->listen_addrs == NULL) if (options->listen_addrs == NULL)
add_listen_addr(options, NULL); add_listen_addr(options, NULL, 0);
if (options->host_key_file == NULL)
options->host_key_file = HOST_KEY_FILE;
if (options->host_dsa_key_file == NULL)
options->host_dsa_key_file = HOST_DSA_KEY_FILE;
if (options->pid_file == NULL) if (options->pid_file == NULL)
options->pid_file = SSH_DAEMON_PID_FILE; options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
if (options->server_key_bits == -1) if (options->server_key_bits == -1)
options->server_key_bits = 768; options->server_key_bits = 768;
if (options->login_grace_time == -1) if (options->login_grace_time == -1)
options->login_grace_time = 120; options->login_grace_time = 120;
if (options->key_regeneration_time == -1) if (options->key_regeneration_time == -1)
options->key_regeneration_time = 3600; options->key_regeneration_time = 3600;
if (options->permit_root_login == -1) if (options->permit_root_login == PERMIT_NOT_SET)
options->permit_root_login = 0; /* no */ options->permit_root_login = PERMIT_NO;
if (options->ignore_rhosts == -1) if (options->ignore_rhosts == -1)
options->ignore_rhosts = 1; options->ignore_rhosts = 1;
if (options->ignore_user_known_hosts == -1) if (options->ignore_user_known_hosts == -1)
@ -118,6 +145,8 @@ fill_default_server_options(ServerOptions *options)
options->check_mail = 1; options->check_mail = 1;
if (options->print_motd == -1) if (options->print_motd == -1)
options->print_motd = 1; options->print_motd = 1;
if (options->print_lastlog == -1)
options->print_lastlog = 1;
if (options->x11_forwarding == -1) if (options->x11_forwarding == -1)
options->x11_forwarding = 1; options->x11_forwarding = 1;
if (options->x11_display_offset == -1) if (options->x11_display_offset == -1)
@ -138,10 +167,14 @@ fill_default_server_options(ServerOptions *options)
options->rhosts_authentication = 0; options->rhosts_authentication = 0;
if (options->rhosts_rsa_authentication == -1) if (options->rhosts_rsa_authentication == -1)
options->rhosts_rsa_authentication = 0; options->rhosts_rsa_authentication = 0;
if (options->hostbased_authentication == -1)
options->hostbased_authentication = 0;
if (options->hostbased_uses_name_from_packet_only == -1)
options->hostbased_uses_name_from_packet_only = 0;
if (options->rsa_authentication == -1) if (options->rsa_authentication == -1)
options->rsa_authentication = 1; options->rsa_authentication = 1;
if (options->dsa_authentication == -1) if (options->pubkey_authentication == -1)
options->dsa_authentication = 1; options->pubkey_authentication = 1;
#if defined(KRB4) && defined(KRB5) #if defined(KRB4) && defined(KRB5)
if (options->kerberos_authentication == -1) if (options->kerberos_authentication == -1)
options->kerberos_authentication = options->kerberos_authentication =
@ -173,18 +206,14 @@ fill_default_server_options(ServerOptions *options)
options->password_authentication = 1; options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1) if (options->kbd_interactive_authentication == -1)
options->kbd_interactive_authentication = 0; options->kbd_interactive_authentication = 0;
#ifdef SKEY if (options->challenge_reponse_authentication == -1)
if (options->skey_authentication == -1) options->challenge_reponse_authentication = 1;
options->skey_authentication = 1;
#endif
if (options->permit_empty_passwd == -1) if (options->permit_empty_passwd == -1)
options->permit_empty_passwd = 0; options->permit_empty_passwd = 0;
if (options->use_login == -1) if (options->use_login == -1)
options->use_login = 0; options->use_login = 0;
if (options->allow_tcp_forwarding == -1) if (options->allow_tcp_forwarding == -1)
options->allow_tcp_forwarding = 1; options->allow_tcp_forwarding = 1;
if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2;
if (options->gateway_ports == -1) if (options->gateway_ports == -1)
options->gateway_ports = 0; options->gateway_ports = 0;
if (options->max_startups == -1) if (options->max_startups == -1)
@ -193,6 +222,12 @@ fill_default_server_options(ServerOptions *options)
options->max_startups_rate = 100; /* 100% */ options->max_startups_rate = 100; /* 100% */
if (options->max_startups_begin == -1) if (options->max_startups_begin == -1)
options->max_startups_begin = options->max_startups; options->max_startups_begin = options->max_startups;
if (options->reverse_mapping_check == -1)
options->reverse_mapping_check = 0;
if (options->client_alive_interval == -1)
options->client_alive_interval = 0;
if (options->client_alive_count_max == -1)
options->client_alive_count_max = 3;
} }
/* Keyword tokens. */ /* Keyword tokens. */
@ -213,17 +248,18 @@ typedef enum {
#ifdef AFS #ifdef AFS
sKrb4TgtPassing, sAFSTokenPassing, sKrb4TgtPassing, sAFSTokenPassing,
#endif #endif
#ifdef SKEY sChallengeResponseAuthentication,
sSkeyAuthentication,
#endif
sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail, sX11Forwarding, sX11DisplayOffset,
sStrictModes, sEmptyPasswd, sKeepAlives, sCheckMail,
sUseLogin, sAllowTcpForwarding, sUseLogin, sAllowTcpForwarding,
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile, sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
sGatewayPorts, sDSAAuthentication, sConnectionsPerPeriod, sXAuthLocation, sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
sSubsystem, sMaxStartups, sVersionAddendum sBanner, sReverseMappingCheck, sHostbasedAuthentication,
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
sClientAliveCountMax, sVersionAddendum, sConnectionsPerPeriod
} ServerOpCodes; } ServerOpCodes;
/* Textual representation of the tokens. */ /* Textual representation of the tokens. */
@ -233,8 +269,8 @@ static struct {
} keywords[] = { } keywords[] = {
{ "port", sPort }, { "port", sPort },
{ "hostkey", sHostKeyFile }, { "hostkey", sHostKeyFile },
{ "hostdsakey", sHostDSAKeyFile }, { "hostdsakey", sHostKeyFile }, /* alias */
{ "pidfile", sPidFile }, { "pidfile", sPidFile },
{ "serverkeybits", sServerKeyBits }, { "serverkeybits", sServerKeyBits },
{ "logingracetime", sLoginGraceTime }, { "logingracetime", sLoginGraceTime },
{ "keyregenerationinterval", sKeyRegenerationTime }, { "keyregenerationinterval", sKeyRegenerationTime },
@ -243,8 +279,11 @@ static struct {
{ "loglevel", sLogLevel }, { "loglevel", sLogLevel },
{ "rhostsauthentication", sRhostsAuthentication }, { "rhostsauthentication", sRhostsAuthentication },
{ "rhostsrsaauthentication", sRhostsRSAAuthentication }, { "rhostsrsaauthentication", sRhostsRSAAuthentication },
{ "hostbasedauthentication", sHostbasedAuthentication },
{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
{ "pubkeyauthentication", sPubkeyAuthentication },
{ "dsaauthentication", sPubkeyAuthentication }, /* alias */
{ "rsaauthentication", sRSAAuthentication }, { "rsaauthentication", sRSAAuthentication },
{ "dsaauthentication", sDSAAuthentication },
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
{ "kerberosauthentication", sKerberosAuthentication }, { "kerberosauthentication", sKerberosAuthentication },
#endif #endif
@ -261,12 +300,12 @@ static struct {
#endif #endif
{ "passwordauthentication", sPasswordAuthentication }, { "passwordauthentication", sPasswordAuthentication },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
#ifdef SKEY { "challengeresponseauthentication", sChallengeResponseAuthentication },
{ "skeyauthentication", sSkeyAuthentication }, { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
#endif
{ "checkmail", sCheckMail }, { "checkmail", sCheckMail },
{ "listenaddress", sListenAddress }, { "listenaddress", sListenAddress },
{ "printmotd", sPrintMotd }, { "printmotd", sPrintMotd },
{ "printlastlog", sPrintLastLog },
{ "ignorerhosts", sIgnoreRhosts }, { "ignorerhosts", sIgnoreRhosts },
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts }, { "ignoreuserknownhosts", sIgnoreUserKnownHosts },
{ "x11forwarding", sX11Forwarding }, { "x11forwarding", sX11Forwarding },
@ -275,7 +314,6 @@ static struct {
{ "strictmodes", sStrictModes }, { "strictmodes", sStrictModes },
{ "permitemptypasswords", sEmptyPasswd }, { "permitemptypasswords", sEmptyPasswd },
{ "uselogin", sUseLogin }, { "uselogin", sUseLogin },
{ "randomseed", sRandomSeedFile },
{ "keepalive", sKeepAlives }, { "keepalive", sKeepAlives },
{ "allowtcpforwarding", sAllowTcpForwarding }, { "allowtcpforwarding", sAllowTcpForwarding },
{ "allowusers", sAllowUsers }, { "allowusers", sAllowUsers },
@ -283,64 +321,73 @@ static struct {
{ "allowgroups", sAllowGroups }, { "allowgroups", sAllowGroups },
{ "denygroups", sDenyGroups }, { "denygroups", sDenyGroups },
{ "ciphers", sCiphers }, { "ciphers", sCiphers },
{ "macs", sMacs },
{ "protocol", sProtocol }, { "protocol", sProtocol },
{ "gatewayports", sGatewayPorts }, { "gatewayports", sGatewayPorts },
{ "connectionsperperiod", sConnectionsPerPeriod }, { "connectionsperperiod", sConnectionsPerPeriod },
{ "subsystem", sSubsystem }, { "subsystem", sSubsystem },
{ "maxstartups", sMaxStartups }, { "maxstartups", sMaxStartups },
{ "versionaddendum", sVersionAddendum }, { "versionaddendum", sVersionAddendum },
{ "banner", sBanner },
{ "reversemappingcheck", sReverseMappingCheck },
{ "clientaliveinterval", sClientAliveInterval },
{ "clientalivecountmax", sClientAliveCountMax },
{ NULL, 0 } { NULL, 0 }
}; };
/* /*
* Returns the number of the token pointed to by cp of length len. Never * Returns the number of the token pointed to by cp or sBadOption.
* returns if the token is not known.
*/ */
static ServerOpCodes static ServerOpCodes
parse_token(const char *cp, const char *filename, parse_token(const char *cp, const char *filename,
int linenum) int linenum)
{ {
unsigned int i; u_int i;
for (i = 0; keywords[i].name; i++) for (i = 0; keywords[i].name; i++)
if (strcasecmp(cp, keywords[i].name) == 0) if (strcasecmp(cp, keywords[i].name) == 0)
return keywords[i].opcode; return keywords[i].opcode;
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n", error("%s: line %d: Bad configuration option: %s",
filename, linenum, cp); filename, linenum, cp);
return sBadOption; return sBadOption;
} }
/*
* add listen address
*/
void void
add_listen_addr(ServerOptions *options, char *addr) add_listen_addr(ServerOptions *options, char *addr, u_short port)
{ {
extern int IPv4or6;
struct addrinfo hints, *ai, *aitop;
char strport[NI_MAXSERV];
int gaierr;
int i; int i;
if (options->num_ports == 0) if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT; options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
for (i = 0; i < options->num_ports; i++) { if (port == 0)
memset(&hints, 0, sizeof(hints)); for (i = 0; i < options->num_ports; i++)
hints.ai_family = IPv4or6; add_one_listen_addr(options, addr, options->ports[i]);
hints.ai_socktype = SOCK_STREAM; else
hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0; add_one_listen_addr(options, addr, port);
snprintf(strport, sizeof strport, "%d", options->ports[i]); }
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
fatal("bad addr or host: %s (%s)\n", void
addr ? addr : "<NULL>", add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
gai_strerror(gaierr)); {
for (ai = aitop; ai->ai_next; ai = ai->ai_next) struct addrinfo hints, *ai, *aitop;
; char strport[NI_MAXSERV];
ai->ai_next = options->listen_addrs; int gaierr;
options->listen_addrs = aitop;
} memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
snprintf(strport, sizeof strport, "%d", port);
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
fatal("bad addr or host: %s (%s)",
addr ? addr : "<NULL>",
gai_strerror(gaierr));
for (ai = aitop; ai->ai_next; ai = ai->ai_next)
;
ai->ai_next = options->listen_addrs;
options->listen_addrs = aitop;
} }
/* Reads the server configuration file. */ /* Reads the server configuration file. */
@ -350,7 +397,7 @@ read_server_config(ServerOptions *options, const char *filename)
{ {
FILE *f; FILE *f;
char line[1024]; char line[1024];
char *cp, **charptr, *arg; char *cp, **charptr, *arg, *p;
int linenum, *intptr, value; int linenum, *intptr, value;
int bad_options = 0; int bad_options = 0;
ServerOpCodes opcode; ServerOpCodes opcode;
@ -369,8 +416,10 @@ read_server_config(ServerOptions *options, const char *filename)
/* Ignore leading whitespace */ /* Ignore leading whitespace */
if (*arg == '\0') if (*arg == '\0')
arg = strdelim(&cp); arg = strdelim(&cp);
if (!*arg || *arg == '#') if (!arg || !*arg || *arg == '#')
continue; continue;
intptr = NULL;
charptr = NULL;
opcode = parse_token(arg, filename, linenum); opcode = parse_token(arg, filename, linenum);
switch (opcode) { switch (opcode) {
case sBadOption: case sBadOption:
@ -384,24 +433,25 @@ read_server_config(ServerOptions *options, const char *filename)
fatal("%s line %d: ports must be specified before " fatal("%s line %d: ports must be specified before "
"ListenAdress.\n", filename, linenum); "ListenAdress.\n", filename, linenum);
if (options->num_ports >= MAX_PORTS) if (options->num_ports >= MAX_PORTS)
fatal("%s line %d: too many ports.\n", fatal("%s line %d: too many ports.",
filename, linenum); filename, linenum);
arg = strdelim(&cp); arg = strdelim(&cp);
if (!arg || *arg == '\0') if (!arg || *arg == '\0')
fatal("%s line %d: missing port number.\n", fatal("%s line %d: missing port number.",
filename, linenum);
options->ports[options->num_ports++] = a2port(arg);
if (options->ports[options->num_ports-1] == 0)
fatal("%s line %d: Badly formatted port number.",
filename, linenum); filename, linenum);
options->ports[options->num_ports++] = atoi(arg);
break; break;
case sServerKeyBits: case sServerKeyBits:
intptr = &options->server_key_bits; intptr = &options->server_key_bits;
parse_int: parse_int:
arg = strdelim(&cp); arg = strdelim(&cp);
if (!arg || *arg == '\0') { if (!arg || *arg == '\0')
fprintf(stderr, "%s line %d: missing integer value.\n", fatal("%s line %d: missing integer value.",
filename, linenum); filename, linenum);
exit(1);
}
value = atoi(arg); value = atoi(arg);
if (value == 0) { if (value == 0) {
fprintf(stderr, "%s line %d: invalid integer value.\n", fprintf(stderr, "%s line %d: invalid integer value.\n",
@ -422,56 +472,84 @@ read_server_config(ServerOptions *options, const char *filename)
case sListenAddress: case sListenAddress:
arg = strdelim(&cp); arg = strdelim(&cp);
if (!arg || *arg == '\0') if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
fatal("%s line %d: missing inet addr.\n", fatal("%s line %d: missing inet addr.",
filename, linenum);
if (*arg == '[') {
if ((p = strchr(arg, ']')) == NULL)
fatal("%s line %d: bad ipv6 inet addr usage.",
filename, linenum);
arg++;
memmove(p, p+1, strlen(p+1)+1);
} else if (((p = strchr(arg, ':')) == NULL) ||
(strchr(p+1, ':') != NULL)) {
add_listen_addr(options, arg, 0);
break;
}
if (*p == ':') {
u_short port;
p++;
if (*p == '\0')
fatal("%s line %d: bad inet addr:port usage.",
filename, linenum);
else {
*(p-1) = '\0';
if ((port = a2port(p)) == 0)
fatal("%s line %d: bad port number.",
filename, linenum);
add_listen_addr(options, arg, port);
}
} else if (*p == '\0')
add_listen_addr(options, arg, 0);
else
fatal("%s line %d: bad inet addr usage.",
filename, linenum); filename, linenum);
add_listen_addr(options, arg);
break; break;
case sHostKeyFile: case sHostKeyFile:
case sHostDSAKeyFile: intptr = &options->num_host_key_files;
charptr = (opcode == sHostKeyFile ) ? if (*intptr >= MAX_HOSTKEYS)
&options->host_key_file : &options->host_dsa_key_file; fatal("%s line %d: too many host keys specified (max %d).",
filename, linenum, MAX_HOSTKEYS);
charptr = &options->host_key_files[*intptr];
parse_filename: parse_filename:
arg = strdelim(&cp); arg = strdelim(&cp);
if (!arg || *arg == '\0') { if (!arg || *arg == '\0')
fprintf(stderr, "%s line %d: missing file name.\n", fatal("%s line %d: missing file name.",
filename, linenum); filename, linenum);
exit(1); if (*charptr == NULL) {
}
if (*charptr == NULL)
*charptr = tilde_expand_filename(arg, getuid()); *charptr = tilde_expand_filename(arg, getuid());
/* increase optional counter */
if (intptr != NULL)
*intptr = *intptr + 1;
}
break; break;
case sPidFile: case sPidFile:
charptr = &options->pid_file; charptr = &options->pid_file;
goto parse_filename; goto parse_filename;
case sRandomSeedFile:
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
filename, linenum);
arg = strdelim(&cp);
break;
case sPermitRootLogin: case sPermitRootLogin:
intptr = &options->permit_root_login; intptr = &options->permit_root_login;
arg = strdelim(&cp); arg = strdelim(&cp);
if (!arg || *arg == '\0') { if (!arg || *arg == '\0')
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n", fatal("%s line %d: missing yes/"
filename, linenum); "without-password/forced-commands-only/no "
exit(1); "argument.", filename, linenum);
} value = 0; /* silence compiler */
if (strcmp(arg, "without-password") == 0) if (strcmp(arg, "without-password") == 0)
value = 2; value = PERMIT_NO_PASSWD;
else if (strcmp(arg, "forced-commands-only") == 0)
value = PERMIT_FORCED_ONLY;
else if (strcmp(arg, "yes") == 0) else if (strcmp(arg, "yes") == 0)
value = 1; value = PERMIT_YES;
else if (strcmp(arg, "no") == 0) else if (strcmp(arg, "no") == 0)
value = 0; value = PERMIT_NO;
else { else
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n", fatal("%s line %d: Bad yes/"
filename, linenum, arg); "without-password/forced-commands-only/no "
exit(1); "argument: %s", filename, linenum, arg);
}
if (*intptr == -1) if (*intptr == -1)
*intptr = value; *intptr = value;
break; break;
@ -480,20 +558,17 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->ignore_rhosts; intptr = &options->ignore_rhosts;
parse_flag: parse_flag:
arg = strdelim(&cp); arg = strdelim(&cp);
if (!arg || *arg == '\0') { if (!arg || *arg == '\0')
fprintf(stderr, "%s line %d: missing yes/no argument.\n", fatal("%s line %d: missing yes/no argument.",
filename, linenum); filename, linenum);
exit(1); value = 0; /* silence compiler */
}
if (strcmp(arg, "yes") == 0) if (strcmp(arg, "yes") == 0)
value = 1; value = 1;
else if (strcmp(arg, "no") == 0) else if (strcmp(arg, "no") == 0)
value = 0; value = 0;
else { else
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n", fatal("%s line %d: Bad yes/no argument: %s",
filename, linenum, arg); filename, linenum, arg);
exit(1);
}
if (*intptr == -1) if (*intptr == -1)
*intptr = value; *intptr = value;
break; break;
@ -510,12 +585,20 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->rhosts_rsa_authentication; intptr = &options->rhosts_rsa_authentication;
goto parse_flag; goto parse_flag;
case sHostbasedAuthentication:
intptr = &options->hostbased_authentication;
goto parse_flag;
case sHostbasedUsesNameFromPacketOnly:
intptr = &options->hostbased_uses_name_from_packet_only;
goto parse_flag;
case sRSAAuthentication: case sRSAAuthentication:
intptr = &options->rsa_authentication; intptr = &options->rsa_authentication;
goto parse_flag; goto parse_flag;
case sDSAAuthentication: case sPubkeyAuthentication:
intptr = &options->dsa_authentication; intptr = &options->pubkey_authentication;
goto parse_flag; goto parse_flag;
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
@ -562,16 +645,18 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->check_mail; intptr = &options->check_mail;
goto parse_flag; goto parse_flag;
#ifdef SKEY case sChallengeResponseAuthentication:
case sSkeyAuthentication: intptr = &options->challenge_reponse_authentication;
intptr = &options->skey_authentication;
goto parse_flag; goto parse_flag;
#endif
case sPrintMotd: case sPrintMotd:
intptr = &options->print_motd; intptr = &options->print_motd;
goto parse_flag; goto parse_flag;
case sPrintLastLog:
intptr = &options->print_lastlog;
goto parse_flag;
case sX11Forwarding: case sX11Forwarding:
intptr = &options->x11_forwarding; intptr = &options->x11_forwarding;
goto parse_flag; goto parse_flag;
@ -583,7 +668,7 @@ read_server_config(ServerOptions *options, const char *filename)
case sXAuthLocation: case sXAuthLocation:
charptr = &options->xauth_location; charptr = &options->xauth_location;
goto parse_filename; goto parse_filename;
case sStrictModes: case sStrictModes:
intptr = &options->strict_modes; intptr = &options->strict_modes;
goto parse_flag; goto parse_flag;
@ -604,12 +689,16 @@ read_server_config(ServerOptions *options, const char *filename)
intptr = &options->gateway_ports; intptr = &options->gateway_ports;
goto parse_flag; goto parse_flag;
case sReverseMappingCheck:
intptr = &options->reverse_mapping_check;
goto parse_flag;
case sLogFacility: case sLogFacility:
intptr = (int *) &options->log_facility; intptr = (int *) &options->log_facility;
arg = strdelim(&cp); arg = strdelim(&cp);
value = log_facility_number(arg); value = log_facility_number(arg);
if (value == (SyslogFacility) - 1) if (value == (SyslogFacility) - 1)
fatal("%.200s line %d: unsupported log facility '%s'\n", fatal("%.200s line %d: unsupported log facility '%s'",
filename, linenum, arg ? arg : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*intptr == -1) if (*intptr == -1)
*intptr = (SyslogFacility) value; *intptr = (SyslogFacility) value;
@ -620,7 +709,7 @@ read_server_config(ServerOptions *options, const char *filename)
arg = strdelim(&cp); arg = strdelim(&cp);
value = log_level_number(arg); value = log_level_number(arg);
if (value == (LogLevel) - 1) if (value == (LogLevel) - 1)
fatal("%.200s line %d: unsupported log level '%s'\n", fatal("%.200s line %d: unsupported log level '%s'",
filename, linenum, arg ? arg : "<NONE>"); filename, linenum, arg ? arg : "<NONE>");
if (*intptr == -1) if (*intptr == -1)
*intptr = (LogLevel) value; *intptr = (LogLevel) value;
@ -633,7 +722,7 @@ read_server_config(ServerOptions *options, const char *filename)
case sAllowUsers: case sAllowUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_users >= MAX_ALLOW_USERS) if (options->num_allow_users >= MAX_ALLOW_USERS)
fatal("%.200s line %d: too many allow users.\n", fatal("%.200s line %d: too many allow users.",
filename, linenum); filename, linenum);
options->allow_users[options->num_allow_users++] = xstrdup(arg); options->allow_users[options->num_allow_users++] = xstrdup(arg);
} }
@ -642,7 +731,7 @@ read_server_config(ServerOptions *options, const char *filename)
case sDenyUsers: case sDenyUsers:
while ((arg = strdelim(&cp)) && *arg != '\0') { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_users >= MAX_DENY_USERS) if (options->num_deny_users >= MAX_DENY_USERS)
fatal("%.200s line %d: too many deny users.\n", fatal(".200%s line %d: too many deny users.",
filename, linenum); filename, linenum);
options->deny_users[options->num_deny_users++] = xstrdup(arg); options->deny_users[options->num_deny_users++] = xstrdup(arg);
} }
@ -651,7 +740,7 @@ read_server_config(ServerOptions *options, const char *filename)
case sAllowGroups: case sAllowGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_allow_groups >= MAX_ALLOW_GROUPS) if (options->num_allow_groups >= MAX_ALLOW_GROUPS)
fatal("%.200s line %d: too many allow groups.\n", fatal("%.200s line %d: too many allow groups.",
filename, linenum); filename, linenum);
options->allow_groups[options->num_allow_groups++] = xstrdup(arg); options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
} }
@ -660,7 +749,7 @@ read_server_config(ServerOptions *options, const char *filename)
case sDenyGroups: case sDenyGroups:
while ((arg = strdelim(&cp)) && *arg != '\0') { while ((arg = strdelim(&cp)) && *arg != '\0') {
if (options->num_deny_groups >= MAX_DENY_GROUPS) if (options->num_deny_groups >= MAX_DENY_GROUPS)
fatal("%.200s line %d: too many deny groups.\n", fatal("%.200s line %d: too many deny groups.",
filename, linenum); filename, linenum);
options->deny_groups[options->num_deny_groups++] = xstrdup(arg); options->deny_groups[options->num_deny_groups++] = xstrdup(arg);
} }
@ -677,6 +766,17 @@ read_server_config(ServerOptions *options, const char *filename)
options->ciphers = xstrdup(arg); options->ciphers = xstrdup(arg);
break; break;
case sMacs:
arg = strdelim(&cp);
if (!arg || *arg == '\0')
fatal("%s line %d: Missing argument.", filename, linenum);
if (!mac_valid(arg))
fatal("%s line %d: Bad SSH2 mac spec '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (options->macs == NULL)
options->macs = xstrdup(arg);
break;
case sProtocol: case sProtocol:
intptr = &options->protocol; intptr = &options->protocol;
arg = strdelim(&cp); arg = strdelim(&cp);
@ -744,20 +844,25 @@ read_server_config(ServerOptions *options, const char *filename)
while (arg != NULL && *arg != '\0'); while (arg != NULL && *arg != '\0');
break; break;
case sBanner:
charptr = &options->banner;
goto parse_filename;
case sClientAliveInterval:
intptr = &options->client_alive_interval;
goto parse_int;
case sClientAliveCountMax:
intptr = &options->client_alive_count_max;
goto parse_int;
default: default:
fatal("%.200s line %d: Missing handler for opcode %s (%d)\n", fatal("%.200s line %d: Missing handler for opcode %s (%d)",
filename, linenum,arg, opcode); filename, linenum, arg, opcode);
}
if ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
fprintf(stderr,
"%s line %d: garbage at end of line; \"%.200s\".\n",
filename, linenum, arg);
exit(1);
} }
if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
fatal("%s line %d: garbage at end of line; \"%.200s\".",
filename, linenum, arg);
} }
fclose(f); fclose(f);
if (bad_options > 0) { if (bad_options > 0)
fatal("%.200s: terminating, %d bad configuration options\n", fatal("%.200s: terminating, %d bad configuration options",
filename, bad_options); filename, bad_options);
}
} }

View File

@ -11,8 +11,8 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
*/ */
/* RCSID("$OpenBSD: servconf.h,v 1.30 2000/10/14 12:12:09 markus Exp $"); */ /* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
/* $FreeBSD$ */ /* RCSID("$FreeBSD$"); */
#ifndef SERVCONF_H #ifndef SERVCONF_H
#define SERVCONF_H #define SERVCONF_H
@ -24,25 +24,35 @@
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ #define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
#define MAX_HOSTKEYS 256 /* Max # hostkeys. */
/* permit_root_login */
#define PERMIT_NOT_SET -1
#define PERMIT_NO 0
#define PERMIT_FORCED_ONLY 1
#define PERMIT_NO_PASSWD 2
#define PERMIT_YES 3
typedef struct { typedef struct {
unsigned int num_ports; u_int num_ports;
unsigned int ports_from_cmdline; u_int ports_from_cmdline;
u_short ports[MAX_PORTS]; /* Port number to listen on. */ u_short ports[MAX_PORTS]; /* Port number to listen on. */
char *listen_addr; /* Address on which the server listens. */ char *listen_addr; /* Address on which the server listens. */
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */ struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
char *host_key_file; /* File containing host key. */ char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */
char *host_dsa_key_file; /* File containing dsa host key. */ int num_host_key_files; /* Number of files for host keys. */
char *pid_file; /* Where to put our pid */ char *pid_file; /* Where to put our pid */
int server_key_bits;/* Size of the server key. */ int server_key_bits;/* Size of the server key. */
int login_grace_time; /* Disconnect if no auth in this time int login_grace_time; /* Disconnect if no auth in this time
* (sec). */ * (sec). */
int key_regeneration_time; /* Server key lifetime (seconds). */ int key_regeneration_time; /* Server key lifetime (seconds). */
int permit_root_login; /* If true, permit root login. */ int permit_root_login; /* PERMIT_*, see above */
int ignore_rhosts; /* Ignore .rhosts and .shosts. */ int ignore_rhosts; /* Ignore .rhosts and .shosts. */
int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts
* for RhostsRsaAuth */ * for RhostsRsaAuth */
int print_motd; /* If true, print /etc/motd. */ int print_motd; /* If true, print /etc/motd. */
int print_lastlog; /* If true, print lastlog */
int check_mail; /* If true, check for new mail. */ int check_mail; /* If true, check for new mail. */
int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
int x11_display_offset; /* What DISPLAY number to start int x11_display_offset; /* What DISPLAY number to start
@ -50,8 +60,9 @@ typedef struct {
char *xauth_location; /* Location of xauth program */ char *xauth_location; /* Location of xauth program */
int strict_modes; /* If true, require string home dir modes. */ int strict_modes; /* If true, require string home dir modes. */
int keepalives; /* If true, set SO_KEEPALIVE. */ int keepalives; /* If true, set SO_KEEPALIVE. */
char *ciphers; /* Ciphers in order of preference. */ char *ciphers; /* Supported SSH2 ciphers. */
int protocol; /* Protocol in order of preference. */ char *macs; /* Supported SSH2 macs. */
int protocol; /* Supported protocol versions. */
int gateway_ports; /* If true, allow remote connects to forwarded ports. */ int gateway_ports; /* If true, allow remote connects to forwarded ports. */
SyslogFacility log_facility; /* Facility for system logging. */ SyslogFacility log_facility; /* Facility for system logging. */
LogLevel log_level; /* Level for system logging. */ LogLevel log_level; /* Level for system logging. */
@ -59,11 +70,13 @@ typedef struct {
* authentication. */ * authentication. */
int rhosts_rsa_authentication; /* If true, permit rhosts RSA int rhosts_rsa_authentication; /* If true, permit rhosts RSA
* authentication. */ * authentication. */
int hostbased_authentication; /* If true, permit ssh2 hostbased auth */
int hostbased_uses_name_from_packet_only; /* experimental */
int rsa_authentication; /* If true, permit RSA authentication. */ int rsa_authentication; /* If true, permit RSA authentication. */
int dsa_authentication; /* If true, permit DSA authentication. */
#if defined(KRB4) || defined(KRB5) #if defined(KRB4) || defined(KRB5)
int kerberos_authentication; /* If true, permit Kerberos auth. */ int kerberos_authentication; /* If true, permit Kerberos auth. */
#endif /* KRB4 || KRB5 */ #endif /* KRB4 || KRB5 */
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
#ifdef KRB4 #ifdef KRB4
int krb4_or_local_passwd; /* If true, permit kerberos v4 int krb4_or_local_passwd; /* If true, permit kerberos v4
* and any other password * and any other password
@ -85,21 +98,18 @@ typedef struct {
int password_authentication; /* If true, permit password int password_authentication; /* If true, permit password
* authentication. */ * authentication. */
int kbd_interactive_authentication; /* If true, permit */ int kbd_interactive_authentication; /* If true, permit */
#ifdef SKEY int challenge_reponse_authentication;
int skey_authentication; /* If true, permit s/key
* authentication. */
#endif
int permit_empty_passwd; /* If false, do not permit empty int permit_empty_passwd; /* If false, do not permit empty
* passwords. */ * passwords. */
int use_login; /* If true, login(1) is used */ int use_login; /* If true, login(1) is used */
int allow_tcp_forwarding; int allow_tcp_forwarding;
unsigned int num_allow_users; u_int num_allow_users;
char *allow_users[MAX_ALLOW_USERS]; char *allow_users[MAX_ALLOW_USERS];
unsigned int num_deny_users; u_int num_deny_users;
char *deny_users[MAX_DENY_USERS]; char *deny_users[MAX_DENY_USERS];
unsigned int num_allow_groups; u_int num_allow_groups;
char *allow_groups[MAX_ALLOW_GROUPS]; char *allow_groups[MAX_ALLOW_GROUPS];
unsigned int num_deny_groups; u_int num_deny_groups;
char *deny_groups[MAX_DENY_GROUPS]; char *deny_groups[MAX_DENY_GROUPS];
unsigned int connections_per_period; /* unsigned int connections_per_period; /*
* If not 0, number of sshd * If not 0, number of sshd
@ -108,13 +118,24 @@ typedef struct {
*/ */
unsigned int connections_period; unsigned int connections_period;
unsigned int num_subsystems; u_int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS]; char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS]; char *subsystem_command[MAX_SUBSYSTEMS];
int max_startups_begin; int max_startups_begin;
int max_startups_rate; int max_startups_rate;
int max_startups; int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
int client_alive_interval; /*
* poke the client this often to
* see if it's still there
*/
int client_alive_count_max; /*
*If the client is unresponsive
* for this many intervals, above
* diconnect the session
*/
} ServerOptions; } ServerOptions;
/* /*

View File

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
* *
* SSH2 support by Markus Friedl. * SSH2 support by Markus Friedl.
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -36,24 +36,31 @@
#include "includes.h" #include "includes.h"
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
RCSID("$OpenBSD: serverloop.c,v 1.34 2000/10/27 07:32:18 markus Exp $"); RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
#include "xmalloc.h" #include "xmalloc.h"
#include "ssh.h"
#include "packet.h" #include "packet.h"
#include "buffer.h" #include "buffer.h"
#include "log.h"
#include "servconf.h" #include "servconf.h"
#include "pty.h" #include "sshpty.h"
#include "channels.h" #include "channels.h"
#include "compat.h" #include "compat.h"
#include "ssh1.h"
#include "ssh2.h" #include "ssh2.h"
#include "auth.h"
#include "session.h" #include "session.h"
#include "dispatch.h" #include "dispatch.h"
#include "auth-options.h" #include "auth-options.h"
#include "serverloop.h"
#include "misc.h"
#include "kex.h"
extern ServerOptions options; extern ServerOptions options;
/* XXX */
extern Kex *xxx_kex;
static Buffer stdin_buffer; /* Buffer for stdin data. */ static Buffer stdin_buffer; /* Buffer for stdin data. */
static Buffer stdout_buffer; /* Buffer for stdout data. */ static Buffer stdout_buffer; /* Buffer for stdout data. */
static Buffer stderr_buffer; /* Buffer for stderr data. */ static Buffer stderr_buffer; /* Buffer for stderr data. */
@ -71,8 +78,8 @@ static int fderr_eof = 0; /* EOF encountered readung from fderr. */
static int fdin_is_tty = 0; /* fdin points to a tty. */ static int fdin_is_tty = 0; /* fdin points to a tty. */
static int connection_in; /* Connection to client (input). */ static int connection_in; /* Connection to client (input). */
static int connection_out; /* Connection to client (output). */ static int connection_out; /* Connection to client (output). */
static unsigned int buffer_high;/* "Soft" max buffer size. */ static int connection_closed = 0; /* Connection to client closed. */
static int max_fd; /* Max file descriptor number for select(). */ static u_int buffer_high; /* "Soft" max buffer size. */
/* /*
* This SIGCHLD kludge is used to detect when the child exits. The server * This SIGCHLD kludge is used to detect when the child exits. The server
@ -85,6 +92,8 @@ static volatile int child_wait_status; /* Status from wait(). */
void server_init_dispatch(void); void server_init_dispatch(void);
int client_alive_timeouts = 0;
void void
sigchld_handler(int sig) sigchld_handler(int sig)
{ {
@ -119,7 +128,7 @@ sigchld_handler2(int sig)
* to the client. * to the client.
*/ */
void void
make_packets_from_stderr_data() make_packets_from_stderr_data(void)
{ {
int len; int len;
@ -148,7 +157,7 @@ make_packets_from_stderr_data()
* client. * client.
*/ */
void void
make_packets_from_stdout_data() make_packets_from_stdout_data(void)
{ {
int len; int len;
@ -162,7 +171,7 @@ make_packets_from_stdout_data()
} else { } else {
/* Keep the packets at reasonable size. */ /* Keep the packets at reasonable size. */
if (len > packet_get_maxsize()) if (len > packet_get_maxsize())
len = packet_get_maxsize(); len = packet_get_maxsize();
} }
packet_start(SSH_SMSG_STDOUT_DATA); packet_start(SSH_SMSG_STDOUT_DATA);
packet_put_string(buffer_ptr(&stdout_buffer), len); packet_put_string(buffer_ptr(&stdout_buffer), len);
@ -179,23 +188,37 @@ make_packets_from_stdout_data()
* for the duration of the wait (0 = infinite). * for the duration of the wait (0 = infinite).
*/ */
void void
wait_until_can_do_something(fd_set * readset, fd_set * writeset, wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
unsigned int max_time_milliseconds) u_int max_time_milliseconds)
{ {
struct timeval tv, *tvp; struct timeval tv, *tvp;
int ret; int ret;
int client_alive_scheduled = 0;
/*
* if using client_alive, set the max timeout accordingly,
* and indicate that this particular timeout was for client
* alive by setting the client_alive_scheduled flag.
*
* this could be randomized somewhat to make traffic
* analysis more difficult, but we're not doing it yet.
*/
if (max_time_milliseconds == 0 && options.client_alive_interval) {
client_alive_scheduled = 1;
max_time_milliseconds = options.client_alive_interval * 1000;
} else
client_alive_scheduled = 0;
/* When select fails we restart from here. */ /* When select fails we restart from here. */
retry_select: retry_select:
/* Initialize select() masks. */ /* Allocate and update select() masks for channel descriptors. */
FD_ZERO(readset); channel_prepare_select(readsetp, writesetp, maxfdp, 0);
FD_ZERO(writeset);
if (compat20) { if (compat20) {
/* wrong: bad condition XXX */ /* wrong: bad condition XXX */
if (channel_not_very_much_buffered_data()) if (channel_not_very_much_buffered_data())
FD_SET(connection_in, readset); FD_SET(connection_in, *readsetp);
} else { } else {
/* /*
* Read packets from the client unless we have too much * Read packets from the client unless we have too much
@ -203,44 +226,38 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
*/ */
if (buffer_len(&stdin_buffer) < buffer_high && if (buffer_len(&stdin_buffer) < buffer_high &&
channel_not_very_much_buffered_data()) channel_not_very_much_buffered_data())
FD_SET(connection_in, readset); FD_SET(connection_in, *readsetp);
/* /*
* If there is not too much data already buffered going to * If there is not too much data already buffered going to
* the client, try to get some more data from the program. * the client, try to get some more data from the program.
*/ */
if (packet_not_very_much_data_to_write()) { if (packet_not_very_much_data_to_write()) {
if (!fdout_eof) if (!fdout_eof)
FD_SET(fdout, readset); FD_SET(fdout, *readsetp);
if (!fderr_eof) if (!fderr_eof)
FD_SET(fderr, readset); FD_SET(fderr, *readsetp);
} }
/* /*
* If we have buffered data, try to write some of that data * If we have buffered data, try to write some of that data
* to the program. * to the program.
*/ */
if (fdin != -1 && buffer_len(&stdin_buffer) > 0) if (fdin != -1 && buffer_len(&stdin_buffer) > 0)
FD_SET(fdin, writeset); FD_SET(fdin, *writesetp);
} }
/* Set masks for channel descriptors. */
channel_prepare_select(readset, writeset);
/* /*
* If we have buffered packet data going to the client, mark that * If we have buffered packet data going to the client, mark that
* descriptor. * descriptor.
*/ */
if (packet_have_data_to_write()) if (packet_have_data_to_write())
FD_SET(connection_out, writeset); FD_SET(connection_out, *writesetp);
/* Update the maximum descriptor number if appropriate. */
if (channel_max_fd() > max_fd)
max_fd = channel_max_fd();
/* /*
* If child has terminated and there is enough buffer space to read * If child has terminated and there is enough buffer space to read
* from it, then read as much as is available and exit. * from it, then read as much as is available and exit.
*/ */
if (child_terminated && packet_not_very_much_data_to_write()) if (child_terminated && packet_not_very_much_data_to_write())
if (max_time_milliseconds == 0) if (max_time_milliseconds == 0 || client_alive_scheduled)
max_time_milliseconds = 100; max_time_milliseconds = 100;
if (max_time_milliseconds == 0) if (max_time_milliseconds == 0)
@ -251,17 +268,41 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
tvp = &tv; tvp = &tv;
} }
if (tvp!=NULL) if (tvp!=NULL)
debug("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds); debug3("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds);
/* Wait for something to happen, or the timeout to expire. */ /* Wait for something to happen, or the timeout to expire. */
ret = select(max_fd + 1, readset, writeset, NULL, tvp); ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
if (ret < 0) { if (ret == -1) {
if (errno != EINTR) if (errno != EINTR)
error("select: %.100s", strerror(errno)); error("select: %.100s", strerror(errno));
else else
goto retry_select; goto retry_select;
} }
if (ret == 0 && client_alive_scheduled) {
/* timeout, check to see how many we have had */
client_alive_timeouts++;
if (client_alive_timeouts > options.client_alive_count_max ) {
packet_disconnect(
"Timeout, your session not responding.");
} else {
/*
* send a bogus channel request with "wantreply"
* we should get back a failure
*/
int id;
id = channel_find_open();
if (id != -1) {
channel_request_start(id,
"keepalive@openssh.com", 1);
packet_send();
} else
packet_disconnect(
"No open channels after timeout!");
}
}
} }
/* /*
@ -279,6 +320,9 @@ process_input(fd_set * readset)
len = read(connection_in, buf, sizeof(buf)); len = read(connection_in, buf, sizeof(buf));
if (len == 0) { if (len == 0) {
verbose("Connection closed by remote host."); verbose("Connection closed by remote host.");
connection_closed = 1;
if (compat20)
return;
fatal_cleanup(); fatal_cleanup();
} else if (len < 0) { } else if (len < 0) {
if (errno != EINTR && errno != EAGAIN) { if (errno != EINTR && errno != EAGAIN) {
@ -351,9 +395,7 @@ process_output(fd_set * writeset)
* Simulate echo to reduce the impact of * Simulate echo to reduce the impact of
* traffic analysis * traffic analysis
*/ */
packet_start(SSH_MSG_IGNORE); packet_send_ignore(len);
memset(buffer_ptr(&stdin_buffer), 0, len);
packet_put_string(buffer_ptr(&stdin_buffer), len);
packet_send(); packet_send();
} }
/* Consume the data from the buffer. */ /* Consume the data from the buffer. */
@ -372,7 +414,7 @@ process_output(fd_set * writeset)
* This is used when the program terminates. * This is used when the program terminates.
*/ */
void void
drain_output() drain_output(void)
{ {
/* Send any buffered stdout data to the client. */ /* Send any buffered stdout data to the client. */
if (buffer_len(&stdout_buffer) > 0) { if (buffer_len(&stdout_buffer) > 0) {
@ -397,9 +439,9 @@ drain_output()
} }
void void
process_buffered_input_packets() process_buffered_input_packets(void)
{ {
dispatch_run(DISPATCH_NONBLOCK, NULL, NULL); dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL);
} }
/* /*
@ -412,13 +454,14 @@ process_buffered_input_packets()
void void
server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
{ {
fd_set readset, writeset; fd_set *readset = NULL, *writeset = NULL;
int max_fd;
int wait_status; /* Status returned by wait(). */ int wait_status; /* Status returned by wait(). */
pid_t wait_pid; /* pid returned by wait(). */ pid_t wait_pid; /* pid returned by wait(). */
int waiting_termination = 0; /* Have displayed waiting close message. */ int waiting_termination = 0; /* Have displayed waiting close message. */
unsigned int max_time_milliseconds; u_int max_time_milliseconds;
unsigned int previous_stdout_buffer_bytes; u_int previous_stdout_buffer_bytes;
unsigned int stdout_buffer_bytes; u_int stdout_buffer_bytes;
int type; int type;
debug("Entering interactive session."); debug("Entering interactive session.");
@ -455,15 +498,11 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
buffer_high = 64 * 1024; buffer_high = 64 * 1024;
/* Initialize max_fd to the maximum of the known file descriptors. */ /* Initialize max_fd to the maximum of the known file descriptors. */
max_fd = fdin; max_fd = MAX(fdin, fdout);
if (fdout > max_fd) if (fderr != -1)
max_fd = fdout; max_fd = MAX(max_fd, fderr);
if (fderr != -1 && fderr > max_fd) max_fd = MAX(max_fd, connection_in);
max_fd = fderr; max_fd = MAX(max_fd, connection_out);
if (connection_in > max_fd)
max_fd = connection_in;
if (connection_out > max_fd)
max_fd = connection_out;
/* Initialize Initialize buffers. */ /* Initialize Initialize buffers. */
buffer_init(&stdin_buffer); buffer_init(&stdin_buffer);
@ -550,18 +589,22 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
} }
} }
/* Sleep in select() until we can do something. */ /* Sleep in select() until we can do something. */
wait_until_can_do_something(&readset, &writeset, wait_until_can_do_something(&readset, &writeset, &max_fd,
max_time_milliseconds); max_time_milliseconds);
/* Process any channel events. */ /* Process any channel events. */
channel_after_select(&readset, &writeset); channel_after_select(readset, writeset);
/* Process input from the client and from program stdout/stderr. */ /* Process input from the client and from program stdout/stderr. */
process_input(&readset); process_input(readset);
/* Process output to the client and to program stdin. */ /* Process output to the client and to program stdin. */
process_output(&writeset); process_output(writeset);
} }
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
/* Cleanup and termination code. */ /* Cleanup and termination code. */
@ -594,7 +637,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* Wait for the child to exit. Get its exit status. */ /* Wait for the child to exit. Get its exit status. */
wait_pid = wait(&wait_status); wait_pid = wait(&wait_status);
if (wait_pid < 0) { if (wait_pid == -1) {
/* /*
* It is possible that the wait was handled by SIGCHLD * It is possible that the wait was handled by SIGCHLD
* handler. This may result in either: this call * handler. This may result in either: this call
@ -652,9 +695,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
void void
server_loop2(void) server_loop2(void)
{ {
fd_set readset, writeset; fd_set *readset = NULL, *writeset = NULL;
int had_channel = 0; int rekeying = 0, max_fd, status;
int status;
pid_t pid; pid_t pid;
debug("Entering interactive session for SSH2."); debug("Entering interactive session for SSH2.");
@ -663,42 +705,61 @@ server_loop2(void)
child_terminated = 0; child_terminated = 0;
connection_in = packet_get_connection_in(); connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out(); connection_out = packet_get_connection_out();
max_fd = connection_in;
if (connection_out > max_fd) max_fd = MAX(connection_in, connection_out);
max_fd = connection_out;
server_init_dispatch(); server_init_dispatch();
for (;;) { for (;;) {
process_buffered_input_packets(); process_buffered_input_packets();
if (!had_channel && channel_still_open())
had_channel = 1; rekeying = (xxx_kex != NULL && !xxx_kex->done);
if (had_channel && !channel_still_open()) {
debug("!channel_still_open."); if (!rekeying && packet_not_very_much_data_to_write())
break;
}
if (packet_not_very_much_data_to_write())
channel_output_poll(); channel_output_poll();
wait_until_can_do_something(&readset, &writeset, 0); wait_until_can_do_something(&readset, &writeset, &max_fd,
rekeying);
if (child_terminated) { if (child_terminated) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status); session_close_by_pid(pid, status);
child_terminated = 0; child_terminated = 0;
} }
channel_after_select(&readset, &writeset); if (!rekeying)
process_input(&readset); channel_after_select(readset, writeset);
process_output(&writeset); process_input(readset);
if (connection_closed)
break;
process_output(writeset);
} }
if (readset)
xfree(readset);
if (writeset)
xfree(writeset);
signal(SIGCHLD, SIG_DFL); signal(SIGCHLD, SIG_DFL);
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
session_close_by_pid(pid, status); session_close_by_pid(pid, status);
channel_stop_listening(); channel_stop_listening();
} }
void
server_input_channel_failure(int type, int plen, void *ctxt)
{
debug("Got CHANNEL_FAILURE for keepalive");
/*
* reset timeout, since we got a sane answer from the client.
* even if this was generated by something other than
* the bogus CHANNEL_REQUEST we send for keepalives.
*/
client_alive_timeouts = 0;
}
void void
server_input_stdin_data(int type, int plen, void *ctxt) server_input_stdin_data(int type, int plen, void *ctxt)
{ {
char *data; char *data;
unsigned int data_len; u_int data_len;
/* Stdin data from the client. Append it to the buffer. */ /* Stdin data from the client. Append it to the buffer. */
/* Ignore any data if the client has closed stdin. */ /* Ignore any data if the client has closed stdin. */
@ -738,10 +799,10 @@ server_input_window_size(int type, int plen, void *ctxt)
pty_change_window_size(fdin, row, col, xpixel, ypixel); pty_change_window_size(fdin, row, col, xpixel, ypixel);
} }
int Channel *
input_direct_tcpip(void) server_request_direct_tcpip(char *ctype)
{ {
int sock; int sock, newch;
char *target, *originator; char *target, *originator;
int target_port, originator_port; int target_port, originator_port;
@ -751,23 +812,47 @@ input_direct_tcpip(void)
originator_port = packet_get_int(); originator_port = packet_get_int();
packet_done(); packet_done();
debug("open direct-tcpip: from %s port %d to %s port %d", debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
originator, originator_port, target, target_port); originator, originator_port, target, target_port);
/* XXX check permission */ /* XXX check permission */
if (no_port_forwarding_flag || !options.allow_tcp_forwarding) {
xfree(target);
xfree(originator);
return -1;
}
sock = channel_connect_to(target, target_port); sock = channel_connect_to(target, target_port);
xfree(target); xfree(target);
xfree(originator); xfree(originator);
if (sock < 0) if (sock < 0)
return -1; return NULL;
return channel_new("direct-tcpip", SSH_CHANNEL_OPEN, newch = channel_new(ctype, SSH_CHANNEL_CONNECTING,
sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1); CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("direct-tcpip"), 1);
return (newch >= 0) ? channel_lookup(newch) : NULL;
}
Channel *
server_request_session(char *ctype)
{
int newch;
debug("input_session_request");
packet_done();
/*
* A server session has no fd to read or write until a
* CHANNEL_REQUEST for a shell is made, so we set the type to
* SSH_CHANNEL_LARVAL. Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
newch = channel_new(ctype, SSH_CHANNEL_LARVAL,
-1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
0, xstrdup("server-session"), 1);
if (session_open(newch) == 1) {
channel_register_callback(newch, SSH2_MSG_CHANNEL_REQUEST,
session_input_channel_req, (void *)0);
channel_register_cleanup(newch, session_close_by_channel);
return channel_lookup(newch);
} else {
debug("session open failed, free channel %d", newch);
channel_free(newch);
}
return NULL;
} }
void void
@ -775,8 +860,7 @@ server_input_channel_open(int type, int plen, void *ctxt)
{ {
Channel *c = NULL; Channel *c = NULL;
char *ctype; char *ctype;
int id; u_int len;
unsigned int len;
int rchan; int rchan;
int rmaxpack; int rmaxpack;
int rwindow; int rwindow;
@ -790,34 +874,12 @@ server_input_channel_open(int type, int plen, void *ctxt)
ctype, rchan, rwindow, rmaxpack); ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "session") == 0) { if (strcmp(ctype, "session") == 0) {
debug("open session"); c = server_request_session(ctype);
packet_done();
/*
* A server session has no fd to read or write
* until a CHANNEL_REQUEST for a shell is made,
* so we set the type to SSH_CHANNEL_LARVAL.
* Additionally, a callback for handling all
* CHANNEL_REQUEST messages is registered.
*/
id = channel_new(ctype, SSH_CHANNEL_LARVAL,
-1, -1, -1, 0, CHAN_SES_PACKET_DEFAULT,
0, xstrdup("server-session"), 1);
if (session_open(id) == 1) {
channel_register_callback(id, SSH2_MSG_CHANNEL_REQUEST,
session_input_channel_req, (void *)0);
channel_register_cleanup(id, session_close_by_channel);
c = channel_lookup(id);
} else {
debug("session open failed, free channel %d", id);
channel_free(id);
}
} else if (strcmp(ctype, "direct-tcpip") == 0) { } else if (strcmp(ctype, "direct-tcpip") == 0) {
id = input_direct_tcpip(); c = server_request_direct_tcpip(ctype);
if (id >= 0)
c = channel_lookup(id);
} }
if (c != NULL) { if (c != NULL) {
debug("confirm %s", ctype); debug("server_input_channel_open: confirm %s", ctype);
c->remote_id = rchan; c->remote_id = rchan;
c->remote_window = rwindow; c->remote_window = rwindow;
c->remote_maxpacket = rmaxpack; c->remote_maxpacket = rmaxpack;
@ -829,7 +891,7 @@ server_input_channel_open(int type, int plen, void *ctxt)
packet_put_int(c->local_maxpacket); packet_put_int(c->local_maxpacket);
packet_send(); packet_send();
} else { } else {
debug("failure %s", ctype); debug("server_input_channel_open: failure %s", ctype);
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
packet_put_int(rchan); packet_put_int(rchan);
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
@ -841,7 +903,57 @@ server_input_channel_open(int type, int plen, void *ctxt)
} }
void void
server_init_dispatch_20() server_input_global_request(int type, int plen, void *ctxt)
{
char *rtype;
int want_reply;
int success = 0;
rtype = packet_get_string(NULL);
want_reply = packet_get_char();
debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply);
/* -R style forwarding */
if (strcmp(rtype, "tcpip-forward") == 0) {
struct passwd *pw;
char *listen_address;
u_short listen_port;
pw = auth_get_user();
if (pw == NULL)
fatal("server_input_global_request: no user");
listen_address = packet_get_string(NULL); /* XXX currently ignored */
listen_port = (u_short)packet_get_int();
debug("server_input_global_request: tcpip-forward listen %s port %d",
listen_address, listen_port);
/* check permissions */
if (!options.allow_tcp_forwarding ||
no_port_forwarding_flag ||
(listen_port < IPPORT_RESERVED && pw->pw_uid != 0)) {
success = 0;
packet_send_debug("Server has disabled port forwarding.");
} else {
/* Start listening on the port */
success = channel_request_forwarding(
listen_address, listen_port,
/*unspec host_to_connect*/ "<unspec host>",
/*unspec port_to_connect*/ 0,
options.gateway_ports, /*remote*/ 1);
}
xfree(listen_address);
}
if (want_reply) {
packet_start(success ?
SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
packet_send();
packet_write_wait();
}
xfree(rtype);
}
void
server_init_dispatch_20(void)
{ {
debug("server_init_dispatch_20"); debug("server_init_dispatch_20");
dispatch_init(&dispatch_protocol_error); dispatch_init(&dispatch_protocol_error);
@ -854,9 +966,14 @@ server_init_dispatch_20()
dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request); dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
/* client_alive */
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
} }
void void
server_init_dispatch_13() server_init_dispatch_13(void)
{ {
debug("server_init_dispatch_13"); debug("server_init_dispatch_13");
dispatch_init(NULL); dispatch_init(NULL);
@ -871,7 +988,7 @@ server_init_dispatch_13()
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
} }
void void
server_init_dispatch_15() server_init_dispatch_15(void)
{ {
server_init_dispatch_13(); server_init_dispatch_13();
debug("server_init_dispatch_15"); debug("server_init_dispatch_15");
@ -879,7 +996,7 @@ server_init_dispatch_15()
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
} }
void void
server_init_dispatch() server_init_dispatch(void)
{ {
if (compat20) if (compat20)
server_init_dispatch_20(); server_init_dispatch_20();
@ -888,3 +1005,4 @@ server_init_dispatch()
else else
server_init_dispatch_15(); server_init_dispatch_15();
} }

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
* *
* SSH2 implementation, * SSH2 implementation,
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -36,33 +36,42 @@
#include "includes.h" #include "includes.h"
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
RCSID("$OpenBSD: ssh-add.c,v 1.22 2000/09/07 20:27:54 deraadt Exp $"); RCSID("$OpenBSD: ssh-add.c,v 1.36 2001/04/18 21:57:42 markus Exp $");
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include "rsa.h"
#include "ssh.h" #include "ssh.h"
#include "rsa.h"
#include "log.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "key.h" #include "key.h"
#include "authfd.h" #include "authfd.h"
#include "authfile.h" #include "authfile.h"
#include "pathnames.h"
#include "readpass.h"
/* we keep a cache of one passphrases */
static char *pass = NULL;
void
clear_pass(void)
{
if (pass) {
memset(pass, 0, strlen(pass));
xfree(pass);
pass = NULL;
}
}
void void
delete_file(AuthenticationConnection *ac, const char *filename) delete_file(AuthenticationConnection *ac, const char *filename)
{ {
Key *public; Key *public;
char *comment; char *comment = NULL;
public = key_new(KEY_RSA); public = key_load_public(filename, &comment);
if (!load_public_key(filename, public, &comment)) { if (public == NULL) {
key_free(public); printf("Bad key file %s\n", filename);
public = key_new(KEY_DSA); return;
if (!try_load_public_key(filename, public, &comment)) {
printf("Bad key file %s\n", filename);
return;
}
} }
if (ssh_remove_identity(ac, public)) if (ssh_remove_identity(ac, public))
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
@ -86,129 +95,61 @@ delete_all(AuthenticationConnection *ac)
if (success) if (success)
fprintf(stderr, "All identities removed.\n"); fprintf(stderr, "All identities removed.\n");
else else
fprintf(stderr, "Failed to remove all identitities.\n"); fprintf(stderr, "Failed to remove all identities.\n");
}
char *
ssh_askpass(char *askpass, char *msg)
{
pid_t pid;
size_t len;
char *nl, *pass;
int p[2], status;
char buf[1024];
if (askpass == NULL)
fatal("internal error: askpass undefined");
if (pipe(p) < 0)
fatal("ssh_askpass: pipe: %s", strerror(errno));
fflush(stdout);
fflush(stderr);
if ((pid = fork()) < 0)
fatal("ssh_askpass: fork: %s", strerror(errno));
if (pid == 0) {
close(p[0]);
if (dup2(p[1], STDOUT_FILENO) < 0)
fatal("ssh_askpass: dup2: %s", strerror(errno));
execlp(askpass, askpass, msg, (char *) 0);
fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
}
close(p[1]);
len = read(p[0], buf, sizeof buf);
close(p[0]);
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
if (len <= 1)
return xstrdup("");
nl = strchr(buf, '\n');
if (nl)
*nl = '\0';
pass = xstrdup(buf);
memset(buf, 0, sizeof(buf));
return pass;
} }
void void
add_file(AuthenticationConnection *ac, const char *filename) add_file(AuthenticationConnection *ac, const char *filename)
{ {
struct stat st; struct stat st;
Key *public;
Key *private; Key *private;
char *saved_comment, *comment, *askpass = NULL; char *comment = NULL;
char buf[1024], msg[1024]; char msg[1024];
int success;
int interactive = isatty(STDIN_FILENO);
int type = KEY_RSA;
if (stat(filename, &st) < 0) { if (stat(filename, &st) < 0) {
perror(filename); perror(filename);
exit(1); exit(1);
} }
/*
* try to load the public key. right now this only works for RSA,
* since DSA keys are fully encrypted
*/
public = key_new(KEY_RSA);
if (!load_public_key(filename, public, &saved_comment)) {
/* ok, so we will asume this is a DSA key */
type = KEY_DSA;
saved_comment = xstrdup(filename);
}
key_free(public);
if (!interactive && getenv("DISPLAY")) {
if (getenv(SSH_ASKPASS_ENV))
askpass = getenv(SSH_ASKPASS_ENV);
else
askpass = SSH_ASKPASS_DEFAULT;
}
/* At first, try empty passphrase */ /* At first, try empty passphrase */
private = key_new(type); private = key_load_private(filename, "", &comment);
success = load_private_key(filename, "", private, &comment); if (comment == NULL)
if (!success) { comment = xstrdup(filename);
/* try last */
if (private == NULL && pass != NULL)
private = key_load_private(filename, pass, NULL);
if (private == NULL) {
/* clear passphrase since it did not work */
clear_pass();
printf("Need passphrase for %.200s\n", filename); printf("Need passphrase for %.200s\n", filename);
if (!interactive && askpass == NULL) { snprintf(msg, sizeof msg, "Enter passphrase for %.200s ",
xfree(saved_comment); comment);
return;
}
snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
for (;;) { for (;;) {
char *pass; pass = read_passphrase(msg, 1);
if (interactive) {
snprintf(buf, sizeof buf, "%s: ", msg);
pass = read_passphrase(buf, 1);
} else {
pass = ssh_askpass(askpass, msg);
}
if (strcmp(pass, "") == 0) { if (strcmp(pass, "") == 0) {
xfree(pass); clear_pass();
xfree(saved_comment); xfree(comment);
return; return;
} }
success = load_private_key(filename, pass, private, &comment); private = key_load_private(filename, pass, &comment);
memset(pass, 0, strlen(pass)); if (private != NULL)
xfree(pass);
if (success)
break; break;
strlcpy(msg, "Bad passphrase, try again", sizeof msg); clear_pass();
strlcpy(msg, "Bad passphrase, try again ", sizeof msg);
} }
} }
xfree(comment); if (ssh_add_identity(ac, private, comment))
if (ssh_add_identity(ac, private, saved_comment)) fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
fprintf(stderr, "Identity added: %s (%s)\n", filename, saved_comment);
else else
fprintf(stderr, "Could not add identity: %s\n", filename); fprintf(stderr, "Could not add identity: %s\n", filename);
xfree(comment);
key_free(private); key_free(private);
xfree(saved_comment);
} }
void void
list_identities(AuthenticationConnection *ac, int fp) list_identities(AuthenticationConnection *ac, int do_fp)
{ {
Key *key; Key *key;
char *comment; char *comment, *fp;
int had_identities = 0; int had_identities = 0;
int version; int version;
@ -217,9 +158,12 @@ list_identities(AuthenticationConnection *ac, int fp)
key != NULL; key != NULL;
key = ssh_get_next_identity(ac, &comment, version)) { key = ssh_get_next_identity(ac, &comment, version)) {
had_identities = 1; had_identities = 1;
if (fp) { if (do_fp) {
printf("%d %s %s\n", fp = key_fingerprint(key, SSH_FP_MD5,
key_size(key), key_fingerprint(key), comment); SSH_FP_HEX);
printf("%d %s %s (%s)\n",
key_size(key), fp, comment, key_type(key));
xfree(fp);
} else { } else {
if (!key_write(key, stdout)) if (!key_write(key, stdout))
fprintf(stderr, "key_write failed"); fprintf(stderr, "key_write failed");
@ -243,16 +187,7 @@ main(int argc, char **argv)
int i; int i;
int deleting = 0; int deleting = 0;
/* check if RSA support exists */ SSLeay_add_all_algorithms();
if (rsa_alive() == 0) {
extern char *__progname;
fprintf(stderr,
"%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
__progname);
exit(1);
}
SSLeay_add_all_algorithms();
/* At first, get a connection to the authentication agent. */ /* At first, get a connection to the authentication agent. */
ac = ssh_get_authentication_connection(); ac = ssh_get_authentication_connection();
@ -291,12 +226,13 @@ main(int argc, char **argv)
ssh_close_authentication_connection(ac); ssh_close_authentication_connection(ac);
exit(1); exit(1);
} }
snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_CLIENT_IDENTITY);
if (deleting) if (deleting)
delete_file(ac, buf); delete_file(ac, buf);
else else
add_file(ac, buf); add_file(ac, buf);
} }
clear_pass();
ssh_close_authentication_connection(ac); ssh_close_authentication_connection(ac);
exit(0); exit(0);
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $ */ /* $OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -13,7 +13,7 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
* *
* SSH2 implementation, * SSH2 implementation,
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -37,9 +37,12 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: ssh-agent.c,v 1.37 2000/09/21 11:07:51 markus Exp $"); RCSID("$OpenBSD: ssh-agent.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/evp.h>
#include <openssl/md5.h>
#include "ssh.h" #include "ssh.h"
#include "rsa.h" #include "rsa.h"
#include "buffer.h" #include "buffer.h"
@ -48,16 +51,12 @@ RCSID("$FreeBSD$");
#include "packet.h" #include "packet.h"
#include "getput.h" #include "getput.h"
#include "mpaux.h" #include "mpaux.h"
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include "key.h" #include "key.h"
#include "authfd.h" #include "authfd.h"
#include "dsa.h" #include "cipher.h"
#include "kex.h" #include "kex.h"
#include "compat.h" #include "compat.h"
#include "log.h"
typedef struct { typedef struct {
int fd; int fd;
@ -68,7 +67,7 @@ typedef struct {
Buffer output; Buffer output;
} SocketEntry; } SocketEntry;
unsigned int sockets_alloc = 0; u_int sockets_alloc = 0;
SocketEntry *sockets = NULL; SocketEntry *sockets = NULL;
typedef struct { typedef struct {
@ -95,6 +94,8 @@ char socket_dir[1024];
extern char *__progname; extern char *__progname;
int prepare_select(fd_set **, fd_set **, int *);
void void
idtab_init(void) idtab_init(void)
{ {
@ -144,14 +145,14 @@ process_request_identities(SocketEntry *e, int version)
buffer_put_int(&msg, tab->nentries); buffer_put_int(&msg, tab->nentries);
for (i = 0; i < tab->nentries; i++) { for (i = 0; i < tab->nentries; i++) {
Identity *id = &tab->identities[i]; Identity *id = &tab->identities[i];
if (id->key->type == KEY_RSA) { if (id->key->type == KEY_RSA1) {
buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
buffer_put_bignum(&msg, id->key->rsa->e); buffer_put_bignum(&msg, id->key->rsa->e);
buffer_put_bignum(&msg, id->key->rsa->n); buffer_put_bignum(&msg, id->key->rsa->n);
} else { } else {
unsigned char *blob; u_char *blob;
unsigned int blen; u_int blen;
dsa_make_key_blob(id->key, &blob, &blen); key_to_blob(id->key, &blob, &blen);
buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, blob, blen);
xfree(blob); xfree(blob);
} }
@ -171,11 +172,11 @@ process_authentication_challenge1(SocketEntry *e)
int i, len; int i, len;
Buffer msg; Buffer msg;
MD5_CTX md; MD5_CTX md;
unsigned char buf[32], mdbuf[16], session_id[16]; u_char buf[32], mdbuf[16], session_id[16];
unsigned int response_type; u_int response_type;
buffer_init(&msg); buffer_init(&msg);
key = key_new(KEY_RSA); key = key_new(KEY_RSA1);
challenge = BN_new(); challenge = BN_new();
buffer_get_int(&e->input); /* ignored */ buffer_get_int(&e->input); /* ignored */
@ -234,14 +235,14 @@ process_sign_request2(SocketEntry *e)
{ {
extern int datafellows; extern int datafellows;
Key *key, *private; Key *key, *private;
unsigned char *blob, *data, *signature = NULL; u_char *blob, *data, *signature = NULL;
unsigned int blen, dlen, slen = 0; u_int blen, dlen, slen = 0;
int flags; int flags;
Buffer msg; Buffer msg;
int ok = -1; int ok = -1;
datafellows = 0; datafellows = 0;
blob = buffer_get_string(&e->input, &blen); blob = buffer_get_string(&e->input, &blen);
data = buffer_get_string(&e->input, &dlen); data = buffer_get_string(&e->input, &dlen);
@ -249,11 +250,11 @@ process_sign_request2(SocketEntry *e)
if (flags & SSH_AGENT_OLD_SIGNATURE) if (flags & SSH_AGENT_OLD_SIGNATURE)
datafellows = SSH_BUG_SIGBLOB; datafellows = SSH_BUG_SIGBLOB;
key = dsa_key_from_blob(blob, blen); key = key_from_blob(blob, blen);
if (key != NULL) { if (key != NULL) {
private = lookup_private_key(key, NULL, 2); private = lookup_private_key(key, NULL, 2);
if (private != NULL) if (private != NULL)
ok = dsa_sign(private, &signature, &slen, data, dlen); ok = key_sign(private, &signature, &slen, data, dlen);
} }
key_free(key); key_free(key);
buffer_init(&msg); buffer_init(&msg);
@ -278,25 +279,25 @@ void
process_remove_identity(SocketEntry *e, int version) process_remove_identity(SocketEntry *e, int version)
{ {
Key *key = NULL, *private; Key *key = NULL, *private;
unsigned char *blob; u_char *blob;
unsigned int blen; u_int blen;
unsigned int bits; u_int bits;
int success = 0; int success = 0;
switch(version){ switch(version){
case 1: case 1:
key = key_new(KEY_RSA); key = key_new(KEY_RSA1);
bits = buffer_get_int(&e->input); bits = buffer_get_int(&e->input);
buffer_get_bignum(&e->input, key->rsa->e); buffer_get_bignum(&e->input, key->rsa->e);
buffer_get_bignum(&e->input, key->rsa->n); buffer_get_bignum(&e->input, key->rsa->n);
if (bits != key_size(key)) if (bits != key_size(key))
log("Warning: identity keysize mismatch: actual %d, announced %d", log("Warning: identity keysize mismatch: actual %d, announced %d",
key_size(key), bits); key_size(key), bits);
break; break;
case 2: case 2:
blob = buffer_get_string(&e->input, &blen); blob = buffer_get_string(&e->input, &blen);
key = dsa_key_from_blob(blob, blen); key = key_from_blob(blob, blen);
xfree(blob); xfree(blob);
break; break;
} }
@ -307,14 +308,24 @@ process_remove_identity(SocketEntry *e, int version)
/* /*
* We have this key. Free the old key. Since we * We have this key. Free the old key. Since we
* don\'t want to leave empty slots in the middle of * don\'t want to leave empty slots in the middle of
* the array, we actually free the key there and copy * the array, we actually free the key there and move
* data from the last entry. * all the entries between the empty slot and the end
* of the array.
*/ */
Idtab *tab = idtab_lookup(version); Idtab *tab = idtab_lookup(version);
key_free(tab->identities[idx].key); key_free(tab->identities[idx].key);
xfree(tab->identities[idx].comment); xfree(tab->identities[idx].comment);
if (idx != tab->nentries) if (tab->nentries < 1)
tab->identities[idx] = tab->identities[tab->nentries]; fatal("process_remove_identity: "
"internal error: tab->nentries %d",
tab->nentries);
if (idx != tab->nentries - 1) {
int i;
for (i = idx; i < tab->nentries - 1; i++)
tab->identities[i] = tab->identities[i+1];
}
tab->identities[tab->nentries - 1].key = NULL;
tab->identities[tab->nentries - 1].comment = NULL;
tab->nentries--; tab->nentries--;
success = 1; success = 1;
} }
@ -328,7 +339,7 @@ process_remove_identity(SocketEntry *e, int version)
void void
process_remove_all_identities(SocketEntry *e, int version) process_remove_all_identities(SocketEntry *e, int version)
{ {
unsigned int i; u_int i;
Idtab *tab = idtab_lookup(version); Idtab *tab = idtab_lookup(version);
/* Loop over all identities and clear the keys. */ /* Loop over all identities and clear the keys. */
@ -350,76 +361,58 @@ void
process_add_identity(SocketEntry *e, int version) process_add_identity(SocketEntry *e, int version)
{ {
Key *k = NULL; Key *k = NULL;
RSA *rsa; char *type_name;
BIGNUM *aux;
BN_CTX *ctx;
char *type;
char *comment; char *comment;
int success = 0; int type, success = 0;
Idtab *tab = idtab_lookup(version); Idtab *tab = idtab_lookup(version);
switch (version) { switch (version) {
case 1: case 1:
k = key_new(KEY_RSA); k = key_new_private(KEY_RSA1);
rsa = k->rsa; buffer_get_int(&e->input); /* ignored */
buffer_get_bignum(&e->input, k->rsa->n);
/* allocate mem for private key */ buffer_get_bignum(&e->input, k->rsa->e);
/* XXX rsa->n and rsa->e are already allocated */ buffer_get_bignum(&e->input, k->rsa->d);
rsa->d = BN_new(); buffer_get_bignum(&e->input, k->rsa->iqmp);
rsa->iqmp = BN_new();
rsa->q = BN_new();
rsa->p = BN_new();
rsa->dmq1 = BN_new();
rsa->dmp1 = BN_new();
buffer_get_int(&e->input); /* ignored */
buffer_get_bignum(&e->input, rsa->n);
buffer_get_bignum(&e->input, rsa->e);
buffer_get_bignum(&e->input, rsa->d);
buffer_get_bignum(&e->input, rsa->iqmp);
/* SSH and SSL have p and q swapped */ /* SSH and SSL have p and q swapped */
buffer_get_bignum(&e->input, rsa->q); /* p */ buffer_get_bignum(&e->input, k->rsa->q); /* p */
buffer_get_bignum(&e->input, rsa->p); /* q */ buffer_get_bignum(&e->input, k->rsa->p); /* q */
/* Generate additional parameters */ /* Generate additional parameters */
aux = BN_new(); generate_additional_parameters(k->rsa);
ctx = BN_CTX_new();
BN_sub(aux, rsa->q, BN_value_one());
BN_mod(rsa->dmq1, rsa->d, aux, ctx);
BN_sub(aux, rsa->p, BN_value_one());
BN_mod(rsa->dmp1, rsa->d, aux, ctx);
BN_clear_free(aux);
BN_CTX_free(ctx);
break; break;
case 2: case 2:
type = buffer_get_string(&e->input, NULL); type_name = buffer_get_string(&e->input, NULL);
if (strcmp(type, KEX_DSS)) { type = key_type_from_name(type_name);
xfree(type_name);
switch(type) {
case KEY_DSA:
k = key_new_private(type);
buffer_get_bignum2(&e->input, k->dsa->p);
buffer_get_bignum2(&e->input, k->dsa->q);
buffer_get_bignum2(&e->input, k->dsa->g);
buffer_get_bignum2(&e->input, k->dsa->pub_key);
buffer_get_bignum2(&e->input, k->dsa->priv_key);
break;
case KEY_RSA:
k = key_new_private(type);
buffer_get_bignum2(&e->input, k->rsa->n);
buffer_get_bignum2(&e->input, k->rsa->e);
buffer_get_bignum2(&e->input, k->rsa->d);
buffer_get_bignum2(&e->input, k->rsa->iqmp);
buffer_get_bignum2(&e->input, k->rsa->p);
buffer_get_bignum2(&e->input, k->rsa->q);
/* Generate additional parameters */
generate_additional_parameters(k->rsa);
break;
default:
buffer_clear(&e->input); buffer_clear(&e->input);
xfree(type);
goto send; goto send;
} }
xfree(type);
k = key_new(KEY_DSA);
/* allocate mem for private key */
k->dsa->priv_key = BN_new();
buffer_get_bignum2(&e->input, k->dsa->p);
buffer_get_bignum2(&e->input, k->dsa->q);
buffer_get_bignum2(&e->input, k->dsa->g);
buffer_get_bignum2(&e->input, k->dsa->pub_key);
buffer_get_bignum2(&e->input, k->dsa->priv_key);
break; break;
} }
comment = buffer_get_string(&e->input, NULL); comment = buffer_get_string(&e->input, NULL);
if (k == NULL) { if (k == NULL) {
xfree(comment); xfree(comment);
@ -451,12 +444,12 @@ process_add_identity(SocketEntry *e, int version)
void void
process_message(SocketEntry *e) process_message(SocketEntry *e)
{ {
unsigned int msg_len; u_int msg_len;
unsigned int type; u_int type;
unsigned char *cp; u_char *cp;
if (buffer_len(&e->input) < 5) if (buffer_len(&e->input) < 5)
return; /* Incomplete message. */ return; /* Incomplete message. */
cp = (unsigned char *) buffer_ptr(&e->input); cp = (u_char *) buffer_ptr(&e->input);
msg_len = GET_32BIT(cp); msg_len = GET_32BIT(cp);
if (msg_len > 256 * 1024) { if (msg_len > 256 * 1024) {
shutdown(e->fd, SHUT_RDWR); shutdown(e->fd, SHUT_RDWR);
@ -515,7 +508,7 @@ process_message(SocketEntry *e)
void void
new_socket(int type, int fd) new_socket(int type, int fd)
{ {
unsigned int i, old_alloc; u_int i, old_alloc;
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
error("fcntl O_NONBLOCK: %s", strerror(errno)); error("fcntl O_NONBLOCK: %s", strerror(errno));
@ -544,17 +537,17 @@ new_socket(int type, int fd)
buffer_init(&sockets[old_alloc].output); buffer_init(&sockets[old_alloc].output);
} }
void int
prepare_select(fd_set *readset, fd_set *writeset) prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
{ {
unsigned int i; u_int i, sz;
for (i = 0; i < sockets_alloc; i++) int n = 0;
for (i = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) { switch (sockets[i].type) {
case AUTH_SOCKET: case AUTH_SOCKET:
case AUTH_CONNECTION: case AUTH_CONNECTION:
FD_SET(sockets[i].fd, readset); n = MAX(n, sockets[i].fd);
if (buffer_len(&sockets[i].output) > 0)
FD_SET(sockets[i].fd, writeset);
break; break;
case AUTH_UNUSED: case AUTH_UNUSED:
break; break;
@ -562,12 +555,40 @@ prepare_select(fd_set *readset, fd_set *writeset)
fatal("Unknown socket type %d", sockets[i].type); fatal("Unknown socket type %d", sockets[i].type);
break; break;
} }
}
sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
if (*fdrp == NULL || n > *fdl) {
if (*fdrp)
xfree(*fdrp);
if (*fdwp)
xfree(*fdwp);
*fdrp = xmalloc(sz);
*fdwp = xmalloc(sz);
*fdl = n;
}
memset(*fdrp, 0, sz);
memset(*fdwp, 0, sz);
for (i = 0; i < sockets_alloc; i++) {
switch (sockets[i].type) {
case AUTH_SOCKET:
case AUTH_CONNECTION:
FD_SET(sockets[i].fd, *fdrp);
if (buffer_len(&sockets[i].output) > 0)
FD_SET(sockets[i].fd, *fdwp);
break;
default:
break;
}
}
return (1);
} }
void void
after_select(fd_set *readset, fd_set *writeset) after_select(fd_set *readset, fd_set *writeset)
{ {
unsigned int i; u_int i;
int len, sock; int len, sock;
socklen_t slen; socklen_t slen;
char buf[1024]; char buf[1024];
@ -580,7 +601,8 @@ after_select(fd_set *readset, fd_set *writeset)
case AUTH_SOCKET: case AUTH_SOCKET:
if (FD_ISSET(sockets[i].fd, readset)) { if (FD_ISSET(sockets[i].fd, readset)) {
slen = sizeof(sunaddr); slen = sizeof(sunaddr);
sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &slen); sock = accept(sockets[i].fd,
(struct sockaddr *) &sunaddr, &slen);
if (sock < 0) { if (sock < 0) {
perror("accept from AUTH_SOCKET"); perror("accept from AUTH_SOCKET");
break; break;
@ -591,8 +613,15 @@ after_select(fd_set *readset, fd_set *writeset)
case AUTH_CONNECTION: case AUTH_CONNECTION:
if (buffer_len(&sockets[i].output) > 0 && if (buffer_len(&sockets[i].output) > 0 &&
FD_ISSET(sockets[i].fd, writeset)) { FD_ISSET(sockets[i].fd, writeset)) {
len = write(sockets[i].fd, buffer_ptr(&sockets[i].output), do {
buffer_len(&sockets[i].output)); len = write(sockets[i].fd,
buffer_ptr(&sockets[i].output),
buffer_len(&sockets[i].output));
if (len == -1 && (errno == EAGAIN ||
errno == EINTR))
continue;
break;
} while (1);
if (len <= 0) { if (len <= 0) {
shutdown(sockets[i].fd, SHUT_RDWR); shutdown(sockets[i].fd, SHUT_RDWR);
close(sockets[i].fd); close(sockets[i].fd);
@ -604,7 +633,13 @@ after_select(fd_set *readset, fd_set *writeset)
buffer_consume(&sockets[i].output, len); buffer_consume(&sockets[i].output, len);
} }
if (FD_ISSET(sockets[i].fd, readset)) { if (FD_ISSET(sockets[i].fd, readset)) {
len = read(sockets[i].fd, buf, sizeof(buf)); do {
len = read(sockets[i].fd, buf, sizeof(buf));
if (len == -1 && (errno == EAGAIN ||
errno == EINTR))
continue;
break;
} while (1);
if (len <= 0) { if (len <= 0) {
shutdown(sockets[i].fd, SHUT_RDWR); shutdown(sockets[i].fd, SHUT_RDWR);
close(sockets[i].fd); close(sockets[i].fd);
@ -625,19 +660,24 @@ after_select(fd_set *readset, fd_set *writeset)
void void
check_parent_exists(int sig) check_parent_exists(int sig)
{ {
int save_errno = errno;
if (parent_pid != -1 && kill(parent_pid, 0) < 0) { if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
/* printf("Parent has died - Authentication agent exiting.\n"); */ /* printf("Parent has died - Authentication agent exiting.\n"); */
exit(1); exit(1);
} }
signal(SIGALRM, check_parent_exists); signal(SIGALRM, check_parent_exists);
alarm(10); alarm(10);
errno = save_errno;
} }
void void
cleanup_socket(void) cleanup_socket(void)
{ {
remove(socket_name); if (socket_name[0])
rmdir(socket_dir); unlink(socket_name);
if (socket_dir[0])
rmdir(socket_dir);
} }
void void
@ -648,30 +688,34 @@ cleanup_exit(int i)
} }
void void
usage() cleanup_handler(int sig)
{
cleanup_socket();
_exit(2);
}
void
usage(void)
{ {
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
__progname); __progname);
exit(1); exit(1);
} }
int int
main(int ac, char **av) main(int ac, char **av)
{ {
fd_set readset, writeset;
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
struct sockaddr_un sunaddr; struct sockaddr_un sunaddr;
struct rlimit rlim;
pid_t pid; pid_t pid;
char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
extern int optind;
fd_set *readsetp = NULL, *writesetp = NULL;
SSLeay_add_all_algorithms();
/* 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);
}
while ((ch = getopt(ac, av, "cks")) != -1) { while ((ch = getopt(ac, av, "cks")) != -1) {
switch (ch) { switch (ch) {
case 'c': case 'c':
@ -706,14 +750,13 @@ main(int ac, char **av)
pidstr = getenv(SSH_AGENTPID_ENV_NAME); pidstr = getenv(SSH_AGENTPID_ENV_NAME);
if (pidstr == NULL) { if (pidstr == NULL) {
fprintf(stderr, "%s not set, cannot kill agent\n", fprintf(stderr, "%s not set, cannot kill agent\n",
SSH_AGENTPID_ENV_NAME); SSH_AGENTPID_ENV_NAME);
exit(1); exit(1);
} }
pid = atoi(pidstr); pid = atoi(pidstr);
if (pid < 1) { /* XXX PID_MAX check too */ if (pid < 1) {
/* Yes, PID_MAX check please */
fprintf(stderr, "%s=\"%s\", which is not a good PID\n", fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
SSH_AGENTPID_ENV_NAME, pidstr); SSH_AGENTPID_ENV_NAME, pidstr);
exit(1); exit(1);
} }
if (kill(pid, SIGTERM) == -1) { if (kill(pid, SIGTERM) == -1) {
@ -735,7 +778,7 @@ main(int ac, char **av)
exit(1); exit(1);
} }
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
parent_pid); parent_pid);
/* /*
* Create socket early so it will exist before command gets run from * Create socket early so it will exist before command gets run from
@ -758,6 +801,7 @@ main(int ac, char **av)
perror("listen"); perror("listen");
cleanup_exit(1); cleanup_exit(1);
} }
/* /*
* Fork, and have the parent execute the command, if any, or present * Fork, and have the parent execute the command, if any, or present
* the socket data. The child continues as the authentication agent. * the socket data. The child continues as the authentication agent.
@ -773,9 +817,9 @@ main(int ac, char **av)
if (ac == 0) { if (ac == 0) {
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME); SSH_AUTHSOCKET_ENV_NAME);
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
SSH_AGENTPID_ENV_NAME); SSH_AGENTPID_ENV_NAME);
printf("echo Agent pid %d;\n", pid); printf("echo Agent pid %d;\n", pid);
exit(0); exit(0);
} }
@ -792,6 +836,12 @@ main(int ac, char **av)
close(1); close(1);
close(2); close(2);
/* deny core dumps, since memory contains unencrypted private keys */
rlim.rlim_cur = rlim.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
perror("setrlimit rlimit_core failed");
cleanup_exit(1);
}
if (setsid() == -1) { if (setsid() == -1) {
perror("setsid"); perror("setsid");
cleanup_exit(1); cleanup_exit(1);
@ -808,18 +858,16 @@ main(int ac, char **av)
idtab_init(); idtab_init();
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, cleanup_exit); signal(SIGHUP, cleanup_handler);
signal(SIGTERM, cleanup_exit); signal(SIGTERM, cleanup_handler);
while (1) { while (1) {
FD_ZERO(&readset); prepare_select(&readsetp, &writesetp, &max_fd);
FD_ZERO(&writeset); if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
prepare_select(&readset, &writeset);
if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
exit(1); exit(1);
} }
after_select(&readset, &writeset); after_select(readsetp, writesetp);
} }
/* NOTREACHED */ /* NOTREACHED */
} }

View File

@ -10,9 +10,9 @@
.\" incompatible with the protocol description in the RFC file, it must be .\" incompatible with the protocol description in the RFC file, it must be
.\" called by a name other than "ssh" or "Secure Shell". .\" called by a name other than "ssh" or "Secure Shell".
.\" .\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions .\" modification, are permitted provided that the following conditions
@ -34,6 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: ssh.1,v 1.107 2001/04/22 23:58:36 markus Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
@ -41,7 +42,7 @@
.Os .Os
.Sh NAME .Sh NAME
.Nm ssh .Nm ssh
.Nd OpenSSH secure shell client (remote login program) .Nd OpenSSH SSH client (remote login program)
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm ssh .Nm ssh
.Op Fl l Ar login_name .Op Fl l Ar login_name
@ -49,11 +50,12 @@
.Op Ar command .Op Ar command
.Pp .Pp
.Nm ssh .Nm ssh
.Op Fl afgknqtvxACNPTX246 .Op Fl afgknqstvxACNPTX1246
.Op Fl c Ar cipher_spec .Op Fl c Ar cipher_spec
.Op Fl e Ar escape_char .Op Fl e Ar escape_char
.Op Fl i Ar identity_file .Op Fl i Ar identity_file
.Op Fl l Ar login_name .Op Fl l Ar login_name
.Op Fl m Ar mac_spec
.Op Fl o Ar option .Op Fl o Ar option
.Op Fl p Ar port .Op Fl p Ar port
.Oo Fl L Xo .Oo Fl L Xo
@ -76,7 +78,7 @@
.Op Ar command .Op Ar command
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
(Secure Shell) is a program for logging into a remote machine and for (SSH client) is a program for logging into a remote machine and for
executing commands on a remote machine. executing commands on a remote machine.
It is intended to replace It is intended to replace
rlogin and rsh, and provide secure encrypted communications between rlogin and rsh, and provide secure encrypted communications between
@ -110,7 +112,7 @@ permitted to log in.
This form of authentication alone is normally not This form of authentication alone is normally not
allowed by the server because it is not secure. allowed by the server because it is not secure.
.Pp .Pp
The second (and primary) authentication method is the The second authentication method is the
.Pa rhosts .Pa rhosts
or or
.Pa hosts.equiv .Pa hosts.equiv
@ -205,15 +207,22 @@ the password cannot be seen by someone listening on the network.
.Ss SSH protocol version 2 .Ss SSH protocol version 2
.Pp .Pp
When a user connects using the protocol version 2 When a user connects using the protocol version 2
different authentication methods are available: different authentication methods are available.
At first, the client attempts to authenticate using the public key method. Using the default values for
If this method fails password authentication is tried. .Cm PreferredAuthentications ,
the client will try to authenticate first using the public key method;
if this method fails password authentication is attempted,
and finally if this method fails keyboard-interactive authentication
is attempted.
If this method fails password authentication is
tried.
.Pp .Pp
The public key method is similar to RSA authentication described The public key method is similar to RSA authentication described
in the previous section except that the DSA algorithm is used in the previous section and allows the RSA or DSA algorithm to be used:
instead of the patented RSA algorithm. The client uses his private key,
The client uses his private DSA key
.Pa $HOME/.ssh/id_dsa .Pa $HOME/.ssh/id_dsa
or
.Pa $HOME/.ssh/id_rsa ,
to sign the session identifier and sends the result to the server. to sign the session identifier and sends the result to the server.
The server checks whether the matching public key is listed in The server checks whether the matching public key is listed in
.Pa $HOME/.ssh/authorized_keys2 .Pa $HOME/.ssh/authorized_keys2
@ -223,12 +232,14 @@ and is only known to the client and the server.
.Pp .Pp
If public key authentication fails or is not available a password If public key authentication fails or is not available a password
can be sent encrypted to the remote host for proving the user's identity. can be sent encrypted to the remote host for proving the user's identity.
This protocol 2 implementation does not yet support Kerberos or .Pp
OPIE authentication. Additionally,
.Nm
supports hostbased or challenge response authentication.
.Pp .Pp
Protocol 2 provides additional mechanisms for confidentiality Protocol 2 provides additional mechanisms for confidentiality
(the traffic is encrypted using 3DES, Blowfish, CAST128 or Arcfour) (the traffic is encrypted using 3DES, Blowfish, CAST128 or Arcfour)
and integrity (hmac-sha1, hmac-md5). and integrity (hmac-md5, hmac-sha1).
Note that protocol 1 lacks a strong mechanism for ensuring the Note that protocol 1 lacks a strong mechanism for ensuring the
integrity of the connection. integrity of the connection.
.Pp .Pp
@ -241,30 +252,7 @@ All communication with
the remote command or shell will be automatically encrypted. the remote command or shell will be automatically encrypted.
.Pp .Pp
If a pseudo-terminal has been allocated (normal login session), the If a pseudo-terminal has been allocated (normal login session), the
user can disconnect with user may use the escape characters noted below.
.Ic ~. ,
and suspend
.Nm
with
.Ic ~^Z .
All forwarded connections can be listed with
.Ic ~#
and if
the session blocks waiting for forwarded X11 or TCP/IP
connections to terminate, it can be backgrounded with
.Ic ~&
(this should not be used while the user shell is active, as it can cause the
shell to hang).
All available escapes can be listed with
.Ic ~? .
.Pp
A single tilde character can be sent as
.Ic ~~
(or by following the tilde by a character other than those described above).
The escape character must always follow a newline to be interpreted as
special.
The escape character can be changed in configuration files
or on the command line.
.Pp .Pp
If no pseudo tty has been allocated, the If no pseudo tty has been allocated, the
session is transparent and can be used to reliably transfer binary session is transparent and can be used to reliably transfer binary
@ -273,12 +261,48 @@ On most systems, setting the escape character to
.Dq none .Dq none
will also make the session transparent even if a tty is used. will also make the session transparent even if a tty is used.
.Pp .Pp
The session terminates when the command or shell in on the remote The session terminates when the command or shell on the remote
machine exists and all X11 and TCP/IP connections have been closed. machine exits and all X11 and TCP/IP connections have been closed.
The exit status of the remote program is returned as the exit status The exit status of the remote program is returned as the exit status
of of
.Nm ssh . .Nm ssh .
.Pp .Pp
.Ss Escape Characters
.Pp
When a pseudo terminal has been requested, ssh supports a number of functions
through the use of an escape character.
.Pp
A single tilde character can be sent as
.Ic ~~
(or by following the tilde by a character other than those described above).
The escape character must always follow a newline to be interpreted as
special.
The escape character can be changed in configuration files using the
.Cm EscapeChar
configuration directive or on the command line by the
.Fl e
option.
.Pp
The supported escapes (assuming the default
.Ql ~ )
are:
.Bl -tag -width Ds
.It Cm ~.
Disconnect
.It Cm ~^Z
Background ssh
.It Cm ~#
List forwarded connections
.It Cm ~&
Background ssh at logout when waiting for forwarded connection / X11 sessions
to terminate (protocol version 1 only)
.It Cm ~?
Display a list of escape characters
.It Cm ~R
Request rekeying of the connection (only useful for SSH protocol version 2
and if the peer supports it)
.El
.Pp
.Ss X11 and TCP forwarding .Ss X11 and TCP forwarding
.Pp .Pp
If the user is using X11 (the If the user is using X11 (the
@ -323,7 +347,7 @@ command line or in a configuration file.
Forwarding of arbitrary TCP/IP connections over the secure channel can Forwarding of arbitrary TCP/IP connections over the secure channel can
be specified either on command line or in a configuration file. be specified either on command line or in a configuration file.
One possible application of TCP/IP forwarding is a secure connection to an One possible application of TCP/IP forwarding is a secure connection to an
electronic purse; another is going trough firewalls. electronic purse; another is going through firewalls.
.Pp .Pp
.Ss Server authentication .Ss Server authentication
.Pp .Pp
@ -333,7 +357,7 @@ identifications for all hosts it has ever been used with.
RSA host keys are stored in RSA host keys are stored in
.Pa $HOME/.ssh/known_hosts .Pa $HOME/.ssh/known_hosts
and and
DSA host keys are stored in host keys used in the protocol version 2 are stored in
.Pa $HOME/.ssh/known_hosts2 .Pa $HOME/.ssh/known_hosts2
in the user's home directory. in the user's home directory.
Additionally, the files Additionally, the files
@ -354,7 +378,8 @@ The
.Cm StrictHostKeyChecking .Cm StrictHostKeyChecking
option (see below) can be used to prevent logins to machines whose option (see below) can be used to prevent logins to machines whose
host key is not known or has changed. host key is not known or has changed.
.Sh OPTIONS .Pp
The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl a .It Fl a
Disables forwarding of the authentication agent connection. Disables forwarding of the authentication agent connection.
@ -375,11 +400,12 @@ cipher which is no longer fully supported in
.Ar blowfish .Ar blowfish
is a fast block cipher, it appears very secure and is much faster than is a fast block cipher, it appears very secure and is much faster than
.Ar 3des . .Ar 3des .
.It Fl c Ar "3des-cbc,blowfish-cbc,arcfour,cast128-cbc" .It Fl c Ar cipher_spec
Additionally, for protocol version 2 a comma-separated list of ciphers can Additionally, for protocol version 2 a comma-separated list of ciphers can
be specified in order of preference. be specified in order of preference.
Protocol version 2 supports 3DES, Blowfish, and CAST128 in CBC mode See
and Arcfour. .Cm Ciphers
for more information.
.It Fl e Ar ch|^ch|none .It Fl e Ar ch|^ch|none
Sets the escape character for sessions with a pty (default: Sets the escape character for sessions with a pty (default:
.Ql ~ ) . .Ql ~ ) .
@ -409,7 +435,7 @@ something like
Allows remote hosts to connect to local forwarded ports. Allows remote hosts to connect to local forwarded ports.
.It Fl i Ar identity_file .It Fl i Ar identity_file
Selects the file from which the identity (private key) for Selects the file from which the identity (private key) for
RSA authentication is read. RSA or DSA authentication is read.
Default is Default is
.Pa $HOME/.ssh/identity .Pa $HOME/.ssh/identity
in the user's home directory. in the user's home directory.
@ -425,6 +451,13 @@ This may also be specified on a per-host basis in the configuration file.
.It Fl l Ar login_name .It Fl l Ar login_name
Specifies the user to log in as on the remote machine. Specifies the user to log in as on the remote machine.
This also may be specified on a per-host basis in the configuration file. This also may be specified on a per-host basis in the configuration file.
.It Fl m Ar mac_spec
Additionally, for protocol version 2 a comma-separated list of MAC
(message authentication code) algorithms can
be specified in order of preference.
See the
.Cm MACs
keyword for more information.
.It Fl n .It Fl n
Redirects stdin from Redirects stdin from
.Pa /dev/null .Pa /dev/null
@ -447,7 +480,7 @@ needs to ask for a password or passphrase; see also the
option.) option.)
.It Fl N .It Fl N
Do not execute a remote command. Do not execute a remote command.
This is usefull if you just want to forward ports This is useful if you just want to forward ports
(protocol version 2 only). (protocol version 2 only).
.It Fl o Ar option .It Fl o Ar option
Can be used to give options in the format used in the config file. Can be used to give options in the format used in the config file.
@ -465,18 +498,28 @@ not permit connections from privileged ports.
Note that this option turns off Note that this option turns off
.Cm RhostsAuthentication .Cm RhostsAuthentication
and and
.Cm RhostsRSAAuthentication . .Cm RhostsRSAAuthentication
for older servers.
.It Fl q .It Fl q
Quiet mode. Quiet mode.
Causes all warning and diagnostic messages to be suppressed. Causes all warning and diagnostic messages to be suppressed.
Only fatal errors are displayed. Only fatal errors are displayed.
.It Fl s
May be used to request invocation of a subsystem on the remote system. Subsystems are a feature of the SSH2 protocol which facilitate the use
of SSH as a secure transport for other application (eg. sftp). The
subsystem is specified as the remote command.
.It Fl t .It Fl t
Force pseudo-tty allocation. Force pseudo-tty allocation.
This can be used to execute arbitrary This can be used to execute arbitrary
screen-based programs on a remote machine, which can be very useful, screen-based programs on a remote machine, which can be very useful,
e.g., when implementing menu services. e.g., when implementing menu services.
Multiple
.Fl t
options force tty allocation, even if
.Nm
has no local tty.
.It Fl T .It Fl T
Disable pseudo-tty allocation (protocol version 2 only). Disable pseudo-tty allocation.
.It Fl v .It Fl v
Verbose mode. Verbose mode.
Causes Causes
@ -484,10 +527,9 @@ Causes
to print debugging messages about its progress. to print debugging messages about its progress.
This is helpful in This is helpful in
debugging connection, authentication, and configuration problems. debugging connection, authentication, and configuration problems.
The verbose mode is also used to display Multiple
.Xr skey 1 .Fl v
challenges, if the user entered "s/key" as password. options increases the verbosity.
Multiple -v options increases the verbosity.
Maximum is 3. Maximum is 3.
.It Fl x .It Fl x
Disables X11 forwarding. Disables X11 forwarding.
@ -541,6 +583,12 @@ from the local machine.
Port forwardings can also be specified in the configuration file. Port forwardings can also be specified in the configuration file.
Privileged ports can be forwarded only when Privileged ports can be forwarded only when
logging in as root on the remote machine. logging in as root on the remote machine.
IPv6 addresses can be specified with an alternative syntax:
.Ar port/host/hostport
.It Fl 1
Forces
.Nm
to try protocol version 1 only.
.It Fl 2 .It Fl 2
Forces Forces
.Nm .Nm
@ -609,6 +657,7 @@ The argument to this keyword must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
This option applies to protocol version 1 only.
.It Cm BatchMode .It Cm BatchMode
If set to If set to
.Dq yes , .Dq yes ,
@ -619,16 +668,20 @@ The argument must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
The default is
.Dq no .
.It Cm CheckHostIP .It Cm CheckHostIP
If this flag is set to If this flag is set to
.Dq yes , .Dq yes ,
ssh will additionally check the host ip address in the ssh will additionally check the host IP address in the
.Pa known_hosts .Pa known_hosts
file. file.
This allows ssh to detect if a host key changed due to DNS spoofing. This allows ssh to detect if a host key changed due to DNS spoofing.
If the option is set to If the option is set to
.Dq no , .Dq no ,
the check will not be executed. the check will not be executed.
The default is
.Dq yes .
.It Cm Cipher .It Cm Cipher
Specifies the cipher to use for encrypting the session Specifies the cipher to use for encrypting the session
in protocol version 1. in protocol version 1.
@ -644,33 +697,32 @@ Specifies the ciphers allowed for protocol version 2
in order of preference. in order of preference.
Multiple ciphers must be comma-separated. Multiple ciphers must be comma-separated.
The default is The default is
.Dq 3des-cbc,blowfish-cbc,cast128-cbc,arcfour . .Pp
.Bd -literal
``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
aes192-cbc,aes256-cbc''
.Ed
.It Cm Compression .It Cm Compression
Specifies whether to use compression. Specifies whether to use compression.
The argument must be The argument must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
The default is
.Dq no .
.It Cm CompressionLevel .It Cm CompressionLevel
Specifies the compression level to use if compression is enable. Specifies the compression level to use if compression is enabled.
The argument must be an integer from 1 (fast) to 9 (slow, best). The argument must be an integer from 1 (fast) to 9 (slow, best).
The default level is 6, which is good for most applications. The default level is 6, which is good for most applications.
The meaning of the values is the same as in The meaning of the values is the same as in
.Xr gzip 1 . .Xr gzip 1 .
Note that this option applies to protocol version 1 only.
.It Cm ConnectionAttempts .It Cm ConnectionAttempts
Specifies the number of tries (one per second) to make before falling Specifies the number of tries (one per second) to make before falling
back to rsh or exiting. back to rsh or exiting.
The argument must be an integer. The argument must be an integer.
This may be useful in scripts if the connection sometimes fails. This may be useful in scripts if the connection sometimes fails.
.It Cm DSAAuthentication The default is 4.
Specifies whether to try DSA authentication.
The argument to this keyword must be
.Dq yes
or
.Dq no .
DSA authentication will only be
attempted if a DSA identity file exists.
Note that this option applies to protocol version 2 only.
.It Cm EscapeChar .It Cm EscapeChar
Sets the escape character (default: Sets the escape character (default:
.Ql ~ ) . .Ql ~ ) .
@ -696,6 +748,8 @@ The argument must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
The default is
.Dq no .
.It Cm ForwardAgent .It Cm ForwardAgent
Specifies whether the connection to the authentication agent (if any) Specifies whether the connection to the authentication agent (if any)
will be forwarded to the remote machine. will be forwarded to the remote machine.
@ -726,8 +780,37 @@ or
The default is The default is
.Dq no . .Dq no .
.It Cm GlobalKnownHostsFile .It Cm GlobalKnownHostsFile
Specifies a file to use instead of Specifies a file to use for the protocol version 1 global
host key database instead of
.Pa /etc/ssh/ssh_known_hosts . .Pa /etc/ssh/ssh_known_hosts .
.It Cm GlobalKnownHostsFile2
Specifies a file to use for the protocol version 2 global
host key database instead of
.Pa /etc/ssh/ssh_known_hosts2 .
.It Cm HostbasedAuthentication
Specifies whether to try rhosts based authentication with public key
authentication.
The argument must be
.Dq yes
or
.Dq no .
The default is
.Dq yes .
This option applies to protocol version 2 only and
is similar to
.Cm RhostsRSAAuthentication .
.It Cm HostKeyAlgorithms
Specfies the protocol version 2 host key algorithms
that the client wants to use in order of preference.
The default for this option is:
.Dq ssh-rsa,ssh-dss
.It Cm HostKeyAlias
Specifies an alias that should be used instead of the
real host name when looking up or saving the host key
in the host key database files.
This option is useful for tunneling ssh connections
or if you have multiple servers running on a single host.
>>>>>>> 1.1.1.7
.It Cm HostName .It Cm HostName
Specifies the real host name to log into. Specifies the real host name to log into.
This can be used to specify nicknames or abbreviations for hosts. This can be used to specify nicknames or abbreviations for hosts.
@ -736,7 +819,7 @@ Numeric IP addresses are also permitted (both on the command line and in
.Cm HostName .Cm HostName
specifications). specifications).
.It Cm IdentityFile .It Cm IdentityFile
Specifies the file from which the user's RSA authentication identity Specifies the file from which the user's RSA or DSA authentication identity
is read (default is read (default
.Pa $HOME/.ssh/identity .Pa $HOME/.ssh/identity
in the user's home directory). in the user's home directory).
@ -747,16 +830,6 @@ syntax to refer to a user's home directory.
It is possible to have It is possible to have
multiple identity files specified in configuration files; all these multiple identity files specified in configuration files; all these
identities will be tried in sequence. identities will be tried in sequence.
.It Cm IdentityFile2
Specifies the file from which the user's DSA authentication identity
is read (default
.Pa $HOME/.ssh/id_dsa
in the user's home directory).
The file name may use the tilde
syntax to refer to a user's home directory.
It is possible to have
multiple identity files specified in configuration files; all these
identities will be tried in sequence.
.It Cm KeepAlive .It Cm KeepAlive
Specifies whether the system should send keepalive messages to the Specifies whether the system should send keepalive messages to the
other side. other side.
@ -802,6 +875,18 @@ Gives the verbosity level that is used when logging messages from
The possible values are: The possible values are:
QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG. QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
The default is INFO. The default is INFO.
.It Cm MACs
Specifies the MAC (message authentication code) algorithms
in order of preference.
The MAC algorithm is used in protocol version 2
for data integrity protection.
Multiple algorithms must be comma-separated.
The default is
.Pp
.Bd -literal
``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-ripemd160@openssh.com,
hmac-sha1-96,hmac-md5-96''
.Ed
.It Cm NumberOfPasswordPrompts .It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up. Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer. The argument to this keyword must be an integer.
@ -812,10 +897,19 @@ The argument to this keyword must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
Note that this option applies to both protocol version 1 and 2. The default is
.Dq yes .
.It Cm Port .It Cm Port
Specifies the port number to connect on the remote host. Specifies the port number to connect on the remote host.
Default is 22. Default is 22.
.It Cm PreferredAuthentications
Specifies the order in which the client should try protocol 2
authentication methods. This allows a client to prefer one method (e.g.
.Cm keyboard-interactive )
over another method (e.g.
.Cm password )
The default for this option is:
.Dq publickey, password, keyboard-interactive
.It Cm Protocol .It Cm Protocol
Specifies the protocol versions Specifies the protocol versions
.Nm .Nm
@ -826,11 +920,11 @@ and
.Dq 2 . .Dq 2 .
Multiple versions must be comma-separated. Multiple versions must be comma-separated.
The default is The default is
.Dq 1,2 . .Dq 2,1 .
This means that This means that
.Nm .Nm
tries version 1 and falls back to version 2 tries version 2 and falls back to version 1
if version 1 is not available. if version 2 is not available.
.It Cm ProxyCommand .It Cm ProxyCommand
Specifies the command to use to connect to the server. Specifies the command to use to connect to the server.
The command The command
@ -856,6 +950,15 @@ Note that
.Cm CheckHostIP .Cm CheckHostIP
is not available for connects with a proxy command. is not available for connects with a proxy command.
.Pp .Pp
.It Cm PubkeyAuthentication
Specifies whether to try public key authentication.
The argument to this keyword must be
.Dq yes
or
.Dq no .
The default is
.Dq yes .
This option applies to protocol version 2 only.
.It Cm RemoteForward .It Cm RemoteForward
Specifies that a TCP/IP port on the remote machine be forwarded over Specifies that a TCP/IP port on the remote machine be forwarded over
the secure channel to given host:port from the local machine. the secure channel to given host:port from the local machine.
@ -873,19 +976,25 @@ Disabling rhosts authentication may reduce
authentication time on slow connections when rhosts authentication is authentication time on slow connections when rhosts authentication is
not used. not used.
Most servers do not permit RhostsAuthentication because it Most servers do not permit RhostsAuthentication because it
is not secure (see RhostsRSAAuthentication). is not secure (see
.Cm RhostsRSAAuthentication ).
The argument to this keyword must be The argument to this keyword must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
The default is
.Dq yes .
This option applies to protocol version 1 only.
.It Cm RhostsRSAAuthentication .It Cm RhostsRSAAuthentication
Specifies whether to try rhosts based authentication with RSA host Specifies whether to try rhosts based authentication with RSA host
authentication. authentication.
This is the primary authentication method for most sites.
The argument must be The argument must be
.Dq yes .Dq yes
or or
.Dq no . .Dq no .
The default is
.Dq yes .
This option applies to protocol version 1 only.
.It Cm RSAAuthentication .It Cm RSAAuthentication
Specifies whether to try RSA authentication. Specifies whether to try RSA authentication.
The argument to this keyword must be The argument to this keyword must be
@ -895,9 +1004,12 @@ or
RSA authentication will only be RSA authentication will only be
attempted if the identity file exists, or an authentication agent is attempted if the identity file exists, or an authentication agent is
running. running.
The default is
.Dq yes .
Note that this option applies to protocol version 1 only. Note that this option applies to protocol version 1 only.
.It Cm SkeyAuthentication .It Cm ChallengeResponseAuthentication
Specifies whether to use Specifies whether to use challenge response authentication.
Currently there is only support for
.Xr skey 1 .Xr skey 1
authentication. authentication.
The argument to this keyword must be The argument to this keyword must be
@ -914,24 +1026,37 @@ will never automatically add host keys to the
.Pa $HOME/.ssh/known_hosts .Pa $HOME/.ssh/known_hosts
and and
.Pa $HOME/.ssh/known_hosts2 .Pa $HOME/.ssh/known_hosts2
files, and refuses to connect hosts whose host key has changed. files, and refuses to connect to hosts whose host key has changed.
This provides maximum protection against trojan horse attacks. This provides maximum protection against trojan horse attacks.
However, it can be somewhat annoying if you don't have good However, it can be somewhat annoying if you don't have good
.Pa /etc/ssh/ssh_known_hosts .Pa /etc/ssh/ssh_known_hosts
and and
.Pa /etc/ssh/ssh_known_hosts2 .Pa /etc/ssh/ssh_known_hosts2
files installed and frequently files installed and frequently
connect new hosts. connect to new hosts.
Basically this option forces the user to manually This option forces the user to manually
add any new hosts. add all new hosts.
Normally this option is disabled, and new hosts If this flag is set to
will automatically be added to the known host files. .Dq no ,
.Nm
will automatically add new host keys to the
user known hosts files.
If this flag is set to
.Dq ask ,
new host keys
will be added to the user known host files only after the user
has confirmed that is what they really want to do, and
.Nm
will refuse to connect to hosts whose host key has changed.
The host keys of The host keys of
known hosts will be verified automatically in either case. known hosts will be verified automatically in all cases.
The argument must be The argument must be
.Dq yes .Dq yes ,
.Dq no
or or
.Dq no . .Dq ask .
The default is
.Dq ask .
.It Cm UsePrivilegedPort .It Cm UsePrivilegedPort
Specifies whether to use a privileged port for outgoing connections. Specifies whether to use a privileged port for outgoing connections.
The argument must be The argument must be
@ -939,21 +1064,27 @@ The argument must be
or or
.Dq no . .Dq no .
The default is The default is
.Dq yes . .Dq no .
Note that setting this option to Note that you need to set this option to
.Dq no .Dq yes
turns off if you want to use
.Cm RhostsAuthentication .Cm RhostsAuthentication
and and
.Cm RhostsRSAAuthentication . .Cm RhostsRSAAuthentication
with older servers.
.It Cm User .It Cm User
Specifies the user to log in as. Specifies the user to log in as.
This can be useful if you have a different user name on different machines. This can be useful if you have a different user name on different machines.
This saves the trouble of This saves the trouble of
having to remember to give the user name on the command line. having to remember to give the user name on the command line.
.It Cm UserKnownHostsFile .It Cm UserKnownHostsFile
Specifies a file to use instead of Specifies a file to use for the protocol version 1 user
host key database instead of
.Pa $HOME/.ssh/known_hosts . .Pa $HOME/.ssh/known_hosts .
.It Cm UserKnownHostsFile2
Specifies a file to use for the protocol version 2 user
host key database instead of
.Pa $HOME/.ssh/known_hosts2 .
.It Cm UseRsh .It Cm UseRsh
Specifies that rlogin/rsh should be used for this host. Specifies that rlogin/rsh should be used for this host.
It is possible that the host does not at all support the It is possible that the host does not at all support the
@ -994,7 +1125,9 @@ the host where the shell runs, and n is an integer \*(>= 1.
.Nm .Nm
uses this special value to forward X11 connections over the secure uses this special value to forward X11 connections over the secure
channel. channel.
The user should normally not set DISPLAY explicitly, as that The user should normally not set
.Ev DISPLAY
explicitly, as that
will render the X11 connection insecure (and will require the user to will render the X11 connection insecure (and will require the user to
manually copy any required authorization cookies). manually copy any required authorization cookies).
.It Ev HOME .It Ev HOME
@ -1018,6 +1151,10 @@ Identifies the client end of the connection.
The variable contains The variable contains
three space-separated values: client ip-address, client port number, three space-separated values: client ip-address, client port number,
and server port number. and server port number.
.It Ev SSH_ORIGINAL_COMMAND
The variable contains the original command line if a forced command
is executed.
It can be used to extract the original arguments.
.It Ev SSH_TTY .It Ev SSH_TTY
This is set to the name of the tty (path to the device) associated This is set to the name of the tty (path to the device) associated
with the current shell or command. with the current shell or command.
@ -1040,14 +1177,18 @@ and adds lines of the format
to the environment. to the environment.
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds
.It Pa $HOME/.ssh/known_hosts .It Pa $HOME/.ssh/known_hosts, $HOME/.ssh/known_hosts2
Records host keys for all hosts the user has logged into (that are not Records host keys for all hosts the user has logged into (that are not
in in
.Pa /etc/ssh/ssh_known_hosts ) . .Pa /etc/ssh/ssh_known_hosts
for protocol version 1 or
.Pa /etc/ssh/ssh_known_hosts2
for protocol version 2).
See See
.Xr sshd 8 . .Xr sshd 8 .
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa .It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa, $HOME/.ssh/id_rsa
Contains the RSA and the DSA authentication identity of the user. Contains the authentication identity of the user.
They are for protocol 1 RSA, protocol 2 DSA, and protocol 2 RSA, respectively.
These files These files
contain sensitive data and should be readable by the user but not contain sensitive data and should be readable by the user but not
accessible by others (read/write/execute). accessible by others (read/write/execute).
@ -1057,7 +1198,7 @@ ignores a private key file if it is accessible by others.
It is possible to specify a passphrase when It is possible to specify a passphrase when
generating the key; the passphrase will be used to encrypt the generating the key; the passphrase will be used to encrypt the
sensitive part of this file using 3DES. sensitive part of this file using 3DES.
.It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub .It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub, $HOME/.ssh/id_rsa.pub
Contains the public key for authentication (public part of the Contains the public key for authentication (public part of the
identity file in human-readable form). identity file in human-readable form).
The contents of the The contents of the
@ -1065,13 +1206,15 @@ The contents of the
file should be added to file should be added to
.Pa $HOME/.ssh/authorized_keys .Pa $HOME/.ssh/authorized_keys
on all machines on all machines
where you wish to log in using RSA authentication. where you wish to log in using protocol version 1 RSA authentication.
The contents of the The contents of the
.Pa $HOME/.ssh/id_dsa.pub .Pa $HOME/.ssh/id_dsa.pub
and
.Pa $HOME/.ssh/id_rsa.pub
file should be added to file should be added to
.Pa $HOME/.ssh/authorized_keys2 .Pa $HOME/.ssh/authorized_keys2
on all machines on all machines
where you wish to log in using DSA authentication. where you wish to log in using protocol version 2 DSA/RSA authentication.
These files are not These files are not
sensitive and can (but need not) be readable by anyone. sensitive and can (but need not) be readable by anyone.
These files are These files are
@ -1098,15 +1241,15 @@ spaces).
This file is not highly sensitive, but the recommended This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others. permissions are read/write for the user, and not accessible by others.
.It Pa $HOME/.ssh/authorized_keys2 .It Pa $HOME/.ssh/authorized_keys2
Lists the DSA keys that can be used for logging in as this user. Lists the public keys (RSA/DSA) that can be used for logging in as this user.
This file is not highly sensitive, but the recommended This file is not highly sensitive, but the recommended
permissions are read/write for the user, and not accessible by others. permissions are read/write for the user, and not accessible by others.
.It Pa /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2 .It Pa /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2
Systemwide list of known host keys. Systemwide list of known host keys.
.Pa /etc/ssh_known_hosts .Pa /etc/ssh/ssh_known_hosts
contains RSA and contains RSA and
.Pa /etc/ssh_known_hosts2 .Pa /etc/ssh/ssh_known_hosts2
contains DSA keys. contains RSA or DSA keys for protocol version 2.
These files should be prepared by the These files should be prepared by the
system administrator to contain the public host keys of all machines in the system administrator to contain the public host keys of all machines in the
organization. organization.
@ -1145,7 +1288,7 @@ also used by rlogin and rsh, which makes using this file insecure.)
Each line of the file contains a host name (in the canonical form Each line of the file contains a host name (in the canonical form
returned by name servers), and then a user name on that host, returned by name servers), and then a user name on that host,
separated by a space. separated by a space.
One some machines this file may need to be On some machines this file may need to be
world-readable if the user's home directory is on a NFS partition, world-readable if the user's home directory is on a NFS partition,
because because
.Xr sshd 8 .Xr sshd 8
@ -1218,49 +1361,34 @@ manual page for more information.
Contains additional definitions for environment variables, see section Contains additional definitions for environment variables, see section
.Sx ENVIRONMENT .Sx ENVIRONMENT
above. above.
.It Pa libcrypto.so.X.1
A version of this library which includes support for the RSA algorithm
is required for proper operation.
.El .El
.Sh AUTHOR .Sh AUTHORS
OpenSSH OpenSSH is a derivative of the original and free
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, ssh 1.2.12 release by Tatu Ylonen.
but with bugs removed and newer features re-added. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
Rapidly after the Theo de Raadt and Dug Song
1.2.12 release, newer versions of the original ssh bore successively removed many bugs, re-added newer features and
more restrictive licenses, and thus demand for a free version was born. created OpenSSH.
.Pp Markus Friedl contributed the support for SSH
This version of OpenSSH protocol versions 1.5 and 2.0.
.Bl -bullet
.It
has all components of a restrictive nature (i.e., patents, see
.Xr ssl 8 )
directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support SSH protocol 1.5 and 2, making it compatible with
all other SSH clients and servers.
.It
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
supports one-time password authentication with
.Xr skey 1 .
.El
.Pp
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
Niels Provos, Theo de Raadt, and Dug Song.
.Pp
The support for SSH protocol 2 was written by Markus Friedl.
.Sh SEE ALSO .Sh SEE ALSO
.Xr rlogin 1 , .Xr rlogin 1 ,
.Xr rsh 1 , .Xr rsh 1 ,
.Xr scp 1 , .Xr scp 1 ,
.Xr sftp 1 ,
.Xr ssh-add 1 , .Xr ssh-add 1 ,
.Xr ssh-agent 1 , .Xr ssh-agent 1 ,
.Xr ssh-keygen 1 , .Xr ssh-keygen 1 ,
.Xr telnet 1 , .Xr telnet 1 ,
.Xr sshd 8 , .Xr sshd 8
.Xr ssl 8 .Rs
.%A T. Ylonen
.%A T. Kivinen
.%A M. Saarinen
.%A T. Rinne
.%A S. Lehtinen
.%T "SSH Protocol Architecture"
.%N draft-ietf-secsh-architecture-07.txt
.%D January 2001
.%O work in progress material
.Re

View File

@ -39,26 +39,36 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: ssh.c,v 1.69 2000/10/27 07:32:19 markus Exp $"); RCSID("$OpenBSD: ssh.c,v 1.116 2001/04/17 12:55:04 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/dsa.h> #include <openssl/err.h>
#include <openssl/rsa.h>
#include "xmalloc.h"
#include "ssh.h" #include "ssh.h"
#include "packet.h" #include "ssh1.h"
#include "buffer.h"
#include "readconf.h"
#include "uidswap.h"
#include "ssh2.h" #include "ssh2.h"
#include "compat.h" #include "compat.h"
#include "cipher.h"
#include "xmalloc.h"
#include "packet.h"
#include "buffer.h"
#include "uidswap.h"
#include "channels.h" #include "channels.h"
#include "key.h" #include "key.h"
#include "authfd.h" #include "authfd.h"
#include "authfile.h" #include "authfile.h"
#include "pathnames.h"
#include "clientloop.h"
#include "log.h"
#include "readconf.h"
#include "sshconnect.h"
#include "tildexpand.h"
#include "dispatch.h"
#include "misc.h"
#include "kex.h"
#include "mac.h"
#include "sshtty.h"
extern char *__progname; extern char *__progname;
@ -71,10 +81,11 @@ int debug_flag = 0;
/* Flag indicating whether a tty should be allocated */ /* Flag indicating whether a tty should be allocated */
int tty_flag = 0; int tty_flag = 0;
int no_tty_flag = 0;
int force_tty_flag = 0;
/* don't exec a shell */ /* don't exec a shell */
int no_shell_flag = 0; int no_shell_flag = 0;
int no_tty_flag = 0;
/* /*
* Flag indicating that nothing should be read from stdin. This can be set * Flag indicating that nothing should be read from stdin. This can be set
@ -113,14 +124,11 @@ struct sockaddr_storage hostaddr;
*/ */
volatile int received_window_change_signal = 0; volatile int received_window_change_signal = 0;
/* Value of argv[0] (set in the main program). */ /* Private host keys. */
char *av0; struct {
Key **keys;
/* Flag indicating whether we have a valid host private key loaded. */ int nkeys;
int host_private_key_loaded = 0; } sensitive_data;
/* Host private key. */
RSA *host_private_key = NULL;
/* Original real UID. */ /* Original real UID. */
uid_t original_real_uid; uid_t original_real_uid;
@ -128,23 +136,27 @@ uid_t original_real_uid;
/* command to be executed */ /* command to be executed */
Buffer command; Buffer command;
/* Should we execute a command or invoke a subsystem? */
int subsystem_flag = 0;
/* Prints a help message to the user. This function never returns. */ /* Prints a help message to the user. This function never returns. */
void void
usage() usage(void)
{ {
fprintf(stderr, "Usage: %s [options] host [command]\n", av0); fprintf(stderr, "Usage: %s [options] host [command]\n", __progname);
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, " -l user Log in using this user name.\n"); fprintf(stderr, " -l user Log in using this user name.\n");
fprintf(stderr, " -n Redirect input from /dev/null.\n"); fprintf(stderr, " -n Redirect input from " _PATH_DEVNULL ".\n");
fprintf(stderr, " -A Enable authentication agent forwarding.\n"); fprintf(stderr, " -A Enable authentication agent forwarding.\n");
fprintf(stderr, " -a Disable authentication agent forwarding.\n"); fprintf(stderr, " -a Disable authentication agent forwarding.\n");
#ifdef AFS #ifdef AFS
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n"); fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
#endif /* AFS */ #endif /* AFS */
fprintf(stderr, " -X Enable X11 connection forwarding.\n"); fprintf(stderr, " -X Enable X11 connection forwarding.\n");
fprintf(stderr, " -x Disable X11 connection forwarding.\n"); fprintf(stderr, " -x Disable X11 connection forwarding.\n");
fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n"); fprintf(stderr, " -i file Identity for public key authentication "
"(default: ~/.ssh/identity)\n");
fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n"); fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n");
fprintf(stderr, " -T Do not allocate a tty.\n"); fprintf(stderr, " -T Do not allocate a tty.\n");
fprintf(stderr, " -v Verbose; display verbose debugging messages.\n"); fprintf(stderr, " -v Verbose; display verbose debugging messages.\n");
@ -156,20 +168,22 @@ usage()
fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n"); fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n");
fprintf(stderr, " -c cipher Select encryption algorithm: " fprintf(stderr, " -c cipher Select encryption algorithm: "
"``3des'', " "``3des'', ``blowfish''\n");
"``blowfish''\n"); fprintf(stderr, " -m macs Specify MAC algorithms for protocol version 2.\n");
fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n"); fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n");
fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n"); fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n");
fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n"); fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n");
fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0); fprintf(stderr, " These cause %s to listen for connections on a port, and\n", __progname);
fprintf(stderr, " forward them to the other side by connecting to host:port.\n"); fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
fprintf(stderr, " -C Enable compression.\n"); fprintf(stderr, " -C Enable compression.\n");
fprintf(stderr, " -N Do not execute a shell or command.\n"); fprintf(stderr, " -N Do not execute a shell or command.\n");
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n"); fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
fprintf(stderr, " -1 Force protocol version 1.\n");
fprintf(stderr, " -2 Force protocol version 2.\n");
fprintf(stderr, " -4 Use IPv4 only.\n"); fprintf(stderr, " -4 Use IPv4 only.\n");
fprintf(stderr, " -6 Use IPv6 only.\n"); fprintf(stderr, " -6 Use IPv6 only.\n");
fprintf(stderr, " -2 Force protocol version 2.\n");
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n"); fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
fprintf(stderr, " -s Invoke command (mandatory) as SSH2 subsystem.\n");
exit(1); exit(1);
} }
@ -214,8 +228,9 @@ rsh_connect(char *host, char *user, Buffer * command)
exit(1); exit(1);
} }
int ssh_session(void); int ssh_session(void);
int ssh_session2(void); int ssh_session2(void);
void load_public_identity_files(void);
/* /*
* Main program for the ssh client. * Main program for the ssh client.
@ -227,7 +242,7 @@ main(int ac, char **av)
u_short fwd_port, fwd_host_port; u_short fwd_port, fwd_host_port;
char *optarg, *cp, buf[256]; char *optarg, *cp, buf[256];
struct stat st; struct stat st;
struct passwd *pw, pwcopy; struct passwd *pw;
int dummy; int dummy;
uid_t original_effective_uid; uid_t original_effective_uid;
@ -245,6 +260,15 @@ main(int ac, char **av)
if (setrlimit(RLIMIT_CORE, &rlim) < 0) if (setrlimit(RLIMIT_CORE, &rlim) < 0)
fatal("setrlimit failed: %.100s", strerror(errno)); fatal("setrlimit failed: %.100s", strerror(errno));
} }
/* Get user data. */
pw = getpwuid(original_real_uid);
if (!pw) {
log("You don't exist, go away!");
exit(1);
}
/* Take a copy of the returned structure. */
pw = pwcopy(pw);
/* /*
* Use uid-swapping to give up root privileges for the duration of * Use uid-swapping to give up root privileges for the duration of
* option processing. We will re-instantiate the rights when we are * option processing. We will re-instantiate the rights when we are
@ -252,7 +276,7 @@ main(int ac, char **av)
* them when the port has been created (actually, when the connection * them when the port has been created (actually, when the connection
* has been made, as we may need to create the port several times). * has been made, as we may need to create the port several times).
*/ */
temporarily_use_uid(original_real_uid); temporarily_use_uid(pw);
/* /*
* Set our umask to something reasonable, as some files are created * Set our umask to something reasonable, as some files are created
@ -262,24 +286,12 @@ main(int ac, char **av)
*/ */
umask(022); umask(022);
/* Save our own name. */
av0 = av[0];
/* Initialize option structure to indicate that no values have been set. */ /* Initialize option structure to indicate that no values have been set. */
initialize_options(&options); initialize_options(&options);
/* Parse command-line arguments. */ /* Parse command-line arguments. */
host = NULL; host = NULL;
/* If program name is not one of the standard names, use it as host name. */
if (strchr(av0, '/'))
cp = strrchr(av0, '/') + 1;
else
cp = av0;
if (strcmp(cp, "rsh") && strcmp(cp, "ssh") && strcmp(cp, "rlogin") &&
strcmp(cp, "slogin") && strcmp(cp, "remsh"))
host = cp;
for (optind = 1; optind < ac; optind++) { for (optind = 1; optind < ac; optind++) {
if (av[optind][0] != '-') { if (av[optind][0] != '-') {
if (host) if (host)
@ -297,7 +309,7 @@ main(int ac, char **av)
opt = av[optind][1]; opt = av[optind][1];
if (!opt) if (!opt)
usage(); usage();
if (strchr("eilcpLRo", opt)) { /* options with arguments */ if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
optarg = av[optind] + 2; optarg = av[optind] + 2;
if (strcmp(optarg, "") == 0) { if (strcmp(optarg, "") == 0) {
if (optind >= ac - 1) if (optind >= ac - 1)
@ -310,6 +322,9 @@ main(int ac, char **av)
optarg = NULL; optarg = NULL;
} }
switch (opt) { switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
break;
case '2': case '2':
options.protocol = SSH_PROTO_2; options.protocol = SSH_PROTO_2;
break; break;
@ -354,16 +369,17 @@ main(int ac, char **av)
case 'i': case 'i':
if (stat(optarg, &st) < 0) { if (stat(optarg, &st) < 0) {
fprintf(stderr, "Warning: Identity file %s does not exist.\n", fprintf(stderr, "Warning: Identity file %s does not exist.\n",
optarg); optarg);
break; break;
} }
if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
fatal("Too many identity files specified (max %d)", fatal("Too many identity files specified (max %d)",
SSH_MAX_IDENTITY_FILES); SSH_MAX_IDENTITY_FILES);
options.identity_files[options.num_identity_files++] = options.identity_files[options.num_identity_files++] = xstrdup(optarg);
xstrdup(optarg);
break; break;
case 't': case 't':
if (tty_flag)
force_tty_flag = 1;
tty_flag = 1; tty_flag = 1;
break; break;
case 'v': case 'v':
@ -374,15 +390,16 @@ main(int ac, char **av)
options.log_level++; options.log_level++;
break; break;
} else { } else {
fatal("Too high debugging level.\n"); fatal("Too high debugging level.");
} }
/* fallthrough */ /* fallthrough */
case 'V': case 'V':
fprintf(stderr, "SSH Version %s, protocol versions %d.%d/%d.%d.\n", fprintf(stderr,
"%s, SSH protocols %d.%d/%d.%d, OpenSSL 0x%8.8lx\n",
SSH_VERSION, SSH_VERSION,
PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1, PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2); PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2,
fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay()); SSLeay());
if (opt == 'V') if (opt == 'V')
exit(0); exit(0);
break; break;
@ -391,10 +408,10 @@ main(int ac, char **av)
break; break;
case 'e': case 'e':
if (optarg[0] == '^' && optarg[2] == 0 && if (optarg[0] == '^' && optarg[2] == 0 &&
(unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128) (u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128)
options.escape_char = (unsigned char) optarg[1] & 31; options.escape_char = (u_char) optarg[1] & 31;
else if (strlen(optarg) == 1) else if (strlen(optarg) == 1)
options.escape_char = (unsigned char) optarg[0]; options.escape_char = (u_char) optarg[0];
else if (strcmp(optarg, "none") == 0) else if (strcmp(optarg, "none") == 0)
options.escape_char = -2; options.escape_char = -2;
else { else {
@ -409,16 +426,34 @@ main(int ac, char **av)
options.cipher = SSH_CIPHER_ILLEGAL; options.cipher = SSH_CIPHER_ILLEGAL;
} else { } else {
/* SSH1 only */ /* SSH1 only */
Cipher *c = cipher_by_name(optarg); options.cipher = cipher_number(optarg);
if (c == NULL || c->number < 0) { if (options.cipher == -1) {
fprintf(stderr, "Unknown cipher type '%s'\n", optarg); fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
exit(1); exit(1);
} }
options.cipher = c->number; if (options.cipher == SSH_CIPHER_3DES) {
options.ciphers = "3des-cbc";
} else if (options.cipher == SSH_CIPHER_BLOWFISH) {
options.ciphers = "blowfish-cbc";
} else {
options.ciphers = (char *)-1;
}
}
break;
case 'm':
if (mac_valid(optarg))
options.macs = xstrdup(optarg);
else {
fprintf(stderr, "Unknown mac type '%s'\n", optarg);
exit(1);
} }
break; break;
case 'p': case 'p':
options.port = atoi(optarg); options.port = a2port(optarg);
if (options.port == 0) {
fprintf(stderr, "Bad port '%s'\n", optarg);
exit(1);
}
break; break;
case 'l': case 'l':
options.user = optarg; options.user = optarg;
@ -445,6 +480,16 @@ main(int ac, char **av)
} }
add_local_forward(&options, fwd_port, buf, fwd_host_port); add_local_forward(&options, fwd_port, buf, fwd_host_port);
break; break;
case 'D':
fwd_port = a2port(optarg);
if (fwd_port == 0) {
fprintf(stderr, "Bad dynamic port '%s'\n", optarg);
exit(1);
}
add_local_forward(&options, fwd_port, "socks4", 0);
break;
case 'C': case 'C':
options.compression = 1; options.compression = 1;
break; break;
@ -461,6 +506,9 @@ main(int ac, char **av)
"command-line", 0, &dummy) != 0) "command-line", 0, &dummy) != 0)
exit(1); exit(1);
break; break;
case 's':
subsystem_flag = 1;
break;
default: default:
usage(); usage();
} }
@ -471,6 +519,7 @@ main(int ac, char **av)
usage(); usage();
SSLeay_add_all_algorithms(); SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
/* Initialize the command to execute on remote host. */ /* Initialize the command to execute on remote host. */
buffer_init(&command); buffer_init(&command);
@ -483,6 +532,10 @@ main(int ac, char **av)
if (optind == ac) { if (optind == ac) {
/* No command specified - execute shell on a tty. */ /* No command specified - execute shell on a tty. */
tty_flag = 1; tty_flag = 1;
if (subsystem_flag) {
fprintf(stderr, "You must specify a subsystem to invoke.\n");
usage();
}
} else { } else {
/* A command has been specified. Store it into the /* A command has been specified. Store it into the
buffer. */ buffer. */
@ -501,65 +554,35 @@ main(int ac, char **av)
if (buffer_len(&command) == 0) if (buffer_len(&command) == 0)
tty_flag = 1; tty_flag = 1;
/* Do not allocate a tty if stdin is not a tty. */ /* Force no tty*/
if (!isatty(fileno(stdin))) {
if (tty_flag)
fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
tty_flag = 0;
}
/* force */
if (no_tty_flag) if (no_tty_flag)
tty_flag = 0; tty_flag = 0;
/* Do not allocate a tty if stdin is not a tty. */
/* Get user data. */ if (!isatty(fileno(stdin)) && !force_tty_flag) {
pw = getpwuid(original_real_uid); if (tty_flag)
if (!pw) { log("Pseudo-terminal will not be allocated because stdin is not a terminal.");
fprintf(stderr, "You don't exist, go away!\n"); tty_flag = 0;
exit(1);
} }
/* 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);
pwcopy.pw_class = xstrdup(pw->pw_class);
pwcopy.pw_expire = pw->pw_expire;
pwcopy.pw_change = pw->pw_change;
pw = &pwcopy;
/* Initialize "log" output. Since we are the client all output /*
actually goes to the terminal. */ * Initialize "log" output. Since we are the client all output
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0); * actually goes to stderr.
*/
log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
SYSLOG_FACILITY_USER, 1);
/* Read per-user configuration file. */ /* Read per-user configuration file. */
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE); snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, _PATH_SSH_USER_CONFFILE);
read_config_file(buf, host, &options); read_config_file(buf, host, &options);
/* Read systemwide configuration file. */ /* Read systemwide configuration file. */
read_config_file(HOST_CONFIG_FILE, host, &options); read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
/* Fill configuration defaults. */ /* Fill configuration defaults. */
fill_default_options(&options); fill_default_options(&options);
/* reinit */ /* reinit */
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0); log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
/* check if RSA support exists */
if ((options.protocol & SSH_PROTO_1) &&
rsa_alive() == 0) {
log("%s: no RSA support in libssl and libcrypto. See ssl(8).",
__progname);
log("Disabling protocol version 1");
options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
}
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
fprintf(stderr, "%s: No protocol version available.\n",
__progname);
exit(1);
}
if (options.user == NULL) if (options.user == NULL)
options.user = xstrdup(pw->pw_name); options.user = xstrdup(pw->pw_name);
@ -585,8 +608,9 @@ main(int ac, char **av)
} }
/* Disable rhosts authentication if not running as root. */ /* Disable rhosts authentication if not running as root. */
if (original_effective_uid != 0 || !options.use_privileged_port) { if (original_effective_uid != 0 || !options.use_privileged_port) {
debug("Rhosts Authentication disabled, "
"originating port will not be trusted.");
options.rhosts_authentication = 0; options.rhosts_authentication = 0;
options.rhosts_rsa_authentication = 0;
} }
/* /*
* If using rsh has been selected, exec it now (without trying * If using rsh has been selected, exec it now (without trying
@ -600,7 +624,7 @@ main(int ac, char **av)
restore_uid(); restore_uid();
/* Switch to the original uid permanently. */ /* Switch to the original uid permanently. */
permanently_set_uid(original_real_uid); permanently_set_uid(pw);
/* Execute rsh. */ /* Execute rsh. */
rsh_connect(host, options.user, &command); rsh_connect(host, options.user, &command);
@ -609,17 +633,12 @@ main(int ac, char **av)
/* Restore our superuser privileges. */ /* Restore our superuser privileges. */
restore_uid(); restore_uid();
/* /* Open a connection to the remote host. */
* Open a connection to the remote host. This needs root privileges
* if rhosts_{rsa_}authentication is enabled.
*/
ok = ssh_connect(host, &hostaddr, options.port, ok = ssh_connect(host, &hostaddr, options.port,
options.connection_attempts, options.connection_attempts,
!options.rhosts_authentication && original_effective_uid != 0 || !options.use_privileged_port,
!options.rhosts_rsa_authentication, pw, options.proxy_command);
original_real_uid,
options.proxy_command);
/* /*
* If we successfully made the connection, load the host private key * If we successfully made the connection, load the host private key
@ -627,13 +646,18 @@ main(int ac, char **av)
* authentication. This must be done before releasing extra * authentication. This must be done before releasing extra
* privileges, because the file is only readable by root. * privileges, because the file is only readable by root.
*/ */
if (ok && (options.protocol & SSH_PROTO_1)) { sensitive_data.nkeys = 0;
Key k; sensitive_data.keys = NULL;
host_private_key = RSA_new(); if (ok && (options.rhosts_rsa_authentication ||
k.type = KEY_RSA; options.hostbased_authentication)) {
k.rsa = host_private_key; sensitive_data.nkeys = 3;
if (load_private_key(HOST_KEY_FILE, "", &k, NULL)) sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key));
host_private_key_loaded = 1; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
_PATH_HOST_KEY_FILE, "", NULL);
sensitive_data.keys[1] = key_load_private_type(KEY_DSA,
_PATH_HOST_DSA_KEY_FILE, "", NULL);
sensitive_data.keys[2] = key_load_private_type(KEY_RSA,
_PATH_HOST_RSA_KEY_FILE, "", NULL);
} }
/* /*
* Get rid of any extra privileges that we may have. We will no * Get rid of any extra privileges that we may have. We will no
@ -650,13 +674,13 @@ main(int ac, char **av)
* process, read the private hostkey and impersonate the host. * process, read the private hostkey and impersonate the host.
* OpenBSD does not allow ptracing of setuid processes. * OpenBSD does not allow ptracing of setuid processes.
*/ */
permanently_set_uid(original_real_uid); permanently_set_uid(pw);
/* /*
* Now that we are back to our own permissions, create ~/.ssh * Now that we are back to our own permissions, create ~/.ssh
* directory if it doesn\'t already exist. * directory if it doesn\'t already exist.
*/ */
snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR); snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, _PATH_SSH_USER_DIR);
if (stat(buf, &st) < 0) if (stat(buf, &st) < 0)
if (mkdir(buf, 0700) < 0) if (mkdir(buf, 0700) < 0)
error("Could not create directory '%.200s'.", buf); error("Could not create directory '%.200s'.", buf);
@ -677,31 +701,36 @@ main(int ac, char **av)
} }
exit(1); exit(1);
} }
/* Expand ~ in options.identity_files. */ /* load options.identity_files */
/* XXX mem-leaks */ load_public_identity_files();
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. */ /* Expand ~ in known host file names. */
options.system_hostfile = tilde_expand_filename(options.system_hostfile, /* XXX mem-leaks: */
original_real_uid); options.system_hostfile =
options.user_hostfile = tilde_expand_filename(options.user_hostfile, tilde_expand_filename(options.system_hostfile, original_real_uid);
original_real_uid); options.user_hostfile =
options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2, tilde_expand_filename(options.user_hostfile, original_real_uid);
original_real_uid); options.system_hostfile2 =
options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2, tilde_expand_filename(options.system_hostfile2, original_real_uid);
original_real_uid); options.user_hostfile2 =
tilde_expand_filename(options.user_hostfile2, original_real_uid);
/* Log into the remote system. This never returns if the login fails. */ /* Log into the remote system. This never returns if the login fails. */
ssh_login(host_private_key_loaded, host_private_key, ssh_login(sensitive_data.keys, sensitive_data.nkeys,
host, (struct sockaddr *)&hostaddr, original_real_uid); host, (struct sockaddr *)&hostaddr, pw);
/* We no longer need the host private key. Clear it now. */ /* We no longer need the private host keys. Clear them now. */
if (host_private_key_loaded) if (sensitive_data.nkeys != 0) {
RSA_free(host_private_key); /* Destroys contents safely */ for (i = 0; i < sensitive_data.nkeys; i++) {
if (sensitive_data.keys[i] != NULL) {
/* Destroys contents safely */
debug3("clear hostkey %d", i);
key_free(sensitive_data.keys[i]);
sensitive_data.keys[i] = NULL;
}
}
xfree(sensitive_data.keys);
}
exit_status = compat20 ? ssh_session2() : ssh_session(); exit_status = compat20 ? ssh_session2() : ssh_session();
packet_close(); packet_close();
@ -717,7 +746,7 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len)
if (options.xauth_location) { if (options.xauth_location) {
/* Try to get Xauthority information for the display. */ /* Try to get Xauthority information for the display. */
snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null", snprintf(line, sizeof line, "%.100s list %.200s 2>" _PATH_DEVNULL,
options.xauth_location, getenv("DISPLAY")); options.xauth_location, getenv("DISPLAY"));
f = popen(line, "r"); f = popen(line, "r");
if (f && fgets(line, sizeof(line), f) && if (f && fgets(line, sizeof(line), f) &&
@ -747,16 +776,61 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len)
} }
} }
void
ssh_init_forwarding(void)
{
int success = 0;
int i;
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
debug("Connections to local port %d forwarded to remote address %.200s:%d",
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port);
success += channel_request_local_forwarding(
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port,
options.gateway_ports);
}
if (i > 0 && success == 0)
error("Could not request local forwarding.");
/* Initiate remote TCP/IP port forwardings. */
for (i = 0; i < options.num_remote_forwards; i++) {
debug("Connections to remote port %d forwarded to local address %.200s:%d",
options.remote_forwards[i].port,
options.remote_forwards[i].host,
options.remote_forwards[i].host_port);
channel_request_remote_forwarding(
options.remote_forwards[i].port,
options.remote_forwards[i].host,
options.remote_forwards[i].host_port);
}
}
void
check_agent_present(void)
{
if (options.forward_agent) {
/* Clear agent forwarding if we don\'t have an agent. */
int authfd = ssh_get_authentication_socket();
if (authfd < 0)
options.forward_agent = 0;
else
ssh_close_authentication_socket(authfd);
}
}
int int
ssh_session(void) ssh_session(void)
{ {
int type; int type;
int i;
int plen; int plen;
int interactive = 0; int interactive = 0;
int have_tty = 0; int have_tty = 0;
struct winsize ws; struct winsize ws;
int authfd;
char *cp; char *cp;
/* Enable compression if requested. */ /* Enable compression if requested. */
@ -802,7 +876,7 @@ ssh_session(void)
packet_put_int(ws.ws_ypixel); packet_put_int(ws.ws_ypixel);
/* Store tty modes in the packet. */ /* Store tty modes in the packet. */
tty_make_modes(fileno(stdin)); tty_make_modes(fileno(stdin), NULL);
/* Send the packet, and wait for it to leave. */ /* Send the packet, and wait for it to leave. */
packet_send(); packet_send();
@ -838,16 +912,11 @@ ssh_session(void)
} }
} }
/* Tell the packet module whether this is an interactive session. */ /* Tell the packet module whether this is an interactive session. */
packet_set_interactive(interactive, options.keepalives); packet_set_interactive(interactive);
/* Clear agent forwarding if we don\'t have an agent. */
authfd = ssh_get_authentication_socket();
if (authfd < 0)
options.forward_agent = 0;
else
ssh_close_authentication_socket(authfd);
/* Request authentication agent forwarding if appropriate. */ /* Request authentication agent forwarding if appropriate. */
check_agent_present();
if (options.forward_agent) { if (options.forward_agent) {
debug("Requesting authentication agent forwarding."); debug("Requesting authentication agent forwarding.");
auth_request_forwarding(); auth_request_forwarding();
@ -858,28 +927,9 @@ ssh_session(void)
if (type != SSH_SMSG_SUCCESS) if (type != SSH_SMSG_SUCCESS)
log("Warning: Remote host denied authentication agent forwarding."); log("Warning: Remote host denied authentication agent forwarding.");
} }
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
debug("Connections to local port %d forwarded to remote address %.200s:%d",
options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port);
channel_request_local_forwarding(options.local_forwards[i].port,
options.local_forwards[i].host,
options.local_forwards[i].host_port,
options.gateway_ports);
}
/* Initiate remote TCP/IP port forwardings. */ /* Initiate port forwardings. */
for (i = 0; i < options.num_remote_forwards; i++) { ssh_init_forwarding();
debug("Connections to remote port %d forwarded to local address %.200s:%d",
options.remote_forwards[i].port,
options.remote_forwards[i].host,
options.remote_forwards[i].host_port);
channel_request_remote_forwarding(options.remote_forwards[i].port,
options.remote_forwards[i].host,
options.remote_forwards[i].host_port);
}
/* If requested, let ssh continue in the background. */ /* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag) if (fork_after_authentication_flag)
@ -911,32 +961,28 @@ ssh_session(void)
} }
void void
init_local_fwd(void) client_subsystem_reply(int type, int plen, void *ctxt)
{ {
int i; int id, len;
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) { id = packet_get_int();
debug("Connections to local port %d forwarded to remote address %.200s:%d", len = buffer_len(&command);
options.local_forwards[i].port, if (len > 900)
options.local_forwards[i].host, len = 900;
options.local_forwards[i].host_port); packet_done();
channel_request_local_forwarding(options.local_forwards[i].port, if (type == SSH2_MSG_CHANNEL_FAILURE)
options.local_forwards[i].host, fatal("Request for subsystem '%.*s' failed on channel %d",
options.local_forwards[i].host_port, len, buffer_ptr(&command), id);
options.gateway_ports);
}
} }
extern void client_set_session_ident(int id);
void void
client_init(int id, void *arg) ssh_session2_callback(int id, void *arg)
{ {
int len; int len;
debug("client_init id %d arg %d", id, (int)arg); int interactive = 0;
struct termios tio;
if (no_shell_flag) debug("client_init id %d arg %ld", id, (long)arg);
goto done;
if (tty_flag) { if (tty_flag) {
struct winsize ws; struct winsize ws;
@ -954,8 +1000,10 @@ client_init(int id, void *arg)
packet_put_int(ws.ws_row); packet_put_int(ws.ws_row);
packet_put_int(ws.ws_xpixel); packet_put_int(ws.ws_xpixel);
packet_put_int(ws.ws_ypixel); packet_put_int(ws.ws_ypixel);
packet_put_cstring(""); /* XXX: encode terminal modes */ tio = get_saved_tio();
tty_make_modes(/*ignored*/ 0, &tio);
packet_send(); packet_send();
interactive = 1;
/* XXX wait for reply */ /* XXX wait for reply */
} }
if (options.forward_x11 && if (options.forward_x11 &&
@ -966,34 +1014,51 @@ client_init(int id, void *arg)
/* Request forwarding with authentication spoofing. */ /* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication spoofing."); debug("Requesting X11 forwarding with authentication spoofing.");
x11_request_forwarding_with_spoofing(id, proto, data); x11_request_forwarding_with_spoofing(id, proto, data);
interactive = 1;
/* XXX wait for reply */ /* XXX wait for reply */
} }
check_agent_present();
if (options.forward_agent) {
debug("Requesting authentication agent forwarding.");
channel_request_start(id, "auth-agent-req@openssh.com", 0);
packet_send();
}
len = buffer_len(&command); len = buffer_len(&command);
if (len > 0) { if (len > 0) {
if (len > 900) if (len > 900)
len = 900; len = 900;
debug("Sending command: %.*s", len, buffer_ptr(&command)); if (subsystem_flag) {
channel_request_start(id, "exec", 0); debug("Sending subsystem: %.*s", len, buffer_ptr(&command));
packet_put_string(buffer_ptr(&command), len); channel_request_start(id, "subsystem", /*want reply*/ 1);
/* register callback for reply */
/* XXX we asume that client_loop has already been called */
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
} else {
debug("Sending command: %.*s", len, buffer_ptr(&command));
channel_request_start(id, "exec", 0);
}
packet_put_string(buffer_ptr(&command), buffer_len(&command));
packet_send(); packet_send();
} else { } else {
channel_request(id, "shell", 0); channel_request(id, "shell", 0);
} }
/* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */ /* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
done:
/* register different callback, etc. XXX */ /* register different callback, etc. XXX */
client_set_session_ident(id); packet_set_interactive(interactive);
} }
int int
ssh_session2(void) ssh_session2_command(void)
{ {
int window, packetmax, id; int id, window, packetmax;
int in, out, err; int in, out, err;
if (stdin_null_flag) { if (stdin_null_flag) {
in = open("/dev/null", O_RDONLY); in = open(_PATH_DEVNULL, O_RDONLY);
} else { } else {
in = dup(STDIN_FILENO); in = dup(STDIN_FILENO);
} }
@ -1011,14 +1076,6 @@ ssh_session2(void)
if (!isatty(err)) if (!isatty(err))
set_nonblock(err); set_nonblock(err);
/* should be pre-session */
init_local_fwd();
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
window = CHAN_SES_WINDOW_DEFAULT; window = CHAN_SES_WINDOW_DEFAULT;
packetmax = CHAN_SES_PACKET_DEFAULT; packetmax = CHAN_SES_PACKET_DEFAULT;
if (!tty_flag) { if (!tty_flag) {
@ -1030,8 +1087,48 @@ ssh_session2(void)
window, packetmax, CHAN_EXTENDED_WRITE, window, packetmax, CHAN_EXTENDED_WRITE,
xstrdup("client-session"), /*nonblock*/0); xstrdup("client-session"), /*nonblock*/0);
debug("channel_new: %d", id);
channel_open(id); channel_open(id);
channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0); channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
ssh_session2_callback, (void *)0);
return id;
}
int
ssh_session2(void)
{
int id;
/* XXX should be pre-session */
ssh_init_forwarding();
id = no_shell_flag ? -1 : ssh_session2_command();
/* If requested, let ssh continue in the background. */
if (fork_after_authentication_flag)
if (daemon(1, 1) < 0)
fatal("daemon() failed: %.200s", strerror(errno));
return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id); return client_loop(tty_flag, tty_flag ? options.escape_char : -1, id);
} }
void
load_public_identity_files(void)
{
char *filename;
Key *public;
int i;
for (i = 0; i < options.num_identity_files; i++) {
filename = tilde_expand_filename(options.identity_files[i],
original_real_uid);
public = key_load_public(filename, NULL);
debug("identity file %s type %d", filename,
public ? public->type : -1);
xfree(options.identity_files[i]);
options.identity_files[i] = filename;
options.identity_keys[i] = public;
}
}

View File

@ -3,8 +3,6 @@
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
* *
* Generic header file for ssh.
*
* As far as I am concerned, the code I have written for this software * As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this * can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is * software must be clearly marked as such, and if the derived work is
@ -12,15 +10,12 @@
* called by a name other than "ssh" or "Secure Shell". * called by a name other than "ssh" or "Secure Shell".
*/ */
/* RCSID("$OpenBSD: ssh.h,v 1.54 2000/10/11 20:27:24 markus Exp $"); */ /* RCSID("$OpenBSD: ssh.h,v 1.62 2001/01/23 10:45:10 markus Exp $"); */
/* $FreeBSD$ */ /* RCSID("$FreeBSD$"); */
#ifndef SSH_H #ifndef SSH_H
#define SSH_H #define SSH_H
#include "rsa.h"
#include "cipher.h"
/* Cipher used for encrypting authentication files. */ /* Cipher used for encrypting authentication files. */
#define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES #define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES
@ -56,95 +51,6 @@
*/ */
#define SSH_SERVICE_NAME "ssh" #define SSH_SERVICE_NAME "ssh"
#define ETCDIR "/etc/ssh"
#define PIDDIR "/var/run"
/*
* System-wide file containing host keys of known hosts. This file should be
* 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
* should be world-readable.
*/
#define HOST_KEY_FILE ETCDIR "/ssh_host_key"
#define SERVER_CONFIG_FILE ETCDIR "/sshd_config"
#define HOST_CONFIG_FILE ETCDIR "/ssh_config"
#define HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key"
#define DH_PRIMES ETCDIR "/primes"
#define SSH_PROGRAM "/usr/bin/ssh"
/*
* The process id of the daemon listening for connections is saved here to
* make it easier to kill the correct daemon when necessary.
*/
#define SSH_DAEMON_PID_FILE PIDDIR "/sshd.pid"
/*
* The directory in user\'s home directory in which the files reside. The
* directory should be world-readable (though not all files are).
*/
#define SSH_USER_DIR ".ssh"
/*
* Per-user file containing host keys of known hosts. This file need not be
* readable by anyone except the user him/herself, though this does not
* contain anything particularly secret.
*/
#define SSH_USER_HOSTFILE "~/.ssh/known_hosts"
#define SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2"
/*
* Name of the default file containing client-side authentication key. This
* file should only be readable by the user him/herself.
*/
#define SSH_CLIENT_IDENTITY ".ssh/identity"
#define SSH_CLIENT_ID_DSA ".ssh/id_dsa"
/*
* Configuration file in user\'s home directory. This file need not be
* readable by anyone but the user him/herself, but does not contain anything
* particularly secret. If the user\'s home directory resides on an NFS
* volume where root is mapped to nobody, this may need to be world-readable.
*/
#define SSH_USER_CONFFILE ".ssh/config"
/*
* File containing a list of those rsa keys that permit logging in as this
* user. This file need not be readable by anyone but the user him/herself,
* but does not contain anything particularly secret. If the user\'s home
* directory resides on an NFS volume where root is mapped to nobody, this
* may need to be world-readable. (This file is read by the daemon which is
* 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
* /bin/sh before starting the shell or command if they exist. They will be
* passed "proto cookie" as arguments if X11 forwarding with spoofing is in
* use. xauth will be run if neither of these exists.
*/
#define SSH_USER_RC ".ssh/rc"
#define SSH_SYSTEM_RC ETCDIR "/sshrc"
/*
* Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use
* ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled.
*/
#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv"
/*
* Name of the environment variable containing the pathname of the
* authentication socket.
*/
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
/* /*
* Name of the environment variable containing the pathname of the * Name of the environment variable containing the pathname of the
* authentication socket. * authentication socket.
@ -152,10 +58,14 @@
#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID" #define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
/* /*
* Default path to ssh-askpass used by ssh-add, * Name of the environment variable containing the pathname of the
* environment variable for overwriting the default location * authentication socket.
*/
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
/*
* Environment variable for overwriting the default location of askpass
*/ */
#define SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass"
#define SSH_ASKPASS_ENV "SSH_ASKPASS" #define SSH_ASKPASS_ENV "SSH_ASKPASS"
/* /*
@ -173,361 +83,9 @@
/* Name of Kerberos service for SSH to use. */ /* Name of Kerberos service for SSH to use. */
#define KRB4_SERVICE_NAME "rcmd" #define KRB4_SERVICE_NAME "rcmd"
/*
* Authentication methods. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
*/
#define SSH_AUTH_RHOSTS 1
#define SSH_AUTH_RSA 2
#define SSH_AUTH_PASSWORD 3
#define SSH_AUTH_RHOSTS_RSA 4
#define SSH_AUTH_TIS 5
#define SSH_AUTH_KERBEROS 6
#define SSH_PASS_KERBEROS_TGT 7
/* 8 to 15 are reserved */
#define SSH_PASS_AFS_TOKEN 21
/* Protocol flags. These are bit masks. */
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
/*
* Definition of message types. New values can be added, but old values
* should not be removed or without careful consideration of the consequences
* for compatibility. The maximum value is 254; value 255 is reserved for
* future extension.
*/
/* Message name */ /* msg code */ /* arguments */
#define SSH_MSG_NONE 0 /* no message */
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
#define SSH_CMSG_USER 4 /* user (string) */
#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
#define SSH_CMSG_EXEC_SHELL 12 /* */
#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
#define SSH_SMSG_SUCCESS 14 /* */
#define SSH_SMSG_FAILURE 15 /* */
#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
#define SSH_CMSG_EOF 19 /* */
#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
#define SSH_MSG_IGNORE 32 /* string */
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
#define SSH_MSG_DEBUG 36 /* string */
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
#define SSH_CMSG_HAVE_KERBEROS_TGT 44
#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
/* Kerberos IV tickets can't be forwarded. This is an AFS hack! */ /* Kerberos IV tickets can't be forwarded. This is an AFS hack! */
#define SSH_CMSG_HAVE_KRB4_TGT SSH_CMSG_HAVE_KERBEROS_TGT /* credentials (s) */ #define SSH_CMSG_HAVE_KRB4_TGT SSH_CMSG_HAVE_KERBEROS_TGT /* credentials (s) */
/*------------ definitions for login.c -------------*/
/*
* Returns the time when the user last logged in. Returns 0 if the
* information is not available. This must be called before record_login.
* The host from which the user logged in is stored in buf.
*/
unsigned long
get_last_login_time(uid_t uid, const char *logname,
char *buf, unsigned int bufsize);
/*
* Records that the user has logged in. This does many things normally done
* by login(1).
*/
void
record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
const char *host, struct sockaddr *addr);
/*
* Records that the user has logged out. This does many thigs normally done
* by login(1) or init.
*/
void record_logout(pid_t pid, const char *ttyname);
/*------------ definitions for sshconnect.c ----------*/
/*
* Opens a TCP/IP connection to the remote server on the given host. If port
* is 0, the default port will be used. If anonymous is zero, a privileged
* port will be allocated to make the connection. This requires super-user
* privileges if anonymous is false. Connection_attempts specifies the
* maximum number of tries, one per second. This returns true on success,
* and zero on failure. If the connection is successful, this calls
* packet_set_connection for the connection.
*/
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int connection_attempts,
int anonymous, uid_t original_real_uid,
const char *proxy_command);
/*
* Starts a dialog with the server, and authenticates the current user on the
* server. This does not need any extra privileges. The basic connection to
* the server must already have been established before this is called. If
* login fails, this function prints an error and never returns. This
* initializes the random state, and leaves it initialized (it will also have
* references from the packet module).
*/
void
ssh_login(int host_key_valid, RSA * host_key, const char *host,
struct sockaddr * hostaddr, uid_t original_real_uid);
/*------------ Definitions for various authentication methods. -------*/
/*
* Tries to authenticate the user using the .rhosts file. Returns true if
* authentication succeeds. If ignore_rhosts is non-zero, this will not
* consider .rhosts and .shosts (/etc/hosts.equiv will still be used).
*/
int auth_rhosts(struct passwd * pw, const char *client_user);
/*
* Tries to authenticate the user using the .rhosts file and the host using
* its host key. Returns true if authentication succeeds.
*/
int
auth_rhosts_rsa(struct passwd * pw, const char *client_user, RSA* client_host_key);
/*
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
*/
int auth_password(struct passwd * pw, const char *password);
/*
* Performs the RSA authentication dialog with the client. This returns 0 if
* the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_rsa(struct passwd * pw, BIGNUM * client_n);
/*
* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer
* over the key. Skips any whitespace at the beginning and at end.
*/
int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n);
/*
* Returns the name of the machine at the other end of the socket. The
* returned string should be freed by the caller.
*/
char *get_remote_hostname(int socket);
/*
* Return the canonical name of the host in the other side of the current
* connection (as returned by packet_get_connection). The host name is
* cached, so it is efficient to call this several times.
*/
const char *get_canonical_hostname(void);
/*
* Returns the local IP address as an ascii string.
*/
const char *get_ipaddr(int socket);
/*
* Returns the remote IP address as an ascii string. The value need not be
* freed by the caller.
*/
const char *get_remote_ipaddr(void);
/* Returns the port number of the peer of the socket. */
int get_peer_port(int sock);
/* Returns the port number of the remote/local host. */
int get_remote_port(void);
int get_local_port(void);
/*
* Performs the RSA authentication challenge-response dialog with the client,
* and returns true (non-zero) if the client gave the correct answer to our
* challenge; returns zero if the client gives a wrong answer.
*/
int auth_rsa_challenge_dialog(RSA *pk);
/*
* Reads a passphrase from /dev/tty with echo turned off. Returns the
* passphrase (allocated with xmalloc). Exits if EOF is encountered. If
* from_stdin is true, the passphrase will be read from stdin instead.
*/
char *read_passphrase(char *prompt, int from_stdin);
/*------------ Definitions for logging. -----------------------*/
/* Supported syslog facilities and levels. */
typedef enum {
SYSLOG_FACILITY_DAEMON,
SYSLOG_FACILITY_USER,
SYSLOG_FACILITY_AUTH,
SYSLOG_FACILITY_LOCAL0,
SYSLOG_FACILITY_LOCAL1,
SYSLOG_FACILITY_LOCAL2,
SYSLOG_FACILITY_LOCAL3,
SYSLOG_FACILITY_LOCAL4,
SYSLOG_FACILITY_LOCAL5,
SYSLOG_FACILITY_LOCAL6,
SYSLOG_FACILITY_LOCAL7
} SyslogFacility;
typedef enum {
SYSLOG_LEVEL_QUIET,
SYSLOG_LEVEL_FATAL,
SYSLOG_LEVEL_ERROR,
SYSLOG_LEVEL_INFO,
SYSLOG_LEVEL_VERBOSE,
SYSLOG_LEVEL_DEBUG1,
SYSLOG_LEVEL_DEBUG2,
SYSLOG_LEVEL_DEBUG3
} LogLevel;
/* Initializes logging. */
void log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr);
/* Logging implementation, depending on server or client */
void do_log(LogLevel level, const char *fmt, va_list args);
/* name to facility/level */
SyslogFacility log_facility_number(char *name);
LogLevel log_level_number(char *name);
/* Output a message to syslog or stderr */
void fatal(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void error(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void log(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void verbose(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug2(const char *fmt,...) __attribute__((format(printf, 1, 2)));
void debug3(const char *fmt,...) __attribute__((format(printf, 1, 2)));
/* same as fatal() but w/o logging */
void fatal_cleanup(void);
/*
* Registers a cleanup function to be called by fatal()/fatal_cleanup()
* before exiting. It is permissible to call fatal_remove_cleanup for the
* function itself from the function.
*/
void fatal_add_cleanup(void (*proc) (void *context), void *context);
/* Removes a cleanup function to be called at fatal(). */
void fatal_remove_cleanup(void (*proc) (void *context), void *context);
/* ---- misc */
/*
* Expands tildes in the file name. Returns data allocated by xmalloc.
* Warning: this calls getpw*.
*/
char *tilde_expand_filename(const char *filename, uid_t my_uid);
/* remove newline at end of string */
char *chop(char *s);
/* return next token in configuration line */
char *strdelim(char **s);
/* set filedescriptor to non-blocking */
void set_nonblock(int fd);
/*
* Performs the interactive session. This handles data transmission between
* the client and the program. Note that the notion of stdin, stdout, and
* stderr in this function is sort of reversed: this function writes to stdin
* (of the child program), and reads from stdout and stderr (of the child
* program).
*/
void server_loop(pid_t pid, int fdin, int fdout, int fderr);
void server_loop2(void);
/* Client side main loop for the interactive session. */
int client_loop(int have_pty, int escape_char, int id);
/* Linked list of custom environment strings (see auth-rsa.c). */
struct envstring {
struct envstring *next;
char *s;
};
/*
* Ensure all of data on socket comes through. f==read || f==write
*/
ssize_t atomicio(ssize_t (*f)(), int fd, void *s, size_t n);
#ifdef KRB5
#include <krb5.h>
int auth_krb5(); /* XXX Doplnit prototypy */
int auth_krb5_tgt();
int krb5_init();
void krb5_cleanup_proc(void *ignore);
int auth_krb5_password(struct passwd *pw, const char *password);
#endif /* KRB5 */
#ifdef KRB4
#include <krb.h>
/*
* Performs Kerberos v4 mutual authentication with the client. This returns 0
* if the client could not be authenticated, and 1 if authentication was
* successful. This may exit if there is a serious protocol violation.
*/
int auth_krb4(const char *server_user, KTEXT auth, char **client);
int krb4_init(uid_t uid);
void krb4_cleanup_proc(void *ignore);
int auth_krb4_password(struct passwd * pw, const char *password);
#ifdef AFS
#include <kafs.h>
/* Accept passed Kerberos v4 ticket-granting ticket and AFS tokens. */
int auth_krb4_tgt(struct passwd * pw, const char *string);
int auth_afs_token(struct passwd * pw, const char *token_string);
int creds_to_radix(CREDENTIALS * creds, unsigned char *buf, size_t buflen);
int radix_to_creds(const char *buf, CREDENTIALS * creds);
#endif /* AFS */
#endif /* KRB4 */
#ifdef SKEY
#include <opie.h>
char *skey_fake_keyinfo(char *username);
int auth_skey_password(struct passwd * pw, const char *password);
#endif /* SKEY */
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
#ifdef USE_PAM #ifdef USE_PAM
#include "auth-pam.h" #include "auth-pam.h"
#endif /* USE_PAM */ #endif /* USE_PAM */

View File

@ -2,7 +2,12 @@
# defaults for users, and the values can be changed in per-user configuration # defaults for users, and the values can be changed in per-user configuration
# files or on the command line. # files or on the command line.
# #
# $FreeBSD$ # $OpenBSD: ssh_config,v 1.10 2001/04/03 21:19:38 todd Exp $
# $FreeBSD$
# This is ssh client systemwide configuration file. See ssh(1) for more
# information. This file provides defaults for users, and the values can
# be changed in per-user configuration files or on the command line.
# Configuration data is parsed as follows: # Configuration data is parsed as follows:
# 1. command line options # 1. command line options
@ -15,9 +20,9 @@
# Site-wide defaults for various options # Site-wide defaults for various options
# Host * # Host *
# ForwardAgent yes # ForwardAgent no
# ForwardX11 yes # ForwardX11 no
# RhostsAuthentication yes # RhostsAuthentication no
# RhostsRSAAuthentication yes # RhostsRSAAuthentication yes
# RSAAuthentication yes # RSAAuthentication yes
# PasswordAuthentication yes # PasswordAuthentication yes
@ -25,8 +30,10 @@
# UseRsh no # UseRsh no
# BatchMode no # BatchMode no
# CheckHostIP yes # CheckHostIP yes
# StrictHostKeyChecking no # StrictHostKeyChecking yes
# IdentityFile ~/.ssh/identity # IdentityFile ~/.ssh/identity
# IdentityFile ~/.ssh/id_dsa
# IdentityFile ~/.ssh/id_rsa
# Port 22 # Port 22
# Protocol 2,1 # Protocol 2,1
# Cipher blowfish # Cipher blowfish

View File

@ -13,24 +13,25 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshconnect.c,v 1.79 2000/09/17 15:52:51 markus Exp $"); RCSID("$OpenBSD: sshconnect.c,v 1.104 2001/04/12 19:15:25 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
#include "ssh.h"
#include "buffer.h" #include "buffer.h"
#include "packet.h" #include "packet.h"
#include "uidswap.h" #include "uidswap.h"
#include "compat.h" #include "compat.h"
#include "readconf.h"
#include "key.h" #include "key.h"
#include "sshconnect.h" #include "sshconnect.h"
#include "hostfile.h" #include "hostfile.h"
#include "log.h"
#include "readconf.h"
#include "atomicio.h"
#include "misc.h"
char *client_version_string = NULL; char *client_version_string = NULL;
char *server_version_string = NULL; char *server_version_string = NULL;
@ -38,11 +39,14 @@ char *server_version_string = NULL;
extern Options options; extern Options options;
extern char *__progname; extern char *__progname;
/* AF_UNSPEC or AF_INET or AF_INET6 */
extern int IPv4or6;
/* /*
* Connect to the given ssh server using a proxy command. * Connect to the given ssh server using a proxy command.
*/ */
int int
ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid, ssh_proxy_connect(const char *host, u_short port, struct passwd *pw,
const char *proxy_command) const char *proxy_command)
{ {
Buffer command; Buffer command;
@ -93,7 +97,7 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
char *argv[10]; char *argv[10];
/* Child. Permanently give up superuser privileges. */ /* Child. Permanently give up superuser privileges. */
permanently_set_uid(original_real_uid); permanently_set_uid(pw);
/* Redirect stdin and stdout. */ /* Redirect stdin and stdout. */
close(pin[1]); close(pin[1]);
@ -110,15 +114,15 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
/* Stderr is left as it is so that error messages get /* Stderr is left as it is so that error messages get
printed on the user's terminal. */ printed on the user's terminal. */
argv[0] = "/bin/sh"; argv[0] = _PATH_BSHELL;
argv[1] = "-c"; argv[1] = "-c";
argv[2] = command_string; argv[2] = command_string;
argv[3] = NULL; argv[3] = NULL;
/* Execute the proxy command. Note that we gave up any /* Execute the proxy command. Note that we gave up any
extra privileges above. */ extra privileges above. */
execv("/bin/sh", argv); execv(argv[0], argv);
perror("/bin/sh"); perror(argv[0]);
exit(1); exit(1);
} }
/* Parent. */ /* Parent. */
@ -142,7 +146,7 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
* Creates a (possibly privileged) socket for use as the ssh connection. * Creates a (possibly privileged) socket for use as the ssh connection.
*/ */
int int
ssh_create_socket(uid_t original_real_uid, int privileged, int family) ssh_create_socket(struct passwd *pw, int privileged, int family)
{ {
int sock; int sock;
@ -162,7 +166,7 @@ ssh_create_socket(uid_t original_real_uid, int privileged, int family)
* Just create an ordinary socket on arbitrary port. We use * Just create an ordinary socket on arbitrary port. We use
* the user's uid to create the socket. * the user's uid to create the socket.
*/ */
temporarily_use_uid(original_real_uid); temporarily_use_uid(pw);
sock = socket(family, SOCK_STREAM, 0); sock = socket(family, SOCK_STREAM, 0);
if (sock < 0) if (sock < 0)
error("socket: %.100s", strerror(errno)); error("socket: %.100s", strerror(errno));
@ -185,15 +189,16 @@ ssh_create_socket(uid_t original_real_uid, int privileged, int family)
int int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr, ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int connection_attempts, u_short port, int connection_attempts,
int anonymous, uid_t original_real_uid, int anonymous, struct passwd *pw,
const char *proxy_command) const char *proxy_command)
{ {
int sock = -1, attempt;
struct servent *sp;
struct addrinfo hints, *ai, *aitop;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
int gaierr; int gaierr;
int on = 1;
int sock = -1, attempt;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
struct addrinfo hints, *ai, *aitop;
struct linger linger; struct linger linger;
struct servent *sp;
debug("ssh_connect: getuid %u geteuid %u anon %d", debug("ssh_connect: getuid %u geteuid %u anon %d",
(u_int) getuid(), (u_int) geteuid(), anonymous); (u_int) getuid(), (u_int) geteuid(), anonymous);
@ -208,7 +213,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
} }
/* If a proxy command is given, connect using it. */ /* If a proxy command is given, connect using it. */
if (proxy_command != NULL) if (proxy_command != NULL)
return ssh_proxy_connect(host, port, original_real_uid, proxy_command); return ssh_proxy_connect(host, port, pw, proxy_command);
/* No proxy command. */ /* No proxy command. */
@ -244,8 +249,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
host, ntop, strport); host, ntop, strport);
/* Create a socket for connecting. */ /* Create a socket for connecting. */
sock = ssh_create_socket(original_real_uid, sock = ssh_create_socket(pw,
!anonymous && geteuid() == 0 && port < IPPORT_RESERVED, !anonymous && geteuid() == 0,
ai->ai_family); ai->ai_family);
if (sock < 0) if (sock < 0)
continue; continue;
@ -254,10 +259,10 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* hope that it will help with tcp_wrappers showing * hope that it will help with tcp_wrappers showing
* the remote uid as root. * the remote uid as root.
*/ */
temporarily_use_uid(original_real_uid); temporarily_use_uid(pw);
if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
/* Successful connection. */ /* Successful connection. */
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
restore_uid(); restore_uid();
break; break;
} else { } else {
@ -295,7 +300,13 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
linger.l_onoff = 1; linger.l_onoff = 1;
linger.l_linger = 5; linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
/* Set keepalives if requested. */
if (options.keepalives &&
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
sizeof(on)) < 0)
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
/* Set the connection. */ /* Set the connection. */
packet_set_connection(sock, sock); packet_set_connection(sock, sock);
@ -308,12 +319,13 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
* identification string. * identification string.
*/ */
void void
ssh_exchange_identification() ssh_exchange_identification(void)
{ {
char buf[256], remote_version[256]; /* must be same size! */ char buf[256], remote_version[256]; /* must be same size! */
int remote_major, remote_minor, i, mismatch; int remote_major, remote_minor, i, mismatch;
int connection_in = packet_get_connection_in(); int connection_in = packet_get_connection_in();
int connection_out = packet_get_connection_out(); int connection_out = packet_get_connection_out();
int minor1 = PROTOCOL_MINOR_1;
/* Read other side\'s version identification. */ /* Read other side\'s version identification. */
for (;;) { for (;;) {
@ -367,9 +379,10 @@ ssh_exchange_identification()
} }
if (remote_minor < 3) { if (remote_minor < 3) {
fatal("Remote machine has too old SSH software version."); fatal("Remote machine has too old SSH software version.");
} else if (remote_minor == 3) { } else if (remote_minor == 3 || remote_minor == 4) {
/* We speak 1.3, too. */ /* We speak 1.3, too. */
enable_compat13(); enable_compat13();
minor1 = 3;
if (options.forward_agent) { if (options.forward_agent) {
log("Agent forwarding disabled for protocol 1.3"); log("Agent forwarding disabled for protocol 1.3");
options.forward_agent = 0; options.forward_agent = 0;
@ -395,7 +408,7 @@ ssh_exchange_identification()
/* Send our own protocol version identification. */ /* Send our own protocol version identification. */
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1, compat20 ? PROTOCOL_MINOR_2 : minor1,
SSH_VERSION); SSH_VERSION);
if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf)) if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
fatal("write: %.100s", strerror(errno)); fatal("write: %.100s", strerror(errno));
@ -405,6 +418,7 @@ ssh_exchange_identification()
debug("Local version string %.100s", client_version_string); debug("Local version string %.100s", client_version_string);
} }
/* defaults to 'no' */
int int
read_yes_or_no(const char *prompt, int defval) read_yes_or_no(const char *prompt, int defval)
{ {
@ -412,10 +426,13 @@ read_yes_or_no(const char *prompt, int defval)
FILE *f; FILE *f;
int retval = -1; int retval = -1;
if (isatty(0)) if (options.batch_mode)
return 0;
if (isatty(STDIN_FILENO))
f = stdin; f = stdin;
else else
f = fopen("/dev/tty", "rw"); f = fopen(_PATH_TTY, "rw");
if (f == NULL) if (f == NULL)
return 0; return 0;
@ -461,11 +478,13 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
Key *file_key; Key *file_key;
char *type = key_type(host_key); char *type = key_type(host_key);
char *ip = NULL; char *ip = NULL;
char hostline[1000], *hostp; char hostline[1000], *hostp, *fp;
HostStatus host_status; HostStatus host_status;
HostStatus ip_status; HostStatus ip_status;
int local = 0, host_ip_differ = 0; int local = 0, host_ip_differ = 0;
char ntop[NI_MAXHOST]; char ntop[NI_MAXHOST];
int host_line, ip_line;
const char *host_file = NULL, *ip_file = NULL;
/* /*
* Force accepting of the host key for loopback/localhost. The * Force accepting of the host key for loopback/localhost. The
@ -487,23 +506,40 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
local = 0; local = 0;
break; break;
} }
if (local) { if (local && options.host_key_alias == NULL) {
debug("Forcing accepting of host key for loopback/localhost."); debug("Forcing accepting of host key for "
"loopback/localhost.");
return; return;
} }
/* /*
* Turn off check_host_ip for proxy connects, since * We don't have the remote ip-address for connections
* we don't have the remote ip-address * using a proxy command
*/ */
if (options.proxy_command != NULL && options.check_host_ip) if (options.proxy_command == NULL) {
options.check_host_ip = 0;
if (options.check_host_ip) {
if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop), if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop),
NULL, 0, NI_NUMERICHOST) != 0) NULL, 0, NI_NUMERICHOST) != 0)
fatal("check_host_key: getnameinfo failed"); fatal("check_host_key: getnameinfo failed");
ip = xstrdup(ntop); ip = xstrdup(ntop);
} else {
ip = xstrdup("<no hostip for proxy command>");
}
/*
* Turn off check_host_ip if the connection is to localhost, via proxy
* command or if we don't have a hostname to compare with
*/
if (options.check_host_ip &&
(local || strcmp(host, ip) == 0 || options.proxy_command != NULL))
options.check_host_ip = 0;
/*
* Allow the user to record the key under a different name. This is
* useful for ssh tunneling over forwarded connections or if you run
* multiple sshd's on different ports on the same machine.
*/
if (options.host_key_alias != NULL) {
host = options.host_key_alias;
debug("using hostkeyalias: %s", host);
} }
/* /*
@ -516,19 +552,25 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
* Check if the host key is present in the user\'s list of known * Check if the host key is present in the user\'s list of known
* hosts or in the systemwide list. * hosts or in the systemwide list.
*/ */
host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key); host_file = user_hostfile;
if (host_status == HOST_NEW) host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key); if (host_status == HOST_NEW) {
host_file = system_hostfile;
host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
}
/* /*
* Also perform check for the ip address, skip the check if we are * Also perform check for the ip address, skip the check if we are
* localhost or the hostname was an ip address to begin with * localhost or the hostname was an ip address to begin with
*/ */
if (options.check_host_ip && !local && strcmp(host, ip)) { if (options.check_host_ip) {
Key *ip_key = key_new(host_key->type); Key *ip_key = key_new(host_key->type);
ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
if (ip_status == HOST_NEW) ip_file = user_hostfile;
ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key); ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
if (ip_status == HOST_NEW) {
ip_file = system_hostfile;
ip_status = check_host_in_hostfile(ip_file, ip, host_key, ip_key, &ip_line);
}
if (host_status == HOST_CHANGED && if (host_status == HOST_CHANGED &&
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
host_ip_differ = 1; host_ip_differ = 1;
@ -544,17 +586,14 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
/* The host is known and the key matches. */ /* The host is known and the key matches. */
debug("Host '%.200s' is known and matches the %s host key.", debug("Host '%.200s' is known and matches the %s host key.",
host, type); host, type);
if (options.check_host_ip) { debug("Found key in %s:%d", host_file, host_line);
if (ip_status == HOST_NEW) { if (options.check_host_ip && ip_status == HOST_NEW) {
if (!add_host_to_hostfile(user_hostfile, ip, host_key)) if (!add_host_to_hostfile(user_hostfile, ip, host_key))
log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).", log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).",
type, ip, user_hostfile); type, ip, user_hostfile);
else else
log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.", log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.",
type, ip); type, ip);
} else if (ip_status != HOST_OK)
log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'",
type, host, ip);
} }
break; break;
case HOST_NEW: case HOST_NEW:
@ -566,16 +605,17 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
} else if (options.strict_host_key_checking == 2) { } else if (options.strict_host_key_checking == 2) {
/* The default */ /* The default */
char prompt[1024]; char prompt[1024];
char *fp = key_fingerprint(host_key); fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
snprintf(prompt, sizeof(prompt), snprintf(prompt, sizeof(prompt),
"The authenticity of host '%.200s' can't be established.\n" "The authenticity of host '%.200s (%s)' can't be established.\n"
"%s key fingerprint is %s.\n" "%s key fingerprint is %s.\n"
"Are you sure you want to continue connecting (yes/no)? ", "Are you sure you want to continue connecting (yes/no)? ",
host, type, fp); host, ip, type, fp);
xfree(fp);
if (!read_yes_or_no(prompt, -1)) if (!read_yes_or_no(prompt, -1))
fatal("Aborted by user!\n"); fatal("Aborted by user!");
} }
if (options.check_host_ip && ip_status == HOST_NEW && strcmp(host, ip)) { if (options.check_host_ip && ip_status == HOST_NEW) {
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
hostp = hostline; hostp = hostline;
} else } else
@ -605,18 +645,25 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
error("and the key for the according IP address %s", ip); error("and the key for the according IP address %s", ip);
error("%s. This could either mean that", msg); error("%s. This could either mean that", msg);
error("DNS SPOOFING is happening or the IP address for the host"); error("DNS SPOOFING is happening or the IP address for the host");
error("and its host key have changed at the same time"); error("and its host key have changed at the same time.");
if (ip_status != HOST_NEW)
error("Offending key for IP in %s:%d", ip_file, ip_line);
} }
/* The host key has changed. */ /* The host key has changed. */
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
error("It is also possible that the %s host key has just been changed.", type); error("It is also possible that the %s host key has just been changed.", type);
error("The fingerprint for the %s key sent by the remote host is\n%s.",
type, fp);
error("Please contact your system administrator."); error("Please contact your system administrator.");
error("Add correct host key in %.100s to get rid of this message.", error("Add correct host key in %.100s to get rid of this message.",
user_hostfile); user_hostfile);
error("Offending key in %s:%d", host_file, host_line);
xfree(fp);
/* /*
* If strict host key checking is in use, the user will have * If strict host key checking is in use, the user will have
@ -638,6 +685,14 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
error("Agent forwarding is disabled to avoid trojan horses."); error("Agent forwarding is disabled to avoid trojan horses.");
options.forward_agent = 0; options.forward_agent = 0;
} }
if (options.forward_x11) {
error("X11 forwarding is disabled to avoid trojan horses.");
options.forward_x11 = 0;
}
if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) {
error("Port forwarding is disabled to avoid trojan horses.");
options.num_local_forwards = options.num_remote_forwards = 0;
}
/* /*
* XXX Should permit the user to change to use the new id. * XXX Should permit the user to change to use the new id.
* This could be done by converting the host key to an * This could be done by converting the host key to an
@ -647,8 +702,25 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
*/ */
break; break;
} }
if (options.check_host_ip)
xfree(ip); if (options.check_host_ip && host_status != HOST_CHANGED &&
ip_status == HOST_CHANGED) {
log("Warning: the %s host key for '%.200s' "
"differs from the key for the IP address '%.128s'",
type, host, ip);
if (host_status == HOST_OK)
log("Matching host key in %s:%d", host_file, host_line);
log("Offending key for IP in %s:%d", ip_file, ip_line);
if (options.strict_host_key_checking == 1) {
fatal("Exiting, you have requested strict checking.");
} else if (options.strict_host_key_checking == 2) {
if (!read_yes_or_no("Are you sure you want " \
"to continue connecting (yes/no)? ", -1))
fatal("Aborted by user!");
}
}
xfree(ip);
} }
#ifdef KRB5 #ifdef KRB5
@ -857,17 +929,12 @@ send_krb5_tgt(krb5_context context, krb5_auth_context auth_context)
* This function does not require super-user privileges. * This function does not require super-user privileges.
*/ */
void void
ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost, ssh_login(Key **keys, int nkeys, const char *orighost,
struct sockaddr *hostaddr, uid_t original_real_uid) struct sockaddr *hostaddr, struct passwd *pw)
{ {
struct passwd *pw;
char *host, *cp; char *host, *cp;
char *server_user, *local_user; char *server_user, *local_user;
/* Get local user name. Use it as server user if no user name was given. */
pw = getpwuid(original_real_uid);
if (!pw)
fatal("User id %u not found from user database.", original_real_uid);
local_user = xstrdup(pw->pw_name); local_user = xstrdup(pw->pw_name);
server_user = options.user ? options.user : local_user; server_user = options.user ? options.user : local_user;
@ -887,10 +954,10 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
/* authenticate user */ /* authenticate user */
if (compat20) { if (compat20) {
ssh_kex2(host, hostaddr); ssh_kex2(host, hostaddr);
ssh_userauth2(server_user, host); ssh_userauth2(local_user, server_user, host, keys, nkeys);
} else { } else {
ssh_kex(host, hostaddr); ssh_kex(host, hostaddr);
ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key); ssh_userauth1(local_user, server_user, host, keys, nkeys);
} }
} }
@ -900,6 +967,10 @@ ssh_put_password(char *password)
int size; int size;
char *padded; char *padded;
if (datafellows & SSH_BUG_PASSWORDPAD) {
packet_put_string(password, strlen(password));
return;
}
size = roundup(strlen(password) + 1, 32); size = roundup(strlen(password) + 1, 32);
padded = xmalloc(size); padded = xmalloc(size);
memset(padded, 0, size); memset(padded, 0, size);

View File

@ -1,3 +1,6 @@
/* $OpenBSD: sshconnect.h,v 1.9 2001/04/12 19:15:25 markus Exp $ */
/* $FreeBSD$ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -20,23 +23,33 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/ */
#ifndef SSHCONNECT_H #ifndef SSHCONNECT_H
#define SSHCONNECT_H #define SSHCONNECT_H
int
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
u_short port, int connection_attempts,
int anonymous, struct passwd *pw,
const char *proxy_command);
void
ssh_login(Key **keys, int nkeys, const char *orighost,
struct sockaddr *hostaddr, struct passwd *pw);
void void
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
const char *user_hostfile, const char *system_hostfile); const char *user_hostfile, const char *system_hostfile);
void ssh_kex(char *host, struct sockaddr *hostaddr); 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_kex2(char *host, struct sockaddr *hostaddr);
void ssh_userauth2(const char *server_user, char *host);
void
ssh_userauth1(const char *local_user, const char *server_user, char *host,
Key **keys, int nkeys);
void
ssh_userauth2(const char *local_user, const char *server_user, char *host,
Key **keys, int nkeys);
void ssh_put_password(char *password); void ssh_put_password(char *password);

View File

@ -13,30 +13,41 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshconnect1.c,v 1.8 2000/10/12 09:59:19 markus Exp $"); RCSID("$OpenBSD: sshconnect1.c,v 1.31 2001/04/17 08:14:01 markus Exp $");
RCSID("$FreeBSD$"); RCSID("$FreeBSD$");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#ifdef KRB4
#include <krb.h>
#endif
#ifdef AFS
#include <kafs.h>
#include "radix.h"
#endif
#include "ssh.h"
#include "ssh1.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "rsa.h" #include "rsa.h"
#include "ssh.h"
#include "buffer.h" #include "buffer.h"
#include "packet.h" #include "packet.h"
#include "mpaux.h" #include "mpaux.h"
#include "uidswap.h" #include "uidswap.h"
#include "log.h"
#include "readconf.h" #include "readconf.h"
#include "key.h" #include "key.h"
#include "authfd.h" #include "authfd.h"
#include "sshconnect.h" #include "sshconnect.h"
#include "authfile.h" #include "authfile.h"
#include "readpass.h"
#include "cipher.h"
#include "canohost.h"
/* Session id for the current session. */ /* Session id for the current session. */
unsigned char session_id[16]; u_char session_id[16];
unsigned int supported_authentications = 0; u_int supported_authentications = 0;
extern Options options; extern Options options;
extern char *__progname; extern char *__progname;
@ -46,13 +57,13 @@ extern char *__progname;
* authenticate using the agent. * authenticate using the agent.
*/ */
int int
try_agent_authentication() try_agent_authentication(void)
{ {
int type; int type;
char *comment; char *comment;
AuthenticationConnection *auth; AuthenticationConnection *auth;
unsigned char response[16]; u_char response[16];
unsigned int i; u_int i;
int plen, clen; int plen, clen;
Key *key; Key *key;
BIGNUM *challenge; BIGNUM *challenge;
@ -63,7 +74,6 @@ try_agent_authentication()
return 0; return 0;
challenge = BN_new(); challenge = BN_new();
key = key_new(KEY_RSA);
/* Loop through identities served by the agent. */ /* Loop through identities served by the agent. */
for (key = ssh_get_first_identity(auth, &comment, 1); for (key = ssh_get_first_identity(auth, &comment, 1);
@ -126,6 +136,7 @@ try_agent_authentication()
/* The server returns success if it accepted the authentication. */ /* The server returns success if it accepted the authentication. */
if (type == SSH_SMSG_SUCCESS) { if (type == SSH_SMSG_SUCCESS) {
ssh_close_authentication_connection(auth);
BN_clear_free(challenge); BN_clear_free(challenge);
debug("RSA authentication accepted by server."); debug("RSA authentication accepted by server.");
return 1; return 1;
@ -135,6 +146,7 @@ try_agent_authentication()
packet_disconnect("Protocol error waiting RSA auth response: %d", packet_disconnect("Protocol error waiting RSA auth response: %d",
type); type);
} }
ssh_close_authentication_connection(auth);
BN_clear_free(challenge); BN_clear_free(challenge);
debug("RSA authentication using agent refused."); debug("RSA authentication using agent refused.");
return 0; return 0;
@ -147,7 +159,7 @@ try_agent_authentication()
void void
respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
{ {
unsigned char buf[32], response[16]; u_char buf[32], response[16];
MD5_CTX md; MD5_CTX md;
int i, len; int i, len;
@ -200,9 +212,9 @@ try_rsa_authentication(const char *authfile)
int plen, clen; int plen, clen;
/* Try to load identification for the authentication key. */ /* Try to load identification for the authentication key. */
public = key_new(KEY_RSA); /* XXKEYLOAD */
if (!load_public_key(authfile, public, &comment)) { public = key_load_public_type(KEY_RSA1, authfile, &comment);
key_free(public); if (public == NULL) {
/* Could not load it. Fail. */ /* Could not load it. Fail. */
return 0; return 0;
} }
@ -241,12 +253,12 @@ try_rsa_authentication(const char *authfile)
debug("Received RSA challenge from server."); debug("Received RSA challenge from server.");
private = key_new(KEY_RSA);
/* /*
* Load the private key. Try first with empty passphrase; if it * Load the private key. Try first with empty passphrase; if it
* fails, ask for a passphrase. * fails, ask for a passphrase.
*/ */
if (!load_private_key(authfile, "", private, NULL)) { private = key_load_private_type(KEY_RSA1, authfile, "", NULL);
if (private == NULL) {
char buf[300]; char buf[300];
snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
comment); comment);
@ -259,7 +271,8 @@ try_rsa_authentication(const char *authfile)
} }
/* Load the authentication file using the pasphrase. */ /* Load the authentication file using the pasphrase. */
if (!load_private_key(authfile, passphrase, private, NULL)) { private = key_load_private_type(KEY_RSA1, authfile, passphrase, NULL);
if (private == NULL) {
memset(passphrase, 0, strlen(passphrase)); memset(passphrase, 0, strlen(passphrase));
xfree(passphrase); xfree(passphrase);
error("Bad passphrase."); error("Bad passphrase.");
@ -274,6 +287,7 @@ try_rsa_authentication(const char *authfile)
/* Expect the server to reject it... */ /* Expect the server to reject it... */
packet_read_expect(&plen, SSH_SMSG_FAILURE); packet_read_expect(&plen, SSH_SMSG_FAILURE);
xfree(comment); xfree(comment);
BN_clear_free(challenge);
return 0; return 0;
} }
/* Destroy the passphrase. */ /* Destroy the passphrase. */
@ -309,7 +323,7 @@ try_rsa_authentication(const char *authfile)
* authentication and RSA host authentication. * authentication and RSA host authentication.
*/ */
int int
try_rhosts_rsa_authentication(const char *local_user, RSA * host_key) try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
{ {
int type; int type;
BIGNUM *challenge; BIGNUM *challenge;
@ -320,9 +334,9 @@ try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
/* Tell the server that we are willing to authenticate using this key. */ /* Tell the server that we are willing to authenticate using this key. */
packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
packet_put_string(local_user, strlen(local_user)); packet_put_string(local_user, strlen(local_user));
packet_put_int(BN_num_bits(host_key->n)); packet_put_int(BN_num_bits(host_key->rsa->n));
packet_put_bignum(host_key->e); packet_put_bignum(host_key->rsa->e);
packet_put_bignum(host_key->n); packet_put_bignum(host_key->rsa->n);
packet_send(); packet_send();
packet_write_wait(); packet_write_wait();
@ -348,7 +362,7 @@ try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
debug("Received RSA challenge for host key from server."); debug("Received RSA challenge for host key from server.");
/* Compute a response to the challenge. */ /* Compute a response to the challenge. */
respond_to_rsa_challenge(challenge, host_key); respond_to_rsa_challenge(challenge, host_key->rsa);
/* We no longer need the challenge. */ /* We no longer need the challenge. */
BN_clear_free(challenge); BN_clear_free(challenge);
@ -367,7 +381,7 @@ try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
#ifdef KRB4 #ifdef KRB4
int int
try_krb4_authentication() try_krb4_authentication(void)
{ {
KTEXT_ST auth; /* Kerberos data */ KTEXT_ST auth; /* Kerberos data */
char *reply; char *reply;
@ -386,11 +400,11 @@ try_krb4_authentication()
if (stat(tkt_string(), &st) < 0) if (stat(tkt_string(), &st) < 0)
return 0; return 0;
strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ); strncpy(inst, (char *) krb_get_phost(get_canonical_hostname(1)), INST_SZ);
realm = (char *) krb_realmofhost(get_canonical_hostname()); realm = (char *) krb_realmofhost(get_canonical_hostname(1));
if (!realm) { if (!realm) {
debug("Kerberos V4: no realm for %s", get_canonical_hostname()); debug("Kerberos V4: no realm for %s", get_canonical_hostname(1));
return 0; return 0;
} }
/* This can really be anything. */ /* This can really be anything. */
@ -445,7 +459,7 @@ try_krb4_authentication()
debug("Kerberos V4 authentication accepted."); debug("Kerberos V4 authentication accepted.");
/* Get server's response. */ /* Get server's response. */
reply = packet_get_string((unsigned int *) &auth.length); reply = packet_get_string((u_int *) &auth.length);
memcpy(auth.dat, reply, auth.length); memcpy(auth.dat, reply, auth.length);
xfree(reply); xfree(reply);
@ -484,7 +498,7 @@ try_krb4_authentication()
#ifdef AFS #ifdef AFS
int int
send_krb4_tgt() send_krb4_tgt(void)
{ {
CREDENTIALS *creds; CREDENTIALS *creds;
char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
@ -510,7 +524,7 @@ send_krb4_tgt()
debug("Kerberos V4 ticket expired: %s", TKT_FILE); debug("Kerberos V4 ticket expired: %s", TKT_FILE);
return 0; return 0;
} }
creds_to_radix(creds, (unsigned char *)buffer, sizeof buffer); creds_to_radix(creds, (u_char *)buffer, sizeof buffer);
xfree(creds); xfree(creds);
packet_start(SSH_CMSG_HAVE_KRB4_TGT); packet_start(SSH_CMSG_HAVE_KRB4_TGT);
@ -549,10 +563,10 @@ send_afs_tokens(void)
p = buf; p = buf;
/* Get secret token. */ /* Get secret token. */
memcpy(&creds.ticket_st.length, p, sizeof(unsigned int)); memcpy(&creds.ticket_st.length, p, sizeof(u_int));
if (creds.ticket_st.length > MAX_KTXT_LEN) if (creds.ticket_st.length > MAX_KTXT_LEN)
break; break;
p += sizeof(unsigned int); p += sizeof(u_int);
memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
p += creds.ticket_st.length; p += creds.ticket_st.length;
@ -578,7 +592,7 @@ send_afs_tokens(void)
creds.pinst[0] = '\0'; creds.pinst[0] = '\0';
/* Encode token, ship it off. */ /* Encode token, ship it off. */
if (creds_to_radix(&creds, (unsigned char*) buffer, sizeof buffer) <= 0) if (creds_to_radix(&creds, (u_char *) buffer, sizeof buffer) <= 0)
break; break;
packet_start(SSH_CMSG_HAVE_AFS_TOKEN); packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
packet_put_string(buffer, strlen(buffer)); packet_put_string(buffer, strlen(buffer));
@ -603,14 +617,15 @@ send_afs_tokens(void)
* Note that the client code is not tied to s/key or TIS. * Note that the client code is not tied to s/key or TIS.
*/ */
int int
try_skey_authentication() try_challenge_reponse_authentication(void)
{ {
int type, i; int type, i;
int payload_len; int payload_len;
unsigned int clen; u_int clen;
char prompt[1024];
char *challenge, *response; char *challenge, *response;
debug("Doing skey authentication."); debug("Doing challenge reponse authentication.");
/* request a challenge */ /* request a challenge */
packet_start(SSH_CMSG_AUTH_TIS); packet_start(SSH_CMSG_AUTH_TIS);
@ -636,9 +651,36 @@ try_skey_authentication()
xfree(challenge); xfree(challenge);
fflush(stderr); fflush(stderr);
for (i = 0; i < options.number_of_password_prompts; i++) { for (i = 0; i < options.number_of_password_prompts; i++) {
/* request a challenge */
packet_start(SSH_CMSG_AUTH_TIS);
packet_send();
packet_write_wait();
type = packet_read(&payload_len);
if (type != SSH_SMSG_FAILURE &&
type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
packet_disconnect("Protocol error: got %d in response "
"to SSH_CMSG_AUTH_TIS", type);
}
if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) {
debug("No challenge.");
return 0;
}
challenge = packet_get_string(&clen);
packet_integrity_check(payload_len, (4 + clen), type);
snprintf(prompt, sizeof prompt, "%s%s", challenge,
strchr(challenge, '\n') ? "" : "\nResponse: ");
xfree(challenge);
if (i != 0) if (i != 0)
error("Permission denied, please try again."); error("Permission denied, please try again.");
response = read_passphrase("Response: ", 0); if (options.cipher == SSH_CIPHER_NONE)
log("WARNING: Encryption is disabled! "
"Reponse will be transmitted in clear text.");
response = read_passphrase(prompt, 0);
if (strcmp(response, "") == 0) {
xfree(response);
break;
}
packet_start(SSH_CMSG_AUTH_TIS_RESPONSE); packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
ssh_put_password(response); ssh_put_password(response);
memset(response, 0, strlen(response)); memset(response, 0, strlen(response));
@ -650,7 +692,7 @@ try_skey_authentication()
return 1; return 1;
if (type != SSH_SMSG_FAILURE) if (type != SSH_SMSG_FAILURE)
packet_disconnect("Protocol error: got %d in response " packet_disconnect("Protocol error: got %d in response "
"to skey-auth-reponse", type); "to SSH_CMSG_AUTH_TIS_RESPONSE", type);
} }
/* failure */ /* failure */
return 0; return 0;
@ -702,10 +744,10 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
Key k; Key k;
int bits, rbits; int bits, rbits;
int ssh_cipher_default = SSH_CIPHER_3DES; int ssh_cipher_default = SSH_CIPHER_3DES;
unsigned char session_key[SSH_SESSION_KEY_LENGTH]; u_char session_key[SSH_SESSION_KEY_LENGTH];
unsigned char cookie[8]; u_char cookie[8];
unsigned int supported_ciphers; u_int supported_ciphers;
unsigned int server_flags, client_flags; u_int server_flags, client_flags;
int payload_len, clen, sum_len = 0; int payload_len, clen, sum_len = 0;
u_int32_t rand = 0; u_int32_t rand = 0;
@ -764,7 +806,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
packet_integrity_check(payload_len, packet_integrity_check(payload_len,
8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
SSH_SMSG_PUBLIC_KEY); SSH_SMSG_PUBLIC_KEY);
k.type = KEY_RSA; k.type = KEY_RSA1;
k.rsa = host_key; k.rsa = host_key;
check_host_key(host, hostaddr, &k, check_host_key(host, hostaddr, &k,
options.user_hostfile, options.system_hostfile); options.user_hostfile, options.system_hostfile);
@ -837,13 +879,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
RSA_free(public_key); RSA_free(public_key);
RSA_free(host_key); RSA_free(host_key);
if (options.cipher == SSH_CIPHER_ILLEGAL) { if (options.cipher == SSH_CIPHER_NOT_SET) {
if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default))
options.cipher = ssh_cipher_default;
} else if (options.cipher == SSH_CIPHER_ILLEGAL ||
!(cipher_mask_ssh1(1) & (1 << options.cipher))) {
log("No valid SSH1 cipher, using %.100s instead.", log("No valid SSH1 cipher, using %.100s instead.",
cipher_name(ssh_cipher_default)); cipher_name(ssh_cipher_default));
options.cipher = ssh_cipher_default; options.cipher = ssh_cipher_default;
} else if (options.cipher == SSH_CIPHER_NOT_SET) {
if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default))
options.cipher = ssh_cipher_default;
} }
/* Check that the selected cipher is supported. */ /* Check that the selected cipher is supported. */
if (!(supported_ciphers & (1 << options.cipher))) if (!(supported_ciphers & (1 << options.cipher)))
@ -892,17 +935,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
* Authenticate user * Authenticate user
*/ */
void void
ssh_userauth( ssh_userauth1(const char *local_user, const char *server_user, char *host,
const char* local_user, Key **keys, int nkeys)
const char* server_user,
char *host,
int host_key_valid, RSA *own_host_key)
{ {
int i, type; int i, type;
int payload_len; int payload_len;
if (supported_authentications == 0) if (supported_authentications == 0)
fatal("ssh_userauth: server supports no auth methods"); fatal("ssh_userauth1: server supports no auth methods");
/* Send the name of the user to log in as on the server. */ /* Send the name of the user to log in as on the server. */
packet_start(SSH_CMSG_USER); packet_start(SSH_CMSG_USER);
@ -1011,9 +1051,12 @@ ssh_userauth(
* authentication. * authentication.
*/ */
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
options.rhosts_rsa_authentication && host_key_valid) { options.rhosts_rsa_authentication) {
if (try_rhosts_rsa_authentication(local_user, own_host_key)) for (i = 0; i < nkeys; i++) {
return; if (keys[i] != NULL && keys[i]->type == KEY_RSA1 &&
try_rhosts_rsa_authentication(local_user, keys[i]))
return;
}
} }
/* Try RSA authentication if the server supports it. */ /* Try RSA authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_RSA)) && if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
@ -1028,13 +1071,15 @@ ssh_userauth(
/* Try RSA authentication for each identity. */ /* Try RSA authentication for each identity. */
for (i = 0; i < options.num_identity_files; i++) for (i = 0; i < options.num_identity_files; i++)
if (try_rsa_authentication(options.identity_files[i])) if (options.identity_keys[i] != NULL &&
options.identity_keys[i]->type == KEY_RSA1 &&
try_rsa_authentication(options.identity_files[i]))
return; return;
} }
/* Try skey authentication if the server supports it. */ /* Try challenge response authentication if the server supports it. */
if ((supported_authentications & (1 << SSH_AUTH_TIS)) && if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
options.skey_authentication && !options.batch_mode) { options.challenge_reponse_authentication && !options.batch_mode) {
if (try_skey_authentication()) if (try_challenge_reponse_authentication())
return; return;
} }
/* Try password authentication if the server supports it. */ /* Try password authentication if the server supports it. */
@ -1042,7 +1087,7 @@ ssh_userauth(
options.password_authentication && !options.batch_mode) { options.password_authentication && !options.batch_mode) {
char prompt[80]; char prompt[80];
snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
server_user, host); server_user, host);
if (try_password_authentication(prompt)) if (try_password_authentication(prompt))
return; return;

File diff suppressed because it is too large Load Diff

View File

@ -10,9 +10,9 @@
.\" incompatible with the protocol description in the RFC file, it must be .\" incompatible with the protocol description in the RFC file, it must be
.\" called by a name other than "ssh" or "Secure Shell". .\" called by a name other than "ssh" or "Secure Shell".
.\" .\"
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. .\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. .\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. .\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions .\" modification, are permitted provided that the following conditions
@ -34,6 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd.8,v 1.120 2001/04/22 23:58:36 markus Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 25, 1999 .Dd September 25, 1999
@ -41,10 +42,10 @@
.Os .Os
.Sh NAME .Sh NAME
.Nm sshd .Nm sshd
.Nd secure shell daemon .Nd OpenSSH SSH daemon
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm sshd .Nm sshd
.Op Fl diqQ46 .Op Fl deiqD46
.Op Fl b Ar bits .Op Fl b Ar bits
.Op Fl f Ar config_file .Op Fl f Ar config_file
.Op Fl g Ar login_grace_time .Op Fl g Ar login_grace_time
@ -55,7 +56,7 @@
.Op Fl V Ar client_protocol_id .Op Fl V Ar client_protocol_id
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
(Secure Shell Daemon) is the daemon program for (SSH Daemon) is the daemon program for
.Xr ssh 1 . .Xr ssh 1 .
Together these programs replace rlogin and rsh, and Together these programs replace rlogin and rsh, and
provide secure encrypted communications between two untrusted hosts provide secure encrypted communications between two untrusted hosts
@ -135,9 +136,9 @@ Each host has a host-specific DSA key used to identify the host.
However, when the daemon starts, it does not generate a server key. However, when the daemon starts, it does not generate a server key.
Forward security is provided through a Diffie-Hellman key agreement. Forward security is provided through a Diffie-Hellman key agreement.
This key agreement results in a shared session key. This key agreement results in a shared session key.
The rest of the session is encrypted .Pp
using a symmetric cipher, currently The rest of the session is encrypted using a symmetric cipher, currently
Blowfish, 3DES or CAST128 in CBC mode or Arcfour. 128 bit AES, Blowfish, 3DES, CAST128, Arcfour, 192 bit AES, or 256 bit AES.
The client selects the encryption algorithm The client selects the encryption algorithm
to use from those offered by the server. to use from those offered by the server.
Additionally, session integrity is provided Additionally, session integrity is provided
@ -145,8 +146,9 @@ through a cryptographic message authentication code
(hmac-sha1 or hmac-md5). (hmac-sha1 or hmac-md5).
.Pp .Pp
Protocol version 2 provides a public key based Protocol version 2 provides a public key based
user authentication method (DSAAuthentication) user (PubkeyAuthentication) or
and conventional password authentication. client host (HostbasedAuthentication) authentication method,
conventional password authentication and challenge response based methods.
.Pp .Pp
.Ss Command execution and data forwarding .Ss Command execution and data forwarding
.Pp .Pp
@ -175,12 +177,15 @@ configuration file.
.Pp .Pp
.Nm .Nm
rereads its configuration file when it receives a hangup signal, rereads its configuration file when it receives a hangup signal,
.Dv SIGHUP . .Dv SIGHUP ,
by executing itself with the name it was started as, ie.
.Pa /usr/sbin/sshd .
.Pp .Pp
The options are as follows: The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl b Ar bits .It Fl b Ar bits
Specifies the number of bits in the server key (default 768). Specifies the number of bits in the ephemeral protocol version 1
server key (default 768).
.Pp .Pp
.It Fl d .It Fl d
Debug mode. Debug mode.
@ -188,8 +193,12 @@ The server sends verbose debug output to the system
log, and does not put itself in the background. log, and does not put itself in the background.
The server also will not fork and will only process one connection. The server also will not fork and will only process one connection.
This option is only intended for debugging for the server. This option is only intended for debugging for the server.
Multiple -d options increases the debugging level. Multiple -d options increase the debugging level.
Maximum is 3. Maximum is 3.
.It Fl e
When this option is specified,
.Nm
will send the output to the standard error instead of the system log.
.It Fl f Ar configuration_file .It Fl f Ar configuration_file
Specifies the name of the configuration file. Specifies the name of the configuration file.
The default is The default is
@ -198,17 +207,19 @@ The default is
refuses to start if there is no configuration file. refuses to start if there is no configuration file.
.It Fl g Ar login_grace_time .It Fl g Ar login_grace_time
Gives the grace time for clients to authenticate themselves (default Gives the grace time for clients to authenticate themselves (default
300 seconds). 600 seconds).
If the client fails to authenticate the user within If the client fails to authenticate the user within
this many seconds, the server disconnects and exits. this many seconds, the server disconnects and exits.
A value of zero indicates no limit. A value of zero indicates no limit.
.It Fl h Ar host_key_file .It Fl h Ar host_key_file
Specifies the file from which the RSA host key is read (default Specifies the file from which the host key is read (default
.Pa /etc/ssh/ssh_host_key ) . .Pa /etc/ssh/ssh_host_key ) .
This option must be given if This option must be given if
.Nm .Nm
is not run as root (as the normal is not run as root (as the normal
host file is normally not readable by anyone but root). host file is normally not readable by anyone but root).
It is possible to have multiple host key files for
the different protocol versions and host key algorithms.
.It Fl i .It Fl i
Specifies that Specifies that
.Nm .Nm
@ -223,8 +234,8 @@ However, with small key sizes (e.g., 512) using
from inetd may from inetd may
be feasible. be feasible.
.It Fl k Ar key_gen_time .It Fl k Ar key_gen_time
Specifies how often the server key is regenerated (default 3600 Specifies how often the ephemeral protocol version 1 server key is
seconds, or one hour). regenerated (default 3600 seconds, or one hour).
The motivation for regenerating the key fairly The motivation for regenerating the key fairly
often is that the key is not stored anywhere, and after about an hour, often is that the key is not stored anywhere, and after about an hour,
it becomes impossible to recover the key for decrypting intercepted it becomes impossible to recover the key for decrypting intercepted
@ -255,16 +266,12 @@ indicates that only dotted decimal addresses
should be put into the should be put into the
.Pa utmp .Pa utmp
file. file.
.It Fl Q .It Fl D
Do not print an error message if RSA support is missing.
.It Fl V Ar client_protocol_id
SSH-2 compatibility mode.
When this option is specified When this option is specified
.Nm .Nm
assumes the client has sent the supplied version string will not detach and does not become a daemon.
and skips the This allows easy monitoring of
Protocol Version Identification Exchange. .Nm sshd .
This option is not intended to be called directly.
.It Fl 4 .It Fl 4
Forces Forces
.Nm .Nm
@ -293,17 +300,17 @@ Specifies whether an AFS token may be forwarded to the server.
Default is Default is
.Dq yes . .Dq yes .
.It Cm AllowGroups .It Cm AllowGroups
This keyword can be followed by a number of group names, separated This keyword can be followed by a list of group names, separated
by spaces. by spaces.
If specified, login is allowed only for users whose primary If specified, login is allowed only for users whose primary
group matches one of the patterns. group or supplementary group list matches one of the patterns.
.Ql \&* .Ql \&*
and and
.Ql ? .Ql ?
can be used as can be used as
wildcards in the patterns. wildcards in the patterns.
Only group names are valid; a numerical group ID isn't recognized. Only group names are valid; a numerical group ID isn't recognized.
By default login is allowed regardless of the primary group. By default login is allowed regardless of the group list.
.Pp .Pp
.It Cm AllowTcpForwarding .It Cm AllowTcpForwarding
Specifies whether TCP forwarding is permitted. Specifies whether TCP forwarding is permitted.
@ -314,7 +321,7 @@ users are also denied shell access, as they can always install their
own forwarders. own forwarders.
.Pp .Pp
.It Cm AllowUsers .It Cm AllowUsers
This keyword can be followed by a number of user names, separated This keyword can be followed by a list of user names, separated
by spaces. by spaces.
If specified, login is allowed only for users names that If specified, login is allowed only for users names that
match one of the patterns. match one of the patterns.
@ -326,29 +333,76 @@ wildcards in the patterns.
Only user names are valid; a numerical user ID isn't recognized. Only user names are valid; a numerical user ID isn't recognized.
By default login is allowed regardless of the user name. By default login is allowed regardless of the user name.
.Pp .Pp
.It Cm Banner
In some jurisdictions, sending a warning message before authentication
may be relevant for getting legal protection.
The contents of the specified file are sent to the remote user before
authentication is allowed.
This option is only available for protocol version 2.
.Pp
.It Cm ChallengeResponseAuthentication
Specifies whether
challenge response
authentication is allowed.
Currently there is only support for
.Xr skey 1
authentication.
The default is
.Dq yes .
.It Cm Ciphers .It Cm Ciphers
Specifies the ciphers allowed for protocol version 2. Specifies the ciphers allowed for protocol version 2.
Multiple ciphers must be comma-separated. Multiple ciphers must be comma-separated.
The default is The default is
.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc . .Dq aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour.
.It Cm CheckMail .It Cm CheckMail
Specifies whether Specifies whether
.Nm .Nm
should check for new mail for interactive logins. should check for new mail for interactive logins.
The default is The default is
.Dq yes . .Dq yes .
.It Cm ClientAliveInterval
Sets a timeout interval in seconds after which if no data has been received
from the client,
.Nm
will send a message through the encrypted
channel to request a response from the client.
The default
is 0, indicating that these messages will not be sent to the client.
This option applies to protocol version 2 only.
.It Cm ClientAliveCountMax
Sets the number of client alive messages (see above) which may be
sent without
.Nm
receiving any messages back from the client. If this threshold is
reached while client alive messages are being sent,
.Nm
will disconnect the client, terminating the session. It is important
to note that the use of client alive messages is very different from
.Cm Keepalive
(below). The client alive messages are sent through the
encrypted channel and therefore will not be spoofable. The TCP keepalive
option enabled by
.Cm Keepalive
is spoofable. You want to use the client
alive mechanism when you are basing something important on
clients having an active connection to the server.
.Pp
The default value is 3. If you set
.Cm ClientAliveInterval
(above) to 15, and leave this value at the default, unresponsive ssh clients
will be disconnected after approximately 45 seconds.
.It Cm DenyGroups .It Cm DenyGroups
This keyword can be followed by a number of group names, separated This keyword can be followed by a number of group names, separated
by spaces. by spaces.
Users whose primary group matches one of the patterns Users whose primary group or supplementary group list matches
aren't allowed to log in. one of the patterns aren't allowed to log in.
.Ql \&* .Ql \&*
and and
.Ql ? .Ql ?
can be used as can be used as
wildcards in the patterns. wildcards in the patterns.
Only group names are valid; a numerical group ID isn't recognized. Only group names are valid; a numerical group ID isn't recognized.
By default login is allowed regardless of the primary group. By default login is allowed regardless of the group list.
.Pp .Pp
.It Cm DenyUsers .It Cm DenyUsers
This keyword can be followed by a number of user names, separated This keyword can be followed by a number of user names, separated
@ -360,11 +414,6 @@ and
can be used as wildcards in the patterns. can be used as wildcards in the patterns.
Only user names are valid; a numerical user ID isn't recognized. Only user names are valid; a numerical user ID isn't recognized.
By default login is allowed regardless of the user name. By default login is allowed regardless of the user name.
.It Cm DSAAuthentication
Specifies whether DSA authentication is allowed.
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
.It Cm GatewayPorts .It Cm GatewayPorts
Specifies whether remote hosts are allowed to connect to ports Specifies whether remote hosts are allowed to connect to ports
forwarded for the client. forwarded for the client.
@ -374,26 +423,40 @@ or
.Dq no . .Dq no .
The default is The default is
.Dq no . .Dq no .
.It Cm HostDSAKey .It Cm HostbasedAuthentication
Specifies the file containing the private DSA host key (default Specifies whether rhosts or /etc/hosts.equiv authentication together
.Pa /etc/ssh/ssh_host_dsa_key ) with successful public key client host authentication is allowed
used by SSH protocol 2.0. (hostbased authentication).
Note that This option is similar to
.Nm .Cm RhostsRSAAuthentication
disables protocol 2.0 if this file is group/world-accessible. and applies to protocol version 2 only.
The default is
.Dq no .
.It Cm HostKey .It Cm HostKey
Specifies the file containing the private RSA host key (default Specifies the file containing the private host keys (default
.Pa /etc/ssh/ssh_host_key ) .Pa /etc/ssh/ssh_host_key )
used by SSH protocols 1.3 and 1.5. used by SSH protocol versions 1 and 2.
Note that Note that
.Nm .Nm
disables protocols 1.3 and 1.5 if this file is group/world-accessible. will refuse to use a file if it is group/world-accessible.
It is possible to have multiple host key files.
.Dq rsa1
keys are used for version 1 and
.Dq dsa
or
.Dq rsa
are used for version 2 of the SSH protocol.
.It Cm IgnoreRhosts .It Cm IgnoreRhosts
Specifies that Specifies that
.Pa .rhosts .Pa .rhosts
and and
.Pa .shosts .Pa .shosts
files will not be used in authentication. files will not be used in
.Cm RhostsAuthentication ,
.Cm RhostsRSAAuthentication
or
.Cm HostbasedAuthentication .
.Pp
.Pa /etc/hosts.equiv .Pa /etc/hosts.equiv
and and
.Pa /etc/ssh/shosts.equiv .Pa /etc/ssh/shosts.equiv
@ -406,7 +469,9 @@ Specifies whether
should ignore the user's should ignore the user's
.Pa $HOME/.ssh/known_hosts .Pa $HOME/.ssh/known_hosts
during during
.Cm RhostsRSAAuthentication . .Cm RhostsRSAAuthentication
or
.Cm HostbasedAuthentication .
The default is The default is
.Dq no . .Dq no .
.It Cm KeepAlive .It Cm KeepAlive
@ -459,8 +524,8 @@ file on logout.
Default is Default is
.Dq yes . .Dq yes .
.It Cm KeyRegenerationInterval .It Cm KeyRegenerationInterval
The server key is automatically regenerated after this many seconds In protocol version 1, the ephemeral server key is automatically regenerated
(if it has been used). after this many seconds (if it has been used).
The purpose of regeneration is to prevent The purpose of regeneration is to prevent
decrypting captured sessions by later breaking into the machine and decrypting captured sessions by later breaking into the machine and
stealing the keys. stealing the keys.
@ -468,14 +533,42 @@ The key is never stored anywhere.
If the value is 0, the key is never regenerated. If the value is 0, the key is never regenerated.
The default is 3600 (seconds). The default is 3600 (seconds).
.It Cm ListenAddress .It Cm ListenAddress
Specifies what local address Specifies the local addresses
.Nm .Nm
should listen on. should listen on.
The default is to listen to all local addresses. The following forms may be used:
Multiple options of this type are permitted. .Pp
Additionally, the .Bl -item -offset indent -compact
.Cm Ports .It
options must precede this option. .Cm ListenAddress
.Sm off
.Ar host No | Ar IPv4_addr No | Ar IPv6_addr
.Sm on
.It
.Cm ListenAddress
.Sm off
.Ar host No | Ar IPv4_addr No : Ar port
.Sm on
.It
.Cm ListenAddress
.Sm off
.Oo
.Ar host No | Ar IPv6_addr Oc : Ar port
.Sm on
.El
.Pp
If
.Ar port
is not specified,
.Nm
will listen on the address and all prior
.Cm Port
options specified. The default is to listen on all local
addresses. Multiple
.Cm ListenAddress
options are permitted. Additionally, any
.Cm Port
options must precede this option for non port qualified addresses.
.It Cm LoginGraceTime .It Cm LoginGraceTime
The server disconnects after this time if the user has not The server disconnects after this time if the user has not
successfully logged in. successfully logged in.
@ -489,6 +582,17 @@ QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
The default is INFO. The default is INFO.
Logging with level DEBUG violates the privacy of users Logging with level DEBUG violates the privacy of users
and is not recommended. and is not recommended.
.It Cm MACs
Specifies the available MAC (message authentication code) algorithms.
The MAC algorithm is used in protocol version 2
for data integrity protection.
Multiple algorithms must be comma-separated.
The default is
.Pp
.Bd -literal
``hmac-md5,hmac-sha1,hmac-ripemd160,hmac-ripemd160@openssh.com,
hmac-sha1-96,hmac-md5-96''
.Ed
.It Cm MaxStartups .It Cm MaxStartups
Specifies the maximum number of concurrent unauthenticated connections to the Specifies the maximum number of concurrent unauthenticated connections to the
.Nm .Nm
@ -503,14 +607,14 @@ the three colon separated values
.Dq start:rate:full .Dq start:rate:full
(e.g., "10:30:60"). (e.g., "10:30:60").
.Nm .Nm
will refuse connection attempts with a probabillity of will refuse connection attempts with a probability of
.Dq rate/100 .Dq rate/100
(30%) (30%)
if there are currently if there are currently
.Dq start .Dq start
(10) (10)
unauthenticated connections. unauthenticated connections.
The probabillity increases linearly and all connection attempts The probability increases linearly and all connection attempts
are refused if the number of unauthenticated connections reaches are refused if the number of unauthenticated connections reaches
.Dq full .Dq full
(60). (60).
@ -518,32 +622,40 @@ are refused if the number of unauthenticated connections reaches
Specifies whether password authentication is allowed. Specifies whether password authentication is allowed.
The default is The default is
.Dq yes . .Dq yes .
Note that this option applies to both protocol versions 1 and 2.
.It Cm PermitEmptyPasswords .It Cm PermitEmptyPasswords
When password authentication is allowed, it specifies whether the When password authentication is allowed, it specifies whether the
server allows login to accounts with empty password strings. server allows login to accounts with empty password strings.
The default is The default is
.Dq no . .Dq no .
.It Cm PermitRootLogin .It Cm PermitRootLogin
Specifies whether the root can log in using Specifies whether root can login using
.Xr ssh 1 . .Xr ssh 1 .
The argument must be The argument must be
.Dq yes , .Dq yes ,
.Dq without-password .Dq without-password ,
.Dq forced-commands-only
or or
.Dq no . .Dq no .
The default is The default is
.Dq no . .Dq no .
If this options is set to
.Dq without-password
only password authentication is disabled for root.
.Pp .Pp
Root login with RSA authentication when the If this option is set to
.Dq without-password
password authentication is disabled for root.
.Pp
If this option is set to
.Dq forced-commands-only
root login with public key authentication will be allowed,
but only if the
.Ar command .Ar command
option has been option has been specified
specified will be allowed regardless of the value of this setting
(which may be useful for taking remote backups even if root login is (which may be useful for taking remote backups even if root login is
normally not allowed). normally not allowed). All other authentication methods are disabled
for root.
.Pp
If this option is set to
.Dq no
root is not allowed to login.
.It Cm PidFile .It Cm PidFile
Specifies the file that contains the process identifier of the Specifies the file that contains the process identifier of the
.Nm .Nm
@ -556,6 +668,14 @@ Specifies the port number that
listens on. listens on.
The default is 22. The default is 22.
Multiple options of this type are permitted. Multiple options of this type are permitted.
See also
.Cm ListenAddress .
.It Cm PrintLastLog
Specifies whether
.Nm
should print the date and time when the user last logged in.
The default is
.Dq yes .
.It Cm PrintMotd .It Cm PrintMotd
Specifies whether Specifies whether
.Nm .Nm
@ -577,10 +697,20 @@ and
.Dq 2 . .Dq 2 .
Multiple versions must be comma-separated. Multiple versions must be comma-separated.
The default is The default is
.Dq 1 . .Dq 2,1 .
.It Cm RandomSeed .It Cm PubkeyAuthentication
Obsolete - accepted and ignored with a warning. Specifies whether public key authentication is allowed.
Random number generation uses other techniques. The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
.It Cm ReverseMappingCheck
Specifies whether
.Nm
should try to verify the remote host name and check that
the resolved host name for the remote IP address maps back to the
very same IP address.
The default is
.Dq no .
.It Cm RhostsAuthentication .It Cm RhostsAuthentication
Specifies whether authentication using rhosts or Specifies whether authentication using rhosts or
.Pa /etc/hosts.equiv .Pa /etc/hosts.equiv
@ -594,6 +724,7 @@ to normal rhosts or
authentication. authentication.
The default is The default is
.Dq no . .Dq no .
This option applies to protocol version 1 only.
.It Cm RhostsRSAAuthentication .It Cm RhostsRSAAuthentication
Specifies whether rhosts or Specifies whether rhosts or
.Pa /etc/hosts.equiv .Pa /etc/hosts.equiv
@ -601,13 +732,14 @@ authentication together
with successful RSA host authentication is allowed. with successful RSA host authentication is allowed.
The default is The default is
.Dq no . .Dq no .
This option applies to protocol version 1 only.
.It Cm RSAAuthentication .It Cm RSAAuthentication
Specifies whether pure RSA authentication is allowed. Specifies whether pure RSA authentication is allowed.
The default is The default is
.Dq yes . .Dq yes .
Note that this option applies to protocol version 1 only. This option applies to protocol version 1 only.
.It Cm ServerKeyBits .It Cm ServerKeyBits
Defines the number of bits in the server key. Defines the number of bits in the ephemeral protocol version 1 server key.
The minimum value is 512, and the default is 768. The minimum value is 512, and the default is 768.
.It Cm SkeyAuthentication .It Cm SkeyAuthentication
Specifies whether Specifies whether
@ -725,29 +857,41 @@ Runs user's shell or command.
The The
.Pa $HOME/.ssh/authorized_keys .Pa $HOME/.ssh/authorized_keys
file lists the RSA keys that are file lists the RSA keys that are
permitted for RSA authentication in SSH protocols 1.3 and 1.5 permitted for RSA authentication in protocol version 1
Similarly, the Similarly, the
.Pa $HOME/.ssh/authorized_keys2 .Pa $HOME/.ssh/authorized_keys2
file lists the DSA keys that are file lists the DSA and RSA keys that are
permitted for DSA authentication in SSH protocol 2.0. permitted for public key authentication (PubkeyAuthentication)
in protocol version 2.
.Pp
Each line of the file contains one Each line of the file contains one
key (empty lines and lines starting with a key (empty lines and lines starting with a
.Ql # .Ql #
are ignored as are ignored as
comments). comments).
Each line consists of the following fields, separated by Each RSA public key consists of the following fields, separated by
spaces: options, bits, exponent, modulus, comment. spaces: options, bits, exponent, modulus, comment.
The options field Each protocol version 2 public key consists of:
is optional; its presence is determined by whether the line starts options, keytype, base64 encoded key, comment.
The options fields
are optional; its presence is determined by whether the line starts
with a number or not (the option field never starts with a number). with a number or not (the option field never starts with a number).
The bits, exponent, modulus and comment fields give the RSA key; the The bits, exponent, modulus and comment fields give the RSA key for
protocol version 1; the
comment field is not used for anything (but may be convenient for the comment field is not used for anything (but may be convenient for the
user to identify the key). user to identify the key).
For protocol version 2 the keytype is
.Dq ssh-dss
or
.Dq ssh-rsa .
.Pp .Pp
Note that lines in this file are usually several hundred bytes long Note that lines in this file are usually several hundred bytes long
(because of the size of the RSA key modulus). (because of the size of the RSA key modulus).
You don't want to type them in; instead, copy the You don't want to type them in; instead, copy the
.Pa identity.pub .Pa identity.pub ,
.Pa id_dsa.pub
or the
.Pa id_rsa.pub
file and edit it. file and edit it.
.Pp .Pp
The options (if present) consist of comma-separated option The options (if present) consist of comma-separated option
@ -781,6 +925,9 @@ authentication.
The command supplied by the user (if any) is ignored. The command supplied by the user (if any) is ignored.
The command is run on a pty if the connection requests a pty; The command is run on a pty if the connection requests a pty;
otherwise it is run without a tty. otherwise it is run without a tty.
Note that if you want a 8-bit clean channel,
you must not request a pty or should specify
.Cm no-pty .
A quote may be included in the command by quoting it with a backslash. A quote may be included in the command by quoting it with a backslash.
This option might be useful This option might be useful
to restrict certain RSA keys to perform just a specific operation. to restrict certain RSA keys to perform just a specific operation.
@ -807,13 +954,24 @@ Forbids authentication agent forwarding when this key is used for
authentication. authentication.
.It Cm no-pty .It Cm no-pty
Prevents tty allocation (a request to allocate a pty will fail). Prevents tty allocation (a request to allocate a pty will fail).
.It Cm permitopen="host:port"
Limit local
.Li ``ssh -L''
port forwarding such that it may only connect to the specified host and
port. Multiple
.Cm permitopen
options may be applied separated by commas. No pattern matching is
performed on the specified hostnames, they must be literal domains or
addresses.
.El .El
.Ss Examples .Ss Examples
.Bd -literal 1024 33 12121.\|.\|.\|312314325 ylo@foo.bar
1024 33 12121...312314325 ylo@foo.bar .Pp
from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23...2334 ylo@niksula from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula
command="dump /home",no-pty,no-port-forwarding 1024 33 23...2323 backup.hut.fi .Pp
.Ed command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi
.Pp
permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23.\|.\|.\|2323
.Sh SSH_KNOWN_HOSTS FILE FORMAT .Sh SSH_KNOWN_HOSTS FILE FORMAT
The The
.Pa /etc/ssh/ssh_known_hosts , .Pa /etc/ssh/ssh_known_hosts ,
@ -869,7 +1027,8 @@ or by taking
and adding the host names at the front. and adding the host names at the front.
.Ss Examples .Ss Examples
.Bd -literal .Bd -literal
closenet,closenet.hut.fi,...,130.233.208.41 1024 37 159...93 closenet.hut.fi closenet,.\|.\|.\|,130.233.208.41 1024 37 159.\|.\|.93 closenet.hut.fi
cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234.....=
.Ed .Ed
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds
@ -878,23 +1037,25 @@ Contains configuration data for
.Nm sshd . .Nm sshd .
This file should be writable by root only, but it is recommended This file should be writable by root only, but it is recommended
(though not necessary) that it be world-readable. (though not necessary) that it be world-readable.
.It Pa /etc/ssh/ssh_host_key .It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key
Contains the private part of the host key. These three files contain the private parts of the host keys.
This file should only be owned by root, readable only by root, and not These files should only be owned by root, readable only by root, and not
accessible to others. accessible to others.
Note that Note that
.Nm .Nm
does not start if this file is group/world-accessible. does not start if this file is group/world-accessible.
.It Pa /etc/ssh/ssh_host_key.pub .It Pa /etc/ssh/ssh_host_key.pub, /etc/ssh/ssh_host_dsa_key.pub, /etc/ssh/ssh_host_rsa_key.pub
Contains the public part of the host key. These three files contain the public parts of the host keys.
This file should be world-readable but writable only by These files should be world-readable but writable only by
root. root.
Its contents should match the private part. Their contents should match the respective private parts.
This file is not These files are not
really used for anything; it is only provided for the convenience of really used for anything; they are provided for the convenience of
the user so its contents can be copied to known hosts files. the user so their contents can be copied to known hosts files.
These two files are created using These files are created using
.Xr ssh-keygen 1 . .Xr ssh-keygen 1 .
.It Pa /etc/primes
Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
.It Pa /var/run/sshd.pid .It Pa /var/run/sshd.pid
Contains the process ID of the Contains the process ID of the
.Nm .Nm
@ -914,7 +1075,7 @@ Users will place the contents of their
files into this file, as described in files into this file, as described in
.Xr ssh-keygen 1 . .Xr ssh-keygen 1 .
.It Pa $HOME/.ssh/authorized_keys2 .It Pa $HOME/.ssh/authorized_keys2
Lists the DSA keys that can be used to log into the user's account. Lists the public keys (RSA or DSA) that can be used to log into the user's account.
This file must be readable by root (which may on some machines imply This file must be readable by root (which may on some machines imply
it being world-readable if the user's home directory resides on an NFS it being world-readable if the user's home directory resides on an NFS
volume). volume).
@ -922,6 +1083,8 @@ It is recommended that it not be accessible by others.
The format of this file is described above. The format of this file is described above.
Users will place the contents of their Users will place the contents of their
.Pa id_dsa.pub .Pa id_dsa.pub
and/or
.Pa id_rsa.pub
files into this file, as described in files into this file, as described in
.Xr ssh-keygen 1 . .Xr ssh-keygen 1 .
.It Pa "/etc/ssh/ssh_known_hosts" and "$HOME/.ssh/known_hosts" .It Pa "/etc/ssh/ssh_known_hosts" and "$HOME/.ssh/known_hosts"
@ -929,12 +1092,23 @@ These files are consulted when using rhosts with RSA host
authentication to check the public key of the host. authentication to check the public key of the host.
The key must be listed in one of these files to be accepted. The key must be listed in one of these files to be accepted.
The client uses the same files The client uses the same files
to verify that the remote host is the one it intended to connect. to verify that it is connecting to the correct remote host.
These files should be writable only by root/the owner. These files should be writable only by root/the owner.
.Pa /etc/ssh/ssh_known_hosts .Pa /etc/ssh/ssh_known_hosts
should be world-readable, and should be world-readable, and
.Pa $HOME/.ssh/known_hosts .Pa $HOME/.ssh/known_hosts
can but need not be world-readable. can but need not be world-readable.
.It Pa "/etc/ssh_known_hosts2" and "$HOME/.ssh/known_hosts2"
These files are consulted when using protocol version 2 hostbased
authentication to check the public key of the host.
The key must be listed in one of these files to be accepted.
The client uses the same files
to verify that it is connecting to the correct remote host.
These files should be writable only by root/the owner.
.Pa /etc/ssh_known_hosts2
should be world-readable, and
.Pa $HOME/.ssh/known_hosts2
can but need not be world-readable.
.It Pa /etc/nologin .It Pa /etc/nologin
If this file exists, If this file exists,
.Nm .Nm
@ -1037,7 +1211,7 @@ This file will probably contain some initialization code followed by
something similar to: something similar to:
.Bd -literal -offset indent .Bd -literal -offset indent
if [ -n "$DISPLAY" ] && read proto cookie; then if [ -n "$DISPLAY" ] && read proto cookie; then
echo add $DISPLAY $proto $cookie | xauth -q - echo add "$DISPLAY" "$proto" "$cookie" | xauth -q -
fi fi
.Ed .Ed
.Pp .Pp
@ -1057,45 +1231,42 @@ This can be used to specify
machine-specific login-time initializations globally. machine-specific login-time initializations globally.
This file should be writable only by root, and should be world-readable. This file should be writable only by root, and should be world-readable.
.El .El
.Sh AUTHOR .Sh AUTHORS
OpenSSH OpenSSH is a derivative of the original and free
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen, ssh 1.2.12 release by Tatu Ylonen.
but with bugs removed and newer features re-added. Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
Rapidly after the Theo de Raadt and Dug Song
1.2.12 release, newer versions of the original ssh bore successively removed many bugs, re-added newer features and
more restrictive licenses, and thus demand for a free version was born. created OpenSSH.
.Pp Markus Friedl contributed the support for SSH
This version of OpenSSH protocol versions 1.5 and 2.0.
.Bl -bullet
.It
has all components of a restrictive nature (i.e., patents, see
.Xr ssl 8 )
directly removed from the source code; any licensed or patented components
are chosen from
external libraries.
.It
has been updated to support SSH protocol 1.5 and 2, making it compatible with
all other SSH clients and servers.
.It
contains added support for
.Xr kerberos 8
authentication and ticket passing.
.It
supports one-time password authentication with
.Xr skey 1 .
.El
.Pp
OpenSSH has been created by Aaron Campbell, Bob Beck, Markus Friedl,
Niels Provos, Theo de Raadt, and Dug Song.
.Pp
The support for SSH protocol 2 was written by Markus Friedl.
.Sh SEE ALSO .Sh SEE ALSO
.Xr scp 1 , .Xr scp 1 ,
.Xr sftp 1 ,
.Xr sftp-server 8 , .Xr sftp-server 8 ,
.Xr ssh 1 , .Xr ssh 1 ,
.Xr ssh-add 1 , .Xr ssh-add 1 ,
.Xr ssh-agent 1 , .Xr ssh-agent 1 ,
.Xr ssh-keygen 1 , .Xr ssh-keygen 1 ,
.Xr ssl 8 ,
.Xr rlogin 1 , .Xr rlogin 1 ,
.Xr rsh 1 .Xr rsh 1
.Rs
.%A T. Ylonen
.%A T. Kivinen
.%A M. Saarinen
.%A T. Rinne
.%A S. Lehtinen
.%T "SSH Protocol Architecture"
.%N draft-ietf-secsh-architecture-07.txt
.%D January 2001
.%O work in progress material
.Re
.Rs
.%A M. Friedl
.%A N. Provos
.%A W. A. Simpson
.%T "Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol"
.%N draft-ietf-secsh-dh-group-exchange-00.txt
.%D January 2001
.%O work in progress material
.Re

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,16 @@
# This is ssh server systemwide configuration file. # $OpenBSD: sshd_config,v 1.38 2001/04/15 21:41:29 deraadt Exp $
# # $FreeBSD$
# $FreeBSD$
# This is the sshd server system-wide configuration file. See sshd(8)
# for more information.
Port 22 Port 22
#Protocol 2,1 #Protocol 2,1
#ListenAddress 0.0.0.0 #ListenAddress 0.0.0.0
#ListenAddress :: #ListenAddress ::
HostKey /etc/ssh/ssh_host_key HostKey /etc/ssh_host_key
HostDsaKey /etc/ssh/ssh_host_dsa_key HostKey /etc/ssh_host_rsa_key
HostKey /etc/ssh_host_dsa_key
ServerKeyBits 768 ServerKeyBits 768
LoginGraceTime 120 LoginGraceTime 120
KeyRegenerationInterval 3600 KeyRegenerationInterval 3600
@ -25,6 +28,7 @@ StrictModes yes
X11Forwarding yes X11Forwarding yes
X11DisplayOffset 10 X11DisplayOffset 10
PrintMotd yes PrintMotd yes
#PrintLastLog no
KeepAlive yes KeepAlive yes
# Logging # Logging
@ -36,15 +40,17 @@ RhostsAuthentication no
# #
# For this to work you will also need host keys in /etc/ssh_known_hosts # For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# #
RSAAuthentication yes RSAAuthentication yes
# To disable tunneled clear text passwords, change to no here! # To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes PasswordAuthentication yes
PermitEmptyPasswords no PermitEmptyPasswords no
# Uncomment to disable s/key passwords # Uncomment to disable s/key passwords
#SkeyAuthentication no #ChallengeResponseAuthentication no
#KbdInteractiveAuthentication yes
# To change Kerberos options # To change Kerberos options
#KerberosAuthentication no #KerberosAuthentication no
@ -58,5 +64,8 @@ PermitEmptyPasswords no
CheckMail yes CheckMail yes
#UseLogin no #UseLogin no
# Uncomment if you want to enable sftp #MaxStartups 10:30:60
#Subsystem sftp /usr/libexec/sftp-server #Banner /etc/issue.net
#ReverseMappingCheck yes
Subsystem sftp /usr/libexec/sftp-server

View File

@ -40,8 +40,9 @@
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $"); RCSID("$OpenBSD: sshlogin.c,v 1.2 2001/03/24 16:43:27 stevesk Exp $");
RCSID("$FreeBSD$");
#include <util.h> #include <libutil.h>
#include <utmp.h> #include <utmp.h>
#include "sshlogin.h" #include "sshlogin.h"
#include "log.h" #include "log.h"

View File

@ -13,8 +13,9 @@
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshpty.c,v 1.1 2001/03/04 01:46:30 djm Exp $"); RCSID("$OpenBSD: sshpty.c,v 1.1 2001/03/04 01:46:30 djm Exp $");
RCSID("$FreeBSD$");
#include <util.h> #include <libutil.h>
#include "sshpty.h" #include "sshpty.h"
#include "log.h" #include "log.h"

View File

@ -1,11 +1,11 @@
/* $FreeBSD$ */ /* $FreeBSD$ */
/* $OpenBSD: version.h,v 1.13 2000/10/16 09:38:45 djm Exp $ */ /* $OpenBSD: version.h,v 1.23 2001/04/24 16:43:16 markus Exp $ */
#ifndef SSH_VERSION #ifndef SSH_VERSION
#define SSH_VERSION (ssh_version_get()) #define SSH_VERSION (ssh_version_get())
#define SSH_VERSION_BASE "OpenSSH_2.3.0" #define SSH_VERSION_BASE "OpenSSH_2.9"
#define SSH_VERSION_ADDENDUM "green@FreeBSD.org 20010319" #define SSH_VERSION_ADDENDUM "green@FreeBSD.org 20010503"
const char *ssh_version_get(void); const char *ssh_version_get(void);
void ssh_version_set_addendum(const char *add); void ssh_version_set_addendum(const char *add);