Fix conflicts for OpenSSH 2.9.
This commit is contained in:
parent
3ed16d1511
commit
ca3176e7c8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76262
@ -24,6 +24,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: auth-chall.c,v 1.7 2001/04/05 10:42:47 markus Exp $");
|
||||
RCSID("$FreeBSD$");
|
||||
|
||||
#include "auth.h"
|
||||
#include "log.h"
|
||||
@ -69,14 +70,14 @@ verify_response(Authctxt *authctxt, char *response)
|
||||
}
|
||||
#else
|
||||
#ifdef SKEY
|
||||
#include <skey.h>
|
||||
#include <opie.h>
|
||||
|
||||
char *
|
||||
get_challenge(Authctxt *authctxt, char *devs)
|
||||
{
|
||||
static char challenge[1024];
|
||||
struct skey skey;
|
||||
if (skeychallenge(&skey, authctxt->user, challenge) == -1)
|
||||
struct opie opie;
|
||||
if (opiechallenge(&opie, authctxt->user, challenge) == -1)
|
||||
return NULL;
|
||||
strlcat(challenge, "\nS/Key Password: ", sizeof challenge);
|
||||
return challenge;
|
||||
@ -85,8 +86,8 @@ int
|
||||
verify_response(Authctxt *authctxt, char *response)
|
||||
{
|
||||
return (authctxt->valid &&
|
||||
skey_haskey(authctxt->pw->pw_name) == 0 &&
|
||||
skey_passcheck(authctxt->pw->pw_name, response) != -1);
|
||||
opie_haskey(authctxt->pw->pw_name) == 0 &&
|
||||
opie_passverify(authctxt->pw->pw_name, response) != -1);
|
||||
}
|
||||
#else
|
||||
/* not available */
|
||||
|
@ -23,13 +23,20 @@
|
||||
*/
|
||||
|
||||
#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 "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
#include "auth.h"
|
||||
|
||||
RCSID("$OpenBSD: auth-krb4.c,v 1.19 2000/10/03 18:03:02 markus Exp $");
|
||||
RCSID("$FreeBSD$");
|
||||
#ifdef AFS
|
||||
#include "radix.h"
|
||||
#endif
|
||||
|
||||
#ifdef KRB4
|
||||
char *ticket = NULL;
|
||||
@ -47,7 +54,7 @@ auth_krb4_password(struct passwd * pw, const char *password)
|
||||
AUTH_DAT adata;
|
||||
KTEXT_ST tkt;
|
||||
struct hostent *hp;
|
||||
unsigned long faddr;
|
||||
u_long faddr;
|
||||
char localhost[MAXHOSTNAMELEN];
|
||||
char phost[INST_SZ];
|
||||
char realm[REALM_SZ];
|
||||
|
@ -11,30 +11,7 @@
|
||||
* incompatible with the protocol description in the RFC file, it must be
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -59,39 +36,41 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
#include "servconf.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
|
||||
* authentication succeeds.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* deny if no user. */
|
||||
if (pw == NULL)
|
||||
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;
|
||||
if (*password == '\0' && options.permit_empty_passwd == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef SKEY_VIA_PASSWD_IS_DISABLED
|
||||
if (options.skey_authentication == 1) {
|
||||
int ret = auth_skey_password(pw, password);
|
||||
if (ret == 1 || ret == 0)
|
||||
return ret;
|
||||
/* Fall back to ordinary passwd authentication. */
|
||||
}
|
||||
#ifdef BSD_AUTH
|
||||
if (auth_userokay(pw->pw_name, authctxt->style, "auth-ssh",
|
||||
(char *)password) == 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef KRB5
|
||||
if (options.kerberos_authentication == 1) {
|
||||
|
@ -13,19 +13,20 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "packet.h"
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "uidswap.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "key.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
|
||||
@ -49,26 +50,27 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key
|
||||
if (!auth_rhosts(pw, client_user))
|
||||
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);
|
||||
|
||||
/* 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->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. */
|
||||
host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname,
|
||||
client_key, found);
|
||||
host_status = check_host_in_hostfile(_PATH_SSH_SYSTEM_HOSTFILE, canonical_hostname,
|
||||
client_key, found, NULL);
|
||||
|
||||
/* Check user host file unless ignored. */
|
||||
if (host_status != HOST_OK && !options.ignore_user_known_hosts) {
|
||||
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
|
||||
*/
|
||||
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);
|
||||
} else {
|
||||
/* 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,
|
||||
client_key, found);
|
||||
client_key, found, NULL);
|
||||
restore_uid();
|
||||
}
|
||||
xfree(user_hostfile);
|
||||
|
@ -14,22 +14,24 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#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/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 */
|
||||
extern ServerOptions options;
|
||||
@ -38,7 +40,7 @@ extern ServerOptions options;
|
||||
* Session identifier that is used to bind key exchange and authentication
|
||||
* 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
|
||||
@ -61,9 +63,9 @@ auth_rsa_challenge_dialog(RSA *pk)
|
||||
{
|
||||
BIGNUM *challenge, *encrypted_challenge;
|
||||
BN_CTX *ctx;
|
||||
unsigned char buf[32], mdbuf[16], response[16];
|
||||
u_char buf[32], mdbuf[16], response[16];
|
||||
MD5_CTX md;
|
||||
unsigned int i;
|
||||
u_int i;
|
||||
int plen, len;
|
||||
|
||||
encrypted_challenge = BN_new();
|
||||
@ -121,11 +123,11 @@ auth_rsa_challenge_dialog(RSA *pk)
|
||||
int
|
||||
auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
{
|
||||
char line[8192], file[1024];
|
||||
char line[8192], file[MAXPATHLEN];
|
||||
int authenticated;
|
||||
unsigned int bits;
|
||||
u_int bits;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
u_long linenum = 0;
|
||||
struct stat st;
|
||||
RSA *pk;
|
||||
|
||||
@ -134,11 +136,11 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
return 0;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
temporarily_use_uid(pw);
|
||||
|
||||
/* The authorized keys. */
|
||||
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 */
|
||||
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);
|
||||
fail = 1;
|
||||
} else {
|
||||
/* Check path to SSH_USER_PERMITTED_KEYS */
|
||||
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", SSH_USER_DIR, NULL
|
||||
"", _PATH_SSH_USER_DIR, NULL
|
||||
};
|
||||
for (i = 0; check[i]; 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) {
|
||||
fclose(f);
|
||||
log("%s",buf);
|
||||
packet_send_debug("%s",buf);
|
||||
log("%s", buf);
|
||||
packet_send_debug("%s", buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
@ -232,19 +234,13 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n)
|
||||
}
|
||||
} else
|
||||
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. */
|
||||
if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) {
|
||||
debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
file, linenum);
|
||||
packet_send_debug("%.100s, line %lu: bad key syntax",
|
||||
SSH_USER_PERMITTED_KEYS, linenum);
|
||||
file, linenum);
|
||||
continue;
|
||||
}
|
||||
/* 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);
|
||||
|
||||
/* 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. */
|
||||
if (!auth_rsa_challenge_dialog(pk)) {
|
||||
|
@ -1,15 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* 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.
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -33,35 +23,27 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#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 "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "groupaccess.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
#include "auth-options.h"
|
||||
#include "canohost.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
|
||||
/*
|
||||
* Check if the user is allowed to log in via ssh. If user is listed in
|
||||
* DenyUsers or user's primary group is listed in DenyGroups, false will
|
||||
* be returned. If AllowUsers isn't empty and user isn't listed there, or
|
||||
* if AllowGroups isn't empty and user isn't listed there, false will be
|
||||
* returned.
|
||||
* Check if the user is allowed to log in via ssh. If user is listed
|
||||
* in DenyUsers or one of user's groups is listed in DenyGroups, false
|
||||
* will be returned. If AllowUsers isn't empty and user isn't listed
|
||||
* there, or if AllowGroups isn't empty and one of user's groups isn't
|
||||
* listed there, false will be returned.
|
||||
* If the user's shell is not executable, false will be returned.
|
||||
* Otherwise true is returned.
|
||||
*/
|
||||
@ -69,12 +51,11 @@ int
|
||||
allowed_user(struct passwd * pw)
|
||||
{
|
||||
struct stat st;
|
||||
struct group *grp;
|
||||
char *shell;
|
||||
int i;
|
||||
|
||||
/* Shouldn't be called if pw is NULL, but better safe than sorry... */
|
||||
if (!pw)
|
||||
if (!pw || !pw->pw_name)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -91,16 +72,12 @@ allowed_user(struct passwd * pw)
|
||||
|
||||
/* Return false if user is listed in DenyUsers */
|
||||
if (options.num_deny_users > 0) {
|
||||
if (!pw->pw_name)
|
||||
return 0;
|
||||
for (i = 0; i < options.num_deny_users; i++)
|
||||
if (match_pattern(pw->pw_name, options.deny_users[i]))
|
||||
return 0;
|
||||
}
|
||||
/* Return false if AllowUsers isn't empty and user isn't listed there */
|
||||
if (options.num_allow_users > 0) {
|
||||
if (!pw->pw_name)
|
||||
return 0;
|
||||
for (i = 0; i < options.num_allow_users; i++)
|
||||
if (match_pattern(pw->pw_name, options.allow_users[i]))
|
||||
break;
|
||||
@ -108,36 +85,91 @@ allowed_user(struct passwd * pw)
|
||||
if (i >= options.num_allow_users)
|
||||
return 0;
|
||||
}
|
||||
/* Get the primary group name if we need it. Return false if it fails */
|
||||
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
|
||||
grp = getgrgid(pw->pw_gid);
|
||||
if (!grp)
|
||||
/* Get the user's group access list (primary and supplementary) */
|
||||
if (ga_init(pw->pw_name, pw->pw_gid) == 0)
|
||||
return 0;
|
||||
|
||||
/* Return false if user's group is listed in DenyGroups */
|
||||
if (options.num_deny_groups > 0) {
|
||||
if (!grp->gr_name)
|
||||
/* Return false if one of user's groups is listed in DenyGroups */
|
||||
if (options.num_deny_groups > 0)
|
||||
if (ga_match(options.deny_groups,
|
||||
options.num_deny_groups)) {
|
||||
ga_free();
|
||||
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
|
||||
*/
|
||||
if (options.num_allow_groups > 0) {
|
||||
if (!grp->gr_name)
|
||||
if (options.num_allow_groups > 0)
|
||||
if (!ga_match(options.allow_groups,
|
||||
options.num_allow_groups)) {
|
||||
ga_free();
|
||||
return 0;
|
||||
for (i = 0; i < options.num_allow_groups; i++)
|
||||
if (match_pattern(grp->gr_name, options.allow_groups[i]))
|
||||
break;
|
||||
/* i < options.num_allow_groups iff we break for
|
||||
loop */
|
||||
if (i >= options.num_allow_groups)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ga_free();
|
||||
}
|
||||
/* We found no reason not to let this user try to log on... */
|
||||
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;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
* 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 $
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef 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);
|
||||
|
||||
#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>
|
||||
/*
|
||||
|
@ -10,19 +10,23 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "ssh1.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "mpaux.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "auth.h"
|
||||
#include "auth-pam.h"
|
||||
#include "session.h"
|
||||
#include "canohost.h"
|
||||
#include "misc.h"
|
||||
#include <login_cap.h>
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
@ -34,7 +38,6 @@ Also is used as an indication of succesful krb5 authentization. */
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern char *forced_command;
|
||||
|
||||
/*
|
||||
* convert ssh auth msg type into description
|
||||
@ -52,13 +55,12 @@ get_authname(int type)
|
||||
return "rhosts-rsa";
|
||||
case SSH_CMSG_AUTH_RHOSTS:
|
||||
return "rhosts";
|
||||
case SSH_CMSG_AUTH_TIS:
|
||||
case SSH_CMSG_AUTH_TIS_RESPONSE:
|
||||
return "challenge-response";
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
case SSH_CMSG_AUTH_KERBEROS:
|
||||
return "kerberos";
|
||||
#endif
|
||||
#ifdef SKEY
|
||||
case SSH_CMSG_AUTH_TIS_RESPONSE:
|
||||
return "s/key";
|
||||
#endif
|
||||
}
|
||||
snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
|
||||
@ -66,26 +68,23 @@ get_authname(int type)
|
||||
}
|
||||
|
||||
/*
|
||||
* read packets and try to authenticate local user 'luser'.
|
||||
* return if authentication is successfull. not that pw == NULL
|
||||
* if the user does not exists or is not allowed to login.
|
||||
* each auth method has to 'fake' authentication for nonexisting
|
||||
* users.
|
||||
* read packets, try to authenticate the user and
|
||||
* return only if authentication is successful
|
||||
*/
|
||||
void
|
||||
do_authloop(struct passwd * pw, char *luser)
|
||||
do_authloop(Authctxt *authctxt)
|
||||
{
|
||||
int authenticated = 0;
|
||||
int attempt = 0;
|
||||
unsigned int bits;
|
||||
u_int bits;
|
||||
RSA *client_host_key;
|
||||
BIGNUM *n;
|
||||
char *client_user, *password;
|
||||
char user[1024];
|
||||
unsigned int dlen;
|
||||
char info[1024];
|
||||
u_int dlen;
|
||||
int plen, nlen, elen;
|
||||
unsigned int ulen;
|
||||
u_int ulen;
|
||||
int type = 0;
|
||||
struct passwd *pw = authctxt->pw;
|
||||
void (*authlog) (const char *fmt,...) = verbose;
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
login_cap_t *lc;
|
||||
@ -96,7 +95,7 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
|
||||
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();
|
||||
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
|
||||
#if 0
|
||||
@ -113,6 +112,24 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
#endif /* KRB5 */
|
||||
#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. */
|
||||
packet_start(SSH_SMSG_FAILURE);
|
||||
packet_send();
|
||||
@ -120,11 +137,11 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
|
||||
client_user = NULL;
|
||||
|
||||
for (attempt = 1;; attempt++) {
|
||||
for (;;) {
|
||||
/* default to fail */
|
||||
authenticated = 0;
|
||||
|
||||
strlcpy(user, "", sizeof user);
|
||||
info[0] = '\0';
|
||||
|
||||
/* Get a packet from the client. */
|
||||
type = packet_read(&plen);
|
||||
@ -143,7 +160,7 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
char *tgt = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
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);
|
||||
}
|
||||
continue;
|
||||
@ -157,7 +174,7 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
char *token_string = packet_get_string(&dlen);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
if (!auth_afs_token(pw, token_string))
|
||||
verbose("AFS token REFUSED for %.100s", luser);
|
||||
verbose("AFS token REFUSED for %.100s", authctxt->user);
|
||||
xfree(token_string);
|
||||
}
|
||||
continue;
|
||||
@ -166,35 +183,36 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
case SSH_CMSG_AUTH_KERBEROS:
|
||||
if (!options.kerberos_authentication) {
|
||||
verbose("Kerberos authentication disabled.");
|
||||
} else {
|
||||
unsigned int length;
|
||||
char *kdata = packet_get_string(&length);
|
||||
packet_integrity_check(plen, 4 + length, type);
|
||||
break;
|
||||
} else {
|
||||
/* Try Kerberos authentication. */
|
||||
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 (kdata[0] == 4) {
|
||||
#ifndef KRB4
|
||||
verbose("Kerberos v4 authentication disabled.");
|
||||
#else
|
||||
char *tkt_user = NULL;
|
||||
KTEXT_ST auth;
|
||||
auth.length = length;
|
||||
if (!authctxt->valid) {
|
||||
/* Do nothing. */
|
||||
} else if (kdata[0] == 4) { /* 4 == KRB_PROT_VERSION */
|
||||
#ifdef KRB4
|
||||
if (auth.length < MAX_KTXT_LEN)
|
||||
memcpy(auth.dat, kdata, auth.length);
|
||||
|
||||
authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
|
||||
|
||||
if (authenticated) {
|
||||
snprintf(user, sizeof user, " tktuser %s", tkt_user);
|
||||
snprintf(info, sizeof info,
|
||||
" tktuser %.100s", tkt_user);
|
||||
xfree(tkt_user);
|
||||
}
|
||||
#endif /* KRB4 */
|
||||
#else
|
||||
verbose("Kerberos v4 authentication disabled.");
|
||||
#endif /* KRB4 */
|
||||
} else {
|
||||
#ifndef KRB5
|
||||
verbose("Kerberos v5 authentication disabled.");
|
||||
#else
|
||||
krb5_data k5data;
|
||||
k5data.length = length;
|
||||
k5data.length = auth.length;
|
||||
k5data.data = kdata;
|
||||
#if 0
|
||||
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. */
|
||||
authenticated = auth_rhosts(pw, client_user);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
snprintf(info, sizeof info, " ruser %.100s", client_user);
|
||||
break;
|
||||
|
||||
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);
|
||||
RSA_free(client_host_key);
|
||||
|
||||
snprintf(user, sizeof user, " ruser %s", client_user);
|
||||
snprintf(info, sizeof info, " ruser %.100s", client_user);
|
||||
break;
|
||||
|
||||
case SSH_CMSG_AUTH_RSA:
|
||||
@ -301,10 +319,10 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
|
||||
#ifdef USE_PAM
|
||||
/* Do PAM auth with password */
|
||||
authenticated = auth_pam_password(pw, password);
|
||||
authenticated = auth_pam_password(authctxt, password);
|
||||
#else /* !USE_PAM */
|
||||
/* Try authentication with the password. */
|
||||
authenticated = auth_password(pw, password);
|
||||
authenticated = auth_password(authctxt, password);
|
||||
#endif /* USE_PAM */
|
||||
|
||||
memset(password, 0, strlen(password));
|
||||
@ -347,18 +365,12 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
#elif defined(SKEY)
|
||||
case SSH_CMSG_AUTH_TIS:
|
||||
debug("rcvd SSH_CMSG_AUTH_TIS");
|
||||
if (options.skey_authentication == 1) {
|
||||
char *skeyinfo = pw ? opie_keyinfo(pw->pw_name) :
|
||||
NULL;
|
||||
if (skeyinfo == NULL) {
|
||||
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);
|
||||
if (options.challenge_reponse_authentication == 1) {
|
||||
char *challenge = get_challenge(authctxt, authctxt->style);
|
||||
if (challenge != NULL) {
|
||||
debug("sending challenge '%s'", challenge);
|
||||
packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
|
||||
packet_put_cstring(skeyinfo);
|
||||
packet_put_cstring(challenge);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
continue;
|
||||
@ -367,13 +379,12 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
break;
|
||||
case 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);
|
||||
debug("skey response == '%s'", response);
|
||||
debug("got response '%s'", response);
|
||||
packet_integrity_check(plen, 4 + dlen, type);
|
||||
authenticated = (pw != NULL &&
|
||||
opie_haskey(pw->pw_name) == 0 &&
|
||||
opie_passverify(pw->pw_name, response) != -1);
|
||||
authenticated = verify_response(authctxt, response);
|
||||
memset(response, 'r', dlen);
|
||||
xfree(response);
|
||||
}
|
||||
break;
|
||||
@ -417,23 +428,6 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
log("Unknown message during authentication: type %d", type);
|
||||
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
|
||||
if (pw != NULL) {
|
||||
@ -461,28 +455,28 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
packet_disconnect("Sorry, you are not allowed to connect.");
|
||||
}
|
||||
#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)
|
||||
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 */
|
||||
if (authenticated ||
|
||||
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;
|
||||
/* Log before sending the reply */
|
||||
auth_log(authctxt, authenticated, get_authname(type), info);
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (authenticated && !do_pam_account(pw->pw_name, client_user))
|
||||
@ -494,10 +488,12 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
client_user = NULL;
|
||||
}
|
||||
|
||||
if (attempt > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, luser);
|
||||
if (authenticated)
|
||||
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_send();
|
||||
packet_write_wait();
|
||||
@ -511,10 +507,11 @@ do_authloop(struct passwd * pw, char *luser)
|
||||
void
|
||||
do_authentication()
|
||||
{
|
||||
struct passwd *pw, pwcopy;
|
||||
Authctxt *authctxt;
|
||||
struct passwd *pw;
|
||||
int plen;
|
||||
unsigned int ulen;
|
||||
char *user;
|
||||
u_int ulen;
|
||||
char *user, *style = NULL;
|
||||
|
||||
/* Get the name of the user that we wish to log in as. */
|
||||
packet_read_expect(&plen, SSH_CMSG_USER);
|
||||
@ -523,39 +520,30 @@ do_authentication()
|
||||
user = packet_get_string(&ulen);
|
||||
packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
|
||||
|
||||
setproctitle("%s", user);
|
||||
if ((style = strchr(user, ':')) != NULL)
|
||||
*style++ = 0;
|
||||
|
||||
#ifdef AFS
|
||||
/* If machine has AFS, set process authentication group. */
|
||||
if (k_hasafs()) {
|
||||
k_setpag();
|
||||
k_unlog();
|
||||
}
|
||||
#endif /* AFS */
|
||||
authctxt = authctxt_new();
|
||||
authctxt->user = user;
|
||||
authctxt->style = style;
|
||||
|
||||
/* Verify that the user is a valid user. */
|
||||
pw = getpwnam(user);
|
||||
if (pw && allowed_user(pw)) {
|
||||
/* 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_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;
|
||||
authctxt->valid = 1;
|
||||
pw = pwcopy(pw);
|
||||
} else {
|
||||
debug("do_authentication: illegal user %s", user);
|
||||
pw = NULL;
|
||||
}
|
||||
authctxt->pw = pw;
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (pw != NULL)
|
||||
start_pam(pw);
|
||||
#endif
|
||||
setproctitle("%s", pw ? user : "unknown");
|
||||
|
||||
/*
|
||||
* If we are not running as root, the user must have the same uid as
|
||||
* the server.
|
||||
@ -563,33 +551,11 @@ do_authentication()
|
||||
if (getuid() != 0 && pw && pw->pw_uid != getuid())
|
||||
packet_disconnect("Cannot change user when server not running as root.");
|
||||
|
||||
debug("Attempting authentication for %s%.100s.", pw ? "" : "illegal user ", user);
|
||||
|
||||
/* If the user has no password, accept authentication immediately. */
|
||||
if (options.password_authentication &&
|
||||
#ifdef KRB5
|
||||
!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);
|
||||
/*
|
||||
* Loop until the user has been authenticated or the connection is
|
||||
* closed, do_authloop() returns only if authentication is successful
|
||||
*/
|
||||
do_authloop(authctxt);
|
||||
|
||||
/* The user has been authenticated and accepted. */
|
||||
packet_start(SSH_SMSG_SUCCESS);
|
||||
@ -597,5 +563,5 @@ do_authentication()
|
||||
packet_write_wait();
|
||||
|
||||
/* Perform session preparation. */
|
||||
do_authenticated(pw);
|
||||
do_authenticated(authctxt);
|
||||
}
|
||||
|
@ -23,34 +23,35 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "ssh2.h"
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "pty.h"
|
||||
#include "sshpty.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "channels.h"
|
||||
#include "bufaux.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
#include "auth.h"
|
||||
#include "key.h"
|
||||
#include "cipher.h"
|
||||
#include "kex.h"
|
||||
|
||||
#include "dsa.h"
|
||||
#include "pathnames.h"
|
||||
#include "uidswap.h"
|
||||
#include "auth-options.h"
|
||||
#include "misc.h"
|
||||
#include "hostfile.h"
|
||||
#include "canohost.h"
|
||||
#include "tildexpand.h"
|
||||
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
#include <login_cap.h>
|
||||
@ -58,7 +59,7 @@ RCSID("$FreeBSD$");
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
extern unsigned char *session_id2;
|
||||
extern u_char *session_id2;
|
||||
extern int session_id2_len;
|
||||
|
||||
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 protocol_error(int type, int plen, void *ctxt);
|
||||
|
||||
|
||||
/* helper */
|
||||
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);
|
||||
int user_key_allowed(struct passwd *pw, Key *key);
|
||||
int
|
||||
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
|
||||
Key *key);
|
||||
|
||||
/* auth */
|
||||
void userauth_banner(void);
|
||||
void userauth_reply(Authctxt *authctxt, int authenticated);
|
||||
int userauth_none(Authctxt *authctxt);
|
||||
int userauth_passwd(Authctxt *authctxt);
|
||||
int userauth_pubkey(Authctxt *authctxt);
|
||||
int userauth_hostbased(Authctxt *authctxt);
|
||||
int userauth_kbdint(Authctxt *authctxt);
|
||||
|
||||
Authmethod authmethods[] = {
|
||||
@ -96,13 +101,16 @@ Authmethod authmethods[] = {
|
||||
&one},
|
||||
{"publickey",
|
||||
userauth_pubkey,
|
||||
&options.dsa_authentication},
|
||||
{"keyboard-interactive",
|
||||
userauth_kbdint,
|
||||
&options.kbd_interactive_authentication},
|
||||
&options.pubkey_authentication},
|
||||
{"password",
|
||||
userauth_passwd,
|
||||
&options.password_authentication},
|
||||
{"keyboard-interactive",
|
||||
userauth_kbdint,
|
||||
&options.kbd_interactive_authentication},
|
||||
{"hostbased",
|
||||
userauth_hostbased,
|
||||
&options.hostbased_authentication},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@ -113,21 +121,22 @@ Authmethod authmethods[] = {
|
||||
void
|
||||
do_authentication2()
|
||||
{
|
||||
Authctxt *authctxt = xmalloc(sizeof(*authctxt));
|
||||
memset(authctxt, 'a', sizeof(*authctxt));
|
||||
authctxt->valid = 0;
|
||||
authctxt->attempt = 0;
|
||||
authctxt->success = 0;
|
||||
Authctxt *authctxt = authctxt_new();
|
||||
|
||||
x_authctxt = authctxt; /*XXX*/
|
||||
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
/* turn off kerberos, not supported by SSH2 */
|
||||
options.kerberos_authentication = 0;
|
||||
#endif
|
||||
/* challenge-reponse is implemented via keyboard interactive */
|
||||
if (options.challenge_reponse_authentication)
|
||||
options.kbd_interactive_authentication = 1;
|
||||
|
||||
dispatch_init(&protocol_error);
|
||||
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
|
||||
do_authenticated2();
|
||||
do_authenticated(authctxt);
|
||||
}
|
||||
|
||||
void
|
||||
@ -144,7 +153,7 @@ void
|
||||
input_service_request(int type, int plen, void *ctxt)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
unsigned int len;
|
||||
u_int len;
|
||||
int accept = 0;
|
||||
char *service = packet_get_string(&len);
|
||||
packet_done();
|
||||
@ -178,33 +187,33 @@ input_userauth_request(int type, int plen, void *ctxt)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authmethod *m = NULL;
|
||||
char *user, *service, *method, *style = NULL;
|
||||
int authenticated = 0;
|
||||
char *user, *service, *method, *authmsg = NULL;
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
login_cap_t *lc;
|
||||
#endif /* HAVE_LOGIN_CAP */
|
||||
#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
|
||||
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();
|
||||
#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
|
||||
|
||||
if (authctxt == NULL)
|
||||
fatal("input_userauth_request: no authctxt");
|
||||
if (authctxt->attempt++ >= AUTH_FAIL_MAX)
|
||||
packet_disconnect("too many failed userauth_requests");
|
||||
|
||||
user = packet_get_string(NULL);
|
||||
service = packet_get_string(NULL);
|
||||
method = packet_get_string(NULL);
|
||||
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 */
|
||||
struct passwd *pw = NULL;
|
||||
setproctitle("%s", user);
|
||||
pw = getpwnam(user);
|
||||
if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
|
||||
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);
|
||||
authctxt->pw = NULL;
|
||||
}
|
||||
setproctitle("%s", pw ? user : "unknown");
|
||||
authctxt->user = xstrdup(user);
|
||||
authctxt->service = xstrdup(service);
|
||||
authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
|
||||
} else if (authctxt->valid) {
|
||||
if (strcmp(user, authctxt->user) != 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);
|
||||
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.");
|
||||
}
|
||||
#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);
|
||||
if (m != NULL) {
|
||||
debug2("input_userauth_request: try method %s", method);
|
||||
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
|
||||
if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL))
|
||||
authenticated = 0;
|
||||
#endif /* USE_PAM */
|
||||
|
||||
/* Log before sending the reply */
|
||||
userauth_log(authctxt, authenticated, method);
|
||||
userauth_reply(authctxt, authenticated);
|
||||
userauth_finish(authctxt, authenticated, method);
|
||||
|
||||
xfree(service);
|
||||
xfree(user);
|
||||
xfree(method);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
userauth_log(Authctxt *authctxt, int authenticated, char *method)
|
||||
userauth_finish(Authctxt *authctxt, int authenticated, char *method)
|
||||
{
|
||||
void (*authlog) (const char *fmt,...) = verbose;
|
||||
char *user = NULL, *authmsg = NULL;
|
||||
if (!authctxt->valid && authenticated)
|
||||
fatal("INTERNAL ERROR: authenticated invalid user %s",
|
||||
authctxt->user);
|
||||
|
||||
/* Raise logging level */
|
||||
if (authenticated == 1 ||
|
||||
!authctxt->valid ||
|
||||
authctxt->attempt >= AUTH_FAIL_LOG ||
|
||||
strcmp(method, "password") == 0)
|
||||
authlog = log;
|
||||
/* Special handling for root */
|
||||
if (authenticated && authctxt->pw->pw_uid == 0 &&
|
||||
!auth_root_allowed(method))
|
||||
authenticated = 0;
|
||||
|
||||
if (authenticated == 1) {
|
||||
authmsg = "Accepted";
|
||||
} else if (authenticated == 0) {
|
||||
authmsg = "Failed";
|
||||
} else {
|
||||
authmsg = "Postponed";
|
||||
}
|
||||
/* Log before sending the reply */
|
||||
auth_log(authctxt, authenticated, method, " ssh2");
|
||||
|
||||
if (authctxt->valid) {
|
||||
user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
|
||||
} else {
|
||||
user = "NOUSER";
|
||||
}
|
||||
|
||||
authlog("%s %s for %.200s from %.200s port %d ssh2",
|
||||
authmsg,
|
||||
method,
|
||||
user,
|
||||
get_remote_ipaddr(),
|
||||
get_remote_port());
|
||||
if (!authctxt->postponed)
|
||||
userauth_reply(authctxt, authenticated);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char *methods;
|
||||
|
||||
/* XXX todo: check if multiple auth methods are needed */
|
||||
if (authenticated == 1) {
|
||||
/* turn off userauth */
|
||||
@ -337,16 +357,16 @@ userauth_reply(Authctxt *authctxt, int authenticated)
|
||||
packet_write_wait();
|
||||
/* now we can break out */
|
||||
authctxt->success = 1;
|
||||
} else if (authenticated == 0) {
|
||||
char *methods = authmethods_get();
|
||||
} else {
|
||||
if (authctxt->failures++ > AUTH_FAIL_MAX)
|
||||
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
|
||||
methods = authmethods_get();
|
||||
packet_start(SSH2_MSG_USERAUTH_FAILURE);
|
||||
packet_put_cstring(methods);
|
||||
packet_put_char(0); /* XXX partial success, unused */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
xfree(methods);
|
||||
} else {
|
||||
/* do nothing, we did already send a reply */
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,10 +378,11 @@ userauth_none(Authctxt *authctxt)
|
||||
if (m != NULL)
|
||||
m->enabled = NULL;
|
||||
packet_done();
|
||||
userauth_banner();
|
||||
#ifdef USE_PAM
|
||||
return authctxt->valid ? auth_pam_password(authctxt->pw, "") : 0;
|
||||
return authctxt->valid ? auth_pam_password(authctxt, "") : 0;
|
||||
#else /* !USE_PAM */
|
||||
return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
|
||||
return authctxt->valid ? auth_password(authctxt, "") : 0;
|
||||
#endif /* USE_PAM */
|
||||
}
|
||||
|
||||
@ -371,7 +392,7 @@ userauth_passwd(Authctxt *authctxt)
|
||||
char *password;
|
||||
int authenticated = 0;
|
||||
int change;
|
||||
unsigned int len;
|
||||
u_int len;
|
||||
change = packet_get_char();
|
||||
if (change)
|
||||
log("password change not supported");
|
||||
@ -379,9 +400,9 @@ userauth_passwd(Authctxt *authctxt)
|
||||
packet_done();
|
||||
if (authctxt->valid &&
|
||||
#ifdef USE_PAM
|
||||
auth_pam_password(authctxt->pw, password) == 1
|
||||
auth_pam_password(authctxt, password) == 1
|
||||
#else
|
||||
auth_password(authctxt->pw, password) == 1
|
||||
auth_password(authctxt, password) == 1
|
||||
#endif
|
||||
)
|
||||
authenticated = 1;
|
||||
@ -402,11 +423,10 @@ userauth_kbdint(Authctxt *authctxt)
|
||||
packet_done();
|
||||
|
||||
debug("keyboard-interactive language %s devs %s", lang, devs);
|
||||
#ifdef SKEY
|
||||
/* XXX hardcoded, we should look at devs */
|
||||
if (options.skey_authentication != 0)
|
||||
authenticated = auth2_skey(authctxt);
|
||||
#endif
|
||||
|
||||
if (options.challenge_reponse_authentication)
|
||||
authenticated = auth2_challenge(authctxt, devs);
|
||||
|
||||
xfree(lang);
|
||||
xfree(devs);
|
||||
return authenticated;
|
||||
@ -418,8 +438,8 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
Buffer b;
|
||||
Key *key;
|
||||
char *pkalg, *pkblob, *sig;
|
||||
unsigned int alen, blen, slen;
|
||||
int have_sig;
|
||||
u_int alen, blen, slen;
|
||||
int have_sig, pktype;
|
||||
int authenticated = 0;
|
||||
|
||||
if (!authctxt->valid) {
|
||||
@ -427,14 +447,28 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
return 0;
|
||||
}
|
||||
have_sig = packet_get_char();
|
||||
pkalg = packet_get_string(&alen);
|
||||
if (strcmp(pkalg, KEX_DSS) != 0) {
|
||||
log("bad pkalg %s", pkalg); /*XXX*/
|
||||
if (datafellows & SSH_BUG_PKAUTH) {
|
||||
debug2("userauth_pubkey: SSH_BUG_PKAUTH");
|
||||
/* 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(pkblob);
|
||||
return 0;
|
||||
}
|
||||
pkblob = packet_get_string(&blen);
|
||||
key = dsa_key_from_blob(pkblob, blen);
|
||||
key = key_from_blob(pkblob, blen);
|
||||
if (key != NULL) {
|
||||
if (have_sig) {
|
||||
sig = packet_get_string(&slen);
|
||||
@ -449,19 +483,23 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, authctxt->user);
|
||||
buffer_put_cstring(&b,
|
||||
datafellows & SSH_BUG_PUBKEYAUTH ?
|
||||
datafellows & SSH_BUG_PKSERVICE ?
|
||||
"ssh-userauth" :
|
||||
authctxt->service);
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, KEX_DSS);
|
||||
if (datafellows & SSH_BUG_PKAUTH) {
|
||||
buffer_put_char(&b, have_sig);
|
||||
} else {
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, pkalg);
|
||||
}
|
||||
buffer_put_string(&b, pkblob, blen);
|
||||
#ifdef DEBUG_DSS
|
||||
#ifdef DEBUG_PK
|
||||
buffer_dump(&b);
|
||||
#endif
|
||||
/* test for correct signature */
|
||||
if (user_dsa_key_allowed(authctxt->pw, key) &&
|
||||
dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
|
||||
if (user_key_allowed(authctxt->pw, key) &&
|
||||
key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
|
||||
authenticated = 1;
|
||||
buffer_clear(&b);
|
||||
xfree(sig);
|
||||
@ -477,24 +515,100 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
* if a user is not allowed to login. is this an
|
||||
* 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_put_string(pkalg, alen);
|
||||
packet_put_string(pkblob, blen);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
authenticated = -1;
|
||||
authctxt->postponed = 1;
|
||||
}
|
||||
}
|
||||
if (authenticated != 1)
|
||||
auth_clear_options();
|
||||
key_free(key);
|
||||
}
|
||||
debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
|
||||
xfree(pkalg);
|
||||
xfree(pkblob);
|
||||
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 */
|
||||
|
||||
struct passwd*
|
||||
@ -509,7 +623,7 @@ char *
|
||||
authmethods_get(void)
|
||||
{
|
||||
Authmethod *method = NULL;
|
||||
unsigned int size = 0;
|
||||
u_int size = 0;
|
||||
char *list;
|
||||
|
||||
for (method = authmethods; method->name != NULL; method++) {
|
||||
@ -553,13 +667,12 @@ authmethod_lookup(const char *name)
|
||||
|
||||
/* return 1 if user allows given key */
|
||||
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;
|
||||
unsigned int bits = -1;
|
||||
FILE *f;
|
||||
unsigned long linenum = 0;
|
||||
u_long linenum = 0;
|
||||
struct stat st;
|
||||
Key *found;
|
||||
|
||||
@ -567,11 +680,11 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
return 0;
|
||||
|
||||
/* Temporarily use the user's uid. */
|
||||
temporarily_use_uid(pw->pw_uid);
|
||||
temporarily_use_uid(pw);
|
||||
|
||||
/* The authorized keys. */
|
||||
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 */
|
||||
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);
|
||||
fail = 1;
|
||||
} else {
|
||||
/* Check path to SSH_USER_PERMITTED_KEYS */
|
||||
/* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
|
||||
int i;
|
||||
static const char *check[] = {
|
||||
"", SSH_USER_DIR, NULL
|
||||
"", _PATH_SSH_USER_DIR, NULL
|
||||
};
|
||||
for (i = 0; check[i]; i++) {
|
||||
snprintf(line, sizeof line, "%.500s/%.100s",
|
||||
@ -621,7 +734,7 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
}
|
||||
if (fail) {
|
||||
fclose(f);
|
||||
log("%s",buf);
|
||||
log("%s", buf);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
@ -638,10 +751,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
bits = key_read(found, &cp);
|
||||
if (bits == 0) {
|
||||
if (key_read(found, &cp) == -1) {
|
||||
/* no key? check if there are options for this key */
|
||||
int quoted = 0;
|
||||
debug2("user_key_allowed: check options: '%s'", cp);
|
||||
options = cp;
|
||||
for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
|
||||
if (*cp == '\\' && cp[1] == '"')
|
||||
@ -652,14 +765,14 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
/* Skip remaining whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
bits = key_read(found, &cp);
|
||||
if (bits == 0) {
|
||||
if (key_read(found, &cp) == -1) {
|
||||
debug2("user_key_allowed: advance: '%s'", cp);
|
||||
/* still no key? advance to next line*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (key_equal(found, key) &&
|
||||
auth_parse_options(pw, options, linenum) == 1) {
|
||||
auth_parse_options(pw, options, file, linenum) == 1) {
|
||||
found_key = 1;
|
||||
debug("matching key found: file %s, line %ld",
|
||||
file, linenum);
|
||||
@ -669,22 +782,73 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
|
||||
restore_uid();
|
||||
fclose(f);
|
||||
key_free(found);
|
||||
if (!found_key)
|
||||
debug2("key not found");
|
||||
return found_key;
|
||||
}
|
||||
|
||||
struct passwd *
|
||||
pwcopy(struct passwd *pw)
|
||||
/* return 1 if given hostkey is allowed */
|
||||
int
|
||||
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
|
||||
Key *key)
|
||||
{
|
||||
struct passwd *copy = xmalloc(sizeof(*copy));
|
||||
memset(copy, 0, sizeof(*copy));
|
||||
copy->pw_name = xstrdup(pw->pw_name);
|
||||
copy->pw_passwd = xstrdup(pw->pw_passwd);
|
||||
copy->pw_uid = pw->pw_uid;
|
||||
copy->pw_gid = pw->pw_gid;
|
||||
copy->pw_class = xstrdup(pw->pw_class);
|
||||
copy->pw_dir = xstrdup(pw->pw_dir);
|
||||
copy->pw_shell = xstrdup(pw->pw_shell);
|
||||
copy->pw_expire = pw->pw_expire;
|
||||
copy->pw_change = pw->pw_change;
|
||||
return copy;
|
||||
Key *found;
|
||||
const char *resolvedname, *ipaddr, *lookup;
|
||||
struct stat st;
|
||||
char *user_hostfile;
|
||||
int host_status, len;
|
||||
|
||||
resolvedname = get_canonical_hostname(options.reverse_mapping_check);
|
||||
ipaddr = get_remote_ipaddr();
|
||||
|
||||
debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
|
||||
chost, resolvedname, ipaddr);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -35,24 +35,24 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "cipher.h"
|
||||
#include "kex.h"
|
||||
#include "dsa.h"
|
||||
#include "compat.h"
|
||||
#include "log.h"
|
||||
#include "atomicio.h"
|
||||
|
||||
/* helper */
|
||||
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. */
|
||||
|
||||
int
|
||||
ssh_get_authentication_socket()
|
||||
ssh_get_authentication_socket(void)
|
||||
{
|
||||
const char *authsocket;
|
||||
int sock, len;
|
||||
@ -76,7 +76,8 @@ ssh_get_authentication_socket()
|
||||
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
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);
|
||||
if (sock < 0)
|
||||
@ -118,6 +119,8 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply
|
||||
len = 4;
|
||||
while (len > 0) {
|
||||
l = read(auth->fd, buf + 4 - len, len);
|
||||
if (l == -1 && (errno == EAGAIN || errno == EINTR))
|
||||
continue;
|
||||
if (l <= 0) {
|
||||
error("Error reading response length from authentication socket.");
|
||||
return 0;
|
||||
@ -137,6 +140,8 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply
|
||||
if (l > sizeof(buf))
|
||||
l = sizeof(buf);
|
||||
l = read(auth->fd, buf, l);
|
||||
if (l == -1 && (errno == EAGAIN || errno == EINTR))
|
||||
continue;
|
||||
if (l <= 0) {
|
||||
error("Error reading response from authentication socket.");
|
||||
return 0;
|
||||
@ -169,7 +174,7 @@ ssh_close_authentication_socket(int sock)
|
||||
*/
|
||||
|
||||
AuthenticationConnection *
|
||||
ssh_get_authentication_connection()
|
||||
ssh_get_authentication_connection(void)
|
||||
{
|
||||
AuthenticationConnection *auth;
|
||||
int sock;
|
||||
@ -208,8 +213,8 @@ ssh_close_authentication_connection(AuthenticationConnection *auth)
|
||||
* Returns the first authentication identity held by the agent.
|
||||
*/
|
||||
|
||||
Key *
|
||||
ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
|
||||
int
|
||||
ssh_get_num_identities(AuthenticationConnection *auth, int version)
|
||||
{
|
||||
int type, code1 = 0, code2 = 0;
|
||||
Buffer request;
|
||||
@ -224,7 +229,7 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
|
||||
code2 = SSH2_AGENT_IDENTITIES_ANSWER;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -237,14 +242,14 @@ ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int versi
|
||||
buffer_clear(&auth->identities);
|
||||
if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
|
||||
buffer_free(&request);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
buffer_free(&request);
|
||||
|
||||
/* Get message type, and verify that we got a proper answer. */
|
||||
type = buffer_get_char(&auth->identities);
|
||||
if (agent_failed(type)) {
|
||||
return NULL;
|
||||
return 0;
|
||||
} else if (type != code2) {
|
||||
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. */
|
||||
auth->howmany = buffer_get_int(&auth->identities);
|
||||
if (auth->howmany > 1024)
|
||||
fatal("Too many identities in authentication reply: %d\n",
|
||||
fatal("Too many identities in authentication reply: %d",
|
||||
auth->howmany);
|
||||
|
||||
/* Return the first entry (if any). */
|
||||
return ssh_get_next_identity(auth, comment, version);
|
||||
return auth->howmany;
|
||||
}
|
||||
|
||||
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 *
|
||||
ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
u_int bits;
|
||||
u_char *blob;
|
||||
u_int blen;
|
||||
Key *key = NULL;
|
||||
|
||||
/* Return failure if no more entries. */
|
||||
@ -277,7 +290,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
|
||||
*/
|
||||
switch(version){
|
||||
case 1:
|
||||
key = key_new(KEY_RSA);
|
||||
key = key_new(KEY_RSA1);
|
||||
bits = buffer_get_int(&auth->identities);
|
||||
buffer_get_bignum(&auth->identities, key->rsa->e);
|
||||
buffer_get_bignum(&auth->identities, key->rsa->n);
|
||||
@ -289,7 +302,7 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
|
||||
case 2:
|
||||
blob = buffer_get_string(&auth->identities, &blen);
|
||||
*comment = buffer_get_string(&auth->identities, NULL);
|
||||
key = dsa_key_from_blob(blob, blen);
|
||||
key = key_from_blob(blob, blen);
|
||||
xfree(blob);
|
||||
break;
|
||||
default:
|
||||
@ -312,16 +325,16 @@ ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int versio
|
||||
int
|
||||
ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
Key* key, BIGNUM *challenge,
|
||||
unsigned char session_id[16],
|
||||
unsigned int response_type,
|
||||
unsigned char response[16])
|
||||
u_char session_id[16],
|
||||
u_int response_type,
|
||||
u_char response[16])
|
||||
{
|
||||
Buffer buffer;
|
||||
int success = 0;
|
||||
int i;
|
||||
int type;
|
||||
|
||||
if (key->type != KEY_RSA)
|
||||
if (key->type != KEY_RSA1)
|
||||
return 0;
|
||||
if (response_type == 0) {
|
||||
log("Compatibility with ssh protocol version 1.0 no longer supported.");
|
||||
@ -363,17 +376,17 @@ ssh_decrypt_challenge(AuthenticationConnection *auth,
|
||||
int
|
||||
ssh_agent_sign(AuthenticationConnection *auth,
|
||||
Key *key,
|
||||
unsigned char **sigp, int *lenp,
|
||||
unsigned char *data, int datalen)
|
||||
u_char **sigp, int *lenp,
|
||||
u_char *data, int datalen)
|
||||
{
|
||||
extern int datafellows;
|
||||
Buffer msg;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
u_char *blob;
|
||||
u_int blen;
|
||||
int type, flags = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (dsa_make_key_blob(key, &blob, &blen) == 0)
|
||||
if (key_to_blob(key, &blob, &blen) == 0)
|
||||
return -1;
|
||||
|
||||
if (datafellows & SSH_BUG_SIGBLOB)
|
||||
@ -406,7 +419,7 @@ ssh_agent_sign(AuthenticationConnection *auth,
|
||||
/* Encode key for a message to the agent. */
|
||||
|
||||
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_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
|
||||
@ -422,17 +435,29 @@ ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
|
||||
}
|
||||
|
||||
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_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
|
||||
buffer_put_cstring(b, KEX_DSS);
|
||||
buffer_put_bignum2(b, key->p);
|
||||
buffer_put_bignum2(b, key->q);
|
||||
buffer_put_bignum2(b, key->g);
|
||||
buffer_put_bignum2(b, key->pub_key);
|
||||
buffer_put_bignum2(b, key->priv_key);
|
||||
buffer_put_string(b, comment, strlen(comment));
|
||||
buffer_put_cstring(b, key_ssh_name(key));
|
||||
switch(key->type){
|
||||
case KEY_RSA:
|
||||
buffer_put_bignum2(b, key->rsa->n);
|
||||
buffer_put_bignum2(b, key->rsa->e);
|
||||
buffer_put_bignum2(b, key->rsa->d);
|
||||
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);
|
||||
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
ssh_encode_identity_rsa(&msg, key->rsa, comment);
|
||||
case KEY_RSA1:
|
||||
ssh_encode_identity_rsa1(&msg, key->rsa, comment);
|
||||
break;
|
||||
case KEY_RSA:
|
||||
case KEY_DSA:
|
||||
ssh_encode_identity_dsa(&msg, key->dsa, comment);
|
||||
ssh_encode_identity_ssh2(&msg, key, comment);
|
||||
break;
|
||||
default:
|
||||
buffer_free(&msg);
|
||||
@ -479,18 +505,18 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
|
||||
{
|
||||
Buffer msg;
|
||||
int type;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
u_char *blob;
|
||||
u_int blen;
|
||||
|
||||
buffer_init(&msg);
|
||||
|
||||
if (key->type == KEY_RSA) {
|
||||
if (key->type == KEY_RSA1) {
|
||||
buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
|
||||
buffer_put_int(&msg, BN_num_bits(key->rsa->n));
|
||||
buffer_put_bignum(&msg, key->rsa->e);
|
||||
buffer_put_bignum(&msg, key->rsa->n);
|
||||
} else if (key->type == KEY_DSA) {
|
||||
dsa_make_key_blob(key, &blob, &blen);
|
||||
} else if (key->type == KEY_DSA || key->type == KEY_RSA) {
|
||||
key_to_blob(key, &blob, &blen);
|
||||
buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
|
||||
buffer_put_string(&msg, blob, blen);
|
||||
xfree(blob);
|
||||
@ -533,7 +559,7 @@ ssh_remove_all_identities(AuthenticationConnection *auth, int version)
|
||||
return decode_reply(type);
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
decode_reply(int type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -36,23 +36,25 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include "cipher.h"
|
||||
#include "xmalloc.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "ssh.h"
|
||||
#include "key.h"
|
||||
#include "ssh.h"
|
||||
#include "log.h"
|
||||
#include "authfile.h"
|
||||
|
||||
/* Version identification string for identity files. */
|
||||
#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||
/* Version identification string for SSH v1 identity files. */
|
||||
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
|
||||
@ -62,8 +64,8 @@ RCSID("$FreeBSD$");
|
||||
*/
|
||||
|
||||
int
|
||||
save_private_key_rsa(const char *filename, const char *passphrase,
|
||||
RSA *key, const char *comment)
|
||||
key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
|
||||
const char *comment)
|
||||
{
|
||||
Buffer buffer, encrypted;
|
||||
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
|
||||
* format would just give known plaintext).
|
||||
*/
|
||||
buffer_put_bignum(&buffer, key->d);
|
||||
buffer_put_bignum(&buffer, key->iqmp);
|
||||
buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
|
||||
buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */
|
||||
buffer_put_bignum(&buffer, key->rsa->d);
|
||||
buffer_put_bignum(&buffer, key->rsa->iqmp);
|
||||
buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
|
||||
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. */
|
||||
while (buffer_len(&buffer) % 8 != 0)
|
||||
@ -112,9 +114,8 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
||||
buffer_init(&encrypted);
|
||||
|
||||
/* First store keyfile id string. */
|
||||
cp = AUTHFILE_ID_STRING;
|
||||
for (i = 0; cp[i]; i++)
|
||||
buffer_put_char(&encrypted, cp[i]);
|
||||
for (i = 0; authfile_id_string[i]; i++)
|
||||
buffer_put_char(&encrypted, authfile_id_string[i]);
|
||||
buffer_put_char(&encrypted, 0);
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Store public key. This will be in plain text. */
|
||||
buffer_put_int(&encrypted, BN_num_bits(key->n));
|
||||
buffer_put_bignum(&encrypted, key->n);
|
||||
buffer_put_bignum(&encrypted, key->e);
|
||||
buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
|
||||
buffer_put_bignum(&encrypted, key->rsa->n);
|
||||
buffer_put_bignum(&encrypted, key->rsa->e);
|
||||
buffer_put_string(&encrypted, comment, strlen(comment));
|
||||
|
||||
/* Allocate space for the private part of the key in the buffer. */
|
||||
buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
|
||||
|
||||
cipher_set_key_string(&ciphercontext, cipher, passphrase);
|
||||
cipher_encrypt(&ciphercontext, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer));
|
||||
cipher_encrypt(&ciphercontext, (u_char *) cp,
|
||||
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
|
||||
memset(&ciphercontext, 0, sizeof(ciphercontext));
|
||||
|
||||
/* Destroy temporary data. */
|
||||
@ -140,15 +141,17 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
||||
buffer_free(&buffer);
|
||||
|
||||
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;
|
||||
}
|
||||
if (write(fd, buffer_ptr(&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));
|
||||
buffer_free(&encrypted);
|
||||
close(fd);
|
||||
remove(filename);
|
||||
unlink(filename);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
@ -156,80 +159,168 @@ save_private_key_rsa(const char *filename, const char *passphrase,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* save DSA key in OpenSSL PEM format */
|
||||
|
||||
/* save SSH v2 key in OpenSSL PEM format */
|
||||
int
|
||||
save_private_key_dsa(const char *filename, const char *passphrase,
|
||||
DSA *dsa, const char *comment)
|
||||
key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
|
||||
const char *comment)
|
||||
{
|
||||
FILE *fp;
|
||||
int fd;
|
||||
int success = 1;
|
||||
int len = strlen(passphrase);
|
||||
int success = 0;
|
||||
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) {
|
||||
error("passphrase too short: %d bytes", len);
|
||||
errno = 0;
|
||||
error("passphrase too short: have %d bytes, need > 4", len);
|
||||
return 0;
|
||||
}
|
||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
debug("open %s failed", filename);
|
||||
error("open %s failed: %s.", filename, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
fp = fdopen(fd, "w");
|
||||
if (fp == NULL ) {
|
||||
debug("fdopen %s failed", filename);
|
||||
error("fdopen %s failed: %s.", filename, strerror(errno));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
if (len > 0) {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
|
||||
(char *)passphrase, strlen(passphrase), NULL, NULL))
|
||||
success = 0;
|
||||
} else {
|
||||
if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
|
||||
NULL, 0, NULL, NULL))
|
||||
success = 0;
|
||||
switch (key->type) {
|
||||
case KEY_DSA:
|
||||
success = PEM_write_DSAPrivateKey(fp, key->dsa,
|
||||
cipher, passphrase, len, NULL, NULL);
|
||||
break;
|
||||
case KEY_RSA:
|
||||
success = PEM_write_RSAPrivateKey(fp, key->rsa,
|
||||
cipher, passphrase, len, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
return success;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
return save_private_key_rsa(filename, passphrase, key->rsa, comment);
|
||||
case KEY_RSA1:
|
||||
return key_save_private_rsa1(key, filename, passphrase,
|
||||
comment);
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
error("key_save_private: cannot save key type %d", key->type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the public part of the key file. Returns 0 if an error was
|
||||
* encountered (the file does not exist or is not readable), and non-zero
|
||||
* 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 the key
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
|
||||
Key *
|
||||
key_load_public_rsa1(int fd, const char *filename, char **commentp)
|
||||
{
|
||||
int fd, i;
|
||||
off_t len;
|
||||
Buffer buffer;
|
||||
Key *pub;
|
||||
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);
|
||||
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));
|
||||
buffer_free(&buffer);
|
||||
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
|
||||
* 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));
|
||||
/* 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);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* 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) != (unsigned char) AUTHFILE_ID_STRING[i]) {
|
||||
debug("Bad key file %.200s.", filename);
|
||||
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 0;
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read cipher type. */
|
||||
cipher_type = buffer_get_char(&buffer);
|
||||
(void) buffer_get_int(&buffer); /* Reserved data. */
|
||||
|
||||
/* Read the public key from the buffer. */
|
||||
buffer_get_int(&buffer);
|
||||
prv->n = BN_new();
|
||||
buffer_get_bignum(&buffer, prv->n);
|
||||
prv->e = BN_new();
|
||||
buffer_get_bignum(&buffer, prv->e);
|
||||
if (comment_return)
|
||||
*comment_return = buffer_get_string(&buffer, NULL);
|
||||
prv = key_new_private(KEY_RSA1);
|
||||
|
||||
buffer_get_bignum(&buffer, prv->rsa->n);
|
||||
buffer_get_bignum(&buffer, prv->rsa->e);
|
||||
if (commentp)
|
||||
*commentp = buffer_get_string(&buffer, NULL);
|
||||
else
|
||||
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. */
|
||||
cipher_set_key_string(&ciphercontext, cipher, passphrase);
|
||||
cipher_decrypt(&ciphercontext, (unsigned char *) cp,
|
||||
(unsigned char *) buffer_ptr(&buffer), buffer_len(&buffer));
|
||||
cipher_decrypt(&ciphercontext, (u_char *) cp,
|
||||
(u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
|
||||
memset(&ciphercontext, 0, sizeof(ciphercontext));
|
||||
buffer_free(&buffer);
|
||||
|
||||
@ -389,138 +393,183 @@ load_private_key_rsa(int fd, const char *filename,
|
||||
if (check1 != buffer_get_char(&decrypted) ||
|
||||
check2 != buffer_get_char(&decrypted)) {
|
||||
if (strcmp(passphrase, "") != 0)
|
||||
debug("Bad passphrase supplied for key file %.200s.", filename);
|
||||
debug("Bad passphrase supplied for key file %.200s.",
|
||||
filename);
|
||||
/* Bad passphrase. */
|
||||
buffer_free(&decrypted);
|
||||
fail:
|
||||
BN_clear_free(prv->n);
|
||||
prv->n = NULL;
|
||||
BN_clear_free(prv->e);
|
||||
prv->e = NULL;
|
||||
if (comment_return)
|
||||
xfree(*comment_return);
|
||||
return 0;
|
||||
goto fail;
|
||||
}
|
||||
/* Read the rest of the private key. */
|
||||
prv->d = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->d);
|
||||
prv->iqmp = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->iqmp); /* u */
|
||||
/* in SSL and SSH p and q are exchanged */
|
||||
prv->q = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->q); /* p */
|
||||
prv->p = BN_new();
|
||||
buffer_get_bignum(&decrypted, prv->p); /* q */
|
||||
buffer_get_bignum(&decrypted, prv->rsa->d);
|
||||
buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
|
||||
/* in SSL and SSH v1 p and q are exchanged */
|
||||
buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
|
||||
buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
|
||||
|
||||
/* calculate p-1 and q-1 */
|
||||
ctx = BN_CTX_new();
|
||||
aux = BN_new();
|
||||
|
||||
BN_sub(aux, prv->q, BN_value_one());
|
||||
prv->dmq1 = BN_new();
|
||||
BN_mod(prv->dmq1, prv->d, aux, ctx);
|
||||
BN_sub(aux, prv->rsa->q, BN_value_one());
|
||||
BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
|
||||
|
||||
BN_sub(aux, prv->p, BN_value_one());
|
||||
prv->dmp1 = BN_new();
|
||||
BN_mod(prv->dmp1, prv->d, aux, ctx);
|
||||
BN_sub(aux, prv->rsa->p, BN_value_one());
|
||||
BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
|
||||
|
||||
BN_clear_free(aux);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
buffer_free(&decrypted);
|
||||
close(fd);
|
||||
return prv;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
if (commentp)
|
||||
xfree(*commentp);
|
||||
close(fd);
|
||||
key_free(prv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
|
||||
Key *
|
||||
key_load_private_pem(int fd, int type, const char *passphrase,
|
||||
char **commentp)
|
||||
{
|
||||
DSA *dsa;
|
||||
BIO *in;
|
||||
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");
|
||||
if (fp == NULL) {
|
||||
error("fdopen failed");
|
||||
return 0;
|
||||
error("fdopen failed: %s", strerror(errno));
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
BIO_set_fp(in, fp, BIO_NOCLOSE);
|
||||
dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
|
||||
if (dsa == NULL) {
|
||||
debug("PEM_read_bio_DSAPrivateKey failed");
|
||||
} else {
|
||||
/* replace k->dsa with loaded key */
|
||||
DSA_free(k->dsa);
|
||||
k->dsa = dsa;
|
||||
}
|
||||
BIO_free(in);
|
||||
fclose(fp);
|
||||
if (comment_return)
|
||||
*comment_return = xstrdup("dsa w/o comment");
|
||||
debug("read DSA private key done");
|
||||
#ifdef DEBUG_DSS
|
||||
DSA_print_fp(stderr, dsa, 8);
|
||||
pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
|
||||
if (pk == NULL) {
|
||||
debug("PEM_read_PrivateKey failed");
|
||||
(void)ERR_get_error();
|
||||
} else if (pk->type == EVP_PKEY_RSA &&
|
||||
(type == KEY_UNSPEC||type==KEY_RSA)) {
|
||||
prv = key_new(KEY_UNSPEC);
|
||||
prv->rsa = EVP_PKEY_get1_RSA(pk);
|
||||
prv->type = KEY_RSA;
|
||||
name = "rsa w/o comment";
|
||||
#ifdef DEBUG_PK
|
||||
RSA_print_fp(stderr, prv->rsa, 8);
|
||||
#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
|
||||
load_private_key(const char *filename, const char *passphrase, Key *key,
|
||||
char **comment_return)
|
||||
key_perm_ok(int fd, const char *filename)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
/* check owner and modes */
|
||||
if (fstat(fd, &st) < 0 ||
|
||||
(st.st_uid != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
|
||||
(st.st_mode & 077) != 0) {
|
||||
close(fd);
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("Bad ownership or mode(0%3.3o) for '%s'.",
|
||||
st.st_mode & 0777, filename);
|
||||
st.st_mode & 0777, filename);
|
||||
error("It is recommended that your private key files are NOT accessible by others.");
|
||||
error("This private key will be ignored.");
|
||||
return 0;
|
||||
}
|
||||
switch (key->type) {
|
||||
case KEY_RSA:
|
||||
if (key->rsa->e != NULL) {
|
||||
BN_clear_free(key->rsa->e);
|
||||
key->rsa->e = NULL;
|
||||
}
|
||||
if (key->rsa->n != NULL) {
|
||||
BN_clear_free(key->rsa->n);
|
||||
key->rsa->n = NULL;
|
||||
}
|
||||
ret = load_private_key_rsa(fd, filename, passphrase,
|
||||
key->rsa, comment_return);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Key *
|
||||
key_load_private_type(int type, const char *filename, const char *passphrase,
|
||||
char **commentp)
|
||||
{
|
||||
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;
|
||||
}
|
||||
switch (type) {
|
||||
case KEY_RSA1:
|
||||
return key_load_private_rsa1(fd, filename, passphrase,
|
||||
commentp);
|
||||
/* closes fd */
|
||||
break;
|
||||
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:
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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
|
||||
do_load_public_key(const char *filename, Key *k, char **commentp)
|
||||
key_try_load_public(Key *k, const char *filename, char **commentp)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned int bits;
|
||||
char line[1024];
|
||||
char line[4096];
|
||||
char *cp;
|
||||
|
||||
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++)
|
||||
;
|
||||
if (*cp) {
|
||||
bits = key_read(k, &cp);
|
||||
if (bits != 0) {
|
||||
if (key_read(k, &cp) == 1) {
|
||||
if (commentp)
|
||||
*commentp=xstrdup(filename);
|
||||
fclose(f);
|
||||
@ -552,19 +600,23 @@ do_load_public_key(const char *filename, Key *k, char **commentp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load public key from pubkey file */
|
||||
int
|
||||
try_load_public_key(const char *filename, Key *k, char **commentp)
|
||||
/* load public key from ssh v1 private or any pubkey file */
|
||||
Key *
|
||||
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)
|
||||
return 1;
|
||||
if (strlcpy(pub, filename, sizeof pub) >= MAXPATHLEN)
|
||||
return 0;
|
||||
if (strlcat(pub, ".pub", sizeof pub) >= MAXPATHLEN)
|
||||
return 0;
|
||||
if (do_load_public_key(pub, k, commentp) == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
pub = key_load_public_type(KEY_RSA1, filename, commentp);
|
||||
if (pub != NULL)
|
||||
return pub;
|
||||
pub = key_new(KEY_UNSPEC);
|
||||
if (key_try_load_public(pub, filename, commentp) == 1)
|
||||
return pub;
|
||||
if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
|
||||
(strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
|
||||
(key_try_load_public(pub, file, commentp) == 1))
|
||||
return pub;
|
||||
key_free(pub);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -37,14 +37,14 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "ssh.h"
|
||||
#include <openssl/bn.h>
|
||||
#include "bufaux.h"
|
||||
#include "xmalloc.h"
|
||||
#include "getput.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* 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 bin_size = (bits + 7) / 8;
|
||||
char unsigned *buf = xmalloc(bin_size);
|
||||
u_char *buf = xmalloc(bin_size);
|
||||
int oi;
|
||||
char msg[2];
|
||||
|
||||
@ -82,7 +82,7 @@ int
|
||||
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bits, bytes;
|
||||
unsigned char buf[2], *bin;
|
||||
u_char buf[2], *bin;
|
||||
|
||||
/* Get the number for bits. */
|
||||
buffer_get(buffer, (char *) buf, 2);
|
||||
@ -91,7 +91,7 @@ buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
bytes = (bits + 7) / 8;
|
||||
if (buffer_len(buffer) < bytes)
|
||||
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);
|
||||
buffer_consume(buffer, bytes);
|
||||
|
||||
@ -105,7 +105,7 @@ void
|
||||
buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int bytes = BN_num_bytes(value) + 1;
|
||||
unsigned char *buf = xmalloc(bytes);
|
||||
u_char *buf = xmalloc(bytes);
|
||||
int oi;
|
||||
int hasnohigh = 0;
|
||||
buf[0] = '\0';
|
||||
@ -118,7 +118,7 @@ buffer_put_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
if (value->neg) {
|
||||
/**XXX should be two's-complement */
|
||||
int i, carry;
|
||||
unsigned char *uc = buf;
|
||||
u_char *uc = buf;
|
||||
log("negativ!");
|
||||
for(i = bytes-1, carry = 1; i>=0; i--) {
|
||||
uc[i] ^= 0xff;
|
||||
@ -136,7 +136,7 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
/**XXX should be two's-complement */
|
||||
int len;
|
||||
unsigned char *bin = (unsigned char *)buffer_get_string(buffer, (unsigned int *)&len);
|
||||
u_char *bin = (u_char *)buffer_get_string(buffer, (u_int *)&len);
|
||||
BN_bin2bn(bin, len, value);
|
||||
xfree(bin);
|
||||
return len;
|
||||
@ -145,25 +145,41 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
|
||||
/*
|
||||
* Returns an integer from the buffer (4 bytes, msb first).
|
||||
*/
|
||||
unsigned int
|
||||
u_int
|
||||
buffer_get_int(Buffer *buffer)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
u_char buf[4];
|
||||
buffer_get(buffer, (char *) buf, 4);
|
||||
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.
|
||||
*/
|
||||
void
|
||||
buffer_put_int(Buffer *buffer, unsigned int value)
|
||||
buffer_put_int(Buffer *buffer, u_int value)
|
||||
{
|
||||
char buf[4];
|
||||
PUT_32BIT(buf, value);
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
/* Get the length. */
|
||||
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.
|
||||
*/
|
||||
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_append(buffer, buf, len);
|
||||
@ -216,7 +232,7 @@ buffer_get_char(Buffer *buffer)
|
||||
{
|
||||
char ch;
|
||||
buffer_get(buffer, &ch, 1);
|
||||
return (unsigned char) ch;
|
||||
return (u_char) ch;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -12,12 +12,15 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "packet.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
|
||||
@ -25,121 +28,124 @@ RCSID("$FreeBSD$");
|
||||
*/
|
||||
|
||||
char *
|
||||
get_remote_hostname(int socket)
|
||||
get_remote_hostname(int socket, int reverse_mapping_check)
|
||||
{
|
||||
struct sockaddr_storage from;
|
||||
int i;
|
||||
socklen_t fromlen;
|
||||
struct addrinfo hints, *ai, *aitop;
|
||||
char name[MAXHOSTNAMELEN];
|
||||
char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
|
||||
char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
|
||||
|
||||
/* Get IP address of client. */
|
||||
fromlen = 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));
|
||||
fatal_cleanup();
|
||||
}
|
||||
if (from.ss_family == AF_INET)
|
||||
check_ip_options(socket, ntop);
|
||||
|
||||
if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
|
||||
NULL, 0, NI_NUMERICHOST) != 0)
|
||||
fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
|
||||
|
||||
debug3("Trying to reverse map address %.100s.", ntop);
|
||||
/* Map the IP address to a host name. */
|
||||
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
|
||||
NULL, 0, NI_NAMEREQD) == 0) {
|
||||
/* Got host name. */
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
/*
|
||||
* 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);
|
||||
NULL, 0, NI_NAMEREQD) != 0) {
|
||||
/* Host name not found. Use ip address. */
|
||||
log("Could not reverse map address %.100s.", ntop);
|
||||
return xstrdup(ntop);
|
||||
}
|
||||
|
||||
check_ip_options:
|
||||
|
||||
/* Got host name. */
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
/*
|
||||
* 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.
|
||||
* Convert it to all lowercase (which is expected by the rest
|
||||
* of this software).
|
||||
*/
|
||||
/* IP options -- IPv4 only */
|
||||
if (from.ss_family == AF_INET) {
|
||||
unsigned char options[200], *ucp;
|
||||
char text[1024], *cp;
|
||||
socklen_t option_size;
|
||||
int ipproto;
|
||||
struct protoent *ip;
|
||||
for (i = 0; name[i]; i++)
|
||||
if (isupper(name[i]))
|
||||
name[i] = tolower(name[i]);
|
||||
|
||||
if ((ip = getprotobyname("ip")) != NULL)
|
||||
ipproto = ip->p_proto;
|
||||
else
|
||||
ipproto = IPPROTO_IP;
|
||||
option_size = sizeof(options);
|
||||
if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options,
|
||||
&option_size) >= 0 && option_size != 0) {
|
||||
cp = text;
|
||||
/* Note: "text" buffer must be at least 3x as big as options. */
|
||||
for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
|
||||
sprintf(cp, " %2.2x", *ucp);
|
||||
log("Connection from %.100s with IP options:%.800s",
|
||||
ntop, text);
|
||||
packet_disconnect("Connection from %.100s with IP options:%.800s",
|
||||
ntop, text);
|
||||
}
|
||||
if (!reverse_mapping_check)
|
||||
return xstrdup(name);
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* connection. The host name is cached, so it is efficient to call this
|
||||
@ -147,23 +153,87 @@ get_remote_hostname(int socket)
|
||||
*/
|
||||
|
||||
const char *
|
||||
get_canonical_hostname()
|
||||
get_canonical_hostname(int reverse_mapping_check)
|
||||
{
|
||||
static char *canonical_host_name = NULL;
|
||||
static int reverse_mapping_checked = 0;
|
||||
|
||||
/* Check if we have previously retrieved this same name. */
|
||||
if (canonical_host_name != NULL)
|
||||
return canonical_host_name;
|
||||
/* Check if we have previously retrieved name with same option. */
|
||||
if (canonical_host_name != NULL) {
|
||||
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. */
|
||||
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
|
||||
canonical_host_name = xstrdup("UNKNOWN");
|
||||
|
||||
reverse_mapping_checked = reverse_mapping_check;
|
||||
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
|
||||
* string must not be freed.
|
||||
@ -173,68 +243,31 @@ const char *
|
||||
get_remote_ipaddr()
|
||||
{
|
||||
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. */
|
||||
if (canonical_host_ip != NULL)
|
||||
return canonical_host_ip;
|
||||
|
||||
/* If not a socket, return UNKNOWN. */
|
||||
if (!packet_connection_is_on_socket()) {
|
||||
canonical_host_ip = xstrdup("UNKNOWN");
|
||||
return canonical_host_ip;
|
||||
/* Check whether we have cached the ipaddr. */
|
||||
if (canonical_host_ip == NULL) {
|
||||
if (packet_connection_is_on_socket()) {
|
||||
canonical_host_ip =
|
||||
get_peer_ipaddr(packet_get_connection_in());
|
||||
if (canonical_host_ip == NULL)
|
||||
fatal_cleanup();
|
||||
} 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the IP-address of the local host as a string. The returned
|
||||
* string must be freed.
|
||||
*/
|
||||
|
||||
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;
|
||||
struct sockaddr_storage from;
|
||||
socklen_t fromlen;
|
||||
char ntop[NI_MAXHOST];
|
||||
|
||||
/* Get IP address of server. */
|
||||
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);
|
||||
static const char *remote = "";
|
||||
if (utmp_len > 0)
|
||||
remote = get_canonical_hostname(reverse_mapping_check);
|
||||
if (utmp_len == 0 || strlen(remote) > utmp_len)
|
||||
remote = get_remote_ipaddr();
|
||||
return remote;
|
||||
}
|
||||
|
||||
/* Returns the local/remote port for the socket. */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,12 +32,14 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
/* RCSID("$OpenBSD: channels.h,v 1.22 2000/10/27 07:48:22 markus Exp $"); */
|
||||
|
||||
#ifndef CHANNELS_H
|
||||
#define CHANNELS_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
/* Definitions for channel types. */
|
||||
#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
|
||||
#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_OUTPUT_DRAINING 9 /* sending remaining data to app */
|
||||
#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
|
||||
@ -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_port_open(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. */
|
||||
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. */
|
||||
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
|
||||
@ -189,9 +198,6 @@ void channel_stop_listening(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. */
|
||||
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
|
||||
* channel to host:port from remote side. This never returns if there was an
|
||||
* error.
|
||||
* channel to host:port from remote side.
|
||||
*/
|
||||
void
|
||||
channel_request_local_forwarding(u_short port, const char *host,
|
||||
u_short remote_port, int gateway_ports);
|
||||
int
|
||||
channel_request_local_forwarding(u_short listen_port,
|
||||
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
|
||||
@ -222,12 +231,18 @@ channel_request_remote_forwarding(u_short port, const char *host,
|
||||
u_short remote_port);
|
||||
|
||||
/*
|
||||
* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually
|
||||
* called by the server, because the user could connect to any port anyway,
|
||||
* and the server has no way to know but to trust the client anyway.
|
||||
* Permits opening to any host/port if permitted_opens[] is empty. This is
|
||||
* usually called by the server, because the user could connect to any port
|
||||
* anyway, and the server has no way to know but to trust the client anyway.
|
||||
*/
|
||||
void channel_permit_all_opens(void);
|
||||
|
||||
/* 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
|
||||
* 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 */
|
||||
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 channel_find_open(void);
|
||||
|
||||
#endif
|
||||
|
@ -35,11 +35,12 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "log.h"
|
||||
#include "cipher.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);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
|
||||
memcpy(&iv1, dest + len - 8, 8);
|
||||
|
||||
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);
|
||||
des_ncbc_encrypt(src, dest, len, cc->u.des3.key1, &iv1, DES_ENCRYPT);
|
||||
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);
|
||||
}
|
||||
void
|
||||
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);
|
||||
|
||||
des_cbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
|
||||
memcpy(iv3, src + len - 8, 8);
|
||||
|
||||
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. */
|
||||
des_ncbc_encrypt(src, dest, len, cc->u.des3.key3, iv3, DES_DECRYPT);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Blowfish */
|
||||
void
|
||||
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
|
||||
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).
|
||||
*/
|
||||
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];
|
||||
|
||||
@ -272,12 +262,12 @@ arcfour_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len)
|
||||
void
|
||||
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
|
||||
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);
|
||||
memcpy(cc->u.cast.iv, (char *)iv, 8);
|
||||
}
|
||||
@ -306,7 +296,7 @@ rijndael_setkey(CipherContext *cc, const u_char *key, u_int keylen)
|
||||
void
|
||||
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);
|
||||
memcpy((u_char *)cc->u.rijndael.iv, iv, RIJNDAEL_BLOCKSIZE);
|
||||
}
|
||||
@ -426,15 +416,15 @@ Cipher ciphers[] = {
|
||||
SSH_CIPHER_SSH2, 16, 32,
|
||||
rijndael_setkey, rijndael_setiv,
|
||||
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)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
u_int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
if (client) {
|
||||
@ -553,7 +543,7 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
|
||||
const char *passphrase)
|
||||
{
|
||||
MD5_CTX md;
|
||||
unsigned char digest[16];
|
||||
u_char digest[16];
|
||||
|
||||
MD5_Init(&md);
|
||||
MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase));
|
||||
|
@ -32,8 +32,8 @@
|
||||
* 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 $"); */
|
||||
/* $FreeBSD$ */
|
||||
/* RCSID("$OpenBSD: cipher.h,v 1.25 2000/12/19 23:17:56 markus Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
|
||||
#ifndef CIPHER_H
|
||||
#define CIPHER_H
|
||||
@ -104,7 +104,7 @@ struct Cipher {
|
||||
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_number(int id);
|
||||
int cipher_number(const char *name);
|
||||
|
@ -24,13 +24,14 @@
|
||||
|
||||
#include "includes.h"
|
||||
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 "xmalloc.h"
|
||||
#include "compat.h"
|
||||
#include <regex.h>
|
||||
#include "log.h"
|
||||
|
||||
int compat13 = 0;
|
||||
int compat20 = 0;
|
||||
@ -59,22 +60,55 @@ compat_datafellows(const char *version)
|
||||
char *pat;
|
||||
int bugs;
|
||||
} check[] = {
|
||||
{ "^OpenSSH[-_]2\\.3", 0 },
|
||||
{ "^OpenSSH[-_]2\\.[012]", SSH_OLD_SESSIONID },
|
||||
{ "^OpenSSH[-_]2\\.[012]",
|
||||
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 },
|
||||
{ "^2\\.1\\.0 ", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
|
||||
SSH_OLD_SESSIONID },
|
||||
{ "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
|
||||
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|
|
||||
SSH_OLD_SESSIONID|
|
||||
SSH_BUG_PUBKEYAUTH|SSH_BUG_X11FWD },
|
||||
{ "^2\\.[23]\\.0 ", SSH_BUG_HMAC},
|
||||
SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
|
||||
SSH_BUG_PKSERVICE|SSH_BUG_X11FWD|
|
||||
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\\.4$", SSH_OLD_SESSIONID}, /* Van Dyke */
|
||||
{ "^3\\.0 SecureCRT", SSH_OLD_SESSIONID},
|
||||
{ "^1\\.7 SecureFX", SSH_OLD_SESSIONID},
|
||||
{ "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG},
|
||||
{ "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG},
|
||||
{ "^2\\.", SSH_BUG_HMAC}, /* XXX fallback */
|
||||
{ "^2\\.4$", SSH_OLD_SESSIONID }, /* Van Dyke */
|
||||
{ "^3\\.0 SecureCRT", SSH_OLD_SESSIONID },
|
||||
{ "^1\\.7 SecureFX", SSH_OLD_SESSIONID },
|
||||
{ "^1\\.2\\.1[89]", SSH_BUG_IGNOREMSG },
|
||||
{ "^1\\.2\\.2[012]", SSH_BUG_IGNOREMSG },
|
||||
{ "^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 }
|
||||
};
|
||||
/* process table, return first match */
|
||||
@ -89,7 +123,7 @@ compat_datafellows(const char *version)
|
||||
ret = regexec(®, version, 0, NULL, 0);
|
||||
regfree(®);
|
||||
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;
|
||||
return;
|
||||
}
|
||||
@ -125,3 +159,33 @@ proto_spec(const char *spec)
|
||||
xfree(s);
|
||||
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);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/* 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
|
||||
#define COMPAT_H
|
||||
@ -32,17 +32,29 @@
|
||||
#define SSH_PROTO_1_PREFERRED 0x02
|
||||
#define SSH_PROTO_2 0x04
|
||||
|
||||
#define SSH_BUG_SIGBLOB 0x01
|
||||
#define SSH_BUG_PUBKEYAUTH 0x02
|
||||
#define SSH_BUG_HMAC 0x04
|
||||
#define SSH_BUG_X11FWD 0x08
|
||||
#define SSH_OLD_SESSIONID 0x10
|
||||
#define SSH_BUG_IGNOREMSG 0x20
|
||||
#define SSH_BUG_SIGBLOB 0x0001
|
||||
#define SSH_BUG_PKSERVICE 0x0002
|
||||
#define SSH_BUG_HMAC 0x0004
|
||||
#define SSH_BUG_X11FWD 0x0008
|
||||
#define SSH_OLD_SESSIONID 0x0010
|
||||
#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_compat20(void);
|
||||
void compat_datafellows(const char *s);
|
||||
int proto_spec(const char *spec);
|
||||
char *compat_cipher_proposal(char *cipher_prop);
|
||||
extern int compat13;
|
||||
extern int compat20;
|
||||
extern int datafellows;
|
||||
|
@ -36,16 +36,14 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "packet.h"
|
||||
#include "match.h"
|
||||
#include "ssh.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "key.h"
|
||||
#include "hostfile.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
|
||||
@ -53,17 +51,15 @@ RCSID("$FreeBSD$");
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/* Skip leading whitespace. */
|
||||
for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
|
||||
bits = key_read(ret, &cp);
|
||||
if (bits == 0)
|
||||
if (key_read(ret, &cp) != 1)
|
||||
return 0;
|
||||
|
||||
/* Skip trailing whitespace. */
|
||||
@ -72,14 +68,14 @@ hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret)
|
||||
|
||||
/* Return results. */
|
||||
*cpp = cp;
|
||||
*bitsp = bits;
|
||||
*bitsp = key_size(ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
BN_copy(e, k->rsa->e);
|
||||
BN_copy(n, k->rsa->n);
|
||||
@ -90,7 +86,7 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n)
|
||||
int
|
||||
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;
|
||||
if (bits != BN_num_bits(key->rsa->n)) {
|
||||
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
|
||||
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;
|
||||
char line[8192];
|
||||
int linenum = 0;
|
||||
unsigned int kbits, hostlen;
|
||||
u_int kbits;
|
||||
char *cp, *cp2;
|
||||
HostStatus end_return;
|
||||
|
||||
debug3("check_host_in_hostfile: filename %s", filename);
|
||||
if (key == NULL)
|
||||
fatal("no key to look up");
|
||||
/* 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)
|
||||
return HOST_NEW;
|
||||
|
||||
/* Cache the length of the host name. */
|
||||
hostlen = strlen(host);
|
||||
|
||||
/*
|
||||
* Return value when the loop terminates. This is set to
|
||||
* 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;
|
||||
|
||||
/* Go trough the file. */
|
||||
/* Go through the file. */
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
cp = line;
|
||||
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. */
|
||||
if (match_hostname(host, cp, (unsigned int) (cp2 - cp)) != 1)
|
||||
if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1)
|
||||
continue;
|
||||
|
||||
/* 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))
|
||||
continue;
|
||||
|
||||
if (numret != NULL)
|
||||
*numret = linenum;
|
||||
|
||||
/* Check if the current key is the same as the given key. */
|
||||
if (key_equal(key, found)) {
|
||||
/* Ok, they match. */
|
||||
debug3("check_host_in_hostfile: match line %d", linenum);
|
||||
fclose(f);
|
||||
return HOST_OK;
|
||||
}
|
||||
|
@ -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>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -31,21 +31,21 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ssh.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "dsa.h"
|
||||
#include "uuencode.h"
|
||||
|
||||
RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $");
|
||||
RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $");
|
||||
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_new(int type)
|
||||
@ -58,6 +58,7 @@ key_new(int type)
|
||||
k->dsa = NULL;
|
||||
k->rsa = NULL;
|
||||
switch (k->type) {
|
||||
case KEY_RSA1:
|
||||
case KEY_RSA:
|
||||
rsa = RSA_new();
|
||||
rsa->n = BN_new();
|
||||
@ -72,7 +73,7 @@ key_new(int type)
|
||||
dsa->pub_key = BN_new();
|
||||
k->dsa = dsa;
|
||||
break;
|
||||
case KEY_EMPTY:
|
||||
case KEY_UNSPEC:
|
||||
break;
|
||||
default:
|
||||
fatal("key_new: bad key type %d", k->type);
|
||||
@ -80,10 +81,35 @@ key_new(int type)
|
||||
}
|
||||
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
|
||||
key_free(Key *k)
|
||||
{
|
||||
switch (k->type) {
|
||||
case KEY_RSA1:
|
||||
case KEY_RSA:
|
||||
if (k->rsa != NULL)
|
||||
RSA_free(k->rsa);
|
||||
@ -94,6 +120,8 @@ key_free(Key *k)
|
||||
DSA_free(k->dsa);
|
||||
k->dsa = NULL;
|
||||
break;
|
||||
case KEY_UNSPEC:
|
||||
break;
|
||||
default:
|
||||
fatal("key_free: bad key type %d", k->type);
|
||||
break;
|
||||
@ -106,6 +134,7 @@ key_equal(Key *a, Key *b)
|
||||
if (a == NULL || b == NULL || a->type != b->type)
|
||||
return 0;
|
||||
switch (a->type) {
|
||||
case KEY_RSA1:
|
||||
case KEY_RSA:
|
||||
return a->rsa != NULL && b->rsa != NULL &&
|
||||
BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
|
||||
@ -125,20 +154,31 @@ key_equal(Key *a, Key *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate key fingerprint in ascii format.
|
||||
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
|
||||
*/
|
||||
char *
|
||||
key_fingerprint(Key *k)
|
||||
u_char*
|
||||
key_fingerprint_raw(Key *k, enum fp_type dgst_type, size_t *dgst_raw_length)
|
||||
{
|
||||
static char retval[(EVP_MAX_MD_SIZE+1)*3];
|
||||
unsigned char *blob = NULL;
|
||||
EVP_MD *md = NULL;
|
||||
EVP_MD_CTX ctx;
|
||||
u_char *blob = NULL;
|
||||
u_char *retval = NULL;
|
||||
int len = 0;
|
||||
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) {
|
||||
case KEY_RSA:
|
||||
case KEY_RSA1:
|
||||
nlen = BN_num_bytes(k->rsa->n);
|
||||
elen = BN_num_bytes(k->rsa->e);
|
||||
len = nlen + elen;
|
||||
@ -147,34 +187,121 @@ key_fingerprint(Key *k)
|
||||
BN_bn2bin(k->rsa->e, blob + nlen);
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
fatal("key_fingerprint: bad key type %d", k->type);
|
||||
fatal("key_fingerprint_raw: bad key type %d", k->type);
|
||||
break;
|
||||
}
|
||||
retval[0] = '\0';
|
||||
|
||||
if (blob != NULL) {
|
||||
int i;
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
EVP_MD *md = EVP_md5();
|
||||
EVP_MD_CTX ctx;
|
||||
retval = xmalloc(EVP_MAX_MD_SIZE);
|
||||
EVP_DigestInit(&ctx, md);
|
||||
EVP_DigestUpdate(&ctx, blob, len);
|
||||
EVP_DigestFinal(&ctx, digest, NULL);
|
||||
for(i = 0; i < md->md_size; i++) {
|
||||
char hex[4];
|
||||
snprintf(hex, sizeof(hex), "%02x:", digest[i]);
|
||||
strlcat(retval, hex, sizeof(retval));
|
||||
}
|
||||
retval[strlen(retval) - 1] = '\0';
|
||||
EVP_DigestFinal(&ctx, retval, NULL);
|
||||
*dgst_raw_length = md->md_size;
|
||||
memset(blob, 0, len);
|
||||
xfree(blob);
|
||||
} else {
|
||||
fatal("key_fingerprint_raw: blob is null");
|
||||
}
|
||||
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
|
||||
* the pointer. The integer must already be initialized. This function is
|
||||
@ -227,59 +354,109 @@ write_bignum(FILE *f, BIGNUM *num)
|
||||
return 0;
|
||||
}
|
||||
fprintf(f, " %s", buf);
|
||||
free(buf);
|
||||
xfree(buf);
|
||||
return 1;
|
||||
}
|
||||
unsigned int
|
||||
|
||||
/* returns 1 ok, -1 error, 0 type mismatch */
|
||||
int
|
||||
key_read(Key *ret, char **cpp)
|
||||
{
|
||||
Key *k;
|
||||
unsigned int bits = 0;
|
||||
char *cp;
|
||||
int len, n;
|
||||
unsigned char *blob;
|
||||
int success = -1;
|
||||
char *cp, *space;
|
||||
int len, n, type;
|
||||
u_int bits;
|
||||
u_char *blob;
|
||||
|
||||
cp = *cpp;
|
||||
|
||||
switch(ret->type) {
|
||||
case KEY_RSA:
|
||||
case KEY_RSA1:
|
||||
/* Get number of bits. */
|
||||
if (*cp < '0' || *cp > '9')
|
||||
return 0; /* Bad bit count... */
|
||||
return -1; /* Bad bit count... */
|
||||
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
|
||||
bits = 10 * bits + *cp - '0';
|
||||
if (bits == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
*cpp = cp;
|
||||
/* Get public exponent, public modulus. */
|
||||
if (!read_bignum(cpp, ret->rsa->e))
|
||||
return 0;
|
||||
return -1;
|
||||
if (!read_bignum(cpp, ret->rsa->n))
|
||||
return 0;
|
||||
return -1;
|
||||
success = 1;
|
||||
break;
|
||||
case KEY_UNSPEC:
|
||||
case KEY_RSA:
|
||||
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;
|
||||
cp += 7;
|
||||
}
|
||||
len = 2*strlen(cp);
|
||||
blob = xmalloc(len);
|
||||
n = uudecode(cp, blob, len);
|
||||
if (n < 0) {
|
||||
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) {
|
||||
error("key_read: dsa_key_from_blob %s failed", cp);
|
||||
return 0;
|
||||
error("key_read: key_from_blob %s failed", cp);
|
||||
return -1;
|
||||
}
|
||||
xfree(blob);
|
||||
if (ret->dsa != NULL)
|
||||
DSA_free(ret->dsa);
|
||||
ret->dsa = k->dsa;
|
||||
k->dsa = NULL;
|
||||
if (k->type != type) {
|
||||
error("key_read: type mismatch: encoding error");
|
||||
key_free(k);
|
||||
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);
|
||||
bits = BN_num_bits(ret->dsa->p);
|
||||
/* advance cp: skip whitespace and data */
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
@ -291,15 +468,15 @@ key_read(Key *ret, char **cpp)
|
||||
fatal("key_read: bad key type: %d", ret->type);
|
||||
break;
|
||||
}
|
||||
return bits;
|
||||
return success;
|
||||
}
|
||||
int
|
||||
key_write(Key *key, FILE *f)
|
||||
{
|
||||
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' */
|
||||
bits = BN_num_bits(key->rsa->n);
|
||||
fprintf(f, "%u", bits);
|
||||
@ -309,14 +486,15 @@ key_write(Key *key, FILE *f)
|
||||
} else {
|
||||
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;
|
||||
unsigned char *blob, *uu;
|
||||
dsa_make_key_blob(key, &blob, &len);
|
||||
u_char *blob, *uu;
|
||||
key_to_blob(key, &blob, &len);
|
||||
uu = xmalloc(2*len);
|
||||
n = uuencode(blob, len, uu, 2*len);
|
||||
if (n > 0) {
|
||||
fprintf(f, "%s %s", SSH_DSS, uu);
|
||||
fprintf(f, "%s %s", key_ssh_name(key), uu);
|
||||
success = 1;
|
||||
}
|
||||
xfree(blob);
|
||||
@ -328,6 +506,9 @@ char *
|
||||
key_type(Key *k)
|
||||
{
|
||||
switch (k->type) {
|
||||
case KEY_RSA1:
|
||||
return "RSA1";
|
||||
break;
|
||||
case KEY_RSA:
|
||||
return "RSA";
|
||||
break;
|
||||
@ -337,9 +518,23 @@ key_type(Key *k)
|
||||
}
|
||||
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){
|
||||
switch (k->type) {
|
||||
case KEY_RSA1:
|
||||
case KEY_RSA:
|
||||
return BN_num_bits(k->rsa->n);
|
||||
break;
|
||||
@ -349,3 +544,241 @@ key_size(Key *k){
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
@ -22,16 +22,18 @@ RCSID("$FreeBSD$");
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "mpaux.h"
|
||||
|
||||
void
|
||||
compute_session_id(unsigned char session_id[16],
|
||||
unsigned char cookie[8],
|
||||
compute_session_id(u_char session_id[16],
|
||||
u_char cookie[8],
|
||||
BIGNUM* host_key_n,
|
||||
BIGNUM* session_key_n)
|
||||
{
|
||||
unsigned int host_key_bytes = BN_num_bytes(host_key_n);
|
||||
unsigned int session_key_bytes = BN_num_bytes(session_key_n);
|
||||
unsigned int bytes = host_key_bytes + session_key_bytes;
|
||||
unsigned char *buf = xmalloc(bytes);
|
||||
u_int host_key_bytes = BN_num_bytes(host_key_n);
|
||||
u_int session_key_bytes = BN_num_bytes(session_key_n);
|
||||
u_int bytes = host_key_bytes + session_key_bytes;
|
||||
u_char *buf = xmalloc(bytes);
|
||||
MD5_CTX md;
|
||||
|
||||
BN_bn2bin(host_key_n, buf);
|
||||
|
@ -11,8 +11,8 @@
|
||||
* 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 $"); */
|
||||
/* $FreeBSD$ */
|
||||
/* RCSID("$OpenBSD: packet.h,v 1.22 2001/04/14 16:33:20 stevesk Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
|
||||
#ifndef 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Sets remote side protocol flags for the current connection. This can be
|
||||
* 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. */
|
||||
unsigned int packet_get_protocol_flags(void);
|
||||
u_int packet_get_protocol_flags(void);
|
||||
|
||||
/* Enables compression in both directions starting from the next packet. */
|
||||
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
|
||||
* 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. */
|
||||
int packet_is_interactive(void);
|
||||
@ -78,16 +78,16 @@ void packet_start(int type);
|
||||
void packet_put_char(int ch);
|
||||
|
||||
/* 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. */
|
||||
void packet_put_bignum(BIGNUM * value);
|
||||
void packet_put_bignum2(BIGNUM * value);
|
||||
|
||||
/* Appends a string to packet data. */
|
||||
void packet_put_string(const char *buf, unsigned int len);
|
||||
void packet_put_string(const char *buf, u_int len);
|
||||
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,
|
||||
@ -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
|
||||
* 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. */
|
||||
unsigned int packet_get_char(void);
|
||||
u_int packet_get_char(void);
|
||||
|
||||
/* 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
|
||||
@ -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
|
||||
* 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
|
||||
@ -179,8 +179,8 @@ extern int max_packet_size;
|
||||
int packet_set_maxsize(int s);
|
||||
#define packet_get_maxsize() max_packet_size
|
||||
|
||||
/* Stores tty modes from the fd into current packet. */
|
||||
void tty_make_modes(int fd);
|
||||
/* Stores tty modes from the fd or tiop into current packet. */
|
||||
void tty_make_modes(int fd, struct termios *tiop);
|
||||
|
||||
/* Parses tty modes for the fd from the current packet. */
|
||||
void tty_parse_modes(int fd, int *n_bytes_ptr);
|
||||
@ -215,4 +215,10 @@ void packet_set_ssh2_format(void);
|
||||
/* returns remaining payload bytes */
|
||||
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 */
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */
|
||||
/* $FreeBSD$ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -12,7 +13,7 @@
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*/
|
||||
|
||||
#define ETCDIR "/etc"
|
||||
#define ETCDIR "/etc/ssh"
|
||||
#define _PATH_SSH_PIDDIR "/var/run"
|
||||
|
||||
/*
|
||||
|
@ -12,14 +12,20 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "readconf.h"
|
||||
#include "match.h"
|
||||
#include "xmalloc.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:
|
||||
|
||||
@ -69,7 +75,7 @@ RCSID("$FreeBSD$");
|
||||
# Defaults for various options
|
||||
Host *
|
||||
ForwardAgent no
|
||||
ForwardX11 yes
|
||||
ForwardX11 no
|
||||
RhostsAuthentication yes
|
||||
PasswordAuthentication yes
|
||||
RSAAuthentication yes
|
||||
@ -90,7 +96,7 @@ typedef enum {
|
||||
oBadOption,
|
||||
oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
|
||||
oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh,
|
||||
oSkeyAuthentication, oXAuthLocation,
|
||||
oChallengeResponseAuthentication, oXAuthLocation,
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
oKerberosAuthentication,
|
||||
#endif /* KRB4 */
|
||||
@ -104,10 +110,12 @@ typedef enum {
|
||||
oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
|
||||
oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
|
||||
oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
|
||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oTISAuthentication,
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oIdentityFile2,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oDSAAuthentication,
|
||||
oKbdInteractiveAuthentication, oKbdInteractiveDevices
|
||||
oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
|
||||
oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
|
||||
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
|
||||
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
|
||||
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
|
||||
oHostKeyAlgorithms
|
||||
} OpCodes;
|
||||
|
||||
/* Textual representations of the tokens. */
|
||||
@ -126,8 +134,13 @@ static struct {
|
||||
{ "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
|
||||
{ "kbdinteractivedevices", oKbdInteractiveDevices },
|
||||
{ "rsaauthentication", oRSAAuthentication },
|
||||
{ "dsaauthentication", oDSAAuthentication },
|
||||
{ "skeyauthentication", oSkeyAuthentication },
|
||||
{ "pubkeyauthentication", oPubkeyAuthentication },
|
||||
{ "dsaauthentication", oPubkeyAuthentication }, /* alias */
|
||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||
{ "hostbasedauthentication", oHostbasedAuthentication },
|
||||
{ "challengeresponseauthentication", oChallengeResponseAuthentication },
|
||||
{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
|
||||
{ "tisauthentication", oChallengeResponseAuthentication }, /* alias */
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
{ "kerberosauthentication", oKerberosAuthentication },
|
||||
#endif /* KRB4 || KRB5 */
|
||||
@ -141,19 +154,20 @@ static struct {
|
||||
{ "fallbacktorsh", oFallBackToRsh },
|
||||
{ "usersh", oUseRsh },
|
||||
{ "identityfile", oIdentityFile },
|
||||
{ "identityfile2", oIdentityFile2 },
|
||||
{ "identityfile2", oIdentityFile }, /* alias */
|
||||
{ "hostname", oHostName },
|
||||
{ "hostkeyalias", oHostKeyAlias },
|
||||
{ "proxycommand", oProxyCommand },
|
||||
{ "port", oPort },
|
||||
{ "cipher", oCipher },
|
||||
{ "ciphers", oCiphers },
|
||||
{ "macs", oMacs },
|
||||
{ "protocol", oProtocol },
|
||||
{ "remoteforward", oRemoteForward },
|
||||
{ "localforward", oLocalForward },
|
||||
{ "user", oUser },
|
||||
{ "host", oHost },
|
||||
{ "escapechar", oEscapeChar },
|
||||
{ "rhostsrsaauthentication", oRhostsRSAAuthentication },
|
||||
{ "globalknownhostsfile", oGlobalKnownHostsFile },
|
||||
{ "userknownhostsfile", oUserKnownHostsFile },
|
||||
{ "globalknownhostsfile2", oGlobalKnownHostsFile2 },
|
||||
@ -166,8 +180,10 @@ static struct {
|
||||
{ "compressionlevel", oCompressionLevel },
|
||||
{ "keepalive", oKeepAlives },
|
||||
{ "numberofpasswordprompts", oNumberOfPasswordPrompts },
|
||||
{ "tisauthentication", oTISAuthentication },
|
||||
{ "loglevel", oLogLevel },
|
||||
{ "dynamicforward", oDynamicForward },
|
||||
{ "preferredauthentications", oPreferredAuthentications },
|
||||
{ "hostkeyalgorithms", oHostKeyAlgorithms },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@ -183,7 +199,7 @@ add_local_forward(Options *options, u_short port, const char *host,
|
||||
Forward *fwd;
|
||||
extern uid_t original_real_uid;
|
||||
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)
|
||||
fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
|
||||
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 if the token is not known.
|
||||
* Returns the number of the token pointed to by cp or oBadOption.
|
||||
*/
|
||||
|
||||
static OpCodes
|
||||
parse_token(const char *cp, const char *filename, int linenum)
|
||||
{
|
||||
unsigned int i;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; keywords[i].name; i++)
|
||||
if (strcasecmp(cp, keywords[i].name) == 0)
|
||||
return keywords[i].opcode;
|
||||
|
||||
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
||||
filename, linenum, cp);
|
||||
error("%s: line %d: Bad configuration option: %s",
|
||||
filename, linenum, cp);
|
||||
return oBadOption;
|
||||
}
|
||||
|
||||
@ -250,7 +265,7 @@ process_config_line(Options *options, const char *host,
|
||||
/* Ignore leading whitespace. */
|
||||
if (*keyword == '\0')
|
||||
keyword = strdelim(&s);
|
||||
if (!*keyword || *keyword == '\n' || *keyword == '#')
|
||||
if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#')
|
||||
return 0;
|
||||
|
||||
opcode = parse_token(keyword, filename, linenum);
|
||||
@ -305,8 +320,8 @@ process_config_line(Options *options, const char *host,
|
||||
charptr = &options->kbd_interactive_devices;
|
||||
goto parse_string;
|
||||
|
||||
case oDSAAuthentication:
|
||||
intptr = &options->dsa_authentication;
|
||||
case oPubkeyAuthentication:
|
||||
intptr = &options->pubkey_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oRSAAuthentication:
|
||||
@ -317,10 +332,8 @@ process_config_line(Options *options, const char *host,
|
||||
intptr = &options->rhosts_rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case oTISAuthentication:
|
||||
/* fallthrough, there is no difference on the client side */
|
||||
case oSkeyAuthentication:
|
||||
intptr = &options->skey_authentication;
|
||||
case oHostbasedAuthentication:
|
||||
intptr = &options->hostbased_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
@ -329,6 +342,10 @@ process_config_line(Options *options, const char *host,
|
||||
goto parse_flag;
|
||||
#endif /* KRB4 || KRB5 */
|
||||
|
||||
case oChallengeResponseAuthentication:
|
||||
intptr = &options->challenge_reponse_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef KRB5
|
||||
case oKrb5TgtPassing:
|
||||
intptr = &options->krb5_tgt_passing;
|
||||
@ -365,7 +382,7 @@ process_config_line(Options *options, const char *host,
|
||||
intptr = &options->strict_host_key_checking;
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing yes/no argument.",
|
||||
fatal("%.200s line %d: Missing yes/no/ask argument.",
|
||||
filename, linenum);
|
||||
value = 0; /* To avoid compiler warning... */
|
||||
if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
|
||||
@ -397,20 +414,15 @@ process_config_line(Options *options, const char *host,
|
||||
goto parse_int;
|
||||
|
||||
case oIdentityFile:
|
||||
case oIdentityFile2:
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (*activep) {
|
||||
intptr = (opcode == oIdentityFile) ?
|
||||
&options->num_identity_files :
|
||||
&options->num_identity_files2;
|
||||
intptr = &options->num_identity_files;
|
||||
if (*intptr >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("%.200s line %d: Too many identity files specified (max %d).",
|
||||
filename, linenum, SSH_MAX_IDENTITY_FILES);
|
||||
charptr = (opcode == oIdentityFile) ?
|
||||
&options->identity_files[*intptr] :
|
||||
&options->identity_files2[*intptr];
|
||||
charptr = &options->identity_files[*intptr];
|
||||
*charptr = xstrdup(arg);
|
||||
*intptr = *intptr + 1;
|
||||
}
|
||||
@ -450,6 +462,14 @@ process_config_line(Options *options, const char *host,
|
||||
charptr = &options->hostname;
|
||||
goto parse_string;
|
||||
|
||||
case oHostKeyAlias:
|
||||
charptr = &options->host_key_alias;
|
||||
goto parse_string;
|
||||
|
||||
case oPreferredAuthentications:
|
||||
charptr = &options->preferred_authentications;
|
||||
goto parse_string;
|
||||
|
||||
case oProxyCommand:
|
||||
charptr = &options->proxy_command;
|
||||
string = xstrdup("");
|
||||
@ -509,6 +529,28 @@ process_config_line(Options *options, const char *host,
|
||||
options->ciphers = xstrdup(arg);
|
||||
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:
|
||||
intptr = &options->protocol;
|
||||
arg = strdelim(&s);
|
||||
@ -527,7 +569,7 @@ process_config_line(Options *options, const char *host,
|
||||
arg = strdelim(&s);
|
||||
value = log_level_number(arg);
|
||||
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>");
|
||||
if (*activep && (LogLevel) * intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
@ -537,10 +579,10 @@ process_config_line(Options *options, const char *host,
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
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.",
|
||||
filename, linenum);
|
||||
fwd_port = atoi(arg);
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing second argument.",
|
||||
@ -556,10 +598,10 @@ process_config_line(Options *options, const char *host,
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
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.",
|
||||
filename, linenum);
|
||||
fwd_port = atoi(arg);
|
||||
arg = strdelim(&s);
|
||||
if (!arg || *arg == '\0')
|
||||
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);
|
||||
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:
|
||||
*activep = 0;
|
||||
while ((arg = strdelim(&s)) != NULL && *arg != '\0')
|
||||
@ -588,10 +642,10 @@ process_config_line(Options *options, const char *host,
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%.200s line %d: Missing argument.", filename, linenum);
|
||||
if (arg[0] == '^' && arg[2] == 0 &&
|
||||
(unsigned char) arg[1] >= 64 && (unsigned char) arg[1] < 128)
|
||||
value = (unsigned char) arg[1] & 31;
|
||||
(u_char) arg[1] >= 64 && (u_char) arg[1] < 128)
|
||||
value = (u_char) arg[1] & 31;
|
||||
else if (strlen(arg) == 1)
|
||||
value = (unsigned char) arg[0];
|
||||
value = (u_char) arg[0];
|
||||
else if (strcmp(arg, "none") == 0)
|
||||
value = -2;
|
||||
else {
|
||||
@ -609,8 +663,7 @@ process_config_line(Options *options, const char *host,
|
||||
}
|
||||
|
||||
/* 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\".",
|
||||
filename, linenum, arg);
|
||||
}
|
||||
@ -653,7 +706,7 @@ read_config_file(const char *filename, const char *host, Options *options)
|
||||
}
|
||||
fclose(f);
|
||||
if (bad_options > 0)
|
||||
fatal("%s: terminating, %d bad configuration options\n",
|
||||
fatal("%s: terminating, %d bad configuration options",
|
||||
filename, bad_options);
|
||||
}
|
||||
|
||||
@ -675,8 +728,8 @@ initialize_options(Options * options)
|
||||
options->use_privileged_port = -1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rsa_authentication = -1;
|
||||
options->dsa_authentication = -1;
|
||||
options->skey_authentication = -1;
|
||||
options->pubkey_authentication = -1;
|
||||
options->challenge_reponse_authentication = -1;
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
options->kerberos_authentication = -1;
|
||||
#endif
|
||||
@ -691,6 +744,7 @@ initialize_options(Options * options)
|
||||
options->kbd_interactive_authentication = -1;
|
||||
options->kbd_interactive_devices = NULL;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->hostbased_authentication = -1;
|
||||
options->fallback_to_rsh = -1;
|
||||
options->use_rsh = -1;
|
||||
options->batch_mode = -1;
|
||||
@ -704,10 +758,12 @@ initialize_options(Options * options)
|
||||
options->number_of_password_prompts = -1;
|
||||
options->cipher = -1;
|
||||
options->ciphers = NULL;
|
||||
options->macs = NULL;
|
||||
options->hostkeyalgorithms = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->num_identity_files = 0;
|
||||
options->num_identity_files2 = 0;
|
||||
options->hostname = NULL;
|
||||
options->host_key_alias = NULL;
|
||||
options->proxy_command = NULL;
|
||||
options->user = NULL;
|
||||
options->escape_char = -1;
|
||||
@ -718,6 +774,7 @@ initialize_options(Options * options)
|
||||
options->num_local_forwards = 0;
|
||||
options->num_remote_forwards = 0;
|
||||
options->log_level = (LogLevel) - 1;
|
||||
options->preferred_authentications = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -728,6 +785,8 @@ initialize_options(Options * options)
|
||||
void
|
||||
fill_default_options(Options * options)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (options->forward_agent == -1)
|
||||
options->forward_agent = 0;
|
||||
if (options->forward_x11 == -1)
|
||||
@ -739,15 +798,15 @@ fill_default_options(Options * options)
|
||||
if (options->gateway_ports == -1)
|
||||
options->gateway_ports = 0;
|
||||
if (options->use_privileged_port == -1)
|
||||
options->use_privileged_port = 1;
|
||||
options->use_privileged_port = 0;
|
||||
if (options->rhosts_authentication == -1)
|
||||
options->rhosts_authentication = 1;
|
||||
if (options->rsa_authentication == -1)
|
||||
options->rsa_authentication = 1;
|
||||
if (options->dsa_authentication == -1)
|
||||
options->dsa_authentication = 1;
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 0;
|
||||
if (options->pubkey_authentication == -1)
|
||||
options->pubkey_authentication = 1;
|
||||
if (options->challenge_reponse_authentication == -1)
|
||||
options->challenge_reponse_authentication = 0;
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication = 1;
|
||||
@ -765,9 +824,11 @@ fill_default_options(Options * options)
|
||||
if (options->password_authentication == -1)
|
||||
options->password_authentication = 1;
|
||||
if (options->kbd_interactive_authentication == -1)
|
||||
options->kbd_interactive_authentication = 0;
|
||||
options->kbd_interactive_authentication = 1;
|
||||
if (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)
|
||||
options->fallback_to_rsh = 0;
|
||||
if (options->use_rsh == -1)
|
||||
@ -794,33 +855,47 @@ fill_default_options(Options * options)
|
||||
if (options->cipher == -1)
|
||||
options->cipher = SSH_CIPHER_NOT_SET;
|
||||
/* 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)
|
||||
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) {
|
||||
options->identity_files[0] =
|
||||
xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1);
|
||||
sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY);
|
||||
options->num_identity_files = 1;
|
||||
}
|
||||
if (options->num_identity_files2 == 0) {
|
||||
options->identity_files2[0] =
|
||||
xmalloc(2 + strlen(SSH_CLIENT_ID_DSA) + 1);
|
||||
sprintf(options->identity_files2[0], "~/%.100s", SSH_CLIENT_ID_DSA);
|
||||
options->num_identity_files2 = 1;
|
||||
if (options->protocol & SSH_PROTO_1) {
|
||||
len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
|
||||
options->identity_files[options->num_identity_files] =
|
||||
xmalloc(len);
|
||||
snprintf(options->identity_files[options->num_identity_files++],
|
||||
len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
|
||||
}
|
||||
if (options->protocol & SSH_PROTO_2) {
|
||||
len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 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)
|
||||
options->escape_char = '~';
|
||||
if (options->system_hostfile == NULL)
|
||||
options->system_hostfile = SSH_SYSTEM_HOSTFILE;
|
||||
options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
|
||||
if (options->user_hostfile == NULL)
|
||||
options->user_hostfile = SSH_USER_HOSTFILE;
|
||||
options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
|
||||
if (options->system_hostfile2 == NULL)
|
||||
options->system_hostfile2 = SSH_SYSTEM_HOSTFILE2;
|
||||
options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
|
||||
if (options->user_hostfile2 == NULL)
|
||||
options->user_hostfile2 = SSH_USER_HOSTFILE2;
|
||||
options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
|
||||
if (options->log_level == (LogLevel) - 1)
|
||||
options->log_level = SYSLOG_LEVEL_INFO;
|
||||
/* options->proxy_command should not be set by default */
|
||||
/* options->user 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 */
|
||||
}
|
||||
|
@ -11,12 +11,14 @@
|
||||
* 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 $"); */
|
||||
/* $FreeBSD$ */
|
||||
/* RCSID("$OpenBSD: readconf.h,v 1.30 2001/04/17 10:53:25 markus Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
|
||||
#ifndef READCONF_H
|
||||
#define READCONF_H
|
||||
|
||||
#include "key.h"
|
||||
|
||||
/* Data structure for representing a forwarding request. */
|
||||
|
||||
typedef struct {
|
||||
@ -36,10 +38,13 @@ typedef struct {
|
||||
int rhosts_rsa_authentication; /* Try rhosts with RSA
|
||||
* authentication. */
|
||||
int rsa_authentication; /* Try RSA authentication. */
|
||||
int dsa_authentication; /* Try DSA authentication. */
|
||||
int skey_authentication; /* Try S/Key or TIS authentication. */
|
||||
int pubkey_authentication; /* Try ssh2 pubkey authentication. */
|
||||
int hostbased_authentication; /* ssh2's rhosts_rsa */
|
||||
int challenge_reponse_authentication;
|
||||
/* Try S/Key or TIS, authentication. */
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
int kerberos_authentication; /* Try Kerberos authentication. */
|
||||
int kerberos_authentication; /* Try Kerberos
|
||||
* authentication. */
|
||||
#endif
|
||||
|
||||
#ifdef KRB5
|
||||
@ -72,8 +77,11 @@ typedef struct {
|
||||
* prompts. */
|
||||
int cipher; /* Cipher to use. */
|
||||
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. */
|
||||
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 *user; /* User to log in as. */
|
||||
int escape_char; /* Escape character; -2 = none */
|
||||
@ -82,11 +90,11 @@ typedef struct {
|
||||
char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */
|
||||
char *system_hostfile2;
|
||||
char *user_hostfile2;
|
||||
char *preferred_authentications;
|
||||
|
||||
int num_identity_files; /* Number of files for RSA identities. */
|
||||
int num_identity_files2; /* DSA identities. */
|
||||
int num_identity_files; /* Number of files for RSA/DSA identities. */
|
||||
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. */
|
||||
int num_local_forwards;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* 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) 1999 Niels Provos. All rights reserved.
|
||||
*
|
||||
@ -60,83 +60,17 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "log.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
|
||||
rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
{
|
||||
unsigned char *inbuf, *outbuf;
|
||||
u_char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
|
||||
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,
|
||||
RSA_PKCS1_PADDING)) <= 0)
|
||||
fatal("rsa_public_encrypt() failed.");
|
||||
fatal("rsa_public_encrypt() failed");
|
||||
|
||||
BN_bin2bn(outbuf, len, out);
|
||||
|
||||
@ -164,7 +98,7 @@ rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
int
|
||||
rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
{
|
||||
unsigned char *inbuf, *outbuf;
|
||||
u_char *inbuf, *outbuf;
|
||||
int len, ilen, olen;
|
||||
|
||||
olen = BN_num_bytes(key->n);
|
||||
@ -187,10 +121,22 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Set whether to output verbose messages during key generation. */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,8 @@
|
||||
* 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 $"); */
|
||||
/* $FreeBSD$ */
|
||||
/* RCSID("$OpenBSD: rsa.h,v 1.11 2001/03/26 23:23:24 markus Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
|
||||
#ifndef RSA_H
|
||||
#define RSA_H
|
||||
@ -20,18 +20,9 @@
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
/* Calls SSL RSA_generate_key, only copies to prv and pub */
|
||||
void rsa_generate_key(RSA * prv, RSA * pub, unsigned int bits);
|
||||
|
||||
/*
|
||||
* 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));
|
||||
int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv));
|
||||
|
||||
void generate_additional_parameters __P((RSA *rsa));
|
||||
|
||||
#endif /* RSA_H */
|
||||
|
@ -10,16 +10,33 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#ifdef KRB4
|
||||
#include <krb.h>
|
||||
#endif
|
||||
#ifdef AFS
|
||||
#include <kafs.h>
|
||||
#endif
|
||||
|
||||
#include "ssh.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
#include "xmalloc.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);
|
||||
void add_listen_addr(ServerOptions *options, char *addr, u_short port);
|
||||
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. */
|
||||
|
||||
@ -30,16 +47,16 @@ initialize_server_options(ServerOptions *options)
|
||||
options->num_ports = 0;
|
||||
options->ports_from_cmdline = 0;
|
||||
options->listen_addrs = NULL;
|
||||
options->host_key_file = NULL;
|
||||
options->host_dsa_key_file = NULL;
|
||||
options->num_host_key_files = 0;
|
||||
options->pid_file = NULL;
|
||||
options->server_key_bits = -1;
|
||||
options->login_grace_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_user_known_hosts = -1;
|
||||
options->print_motd = -1;
|
||||
options->print_lastlog = -1;
|
||||
options->check_mail = -1;
|
||||
options->x11_forwarding = -1;
|
||||
options->x11_display_offset = -1;
|
||||
@ -50,8 +67,10 @@ initialize_server_options(ServerOptions *options)
|
||||
options->log_level = (LogLevel) - 1;
|
||||
options->rhosts_authentication = -1;
|
||||
options->rhosts_rsa_authentication = -1;
|
||||
options->hostbased_authentication = -1;
|
||||
options->hostbased_uses_name_from_packet_only = -1;
|
||||
options->rsa_authentication = -1;
|
||||
options->dsa_authentication = -1;
|
||||
options->pubkey_authentication = -1;
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
options->kerberos_authentication = -1;
|
||||
#endif
|
||||
@ -68,9 +87,7 @@ initialize_server_options(ServerOptions *options)
|
||||
#endif
|
||||
options->password_authentication = -1;
|
||||
options->kbd_interactive_authentication = -1;
|
||||
#ifdef SKEY
|
||||
options->skey_authentication = -1;
|
||||
#endif
|
||||
options->challenge_reponse_authentication = -1;
|
||||
options->permit_empty_passwd = -1;
|
||||
options->use_login = -1;
|
||||
options->allow_tcp_forwarding = -1;
|
||||
@ -79,6 +96,7 @@ initialize_server_options(ServerOptions *options)
|
||||
options->num_allow_groups = 0;
|
||||
options->num_deny_groups = 0;
|
||||
options->ciphers = NULL;
|
||||
options->macs = NULL;
|
||||
options->protocol = SSH_PROTO_UNKNOWN;
|
||||
options->gateway_ports = -1;
|
||||
options->connections_per_period = 0;
|
||||
@ -87,29 +105,38 @@ initialize_server_options(ServerOptions *options)
|
||||
options->max_startups_begin = -1;
|
||||
options->max_startups_rate = -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
|
||||
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)
|
||||
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
|
||||
if (options->listen_addrs == NULL)
|
||||
add_listen_addr(options, NULL);
|
||||
if (options->host_key_file == NULL)
|
||||
options->host_key_file = HOST_KEY_FILE;
|
||||
if (options->host_dsa_key_file == NULL)
|
||||
options->host_dsa_key_file = HOST_DSA_KEY_FILE;
|
||||
add_listen_addr(options, NULL, 0);
|
||||
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)
|
||||
options->server_key_bits = 768;
|
||||
if (options->login_grace_time == -1)
|
||||
options->login_grace_time = 120;
|
||||
if (options->key_regeneration_time == -1)
|
||||
options->key_regeneration_time = 3600;
|
||||
if (options->permit_root_login == -1)
|
||||
options->permit_root_login = 0; /* no */
|
||||
if (options->permit_root_login == PERMIT_NOT_SET)
|
||||
options->permit_root_login = PERMIT_NO;
|
||||
if (options->ignore_rhosts == -1)
|
||||
options->ignore_rhosts = 1;
|
||||
if (options->ignore_user_known_hosts == -1)
|
||||
@ -118,6 +145,8 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->check_mail = 1;
|
||||
if (options->print_motd == -1)
|
||||
options->print_motd = 1;
|
||||
if (options->print_lastlog == -1)
|
||||
options->print_lastlog = 1;
|
||||
if (options->x11_forwarding == -1)
|
||||
options->x11_forwarding = 1;
|
||||
if (options->x11_display_offset == -1)
|
||||
@ -138,10 +167,14 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->rhosts_authentication = 0;
|
||||
if (options->rhosts_rsa_authentication == -1)
|
||||
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)
|
||||
options->rsa_authentication = 1;
|
||||
if (options->dsa_authentication == -1)
|
||||
options->dsa_authentication = 1;
|
||||
if (options->pubkey_authentication == -1)
|
||||
options->pubkey_authentication = 1;
|
||||
#if defined(KRB4) && defined(KRB5)
|
||||
if (options->kerberos_authentication == -1)
|
||||
options->kerberos_authentication =
|
||||
@ -173,18 +206,14 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->password_authentication = 1;
|
||||
if (options->kbd_interactive_authentication == -1)
|
||||
options->kbd_interactive_authentication = 0;
|
||||
#ifdef SKEY
|
||||
if (options->skey_authentication == -1)
|
||||
options->skey_authentication = 1;
|
||||
#endif
|
||||
if (options->challenge_reponse_authentication == -1)
|
||||
options->challenge_reponse_authentication = 1;
|
||||
if (options->permit_empty_passwd == -1)
|
||||
options->permit_empty_passwd = 0;
|
||||
if (options->use_login == -1)
|
||||
options->use_login = 0;
|
||||
if (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)
|
||||
options->gateway_ports = 0;
|
||||
if (options->max_startups == -1)
|
||||
@ -193,6 +222,12 @@ fill_default_server_options(ServerOptions *options)
|
||||
options->max_startups_rate = 100; /* 100% */
|
||||
if (options->max_startups_begin == -1)
|
||||
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. */
|
||||
@ -213,17 +248,18 @@ typedef enum {
|
||||
#ifdef AFS
|
||||
sKrb4TgtPassing, sAFSTokenPassing,
|
||||
#endif
|
||||
#ifdef SKEY
|
||||
sSkeyAuthentication,
|
||||
#endif
|
||||
sChallengeResponseAuthentication,
|
||||
sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
|
||||
sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
|
||||
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
|
||||
sX11Forwarding, sX11DisplayOffset,
|
||||
sStrictModes, sEmptyPasswd, sKeepAlives, sCheckMail,
|
||||
sUseLogin, sAllowTcpForwarding,
|
||||
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||
sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
|
||||
sGatewayPorts, sDSAAuthentication, sConnectionsPerPeriod, sXAuthLocation,
|
||||
sSubsystem, sMaxStartups, sVersionAddendum
|
||||
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
|
||||
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
|
||||
sBanner, sReverseMappingCheck, sHostbasedAuthentication,
|
||||
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
|
||||
sClientAliveCountMax, sVersionAddendum, sConnectionsPerPeriod
|
||||
} ServerOpCodes;
|
||||
|
||||
/* Textual representation of the tokens. */
|
||||
@ -233,8 +269,8 @@ static struct {
|
||||
} keywords[] = {
|
||||
{ "port", sPort },
|
||||
{ "hostkey", sHostKeyFile },
|
||||
{ "hostdsakey", sHostDSAKeyFile },
|
||||
{ "pidfile", sPidFile },
|
||||
{ "hostdsakey", sHostKeyFile }, /* alias */
|
||||
{ "pidfile", sPidFile },
|
||||
{ "serverkeybits", sServerKeyBits },
|
||||
{ "logingracetime", sLoginGraceTime },
|
||||
{ "keyregenerationinterval", sKeyRegenerationTime },
|
||||
@ -243,8 +279,11 @@ static struct {
|
||||
{ "loglevel", sLogLevel },
|
||||
{ "rhostsauthentication", sRhostsAuthentication },
|
||||
{ "rhostsrsaauthentication", sRhostsRSAAuthentication },
|
||||
{ "hostbasedauthentication", sHostbasedAuthentication },
|
||||
{ "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly },
|
||||
{ "pubkeyauthentication", sPubkeyAuthentication },
|
||||
{ "dsaauthentication", sPubkeyAuthentication }, /* alias */
|
||||
{ "rsaauthentication", sRSAAuthentication },
|
||||
{ "dsaauthentication", sDSAAuthentication },
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
{ "kerberosauthentication", sKerberosAuthentication },
|
||||
#endif
|
||||
@ -261,12 +300,12 @@ static struct {
|
||||
#endif
|
||||
{ "passwordauthentication", sPasswordAuthentication },
|
||||
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
|
||||
#ifdef SKEY
|
||||
{ "skeyauthentication", sSkeyAuthentication },
|
||||
#endif
|
||||
{ "challengeresponseauthentication", sChallengeResponseAuthentication },
|
||||
{ "skeyauthentication", sChallengeResponseAuthentication }, /* alias */
|
||||
{ "checkmail", sCheckMail },
|
||||
{ "listenaddress", sListenAddress },
|
||||
{ "printmotd", sPrintMotd },
|
||||
{ "printlastlog", sPrintLastLog },
|
||||
{ "ignorerhosts", sIgnoreRhosts },
|
||||
{ "ignoreuserknownhosts", sIgnoreUserKnownHosts },
|
||||
{ "x11forwarding", sX11Forwarding },
|
||||
@ -275,7 +314,6 @@ static struct {
|
||||
{ "strictmodes", sStrictModes },
|
||||
{ "permitemptypasswords", sEmptyPasswd },
|
||||
{ "uselogin", sUseLogin },
|
||||
{ "randomseed", sRandomSeedFile },
|
||||
{ "keepalive", sKeepAlives },
|
||||
{ "allowtcpforwarding", sAllowTcpForwarding },
|
||||
{ "allowusers", sAllowUsers },
|
||||
@ -283,64 +321,73 @@ static struct {
|
||||
{ "allowgroups", sAllowGroups },
|
||||
{ "denygroups", sDenyGroups },
|
||||
{ "ciphers", sCiphers },
|
||||
{ "macs", sMacs },
|
||||
{ "protocol", sProtocol },
|
||||
{ "gatewayports", sGatewayPorts },
|
||||
{ "connectionsperperiod", sConnectionsPerPeriod },
|
||||
{ "subsystem", sSubsystem },
|
||||
{ "maxstartups", sMaxStartups },
|
||||
{ "versionaddendum", sVersionAddendum },
|
||||
{ "banner", sBanner },
|
||||
{ "reversemappingcheck", sReverseMappingCheck },
|
||||
{ "clientaliveinterval", sClientAliveInterval },
|
||||
{ "clientalivecountmax", sClientAliveCountMax },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the number of the token pointed to by cp of length len. Never
|
||||
* returns if the token is not known.
|
||||
* Returns the number of the token pointed to by cp or sBadOption.
|
||||
*/
|
||||
|
||||
static ServerOpCodes
|
||||
parse_token(const char *cp, const char *filename,
|
||||
int linenum)
|
||||
{
|
||||
unsigned int i;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; keywords[i].name; i++)
|
||||
if (strcasecmp(cp, keywords[i].name) == 0)
|
||||
return keywords[i].opcode;
|
||||
|
||||
fprintf(stderr, "%s: line %d: Bad configuration option: %s\n",
|
||||
filename, linenum, cp);
|
||||
error("%s: line %d: Bad configuration option: %s",
|
||||
filename, linenum, cp);
|
||||
return sBadOption;
|
||||
}
|
||||
|
||||
/*
|
||||
* add listen address
|
||||
*/
|
||||
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;
|
||||
|
||||
if (options->num_ports == 0)
|
||||
options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
|
||||
for (i = 0; i < options->num_ports; i++) {
|
||||
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", options->ports[i]);
|
||||
if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
|
||||
fatal("bad addr or host: %s (%s)\n",
|
||||
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;
|
||||
}
|
||||
if (port == 0)
|
||||
for (i = 0; i < options->num_ports; i++)
|
||||
add_one_listen_addr(options, addr, options->ports[i]);
|
||||
else
|
||||
add_one_listen_addr(options, addr, port);
|
||||
}
|
||||
|
||||
void
|
||||
add_one_listen_addr(ServerOptions *options, char *addr, u_short port)
|
||||
{
|
||||
struct addrinfo hints, *ai, *aitop;
|
||||
char strport[NI_MAXSERV];
|
||||
int gaierr;
|
||||
|
||||
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. */
|
||||
@ -350,7 +397,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
char line[1024];
|
||||
char *cp, **charptr, *arg;
|
||||
char *cp, **charptr, *arg, *p;
|
||||
int linenum, *intptr, value;
|
||||
int bad_options = 0;
|
||||
ServerOpCodes opcode;
|
||||
@ -369,8 +416,10 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
/* Ignore leading whitespace */
|
||||
if (*arg == '\0')
|
||||
arg = strdelim(&cp);
|
||||
if (!*arg || *arg == '#')
|
||||
if (!arg || !*arg || *arg == '#')
|
||||
continue;
|
||||
intptr = NULL;
|
||||
charptr = NULL;
|
||||
opcode = parse_token(arg, filename, linenum);
|
||||
switch (opcode) {
|
||||
case sBadOption:
|
||||
@ -384,24 +433,25 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
fatal("%s line %d: ports must be specified before "
|
||||
"ListenAdress.\n", filename, linenum);
|
||||
if (options->num_ports >= MAX_PORTS)
|
||||
fatal("%s line %d: too many ports.\n",
|
||||
fatal("%s line %d: too many ports.",
|
||||
filename, linenum);
|
||||
arg = strdelim(&cp);
|
||||
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);
|
||||
options->ports[options->num_ports++] = atoi(arg);
|
||||
break;
|
||||
|
||||
case sServerKeyBits:
|
||||
intptr = &options->server_key_bits;
|
||||
parse_int:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing integer value.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing integer value.",
|
||||
filename, linenum);
|
||||
value = atoi(arg);
|
||||
if (value == 0) {
|
||||
fprintf(stderr, "%s line %d: invalid integer value.\n",
|
||||
@ -422,56 +472,84 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
|
||||
case sListenAddress:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing inet addr.\n",
|
||||
if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
|
||||
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);
|
||||
add_listen_addr(options, arg);
|
||||
break;
|
||||
|
||||
case sHostKeyFile:
|
||||
case sHostDSAKeyFile:
|
||||
charptr = (opcode == sHostKeyFile ) ?
|
||||
&options->host_key_file : &options->host_dsa_key_file;
|
||||
intptr = &options->num_host_key_files;
|
||||
if (*intptr >= MAX_HOSTKEYS)
|
||||
fatal("%s line %d: too many host keys specified (max %d).",
|
||||
filename, linenum, MAX_HOSTKEYS);
|
||||
charptr = &options->host_key_files[*intptr];
|
||||
parse_filename:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing file name.\n",
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing file name.",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (*charptr == NULL)
|
||||
if (*charptr == NULL) {
|
||||
*charptr = tilde_expand_filename(arg, getuid());
|
||||
/* increase optional counter */
|
||||
if (intptr != NULL)
|
||||
*intptr = *intptr + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case sPidFile:
|
||||
charptr = &options->pid_file;
|
||||
goto parse_filename;
|
||||
|
||||
case sRandomSeedFile:
|
||||
fprintf(stderr, "%s line %d: \"randomseed\" option is obsolete.\n",
|
||||
filename, linenum);
|
||||
arg = strdelim(&cp);
|
||||
break;
|
||||
|
||||
case sPermitRootLogin:
|
||||
intptr = &options->permit_root_login;
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing yes/without-password/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing yes/"
|
||||
"without-password/forced-commands-only/no "
|
||||
"argument.", filename, linenum);
|
||||
value = 0; /* silence compiler */
|
||||
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)
|
||||
value = 1;
|
||||
value = PERMIT_YES;
|
||||
else if (strcmp(arg, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/without-password/no argument: %s\n",
|
||||
filename, linenum, arg);
|
||||
exit(1);
|
||||
}
|
||||
value = PERMIT_NO;
|
||||
else
|
||||
fatal("%s line %d: Bad yes/"
|
||||
"without-password/forced-commands-only/no "
|
||||
"argument: %s", filename, linenum, arg);
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
@ -480,20 +558,17 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
intptr = &options->ignore_rhosts;
|
||||
parse_flag:
|
||||
arg = strdelim(&cp);
|
||||
if (!arg || *arg == '\0') {
|
||||
fprintf(stderr, "%s line %d: missing yes/no argument.\n",
|
||||
filename, linenum);
|
||||
exit(1);
|
||||
}
|
||||
if (!arg || *arg == '\0')
|
||||
fatal("%s line %d: missing yes/no argument.",
|
||||
filename, linenum);
|
||||
value = 0; /* silence compiler */
|
||||
if (strcmp(arg, "yes") == 0)
|
||||
value = 1;
|
||||
else if (strcmp(arg, "no") == 0)
|
||||
value = 0;
|
||||
else {
|
||||
fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n",
|
||||
else
|
||||
fatal("%s line %d: Bad yes/no argument: %s",
|
||||
filename, linenum, arg);
|
||||
exit(1);
|
||||
}
|
||||
if (*intptr == -1)
|
||||
*intptr = value;
|
||||
break;
|
||||
@ -510,12 +585,20 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
intptr = &options->rhosts_rsa_authentication;
|
||||
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:
|
||||
intptr = &options->rsa_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
case sDSAAuthentication:
|
||||
intptr = &options->dsa_authentication;
|
||||
case sPubkeyAuthentication:
|
||||
intptr = &options->pubkey_authentication;
|
||||
goto parse_flag;
|
||||
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
@ -562,16 +645,18 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
intptr = &options->check_mail;
|
||||
goto parse_flag;
|
||||
|
||||
#ifdef SKEY
|
||||
case sSkeyAuthentication:
|
||||
intptr = &options->skey_authentication;
|
||||
case sChallengeResponseAuthentication:
|
||||
intptr = &options->challenge_reponse_authentication;
|
||||
goto parse_flag;
|
||||
#endif
|
||||
|
||||
case sPrintMotd:
|
||||
intptr = &options->print_motd;
|
||||
goto parse_flag;
|
||||
|
||||
case sPrintLastLog:
|
||||
intptr = &options->print_lastlog;
|
||||
goto parse_flag;
|
||||
|
||||
case sX11Forwarding:
|
||||
intptr = &options->x11_forwarding;
|
||||
goto parse_flag;
|
||||
@ -583,7 +668,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
case sXAuthLocation:
|
||||
charptr = &options->xauth_location;
|
||||
goto parse_filename;
|
||||
|
||||
|
||||
case sStrictModes:
|
||||
intptr = &options->strict_modes;
|
||||
goto parse_flag;
|
||||
@ -604,12 +689,16 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
intptr = &options->gateway_ports;
|
||||
goto parse_flag;
|
||||
|
||||
case sReverseMappingCheck:
|
||||
intptr = &options->reverse_mapping_check;
|
||||
goto parse_flag;
|
||||
|
||||
case sLogFacility:
|
||||
intptr = (int *) &options->log_facility;
|
||||
arg = strdelim(&cp);
|
||||
value = log_facility_number(arg);
|
||||
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>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (SyslogFacility) value;
|
||||
@ -620,7 +709,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
arg = strdelim(&cp);
|
||||
value = log_level_number(arg);
|
||||
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>");
|
||||
if (*intptr == -1)
|
||||
*intptr = (LogLevel) value;
|
||||
@ -633,7 +722,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
case sAllowUsers:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
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);
|
||||
options->allow_users[options->num_allow_users++] = xstrdup(arg);
|
||||
}
|
||||
@ -642,7 +731,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
case sDenyUsers:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
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);
|
||||
options->deny_users[options->num_deny_users++] = xstrdup(arg);
|
||||
}
|
||||
@ -651,7 +740,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
case sAllowGroups:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
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);
|
||||
options->allow_groups[options->num_allow_groups++] = xstrdup(arg);
|
||||
}
|
||||
@ -660,7 +749,7 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
case sDenyGroups:
|
||||
while ((arg = strdelim(&cp)) && *arg != '\0') {
|
||||
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);
|
||||
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);
|
||||
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:
|
||||
intptr = &options->protocol;
|
||||
arg = strdelim(&cp);
|
||||
@ -744,20 +844,25 @@ read_server_config(ServerOptions *options, const char *filename)
|
||||
while (arg != NULL && *arg != '\0');
|
||||
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:
|
||||
fatal("%.200s line %d: Missing handler for opcode %s (%d)\n",
|
||||
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);
|
||||
fatal("%.200s line %d: Missing handler for opcode %s (%d)",
|
||||
filename, linenum, arg, opcode);
|
||||
}
|
||||
if ((arg = strdelim(&cp)) != NULL && *arg != '\0')
|
||||
fatal("%s line %d: garbage at end of line; \"%.200s\".",
|
||||
filename, linenum, arg);
|
||||
}
|
||||
fclose(f);
|
||||
if (bad_options > 0) {
|
||||
fatal("%.200s: terminating, %d bad configuration options\n",
|
||||
filename, bad_options);
|
||||
}
|
||||
if (bad_options > 0)
|
||||
fatal("%.200s: terminating, %d bad configuration options",
|
||||
filename, bad_options);
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
* 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 $"); */
|
||||
/* $FreeBSD$ */
|
||||
/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
|
||||
#ifndef SERVCONF_H
|
||||
#define SERVCONF_H
|
||||
@ -24,25 +24,35 @@
|
||||
#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
|
||||
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
|
||||
#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 {
|
||||
unsigned int num_ports;
|
||||
unsigned int ports_from_cmdline;
|
||||
u_int num_ports;
|
||||
u_int ports_from_cmdline;
|
||||
u_short ports[MAX_PORTS]; /* Port number to listen on. */
|
||||
char *listen_addr; /* Address on which the server listens. */
|
||||
struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
|
||||
char *host_key_file; /* File containing host key. */
|
||||
char *host_dsa_key_file; /* File containing dsa host key. */
|
||||
char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */
|
||||
int num_host_key_files; /* Number of files for host keys. */
|
||||
char *pid_file; /* Where to put our pid */
|
||||
int server_key_bits;/* Size of the server key. */
|
||||
int login_grace_time; /* Disconnect if no auth in this time
|
||||
* (sec). */
|
||||
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_user_known_hosts; /* Ignore ~/.ssh/known_hosts
|
||||
* for RhostsRsaAuth */
|
||||
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 x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */
|
||||
int x11_display_offset; /* What DISPLAY number to start
|
||||
@ -50,8 +60,9 @@ typedef struct {
|
||||
char *xauth_location; /* Location of xauth program */
|
||||
int strict_modes; /* If true, require string home dir modes. */
|
||||
int keepalives; /* If true, set SO_KEEPALIVE. */
|
||||
char *ciphers; /* Ciphers in order of preference. */
|
||||
int protocol; /* Protocol in order of preference. */
|
||||
char *ciphers; /* Supported SSH2 ciphers. */
|
||||
char *macs; /* Supported SSH2 macs. */
|
||||
int protocol; /* Supported protocol versions. */
|
||||
int gateway_ports; /* If true, allow remote connects to forwarded ports. */
|
||||
SyslogFacility log_facility; /* Facility for system logging. */
|
||||
LogLevel log_level; /* Level for system logging. */
|
||||
@ -59,11 +70,13 @@ typedef struct {
|
||||
* authentication. */
|
||||
int rhosts_rsa_authentication; /* If true, permit rhosts RSA
|
||||
* 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 dsa_authentication; /* If true, permit DSA authentication. */
|
||||
#if defined(KRB4) || defined(KRB5)
|
||||
int kerberos_authentication; /* If true, permit Kerberos auth. */
|
||||
#endif /* KRB4 || KRB5 */
|
||||
int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */
|
||||
#ifdef KRB4
|
||||
int krb4_or_local_passwd; /* If true, permit kerberos v4
|
||||
* and any other password
|
||||
@ -85,21 +98,18 @@ typedef struct {
|
||||
int password_authentication; /* If true, permit password
|
||||
* authentication. */
|
||||
int kbd_interactive_authentication; /* If true, permit */
|
||||
#ifdef SKEY
|
||||
int skey_authentication; /* If true, permit s/key
|
||||
* authentication. */
|
||||
#endif
|
||||
int challenge_reponse_authentication;
|
||||
int permit_empty_passwd; /* If false, do not permit empty
|
||||
* passwords. */
|
||||
int use_login; /* If true, login(1) is used */
|
||||
int allow_tcp_forwarding;
|
||||
unsigned int num_allow_users;
|
||||
u_int num_allow_users;
|
||||
char *allow_users[MAX_ALLOW_USERS];
|
||||
unsigned int num_deny_users;
|
||||
u_int num_deny_users;
|
||||
char *deny_users[MAX_DENY_USERS];
|
||||
unsigned int num_allow_groups;
|
||||
u_int num_allow_groups;
|
||||
char *allow_groups[MAX_ALLOW_GROUPS];
|
||||
unsigned int num_deny_groups;
|
||||
u_int num_deny_groups;
|
||||
char *deny_groups[MAX_DENY_GROUPS];
|
||||
unsigned int connections_per_period; /*
|
||||
* If not 0, number of sshd
|
||||
@ -108,13 +118,24 @@ typedef struct {
|
||||
*/
|
||||
unsigned int connections_period;
|
||||
|
||||
unsigned int num_subsystems;
|
||||
u_int num_subsystems;
|
||||
char *subsystem_name[MAX_SUBSYSTEMS];
|
||||
char *subsystem_command[MAX_SUBSYSTEMS];
|
||||
|
||||
int max_startups_begin;
|
||||
int max_startups_rate;
|
||||
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;
|
||||
/*
|
||||
|
@ -11,7 +11,7 @@
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* 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
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -36,24 +36,31 @@
|
||||
|
||||
#include "includes.h"
|
||||
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 "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "log.h"
|
||||
#include "servconf.h"
|
||||
#include "pty.h"
|
||||
#include "sshpty.h"
|
||||
#include "channels.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "ssh1.h"
|
||||
#include "ssh2.h"
|
||||
#include "auth.h"
|
||||
#include "session.h"
|
||||
#include "dispatch.h"
|
||||
#include "auth-options.h"
|
||||
#include "serverloop.h"
|
||||
#include "misc.h"
|
||||
#include "kex.h"
|
||||
|
||||
extern ServerOptions options;
|
||||
|
||||
/* XXX */
|
||||
extern Kex *xxx_kex;
|
||||
|
||||
static Buffer stdin_buffer; /* Buffer for stdin data. */
|
||||
static Buffer stdout_buffer; /* Buffer for stdout 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 connection_in; /* Connection to client (input). */
|
||||
static int connection_out; /* Connection to client (output). */
|
||||
static unsigned int buffer_high;/* "Soft" max buffer size. */
|
||||
static int max_fd; /* Max file descriptor number for select(). */
|
||||
static int connection_closed = 0; /* Connection to client closed. */
|
||||
static u_int buffer_high; /* "Soft" max buffer size. */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
int client_alive_timeouts = 0;
|
||||
|
||||
void
|
||||
sigchld_handler(int sig)
|
||||
{
|
||||
@ -119,7 +128,7 @@ sigchld_handler2(int sig)
|
||||
* to the client.
|
||||
*/
|
||||
void
|
||||
make_packets_from_stderr_data()
|
||||
make_packets_from_stderr_data(void)
|
||||
{
|
||||
int len;
|
||||
|
||||
@ -148,7 +157,7 @@ make_packets_from_stderr_data()
|
||||
* client.
|
||||
*/
|
||||
void
|
||||
make_packets_from_stdout_data()
|
||||
make_packets_from_stdout_data(void)
|
||||
{
|
||||
int len;
|
||||
|
||||
@ -162,7 +171,7 @@ make_packets_from_stdout_data()
|
||||
} else {
|
||||
/* Keep the packets at reasonable size. */
|
||||
if (len > packet_get_maxsize())
|
||||
len = packet_get_maxsize();
|
||||
len = packet_get_maxsize();
|
||||
}
|
||||
packet_start(SSH_SMSG_STDOUT_DATA);
|
||||
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).
|
||||
*/
|
||||
void
|
||||
wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
unsigned int max_time_milliseconds)
|
||||
wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
|
||||
u_int max_time_milliseconds)
|
||||
{
|
||||
struct timeval tv, *tvp;
|
||||
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. */
|
||||
retry_select:
|
||||
|
||||
/* Initialize select() masks. */
|
||||
FD_ZERO(readset);
|
||||
FD_ZERO(writeset);
|
||||
/* Allocate and update select() masks for channel descriptors. */
|
||||
channel_prepare_select(readsetp, writesetp, maxfdp, 0);
|
||||
|
||||
if (compat20) {
|
||||
/* wrong: bad condition XXX */
|
||||
if (channel_not_very_much_buffered_data())
|
||||
FD_SET(connection_in, readset);
|
||||
FD_SET(connection_in, *readsetp);
|
||||
} else {
|
||||
/*
|
||||
* 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 &&
|
||||
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
|
||||
* the client, try to get some more data from the program.
|
||||
*/
|
||||
if (packet_not_very_much_data_to_write()) {
|
||||
if (!fdout_eof)
|
||||
FD_SET(fdout, readset);
|
||||
FD_SET(fdout, *readsetp);
|
||||
if (!fderr_eof)
|
||||
FD_SET(fderr, readset);
|
||||
FD_SET(fderr, *readsetp);
|
||||
}
|
||||
/*
|
||||
* If we have buffered data, try to write some of that data
|
||||
* to the program.
|
||||
*/
|
||||
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
|
||||
* descriptor.
|
||||
*/
|
||||
if (packet_have_data_to_write())
|
||||
FD_SET(connection_out, writeset);
|
||||
|
||||
/* Update the maximum descriptor number if appropriate. */
|
||||
if (channel_max_fd() > max_fd)
|
||||
max_fd = channel_max_fd();
|
||||
FD_SET(connection_out, *writesetp);
|
||||
|
||||
/*
|
||||
* If child has terminated and there is enough buffer space to read
|
||||
* from it, then read as much as is available and exit.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (max_time_milliseconds == 0)
|
||||
@ -251,17 +268,41 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset,
|
||||
tvp = &tv;
|
||||
}
|
||||
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. */
|
||||
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)
|
||||
error("select: %.100s", strerror(errno));
|
||||
else
|
||||
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));
|
||||
if (len == 0) {
|
||||
verbose("Connection closed by remote host.");
|
||||
connection_closed = 1;
|
||||
if (compat20)
|
||||
return;
|
||||
fatal_cleanup();
|
||||
} else if (len < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
@ -351,9 +395,7 @@ process_output(fd_set * writeset)
|
||||
* Simulate echo to reduce the impact of
|
||||
* traffic analysis
|
||||
*/
|
||||
packet_start(SSH_MSG_IGNORE);
|
||||
memset(buffer_ptr(&stdin_buffer), 0, len);
|
||||
packet_put_string(buffer_ptr(&stdin_buffer), len);
|
||||
packet_send_ignore(len);
|
||||
packet_send();
|
||||
}
|
||||
/* Consume the data from the buffer. */
|
||||
@ -372,7 +414,7 @@ process_output(fd_set * writeset)
|
||||
* This is used when the program terminates.
|
||||
*/
|
||||
void
|
||||
drain_output()
|
||||
drain_output(void)
|
||||
{
|
||||
/* Send any buffered stdout data to the client. */
|
||||
if (buffer_len(&stdout_buffer) > 0) {
|
||||
@ -397,9 +439,9 @@ drain_output()
|
||||
}
|
||||
|
||||
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
|
||||
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(). */
|
||||
pid_t wait_pid; /* pid returned by wait(). */
|
||||
int waiting_termination = 0; /* Have displayed waiting close message. */
|
||||
unsigned int max_time_milliseconds;
|
||||
unsigned int previous_stdout_buffer_bytes;
|
||||
unsigned int stdout_buffer_bytes;
|
||||
u_int max_time_milliseconds;
|
||||
u_int previous_stdout_buffer_bytes;
|
||||
u_int stdout_buffer_bytes;
|
||||
int type;
|
||||
|
||||
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;
|
||||
|
||||
/* Initialize max_fd to the maximum of the known file descriptors. */
|
||||
max_fd = fdin;
|
||||
if (fdout > max_fd)
|
||||
max_fd = fdout;
|
||||
if (fderr != -1 && fderr > max_fd)
|
||||
max_fd = fderr;
|
||||
if (connection_in > max_fd)
|
||||
max_fd = connection_in;
|
||||
if (connection_out > max_fd)
|
||||
max_fd = connection_out;
|
||||
max_fd = MAX(fdin, fdout);
|
||||
if (fderr != -1)
|
||||
max_fd = MAX(max_fd, fderr);
|
||||
max_fd = MAX(max_fd, connection_in);
|
||||
max_fd = MAX(max_fd, connection_out);
|
||||
|
||||
/* Initialize Initialize buffers. */
|
||||
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. */
|
||||
wait_until_can_do_something(&readset, &writeset,
|
||||
max_time_milliseconds);
|
||||
wait_until_can_do_something(&readset, &writeset, &max_fd,
|
||||
max_time_milliseconds);
|
||||
|
||||
/* 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(&readset);
|
||||
process_input(readset);
|
||||
|
||||
/* 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. */
|
||||
|
||||
@ -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_pid = wait(&wait_status);
|
||||
if (wait_pid < 0) {
|
||||
if (wait_pid == -1) {
|
||||
/*
|
||||
* It is possible that the wait was handled by SIGCHLD
|
||||
* 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
|
||||
server_loop2(void)
|
||||
{
|
||||
fd_set readset, writeset;
|
||||
int had_channel = 0;
|
||||
int status;
|
||||
fd_set *readset = NULL, *writeset = NULL;
|
||||
int rekeying = 0, max_fd, status;
|
||||
pid_t pid;
|
||||
|
||||
debug("Entering interactive session for SSH2.");
|
||||
@ -663,42 +705,61 @@ server_loop2(void)
|
||||
child_terminated = 0;
|
||||
connection_in = packet_get_connection_in();
|
||||
connection_out = packet_get_connection_out();
|
||||
max_fd = connection_in;
|
||||
if (connection_out > max_fd)
|
||||
max_fd = connection_out;
|
||||
|
||||
max_fd = MAX(connection_in, connection_out);
|
||||
|
||||
server_init_dispatch();
|
||||
|
||||
for (;;) {
|
||||
process_buffered_input_packets();
|
||||
if (!had_channel && channel_still_open())
|
||||
had_channel = 1;
|
||||
if (had_channel && !channel_still_open()) {
|
||||
debug("!channel_still_open.");
|
||||
break;
|
||||
}
|
||||
if (packet_not_very_much_data_to_write())
|
||||
|
||||
rekeying = (xxx_kex != NULL && !xxx_kex->done);
|
||||
|
||||
if (!rekeying && packet_not_very_much_data_to_write())
|
||||
channel_output_poll();
|
||||
wait_until_can_do_something(&readset, &writeset, 0);
|
||||
wait_until_can_do_something(&readset, &writeset, &max_fd,
|
||||
rekeying);
|
||||
if (child_terminated) {
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
child_terminated = 0;
|
||||
}
|
||||
channel_after_select(&readset, &writeset);
|
||||
process_input(&readset);
|
||||
process_output(&writeset);
|
||||
if (!rekeying)
|
||||
channel_after_select(readset, writeset);
|
||||
process_input(readset);
|
||||
if (connection_closed)
|
||||
break;
|
||||
process_output(writeset);
|
||||
}
|
||||
if (readset)
|
||||
xfree(readset);
|
||||
if (writeset)
|
||||
xfree(writeset);
|
||||
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
session_close_by_pid(pid, status);
|
||||
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
|
||||
server_input_stdin_data(int type, int plen, void *ctxt)
|
||||
{
|
||||
char *data;
|
||||
unsigned int data_len;
|
||||
u_int data_len;
|
||||
|
||||
/* Stdin data from the client. Append it to the buffer. */
|
||||
/* 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);
|
||||
}
|
||||
|
||||
int
|
||||
input_direct_tcpip(void)
|
||||
Channel *
|
||||
server_request_direct_tcpip(char *ctype)
|
||||
{
|
||||
int sock;
|
||||
int sock, newch;
|
||||
char *target, *originator;
|
||||
int target_port, originator_port;
|
||||
|
||||
@ -751,23 +812,47 @@ input_direct_tcpip(void)
|
||||
originator_port = packet_get_int();
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
xfree(target);
|
||||
xfree(originator);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
return channel_new("direct-tcpip", SSH_CHANNEL_OPEN,
|
||||
return NULL;
|
||||
newch = channel_new(ctype, SSH_CHANNEL_CONNECTING,
|
||||
sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
|
||||
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
|
||||
@ -775,8 +860,7 @@ server_input_channel_open(int type, int plen, void *ctxt)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
char *ctype;
|
||||
int id;
|
||||
unsigned int len;
|
||||
u_int len;
|
||||
int rchan;
|
||||
int rmaxpack;
|
||||
int rwindow;
|
||||
@ -790,34 +874,12 @@ server_input_channel_open(int type, int plen, void *ctxt)
|
||||
ctype, rchan, rwindow, rmaxpack);
|
||||
|
||||
if (strcmp(ctype, "session") == 0) {
|
||||
debug("open session");
|
||||
packet_done();
|
||||
/*
|
||||
* A server session has no fd to read or write
|
||||
* until a CHANNEL_REQUEST for a shell is made,
|
||||
* so we set the type to SSH_CHANNEL_LARVAL.
|
||||
* Additionally, a callback for handling all
|
||||
* CHANNEL_REQUEST messages is registered.
|
||||
*/
|
||||
id = channel_new(ctype, SSH_CHANNEL_LARVAL,
|
||||
-1, -1, -1, 0, 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);
|
||||
}
|
||||
c = server_request_session(ctype);
|
||||
} else if (strcmp(ctype, "direct-tcpip") == 0) {
|
||||
id = input_direct_tcpip();
|
||||
if (id >= 0)
|
||||
c = channel_lookup(id);
|
||||
c = server_request_direct_tcpip(ctype);
|
||||
}
|
||||
if (c != NULL) {
|
||||
debug("confirm %s", ctype);
|
||||
debug("server_input_channel_open: confirm %s", ctype);
|
||||
c->remote_id = rchan;
|
||||
c->remote_window = rwindow;
|
||||
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_send();
|
||||
} else {
|
||||
debug("failure %s", ctype);
|
||||
debug("server_input_channel_open: failure %s", ctype);
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(rchan);
|
||||
packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
|
||||
@ -841,7 +903,57 @@ server_input_channel_open(int type, int plen, void *ctxt)
|
||||
}
|
||||
|
||||
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");
|
||||
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_REQUEST, &channel_input_channel_request);
|
||||
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
|
||||
server_init_dispatch_13()
|
||||
server_init_dispatch_13(void)
|
||||
{
|
||||
debug("server_init_dispatch_13");
|
||||
dispatch_init(NULL);
|
||||
@ -871,7 +988,7 @@ server_init_dispatch_13()
|
||||
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
|
||||
}
|
||||
void
|
||||
server_init_dispatch_15()
|
||||
server_init_dispatch_15(void)
|
||||
{
|
||||
server_init_dispatch_13();
|
||||
debug("server_init_dispatch_15");
|
||||
@ -879,7 +996,7 @@ server_init_dispatch_15()
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose);
|
||||
}
|
||||
void
|
||||
server_init_dispatch()
|
||||
server_init_dispatch(void)
|
||||
{
|
||||
if (compat20)
|
||||
server_init_dispatch_20();
|
||||
@ -888,3 +1005,4 @@ server_init_dispatch()
|
||||
else
|
||||
server_init_dispatch_15();
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* 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
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -36,33 +36,42 @@
|
||||
|
||||
#include "includes.h"
|
||||
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/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "log.h"
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "authfd.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
|
||||
delete_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
Key *public;
|
||||
char *comment;
|
||||
char *comment = NULL;
|
||||
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(filename, public, &comment)) {
|
||||
key_free(public);
|
||||
public = key_new(KEY_DSA);
|
||||
if (!try_load_public_key(filename, public, &comment)) {
|
||||
printf("Bad key file %s\n", filename);
|
||||
return;
|
||||
}
|
||||
public = key_load_public(filename, &comment);
|
||||
if (public == NULL) {
|
||||
printf("Bad key file %s\n", filename);
|
||||
return;
|
||||
}
|
||||
if (ssh_remove_identity(ac, public))
|
||||
fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
|
||||
@ -86,129 +95,61 @@ delete_all(AuthenticationConnection *ac)
|
||||
if (success)
|
||||
fprintf(stderr, "All identities removed.\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to remove all identitities.\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;
|
||||
fprintf(stderr, "Failed to remove all identities.\n");
|
||||
}
|
||||
|
||||
void
|
||||
add_file(AuthenticationConnection *ac, const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
Key *public;
|
||||
Key *private;
|
||||
char *saved_comment, *comment, *askpass = NULL;
|
||||
char buf[1024], msg[1024];
|
||||
int success;
|
||||
int interactive = isatty(STDIN_FILENO);
|
||||
int type = KEY_RSA;
|
||||
char *comment = NULL;
|
||||
char msg[1024];
|
||||
|
||||
if (stat(filename, &st) < 0) {
|
||||
perror(filename);
|
||||
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 */
|
||||
private = key_new(type);
|
||||
success = load_private_key(filename, "", private, &comment);
|
||||
if (!success) {
|
||||
private = key_load_private(filename, "", &comment);
|
||||
if (comment == NULL)
|
||||
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);
|
||||
if (!interactive && askpass == NULL) {
|
||||
xfree(saved_comment);
|
||||
return;
|
||||
}
|
||||
snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
|
||||
snprintf(msg, sizeof msg, "Enter passphrase for %.200s ",
|
||||
comment);
|
||||
for (;;) {
|
||||
char *pass;
|
||||
if (interactive) {
|
||||
snprintf(buf, sizeof buf, "%s: ", msg);
|
||||
pass = read_passphrase(buf, 1);
|
||||
} else {
|
||||
pass = ssh_askpass(askpass, msg);
|
||||
}
|
||||
pass = read_passphrase(msg, 1);
|
||||
if (strcmp(pass, "") == 0) {
|
||||
xfree(pass);
|
||||
xfree(saved_comment);
|
||||
clear_pass();
|
||||
xfree(comment);
|
||||
return;
|
||||
}
|
||||
success = load_private_key(filename, pass, private, &comment);
|
||||
memset(pass, 0, strlen(pass));
|
||||
xfree(pass);
|
||||
if (success)
|
||||
private = key_load_private(filename, pass, &comment);
|
||||
if (private != NULL)
|
||||
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, saved_comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, saved_comment);
|
||||
if (ssh_add_identity(ac, private, comment))
|
||||
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
|
||||
else
|
||||
fprintf(stderr, "Could not add identity: %s\n", filename);
|
||||
xfree(comment);
|
||||
key_free(private);
|
||||
xfree(saved_comment);
|
||||
}
|
||||
|
||||
void
|
||||
list_identities(AuthenticationConnection *ac, int fp)
|
||||
list_identities(AuthenticationConnection *ac, int do_fp)
|
||||
{
|
||||
Key *key;
|
||||
char *comment;
|
||||
char *comment, *fp;
|
||||
int had_identities = 0;
|
||||
int version;
|
||||
|
||||
@ -217,9 +158,12 @@ list_identities(AuthenticationConnection *ac, int fp)
|
||||
key != NULL;
|
||||
key = ssh_get_next_identity(ac, &comment, version)) {
|
||||
had_identities = 1;
|
||||
if (fp) {
|
||||
printf("%d %s %s\n",
|
||||
key_size(key), key_fingerprint(key), comment);
|
||||
if (do_fp) {
|
||||
fp = key_fingerprint(key, SSH_FP_MD5,
|
||||
SSH_FP_HEX);
|
||||
printf("%d %s %s (%s)\n",
|
||||
key_size(key), fp, comment, key_type(key));
|
||||
xfree(fp);
|
||||
} else {
|
||||
if (!key_write(key, stdout))
|
||||
fprintf(stderr, "key_write failed");
|
||||
@ -243,16 +187,7 @@ main(int argc, char **argv)
|
||||
int i;
|
||||
int deleting = 0;
|
||||
|
||||
/* check if RSA support exists */
|
||||
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();
|
||||
SSLeay_add_all_algorithms();
|
||||
|
||||
/* At first, get a connection to the authentication agent. */
|
||||
ac = ssh_get_authentication_connection();
|
||||
@ -291,12 +226,13 @@ main(int argc, char **argv)
|
||||
ssh_close_authentication_connection(ac);
|
||||
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)
|
||||
delete_file(ac, buf);
|
||||
else
|
||||
add_file(ac, buf);
|
||||
}
|
||||
clear_pass();
|
||||
ssh_close_authentication_connection(ac);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -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>
|
||||
@ -13,7 +13,7 @@
|
||||
* called by a name other than "ssh" or "Secure Shell".
|
||||
*
|
||||
* 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
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -37,9 +37,12 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "buffer.h"
|
||||
@ -48,16 +51,12 @@ RCSID("$FreeBSD$");
|
||||
#include "packet.h"
|
||||
#include "getput.h"
|
||||
#include "mpaux.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "dsa.h"
|
||||
#include "cipher.h"
|
||||
#include "kex.h"
|
||||
#include "compat.h"
|
||||
#include "log.h"
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
@ -68,7 +67,7 @@ typedef struct {
|
||||
Buffer output;
|
||||
} SocketEntry;
|
||||
|
||||
unsigned int sockets_alloc = 0;
|
||||
u_int sockets_alloc = 0;
|
||||
SocketEntry *sockets = NULL;
|
||||
|
||||
typedef struct {
|
||||
@ -95,6 +94,8 @@ char socket_dir[1024];
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
int prepare_select(fd_set **, fd_set **, int *);
|
||||
|
||||
void
|
||||
idtab_init(void)
|
||||
{
|
||||
@ -144,14 +145,14 @@ process_request_identities(SocketEntry *e, int version)
|
||||
buffer_put_int(&msg, tab->nentries);
|
||||
for (i = 0; i < tab->nentries; 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_bignum(&msg, id->key->rsa->e);
|
||||
buffer_put_bignum(&msg, id->key->rsa->n);
|
||||
} else {
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
dsa_make_key_blob(id->key, &blob, &blen);
|
||||
u_char *blob;
|
||||
u_int blen;
|
||||
key_to_blob(id->key, &blob, &blen);
|
||||
buffer_put_string(&msg, blob, blen);
|
||||
xfree(blob);
|
||||
}
|
||||
@ -171,11 +172,11 @@ process_authentication_challenge1(SocketEntry *e)
|
||||
int i, len;
|
||||
Buffer msg;
|
||||
MD5_CTX md;
|
||||
unsigned char buf[32], mdbuf[16], session_id[16];
|
||||
unsigned int response_type;
|
||||
u_char buf[32], mdbuf[16], session_id[16];
|
||||
u_int response_type;
|
||||
|
||||
buffer_init(&msg);
|
||||
key = key_new(KEY_RSA);
|
||||
key = key_new(KEY_RSA1);
|
||||
challenge = BN_new();
|
||||
|
||||
buffer_get_int(&e->input); /* ignored */
|
||||
@ -234,14 +235,14 @@ process_sign_request2(SocketEntry *e)
|
||||
{
|
||||
extern int datafellows;
|
||||
Key *key, *private;
|
||||
unsigned char *blob, *data, *signature = NULL;
|
||||
unsigned int blen, dlen, slen = 0;
|
||||
u_char *blob, *data, *signature = NULL;
|
||||
u_int blen, dlen, slen = 0;
|
||||
int flags;
|
||||
Buffer msg;
|
||||
int ok = -1;
|
||||
|
||||
datafellows = 0;
|
||||
|
||||
|
||||
blob = buffer_get_string(&e->input, &blen);
|
||||
data = buffer_get_string(&e->input, &dlen);
|
||||
|
||||
@ -249,11 +250,11 @@ process_sign_request2(SocketEntry *e)
|
||||
if (flags & SSH_AGENT_OLD_SIGNATURE)
|
||||
datafellows = SSH_BUG_SIGBLOB;
|
||||
|
||||
key = dsa_key_from_blob(blob, blen);
|
||||
key = key_from_blob(blob, blen);
|
||||
if (key != NULL) {
|
||||
private = lookup_private_key(key, NULL, 2);
|
||||
if (private != NULL)
|
||||
ok = dsa_sign(private, &signature, &slen, data, dlen);
|
||||
ok = key_sign(private, &signature, &slen, data, dlen);
|
||||
}
|
||||
key_free(key);
|
||||
buffer_init(&msg);
|
||||
@ -278,25 +279,25 @@ void
|
||||
process_remove_identity(SocketEntry *e, int version)
|
||||
{
|
||||
Key *key = NULL, *private;
|
||||
unsigned char *blob;
|
||||
unsigned int blen;
|
||||
unsigned int bits;
|
||||
u_char *blob;
|
||||
u_int blen;
|
||||
u_int bits;
|
||||
int success = 0;
|
||||
|
||||
switch(version){
|
||||
case 1:
|
||||
key = key_new(KEY_RSA);
|
||||
key = key_new(KEY_RSA1);
|
||||
bits = buffer_get_int(&e->input);
|
||||
buffer_get_bignum(&e->input, key->rsa->e);
|
||||
buffer_get_bignum(&e->input, key->rsa->n);
|
||||
|
||||
if (bits != key_size(key))
|
||||
log("Warning: identity keysize mismatch: actual %d, announced %d",
|
||||
key_size(key), bits);
|
||||
key_size(key), bits);
|
||||
break;
|
||||
case 2:
|
||||
blob = buffer_get_string(&e->input, &blen);
|
||||
key = dsa_key_from_blob(blob, blen);
|
||||
key = key_from_blob(blob, blen);
|
||||
xfree(blob);
|
||||
break;
|
||||
}
|
||||
@ -307,14 +308,24 @@ process_remove_identity(SocketEntry *e, int version)
|
||||
/*
|
||||
* We have this key. Free the old key. Since we
|
||||
* don\'t want to leave empty slots in the middle of
|
||||
* the array, we actually free the key there and copy
|
||||
* data from the last entry.
|
||||
* the array, we actually free the key there and move
|
||||
* all the entries between the empty slot and the end
|
||||
* of the array.
|
||||
*/
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
key_free(tab->identities[idx].key);
|
||||
xfree(tab->identities[idx].comment);
|
||||
if (idx != tab->nentries)
|
||||
tab->identities[idx] = tab->identities[tab->nentries];
|
||||
if (tab->nentries < 1)
|
||||
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--;
|
||||
success = 1;
|
||||
}
|
||||
@ -328,7 +339,7 @@ process_remove_identity(SocketEntry *e, int version)
|
||||
void
|
||||
process_remove_all_identities(SocketEntry *e, int version)
|
||||
{
|
||||
unsigned int i;
|
||||
u_int i;
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
|
||||
/* Loop over all identities and clear the keys. */
|
||||
@ -350,76 +361,58 @@ void
|
||||
process_add_identity(SocketEntry *e, int version)
|
||||
{
|
||||
Key *k = NULL;
|
||||
RSA *rsa;
|
||||
BIGNUM *aux;
|
||||
BN_CTX *ctx;
|
||||
char *type;
|
||||
char *type_name;
|
||||
char *comment;
|
||||
int success = 0;
|
||||
int type, success = 0;
|
||||
Idtab *tab = idtab_lookup(version);
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
k = key_new(KEY_RSA);
|
||||
rsa = k->rsa;
|
||||
|
||||
/* allocate mem for private key */
|
||||
/* XXX rsa->n and rsa->e are already allocated */
|
||||
rsa->d = BN_new();
|
||||
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);
|
||||
k = key_new_private(KEY_RSA1);
|
||||
buffer_get_int(&e->input); /* ignored */
|
||||
buffer_get_bignum(&e->input, k->rsa->n);
|
||||
buffer_get_bignum(&e->input, k->rsa->e);
|
||||
buffer_get_bignum(&e->input, k->rsa->d);
|
||||
buffer_get_bignum(&e->input, k->rsa->iqmp);
|
||||
|
||||
/* SSH and SSL have p and q swapped */
|
||||
buffer_get_bignum(&e->input, rsa->q); /* p */
|
||||
buffer_get_bignum(&e->input, rsa->p); /* q */
|
||||
buffer_get_bignum(&e->input, k->rsa->q); /* p */
|
||||
buffer_get_bignum(&e->input, k->rsa->p); /* q */
|
||||
|
||||
/* 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);
|
||||
|
||||
generate_additional_parameters(k->rsa);
|
||||
break;
|
||||
case 2:
|
||||
type = buffer_get_string(&e->input, NULL);
|
||||
if (strcmp(type, KEX_DSS)) {
|
||||
type_name = buffer_get_string(&e->input, NULL);
|
||||
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);
|
||||
xfree(type);
|
||||
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;
|
||||
}
|
||||
|
||||
comment = buffer_get_string(&e->input, NULL);
|
||||
if (k == NULL) {
|
||||
xfree(comment);
|
||||
@ -451,12 +444,12 @@ process_add_identity(SocketEntry *e, int version)
|
||||
void
|
||||
process_message(SocketEntry *e)
|
||||
{
|
||||
unsigned int msg_len;
|
||||
unsigned int type;
|
||||
unsigned char *cp;
|
||||
u_int msg_len;
|
||||
u_int type;
|
||||
u_char *cp;
|
||||
if (buffer_len(&e->input) < 5)
|
||||
return; /* Incomplete message. */
|
||||
cp = (unsigned char *) buffer_ptr(&e->input);
|
||||
cp = (u_char *) buffer_ptr(&e->input);
|
||||
msg_len = GET_32BIT(cp);
|
||||
if (msg_len > 256 * 1024) {
|
||||
shutdown(e->fd, SHUT_RDWR);
|
||||
@ -515,7 +508,7 @@ process_message(SocketEntry *e)
|
||||
void
|
||||
new_socket(int type, int fd)
|
||||
{
|
||||
unsigned int i, old_alloc;
|
||||
u_int i, old_alloc;
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
error("fcntl O_NONBLOCK: %s", strerror(errno));
|
||||
|
||||
@ -544,17 +537,17 @@ new_socket(int type, int fd)
|
||||
buffer_init(&sockets[old_alloc].output);
|
||||
}
|
||||
|
||||
void
|
||||
prepare_select(fd_set *readset, fd_set *writeset)
|
||||
int
|
||||
prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < sockets_alloc; i++)
|
||||
u_int i, sz;
|
||||
int n = 0;
|
||||
|
||||
for (i = 0; i < sockets_alloc; i++) {
|
||||
switch (sockets[i].type) {
|
||||
case AUTH_SOCKET:
|
||||
case AUTH_CONNECTION:
|
||||
FD_SET(sockets[i].fd, readset);
|
||||
if (buffer_len(&sockets[i].output) > 0)
|
||||
FD_SET(sockets[i].fd, writeset);
|
||||
n = MAX(n, sockets[i].fd);
|
||||
break;
|
||||
case AUTH_UNUSED:
|
||||
break;
|
||||
@ -562,12 +555,40 @@ prepare_select(fd_set *readset, fd_set *writeset)
|
||||
fatal("Unknown socket type %d", sockets[i].type);
|
||||
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
|
||||
after_select(fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
unsigned int i;
|
||||
u_int i;
|
||||
int len, sock;
|
||||
socklen_t slen;
|
||||
char buf[1024];
|
||||
@ -580,7 +601,8 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
case AUTH_SOCKET:
|
||||
if (FD_ISSET(sockets[i].fd, readset)) {
|
||||
slen = sizeof(sunaddr);
|
||||
sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &slen);
|
||||
sock = accept(sockets[i].fd,
|
||||
(struct sockaddr *) &sunaddr, &slen);
|
||||
if (sock < 0) {
|
||||
perror("accept from AUTH_SOCKET");
|
||||
break;
|
||||
@ -591,8 +613,15 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
case AUTH_CONNECTION:
|
||||
if (buffer_len(&sockets[i].output) > 0 &&
|
||||
FD_ISSET(sockets[i].fd, writeset)) {
|
||||
len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
|
||||
buffer_len(&sockets[i].output));
|
||||
do {
|
||||
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) {
|
||||
shutdown(sockets[i].fd, SHUT_RDWR);
|
||||
close(sockets[i].fd);
|
||||
@ -604,7 +633,13 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
buffer_consume(&sockets[i].output, len);
|
||||
}
|
||||
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) {
|
||||
shutdown(sockets[i].fd, SHUT_RDWR);
|
||||
close(sockets[i].fd);
|
||||
@ -625,19 +660,24 @@ after_select(fd_set *readset, fd_set *writeset)
|
||||
void
|
||||
check_parent_exists(int sig)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
|
||||
/* printf("Parent has died - Authentication agent exiting.\n"); */
|
||||
exit(1);
|
||||
}
|
||||
signal(SIGALRM, check_parent_exists);
|
||||
alarm(10);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_socket(void)
|
||||
{
|
||||
remove(socket_name);
|
||||
rmdir(socket_dir);
|
||||
if (socket_name[0])
|
||||
unlink(socket_name);
|
||||
if (socket_dir[0])
|
||||
rmdir(socket_dir);
|
||||
}
|
||||
|
||||
void
|
||||
@ -648,30 +688,34 @@ cleanup_exit(int i)
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
cleanup_handler(int sig)
|
||||
{
|
||||
cleanup_socket();
|
||||
_exit(2);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
|
||||
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
|
||||
__progname);
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int ac, char **av)
|
||||
{
|
||||
fd_set readset, writeset;
|
||||
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
|
||||
struct sockaddr_un sunaddr;
|
||||
struct rlimit rlim;
|
||||
pid_t 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) {
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
@ -706,14 +750,13 @@ main(int ac, char **av)
|
||||
pidstr = getenv(SSH_AGENTPID_ENV_NAME);
|
||||
if (pidstr == NULL) {
|
||||
fprintf(stderr, "%s not set, cannot kill agent\n",
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
exit(1);
|
||||
}
|
||||
pid = atoi(pidstr);
|
||||
if (pid < 1) { /* XXX PID_MAX check too */
|
||||
/* Yes, PID_MAX check please */
|
||||
if (pid < 1) {
|
||||
fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
|
||||
SSH_AGENTPID_ENV_NAME, pidstr);
|
||||
SSH_AGENTPID_ENV_NAME, pidstr);
|
||||
exit(1);
|
||||
}
|
||||
if (kill(pid, SIGTERM) == -1) {
|
||||
@ -735,7 +778,7 @@ main(int ac, char **av)
|
||||
exit(1);
|
||||
}
|
||||
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
|
||||
@ -758,6 +801,7 @@ main(int ac, char **av)
|
||||
perror("listen");
|
||||
cleanup_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork, and have the parent execute the command, if any, or present
|
||||
* the socket data. The child continues as the authentication agent.
|
||||
@ -773,9 +817,9 @@ main(int ac, char **av)
|
||||
if (ac == 0) {
|
||||
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
|
||||
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
|
||||
SSH_AUTHSOCKET_ENV_NAME);
|
||||
SSH_AUTHSOCKET_ENV_NAME);
|
||||
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
printf("echo Agent pid %d;\n", pid);
|
||||
exit(0);
|
||||
}
|
||||
@ -792,6 +836,12 @@ main(int ac, char **av)
|
||||
close(1);
|
||||
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) {
|
||||
perror("setsid");
|
||||
cleanup_exit(1);
|
||||
@ -808,18 +858,16 @@ main(int ac, char **av)
|
||||
idtab_init();
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, cleanup_exit);
|
||||
signal(SIGTERM, cleanup_exit);
|
||||
signal(SIGHUP, cleanup_handler);
|
||||
signal(SIGTERM, cleanup_handler);
|
||||
while (1) {
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&writeset);
|
||||
prepare_select(&readset, &writeset);
|
||||
if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
|
||||
prepare_select(&readsetp, &writesetp, &max_fd);
|
||||
if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
exit(1);
|
||||
}
|
||||
after_select(&readset, &writeset);
|
||||
after_select(readsetp, writesetp);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
@ -10,9 +10,9 @@
|
||||
.\" incompatible with the protocol description in the RFC file, it must be
|
||||
.\" called by a name other than "ssh" or "Secure Shell".
|
||||
.\"
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" 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
|
||||
.\" 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$
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
@ -41,7 +42,7 @@
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ssh
|
||||
.Nd OpenSSH secure shell client (remote login program)
|
||||
.Nd OpenSSH SSH client (remote login program)
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh
|
||||
.Op Fl l Ar login_name
|
||||
@ -49,11 +50,12 @@
|
||||
.Op Ar command
|
||||
.Pp
|
||||
.Nm ssh
|
||||
.Op Fl afgknqtvxACNPTX246
|
||||
.Op Fl afgknqstvxACNPTX1246
|
||||
.Op Fl c Ar cipher_spec
|
||||
.Op Fl e Ar escape_char
|
||||
.Op Fl i Ar identity_file
|
||||
.Op Fl l Ar login_name
|
||||
.Op Fl m Ar mac_spec
|
||||
.Op Fl o Ar option
|
||||
.Op Fl p Ar port
|
||||
.Oo Fl L Xo
|
||||
@ -76,7 +78,7 @@
|
||||
.Op Ar command
|
||||
.Sh DESCRIPTION
|
||||
.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.
|
||||
It is intended to replace
|
||||
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
|
||||
allowed by the server because it is not secure.
|
||||
.Pp
|
||||
The second (and primary) authentication method is the
|
||||
The second authentication method is the
|
||||
.Pa rhosts
|
||||
or
|
||||
.Pa hosts.equiv
|
||||
@ -205,15 +207,22 @@ the password cannot be seen by someone listening on the network.
|
||||
.Ss SSH protocol version 2
|
||||
.Pp
|
||||
When a user connects using the protocol version 2
|
||||
different authentication methods are available:
|
||||
At first, the client attempts to authenticate using the public key method.
|
||||
If this method fails password authentication is tried.
|
||||
different authentication methods are available.
|
||||
Using the default values for
|
||||
.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
|
||||
The public key method is similar to RSA authentication described
|
||||
in the previous section except that the DSA algorithm is used
|
||||
instead of the patented RSA algorithm.
|
||||
The client uses his private DSA key
|
||||
in the previous section and allows the RSA or DSA algorithm to be used:
|
||||
The client uses his private key,
|
||||
.Pa $HOME/.ssh/id_dsa
|
||||
or
|
||||
.Pa $HOME/.ssh/id_rsa ,
|
||||
to sign the session identifier and sends the result to the server.
|
||||
The server checks whether the matching public key is listed in
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
@ -223,12 +232,14 @@ and is only known to the client and the server.
|
||||
.Pp
|
||||
If public key authentication fails or is not available a password
|
||||
can be sent encrypted to the remote host for proving the user's identity.
|
||||
This protocol 2 implementation does not yet support Kerberos or
|
||||
OPIE authentication.
|
||||
.Pp
|
||||
Additionally,
|
||||
.Nm
|
||||
supports hostbased or challenge response authentication.
|
||||
.Pp
|
||||
Protocol 2 provides additional mechanisms for confidentiality
|
||||
(the traffic is encrypted using 3DES, Blowfish, CAST128 or Arcfour)
|
||||
and integrity (hmac-sha1, hmac-md5).
|
||||
and integrity (hmac-md5, hmac-sha1).
|
||||
Note that protocol 1 lacks a strong mechanism for ensuring the
|
||||
integrity of the connection.
|
||||
.Pp
|
||||
@ -241,30 +252,7 @@ All communication with
|
||||
the remote command or shell will be automatically encrypted.
|
||||
.Pp
|
||||
If a pseudo-terminal has been allocated (normal login session), the
|
||||
user can disconnect with
|
||||
.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.
|
||||
user may use the escape characters noted below.
|
||||
.Pp
|
||||
If no pseudo tty has been allocated, the
|
||||
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
|
||||
will also make the session transparent even if a tty is used.
|
||||
.Pp
|
||||
The session terminates when the command or shell in on the remote
|
||||
machine exists and all X11 and TCP/IP connections have been closed.
|
||||
The session terminates when the command or shell on the remote
|
||||
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
|
||||
of
|
||||
.Nm ssh .
|
||||
.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
|
||||
.Pp
|
||||
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
|
||||
be specified either on command line or in a configuration file.
|
||||
One possible application of TCP/IP forwarding is a secure connection to an
|
||||
electronic purse; another is going trough firewalls.
|
||||
electronic purse; another is going through firewalls.
|
||||
.Pp
|
||||
.Ss Server authentication
|
||||
.Pp
|
||||
@ -333,7 +357,7 @@ identifications for all hosts it has ever been used with.
|
||||
RSA host keys are stored in
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
and
|
||||
DSA host keys are stored in
|
||||
host keys used in the protocol version 2 are stored in
|
||||
.Pa $HOME/.ssh/known_hosts2
|
||||
in the user's home directory.
|
||||
Additionally, the files
|
||||
@ -354,7 +378,8 @@ The
|
||||
.Cm StrictHostKeyChecking
|
||||
option (see below) can be used to prevent logins to machines whose
|
||||
host key is not known or has changed.
|
||||
.Sh OPTIONS
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a
|
||||
Disables forwarding of the authentication agent connection.
|
||||
@ -375,11 +400,12 @@ cipher which is no longer fully supported in
|
||||
.Ar blowfish
|
||||
is a fast block cipher, it appears very secure and is much faster than
|
||||
.Ar 3des .
|
||||
.It Fl c Ar "3des-cbc,blowfish-cbc,arcfour,cast128-cbc"
|
||||
.It Fl c Ar cipher_spec
|
||||
Additionally, for protocol version 2 a comma-separated list of ciphers can
|
||||
be specified in order of preference.
|
||||
Protocol version 2 supports 3DES, Blowfish, and CAST128 in CBC mode
|
||||
and Arcfour.
|
||||
See
|
||||
.Cm Ciphers
|
||||
for more information.
|
||||
.It Fl e Ar ch|^ch|none
|
||||
Sets the escape character for sessions with a pty (default:
|
||||
.Ql ~ ) .
|
||||
@ -409,7 +435,7 @@ something like
|
||||
Allows remote hosts to connect to local forwarded ports.
|
||||
.It Fl i Ar identity_file
|
||||
Selects the file from which the identity (private key) for
|
||||
RSA authentication is read.
|
||||
RSA or DSA authentication is read.
|
||||
Default is
|
||||
.Pa $HOME/.ssh/identity
|
||||
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
|
||||
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.
|
||||
.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
|
||||
Redirects stdin from
|
||||
.Pa /dev/null
|
||||
@ -447,7 +480,7 @@ needs to ask for a password or passphrase; see also the
|
||||
option.)
|
||||
.It Fl N
|
||||
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).
|
||||
.It Fl o Ar option
|
||||
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
|
||||
.Cm RhostsAuthentication
|
||||
and
|
||||
.Cm RhostsRSAAuthentication .
|
||||
.Cm RhostsRSAAuthentication
|
||||
for older servers.
|
||||
.It Fl q
|
||||
Quiet mode.
|
||||
Causes all warning and diagnostic messages to be suppressed.
|
||||
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
|
||||
Force pseudo-tty allocation.
|
||||
This can be used to execute arbitrary
|
||||
screen-based programs on a remote machine, which can be very useful,
|
||||
e.g., when implementing menu services.
|
||||
Multiple
|
||||
.Fl t
|
||||
options force tty allocation, even if
|
||||
.Nm
|
||||
has no local tty.
|
||||
.It Fl T
|
||||
Disable pseudo-tty allocation (protocol version 2 only).
|
||||
Disable pseudo-tty allocation.
|
||||
.It Fl v
|
||||
Verbose mode.
|
||||
Causes
|
||||
@ -484,10 +527,9 @@ Causes
|
||||
to print debugging messages about its progress.
|
||||
This is helpful in
|
||||
debugging connection, authentication, and configuration problems.
|
||||
The verbose mode is also used to display
|
||||
.Xr skey 1
|
||||
challenges, if the user entered "s/key" as password.
|
||||
Multiple -v options increases the verbosity.
|
||||
Multiple
|
||||
.Fl v
|
||||
options increases the verbosity.
|
||||
Maximum is 3.
|
||||
.It Fl x
|
||||
Disables X11 forwarding.
|
||||
@ -541,6 +583,12 @@ from the local machine.
|
||||
Port forwardings can also be specified in the configuration file.
|
||||
Privileged ports can be forwarded only when
|
||||
logging in as root on the remote machine.
|
||||
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
|
||||
Forces
|
||||
.Nm
|
||||
@ -609,6 +657,7 @@ The argument to this keyword must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
This option applies to protocol version 1 only.
|
||||
.It Cm BatchMode
|
||||
If set to
|
||||
.Dq yes ,
|
||||
@ -619,16 +668,20 @@ The argument must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm CheckHostIP
|
||||
If this flag is set to
|
||||
.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
|
||||
file.
|
||||
This allows ssh to detect if a host key changed due to DNS spoofing.
|
||||
If the option is set to
|
||||
.Dq no ,
|
||||
the check will not be executed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
.It Cm Cipher
|
||||
Specifies the cipher to use for encrypting the session
|
||||
in protocol version 1.
|
||||
@ -644,33 +697,32 @@ Specifies the ciphers allowed for protocol version 2
|
||||
in order of preference.
|
||||
Multiple ciphers must be comma-separated.
|
||||
The default is
|
||||
.Dq 3des-cbc,blowfish-cbc,cast128-cbc,arcfour .
|
||||
.Pp
|
||||
.Bd -literal
|
||||
``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,
|
||||
aes192-cbc,aes256-cbc''
|
||||
.Ed
|
||||
.It Cm Compression
|
||||
Specifies whether to use compression.
|
||||
The argument must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.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 default level is 6, which is good for most applications.
|
||||
The meaning of the values is the same as in
|
||||
.Xr gzip 1 .
|
||||
Note that this option applies to protocol version 1 only.
|
||||
.It Cm ConnectionAttempts
|
||||
Specifies the number of tries (one per second) to make before falling
|
||||
back to rsh or exiting.
|
||||
The argument must be an integer.
|
||||
This may be useful in scripts if the connection sometimes fails.
|
||||
.It Cm DSAAuthentication
|
||||
Specifies whether to try DSA authentication.
|
||||
The argument to this keyword must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
DSA authentication will only be
|
||||
attempted if a DSA identity file exists.
|
||||
Note that this option applies to protocol version 2 only.
|
||||
The default is 4.
|
||||
.It Cm EscapeChar
|
||||
Sets the escape character (default:
|
||||
.Ql ~ ) .
|
||||
@ -696,6 +748,8 @@ The argument must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm ForwardAgent
|
||||
Specifies whether the connection to the authentication agent (if any)
|
||||
will be forwarded to the remote machine.
|
||||
@ -726,8 +780,37 @@ or
|
||||
The default is
|
||||
.Dq no .
|
||||
.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 .
|
||||
.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
|
||||
Specifies the real host name to log into.
|
||||
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
|
||||
specifications).
|
||||
.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
|
||||
.Pa $HOME/.ssh/identity
|
||||
in the user's home directory).
|
||||
@ -747,16 +830,6 @@ syntax to refer to a user's home directory.
|
||||
It is possible to have
|
||||
multiple identity files specified in configuration files; all these
|
||||
identities will be tried in sequence.
|
||||
.It Cm IdentityFile2
|
||||
Specifies the file from which the user's DSA authentication identity
|
||||
is read (default
|
||||
.Pa $HOME/.ssh/id_dsa
|
||||
in the user's home directory).
|
||||
The file name may use the tilde
|
||||
syntax to refer to a user's home directory.
|
||||
It is possible to have
|
||||
multiple identity files specified in configuration files; all these
|
||||
identities will be tried in sequence.
|
||||
.It Cm KeepAlive
|
||||
Specifies whether the system should send keepalive messages to the
|
||||
other side.
|
||||
@ -802,6 +875,18 @@ Gives the verbosity level that is used when logging messages from
|
||||
The possible values are:
|
||||
QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
|
||||
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
|
||||
Specifies the number of password prompts before giving up.
|
||||
The argument to this keyword must be an integer.
|
||||
@ -812,10 +897,19 @@ The argument to this keyword must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
Note that this option applies to both protocol version 1 and 2.
|
||||
The default is
|
||||
.Dq yes .
|
||||
.It Cm Port
|
||||
Specifies the port number to connect on the remote host.
|
||||
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
|
||||
Specifies the protocol versions
|
||||
.Nm
|
||||
@ -826,11 +920,11 @@ and
|
||||
.Dq 2 .
|
||||
Multiple versions must be comma-separated.
|
||||
The default is
|
||||
.Dq 1,2 .
|
||||
.Dq 2,1 .
|
||||
This means that
|
||||
.Nm
|
||||
tries version 1 and falls back to version 2
|
||||
if version 1 is not available.
|
||||
tries version 2 and falls back to version 1
|
||||
if version 2 is not available.
|
||||
.It Cm ProxyCommand
|
||||
Specifies the command to use to connect to the server.
|
||||
The command
|
||||
@ -856,6 +950,15 @@ Note that
|
||||
.Cm CheckHostIP
|
||||
is not available for connects with a proxy command.
|
||||
.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
|
||||
Specifies that a TCP/IP port on the remote machine be forwarded over
|
||||
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
|
||||
not used.
|
||||
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
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq yes .
|
||||
This option applies to protocol version 1 only.
|
||||
.It Cm RhostsRSAAuthentication
|
||||
Specifies whether to try rhosts based authentication with RSA host
|
||||
authentication.
|
||||
This is the primary authentication method for most sites.
|
||||
The argument must be
|
||||
.Dq yes
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq yes .
|
||||
This option applies to protocol version 1 only.
|
||||
.It Cm RSAAuthentication
|
||||
Specifies whether to try RSA authentication.
|
||||
The argument to this keyword must be
|
||||
@ -895,9 +1004,12 @@ or
|
||||
RSA authentication will only be
|
||||
attempted if the identity file exists, or an authentication agent is
|
||||
running.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to protocol version 1 only.
|
||||
.It Cm SkeyAuthentication
|
||||
Specifies whether to use
|
||||
.It Cm ChallengeResponseAuthentication
|
||||
Specifies whether to use challenge response authentication.
|
||||
Currently there is only support for
|
||||
.Xr skey 1
|
||||
authentication.
|
||||
The argument to this keyword must be
|
||||
@ -914,24 +1026,37 @@ will never automatically add host keys to the
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
and
|
||||
.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.
|
||||
However, it can be somewhat annoying if you don't have good
|
||||
.Pa /etc/ssh/ssh_known_hosts
|
||||
and
|
||||
.Pa /etc/ssh/ssh_known_hosts2
|
||||
files installed and frequently
|
||||
connect new hosts.
|
||||
Basically this option forces the user to manually
|
||||
add any new hosts.
|
||||
Normally this option is disabled, and new hosts
|
||||
will automatically be added to the known host files.
|
||||
connect to new hosts.
|
||||
This option forces the user to manually
|
||||
add all new hosts.
|
||||
If this flag is set to
|
||||
.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
|
||||
known hosts will be verified automatically in either case.
|
||||
known hosts will be verified automatically in all cases.
|
||||
The argument must be
|
||||
.Dq yes
|
||||
.Dq yes ,
|
||||
.Dq no
|
||||
or
|
||||
.Dq no .
|
||||
.Dq ask .
|
||||
The default is
|
||||
.Dq ask .
|
||||
.It Cm UsePrivilegedPort
|
||||
Specifies whether to use a privileged port for outgoing connections.
|
||||
The argument must be
|
||||
@ -939,21 +1064,27 @@ The argument must be
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that setting this option to
|
||||
.Dq no
|
||||
turns off
|
||||
.Dq no .
|
||||
Note that you need to set this option to
|
||||
.Dq yes
|
||||
if you want to use
|
||||
.Cm RhostsAuthentication
|
||||
and
|
||||
.Cm RhostsRSAAuthentication .
|
||||
.Cm RhostsRSAAuthentication
|
||||
with older servers.
|
||||
.It Cm User
|
||||
Specifies the user to log in as.
|
||||
This can be useful if you have a different user name on different machines.
|
||||
This saves the trouble of
|
||||
having to remember to give the user name on the command line.
|
||||
.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 .
|
||||
.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
|
||||
Specifies that rlogin/rsh should be used for this host.
|
||||
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
|
||||
uses this special value to forward X11 connections over the secure
|
||||
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
|
||||
manually copy any required authorization cookies).
|
||||
.It Ev HOME
|
||||
@ -1018,6 +1151,10 @@ Identifies the client end of the connection.
|
||||
The variable contains
|
||||
three space-separated values: client ip-address, client 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
|
||||
This is set to the name of the tty (path to the device) associated
|
||||
with the current shell or command.
|
||||
@ -1040,14 +1177,18 @@ and adds lines of the format
|
||||
to the environment.
|
||||
.Sh FILES
|
||||
.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
|
||||
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
|
||||
.Xr sshd 8 .
|
||||
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa
|
||||
Contains the RSA and the DSA authentication identity of the user.
|
||||
.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa, $HOME/.ssh/id_rsa
|
||||
Contains the authentication identity of the user.
|
||||
They are for protocol 1 RSA, protocol 2 DSA, and protocol 2 RSA, respectively.
|
||||
These files
|
||||
contain sensitive data and should be readable by the user but not
|
||||
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
|
||||
generating the key; the passphrase will be used to encrypt the
|
||||
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
|
||||
identity file in human-readable form).
|
||||
The contents of the
|
||||
@ -1065,13 +1206,15 @@ The contents of the
|
||||
file should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
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
|
||||
.Pa $HOME/.ssh/id_dsa.pub
|
||||
and
|
||||
.Pa $HOME/.ssh/id_rsa.pub
|
||||
file should be added to
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
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
|
||||
sensitive and can (but need not) be readable by anyone.
|
||||
These files are
|
||||
@ -1098,15 +1241,15 @@ spaces).
|
||||
This file is not highly sensitive, but the recommended
|
||||
permissions are read/write for the user, and not accessible by others.
|
||||
.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
|
||||
permissions are read/write for the user, and not accessible by others.
|
||||
.It Pa /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2
|
||||
Systemwide list of known host keys.
|
||||
.Pa /etc/ssh_known_hosts
|
||||
.Pa /etc/ssh/ssh_known_hosts
|
||||
contains RSA and
|
||||
.Pa /etc/ssh_known_hosts2
|
||||
contains DSA keys.
|
||||
.Pa /etc/ssh/ssh_known_hosts2
|
||||
contains RSA or DSA keys for protocol version 2.
|
||||
These files should be prepared by the
|
||||
system administrator to contain the public host keys of all machines in the
|
||||
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
|
||||
returned by name servers), and then a user name on that host,
|
||||
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,
|
||||
because
|
||||
.Xr sshd 8
|
||||
@ -1218,49 +1361,34 @@ manual page for more information.
|
||||
Contains additional definitions for environment variables, see section
|
||||
.Sx ENVIRONMENT
|
||||
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
|
||||
.Sh AUTHOR
|
||||
OpenSSH
|
||||
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen,
|
||||
but with bugs removed and newer features re-added.
|
||||
Rapidly after the
|
||||
1.2.12 release, newer versions of the original ssh bore successively
|
||||
more restrictive licenses, and thus demand for a free version was born.
|
||||
.Pp
|
||||
This version of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
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 AUTHORS
|
||||
OpenSSH is a derivative of the original and free
|
||||
ssh 1.2.12 release by Tatu Ylonen.
|
||||
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
|
||||
Theo de Raadt and Dug Song
|
||||
removed many bugs, re-added newer features and
|
||||
created OpenSSH.
|
||||
Markus Friedl contributed the support for SSH
|
||||
protocol versions 1.5 and 2.0.
|
||||
.Sh SEE ALSO
|
||||
.Xr rlogin 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr scp 1 ,
|
||||
.Xr sftp 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr telnet 1 ,
|
||||
.Xr sshd 8 ,
|
||||
.Xr ssl 8
|
||||
.Xr sshd 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
|
||||
|
@ -39,26 +39,36 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "readconf.h"
|
||||
#include "uidswap.h"
|
||||
|
||||
#include "ssh1.h"
|
||||
#include "ssh2.h"
|
||||
#include "compat.h"
|
||||
#include "cipher.h"
|
||||
#include "xmalloc.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "uidswap.h"
|
||||
#include "channels.h"
|
||||
#include "key.h"
|
||||
#include "authfd.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;
|
||||
|
||||
@ -71,10 +81,11 @@ int debug_flag = 0;
|
||||
|
||||
/* Flag indicating whether a tty should be allocated */
|
||||
int tty_flag = 0;
|
||||
int no_tty_flag = 0;
|
||||
int force_tty_flag = 0;
|
||||
|
||||
/* don't exec a shell */
|
||||
int no_shell_flag = 0;
|
||||
int no_tty_flag = 0;
|
||||
|
||||
/*
|
||||
* Flag indicating that nothing should be read from stdin. This can be set
|
||||
@ -113,14 +124,11 @@ struct sockaddr_storage hostaddr;
|
||||
*/
|
||||
volatile int received_window_change_signal = 0;
|
||||
|
||||
/* Value of argv[0] (set in the main program). */
|
||||
char *av0;
|
||||
|
||||
/* Flag indicating whether we have a valid host private key loaded. */
|
||||
int host_private_key_loaded = 0;
|
||||
|
||||
/* Host private key. */
|
||||
RSA *host_private_key = NULL;
|
||||
/* Private host keys. */
|
||||
struct {
|
||||
Key **keys;
|
||||
int nkeys;
|
||||
} sensitive_data;
|
||||
|
||||
/* Original real UID. */
|
||||
uid_t original_real_uid;
|
||||
@ -128,23 +136,27 @@ uid_t original_real_uid;
|
||||
/* command to be executed */
|
||||
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. */
|
||||
|
||||
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, " -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 Disable authentication agent forwarding.\n");
|
||||
#ifdef AFS
|
||||
fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n");
|
||||
#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, " -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 Do not allocate a tty.\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, " -c cipher Select encryption algorithm: "
|
||||
"``3des'', "
|
||||
"``blowfish''\n");
|
||||
"``3des'', ``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, " -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, " 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, " -C Enable compression.\n");
|
||||
fprintf(stderr, " -N Do not execute a shell or command.\n");
|
||||
fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
|
||||
fprintf(stderr, " -1 Force protocol version 1.\n");
|
||||
fprintf(stderr, " -2 Force protocol version 2.\n");
|
||||
fprintf(stderr, " -4 Use IPv4 only.\n");
|
||||
fprintf(stderr, " -6 Use IPv6 only.\n");
|
||||
fprintf(stderr, " -2 Force protocol version 2.\n");
|
||||
fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
|
||||
fprintf(stderr, " -s Invoke command (mandatory) as SSH2 subsystem.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -214,8 +228,9 @@ rsh_connect(char *host, char *user, Buffer * command)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int ssh_session(void);
|
||||
int ssh_session2(void);
|
||||
int ssh_session(void);
|
||||
int ssh_session2(void);
|
||||
void load_public_identity_files(void);
|
||||
|
||||
/*
|
||||
* Main program for the ssh client.
|
||||
@ -227,7 +242,7 @@ main(int ac, char **av)
|
||||
u_short fwd_port, fwd_host_port;
|
||||
char *optarg, *cp, buf[256];
|
||||
struct stat st;
|
||||
struct passwd *pw, pwcopy;
|
||||
struct passwd *pw;
|
||||
int dummy;
|
||||
uid_t original_effective_uid;
|
||||
|
||||
@ -245,6 +260,15 @@ main(int ac, char **av)
|
||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
@ -262,24 +286,12 @@ main(int ac, char **av)
|
||||
*/
|
||||
umask(022);
|
||||
|
||||
/* Save our own name. */
|
||||
av0 = av[0];
|
||||
|
||||
/* Initialize option structure to indicate that no values have been set. */
|
||||
initialize_options(&options);
|
||||
|
||||
/* Parse command-line arguments. */
|
||||
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++) {
|
||||
if (av[optind][0] != '-') {
|
||||
if (host)
|
||||
@ -297,7 +309,7 @@ main(int ac, char **av)
|
||||
opt = av[optind][1];
|
||||
if (!opt)
|
||||
usage();
|
||||
if (strchr("eilcpLRo", opt)) { /* options with arguments */
|
||||
if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
|
||||
optarg = av[optind] + 2;
|
||||
if (strcmp(optarg, "") == 0) {
|
||||
if (optind >= ac - 1)
|
||||
@ -310,6 +322,9 @@ main(int ac, char **av)
|
||||
optarg = NULL;
|
||||
}
|
||||
switch (opt) {
|
||||
case '1':
|
||||
options.protocol = SSH_PROTO_1;
|
||||
break;
|
||||
case '2':
|
||||
options.protocol = SSH_PROTO_2;
|
||||
break;
|
||||
@ -354,16 +369,17 @@ main(int ac, char **av)
|
||||
case 'i':
|
||||
if (stat(optarg, &st) < 0) {
|
||||
fprintf(stderr, "Warning: Identity file %s does not exist.\n",
|
||||
optarg);
|
||||
optarg);
|
||||
break;
|
||||
}
|
||||
if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
|
||||
fatal("Too many identity files specified (max %d)",
|
||||
SSH_MAX_IDENTITY_FILES);
|
||||
options.identity_files[options.num_identity_files++] =
|
||||
xstrdup(optarg);
|
||||
SSH_MAX_IDENTITY_FILES);
|
||||
options.identity_files[options.num_identity_files++] = xstrdup(optarg);
|
||||
break;
|
||||
case 't':
|
||||
if (tty_flag)
|
||||
force_tty_flag = 1;
|
||||
tty_flag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
@ -374,15 +390,16 @@ main(int ac, char **av)
|
||||
options.log_level++;
|
||||
break;
|
||||
} else {
|
||||
fatal("Too high debugging level.\n");
|
||||
fatal("Too high debugging level.");
|
||||
}
|
||||
/* fallthrough */
|
||||
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,
|
||||
PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1,
|
||||
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2);
|
||||
fprintf(stderr, "Compiled with SSL (0x%8.8lx).\n", SSLeay());
|
||||
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2,
|
||||
SSLeay());
|
||||
if (opt == 'V')
|
||||
exit(0);
|
||||
break;
|
||||
@ -391,10 +408,10 @@ main(int ac, char **av)
|
||||
break;
|
||||
case 'e':
|
||||
if (optarg[0] == '^' && optarg[2] == 0 &&
|
||||
(unsigned char) optarg[1] >= 64 && (unsigned char) optarg[1] < 128)
|
||||
options.escape_char = (unsigned char) optarg[1] & 31;
|
||||
(u_char) optarg[1] >= 64 && (u_char) optarg[1] < 128)
|
||||
options.escape_char = (u_char) optarg[1] & 31;
|
||||
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)
|
||||
options.escape_char = -2;
|
||||
else {
|
||||
@ -409,16 +426,34 @@ main(int ac, char **av)
|
||||
options.cipher = SSH_CIPHER_ILLEGAL;
|
||||
} else {
|
||||
/* SSH1 only */
|
||||
Cipher *c = cipher_by_name(optarg);
|
||||
if (c == NULL || c->number < 0) {
|
||||
options.cipher = cipher_number(optarg);
|
||||
if (options.cipher == -1) {
|
||||
fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
|
||||
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;
|
||||
case 'p':
|
||||
options.port = atoi(optarg);
|
||||
options.port = a2port(optarg);
|
||||
if (options.port == 0) {
|
||||
fprintf(stderr, "Bad port '%s'\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
options.user = optarg;
|
||||
@ -445,6 +480,16 @@ main(int ac, char **av)
|
||||
}
|
||||
add_local_forward(&options, fwd_port, buf, fwd_host_port);
|
||||
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':
|
||||
options.compression = 1;
|
||||
break;
|
||||
@ -461,6 +506,9 @@ main(int ac, char **av)
|
||||
"command-line", 0, &dummy) != 0)
|
||||
exit(1);
|
||||
break;
|
||||
case 's':
|
||||
subsystem_flag = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
@ -471,6 +519,7 @@ main(int ac, char **av)
|
||||
usage();
|
||||
|
||||
SSLeay_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
|
||||
/* Initialize the command to execute on remote host. */
|
||||
buffer_init(&command);
|
||||
@ -483,6 +532,10 @@ main(int ac, char **av)
|
||||
if (optind == ac) {
|
||||
/* No command specified - execute shell on a tty. */
|
||||
tty_flag = 1;
|
||||
if (subsystem_flag) {
|
||||
fprintf(stderr, "You must specify a subsystem to invoke.\n");
|
||||
usage();
|
||||
}
|
||||
} else {
|
||||
/* A command has been specified. Store it into the
|
||||
buffer. */
|
||||
@ -501,65 +554,35 @@ main(int ac, char **av)
|
||||
if (buffer_len(&command) == 0)
|
||||
tty_flag = 1;
|
||||
|
||||
/* Do not allocate a tty if stdin is not a 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 */
|
||||
/* Force no tty*/
|
||||
if (no_tty_flag)
|
||||
tty_flag = 0;
|
||||
|
||||
/* Get user data. */
|
||||
pw = getpwuid(original_real_uid);
|
||||
if (!pw) {
|
||||
fprintf(stderr, "You don't exist, go away!\n");
|
||||
exit(1);
|
||||
/* Do not allocate a tty if stdin is not a tty. */
|
||||
if (!isatty(fileno(stdin)) && !force_tty_flag) {
|
||||
if (tty_flag)
|
||||
log("Pseudo-terminal will not be allocated because stdin is not a terminal.");
|
||||
tty_flag = 0;
|
||||
}
|
||||
/* 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. */
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
||||
/*
|
||||
* Initialize "log" output. Since we are the client all output
|
||||
* 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. */
|
||||
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 systemwide configuration file. */
|
||||
read_config_file(HOST_CONFIG_FILE, host, &options);
|
||||
read_config_file(_PATH_HOST_CONFIG_FILE, host, &options);
|
||||
|
||||
/* Fill configuration defaults. */
|
||||
fill_default_options(&options);
|
||||
|
||||
/* reinit */
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
|
||||
|
||||
/* check if RSA support exists */
|
||||
if ((options.protocol & SSH_PROTO_1) &&
|
||||
rsa_alive() == 0) {
|
||||
log("%s: no RSA support in libssl and libcrypto. See ssl(8).",
|
||||
__progname);
|
||||
log("Disabling protocol version 1");
|
||||
options.protocol &= ~ (SSH_PROTO_1|SSH_PROTO_1_PREFERRED);
|
||||
}
|
||||
if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) {
|
||||
fprintf(stderr, "%s: No protocol version available.\n",
|
||||
__progname);
|
||||
exit(1);
|
||||
}
|
||||
log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1);
|
||||
|
||||
if (options.user == NULL)
|
||||
options.user = xstrdup(pw->pw_name);
|
||||
@ -585,8 +608,9 @@ main(int ac, char **av)
|
||||
}
|
||||
/* Disable rhosts authentication if not running as root. */
|
||||
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_rsa_authentication = 0;
|
||||
}
|
||||
/*
|
||||
* If using rsh has been selected, exec it now (without trying
|
||||
@ -600,7 +624,7 @@ main(int ac, char **av)
|
||||
restore_uid();
|
||||
|
||||
/* Switch to the original uid permanently. */
|
||||
permanently_set_uid(original_real_uid);
|
||||
permanently_set_uid(pw);
|
||||
|
||||
/* Execute rsh. */
|
||||
rsh_connect(host, options.user, &command);
|
||||
@ -609,17 +633,12 @@ main(int ac, char **av)
|
||||
/* Restore our superuser privileges. */
|
||||
restore_uid();
|
||||
|
||||
/*
|
||||
* Open a connection to the remote host. This needs root privileges
|
||||
* if rhosts_{rsa_}authentication is enabled.
|
||||
*/
|
||||
/* Open a connection to the remote host. */
|
||||
|
||||
ok = ssh_connect(host, &hostaddr, options.port,
|
||||
options.connection_attempts,
|
||||
!options.rhosts_authentication &&
|
||||
!options.rhosts_rsa_authentication,
|
||||
original_real_uid,
|
||||
options.proxy_command);
|
||||
options.connection_attempts,
|
||||
original_effective_uid != 0 || !options.use_privileged_port,
|
||||
pw, options.proxy_command);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* privileges, because the file is only readable by root.
|
||||
*/
|
||||
if (ok && (options.protocol & SSH_PROTO_1)) {
|
||||
Key k;
|
||||
host_private_key = RSA_new();
|
||||
k.type = KEY_RSA;
|
||||
k.rsa = host_private_key;
|
||||
if (load_private_key(HOST_KEY_FILE, "", &k, NULL))
|
||||
host_private_key_loaded = 1;
|
||||
sensitive_data.nkeys = 0;
|
||||
sensitive_data.keys = NULL;
|
||||
if (ok && (options.rhosts_rsa_authentication ||
|
||||
options.hostbased_authentication)) {
|
||||
sensitive_data.nkeys = 3;
|
||||
sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key));
|
||||
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
|
||||
@ -650,13 +674,13 @@ main(int ac, char **av)
|
||||
* process, read the private hostkey and impersonate the host.
|
||||
* 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
|
||||
* 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 (mkdir(buf, 0700) < 0)
|
||||
error("Could not create directory '%.200s'.", buf);
|
||||
@ -677,31 +701,36 @@ main(int ac, char **av)
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
/* Expand ~ in options.identity_files. */
|
||||
/* XXX mem-leaks */
|
||||
for (i = 0; i < options.num_identity_files; i++)
|
||||
options.identity_files[i] =
|
||||
tilde_expand_filename(options.identity_files[i], original_real_uid);
|
||||
for (i = 0; i < options.num_identity_files2; i++)
|
||||
options.identity_files2[i] =
|
||||
tilde_expand_filename(options.identity_files2[i], original_real_uid);
|
||||
/* load options.identity_files */
|
||||
load_public_identity_files();
|
||||
|
||||
/* Expand ~ in known host file names. */
|
||||
options.system_hostfile = tilde_expand_filename(options.system_hostfile,
|
||||
original_real_uid);
|
||||
options.user_hostfile = tilde_expand_filename(options.user_hostfile,
|
||||
original_real_uid);
|
||||
options.system_hostfile2 = tilde_expand_filename(options.system_hostfile2,
|
||||
original_real_uid);
|
||||
options.user_hostfile2 = tilde_expand_filename(options.user_hostfile2,
|
||||
original_real_uid);
|
||||
/* XXX mem-leaks: */
|
||||
options.system_hostfile =
|
||||
tilde_expand_filename(options.system_hostfile, original_real_uid);
|
||||
options.user_hostfile =
|
||||
tilde_expand_filename(options.user_hostfile, original_real_uid);
|
||||
options.system_hostfile2 =
|
||||
tilde_expand_filename(options.system_hostfile2, original_real_uid);
|
||||
options.user_hostfile2 =
|
||||
tilde_expand_filename(options.user_hostfile2, original_real_uid);
|
||||
|
||||
/* Log into the remote system. This never returns if the login fails. */
|
||||
ssh_login(host_private_key_loaded, host_private_key,
|
||||
host, (struct sockaddr *)&hostaddr, original_real_uid);
|
||||
ssh_login(sensitive_data.keys, sensitive_data.nkeys,
|
||||
host, (struct sockaddr *)&hostaddr, pw);
|
||||
|
||||
/* We no longer need the host private key. Clear it now. */
|
||||
if (host_private_key_loaded)
|
||||
RSA_free(host_private_key); /* Destroys contents safely */
|
||||
/* We no longer need the private host keys. Clear them now. */
|
||||
if (sensitive_data.nkeys != 0) {
|
||||
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();
|
||||
packet_close();
|
||||
@ -717,7 +746,7 @@ x11_get_proto(char *proto, int proto_len, char *data, int data_len)
|
||||
|
||||
if (options.xauth_location) {
|
||||
/* 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"));
|
||||
f = popen(line, "r");
|
||||
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
|
||||
ssh_session(void)
|
||||
{
|
||||
int type;
|
||||
int i;
|
||||
int plen;
|
||||
int interactive = 0;
|
||||
int have_tty = 0;
|
||||
struct winsize ws;
|
||||
int authfd;
|
||||
char *cp;
|
||||
|
||||
/* Enable compression if requested. */
|
||||
@ -802,7 +876,7 @@ ssh_session(void)
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
|
||||
/* 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. */
|
||||
packet_send();
|
||||
@ -838,16 +912,11 @@ ssh_session(void)
|
||||
}
|
||||
}
|
||||
/* Tell the packet module whether this is an interactive session. */
|
||||
packet_set_interactive(interactive, options.keepalives);
|
||||
|
||||
/* 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);
|
||||
packet_set_interactive(interactive);
|
||||
|
||||
/* Request authentication agent forwarding if appropriate. */
|
||||
check_agent_present();
|
||||
|
||||
if (options.forward_agent) {
|
||||
debug("Requesting authentication agent forwarding.");
|
||||
auth_request_forwarding();
|
||||
@ -858,28 +927,9 @@ ssh_session(void)
|
||||
if (type != SSH_SMSG_SUCCESS)
|
||||
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. */
|
||||
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);
|
||||
}
|
||||
/* Initiate port forwardings. */
|
||||
ssh_init_forwarding();
|
||||
|
||||
/* If requested, let ssh continue in the background. */
|
||||
if (fork_after_authentication_flag)
|
||||
@ -911,32 +961,28 @@ ssh_session(void)
|
||||
}
|
||||
|
||||
void
|
||||
init_local_fwd(void)
|
||||
client_subsystem_reply(int type, int plen, void *ctxt)
|
||||
{
|
||||
int i;
|
||||
/* Initiate local TCP/IP port forwardings. */
|
||||
for (i = 0; i < options.num_local_forwards; i++) {
|
||||
debug("Connections to local port %d forwarded to remote address %.200s:%d",
|
||||
options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port);
|
||||
channel_request_local_forwarding(options.local_forwards[i].port,
|
||||
options.local_forwards[i].host,
|
||||
options.local_forwards[i].host_port,
|
||||
options.gateway_ports);
|
||||
}
|
||||
int id, len;
|
||||
|
||||
id = packet_get_int();
|
||||
len = buffer_len(&command);
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
packet_done();
|
||||
if (type == SSH2_MSG_CHANNEL_FAILURE)
|
||||
fatal("Request for subsystem '%.*s' failed on channel %d",
|
||||
len, buffer_ptr(&command), id);
|
||||
}
|
||||
|
||||
extern void client_set_session_ident(int id);
|
||||
|
||||
void
|
||||
client_init(int id, void *arg)
|
||||
ssh_session2_callback(int id, void *arg)
|
||||
{
|
||||
int len;
|
||||
debug("client_init id %d arg %d", id, (int)arg);
|
||||
int interactive = 0;
|
||||
struct termios tio;
|
||||
|
||||
if (no_shell_flag)
|
||||
goto done;
|
||||
debug("client_init id %d arg %ld", id, (long)arg);
|
||||
|
||||
if (tty_flag) {
|
||||
struct winsize ws;
|
||||
@ -954,8 +1000,10 @@ client_init(int id, void *arg)
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_put_cstring(""); /* XXX: encode terminal modes */
|
||||
tio = get_saved_tio();
|
||||
tty_make_modes(/*ignored*/ 0, &tio);
|
||||
packet_send();
|
||||
interactive = 1;
|
||||
/* XXX wait for reply */
|
||||
}
|
||||
if (options.forward_x11 &&
|
||||
@ -966,34 +1014,51 @@ client_init(int id, void *arg)
|
||||
/* Request forwarding with authentication spoofing. */
|
||||
debug("Requesting X11 forwarding with authentication spoofing.");
|
||||
x11_request_forwarding_with_spoofing(id, proto, data);
|
||||
interactive = 1;
|
||||
/* 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);
|
||||
if (len > 0) {
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
debug("Sending command: %.*s", len, buffer_ptr(&command));
|
||||
channel_request_start(id, "exec", 0);
|
||||
packet_put_string(buffer_ptr(&command), len);
|
||||
if (subsystem_flag) {
|
||||
debug("Sending subsystem: %.*s", len, buffer_ptr(&command));
|
||||
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();
|
||||
} else {
|
||||
channel_request(id, "shell", 0);
|
||||
}
|
||||
/* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */
|
||||
done:
|
||||
|
||||
/* register different callback, etc. XXX */
|
||||
client_set_session_ident(id);
|
||||
packet_set_interactive(interactive);
|
||||
}
|
||||
|
||||
int
|
||||
ssh_session2(void)
|
||||
ssh_session2_command(void)
|
||||
{
|
||||
int window, packetmax, id;
|
||||
int id, window, packetmax;
|
||||
int in, out, err;
|
||||
|
||||
if (stdin_null_flag) {
|
||||
in = open("/dev/null", O_RDONLY);
|
||||
in = open(_PATH_DEVNULL, O_RDONLY);
|
||||
} else {
|
||||
in = dup(STDIN_FILENO);
|
||||
}
|
||||
@ -1011,14 +1076,6 @@ ssh_session2(void)
|
||||
if (!isatty(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;
|
||||
packetmax = CHAN_SES_PACKET_DEFAULT;
|
||||
if (!tty_flag) {
|
||||
@ -1030,8 +1087,48 @@ ssh_session2(void)
|
||||
window, packetmax, CHAN_EXTENDED_WRITE,
|
||||
xstrdup("client-session"), /*nonblock*/0);
|
||||
|
||||
debug("channel_new: %d", 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,6 @@
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
*
|
||||
* Generic header file for ssh.
|
||||
*
|
||||
* 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
|
||||
@ -12,15 +10,12 @@
|
||||
* 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 $"); */
|
||||
/* $FreeBSD$ */
|
||||
/* RCSID("$OpenBSD: ssh.h,v 1.62 2001/01/23 10:45:10 markus Exp $"); */
|
||||
/* RCSID("$FreeBSD$"); */
|
||||
|
||||
#ifndef SSH_H
|
||||
#define SSH_H
|
||||
|
||||
#include "rsa.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/* Cipher used for encrypting authentication files. */
|
||||
#define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES
|
||||
|
||||
@ -56,95 +51,6 @@
|
||||
*/
|
||||
#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
|
||||
* authentication socket.
|
||||
@ -152,10 +58,14 @@
|
||||
#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
|
||||
|
||||
/*
|
||||
* Default path to ssh-askpass used by ssh-add,
|
||||
* environment variable for overwriting the default location
|
||||
* Name of the environment variable containing the pathname of the
|
||||
* 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"
|
||||
|
||||
/*
|
||||
@ -173,361 +83,9 @@
|
||||
/* Name of Kerberos service for SSH to use. */
|
||||
#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! */
|
||||
#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
|
||||
#include "auth-pam.h"
|
||||
#endif /* USE_PAM */
|
||||
|
@ -2,7 +2,12 @@
|
||||
# defaults for users, and the values can be changed in per-user configuration
|
||||
# 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:
|
||||
# 1. command line options
|
||||
@ -15,9 +20,9 @@
|
||||
# Site-wide defaults for various options
|
||||
|
||||
# Host *
|
||||
# ForwardAgent yes
|
||||
# ForwardX11 yes
|
||||
# RhostsAuthentication yes
|
||||
# ForwardAgent no
|
||||
# ForwardX11 no
|
||||
# RhostsAuthentication no
|
||||
# RhostsRSAAuthentication yes
|
||||
# RSAAuthentication yes
|
||||
# PasswordAuthentication yes
|
||||
@ -25,8 +30,10 @@
|
||||
# UseRsh no
|
||||
# BatchMode no
|
||||
# CheckHostIP yes
|
||||
# StrictHostKeyChecking no
|
||||
# StrictHostKeyChecking yes
|
||||
# IdentityFile ~/.ssh/identity
|
||||
# IdentityFile ~/.ssh/id_dsa
|
||||
# IdentityFile ~/.ssh/id_rsa
|
||||
# Port 22
|
||||
# Protocol 2,1
|
||||
# Cipher blowfish
|
||||
|
@ -13,24 +13,25 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
#include "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "uidswap.h"
|
||||
#include "compat.h"
|
||||
#include "readconf.h"
|
||||
#include "key.h"
|
||||
#include "sshconnect.h"
|
||||
#include "hostfile.h"
|
||||
#include "log.h"
|
||||
#include "readconf.h"
|
||||
#include "atomicio.h"
|
||||
#include "misc.h"
|
||||
|
||||
char *client_version_string = NULL;
|
||||
char *server_version_string = NULL;
|
||||
@ -38,11 +39,14 @@ char *server_version_string = NULL;
|
||||
extern Options options;
|
||||
extern char *__progname;
|
||||
|
||||
/* AF_UNSPEC or AF_INET or AF_INET6 */
|
||||
extern int IPv4or6;
|
||||
|
||||
/*
|
||||
* Connect to the given ssh server using a proxy command.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
Buffer command;
|
||||
@ -93,7 +97,7 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
|
||||
char *argv[10];
|
||||
|
||||
/* Child. Permanently give up superuser privileges. */
|
||||
permanently_set_uid(original_real_uid);
|
||||
permanently_set_uid(pw);
|
||||
|
||||
/* Redirect stdin and stdout. */
|
||||
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
|
||||
printed on the user's terminal. */
|
||||
argv[0] = "/bin/sh";
|
||||
argv[0] = _PATH_BSHELL;
|
||||
argv[1] = "-c";
|
||||
argv[2] = command_string;
|
||||
argv[3] = NULL;
|
||||
|
||||
/* Execute the proxy command. Note that we gave up any
|
||||
extra privileges above. */
|
||||
execv("/bin/sh", argv);
|
||||
perror("/bin/sh");
|
||||
execv(argv[0], argv);
|
||||
perror(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
/* 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.
|
||||
*/
|
||||
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;
|
||||
|
||||
@ -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
|
||||
* the user's uid to create the socket.
|
||||
*/
|
||||
temporarily_use_uid(original_real_uid);
|
||||
temporarily_use_uid(pw);
|
||||
sock = socket(family, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
error("socket: %.100s", strerror(errno));
|
||||
@ -185,15 +189,16 @@ ssh_create_socket(uid_t original_real_uid, int privileged, int family)
|
||||
int
|
||||
ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
u_short port, int connection_attempts,
|
||||
int anonymous, uid_t original_real_uid,
|
||||
int anonymous, struct passwd *pw,
|
||||
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 on = 1;
|
||||
int sock = -1, attempt;
|
||||
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
|
||||
struct addrinfo hints, *ai, *aitop;
|
||||
struct linger linger;
|
||||
struct servent *sp;
|
||||
|
||||
debug("ssh_connect: getuid %u geteuid %u anon %d",
|
||||
(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 (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. */
|
||||
|
||||
@ -244,8 +249,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
host, ntop, strport);
|
||||
|
||||
/* Create a socket for connecting. */
|
||||
sock = ssh_create_socket(original_real_uid,
|
||||
!anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
|
||||
sock = ssh_create_socket(pw,
|
||||
!anonymous && geteuid() == 0,
|
||||
ai->ai_family);
|
||||
if (sock < 0)
|
||||
continue;
|
||||
@ -254,10 +259,10 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
* hope that it will help with tcp_wrappers showing
|
||||
* 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) {
|
||||
/* Successful connection. */
|
||||
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
|
||||
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
|
||||
restore_uid();
|
||||
break;
|
||||
} else {
|
||||
@ -295,7 +300,13 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
/* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
|
||||
linger.l_onoff = 1;
|
||||
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. */
|
||||
packet_set_connection(sock, sock);
|
||||
@ -308,12 +319,13 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
|
||||
* identification string.
|
||||
*/
|
||||
void
|
||||
ssh_exchange_identification()
|
||||
ssh_exchange_identification(void)
|
||||
{
|
||||
char buf[256], remote_version[256]; /* must be same size! */
|
||||
int remote_major, remote_minor, i, mismatch;
|
||||
int connection_in = packet_get_connection_in();
|
||||
int connection_out = packet_get_connection_out();
|
||||
int minor1 = PROTOCOL_MINOR_1;
|
||||
|
||||
/* Read other side\'s version identification. */
|
||||
for (;;) {
|
||||
@ -367,9 +379,10 @@ ssh_exchange_identification()
|
||||
}
|
||||
if (remote_minor < 3) {
|
||||
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. */
|
||||
enable_compat13();
|
||||
minor1 = 3;
|
||||
if (options.forward_agent) {
|
||||
log("Agent forwarding disabled for protocol 1.3");
|
||||
options.forward_agent = 0;
|
||||
@ -395,7 +408,7 @@ ssh_exchange_identification()
|
||||
/* Send our own protocol version identification. */
|
||||
snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
|
||||
compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
|
||||
compat20 ? PROTOCOL_MINOR_2 : PROTOCOL_MINOR_1,
|
||||
compat20 ? PROTOCOL_MINOR_2 : minor1,
|
||||
SSH_VERSION);
|
||||
if (atomicio(write, connection_out, buf, strlen(buf)) != strlen(buf))
|
||||
fatal("write: %.100s", strerror(errno));
|
||||
@ -405,6 +418,7 @@ ssh_exchange_identification()
|
||||
debug("Local version string %.100s", client_version_string);
|
||||
}
|
||||
|
||||
/* defaults to 'no' */
|
||||
int
|
||||
read_yes_or_no(const char *prompt, int defval)
|
||||
{
|
||||
@ -412,10 +426,13 @@ read_yes_or_no(const char *prompt, int defval)
|
||||
FILE *f;
|
||||
int retval = -1;
|
||||
|
||||
if (isatty(0))
|
||||
if (options.batch_mode)
|
||||
return 0;
|
||||
|
||||
if (isatty(STDIN_FILENO))
|
||||
f = stdin;
|
||||
else
|
||||
f = fopen("/dev/tty", "rw");
|
||||
f = fopen(_PATH_TTY, "rw");
|
||||
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
@ -461,11 +478,13 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||
Key *file_key;
|
||||
char *type = key_type(host_key);
|
||||
char *ip = NULL;
|
||||
char hostline[1000], *hostp;
|
||||
char hostline[1000], *hostp, *fp;
|
||||
HostStatus host_status;
|
||||
HostStatus ip_status;
|
||||
int local = 0, host_ip_differ = 0;
|
||||
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
|
||||
@ -487,23 +506,40 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||
local = 0;
|
||||
break;
|
||||
}
|
||||
if (local) {
|
||||
debug("Forcing accepting of host key for loopback/localhost.");
|
||||
if (local && options.host_key_alias == NULL) {
|
||||
debug("Forcing accepting of host key for "
|
||||
"loopback/localhost.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off check_host_ip for proxy connects, since
|
||||
* we don't have the remote ip-address
|
||||
* We don't have the remote ip-address for connections
|
||||
* using a proxy command
|
||||
*/
|
||||
if (options.proxy_command != NULL && options.check_host_ip)
|
||||
options.check_host_ip = 0;
|
||||
|
||||
if (options.check_host_ip) {
|
||||
if (options.proxy_command == NULL) {
|
||||
if (getnameinfo(hostaddr, hostaddr->sa_len, ntop, sizeof(ntop),
|
||||
NULL, 0, NI_NUMERICHOST) != 0)
|
||||
fatal("check_host_key: getnameinfo failed");
|
||||
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
|
||||
* hosts or in the systemwide list.
|
||||
*/
|
||||
host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key);
|
||||
if (host_status == HOST_NEW)
|
||||
host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key);
|
||||
host_file = user_hostfile;
|
||||
host_status = check_host_in_hostfile(host_file, host, host_key, file_key, &host_line);
|
||||
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
|
||||
* 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);
|
||||
ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key);
|
||||
|
||||
if (ip_status == HOST_NEW)
|
||||
ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key);
|
||||
ip_file = user_hostfile;
|
||||
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 &&
|
||||
(ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
|
||||
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. */
|
||||
debug("Host '%.200s' is known and matches the %s host key.",
|
||||
host, type);
|
||||
if (options.check_host_ip) {
|
||||
if (ip_status == HOST_NEW) {
|
||||
if (!add_host_to_hostfile(user_hostfile, ip, host_key))
|
||||
log("Failed to add the %s host key for IP address '%.30s' to the list of known hosts (%.30s).",
|
||||
type, ip, user_hostfile);
|
||||
else
|
||||
log("Warning: Permanently added the %s host key for IP address '%.30s' to the list of known hosts.",
|
||||
type, ip);
|
||||
} else if (ip_status != HOST_OK)
|
||||
log("Warning: the %s host key for '%.200s' differs from the key for the IP address '%.30s'",
|
||||
type, host, ip);
|
||||
debug("Found key in %s:%d", host_file, host_line);
|
||||
if (options.check_host_ip && ip_status == HOST_NEW) {
|
||||
if (!add_host_to_hostfile(user_hostfile, ip, host_key))
|
||||
log("Failed to add the %s host key for IP address '%.128s' to the list of known hosts (%.30s).",
|
||||
type, ip, user_hostfile);
|
||||
else
|
||||
log("Warning: Permanently added the %s host key for IP address '%.128s' to the list of known hosts.",
|
||||
type, ip);
|
||||
}
|
||||
break;
|
||||
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) {
|
||||
/* The default */
|
||||
char prompt[1024];
|
||||
char *fp = key_fingerprint(host_key);
|
||||
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
|
||||
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"
|
||||
"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))
|
||||
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);
|
||||
hostp = hostline;
|
||||
} 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("%s. This could either mean that", msg);
|
||||
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. */
|
||||
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
|
||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
||||
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
|
||||
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
|
||||
error("It is also possible that the %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("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
|
||||
@ -638,6 +685,14 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||
error("Agent forwarding is disabled to avoid trojan horses.");
|
||||
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.
|
||||
* 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;
|
||||
}
|
||||
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
|
||||
@ -857,17 +929,12 @@ send_krb5_tgt(krb5_context context, krb5_auth_context auth_context)
|
||||
* This function does not require super-user privileges.
|
||||
*/
|
||||
void
|
||||
ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost,
|
||||
struct sockaddr *hostaddr, uid_t original_real_uid)
|
||||
ssh_login(Key **keys, int nkeys, const char *orighost,
|
||||
struct sockaddr *hostaddr, struct passwd *pw)
|
||||
{
|
||||
struct passwd *pw;
|
||||
char *host, *cp;
|
||||
char *server_user, *local_user;
|
||||
|
||||
/* Get local user name. Use it as server user if no user name was given. */
|
||||
pw = getpwuid(original_real_uid);
|
||||
if (!pw)
|
||||
fatal("User id %u not found from user database.", original_real_uid);
|
||||
local_user = xstrdup(pw->pw_name);
|
||||
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 */
|
||||
if (compat20) {
|
||||
ssh_kex2(host, hostaddr);
|
||||
ssh_userauth2(server_user, host);
|
||||
ssh_userauth2(local_user, server_user, host, keys, nkeys);
|
||||
} else {
|
||||
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;
|
||||
char *padded;
|
||||
|
||||
if (datafellows & SSH_BUG_PASSWORDPAD) {
|
||||
packet_put_string(password, strlen(password));
|
||||
return;
|
||||
}
|
||||
size = roundup(strlen(password) + 1, 32);
|
||||
padded = xmalloc(size);
|
||||
memset(padded, 0, size);
|
||||
|
@ -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.
|
||||
*
|
||||
@ -20,23 +23,33 @@
|
||||
* 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef 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
|
||||
check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||
const char *user_hostfile, const char *system_hostfile);
|
||||
|
||||
void ssh_kex(char *host, struct sockaddr *hostaddr);
|
||||
void
|
||||
ssh_userauth(const char* local_user, const char* server_user, char *host,
|
||||
int host_key_valid, RSA *own_host_key);
|
||||
|
||||
void ssh_kex2(char *host, struct sockaddr *hostaddr);
|
||||
void ssh_userauth2(const char *server_user, char *host);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -13,30 +13,41 @@
|
||||
*/
|
||||
|
||||
#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$");
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/rsa.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 "rsa.h"
|
||||
#include "ssh.h"
|
||||
#include "buffer.h"
|
||||
#include "packet.h"
|
||||
#include "mpaux.h"
|
||||
#include "uidswap.h"
|
||||
#include "log.h"
|
||||
#include "readconf.h"
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "sshconnect.h"
|
||||
#include "authfile.h"
|
||||
#include "readpass.h"
|
||||
#include "cipher.h"
|
||||
#include "canohost.h"
|
||||
|
||||
/* Session id for the current session. */
|
||||
unsigned char session_id[16];
|
||||
unsigned int supported_authentications = 0;
|
||||
u_char session_id[16];
|
||||
u_int supported_authentications = 0;
|
||||
|
||||
extern Options options;
|
||||
extern char *__progname;
|
||||
@ -46,13 +57,13 @@ extern char *__progname;
|
||||
* authenticate using the agent.
|
||||
*/
|
||||
int
|
||||
try_agent_authentication()
|
||||
try_agent_authentication(void)
|
||||
{
|
||||
int type;
|
||||
char *comment;
|
||||
AuthenticationConnection *auth;
|
||||
unsigned char response[16];
|
||||
unsigned int i;
|
||||
u_char response[16];
|
||||
u_int i;
|
||||
int plen, clen;
|
||||
Key *key;
|
||||
BIGNUM *challenge;
|
||||
@ -63,7 +74,6 @@ try_agent_authentication()
|
||||
return 0;
|
||||
|
||||
challenge = BN_new();
|
||||
key = key_new(KEY_RSA);
|
||||
|
||||
/* Loop through identities served by the agent. */
|
||||
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. */
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
ssh_close_authentication_connection(auth);
|
||||
BN_clear_free(challenge);
|
||||
debug("RSA authentication accepted by server.");
|
||||
return 1;
|
||||
@ -135,6 +146,7 @@ try_agent_authentication()
|
||||
packet_disconnect("Protocol error waiting RSA auth response: %d",
|
||||
type);
|
||||
}
|
||||
ssh_close_authentication_connection(auth);
|
||||
BN_clear_free(challenge);
|
||||
debug("RSA authentication using agent refused.");
|
||||
return 0;
|
||||
@ -147,7 +159,7 @@ try_agent_authentication()
|
||||
void
|
||||
respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv)
|
||||
{
|
||||
unsigned char buf[32], response[16];
|
||||
u_char buf[32], response[16];
|
||||
MD5_CTX md;
|
||||
int i, len;
|
||||
|
||||
@ -200,9 +212,9 @@ try_rsa_authentication(const char *authfile)
|
||||
int plen, clen;
|
||||
|
||||
/* Try to load identification for the authentication key. */
|
||||
public = key_new(KEY_RSA);
|
||||
if (!load_public_key(authfile, public, &comment)) {
|
||||
key_free(public);
|
||||
/* XXKEYLOAD */
|
||||
public = key_load_public_type(KEY_RSA1, authfile, &comment);
|
||||
if (public == NULL) {
|
||||
/* Could not load it. Fail. */
|
||||
return 0;
|
||||
}
|
||||
@ -241,12 +253,12 @@ try_rsa_authentication(const char *authfile)
|
||||
|
||||
debug("Received RSA challenge from server.");
|
||||
|
||||
private = key_new(KEY_RSA);
|
||||
/*
|
||||
* Load the private key. Try first with empty passphrase; if it
|
||||
* fails, ask for a passphrase.
|
||||
*/
|
||||
if (!load_private_key(authfile, "", private, NULL)) {
|
||||
private = key_load_private_type(KEY_RSA1, authfile, "", NULL);
|
||||
if (private == NULL) {
|
||||
char buf[300];
|
||||
snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
|
||||
comment);
|
||||
@ -259,7 +271,8 @@ try_rsa_authentication(const char *authfile)
|
||||
}
|
||||
|
||||
/* 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));
|
||||
xfree(passphrase);
|
||||
error("Bad passphrase.");
|
||||
@ -274,6 +287,7 @@ try_rsa_authentication(const char *authfile)
|
||||
/* Expect the server to reject it... */
|
||||
packet_read_expect(&plen, SSH_SMSG_FAILURE);
|
||||
xfree(comment);
|
||||
BN_clear_free(challenge);
|
||||
return 0;
|
||||
}
|
||||
/* Destroy the passphrase. */
|
||||
@ -309,7 +323,7 @@ try_rsa_authentication(const char *authfile)
|
||||
* authentication and RSA host authentication.
|
||||
*/
|
||||
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;
|
||||
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. */
|
||||
packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
|
||||
packet_put_string(local_user, strlen(local_user));
|
||||
packet_put_int(BN_num_bits(host_key->n));
|
||||
packet_put_bignum(host_key->e);
|
||||
packet_put_bignum(host_key->n);
|
||||
packet_put_int(BN_num_bits(host_key->rsa->n));
|
||||
packet_put_bignum(host_key->rsa->e);
|
||||
packet_put_bignum(host_key->rsa->n);
|
||||
packet_send();
|
||||
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.");
|
||||
|
||||
/* 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. */
|
||||
BN_clear_free(challenge);
|
||||
@ -367,7 +381,7 @@ try_rhosts_rsa_authentication(const char *local_user, RSA * host_key)
|
||||
|
||||
#ifdef KRB4
|
||||
int
|
||||
try_krb4_authentication()
|
||||
try_krb4_authentication(void)
|
||||
{
|
||||
KTEXT_ST auth; /* Kerberos data */
|
||||
char *reply;
|
||||
@ -386,11 +400,11 @@ try_krb4_authentication()
|
||||
if (stat(tkt_string(), &st) < 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) {
|
||||
debug("Kerberos V4: no realm for %s", get_canonical_hostname());
|
||||
debug("Kerberos V4: no realm for %s", get_canonical_hostname(1));
|
||||
return 0;
|
||||
}
|
||||
/* This can really be anything. */
|
||||
@ -445,7 +459,7 @@ try_krb4_authentication()
|
||||
debug("Kerberos V4 authentication accepted.");
|
||||
|
||||
/* 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);
|
||||
xfree(reply);
|
||||
|
||||
@ -484,7 +498,7 @@ try_krb4_authentication()
|
||||
|
||||
#ifdef AFS
|
||||
int
|
||||
send_krb4_tgt()
|
||||
send_krb4_tgt(void)
|
||||
{
|
||||
CREDENTIALS *creds;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
creds_to_radix(creds, (unsigned char *)buffer, sizeof buffer);
|
||||
creds_to_radix(creds, (u_char *)buffer, sizeof buffer);
|
||||
xfree(creds);
|
||||
|
||||
packet_start(SSH_CMSG_HAVE_KRB4_TGT);
|
||||
@ -549,10 +563,10 @@ send_afs_tokens(void)
|
||||
p = buf;
|
||||
|
||||
/* 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)
|
||||
break;
|
||||
p += sizeof(unsigned int);
|
||||
p += sizeof(u_int);
|
||||
memcpy(creds.ticket_st.dat, p, creds.ticket_st.length);
|
||||
p += creds.ticket_st.length;
|
||||
|
||||
@ -578,7 +592,7 @@ send_afs_tokens(void)
|
||||
creds.pinst[0] = '\0';
|
||||
|
||||
/* 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;
|
||||
packet_start(SSH_CMSG_HAVE_AFS_TOKEN);
|
||||
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.
|
||||
*/
|
||||
int
|
||||
try_skey_authentication()
|
||||
try_challenge_reponse_authentication(void)
|
||||
{
|
||||
int type, i;
|
||||
int payload_len;
|
||||
unsigned int clen;
|
||||
u_int clen;
|
||||
char prompt[1024];
|
||||
char *challenge, *response;
|
||||
|
||||
debug("Doing skey authentication.");
|
||||
debug("Doing challenge reponse authentication.");
|
||||
|
||||
/* request a challenge */
|
||||
packet_start(SSH_CMSG_AUTH_TIS);
|
||||
@ -636,9 +651,36 @@ try_skey_authentication()
|
||||
xfree(challenge);
|
||||
fflush(stderr);
|
||||
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)
|
||||
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);
|
||||
ssh_put_password(response);
|
||||
memset(response, 0, strlen(response));
|
||||
@ -650,7 +692,7 @@ try_skey_authentication()
|
||||
return 1;
|
||||
if (type != SSH_SMSG_FAILURE)
|
||||
packet_disconnect("Protocol error: got %d in response "
|
||||
"to skey-auth-reponse", type);
|
||||
"to SSH_CMSG_AUTH_TIS_RESPONSE", type);
|
||||
}
|
||||
/* failure */
|
||||
return 0;
|
||||
@ -702,10 +744,10 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
|
||||
Key k;
|
||||
int bits, rbits;
|
||||
int ssh_cipher_default = SSH_CIPHER_3DES;
|
||||
unsigned char session_key[SSH_SESSION_KEY_LENGTH];
|
||||
unsigned char cookie[8];
|
||||
unsigned int supported_ciphers;
|
||||
unsigned int server_flags, client_flags;
|
||||
u_char session_key[SSH_SESSION_KEY_LENGTH];
|
||||
u_char cookie[8];
|
||||
u_int supported_ciphers;
|
||||
u_int server_flags, client_flags;
|
||||
int payload_len, clen, sum_len = 0;
|
||||
u_int32_t rand = 0;
|
||||
|
||||
@ -764,7 +806,7 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
|
||||
packet_integrity_check(payload_len,
|
||||
8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4,
|
||||
SSH_SMSG_PUBLIC_KEY);
|
||||
k.type = KEY_RSA;
|
||||
k.type = KEY_RSA1;
|
||||
k.rsa = host_key;
|
||||
check_host_key(host, hostaddr, &k,
|
||||
options.user_hostfile, options.system_hostfile);
|
||||
@ -837,13 +879,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
|
||||
RSA_free(public_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.",
|
||||
cipher_name(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. */
|
||||
if (!(supported_ciphers & (1 << options.cipher)))
|
||||
@ -892,17 +935,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
|
||||
* Authenticate user
|
||||
*/
|
||||
void
|
||||
ssh_userauth(
|
||||
const char* local_user,
|
||||
const char* server_user,
|
||||
char *host,
|
||||
int host_key_valid, RSA *own_host_key)
|
||||
ssh_userauth1(const char *local_user, const char *server_user, char *host,
|
||||
Key **keys, int nkeys)
|
||||
{
|
||||
int i, type;
|
||||
int payload_len;
|
||||
|
||||
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. */
|
||||
packet_start(SSH_CMSG_USER);
|
||||
@ -1011,9 +1051,12 @@ ssh_userauth(
|
||||
* authentication.
|
||||
*/
|
||||
if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) &&
|
||||
options.rhosts_rsa_authentication && host_key_valid) {
|
||||
if (try_rhosts_rsa_authentication(local_user, own_host_key))
|
||||
return;
|
||||
options.rhosts_rsa_authentication) {
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
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. */
|
||||
if ((supported_authentications & (1 << SSH_AUTH_RSA)) &&
|
||||
@ -1028,13 +1071,15 @@ ssh_userauth(
|
||||
|
||||
/* Try RSA authentication for each identity. */
|
||||
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;
|
||||
}
|
||||
/* Try skey authentication if the server supports it. */
|
||||
/* Try challenge response authentication if the server supports it. */
|
||||
if ((supported_authentications & (1 << SSH_AUTH_TIS)) &&
|
||||
options.skey_authentication && !options.batch_mode) {
|
||||
if (try_skey_authentication())
|
||||
options.challenge_reponse_authentication && !options.batch_mode) {
|
||||
if (try_challenge_reponse_authentication())
|
||||
return;
|
||||
}
|
||||
/* Try password authentication if the server supports it. */
|
||||
@ -1042,7 +1087,7 @@ ssh_userauth(
|
||||
options.password_authentication && !options.batch_mode) {
|
||||
char prompt[80];
|
||||
|
||||
snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
|
||||
snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
|
||||
server_user, host);
|
||||
if (try_password_authentication(prompt))
|
||||
return;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,9 +10,9 @@
|
||||
.\" incompatible with the protocol description in the RFC file, it must be
|
||||
.\" called by a name other than "ssh" or "Secure Shell".
|
||||
.\"
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
|
||||
.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
|
||||
.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
|
||||
.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" 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
|
||||
.\" 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$
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
@ -41,10 +42,10 @@
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sshd
|
||||
.Nd secure shell daemon
|
||||
.Nd OpenSSH SSH daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm sshd
|
||||
.Op Fl diqQ46
|
||||
.Op Fl deiqD46
|
||||
.Op Fl b Ar bits
|
||||
.Op Fl f Ar config_file
|
||||
.Op Fl g Ar login_grace_time
|
||||
@ -55,7 +56,7 @@
|
||||
.Op Fl V Ar client_protocol_id
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
(Secure Shell Daemon) is the daemon program for
|
||||
(SSH Daemon) is the daemon program for
|
||||
.Xr ssh 1 .
|
||||
Together these programs replace rlogin and rsh, and
|
||||
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.
|
||||
Forward security is provided through a Diffie-Hellman key agreement.
|
||||
This key agreement results in a shared session key.
|
||||
The rest of the session is encrypted
|
||||
using a symmetric cipher, currently
|
||||
Blowfish, 3DES or CAST128 in CBC mode or Arcfour.
|
||||
.Pp
|
||||
The rest of the session is encrypted using a symmetric cipher, currently
|
||||
128 bit AES, Blowfish, 3DES, CAST128, Arcfour, 192 bit AES, or 256 bit AES.
|
||||
The client selects the encryption algorithm
|
||||
to use from those offered by the server.
|
||||
Additionally, session integrity is provided
|
||||
@ -145,8 +146,9 @@ through a cryptographic message authentication code
|
||||
(hmac-sha1 or hmac-md5).
|
||||
.Pp
|
||||
Protocol version 2 provides a public key based
|
||||
user authentication method (DSAAuthentication)
|
||||
and conventional password authentication.
|
||||
user (PubkeyAuthentication) or
|
||||
client host (HostbasedAuthentication) authentication method,
|
||||
conventional password authentication and challenge response based methods.
|
||||
.Pp
|
||||
.Ss Command execution and data forwarding
|
||||
.Pp
|
||||
@ -175,12 +177,15 @@ configuration file.
|
||||
.Pp
|
||||
.Nm
|
||||
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
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.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
|
||||
.It Fl d
|
||||
Debug mode.
|
||||
@ -188,8 +193,12 @@ The server sends verbose debug output to the system
|
||||
log, and does not put itself in the background.
|
||||
The server also will not fork and will only process one connection.
|
||||
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.
|
||||
.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
|
||||
Specifies the name of the configuration file.
|
||||
The default is
|
||||
@ -198,17 +207,19 @@ The default is
|
||||
refuses to start if there is no configuration file.
|
||||
.It Fl g Ar login_grace_time
|
||||
Gives the grace time for clients to authenticate themselves (default
|
||||
300 seconds).
|
||||
600 seconds).
|
||||
If the client fails to authenticate the user within
|
||||
this many seconds, the server disconnects and exits.
|
||||
A value of zero indicates no limit.
|
||||
.It Fl h Ar host_key_file
|
||||
Specifies the file from which the RSA host key is read (default
|
||||
Specifies the file from which the host key is read (default
|
||||
.Pa /etc/ssh/ssh_host_key ) .
|
||||
This option must be given if
|
||||
.Nm
|
||||
is not run as root (as the normal
|
||||
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
|
||||
Specifies that
|
||||
.Nm
|
||||
@ -223,8 +234,8 @@ However, with small key sizes (e.g., 512) using
|
||||
from inetd may
|
||||
be feasible.
|
||||
.It Fl k Ar key_gen_time
|
||||
Specifies how often the server key is regenerated (default 3600
|
||||
seconds, or one hour).
|
||||
Specifies how often the ephemeral protocol version 1 server key is
|
||||
regenerated (default 3600 seconds, or one hour).
|
||||
The motivation for regenerating the key fairly
|
||||
often is that the key is not stored anywhere, and after about an hour,
|
||||
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
|
||||
.Pa utmp
|
||||
file.
|
||||
.It Fl Q
|
||||
Do not print an error message if RSA support is missing.
|
||||
.It Fl V Ar client_protocol_id
|
||||
SSH-2 compatibility mode.
|
||||
.It Fl D
|
||||
When this option is specified
|
||||
.Nm
|
||||
assumes the client has sent the supplied version string
|
||||
and skips the
|
||||
Protocol Version Identification Exchange.
|
||||
This option is not intended to be called directly.
|
||||
will not detach and does not become a daemon.
|
||||
This allows easy monitoring of
|
||||
.Nm sshd .
|
||||
.It Fl 4
|
||||
Forces
|
||||
.Nm
|
||||
@ -293,17 +300,17 @@ Specifies whether an AFS token may be forwarded to the server.
|
||||
Default is
|
||||
.Dq yes .
|
||||
.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.
|
||||
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 \&*
|
||||
and
|
||||
.Ql ?
|
||||
can be used as
|
||||
wildcards in the patterns.
|
||||
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
|
||||
.It Cm AllowTcpForwarding
|
||||
Specifies whether TCP forwarding is permitted.
|
||||
@ -314,7 +321,7 @@ users are also denied shell access, as they can always install their
|
||||
own forwarders.
|
||||
.Pp
|
||||
.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.
|
||||
If specified, login is allowed only for users names that
|
||||
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.
|
||||
By default login is allowed regardless of the user name.
|
||||
.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
|
||||
Specifies the ciphers allowed for protocol version 2.
|
||||
Multiple ciphers must be comma-separated.
|
||||
The default is
|
||||
.Dq 3des-cbc,blowfish-cbc,arcfour,cast128-cbc .
|
||||
.Dq aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour.
|
||||
.It Cm CheckMail
|
||||
Specifies whether
|
||||
.Nm
|
||||
should check for new mail for interactive logins.
|
||||
The default is
|
||||
.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
|
||||
This keyword can be followed by a number of group names, separated
|
||||
by spaces.
|
||||
Users whose primary group matches one of the patterns
|
||||
aren't allowed to log in.
|
||||
Users whose primary group or supplementary group list matches
|
||||
one of the patterns aren't allowed to log in.
|
||||
.Ql \&*
|
||||
and
|
||||
.Ql ?
|
||||
can be used as
|
||||
wildcards in the patterns.
|
||||
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
|
||||
.It Cm DenyUsers
|
||||
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.
|
||||
Only user names are valid; a numerical user ID isn't recognized.
|
||||
By default login is allowed regardless of the user name.
|
||||
.It Cm DSAAuthentication
|
||||
Specifies whether DSA authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to protocol version 2 only.
|
||||
.It Cm GatewayPorts
|
||||
Specifies whether remote hosts are allowed to connect to ports
|
||||
forwarded for the client.
|
||||
@ -374,26 +423,40 @@ or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm HostDSAKey
|
||||
Specifies the file containing the private DSA host key (default
|
||||
.Pa /etc/ssh/ssh_host_dsa_key )
|
||||
used by SSH protocol 2.0.
|
||||
Note that
|
||||
.Nm
|
||||
disables protocol 2.0 if this file is group/world-accessible.
|
||||
.It Cm HostbasedAuthentication
|
||||
Specifies whether rhosts or /etc/hosts.equiv authentication together
|
||||
with successful public key client host authentication is allowed
|
||||
(hostbased authentication).
|
||||
This option is similar to
|
||||
.Cm RhostsRSAAuthentication
|
||||
and applies to protocol version 2 only.
|
||||
The default is
|
||||
.Dq no .
|
||||
.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 )
|
||||
used by SSH protocols 1.3 and 1.5.
|
||||
used by SSH protocol versions 1 and 2.
|
||||
Note that
|
||||
.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
|
||||
Specifies that
|
||||
.Pa .rhosts
|
||||
and
|
||||
.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
|
||||
and
|
||||
.Pa /etc/ssh/shosts.equiv
|
||||
@ -406,7 +469,9 @@ Specifies whether
|
||||
should ignore the user's
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
during
|
||||
.Cm RhostsRSAAuthentication .
|
||||
.Cm RhostsRSAAuthentication
|
||||
or
|
||||
.Cm HostbasedAuthentication .
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm KeepAlive
|
||||
@ -459,8 +524,8 @@ file on logout.
|
||||
Default is
|
||||
.Dq yes .
|
||||
.It Cm KeyRegenerationInterval
|
||||
The server key is automatically regenerated after this many seconds
|
||||
(if it has been used).
|
||||
In protocol version 1, the ephemeral server key is automatically regenerated
|
||||
after this many seconds (if it has been used).
|
||||
The purpose of regeneration is to prevent
|
||||
decrypting captured sessions by later breaking into the machine and
|
||||
stealing the keys.
|
||||
@ -468,14 +533,42 @@ The key is never stored anywhere.
|
||||
If the value is 0, the key is never regenerated.
|
||||
The default is 3600 (seconds).
|
||||
.It Cm ListenAddress
|
||||
Specifies what local address
|
||||
Specifies the local addresses
|
||||
.Nm
|
||||
should listen on.
|
||||
The default is to listen to all local addresses.
|
||||
Multiple options of this type are permitted.
|
||||
Additionally, the
|
||||
.Cm Ports
|
||||
options must precede this option.
|
||||
The following forms may be used:
|
||||
.Pp
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
.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
|
||||
The server disconnects after this time if the user has not
|
||||
successfully logged in.
|
||||
@ -489,6 +582,17 @@ QUIET, FATAL, ERROR, INFO, VERBOSE and DEBUG.
|
||||
The default is INFO.
|
||||
Logging with level DEBUG violates the privacy of users
|
||||
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
|
||||
Specifies the maximum number of concurrent unauthenticated connections to the
|
||||
.Nm
|
||||
@ -503,14 +607,14 @@ the three colon separated values
|
||||
.Dq start:rate:full
|
||||
(e.g., "10:30:60").
|
||||
.Nm
|
||||
will refuse connection attempts with a probabillity of
|
||||
will refuse connection attempts with a probability of
|
||||
.Dq rate/100
|
||||
(30%)
|
||||
if there are currently
|
||||
.Dq start
|
||||
(10)
|
||||
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
|
||||
.Dq full
|
||||
(60).
|
||||
@ -518,32 +622,40 @@ are refused if the number of unauthenticated connections reaches
|
||||
Specifies whether password authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to both protocol versions 1 and 2.
|
||||
.It Cm PermitEmptyPasswords
|
||||
When password authentication is allowed, it specifies whether the
|
||||
server allows login to accounts with empty password strings.
|
||||
The default is
|
||||
.Dq no .
|
||||
.It Cm PermitRootLogin
|
||||
Specifies whether the root can log in using
|
||||
Specifies whether root can login using
|
||||
.Xr ssh 1 .
|
||||
The argument must be
|
||||
.Dq yes ,
|
||||
.Dq without-password
|
||||
.Dq without-password ,
|
||||
.Dq forced-commands-only
|
||||
or
|
||||
.Dq no .
|
||||
The default is
|
||||
.Dq no .
|
||||
If this options is set to
|
||||
.Dq without-password
|
||||
only password authentication is disabled for root.
|
||||
.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
|
||||
option has been
|
||||
specified will be allowed regardless of the value of this setting
|
||||
option has been specified
|
||||
(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
|
||||
Specifies the file that contains the process identifier of the
|
||||
.Nm
|
||||
@ -556,6 +668,14 @@ Specifies the port number that
|
||||
listens on.
|
||||
The default is 22.
|
||||
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
|
||||
Specifies whether
|
||||
.Nm
|
||||
@ -577,10 +697,20 @@ and
|
||||
.Dq 2 .
|
||||
Multiple versions must be comma-separated.
|
||||
The default is
|
||||
.Dq 1 .
|
||||
.It Cm RandomSeed
|
||||
Obsolete - accepted and ignored with a warning.
|
||||
Random number generation uses other techniques.
|
||||
.Dq 2,1 .
|
||||
.It Cm PubkeyAuthentication
|
||||
Specifies whether public key authentication is allowed.
|
||||
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
|
||||
Specifies whether authentication using rhosts or
|
||||
.Pa /etc/hosts.equiv
|
||||
@ -594,6 +724,7 @@ to normal rhosts or
|
||||
authentication.
|
||||
The default is
|
||||
.Dq no .
|
||||
This option applies to protocol version 1 only.
|
||||
.It Cm RhostsRSAAuthentication
|
||||
Specifies whether rhosts or
|
||||
.Pa /etc/hosts.equiv
|
||||
@ -601,13 +732,14 @@ authentication together
|
||||
with successful RSA host authentication is allowed.
|
||||
The default is
|
||||
.Dq no .
|
||||
This option applies to protocol version 1 only.
|
||||
.It Cm RSAAuthentication
|
||||
Specifies whether pure RSA authentication is allowed.
|
||||
The default is
|
||||
.Dq yes .
|
||||
Note that this option applies to protocol version 1 only.
|
||||
This option applies to protocol version 1 only.
|
||||
.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.
|
||||
.It Cm SkeyAuthentication
|
||||
Specifies whether
|
||||
@ -725,29 +857,41 @@ Runs user's shell or command.
|
||||
The
|
||||
.Pa $HOME/.ssh/authorized_keys
|
||||
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
|
||||
.Pa $HOME/.ssh/authorized_keys2
|
||||
file lists the DSA keys that are
|
||||
permitted for DSA authentication in SSH protocol 2.0.
|
||||
file lists the DSA and RSA keys that are
|
||||
permitted for public key authentication (PubkeyAuthentication)
|
||||
in protocol version 2.
|
||||
.Pp
|
||||
Each line of the file contains one
|
||||
key (empty lines and lines starting with a
|
||||
.Ql #
|
||||
are ignored as
|
||||
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.
|
||||
The options field
|
||||
is optional; its presence is determined by whether the line starts
|
||||
Each protocol version 2 public key consists of:
|
||||
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).
|
||||
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
|
||||
user to identify the key).
|
||||
For protocol version 2 the keytype is
|
||||
.Dq ssh-dss
|
||||
or
|
||||
.Dq ssh-rsa .
|
||||
.Pp
|
||||
Note that lines in this file are usually several hundred bytes long
|
||||
(because of the size of the RSA key modulus).
|
||||
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.
|
||||
.Pp
|
||||
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 is run on a pty if the connection requests a pty;
|
||||
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.
|
||||
This option might be useful
|
||||
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.
|
||||
.It Cm no-pty
|
||||
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
|
||||
.Ss Examples
|
||||
.Bd -literal
|
||||
1024 33 12121...312314325 ylo@foo.bar
|
||||
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
|
||||
.Ed
|
||||
1024 33 12121.\|.\|.\|312314325 ylo@foo.bar
|
||||
.Pp
|
||||
from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula
|
||||
.Pp
|
||||
command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi
|
||||
.Pp
|
||||
permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23.\|.\|.\|2323
|
||||
.Sh SSH_KNOWN_HOSTS FILE FORMAT
|
||||
The
|
||||
.Pa /etc/ssh/ssh_known_hosts ,
|
||||
@ -869,7 +1027,8 @@ or by taking
|
||||
and adding the host names at the front.
|
||||
.Ss Examples
|
||||
.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
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
@ -878,23 +1037,25 @@ Contains configuration data for
|
||||
.Nm sshd .
|
||||
This file should be writable by root only, but it is recommended
|
||||
(though not necessary) that it be world-readable.
|
||||
.It Pa /etc/ssh/ssh_host_key
|
||||
Contains the private part of the host key.
|
||||
This file should only be owned by root, readable only by root, and not
|
||||
.It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key
|
||||
These three files contain the private parts of the host keys.
|
||||
These files should only be owned by root, readable only by root, and not
|
||||
accessible to others.
|
||||
Note that
|
||||
.Nm
|
||||
does not start if this file is group/world-accessible.
|
||||
.It Pa /etc/ssh/ssh_host_key.pub
|
||||
Contains the public part of the host key.
|
||||
This file should be world-readable but writable only by
|
||||
.It Pa /etc/ssh/ssh_host_key.pub, /etc/ssh/ssh_host_dsa_key.pub, /etc/ssh/ssh_host_rsa_key.pub
|
||||
These three files contain the public parts of the host keys.
|
||||
These files should be world-readable but writable only by
|
||||
root.
|
||||
Its contents should match the private part.
|
||||
This file is not
|
||||
really used for anything; it is only provided for the convenience of
|
||||
the user so its contents can be copied to known hosts files.
|
||||
These two files are created using
|
||||
Their contents should match the respective private parts.
|
||||
These files are not
|
||||
really used for anything; they are provided for the convenience of
|
||||
the user so their contents can be copied to known hosts files.
|
||||
These files are created using
|
||||
.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
|
||||
Contains the process ID of the
|
||||
.Nm
|
||||
@ -914,7 +1075,7 @@ Users will place the contents of their
|
||||
files into this file, as described in
|
||||
.Xr ssh-keygen 1 .
|
||||
.It Pa $HOME/.ssh/authorized_keys2
|
||||
Lists the DSA keys that can be used to log into the user's account.
|
||||
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
|
||||
it being world-readable if the user's home directory resides on an NFS
|
||||
volume).
|
||||
@ -922,6 +1083,8 @@ It is recommended that it not be accessible by others.
|
||||
The format of this file is described above.
|
||||
Users will place the contents of their
|
||||
.Pa id_dsa.pub
|
||||
and/or
|
||||
.Pa id_rsa.pub
|
||||
files into this file, as described in
|
||||
.Xr ssh-keygen 1 .
|
||||
.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.
|
||||
The key must be listed in one of these files to be accepted.
|
||||
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.
|
||||
.Pa /etc/ssh/ssh_known_hosts
|
||||
should be world-readable, and
|
||||
.Pa $HOME/.ssh/known_hosts
|
||||
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
|
||||
If this file exists,
|
||||
.Nm
|
||||
@ -1037,7 +1211,7 @@ This file will probably contain some initialization code followed by
|
||||
something similar to:
|
||||
.Bd -literal -offset indent
|
||||
if [ -n "$DISPLAY" ] && read proto cookie; then
|
||||
echo add $DISPLAY $proto $cookie | xauth -q -
|
||||
echo add "$DISPLAY" "$proto" "$cookie" | xauth -q -
|
||||
fi
|
||||
.Ed
|
||||
.Pp
|
||||
@ -1057,45 +1231,42 @@ This can be used to specify
|
||||
machine-specific login-time initializations globally.
|
||||
This file should be writable only by root, and should be world-readable.
|
||||
.El
|
||||
.Sh AUTHOR
|
||||
OpenSSH
|
||||
is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen,
|
||||
but with bugs removed and newer features re-added.
|
||||
Rapidly after the
|
||||
1.2.12 release, newer versions of the original ssh bore successively
|
||||
more restrictive licenses, and thus demand for a free version was born.
|
||||
.Pp
|
||||
This version of OpenSSH
|
||||
.Bl -bullet
|
||||
.It
|
||||
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 AUTHORS
|
||||
OpenSSH is a derivative of the original and free
|
||||
ssh 1.2.12 release by Tatu Ylonen.
|
||||
Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos,
|
||||
Theo de Raadt and Dug Song
|
||||
removed many bugs, re-added newer features and
|
||||
created OpenSSH.
|
||||
Markus Friedl contributed the support for SSH
|
||||
protocol versions 1.5 and 2.0.
|
||||
.Sh SEE ALSO
|
||||
.Xr scp 1 ,
|
||||
.Xr sftp 1 ,
|
||||
.Xr sftp-server 8 ,
|
||||
.Xr ssh 1 ,
|
||||
.Xr ssh-add 1 ,
|
||||
.Xr ssh-agent 1 ,
|
||||
.Xr ssh-keygen 1 ,
|
||||
.Xr ssl 8 ,
|
||||
.Xr rlogin 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
@ -1,13 +1,16 @@
|
||||
# This is ssh server systemwide configuration file.
|
||||
#
|
||||
# $FreeBSD$
|
||||
# $OpenBSD: sshd_config,v 1.38 2001/04/15 21:41:29 deraadt Exp $
|
||||
# $FreeBSD$
|
||||
|
||||
# This is the sshd server system-wide configuration file. See sshd(8)
|
||||
# for more information.
|
||||
|
||||
Port 22
|
||||
#Protocol 2,1
|
||||
#ListenAddress 0.0.0.0
|
||||
#ListenAddress ::
|
||||
HostKey /etc/ssh/ssh_host_key
|
||||
HostDsaKey /etc/ssh/ssh_host_dsa_key
|
||||
HostKey /etc/ssh_host_key
|
||||
HostKey /etc/ssh_host_rsa_key
|
||||
HostKey /etc/ssh_host_dsa_key
|
||||
ServerKeyBits 768
|
||||
LoginGraceTime 120
|
||||
KeyRegenerationInterval 3600
|
||||
@ -25,6 +28,7 @@ StrictModes yes
|
||||
X11Forwarding yes
|
||||
X11DisplayOffset 10
|
||||
PrintMotd yes
|
||||
#PrintLastLog no
|
||||
KeepAlive yes
|
||||
|
||||
# Logging
|
||||
@ -36,15 +40,17 @@ RhostsAuthentication no
|
||||
#
|
||||
# For this to work you will also need host keys in /etc/ssh_known_hosts
|
||||
RhostsRSAAuthentication no
|
||||
# similar for protocol version 2
|
||||
HostbasedAuthentication no
|
||||
#
|
||||
RSAAuthentication yes
|
||||
|
||||
# To disable tunneled clear text passwords, change to no here!
|
||||
PasswordAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
|
||||
# Uncomment to disable s/key passwords
|
||||
#SkeyAuthentication no
|
||||
#KbdInteractiveAuthentication yes
|
||||
#ChallengeResponseAuthentication no
|
||||
|
||||
# To change Kerberos options
|
||||
#KerberosAuthentication no
|
||||
@ -58,5 +64,8 @@ PermitEmptyPasswords no
|
||||
CheckMail yes
|
||||
#UseLogin no
|
||||
|
||||
# Uncomment if you want to enable sftp
|
||||
#Subsystem sftp /usr/libexec/sftp-server
|
||||
#MaxStartups 10:30:60
|
||||
#Banner /etc/issue.net
|
||||
#ReverseMappingCheck yes
|
||||
|
||||
Subsystem sftp /usr/libexec/sftp-server
|
||||
|
@ -40,8 +40,9 @@
|
||||
|
||||
#include "includes.h"
|
||||
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 "sshlogin.h"
|
||||
#include "log.h"
|
||||
|
@ -13,8 +13,9 @@
|
||||
|
||||
#include "includes.h"
|
||||
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 "log.h"
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/* $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
|
||||
|
||||
#define SSH_VERSION (ssh_version_get())
|
||||
#define SSH_VERSION_BASE "OpenSSH_2.3.0"
|
||||
#define SSH_VERSION_ADDENDUM "green@FreeBSD.org 20010319"
|
||||
#define SSH_VERSION_BASE "OpenSSH_2.9"
|
||||
#define SSH_VERSION_ADDENDUM "green@FreeBSD.org 20010503"
|
||||
|
||||
const char *ssh_version_get(void);
|
||||
void ssh_version_set_addendum(const char *add);
|
||||
|
Loading…
Reference in New Issue
Block a user