diff options
author | green <green@FreeBSD.org> | 2001-05-04 04:14:23 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2001-05-04 04:14:23 +0000 |
commit | 119a11eb6ba03d0462b261cbf754fd7f9403856f (patch) | |
tree | b1b150fe8db4b17e6f78564346bf7ba5b1fbddfb /crypto | |
parent | 08fd06354d1aae8cd1350eb68d9f549e0c4d9037 (diff) | |
download | FreeBSD-src-119a11eb6ba03d0462b261cbf754fd7f9403856f.zip FreeBSD-src-119a11eb6ba03d0462b261cbf754fd7f9403856f.tar.gz |
Fix conflicts for OpenSSH 2.9.
Diffstat (limited to 'crypto')
49 files changed, 5736 insertions, 4374 deletions
diff --git a/crypto/openssh/auth-chall.c b/crypto/openssh/auth-chall.c index f3502f4..a87799b 100644 --- a/crypto/openssh/auth-chall.c +++ b/crypto/openssh/auth-chall.c @@ -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 */ diff --git a/crypto/openssh/auth-krb4.c b/crypto/openssh/auth-krb4.c index 8279a47..bf63720 100644 --- a/crypto/openssh/auth-krb4.c +++ b/crypto/openssh/auth-krb4.c @@ -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]; diff --git a/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c index fdda41c..1ca7fa9 100644 --- a/crypto/openssh/auth-passwd.c +++ b/crypto/openssh/auth-passwd.c @@ -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) { diff --git a/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c index a9dd117..596a7bb 100644 --- a/crypto/openssh/auth-rh-rsa.c +++ b/crypto/openssh/auth-rh-rsa.c @@ -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); diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c index 00d6c90..a7e0625 100644 --- a/crypto/openssh/auth-rsa.c +++ b/crypto/openssh/auth-rsa.c @@ -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 <openssl/rsa.h> +#include <openssl/md5.h> + #include "rsa.h" #include "packet.h" #include "xmalloc.h" -#include "ssh.h" +#include "ssh1.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 "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)) { diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c index 2ab6e66..df945e0 100644 --- a/crypto/openssh/auth.c +++ b/crypto/openssh/auth.c @@ -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; +} diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index 500b73a..cd27684 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -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> /* diff --git a/crypto/openssh/auth1.c b/crypto/openssh/auth1.c index b5d3bd8..db8a463 100644 --- a/crypto/openssh/auth1.c +++ b/crypto/openssh/auth1.c @@ -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,40 +55,36 @@ 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); return buf; } /* - * 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); - - /* 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; + 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); + + 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()); - - /* 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); + pw->pw_name, + get_canonical_hostname(options.reverse_mapping_check)); - 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); } diff --git a/crypto/openssh/auth2.c b/crypto/openssh/auth2.c index 6785fac..5b8ea1a 100644 --- a/crypto/openssh/auth2.c +++ b/crypto/openssh/auth2.c @@ -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 ((style = strchr(user, ':')) != NULL) + *style++ = 0; - if (authctxt->attempt == 1) { + 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"; - } + if (!authctxt->postponed) + userauth_reply(authctxt, authenticated); +} - authlog("%s %s for %.200s from %.200s port %d ssh2", - authmsg, - method, - user, - get_remote_ipaddr(), - get_remote_port()); +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 +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,21 +515,97 @@ 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; } @@ -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); } diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c index db0a4e9..953c852 100644 --- a/crypto/openssh/authfd.c +++ b/crypto/openssh/authfd.c @@ -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) { diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c index a2dc524..298b1ed 100644 --- a/crypto/openssh/authfile.c +++ b/crypto/openssh/authfile.c @@ -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,83 @@ 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; - 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); @@ -240,26 +246,24 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) debug("Read from key file %.200s failed: %.100s", filename, 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); + /* 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 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) != (u_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; + return NULL; } /* Skip cipher type and reserved data. */ (void) buffer_get_char(&buffer); /* cipher type */ @@ -267,36 +271,33 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) /* 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); + 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 1; + return pub; } -/* load public key from private-key file */ -int -load_public_key(const char *filename, Key * key, char **comment_return) +/* load public key from private-key file, works only for SSH v1 */ +Key * +key_load_public_type(int type, const char *filename, char **commentp) { - switch (key->type) { - case KEY_RSA: - return load_public_key_rsa(filename, key->rsa, comment_return); - break; - case KEY_DSA: - default: - break; + 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 0; + return NULL; } /* @@ -306,9 +307,9 @@ load_public_key(const char *filename, Key * key, char **comment_return) * 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) +Key * +key_load_private_rsa1(int fd, const char *filename, const char *passphrase, + char **commentp) { int i, check1, check2, cipher_type; off_t len; @@ -318,6 +319,7 @@ load_private_key_rsa(int fd, const char *filename, Cipher *cipher; BN_CTX *ctx; BIGNUM *aux; + Key *prv = NULL; len = lseek(fd, (off_t) 0, SEEK_END); lseek(fd, (off_t) 0, SEEK_SET); @@ -327,41 +329,43 @@ load_private_key_rsa(int fd, const char *filename, if (read(fd, cp, (size_t) len) != (size_t) len) { debug("Read from key file %.200s failed: %.100s", filename, - strerror(errno)); + strerror(errno)); buffer_free(&buffer); close(fd); - return 0; + 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); + /* 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 0; + close(fd); + 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"); + 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 + } 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 { - /* replace k->dsa with loaded key */ - DSA_free(k->dsa); - k->dsa = dsa; + error("PEM_read_PrivateKey: mismatch or " + "unknown EVP_PKEY save_type %d", pk->save_type); } - BIO_free(in); fclose(fp); - if (comment_return) - *comment_return = xstrdup("dsa w/o comment"); - debug("read DSA private key done"); -#ifdef DEBUG_DSS - DSA_print_fp(stderr, dsa, 8); -#endif - return dsa != NULL ? 1 : 0; + 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]; - - 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; + Key *pub; + char file[MAXPATHLEN]; + + 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; } diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c index 192c0c5..cf8a170 100644 --- a/crypto/openssh/bufaux.c +++ b/crypto/openssh/bufaux.c @@ -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; } /* diff --git a/crypto/openssh/canohost.c b/crypto/openssh/canohost.c index bc6872e..b535444 100644 --- a/crypto/openssh/canohost.c +++ b/crypto/openssh/canohost.c @@ -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,216 +28,246 @@ 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'; + /* + * 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]); + if (!reverse_mapping_check) + 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. + * 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). */ - /* 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; - - 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); - } + 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 * several times. */ 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 IP-address of the remote host as a string. The returned - * string must not be freed. + * Returns the remote IP-address of socket as a string. The returned + * string must be freed. */ - -const char * -get_remote_ipaddr() +char * +get_socket_address(int socket, int remote, int flags) { - static char *canonical_host_ip = NULL; - struct sockaddr_storage from; - socklen_t fromlen; - int socket; + struct sockaddr_storage addr; + socklen_t addrlen; 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; - } - /* 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(); + 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 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"); + /* 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); +} - canonical_host_ip = xstrdup(ntop); +char * +get_peer_ipaddr(int socket) +{ + return get_socket_address(socket, 1, NI_NUMERICHOST); +} - /* Return ip address string. */ - return canonical_host_ip; +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 local host as a string. The returned - * string must be freed. + * Returns the IP-address of the remote host as a string. The returned + * string must not be freed. */ const char * -get_ipaddr(int socket) +get_remote_ipaddr() { 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(); + /* 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 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 canonical_host_ip; +} - /* Return ip address string. */ - return xstrdup(ntop); +const char * +get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check) +{ + 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. */ diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index 1abc940..9671ed3 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -40,25 +40,26 @@ */ #include "includes.h" +RCSID("$OpenBSD: channels.c,v 1.109 2001/04/17 12:55:03 markus Exp $"); RCSID("$FreeBSD$"); -RCSID("$OpenBSD: channels.c,v 1.72 2000/10/27 07:48:22 markus Exp $"); + +#include <openssl/rsa.h> +#include <openssl/dsa.h> #include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" #include "packet.h" #include "xmalloc.h" #include "buffer.h" +#include "bufaux.h" #include "uidswap.h" -#include "readconf.h" -#include "servconf.h" - +#include "log.h" +#include "misc.h" #include "channels.h" #include "nchan.h" #include "compat.h" - -#include "ssh2.h" - -#include <openssl/rsa.h> -#include <openssl/dsa.h> +#include "canohost.h" #include "key.h" #include "authfd.h" @@ -85,7 +86,7 @@ static int channels_alloc = 0; * Maximum file descriptor value used in any of the channels. This is * updated in channel_allocate. */ -static int channel_max_fd_value = 0; +static int channel_max_fd = 0; /* Name and directory of socket for authentication agent forwarding. */ static char *channel_forwarded_auth_socket_name = NULL; @@ -96,14 +97,14 @@ char *x11_saved_proto = NULL; /* Saved X11 authentication data. This is the real data. */ char *x11_saved_data = NULL; -unsigned int x11_saved_data_len = 0; +u_int x11_saved_data_len = 0; /* * Fake X11 authentication data. This is what the server will be sending us; * we should replace any occurrences of this by the real data. */ char *x11_fake_data = NULL; -unsigned int x11_fake_data_len; +u_int x11_fake_data_len; /* * Data structure for storing which hosts are permitted for forward requests. @@ -131,6 +132,11 @@ static int all_opens_permitted = 0; /* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */ static int have_hostname_in_open = 0; +/* AF_UNSPEC or AF_INET or AF_INET6 */ +extern int IPv4or6; + +void port_open_helper(Channel *c, char *rtype); + /* Sets specific protocol options. */ void @@ -139,18 +145,6 @@ channel_set_options(int hostname_in_open) have_hostname_in_open = hostname_in_open; } -/* - * 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. - */ - -void -channel_permit_all_opens() -{ - all_opens_permitted = 1; -} - /* lookup channel by id */ Channel * @@ -179,12 +173,10 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, int extusage, int nonblock) { /* Update the maximum file descriptor value. */ - if (rfd > channel_max_fd_value) - channel_max_fd_value = rfd; - if (wfd > channel_max_fd_value) - channel_max_fd_value = wfd; - if (efd > channel_max_fd_value) - channel_max_fd_value = efd; + channel_max_fd = MAX(channel_max_fd, rfd); + channel_max_fd = MAX(channel_max_fd, wfd); + channel_max_fd = MAX(channel_max_fd, efd); + /* XXX set close-on-exec -markus */ c->rfd = rfd; @@ -195,10 +187,10 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, /* XXX ugly hack: nonblock is only set by the server */ if (nonblock && isatty(c->rfd)) { - debug("channel: %d: rfd %d isatty", c->self, c->rfd); + debug("channel %d: rfd %d isatty", c->self, c->rfd); c->isatty = 1; if (!isatty(c->wfd)) { - error("channel: %d: wfd %d is not a tty?", + error("channel %d: wfd %d is not a tty?", c->self, c->wfd); } } else { @@ -320,9 +312,13 @@ void channel_free(int id) { Channel *c = channel_lookup(id); + char *s = channel_open_message(); + if (c == NULL) packet_disconnect("channel free: bad local channel %d", id); - debug("channel_free: channel %d: status: %s", id, channel_open_message()); + debug("channel_free: channel %d: status: %s", id, s); + xfree(s); + if (c->dettach_user != NULL) { debug("channel_free: channel %d: dettaching channel user", id); c->dettach_user(c->self, NULL); @@ -359,6 +355,13 @@ channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) } void +channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) +{ + debug3("channel %d: waiting for connection", c->self); + FD_SET(c->sock, writeset); +} + +void channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) { if (buffer_len(&c->input) < packet_get_maxsize()) @@ -418,7 +421,7 @@ channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) packet_put_int(c->remote_id); packet_send(); c->type = SSH_CHANNEL_CLOSED; - debug("Closing channel %d after input drain.", c->self); + debug("channel %d: closing after input drain.", c->self); } } @@ -442,15 +445,15 @@ channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) int x11_open_helper(Channel *c) { - unsigned char *ucp; - unsigned int proto_len, data_len; + u_char *ucp; + u_int proto_len, data_len; /* Check if the fixed size part of the packet is in buffer. */ if (buffer_len(&c->output) < 12) return 0; /* Parse the lengths of variable-length fields. */ - ucp = (unsigned char *) buffer_ptr(&c->output); + ucp = (u_char *) buffer_ptr(&c->output); if (ucp[0] == 0x42) { /* Byte order MSB first. */ proto_len = 256 * ucp[6] + ucp[7]; data_len = 256 * ucp[8] + ucp[9]; @@ -510,7 +513,7 @@ channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) * We have received an X11 connection that has bad * authentication information. */ - log("X11 connection rejected because of wrong authentication.\r\n"); + log("X11 connection rejected because of wrong authentication."); buffer_clear(&c->input); buffer_clear(&c->output); close(c->sock); @@ -540,6 +543,116 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) } } +/* try to decode a socks4 header */ +int +channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) +{ + u_char *p, *host; + int len, have, i, found; + char username[256]; + struct { + u_int8_t version; + u_int8_t command; + u_int16_t dest_port; + struct in_addr dest_addr; + } s4_req, s4_rsp; + + debug2("channel %d: decode socks4", c->self); + + have = buffer_len(&c->input); + len = sizeof(s4_req); + if (have < len) + return 0; + p = buffer_ptr(&c->input); + for (found = 0, i = len; i < have; i++) { + if (p[i] == '\0') { + found = 1; + break; + } + if (i > 1024) { + /* the peer is probably sending garbage */ + debug("channel %d: decode socks4: too long", + c->self); + return -1; + } + } + if (!found) + return 0; + buffer_get(&c->input, (char *)&s4_req.version, 1); + buffer_get(&c->input, (char *)&s4_req.command, 1); + buffer_get(&c->input, (char *)&s4_req.dest_port, 2); + buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); + have = buffer_len(&c->input); + p = buffer_ptr(&c->input); + len = strlen(p); + debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); + if (len > have) + fatal("channel %d: decode socks4: len %d > have %d", + c->self, len, have); + strlcpy(username, p, sizeof(username)); + buffer_consume(&c->input, len); + buffer_consume(&c->input, 1); /* trailing '\0' */ + + host = inet_ntoa(s4_req.dest_addr); + strlcpy(c->path, host, sizeof(c->path)); + c->host_port = ntohs(s4_req.dest_port); + + debug("channel %d: dynamic request: socks4 host %s port %u command %u", + c->self, host, c->host_port, s4_req.command); + + if (s4_req.command != 1) { + debug("channel %d: cannot handle: socks4 cn %d", + c->self, s4_req.command); + return -1; + } + s4_rsp.version = 0; /* vn: 0 for reply */ + s4_rsp.command = 90; /* cd: req granted */ + s4_rsp.dest_port = 0; /* ignored */ + s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ + buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); + return 1; +} + +/* dynamic port forwarding */ +void +channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) +{ + u_char *p; + int have, ret; + + have = buffer_len(&c->input); + + debug2("channel %d: pre_dynamic: have %d", c->self, have); + /* buffer_dump(&c->input); */ + /* check if the fixed size part of the packet is in buffer. */ + if (have < 4) { + /* need more */ + FD_SET(c->sock, readset); + return; + } + /* try to guess the protocol */ + p = buffer_ptr(&c->input); + switch (p[0]) { + case 0x04: + ret = channel_decode_socks4(c, readset, writeset); + break; + default: + ret = -1; + break; + } + if (ret < 0) { + channel_free(c->self); + } else if (ret == 0) { + debug2("channel %d: pre_dynamic: need more", c->self); + /* need more */ + FD_SET(c->sock, readset); + } else { + /* switch to the next state */ + c->type = SSH_CHANNEL_OPENING; + port_open_helper(c, "direct-tcpip"); + } +} + /* This is our fake X11 server socket. */ void channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) @@ -547,7 +660,7 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) struct sockaddr addr; int newsock, newch; socklen_t addrlen; - char buf[16384], *remote_hostname; + char buf[16384], *remote_ipaddr; int remote_port; if (FD_ISSET(c->sock, readset)) { @@ -558,10 +671,10 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) error("accept: %.100s", strerror(errno)); return; } - remote_hostname = get_remote_hostname(newsock); + remote_ipaddr = get_peer_ipaddr(newsock); remote_port = get_peer_port(newsock); snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", - remote_hostname, remote_port); + remote_ipaddr, remote_port); newch = channel_new("x11", SSH_CHANNEL_OPENING, newsock, newsock, -1, @@ -573,8 +686,8 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) packet_put_int(newch); packet_put_int(c->local_window_max); packet_put_int(c->local_maxpacket); - /* originator host and port */ - packet_put_cstring(remote_hostname); + /* originator ipaddr and port */ + packet_put_cstring(remote_ipaddr); if (datafellows & SSH_BUG_X11FWD) { debug("ssh2 x11 bug compat mode"); } else { @@ -588,8 +701,58 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) packet_put_string(buf, strlen(buf)); packet_send(); } - xfree(remote_hostname); + xfree(remote_ipaddr); + } +} + +void +port_open_helper(Channel *c, char *rtype) +{ + int direct; + char buf[1024]; + char *remote_ipaddr = get_peer_ipaddr(c->sock); + u_short remote_port = get_peer_port(c->sock); + + direct = (strcmp(rtype, "direct-tcpip") == 0); + + snprintf(buf, sizeof buf, + "%s: listening port %d for %.100s port %d, " + "connect from %.200s port %d", + rtype, c->listening_port, c->path, c->host_port, + remote_ipaddr, remote_port); + + xfree(c->remote_name); + c->remote_name = xstrdup(buf); + + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring(rtype); + packet_put_int(c->self); + packet_put_int(c->local_window_max); + packet_put_int(c->local_maxpacket); + if (direct) { + /* target host, port */ + packet_put_cstring(c->path); + packet_put_int(c->host_port); + } else { + /* listen address, port */ + packet_put_cstring(c->path); + packet_put_int(c->listening_port); + } + /* originator host and port */ + packet_put_cstring(remote_ipaddr); + packet_put_int(remote_port); + packet_send(); + } else { + packet_start(SSH_MSG_PORT_OPEN); + packet_put_int(c->self); + packet_put_cstring(c->path); + packet_put_int(c->host_port); + if (have_hostname_in_open) + packet_put_cstring(c->remote_name); + packet_send(); } + xfree(remote_ipaddr); } /* @@ -598,57 +761,44 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) void channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) { + Channel *nc; struct sockaddr addr; - int newsock, newch; + int newsock, newch, nextstate; socklen_t addrlen; - char buf[1024], *remote_hostname; - int remote_port; + char *rtype; if (FD_ISSET(c->sock, readset)) { debug("Connection to port %d forwarding " "to %.100s port %d requested.", c->listening_port, c->path, c->host_port); + + rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? + "forwarded-tcpip" : "direct-tcpip"; + nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC : + SSH_CHANNEL_OPENING; + addrlen = sizeof(addr); newsock = accept(c->sock, &addr, &addrlen); if (newsock < 0) { error("accept: %.100s", strerror(errno)); return; } - remote_hostname = get_remote_hostname(newsock); - remote_port = get_peer_port(newsock); - snprintf(buf, sizeof buf, - "listen port %d for %.100s port %d, " - "connect from %.200s port %d", - c->listening_port, c->path, c->host_port, - remote_hostname, remote_port); - newch = channel_new("direct-tcpip", - SSH_CHANNEL_OPENING, newsock, newsock, -1, + newch = channel_new(rtype, + nextstate, newsock, newsock, -1, c->local_window_max, c->local_maxpacket, - 0, xstrdup(buf), 1); - if (compat20) { - packet_start(SSH2_MSG_CHANNEL_OPEN); - packet_put_cstring("direct-tcpip"); - packet_put_int(newch); - packet_put_int(c->local_window_max); - packet_put_int(c->local_maxpacket); - /* target host and port */ - packet_put_string(c->path, strlen(c->path)); - packet_put_int(c->host_port); - /* originator host and port */ - packet_put_cstring(remote_hostname); - packet_put_int(remote_port); - packet_send(); - } else { - packet_start(SSH_MSG_PORT_OPEN); - packet_put_int(newch); - packet_put_string(c->path, strlen(c->path)); - packet_put_int(c->host_port); - if (have_hostname_in_open) { - packet_put_string(buf, strlen(buf)); - } - packet_send(); + 0, xstrdup(rtype), 1); + + nc = channel_lookup(newch); + if (nc == NULL) { + error("xxx: no new channel:"); + return; } - xfree(remote_hostname); + nc->listening_port = c->listening_port; + nc->host_port = c->host_port; + strlcpy(nc->path, c->path, sizeof(nc->path)); + + if (nextstate != SSH_CHANNEL_DYNAMIC) + port_open_helper(nc, rtype); } } @@ -670,14 +820,46 @@ channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) error("accept from auth socket: %.100s", strerror(errno)); return; } - newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup("accepted auth socket")); - packet_start(SSH_SMSG_AGENT_OPEN); - packet_put_int(newch); + newch = channel_new("accepted auth socket", + SSH_CHANNEL_OPENING, newsock, newsock, -1, + c->local_window_max, c->local_maxpacket, + 0, xstrdup("accepted auth socket"), 1); + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring("auth-agent@openssh.com"); + packet_put_int(newch); + packet_put_int(c->local_window_max); + packet_put_int(c->local_maxpacket); + } else { + packet_start(SSH_SMSG_AGENT_OPEN); + packet_put_int(newch); + } packet_send(); } } +void +channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (FD_ISSET(c->sock, writeset)) { + int err = 0; + int sz = sizeof(err); + c->type = SSH_CHANNEL_OPEN; + if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, (char *)&err, &sz) < 0) { + debug("getsockopt SO_ERROR failed"); + } else { + if (err == 0) { + debug("channel %d: connected)", c->self); + } else { + debug("channel %d: not connected: %s", + c->self, strerror(err)); + chan_read_failed(c); + chan_write_failed(c); + } + } + } +} + int channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) { @@ -692,10 +874,14 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) if (len <= 0) { debug("channel %d: read<=0 rfd %d len %d", c->self, c->rfd, len); - if (compat13) { + if (c->type != SSH_CHANNEL_OPEN) { + debug("channel %d: not open", c->self); + channel_free(c->self); + return -1; + } else if (compat13) { buffer_consume(&c->output, buffer_len(&c->output)); c->type = SSH_CHANNEL_INPUT_DRAINING; - debug("Channel %d status set to input draining.", c->self); + debug("channel %d: status set to input draining.", c->self); } else { chan_read_failed(c); } @@ -703,7 +889,7 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) } if(c->input_filter != NULL) { if (c->input_filter(c, buf, len) == -1) { - debug("filter stops channel %d", c->self); + debug("channel %d: filter stops", c->self); chan_read_failed(c); } } else { @@ -715,6 +901,7 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) int channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) { + struct termios tio; int len; /* Send buffered output data to the socket. */ @@ -726,9 +913,13 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) if (len < 0 && (errno == EINTR || errno == EAGAIN)) return 1; if (len <= 0) { - if (compat13) { + if (c->type != SSH_CHANNEL_OPEN) { + debug("channel %d: not open", c->self); + channel_free(c->self); + return -1; + } else if (compat13) { buffer_consume(&c->output, buffer_len(&c->output)); - debug("Channel %d status set to input draining.", c->self); + debug("channel %d: status set to input draining.", c->self); c->type = SSH_CHANNEL_INPUT_DRAINING; } else { chan_write_failed(c); @@ -736,16 +927,15 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) return -1; } if (compat20 && c->isatty) { - struct termios tio; if (tcgetattr(c->wfd, &tio) == 0 && !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { /* * Simulate echo to reduce the impact of - * traffic analysis. + * traffic analysis. We need to match the + * size of a SSH2_MSG_CHANNEL_DATA message + * (4 byte channel id + data) */ - packet_start(SSH2_MSG_IGNORE); - memset(buffer_ptr(&c->output), 0, len); - packet_put_string(buffer_ptr(&c->output), len); + packet_send_ignore(4 + len); packet_send(); } } @@ -771,7 +961,14 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) buffer_len(&c->extended)); debug2("channel %d: written %d to efd %d", c->self, len, c->efd); - if (len > 0) { + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + debug2("channel %d: closing write-efd %d", + c->self, c->efd); + close(c->efd); + c->efd = -1; + } else { buffer_consume(&c->extended, len); c->local_consumed += len; } @@ -780,21 +977,25 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) len = read(c->efd, buf, sizeof(buf)); debug2("channel %d: read %d from efd %d", c->self, len, c->efd); - if (len == 0) { - debug("channel %d: closing efd %d", + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + debug2("channel %d: closing read-efd %d", c->self, c->efd); close(c->efd); c->efd = -1; - } else if (len > 0) + } else { buffer_append(&c->extended, buf, len); + } } } return 1; } int -channel_check_window(Channel *c, fd_set * readset, fd_set * writeset) +channel_check_window(Channel *c) { - if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && + if (c->type == SSH_CHANNEL_OPEN && + !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && c->local_window < c->local_window_max/2 && c->local_consumed > 0) { packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); @@ -823,7 +1024,8 @@ channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset) channel_handle_rfd(c, readset, writeset); channel_handle_wfd(c, readset, writeset); channel_handle_efd(c, readset, writeset); - channel_check_window(c, readset, writeset); + + channel_check_window(c); } void @@ -847,11 +1049,19 @@ channel_handler_init_20(void) channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; + channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; + channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; + channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; + channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; + channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_2; } void @@ -864,12 +1074,16 @@ channel_handler_init_13(void) channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; + channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; + channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; + channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; + channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; } void @@ -880,11 +1094,15 @@ channel_handler_init_15(void) channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; + channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; + channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; + channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1; } void @@ -921,14 +1139,51 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) if (ftab[c->type] == NULL) continue; (*ftab[c->type])(c, readset, writeset); - chan_delete_if_full_closed(c); + if (chan_is_dead(c)) { + /* + * we have to remove the fd's from the select mask + * before the channels are free'd and the fd's are + * closed + */ + if (c->wfd != -1) + FD_CLR(c->wfd, writeset); + if (c->rfd != -1) + FD_CLR(c->rfd, readset); + if (c->efd != -1) { + if (c->extended_usage == CHAN_EXTENDED_READ) + FD_CLR(c->efd, readset); + if (c->extended_usage == CHAN_EXTENDED_WRITE) + FD_CLR(c->efd, writeset); + } + channel_free(c->self); + } } } void -channel_prepare_select(fd_set * readset, fd_set * writeset) +channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, + int rekeying) { - channel_handler(channel_pre, readset, writeset); + int n; + u_int sz; + + n = MAX(*maxfdp, channel_max_fd); + + sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); + if (*readsetp == NULL || n > *maxfdp) { + if (*readsetp) + xfree(*readsetp); + if (*writesetp) + xfree(*writesetp); + *readsetp = xmalloc(sz); + *writesetp = xmalloc(sz); + *maxfdp = n; + } + memset(*readsetp, 0, sz); + memset(*writesetp, 0, sz); + + if (!rekeying) + channel_handler(channel_pre, *readsetp, *writesetp); } void @@ -937,7 +1192,7 @@ channel_after_select(fd_set * readset, fd_set * writeset) channel_handler(channel_post, readset, writeset); } -/* If there is data to send to the connection, send some of it now. */ +/* If there is data to send to the connection, enqueue some of it now. */ void channel_output_poll() @@ -956,19 +1211,18 @@ channel_output_poll() } else { if (c->type != SSH_CHANNEL_OPEN) continue; - if (c->istate != CHAN_INPUT_OPEN && - c->istate != CHAN_INPUT_WAIT_DRAIN) - continue; } if (compat20 && (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { - debug("channel: %d: no data after CLOSE", c->self); + /* XXX is this true? */ + debug2("channel %d: no data after CLOSE", c->self); continue; } /* Get the amount of buffered data for this channel. */ - len = buffer_len(&c->input); - if (len > 0) { + if ((c->istate == CHAN_INPUT_OPEN || + c->istate == CHAN_INPUT_WAIT_DRAIN) && + (len = buffer_len(&c->input)) > 0) { /* Send some data for the other side over the secure connection. */ if (compat20) { if (len > c->remote_window) @@ -1008,6 +1262,9 @@ channel_output_poll() c->remote_window > 0 && (len = buffer_len(&c->extended)) > 0 && c->extended_usage == CHAN_EXTENDED_READ) { + debug2("channel %d: rwin %d elen %d euse %d", + c->self, c->remote_window, buffer_len(&c->extended), + c->extended_usage); if (len > c->remote_window) len = c->remote_window; if (len > c->remote_maxpacket) @@ -1019,6 +1276,7 @@ channel_output_poll() packet_send(); buffer_consume(&c->extended, len); c->remote_window -= len; + debug2("channel %d: sent ext data %d", c->self, len); } } } @@ -1034,7 +1292,7 @@ channel_input_data(int type, int plen, void *ctxt) { int id; char *data; - unsigned int data_len; + u_int data_len; Channel *c; /* Get the channel number and verify it. */ @@ -1080,7 +1338,7 @@ channel_input_extended_data(int type, int plen, void *ctxt) int id; int tcode; char *data; - unsigned int data_len; + u_int data_len; Channel *c; /* Get the channel number and verify it. */ @@ -1123,7 +1381,7 @@ channel_input_extended_data(int type, int plen, void *ctxt) int channel_not_very_much_buffered_data() { - unsigned int i; + u_int i; Channel *c; for (i = 0; i < channels_alloc; i++) { @@ -1262,7 +1520,8 @@ channel_input_open_confirmation(int type, int plen, void *ctxt) void channel_input_open_failure(int type, int plen, void *ctxt) { - int id; + int id, reason; + char *msg = NULL, *lang = NULL; Channel *c; if (!compat20) @@ -1275,13 +1534,18 @@ channel_input_open_failure(int type, int plen, void *ctxt) packet_disconnect("Received open failure for " "non-opening channel %d.", id); if (compat20) { - int reason = packet_get_int(); - char *msg = packet_get_string(NULL); - char *lang = packet_get_string(NULL); - log("channel_open_failure: %d: reason %d: %s", id, reason, msg); + reason = packet_get_int(); + if (packet_remaining() > 0) { + msg = packet_get_string(NULL); + lang = packet_get_string(NULL); + } packet_done(); - xfree(msg); - xfree(lang); + log("channel_open_failure: %d: reason %d %s", id, + reason, msg ? msg : "<no additional info>"); + if (msg != NULL) + xfree(msg); + if (lang != NULL) + xfree(lang); } /* Free the channel. This will also close the socket. */ channel_free(id); @@ -1306,7 +1570,7 @@ channel_input_channel_request(int type, int plen, void *ctxt) debug2("callback done"); } else { char *service = packet_get_string(NULL); - debug("channel: %d rcvd request for %s", c->self, service); + debug("channel %d: rcvd request for %s", c->self, service); debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event); xfree(service); } @@ -1349,10 +1613,11 @@ channel_stop_listening() switch (channels[i].type) { case SSH_CHANNEL_AUTH_SOCKET: close(channels[i].sock); - remove(channels[i].path); + unlink(channels[i].path); channel_free(i); break; case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_X11_LISTENER: close(channels[i].sock); channel_free(i); @@ -1377,27 +1642,22 @@ channel_close_all() channel_close_fds(&channels[i]); } -/* Returns the maximum file descriptor number used by the channels. */ - -int -channel_max_fd() -{ - return channel_max_fd_value; -} - /* Returns true if any channel is still open. */ int channel_still_open() { - unsigned int i; + u_int i; for (i = 0; i < channels_alloc; i++) switch (channels[i].type) { case SSH_CHANNEL_FREE: case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_DYNAMIC: + case SSH_CHANNEL_CONNECTING: /* XXX ??? */ continue; case SSH_CHANNEL_LARVAL: if (!compat20) @@ -1419,6 +1679,41 @@ channel_still_open() return 0; } +/* Returns the id of an open channel suitable for keepaliving */ + +int +channel_find_open() +{ + u_int i; + for (i = 0; i < channels_alloc; i++) + switch (channels[i].type) { + case SSH_CHANNEL_CLOSED: + case SSH_CHANNEL_DYNAMIC: + case SSH_CHANNEL_FREE: + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_OPENING: + continue; + case SSH_CHANNEL_LARVAL: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_CONNECTING: /* XXX ??? */ + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + return i; + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + return i; + default: + fatal("channel_find_open: bad channel type %d", channels[i].type); + /* NOTREACHED */ + } + return -1; +} + + /* * Returns a message describing the currently open forwarded connections, * suitable for sending to the client. The message contains crlf pairs for @@ -1441,11 +1736,14 @@ channel_open_message() case SSH_CHANNEL_FREE: case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: continue; case SSH_CHANNEL_LARVAL: case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_CONNECTING: + case SSH_CHANNEL_DYNAMIC: case SSH_CHANNEL_OPEN: case SSH_CHANNEL_X11_OPEN: case SSH_CHANNEL_INPUT_DRAINING: @@ -1473,19 +1771,48 @@ channel_open_message() * Initiate forwarding of connections to local port "port" through the secure * channel to host:port from remote side. */ +int +channel_request_local_forwarding(u_short listen_port, const char *host_to_connect, + u_short port_to_connect, int gateway_ports) +{ + return channel_request_forwarding( + NULL, listen_port, + host_to_connect, port_to_connect, + gateway_ports, /*remote_fwd*/ 0); +} -void -channel_request_local_forwarding(u_short port, const char *host, - u_short host_port, int gateway_ports) +/* + * If 'remote_fwd' is true we have a '-R style' listener for protocol 2 + * (SSH_CHANNEL_RPORT_LISTENER). + */ +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) { - int success, ch, sock, on = 1; + int success, ch, sock, on = 1, ctype; struct addrinfo hints, *ai, *aitop; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + const char *host; struct linger linger; - if (strlen(host) > sizeof(channels[0].path) - 1) - packet_disconnect("Forward host name too long."); + success = 0; + + if (remote_fwd) { + host = listen_address; + ctype = SSH_CHANNEL_RPORT_LISTENER; + } else { + host = host_to_connect; + ctype =SSH_CHANNEL_PORT_LISTENER; + } + if (strlen(host) > sizeof(channels[0].path) - 1) { + error("Forward host name too long."); + return success; + } + + /* XXX listen_address is currently ignored */ /* * getaddrinfo returns a loopback address if the hostname is * set to NULL and hints.ai_flags is not AI_PASSIVE @@ -1494,17 +1821,16 @@ channel_request_local_forwarding(u_short port, const char *host, hints.ai_family = IPv4or6; hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%d", port); + snprintf(strport, sizeof strport, "%d", listen_port); if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) packet_disconnect("getaddrinfo: fatal error"); - success = 0; for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - error("channel_request_local_forwarding: getnameinfo failed"); + error("channel_request_forwarding: getnameinfo failed"); continue; } /* Create a port to listen for the host. */ @@ -1538,19 +1864,19 @@ channel_request_local_forwarding(u_short port, const char *host, continue; } /* Allocate a channel number for the socket. */ - ch = channel_new( - "port listener", SSH_CHANNEL_PORT_LISTENER, - sock, sock, -1, + ch = channel_new("port listener", ctype, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, xstrdup("port listener"), 1); strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); - channels[ch].host_port = host_port; - channels[ch].listening_port = port; + channels[ch].host_port = port_to_connect; + channels[ch].listening_port = listen_port; success = 1; } if (success == 0) - packet_disconnect("cannot listen port: %d", port); + error("channel_request_forwarding: cannot listen to port: %d", + listen_port); freeaddrinfo(aitop); + return success; } /* @@ -1559,19 +1885,15 @@ channel_request_local_forwarding(u_short port, const char *host, */ void -channel_request_remote_forwarding(u_short listen_port, const char *host_to_connect, - u_short port_to_connect) +channel_request_remote_forwarding(u_short listen_port, + const char *host_to_connect, u_short port_to_connect) { - int payload_len; + int payload_len, type, success = 0; + /* Record locally that connection to this host/port is permitted. */ if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) fatal("channel_request_remote_forwarding: too many forwards"); - permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); - permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; - permitted_opens[num_permitted_opens].listen_port = listen_port; - num_permitted_opens++; - /* Send the forward request to the remote side. */ if (compat20) { const char *address_to_bind = "0.0.0.0"; @@ -1580,6 +1902,10 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne packet_put_char(0); /* boolean: want reply */ packet_put_cstring(address_to_bind); packet_put_int(listen_port); + packet_send(); + packet_write_wait(); + /* Assume that server accepts the request */ + success = 1; } else { packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); packet_put_int(listen_port); @@ -1587,11 +1913,27 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne packet_put_int(port_to_connect); packet_send(); packet_write_wait(); - /* - * Wait for response from the remote side. It will send a disconnect - * message on failure, and we will never see it here. - */ - packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); + + /* Wait for response from the remote side. */ + type = packet_read(&payload_len); + switch (type) { + case SSH_SMSG_SUCCESS: + success = 1; + break; + case SSH_SMSG_FAILURE: + log("Warning: Server denied remote port forwarding."); + break; + default: + /* Unknown packet */ + packet_disconnect("Protocol error for port forward request:" + "received packet type %d.", type); + } + } + if (success) { + permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); + permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; + permitted_opens[num_permitted_opens].listen_port = listen_port; + num_permitted_opens++; } } @@ -1619,18 +1961,54 @@ channel_input_port_forward_request(int is_root, int gateway_ports) if (port < IPPORT_RESERVED && !is_root) packet_disconnect("Requested forwarding of port %d but user is not root.", port); - /* - * Initiate forwarding, - */ + /* Initiate forwarding */ channel_request_local_forwarding(port, hostname, host_port, gateway_ports); /* Free the argument string. */ xfree(hostname); } -/* XXX move to aux.c */ +/* + * 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() +{ + if (num_permitted_opens == 0) + all_opens_permitted = 1; +} + +void +channel_add_permitted_opens(char *host, int port) +{ + if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) + fatal("channel_request_remote_forwarding: too many forwards"); + debug("allow port forwarding to host %s port %d", host, port); + + permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); + permitted_opens[num_permitted_opens].port_to_connect = port; + num_permitted_opens++; + + all_opens_permitted = 0; +} + +void +channel_clear_permitted_opens(void) +{ + int i; + + for (i = 0; i < num_permitted_opens; i++) + xfree(permitted_opens[i].host_to_connect); + num_permitted_opens = 0; + +} + + +/* return socket to remote host, port */ int -channel_connect_to(const char *host, u_short host_port) +connect_to(const char *host, u_short port) { struct addrinfo hints, *ai, *aitop; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; @@ -1640,9 +2018,10 @@ channel_connect_to(const char *host, u_short host_port) memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%d", host_port); + snprintf(strport, sizeof strport, "%d", port); if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { - error("%.100s: unknown host (%s)", host, gai_strerror(gaierr)); + error("connect_to %.100s: unknown host (%s)", host, + gai_strerror(gaierr)); return -1; } for (ai = aitop; ai; ai = ai->ai_next) { @@ -1650,33 +2029,72 @@ channel_connect_to(const char *host, u_short host_port) continue; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - error("channel_connect_to: getnameinfo failed"); + error("connect_to: getnameinfo failed"); continue; } - /* Create the socket. */ sock = socket(ai->ai_family, SOCK_STREAM, 0); if (sock < 0) { error("socket: %.100s", strerror(errno)); continue; } - /* Connect to the host/port. */ - if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { - error("connect %.100s port %s: %.100s", ntop, strport, + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) + fatal("connect_to: F_SETFL: %s", strerror(errno)); + if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && + errno != EINPROGRESS) { + error("connect_to %.100s port %s: %.100s", ntop, strport, strerror(errno)); close(sock); - continue; /* fail -- try next */ + continue; /* fail -- try next */ } break; /* success */ } freeaddrinfo(aitop); if (!ai) { - error("connect %.100s port %d: failed.", host, host_port); + error("connect_to %.100s port %d: failed.", host, port); return -1; } /* success */ return sock; } + +int +channel_connect_by_listen_adress(u_short listen_port) +{ + int i; + + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].listen_port == listen_port) + return connect_to( + permitted_opens[i].host_to_connect, + permitted_opens[i].port_to_connect); + error("WARNING: Server requests forwarding for unknown listen_port %d", + listen_port); + return -1; +} + +/* Check if connecting to that port is permitted and connect. */ +int +channel_connect_to(const char *host, u_short port) +{ + int i, permit; + + permit = all_opens_permitted; + if (!permit) { + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].port_to_connect == port && + strcmp(permitted_opens[i].host_to_connect, host) == 0) + permit = 1; + + } + if (!permit) { + log("Received request to connect to host %.100s port %d, " + "but the request was denied.", host, port); + return -1; + } + return connect_to(host, port); +} + /* * This is called after receiving PORT_OPEN message. This attempts to * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION @@ -1688,53 +2106,25 @@ channel_input_port_open(int type, int plen, void *ctxt) { u_short host_port; char *host, *originator_string; - int remote_channel, sock = -1, newch, i, denied; - unsigned int host_len, originator_len; + int remote_channel, sock = -1, newch; - /* Get remote channel number. */ remote_channel = packet_get_int(); - - /* Get host name to connect to. */ - host = packet_get_string(&host_len); - - /* Get port to connect to. */ + host = packet_get_string(NULL); host_port = packet_get_int(); - /* Get remote originator name. */ if (have_hostname_in_open) { - originator_string = packet_get_string(&originator_len); - originator_len += 4; /* size of packet_int */ + originator_string = packet_get_string(NULL); } else { originator_string = xstrdup("unknown (remote did not supply name)"); - originator_len = 0; /* no originator supplied */ - } - - packet_integrity_check(plen, - 4 + 4 + host_len + 4 + originator_len, SSH_MSG_PORT_OPEN); - - /* Check if opening that port is permitted. */ - denied = 0; - if (!all_opens_permitted) { - /* Go trough all permitted ports. */ - for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].port_to_connect == host_port && - strcmp(permitted_opens[i].host_to_connect, host) == 0) - break; - - /* Check if we found the requested port among those permitted. */ - if (i >= num_permitted_opens) { - /* The port is not permitted. */ - log("Received request to connect to %.100s:%d, but the request was denied.", - host, host_port); - denied = 1; - } } - sock = denied ? -1 : channel_connect_to(host, host_port); - if (sock > 0) { - /* Allocate a channel for this connection. */ - newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string); + packet_done(); + sock = channel_connect_to(host, host_port); + if (sock != -1) { + newch = channel_allocate(SSH_CHANNEL_CONNECTING, + sock, originator_string); channels[newch].remote_id = remote_channel; + /*XXX delay answer? */ packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); packet_put_int(remote_channel); packet_put_int(newch); @@ -1802,6 +2192,7 @@ x11_create_display_inet(int screen_number, int x11_display_offset) if (num_socks == NUM_SOCKS) break; } + freeaddrinfo(aitop); if (num_socks > 0) break; } @@ -1845,7 +2236,7 @@ x11_create_display_inet(int screen_number, int x11_display_offset) static int -connect_local_xsocket(unsigned int dnr) +connect_local_xsocket(u_int dnr) { static const char *const x_sockets[] = { X_UNIX_PATH "%u", @@ -1978,7 +2369,7 @@ x11_input_open(int type, int plen, void *ctxt) { int remote_channel, sock = 0, newch; char *remote_host; - unsigned int remote_len; + u_int remote_len; /* Get remote channel number. */ remote_channel = packet_get_int(); @@ -2049,8 +2440,8 @@ void x11_request_forwarding_with_spoofing(int client_session_id, const char *proto, const char *data) { - unsigned int data_len = (unsigned int) strlen(data) / 2; - unsigned int i, value; + u_int data_len = (u_int) strlen(data) / 2; + u_int i, value, len; char *new_data; int screen_number; const char *cp; @@ -2088,9 +2479,11 @@ x11_request_forwarding_with_spoofing(int client_session_id, x11_fake_data_len = data_len; /* Convert the fake data into hex. */ - new_data = xmalloc(2 * data_len + 1); + len = 2 * data_len + 1; + new_data = xmalloc(len); for (i = 0; i < data_len; i++) - sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]); + snprintf(new_data + 2 * i, len - 2 * i, + "%02x", (u_char) x11_fake_data[i]); /* Send the request packet. */ if (compat20) { @@ -2134,7 +2527,7 @@ auth_get_socket_name() void cleanup_socket(void) { - remove(channel_forwarded_auth_socket_name); + unlink(channel_forwarded_auth_socket_name); rmdir(channel_forwarded_auth_socket_dir); } @@ -2153,7 +2546,7 @@ auth_input_request_forwarding(struct passwd * pw) fatal("Protocol error: authentication forwarding requested twice."); /* Temporarily drop privileged uid for mkdir/bind. */ - temporarily_use_uid(pw->pw_uid); + temporarily_use_uid(pw); /* Allocate a buffer for the socket name, and format the name. */ channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME); @@ -2201,8 +2594,11 @@ auth_input_request_forwarding(struct passwd * pw) packet_disconnect("listen: %.100s", strerror(errno)); /* Allocate a channel for the authentication agent socket. */ - newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock, - xstrdup("auth socket")); + newch = channel_new("auth socket", + SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, xstrdup("auth socket"), 1); + strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, sizeof(channels[newch].path)); return 1; @@ -2332,7 +2728,7 @@ channel_cancel_cleanup(int id) } c->dettach_user = NULL; } -void +void channel_register_filter(int id, channel_filter_fn *fn) { Channel *c = channel_lookup(id); diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index 8f23dee..0085199 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -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 diff --git a/crypto/openssh/cipher.c b/crypto/openssh/cipher.c index bb91d7e..07036d4 100644 --- a/crypto/openssh/cipher.c +++ b/crypto/openssh/cipher.c @@ -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)); diff --git a/crypto/openssh/cipher.h b/crypto/openssh/cipher.h index 006fef9..870d1da 100644 --- a/crypto/openssh/cipher.h +++ b/crypto/openssh/cipher.h @@ -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); diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c index c5f69cf..0fc3518 100644 --- a/crypto/openssh/compat.c +++ b/crypto/openssh/compat.c @@ -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); +} diff --git a/crypto/openssh/compat.h b/crypto/openssh/compat.h index 2b3e5aa..a13234c 100644 --- a/crypto/openssh/compat.h +++ b/crypto/openssh/compat.h @@ -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; diff --git a/crypto/openssh/hostfile.c b/crypto/openssh/hostfile.c index ef97825..fa70d7e 100644 --- a/crypto/openssh/hostfile.c +++ b/crypto/openssh/hostfile.c @@ -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; } diff --git a/crypto/openssh/includes.h b/crypto/openssh/includes.h index 621d39f..8cf76f4 100644 --- a/crypto/openssh/includes.h +++ b/crypto/openssh/includes.h @@ -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 diff --git a/crypto/openssh/key.c b/crypto/openssh/key.c index f83724a..e3279c8 100644 --- a/crypto/openssh/key.c +++ b/crypto/openssh/key.c @@ -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> +RCSID("$OpenBSD: key.c,v 1.25 2001/04/17 10:53:24 markus Exp $"); +RCSID("$FreeBSD$"); + #include <openssl/evp.h> + #include "xmalloc.h" #include "key.h" -#include "dsa.h" +#include "rsa.h" +#include "ssh-dss.h" +#include "ssh-rsa.h" #include "uuencode.h" - -RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $"); -RCSID("$FreeBSD$"); - -#define SSH_DSS "ssh-dss" +#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,31 +187,118 @@ 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; } @@ -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; + } +} diff --git a/crypto/openssh/mpaux.c b/crypto/openssh/mpaux.c index 7df7791..d2ef24f 100644 --- a/crypto/openssh/mpaux.c +++ b/crypto/openssh/mpaux.c @@ -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); diff --git a/crypto/openssh/packet.h b/crypto/openssh/packet.h index ea0a839..09dd995 100644 --- a/crypto/openssh/packet.h +++ b/crypto/openssh/packet.h @@ -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 */ diff --git a/crypto/openssh/pathnames.h b/crypto/openssh/pathnames.h index 2f109b3..0b0f2d3 100644 --- a/crypto/openssh/pathnames.h +++ b/crypto/openssh/pathnames.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" /* diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index d5e21b7..47b4b48 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_string: 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 @@ parse_int: 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 @@ parse_int: 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 @@ parse_int: 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 @@ parse_int: 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 @@ parse_int: 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 @@ parse_int: 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 @@ parse_int: } /* 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 */ } diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index 6d0199e..f429f76 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -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; diff --git a/crypto/openssh/rsa.c b/crypto/openssh/rsa.c index 3dabac1..357272b 100644 --- a/crypto/openssh/rsa.c +++ b/crypto/openssh/rsa.c @@ -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); } + diff --git a/crypto/openssh/rsa.h b/crypto/openssh/rsa.h index 152aa9a..f5e0c96 100644 --- a/crypto/openssh/rsa.h +++ b/crypto/openssh/rsa.h @@ -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 */ diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index bbc4367..17bdbc5 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -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" + +void add_listen_addr(ServerOptions *options, char *addr, u_short port); +void add_one_listen_addr(ServerOptions *options, char *addr, u_short port); -/* add listen address */ -void add_listen_addr(ServerOptions *options, char *addr); +/* 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 @@ parse_int: 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 @@ parse_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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: case sXAuthLocation: charptr = &options->xauth_location; goto parse_filename; - + case sStrictModes: intptr = &options->strict_modes; goto parse_flag; @@ -604,12 +689,16 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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 @@ parse_flag: 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); } diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index f4ce52c..2d84ee4 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -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; /* diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c index 5372ab3..02d034e 100644 --- a/crypto/openssh/serverloop.c +++ b/crypto/openssh/serverloop.c @@ -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 @@ retry_select: */ 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 @@ retry_select: 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,31 +705,37 @@ 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); @@ -695,10 +743,23 @@ server_loop2(void) } 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(); } + diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index 300dc5a..47cfd3e 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -9,7 +9,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 @@ -33,25 +33,31 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.42 2000/10/27 07:32:18 markus Exp $"); +RCSID("$OpenBSD: session.c,v 1.74 2001/04/17 19:34:25 markus Exp $"); RCSID("$FreeBSD$"); -#include "xmalloc.h" #include "ssh.h" -#include "pty.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "sshpty.h" #include "packet.h" #include "buffer.h" #include "mpaux.h" -#include "servconf.h" #include "uidswap.h" #include "compat.h" #include "channels.h" #include "nchan.h" - #include "bufaux.h" -#include "ssh2.h" #include "auth.h" #include "auth-options.h" +#include "pathnames.h" +#include "log.h" +#include "servconf.h" +#include "sshlogin.h" +#include "serverloop.h" +#include "canohost.h" +#include "session.h" #ifdef __FreeBSD__ #define _PATH_CHPASS "/usr/bin/passwd" @@ -72,7 +78,6 @@ typedef struct Session Session; struct Session { int used; int self; - int extended; struct passwd *pw; pid_t pid; /* tty */ @@ -88,6 +93,7 @@ struct Session { int single_connection; /* proto 2 */ int chanid; + int is_subsystem; }; /* func */ @@ -96,29 +102,30 @@ Session *session_new(void); void session_set_fds(Session *s, int fdin, int fdout, int fderr); void session_pty_cleanup(Session *s); void session_proctitle(Session *s); -void do_exec_pty(Session *s, const char *command, struct passwd * pw); -void do_exec_no_pty(Session *s, const char *command, struct passwd * pw); -char *do_login(Session *s, const char *command); +void do_exec_pty(Session *s, const char *command); +void do_exec_no_pty(Session *s, const char *command); +void do_login(Session *s, const char *command); +void do_child(Session *s, const char *command); +void do_motd(void); +int check_quietlogin(Session *s, const char *command); -void -do_child(const char *command, struct passwd * pw, const char *term, - const char *display, const char *auth_proto, - const char *auth_data, const char *ttyname); +void do_authenticated1(Authctxt *authctxt); +void do_authenticated2(Authctxt *authctxt); /* import */ extern ServerOptions options; extern char *__progname; extern int log_stderr; extern int debug_flag; -extern unsigned int utmp_len; - +extern u_int utmp_len; extern int startup_pipe; +extern void destroy_sensitive_data(void); /* Local Xauthority file. */ static char *xauthfile; /* original command from peer. */ -char *original_command = NULL; +char *original_command = NULL; /* data */ #define MAX_SESSIONS 10 @@ -128,6 +135,40 @@ Session sessions[MAX_SESSIONS]; static login_cap_t *lc; #endif +void +do_authenticated(Authctxt *authctxt) +{ + /* + * Cancel the alarm we set to limit the time taken for + * authentication. + */ + alarm(0); + if (startup_pipe != -1) { + close(startup_pipe); + startup_pipe = -1; + } +#ifdef HAVE_LOGIN_CAP + if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) { + error("unable to get login class"); + return; + } +#ifdef BSD_AUTH + if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) { + packet_disconnect("Approval failure for %s", + authctxt->pw->pw_name); + } +#endif +#endif + /* setup the channel layer */ + if (!no_port_forwarding_flag && options.allow_tcp_forwarding) + channel_permit_all_opens(); + + if (compat20) + do_authenticated2(authctxt); + else + do_authenticated1(authctxt); +} + /* * Remove local Xauthority file. */ @@ -177,53 +218,23 @@ pty_cleanup_proc(void *session) * are requested, etc. */ void -do_authenticated(struct passwd * pw) +do_authenticated1(Authctxt *authctxt) { Session *s; - int type, fd; - int compression_level = 0, enable_compression_after_reply = 0; - int have_pty = 0; char *command; - int n_bytes; - int plen; - unsigned int proto_len, data_len, dlen; - - /* - * Cancel the alarm we set to limit the time taken for - * authentication. - */ - alarm(0); - if (startup_pipe != -1) { - close(startup_pipe); - startup_pipe = -1; - } - - /* - * Inform the channel mechanism that we are the server side and that - * the client may request to connect to any port at all. (The user - * could do it anyway, and we wouldn\'t know what is permitted except - * by the client telling us, so we can equally well trust the client - * not to request anything bogus.) - */ - if (!no_port_forwarding_flag && options.allow_tcp_forwarding) - channel_permit_all_opens(); + int success, type, fd, n_bytes, plen, screen_flag, have_pty = 0; + int compression_level = 0, enable_compression_after_reply = 0; + u_int proto_len, data_len, dlen; s = session_new(); - s->pw = pw; - -#ifdef HAVE_LOGIN_CAP - if ((lc = login_getclass(pw->pw_class)) == NULL) { - error("unable to get login class"); - return; - } -#endif + s->pw = authctxt->pw; /* * We stay in this loop until the client requests to execute a shell * or a command. */ for (;;) { - int success = 0; + success = 0; /* Get a packet from the client. */ type = packet_read(&plen); @@ -260,7 +271,7 @@ do_authenticated(struct passwd * pw) break; } fatal_add_cleanup(pty_cleanup_proc, (void *)s); - pty_setowner(pw, s->tty); + pty_setowner(s->pw, s->tty); /* Get TERM from the packet. Note that the value may be of arbitrary length. */ s->term = packet_get_string(&dlen); @@ -310,12 +321,23 @@ do_authenticated(struct passwd * pw) s->auth_proto = packet_get_string(&proto_len); s->auth_data = packet_get_string(&data_len); - packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type); - if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) + screen_flag = packet_get_protocol_flags() & + SSH_PROTOFLAG_SCREEN_NUMBER; + debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); + + if (packet_remaining() == 4) { + if (!screen_flag) + debug2("Buggy client: " + "X11 screen flag missing"); + packet_integrity_check(plen, + 4 + proto_len + 4 + data_len + 4, type); s->screen = packet_get_int(); - else + } else { + packet_integrity_check(plen, + 4 + proto_len + 4 + data_len, type); s->screen = 0; + } s->display = x11_create_display_inet(s->screen, options.x11_display_offset); if (s->display == NULL) @@ -324,7 +346,7 @@ do_authenticated(struct passwd * pw) /* Setup to always have a local .Xauthority. */ xauthfile = xmalloc(MAXPATHLEN); strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); - temporarily_use_uid(pw->pw_uid); + temporarily_use_uid(s->pw); if (mkdtemp(xauthfile) == NULL) { restore_uid(); error("private X11 dir: mkdtemp %s failed: %s", @@ -349,7 +371,7 @@ do_authenticated(struct passwd * pw) break; } debug("Received authentication agent forwarding request."); - success = auth_input_request_forwarding(pw); + success = auth_input_request_forwarding(s->pw); break; case SSH_CMSG_PORT_FORWARD_REQUEST: @@ -362,7 +384,7 @@ do_authenticated(struct passwd * pw) break; } debug("Received TCP/IP port forwarding request."); - channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports); + channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports); success = 1; break; @@ -373,10 +395,6 @@ do_authenticated(struct passwd * pw) case SSH_CMSG_EXEC_SHELL: case SSH_CMSG_EXEC_CMD: - /* Set interactive/non-interactive mode. */ - packet_set_interactive(have_pty || s->display != NULL, - options.keepalives); - if (type == SSH_CMSG_EXEC_CMD) { command = packet_get_string(&dlen); debug("Exec command '%.500s'", command); @@ -391,9 +409,9 @@ do_authenticated(struct passwd * pw) debug("Forced command '%.500s'", forced_command); } if (have_pty) - do_exec_pty(s, command, pw); + do_exec_pty(s, command); else - do_exec_no_pty(s, command, pw); + do_exec_no_pty(s, command); if (command != NULL) xfree(command); @@ -427,7 +445,7 @@ do_authenticated(struct passwd * pw) * setting up file descriptors and such. */ void -do_exec_no_pty(Session *s, const char *command, struct passwd * pw) +do_exec_no_pty(Session *s, const char *command) { int pid; @@ -504,12 +522,14 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) #endif /* USE_PIPES */ /* Do processing for the child (exec command etc). */ - do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL); + do_child(s, command); /* NOTREACHED */ } if (pid < 0) packet_disconnect("fork failed: %.100s", strerror(errno)); s->pid = pid; + /* Set interactive/non-interactive mode. */ + packet_set_interactive(s->display != NULL); #ifdef USE_PIPES /* We are the parent. Close the child sides of the pipes. */ close(pin[0]); @@ -517,11 +537,11 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) close(perr[1]); if (compat20) { - session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1); + session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]); } else { /* Enter the interactive session. */ server_loop(pid, pin[1], pout[0], perr[0]); - /* server_loop has closed pin[1], pout[1], and perr[1]. */ + /* server_loop has closed pin[1], pout[0], and perr[0]. */ } #else /* USE_PIPES */ /* We are the parent. Close the child sides of the socket pairs. */ @@ -533,7 +553,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) * handle the case that fdin and fdout are the same. */ if (compat20) { - session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1); + session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); } else { server_loop(pid, inout[1], inout[1], err[1]); /* server_loop has closed inout[1] and err[1]. */ @@ -548,7 +568,7 @@ do_exec_no_pty(Session *s, const char *command, struct passwd * pw) * lastlog, and other such operations. */ void -do_exec_pty(Session *s, const char *command, struct passwd * pw) +do_exec_pty(Session *s, const char *command) { int fdout, ptyfd, ttyfd, ptymaster; pid_t pid; @@ -559,7 +579,7 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) ttyfd = s->ttyfd; #ifdef USE_PAM - do_pam_session(pw->pw_name, s->tty); + do_pam_session(s->pw->pw_name, s->tty); do_pam_setcred(); #endif /* USE_PAM */ @@ -590,12 +610,11 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) close(ttyfd); /* record login, etc. similar to login(1) */ - if (!options.use_login) - command = do_login(s, command); + if (!(options.use_login && command == NULL)) + do_login(s, command); /* Do common processing for the child, such as execing the command. */ - do_child(command, pw, s->term, s->display, s->auth_proto, - s->auth_data, s->tty); + do_child(s, command); /* NOTREACHED */ } if (pid < 0) @@ -621,6 +640,7 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) s->ptymaster = ptymaster; /* Enter interactive session. */ + packet_set_interactive(1); if (compat20) { session_set_fds(s, ptyfd, fdout, -1); } else { @@ -630,29 +650,16 @@ do_exec_pty(Session *s, const char *command, struct passwd * pw) } } -const char * -get_remote_name_or_ip(void) -{ - static const char *remote = ""; - if (utmp_len > 0) - remote = get_canonical_hostname(); - if (utmp_len == 0 || strlen(remote) > utmp_len) - remote = get_remote_ipaddr(); - return remote; -} - /* administrative, login(1)-like work */ -char * +void do_login(Session *s, const char *command) { FILE *f; char *time_string, *newcommand; char buf[256]; char hostname[MAXHOSTNAMELEN]; - int quiet_login; socklen_t fromlen; struct sockaddr_storage from; - struct stat st; time_t last_login_time; struct passwd * pw = s->pw; pid_t pid = getpid(); @@ -665,8 +672,6 @@ do_login(Session *s, const char *command) time_t warntime = DEFAULT_WARN; #endif /* __FreeBSD__ */ - newcommand = (char *)command; - /* * Get IP address of client. If the connection is not a socket, let * the address be 0.0.0.0. @@ -682,13 +687,16 @@ do_login(Session *s, const char *command) } /* Get the time and hostname when the user last logged in. */ - hostname[0] = '\0'; - last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, - hostname, sizeof(hostname)); + if (options.print_lastlog) { + hostname[0] = '\0'; + last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, + hostname, sizeof(hostname)); + } /* Record that there was a login on that tty from the remote host. */ record_login(pid, s->tty, pw->pw_name, pw->pw_uid, - get_remote_name_or_ip(), (struct sockaddr *)&from); + get_remote_name_or_ip(utmp_len, options.reverse_mapping_check), + (struct sockaddr *)&from); #ifdef USE_PAM /* @@ -701,20 +709,8 @@ do_login(Session *s, const char *command) } #endif - /* Done if .hushlogin exists or a command given. */ - if (command != NULL) - return newcommand; - snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); -#ifdef HAVE_LOGIN_CAP - lc = login_getpwclass(pw); - if (lc == NULL) - lc = login_getclassbyname(NULL, pw); - quiet_login = login_getcapbool(lc, "hushlogin", quiet_login) || stat(buf, &st) >= 0; -#else - quiet_login = stat(buf, &st) >= 0; -#endif /* HAVE_LOGIN_CAP */ #ifdef USE_PAM - if (!quiet_login && !pam_password_change_required()) + if (!check_quietlogin(s, command) && !pam_password_change_required()) print_pam_messages(); #endif /* USE_PAM */ @@ -739,7 +735,7 @@ do_login(Session *s, const char *command) xfree(newcommand); newcommand = xstrdup(_PATH_CHPASS); } else if (pw->pw_change - tv.tv_sec < warntime && - !quiet_login) + !check_quietlogin(s, command)) (void)printf( "Warning: your password expires on %s", ctime(&pw->pw_change)); @@ -755,10 +751,11 @@ do_login(Session *s, const char *command) "Sorry -- your account has expired.\n"); log( "LOGIN %.200s REFUSED (EXPIRED) FROM %.200s ON TTY %.200s", - pw->pw_name, get_remote_name_or_ip(), s->tty); + pw->pw_name, get_remote_name_or_ip(utmp_len, + options.reverse_mapping_check), s->tty); exit(254); } else if (pw->pw_expire - tv.tv_sec < warntime && - !quiet_login) + !check_quietlogin(s, command)) (void)printf( "Warning: your account expires on %s", ctime(&pw->pw_expire)); @@ -771,7 +768,8 @@ do_login(Session *s, const char *command) (void)printf("Permission denied.\n"); log( "LOGIN %.200s REFUSED (TTY) FROM %.200s ON TTY %.200s", - pw->pw_name, get_remote_name_or_ip(), s->tty); + pw->pw_name, get_remote_name_or_ip(utmp_len, + options.reverse_mapping_check), s->tty); exit(254); } #endif /* HAVE_LOGIN_CAP */ @@ -784,9 +782,9 @@ do_login(Session *s, const char *command) * are going to another machine). Login(1) will do this for * us as well, so check if login(1) is used */ - if (newcommand == NULL && last_login_time != 0 && !quiet_login && + if (command == NULL && options.print_lastlog && + last_login_time != 0 && !check_quietlogin(s, command) && !options.use_login) { - /* Convert the date to a string. */ time_string = ctime(&last_login_time); /* Remove the trailing newline. */ if (strchr(time_string, '\n')) @@ -798,7 +796,8 @@ do_login(Session *s, const char *command) } #ifdef HAVE_LOGIN_CAP - if (newcommand == NULL && !quiet_login && !options.use_login) { + if (command == NULL && !check_quietlogin(s, command) && + !options.use_login) { fname = login_getcapstr(lc, "copyright", NULL, NULL); if (fname != NULL && (f = fopen(fname, "r")) != NULL) { while (fgets(buf, sizeof(buf), f) != NULL) @@ -818,8 +817,20 @@ do_login(Session *s, const char *command) * used. Note that some machines appear to print it in * /etc/profile or similar. */ - if (newcommand == NULL && options.print_motd && !quiet_login && - !options.use_login) { + if (command == NULL && !check_quietlogin(s, command) && !options.use_login) + do_motd(); +} + +/* + * Display the message of the day. + */ +void +do_motd(void) +{ + FILE *f; + char buf[256]; + + if (options.print_motd) { #ifdef HAVE_LOGIN_CAP f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", "/etc/motd"), "r"); @@ -832,12 +843,30 @@ do_login(Session *s, const char *command) fclose(f); } } +} +/* + * Check for quiet login, either .hushlogin or command given. + */ +int +check_quietlogin(Session *s, const char *command) +{ + char buf[256]; + struct passwd * pw = s->pw; + struct stat st; + + /* Return 1 if .hushlogin exists or a command given. */ + if (command != NULL) + return 1; + snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); #ifdef HAVE_LOGIN_CAP - login_close(lc); - lc = NULL; -#endif /* HAVE_LOGIN_CAP */ - return newcommand; + if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) + return 1; +#else + if (stat(buf, &st) >= 0) + return 1; +#endif + return 0; } /* @@ -845,10 +874,10 @@ do_login(Session *s, const char *command) * already exists, its value is overriden. */ void -child_set_env(char ***envp, unsigned int *envsizep, const char *name, +child_set_env(char ***envp, u_int *envsizep, const char *name, const char *value) { - unsigned int i, namelen; + u_int i, namelen; char **env; /* @@ -886,7 +915,7 @@ child_set_env(char ***envp, unsigned int *envsizep, const char *name, * and assignments of the form name=value. No other forms are allowed. */ void -read_environment_file(char ***env, unsigned int *envsize, +read_environment_file(char ***env, u_int *envsize, const char *filename) { FILE *f; @@ -957,19 +986,22 @@ void do_pam_environment(char ***env, int *envsize) * ids, and executing the command or shell. */ void -do_child(const char *command, struct passwd * pw, const char *term, - const char *display, const char *auth_proto, - const char *auth_data, const char *ttyname) +do_child(Session *s, const char *command) { const char *shell, *hostname = NULL, *cp = NULL; + struct passwd * pw = s->pw; char buf[256]; char cmd[1024]; FILE *f = NULL; - unsigned int envsize, i; - char **env = NULL; + u_int envsize, i; + char **env; extern char **environ; struct stat st; char *argv[10]; + int do_xauth = s->auth_proto != NULL && s->auth_data != NULL; + + /* remove hostkey from the child's memory */ + destroy_sensitive_data(); /* login(1) is only called if we execute the login shell */ if (options.use_login && command != NULL) @@ -978,11 +1010,7 @@ do_child(const char *command, struct passwd * pw, const char *term, #ifndef USE_PAM if (!options.use_login) { #ifdef HAVE_LOGIN_CAP - lc = login_getpwclass(pw); - if (lc == NULL) - lc = login_getclassbyname(NULL, pw); - if (pw->pw_uid != 0) - auth_checknologin(lc); + if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, _PATH_NOLOGIN), "r"); #else @@ -1044,7 +1072,6 @@ do_child(const char *command, struct passwd * pw, const char *term, (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { perror("unable to set user context"); exit(1); - } #else if (setlogin(pw->pw_name) < 0) @@ -1061,7 +1088,7 @@ do_child(const char *command, struct passwd * pw, const char *term, endgrent(); /* Permanently switch to the desired uid. */ - permanently_set_uid(pw->pw_uid); + permanently_set_uid(pw); #endif /* HAVE_LOGIN_CAP */ } if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) @@ -1136,12 +1163,12 @@ do_child(const char *command, struct passwd * pw, const char *term, get_remote_ipaddr(), get_remote_port(), get_local_port()); child_set_env(&env, &envsize, "SSH_CLIENT", buf); - if (ttyname) - child_set_env(&env, &envsize, "SSH_TTY", ttyname); - if (term) - child_set_env(&env, &envsize, "TERM", term); - if (display) - child_set_env(&env, &envsize, "DISPLAY", display); + if (s->ttyfd != -1) + child_set_env(&env, &envsize, "SSH_TTY", s->tty); + if (s->term) + child_set_env(&env, &envsize, "TERM", s->term); + if (s->display) + child_set_env(&env, &envsize, "DISPLAY", s->display); if (original_command) child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", original_command); @@ -1205,7 +1232,8 @@ do_child(const char *command, struct passwd * pw, const char *term, } /* we have to stash the hostname before we close our socket. */ if (options.use_login) - hostname = get_remote_name_or_ip(); + hostname = get_remote_name_or_ip(utmp_len, + options.reverse_mapping_check); /* * Close the connection descriptors; note that this is the child, and * the server will still have the socket open, and it is important @@ -1233,15 +1261,6 @@ do_child(const char *command, struct passwd * pw, const char *term, endpwent(); /* - * Close any extra open file descriptors so that we don\'t have them - * hanging around in clients. Note that we want to do this after - * initgroups, because at least on Solaris 2.3 it leaves file - * descriptors open. - */ - for (i = 3; i < getdtablesize(); i++) - close(i); - - /* * Restore any signal handlers set by sshd previously that should * be restored to their initial state. */ @@ -1254,9 +1273,6 @@ do_child(const char *command, struct passwd * pw, const char *term, #endif /* __FreeBSD__ */ chdir(pw->pw_dir) < 0 ) { -#ifdef __FreeBSD__ - int quiet_login = 0; -#endif /* __FreeBSD__ */ #ifdef HAVE_LOGIN_CAP if (login_getcapbool(lc, "requirehome", 0)) { (void)printf("Home directory not available\n"); @@ -1272,10 +1288,7 @@ do_child(const char *command, struct passwd * pw, const char *term, pw->pw_name, ttyname); exit(254); } -#ifdef HAVE_LOGIN_CAP - quiet_login = login_getcapbool(lc, "hushlogin", 0); -#endif /* HAVE_LOGIN_CAP */ - if (!quiet_login || *pw->pw_dir) + if (!check_quietlogin(s, command) || *pw->pw_dir) (void)printf( "No home directory.\nLogging in with home = \"/\".\n"); @@ -1285,10 +1298,15 @@ do_child(const char *command, struct passwd * pw, const char *term, pw->pw_dir, strerror(errno)); #endif /* __FreeBSD__ */ } -#ifdef HAVE_LOGIN_CAP - login_close(lc); - lc = NULL; -#endif /* HAVE_LOGIN_CAP */ + + /* + * Close any extra open file descriptors so that we don\'t have them + * hanging around in clients. Note that we want to do this after + * initgroups, because at least on Solaris 2.3 it leaves file + * descriptors open. + */ + for (i = 3; i < getdtablesize(); i++) + close(i); /* * Must take new environment into use so that .ssh/rc, /etc/sshrc and @@ -1301,58 +1319,66 @@ do_child(const char *command, struct passwd * pw, const char *term, * in this order). */ if (!options.use_login) { - if (stat(SSH_USER_RC, &st) >= 0) { + /* ignore _PATH_SSH_USER_RC for subsystems */ + if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { if (debug_flag) - fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); - - f = popen("/bin/sh " SSH_USER_RC, "w"); + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, + _PATH_SSH_USER_RC); + f = popen(_PATH_BSHELL " " _PATH_SSH_USER_RC, "w"); if (f) { - if (auth_proto != NULL && auth_data != NULL) - fprintf(f, "%s %s\n", auth_proto, auth_data); + if (do_xauth) + fprintf(f, "%s %s\n", s->auth_proto, + s->auth_data); pclose(f); } else - fprintf(stderr, "Could not run %s\n", SSH_USER_RC); - } else if (stat(SSH_SYSTEM_RC, &st) >= 0) { + fprintf(stderr, "Could not run %s\n", + _PATH_SSH_USER_RC); + } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { if (debug_flag) - fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC); - - f = popen("/bin/sh " SSH_SYSTEM_RC, "w"); + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, + _PATH_SSH_SYSTEM_RC); + f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); if (f) { - if (auth_proto != NULL && auth_data != NULL) - fprintf(f, "%s %s\n", auth_proto, auth_data); + if (do_xauth) + fprintf(f, "%s %s\n", s->auth_proto, + s->auth_data); pclose(f); } else - fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); - } else if (options.xauth_location != NULL) { + fprintf(stderr, "Could not run %s\n", + _PATH_SSH_SYSTEM_RC); + } else if (do_xauth && options.xauth_location != NULL) { /* Add authority data to .Xauthority if appropriate. */ - if (auth_proto != NULL && auth_data != NULL) { - char *screen = strchr(display, ':'); - if (debug_flag) { + char *screen = strchr(s->display, ':'); + + if (debug_flag) { + fprintf(stderr, + "Running %.100s add " + "%.100s %.100s %.100s\n", + options.xauth_location, s->display, + s->auth_proto, s->auth_data); + if (screen != NULL) fprintf(stderr, - "Running %.100s add %.100s %.100s %.100s\n", - options.xauth_location, display, - auth_proto, auth_data); - if (screen != NULL) - fprintf(stderr, - "Adding %.*s/unix%s %s %s\n", - (int)(screen-display), display, - screen, auth_proto, auth_data); - } - snprintf(cmd, sizeof cmd, "%s -q -", - options.xauth_location); - f = popen(cmd, "w"); - if (f) { - fprintf(f, "add %s %s %s\n", display, - auth_proto, auth_data); - if (screen != NULL) - fprintf(f, "add %.*s/unix%s %s %s\n", - (int)(screen-display), display, - screen, auth_proto, auth_data); - pclose(f); - } else { - fprintf(stderr, "Could not run %s\n", - cmd); - } + "Adding %.*s/unix%s %s %s\n", + (int)(screen - s->display), + s->display, screen, + s->auth_proto, s->auth_data); + } + snprintf(cmd, sizeof cmd, "%s -q -", + options.xauth_location); + f = popen(cmd, "w"); + if (f) { + fprintf(f, "add %s %s %s\n", s->display, + s->auth_proto, s->auth_data); + if (screen != NULL) + fprintf(f, "add %.*s/unix%s %s %s\n", + (int)(screen - s->display), + s->display, screen, + s->auth_proto, + s->auth_data); + pclose(f); + } else { + fprintf(stderr, "Could not run %s\n", + cmd); } } /* Get the last component of the shell name. */ @@ -1362,6 +1388,10 @@ do_child(const char *command, struct passwd * pw, const char *term, else cp = shell; } + + /* restore SIGPIPE for child */ + signal(SIGPIPE, SIG_DFL); + /* * If we have no command, execute the shell. In this case, the shell * name to be passed in argv[0] is preceded by '-' to indicate that @@ -1375,9 +1405,10 @@ do_child(const char *command, struct passwd * pw, const char *term, * Check for mail if we have a tty and it was enabled * in server options. */ - if (ttyname && options.check_mail) { + if (s->ttyfd != -1 && options.check_mail) { char *mailbox; struct stat mailstat; + mailbox = getenv("MAIL"); if (mailbox != NULL) { if (stat(mailbox, &mailstat) != 0 || @@ -1448,19 +1479,11 @@ session_new(void) for(i = 0; i < MAX_SESSIONS; i++) { Session *s = &sessions[i]; if (! s->used) { - s->pid = 0; - s->extended = 0; + memset(s, 0, sizeof(*s)); s->chanid = -1; s->ptyfd = -1; s->ttyfd = -1; - s->term = NULL; - s->pw = NULL; - s->display = NULL; - s->screen = 0; - s->auth_data = NULL; - s->auth_proto = NULL; s->used = 1; - s->pw = NULL; debug("session_new: session %d", i); return s; } @@ -1494,7 +1517,7 @@ session_open(int chanid) } s->pw = auth_get_user(); if (s->pw == NULL) - fatal("no user for session %i", s->self); + fatal("no user for session %d", s->self); debug("session_open: session %d: link with channel %d", s->self, chanid); s->chanid = chanid; return 1; @@ -1546,8 +1569,8 @@ session_window_change_req(Session *s) int session_pty_req(Session *s) { - unsigned int len; - char *term_modes; /* encoded terminal modes */ + u_int len; + int n_bytes; if (no_pty_flag) return 0; @@ -1558,8 +1581,6 @@ session_pty_req(Session *s) s->row = packet_get_int(); s->xpixel = packet_get_int(); s->ypixel = packet_get_int(); - term_modes = packet_get_string(&len); - packet_done(); if (strcmp(s->term, "") == 0) { xfree(s->term); @@ -1572,7 +1593,6 @@ session_pty_req(Session *s) s->ptyfd = -1; s->ttyfd = -1; error("session_pty_req: session %d alloc failed", s->self); - xfree(term_modes); return 0; } debug("session_pty_req: session %d alloc %s", s->self, s->tty); @@ -1585,17 +1605,19 @@ session_pty_req(Session *s) /* Get window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); + /* Get tty modes from the packet. */ + tty_parse_modes(s->ttyfd, &n_bytes); + packet_done(); + session_proctitle(s); - /* XXX parse and set terminal modes */ - xfree(term_modes); return 1; } int session_subsystem_req(Session *s) { - unsigned int len; + u_int len; int success = 0; char *subsys = packet_get_string(&len); int i; @@ -1606,7 +1628,8 @@ session_subsystem_req(Session *s) for (i = 0; i < options.num_subsystems; i++) { if(strcmp(subsys, options.subsystem_name[i]) == 0) { debug("subsystem: exec() %s", options.subsystem_command[i]); - do_exec_no_pty(s, options.subsystem_command[i], s->pw); + s->is_subsystem = 1; + do_exec_no_pty(s, options.subsystem_command[i]); success = 1; } } @@ -1653,7 +1676,7 @@ session_x11_req(Session *s) } xauthfile = xmalloc(MAXPATHLEN); strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); - temporarily_use_uid(s->pw->pw_uid); + temporarily_use_uid(s->pw); if (mkdtemp(xauthfile) == NULL) { restore_uid(); error("private X11 dir: mkdtemp %s failed: %s", @@ -1680,18 +1703,17 @@ session_shell_req(Session *s) /* if forced_command == NULL, the shell is execed */ char *shell = forced_command; packet_done(); - s->extended = 1; if (s->ttyfd == -1) - do_exec_no_pty(s, shell, s->pw); + do_exec_no_pty(s, shell); else - do_exec_pty(s, shell, s->pw); + do_exec_pty(s, shell); return 1; } int session_exec_req(Session *s) { - unsigned int len; + u_int len; char *command = packet_get_string(&len); packet_done(); if (forced_command) { @@ -1699,20 +1721,36 @@ session_exec_req(Session *s) command = forced_command; debug("Forced command '%.500s'", forced_command); } - s->extended = 1; if (s->ttyfd == -1) - do_exec_no_pty(s, command, s->pw); + do_exec_no_pty(s, command); else - do_exec_pty(s, command, s->pw); + do_exec_pty(s, command); if (forced_command == NULL) xfree(command); return 1; } +int +session_auth_agent_req(Session *s) +{ + static int called = 0; + packet_done(); + if (no_agent_forwarding_flag) { + debug("session_auth_agent_req: no_agent_forwarding_flag"); + return 0; + } + if (called) { + return 0; + } else { + called = 1; + return auth_input_request_forwarding(s->pw); + } +} + void session_input_channel_req(int id, void *arg) { - unsigned int len; + u_int len; int reply; int success = 0; char *rtype; @@ -1733,8 +1771,8 @@ session_input_channel_req(int id, void *arg) s->self, id, rtype, reply); /* - * a session is in LARVAL state until a shell - * or programm is executed + * a session is in LARVAL state until a shell, a command + * or a subsystem is executed */ if (c->type == SSH_CHANNEL_LARVAL) { if (strcmp(rtype, "shell") == 0) { @@ -1745,6 +1783,8 @@ session_input_channel_req(int id, void *arg) success = session_pty_req(s); } else if (strcmp(rtype, "x11-req") == 0) { success = session_x11_req(s); + } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { + success = session_auth_agent_req(s); } else if (strcmp(rtype, "subsystem") == 0) { success = session_subsystem_req(s); } @@ -1785,7 +1825,7 @@ session_pty_cleanup(Session *s) if (s == NULL || s->ttyfd == -1) return; - debug("session_pty_cleanup: session %i release %s", s->self, s->tty); + debug("session_pty_cleanup: session %d release %s", s->self, s->tty); /* Cancel the cleanup function. */ fatal_remove_cleanup(pty_cleanup_proc, (void *)s); @@ -1945,26 +1985,9 @@ session_proctitle(Session *s) } void -do_authenticated2(void) +do_authenticated2(Authctxt *authctxt) { - struct passwd *pw; - /* - * Cancel the alarm we set to limit the time taken for - * authentication. - */ - alarm(0); - if (startup_pipe != -1) { - close(startup_pipe); - startup_pipe = -1; - } -#ifdef HAVE_LOGIN_CAP - pw = auth_get_user(); - if ((lc = login_getclass(pw->pw_class)) == NULL) { - error("unable to get login class"); - return; - } -#endif server_loop2(); if (xauthfile) xauthfile_cleanup_proc(NULL); diff --git a/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c index 9dde364..61f7c66 100644 --- a/crypto/openssh/ssh-add.c +++ b/crypto/openssh/ssh-add.c @@ -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); } diff --git a/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c index bbd6a78..ae0f044 100644 --- a/crypto/openssh/ssh-agent.c +++ b/crypto/openssh/ssh-agent.c @@ -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 @@ send: 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 */ } diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1 index cee2092..025e681 100644 --- a/crypto/openssh/ssh.1 +++ b/crypto/openssh/ssh.1 @@ -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 diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index 7acb513..49c383a 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -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 "ssh1.h" +#include "ssh2.h" +#include "compat.h" +#include "cipher.h" +#include "xmalloc.h" #include "packet.h" #include "buffer.h" -#include "readconf.h" #include "uidswap.h" - -#include "ssh2.h" -#include "compat.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; + /* Force no tty*/ + if (no_tty_flag) + tty_flag = 0; /* Do not allocate a tty if stdin is not a tty. */ - if (!isatty(fileno(stdin))) { + if (!isatty(fileno(stdin)) && !force_tty_flag) { if (tty_flag) - fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n"); + log("Pseudo-terminal will not be allocated because stdin is not a terminal."); tty_flag = 0; } - /* force */ - 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); - } - /* 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); - - /* We no longer need the host private key. Clear it now. */ - if (host_private_key_loaded) - RSA_free(host_private_key); /* Destroys contents safely */ + ssh_login(sensitive_data.keys, sensitive_data.nkeys, + host, (struct sockaddr *)&hostaddr, pw); + + /* 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; -extern void client_set_session_ident(int id); + 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); +} 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; + } +} diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h index b7ecde7..7485fb8 100644 --- a/crypto/openssh/ssh.h +++ b/crypto/openssh/ssh.h @@ -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,106 +51,21 @@ */ #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" +#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID" /* * Name of the environment variable containing the pathname of the * authentication socket. */ -#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID" +#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK" /* - * Default path to ssh-askpass used by ssh-add, - * environment variable for overwriting the default location + * 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 */ diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config index 9a09310..15ffbd4 100644 --- a/crypto/openssh/ssh_config +++ b/crypto/openssh/ssh_config @@ -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 diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c index 21ee0e6..0d2e089 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -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 gaierr; + int on = 1; int sock = -1, attempt; - struct servent *sp; - struct addrinfo hints, *ai, *aitop; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - int gaierr; + 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 @@ out: * 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); diff --git a/crypto/openssh/sshconnect.h b/crypto/openssh/sshconnect.h index b2e70d5..575827d 100644 --- a/crypto/openssh/sshconnect.h +++ b/crypto/openssh/sshconnect.h @@ -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); diff --git a/crypto/openssh/sshconnect1.c b/crypto/openssh/sshconnect1.c index 2b2d5fc..94f670c 100644 --- a/crypto/openssh/sshconnect1.c +++ b/crypto/openssh/sshconnect1.c @@ -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; diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c index fb7bff0..4f76bd0 100644 --- a/crypto/openssh/sshconnect2.c +++ b/crypto/openssh/sshconnect2.c @@ -24,37 +24,37 @@ #include "includes.h" RCSID("$FreeBSD$"); -RCSID("$OpenBSD: sshconnect2.c,v 1.27 2000/10/19 16:45:16 provos Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.72 2001/04/18 23:43:26 markus Exp $"); #include <openssl/bn.h> -#include <openssl/rsa.h> -#include <openssl/dsa.h> #include <openssl/md5.h> #include <openssl/dh.h> #include <openssl/hmac.h> #include "ssh.h" +#include "ssh2.h" #include "xmalloc.h" #include "rsa.h" #include "buffer.h" #include "packet.h" #include "uidswap.h" #include "compat.h" -#include "readconf.h" #include "bufaux.h" -#include "ssh2.h" +#include "cipher.h" #include "kex.h" #include "myproposal.h" #include "key.h" -#include "dsa.h" #include "sshconnect.h" #include "authfile.h" #include "cli.h" -#include "dispatch.h" +#include "dh.h" #include "authfd.h" - -void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); -void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); +#include "log.h" +#include "readconf.h" +#include "readpass.h" +#include "match.h" +#include "dispatch.h" +#include "canohost.h" /* import */ extern char *client_version_string; @@ -65,78 +65,69 @@ extern Options options; * SSH2 key exchange */ -unsigned char *session_id2 = NULL; +u_char *session_id2 = NULL; int session_id2_len = 0; +char *xxx_host; +struct sockaddr *xxx_hostaddr; + +Kex *xxx_kex = NULL; + +int +check_host_key_callback(Key *hostkey) +{ + check_host_key(xxx_host, xxx_hostaddr, hostkey, + options.user_hostfile2, options.system_hostfile2); + return 0; +} + void ssh_kex2(char *host, struct sockaddr *hostaddr) { - int i, plen; Kex *kex; - Buffer *client_kexinit, *server_kexinit; - char *sprop[PROPOSAL_MAX]; - - if (options.ciphers == NULL) { - if (options.cipher == SSH_CIPHER_3DES) { - options.ciphers = "3des-cbc"; - } else if (options.cipher == SSH_CIPHER_BLOWFISH) { - options.ciphers = "blowfish-cbc"; - } else if (options.cipher == SSH_CIPHER_DES) { - fatal("cipher DES not supported for protocol version 2"); - } + + xxx_host = host; + xxx_hostaddr = hostaddr; + + if (options.ciphers == (char *)-1) { + log("No valid ciphers for protocol version 2 given, using defaults."); + options.ciphers = NULL; } if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); if (options.compression) { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib"; + myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; } else { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; + myproposal[PROPOSAL_COMP_ALGS_CTOS] = myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; } - - /* buffers with raw kexinit messages */ - server_kexinit = xmalloc(sizeof(*server_kexinit)); - buffer_init(server_kexinit); - client_kexinit = kex_init(myproposal); - - /* algorithm negotiation */ - kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); - kex = kex_choose_conf(myproposal, sprop, 0); - for (i = 0; i < PROPOSAL_MAX; i++) - xfree(sprop[i]); - - /* server authentication and session key agreement */ - switch(kex->kex_type) { - case DH_GRP1_SHA1: - ssh_dh1_client(kex, host, hostaddr, - client_kexinit, server_kexinit); - break; - case DH_GEX_SHA1: - ssh_dhgex_client(kex, host, hostaddr, client_kexinit, - server_kexinit); - break; - default: - fatal("Unsupported key exchange %d", kex->kex_type); + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } + if (options.hostkeyalgorithms != NULL) + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + options.hostkeyalgorithms; - buffer_free(client_kexinit); - buffer_free(server_kexinit); - xfree(client_kexinit); - xfree(server_kexinit); + /* start key exchange */ + kex = kex_setup(myproposal); + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; + kex->check_host_key=&check_host_key_callback; - debug("Wait SSH2_MSG_NEWKEYS."); - packet_read_expect(&plen, SSH2_MSG_NEWKEYS); - packet_done(); - debug("GOT SSH2_MSG_NEWKEYS."); + xxx_kex = kex; - debug("send SSH2_MSG_NEWKEYS."); - packet_start(SSH2_MSG_NEWKEYS); - packet_send(); - packet_write_wait(); - debug("done: send SSH2_MSG_NEWKEYS."); + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); + + session_id2 = kex->session_id; + session_id2_len = kex->session_id_len; #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ @@ -145,302 +136,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) packet_send(); packet_write_wait(); #endif - debug("done: KEX2."); -} - -/* diffie-hellman-group1-sha1 */ - -void -ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, - Buffer *client_kexinit, Buffer *server_kexinit) -{ -#ifdef DEBUG_KEXDH - int i; -#endif - int plen, dlen; - unsigned int klen, kout; - char *signature = NULL; - unsigned int slen; - char *server_host_key_blob = NULL; - Key *server_host_key; - unsigned int sbloblen; - DH *dh; - BIGNUM *dh_server_pub = 0; - BIGNUM *shared_secret = 0; - unsigned char *kbuf; - unsigned char *hash; - - debug("Sending SSH2_MSG_KEXDH_INIT."); - /* generate and send 'e', client DH public key */ - dh = dh_new_group1(); - packet_start(SSH2_MSG_KEXDH_INIT); - packet_put_bignum2(dh->pub_key); - packet_send(); - packet_write_wait(); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\np= "); - BN_print_fp(stderr, dh->p); - fprintf(stderr, "\ng= "); - BN_print_fp(stderr, dh->g); - fprintf(stderr, "\npub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); - DHparams_print_fp(stderr, dh); -#endif - - debug("Wait SSH2_MSG_KEXDH_REPLY."); - - packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); - - debug("Got SSH2_MSG_KEXDH_REPLY."); - - /* key, cert */ - server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); - if (server_host_key == NULL) - fatal("cannot decode server_host_key_blob"); - - check_host_key(host, hostaddr, server_host_key, - options.user_hostfile2, options.system_hostfile2); - - /* DH paramter f, server public DH key */ - dh_server_pub = BN_new(); - if (dh_server_pub == NULL) - fatal("dh_server_pub == NULL"); - packet_get_bignum2(dh_server_pub, &dlen); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\ndh_server_pub= "); - BN_print_fp(stderr, dh_server_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_server_pub)); -#endif - - /* signed H */ - signature = packet_get_string(&slen); - packet_done(); - - if (!dh_pub_is_valid(dh, dh_server_pub)) - packet_disconnect("bad server public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_server_pub, dh); -#ifdef DEBUG_KEXDH - debug("shared secret: len %d/%d", klen, kout); - fprintf(stderr, "shared secret == "); - for (i = 0; i< kout; i++) - fprintf(stderr, "%02x", (kbuf[i])&0xff); - fprintf(stderr, "\n"); -#endif - shared_secret = BN_new(); - - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - /* calc and verify H */ - hash = kex_hash( - client_version_string, - server_version_string, - buffer_ptr(client_kexinit), buffer_len(client_kexinit), - buffer_ptr(server_kexinit), buffer_len(server_kexinit), - server_host_key_blob, sbloblen, - dh->pub_key, - dh_server_pub, - shared_secret - ); - xfree(server_host_key_blob); - DH_free(dh); -#ifdef DEBUG_KEXDH - fprintf(stderr, "hash == "); - for (i = 0; i< 20; i++) - fprintf(stderr, "%02x", (hash[i])&0xff); - fprintf(stderr, "\n"); -#endif - if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) - fatal("dsa_verify failed for server_host_key"); - key_free(server_host_key); - - kex_derive_keys(kex, hash, shared_secret); - packet_set_kex(kex); - - /* save session id */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); -} - -/* diffie-hellman-group-exchange-sha1 */ - -/* - * Estimates the group order for a Diffie-Hellman group that has an - * attack complexity approximately the same as O(2**bits). Estimate - * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) - */ - -int -dh_estimate(int bits) -{ - - if (bits < 64) - return (512); /* O(2**63) */ - if (bits < 128) - return (1024); /* O(2**86) */ - if (bits < 192) - return (2048); /* O(2**116) */ - return (4096); /* O(2**156) */ -} - -void -ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, - Buffer *client_kexinit, Buffer *server_kexinit) -{ -#ifdef DEBUG_KEXDH - int i; -#endif - int plen, dlen; - unsigned int klen, kout; - char *signature = NULL; - unsigned int slen, nbits; - char *server_host_key_blob = NULL; - Key *server_host_key; - unsigned int sbloblen; - DH *dh; - BIGNUM *dh_server_pub = 0; - BIGNUM *shared_secret = 0; - BIGNUM *p = 0, *g = 0; - unsigned char *kbuf; - unsigned char *hash; - - nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8); - - debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST."); - packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); - packet_put_int(nbits); - packet_send(); - packet_write_wait(); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\nnbits = %d", nbits); -#endif - - debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP."); - - packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); - - debug("Got SSH2_MSG_KEX_DH_GEX_GROUP."); - - if ((p = BN_new()) == NULL) - fatal("BN_new"); - packet_get_bignum2(p, &dlen); - if ((g = BN_new()) == NULL) - fatal("BN_new"); - packet_get_bignum2(g, &dlen); - if ((dh = dh_new_group(g, p)) == NULL) - fatal("dh_new_group"); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\np= "); - BN_print_fp(stderr, dh->p); - fprintf(stderr, "\ng= "); - BN_print_fp(stderr, dh->g); - fprintf(stderr, "\npub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); - DHparams_print_fp(stderr, dh); -#endif - - debug("Sending SSH2_MSG_KEX_DH_GEX_INIT."); - /* generate and send 'e', client DH public key */ - packet_start(SSH2_MSG_KEX_DH_GEX_INIT); - packet_put_bignum2(dh->pub_key); - packet_send(); - packet_write_wait(); - - debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY."); - - packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); - - debug("Got SSH2_MSG_KEXDH_REPLY."); - - /* key, cert */ - server_host_key_blob = packet_get_string(&sbloblen); - server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen); - if (server_host_key == NULL) - fatal("cannot decode server_host_key_blob"); - - check_host_key(host, hostaddr, server_host_key, - options.user_hostfile2, options.system_hostfile2); - - /* DH paramter f, server public DH key */ - dh_server_pub = BN_new(); - if (dh_server_pub == NULL) - fatal("dh_server_pub == NULL"); - packet_get_bignum2(dh_server_pub, &dlen); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\ndh_server_pub= "); - BN_print_fp(stderr, dh_server_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_server_pub)); -#endif - - /* signed H */ - signature = packet_get_string(&slen); - packet_done(); - - if (!dh_pub_is_valid(dh, dh_server_pub)) - packet_disconnect("bad server public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_server_pub, dh); -#ifdef DEBUG_KEXDH - debug("shared secret: len %d/%d", klen, kout); - fprintf(stderr, "shared secret == "); - for (i = 0; i< kout; i++) - fprintf(stderr, "%02x", (kbuf[i])&0xff); - fprintf(stderr, "\n"); -#endif - shared_secret = BN_new(); - - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - /* calc and verify H */ - hash = kex_hash_gex( - client_version_string, - server_version_string, - buffer_ptr(client_kexinit), buffer_len(client_kexinit), - buffer_ptr(server_kexinit), buffer_len(server_kexinit), - server_host_key_blob, sbloblen, - nbits, dh->p, dh->g, - dh->pub_key, - dh_server_pub, - shared_secret - ); - xfree(server_host_key_blob); - DH_free(dh); -#ifdef DEBUG_KEXDH - fprintf(stderr, "hash == "); - for (i = 0; i< 20; i++) - fprintf(stderr, "%02x", (hash[i])&0xff); - fprintf(stderr, "\n"); -#endif - if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1) - fatal("dsa_verify failed for server_host_key"); - key_free(server_host_key); - - kex_derive_keys(kex, hash, shared_secret); - packet_set_kex(kex); - - /* save session id */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); + debug("done: ssh_kex2."); } /* @@ -452,15 +148,24 @@ typedef struct Authmethod Authmethod; typedef int sign_cb_fn( Authctxt *authctxt, Key *key, - unsigned char **sigp, int *lenp, unsigned char *data, int datalen); + u_char **sigp, int *lenp, u_char *data, int datalen); struct Authctxt { const char *server_user; + const char *local_user; const char *host; const char *service; - AuthenticationConnection *agent; Authmethod *method; int success; + char *authlist; + /* pubkey */ + Key *last_key; + sign_cb_fn *last_key_sign; + int last_key_hint; + AuthenticationConnection *agent; + /* hostbased */ + Key **keys; + int nkeys; }; struct Authmethod { char *name; /* string to compare against server's list */ @@ -471,22 +176,32 @@ struct Authmethod { void input_userauth_success(int type, int plen, void *ctxt); void input_userauth_failure(int type, int plen, void *ctxt); +void input_userauth_banner(int type, int plen, void *ctxt); void input_userauth_error(int type, int plen, void *ctxt); void input_userauth_info_req(int type, int plen, void *ctxt); +void input_userauth_pk_ok(int type, int plen, void *ctxt); int userauth_none(Authctxt *authctxt); int userauth_pubkey(Authctxt *authctxt); int userauth_passwd(Authctxt *authctxt); int userauth_kbdint(Authctxt *authctxt); +int userauth_hostbased(Authctxt *authctxt); + +void userauth(Authctxt *authctxt, char *authlist); + +int +sign_and_send_pubkey(Authctxt *authctxt, Key *k, + sign_cb_fn *sign_callback); +void clear_auth_state(Authctxt *authctxt); -void authmethod_clear(); Authmethod *authmethod_get(char *authlist); Authmethod *authmethod_lookup(const char *name); +char *authmethods_get(void); Authmethod authmethods[] = { {"publickey", userauth_pubkey, - &options.dsa_authentication, + &options.pubkey_authentication, NULL}, {"password", userauth_passwd, @@ -496,6 +211,10 @@ Authmethod authmethods[] = { userauth_kbdint, &options.kbd_interactive_authentication, &options.batch_mode}, + {"hostbased", + userauth_hostbased, + &options.hostbased_authentication, + NULL}, {"none", userauth_none, NULL, @@ -504,12 +223,16 @@ Authmethod authmethods[] = { }; void -ssh_userauth2(const char *server_user, char *host) +ssh_userauth2(const char *local_user, const char *server_user, char *host, + Key **keys, int nkeys) { Authctxt authctxt; int type; int plen; + if (options.challenge_reponse_authentication) + options.kbd_interactive_authentication = 1; + debug("send SSH2_MSG_SERVICE_REQUEST"); packet_start(SSH2_MSG_SERVICE_REQUEST); packet_put_cstring("ssh-userauth"); @@ -523,23 +246,28 @@ ssh_userauth2(const char *server_user, char *host) char *reply = packet_get_string(&plen); debug("service_accept: %s", reply); xfree(reply); - packet_done(); } else { debug("buggy server: service_accept w/o service"); } packet_done(); debug("got SSH2_MSG_SERVICE_ACCEPT"); + if (options.preferred_authentications == NULL) + options.preferred_authentications = authmethods_get(); + /* setup authentication context */ authctxt.agent = ssh_get_authentication_connection(); authctxt.server_user = server_user; + authctxt.local_user = local_user; authctxt.host = host; authctxt.service = "ssh-connection"; /* service name */ authctxt.success = 0; authctxt.method = authmethod_lookup("none"); + authctxt.authlist = NULL; + authctxt.keys = keys; + authctxt.nkeys = nkeys; if (authctxt.method == NULL) fatal("ssh_userauth2: internal error: cannot send userauth none request"); - authmethod_clear(); /* initial userauth request */ userauth_none(&authctxt); @@ -547,17 +275,54 @@ ssh_userauth2(const char *server_user, char *host) dispatch_init(&input_userauth_error); dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); + dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ if (authctxt.agent != NULL) ssh_close_authentication_connection(authctxt.agent); - debug("ssh-userauth2 successfull: method %s", authctxt.method->name); + debug("ssh-userauth2 successful: method %s", authctxt.method->name); +} +void +userauth(Authctxt *authctxt, char *authlist) +{ + if (authlist == NULL) { + authlist = authctxt->authlist; + } else { + if (authctxt->authlist) + xfree(authctxt->authlist); + authctxt->authlist = authlist; + } + for (;;) { + Authmethod *method = authmethod_get(authlist); + if (method == NULL) + fatal("Permission denied (%s).", authlist); + authctxt->method = method; + if (method->userauth(authctxt) != 0) { + debug2("we sent a %s packet, wait for reply", method->name); + break; + } else { + debug2("we did not send a packet, disable method"); + method->enabled = NULL; + } + } } void input_userauth_error(int type, int plen, void *ctxt) { - fatal("input_userauth_error: bad message during authentication"); + fatal("input_userauth_error: bad message during authentication: " + "type %d", type); +} +void +input_userauth_banner(int type, int plen, void *ctxt) +{ + char *msg, *lang; + debug3("input_userauth_banner"); + msg = packet_get_string(NULL); + lang = packet_get_string(NULL); + fprintf(stderr, "%s", msg); + xfree(msg); + xfree(lang); } void input_userauth_success(int type, int plen, void *ctxt) @@ -565,12 +330,14 @@ input_userauth_success(int type, int plen, void *ctxt) Authctxt *authctxt = ctxt; if (authctxt == NULL) fatal("input_userauth_success: no authentication context"); + if (authctxt->authlist) + xfree(authctxt->authlist); + clear_auth_state(authctxt); authctxt->success = 1; /* break out */ } void input_userauth_failure(int type, int plen, void *ctxt) { - Authmethod *method = NULL; Authctxt *authctxt = ctxt; char *authlist = NULL; int partial; @@ -583,23 +350,78 @@ input_userauth_failure(int type, int plen, void *ctxt) packet_done(); if (partial != 0) - debug("partial success"); + log("Authenticated with partial success."); debug("authentications that can continue: %s", authlist); - for (;;) { - method = authmethod_get(authlist); - if (method == NULL) - fatal("Unable to find an authentication method"); - authctxt->method = method; - if (method->userauth(authctxt) != 0) { - debug2("we sent a %s packet, wait for reply", method->name); + clear_auth_state(authctxt); + userauth(authctxt, authlist); +} +void +input_userauth_pk_ok(int type, int plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Key *key = NULL; + Buffer b; + int alen, blen, sent = 0; + char *pkalg, *pkblob, *fp; + + if (authctxt == NULL) + fatal("input_userauth_pk_ok: no authentication context"); + if (datafellows & SSH_BUG_PKOK) { + /* this is similar to SSH_BUG_PKAUTH */ + debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); + pkblob = packet_get_string(&blen); + buffer_init(&b); + buffer_append(&b, pkblob, blen); + pkalg = buffer_get_string(&b, &alen); + buffer_free(&b); + } else { + pkalg = packet_get_string(&alen); + pkblob = packet_get_string(&blen); + } + packet_done(); + + debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d", + pkalg, blen, authctxt->last_key, authctxt->last_key_hint); + + do { + if (authctxt->last_key == NULL || + authctxt->last_key_sign == NULL) { + debug("no last key or no sign cb"); break; - } else { - debug2("we did not send a packet, disable method"); - method->enabled = NULL; } - } - xfree(authlist); + if (key_type_from_name(pkalg) == KEY_UNSPEC) { + debug("unknown pkalg %s", pkalg); + break; + } + if ((key = key_from_blob(pkblob, blen)) == NULL) { + debug("no key from blob. pkalg %s", pkalg); + break; + } + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + debug2("input_userauth_pk_ok: fp %s", fp); + xfree(fp); + if (!key_equal(key, authctxt->last_key)) { + debug("key != last_key"); + break; + } + sent = sign_and_send_pubkey(authctxt, key, + authctxt->last_key_sign); + } while(0); + + if (key != NULL) + key_free(key); + xfree(pkalg); + xfree(pkblob); + + /* unregister */ + clear_auth_state(authctxt); + dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL); + + /* try another method if we did not send a packet*/ + if (sent == 0) + userauth(authctxt, NULL); + } int @@ -611,7 +433,6 @@ userauth_none(Authctxt *authctxt) packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_send(); - packet_write_wait(); return 1; } @@ -628,7 +449,7 @@ userauth_passwd(Authctxt *authctxt) if(attempt != 1) error("Permission denied, please try again."); - snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", + snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", authctxt->server_user, authctxt->host); password = read_passphrase(prompt, 0); packet_start(SSH2_MSG_USERAUTH_REQUEST); @@ -639,28 +460,46 @@ userauth_passwd(Authctxt *authctxt) ssh_put_password(password); memset(password, 0, strlen(password)); xfree(password); + packet_inject_ignore(64); packet_send(); - packet_write_wait(); return 1; } +void +clear_auth_state(Authctxt *authctxt) +{ + /* XXX clear authentication state */ + if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) { + debug3("clear_auth_state: key_free %p", authctxt->last_key); + key_free(authctxt->last_key); + } + authctxt->last_key = NULL; + authctxt->last_key_hint = -2; + authctxt->last_key_sign = NULL; +} + int sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) { Buffer b; - unsigned char *blob, *signature; + u_char *blob, *signature; int bloblen, slen; int skip = 0; int ret = -1; int have_sig = 1; - dsa_make_key_blob(k, &blob, &bloblen); + debug3("sign_and_send_pubkey"); + if (key_to_blob(k, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + debug3("sign_and_send_pubkey: cannot handle key"); + return 0; + } /* data to be signed */ buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); - skip = session_id2_len; + skip = session_id2_len; } else { buffer_put_string(&b, session_id2, session_id2_len); skip = buffer_len(&b); @@ -668,36 +507,44 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->server_user); buffer_put_cstring(&b, - datafellows & SSH_BUG_PUBKEYAUTH ? + datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); - buffer_put_cstring(&b, authctxt->method->name); - 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, authctxt->method->name); + buffer_put_char(&b, have_sig); + buffer_put_cstring(&b, key_ssh_name(k)); + } buffer_put_string(&b, blob, bloblen); /* generate signature */ - ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); + ret = (*sign_callback)(authctxt, k, &signature, &slen, + buffer_ptr(&b), buffer_len(&b)); if (ret == -1) { xfree(blob); buffer_free(&b); return 0; } -#ifdef DEBUG_DSS +#ifdef DEBUG_PK buffer_dump(&b); #endif - if (datafellows & SSH_BUG_PUBKEYAUTH) { + if (datafellows & SSH_BUG_PKSERVICE) { buffer_clear(&b); buffer_append(&b, session_id2, session_id2_len); + skip = session_id2_len; buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->server_user); buffer_put_cstring(&b, authctxt->service); buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); - buffer_put_cstring(&b, KEX_DSS); + if (!(datafellows & SSH_BUG_PKAUTH)) + buffer_put_cstring(&b, key_ssh_name(k)); buffer_put_string(&b, blob, bloblen); } xfree(blob); + /* append signature */ buffer_put_string(&b, signature, slen); xfree(signature); @@ -711,96 +558,137 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_raw(buffer_ptr(&b), buffer_len(&b)); buffer_free(&b); - - /* send */ packet_send(); - packet_write_wait(); return 1; } -/* sign callback */ -int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, - unsigned char *data, int datalen) +int +send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback, + int hint) { - return dsa_sign(key, sigp, lenp, data, datalen); + u_char *blob; + int bloblen, have_sig = 0; + + debug3("send_pubkey_test"); + + if (key_to_blob(k, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + debug3("send_pubkey_test: cannot handle key"); + return 0; + } + /* register callback for USERAUTH_PK_OK message */ + authctxt->last_key_sign = sign_callback; + authctxt->last_key_hint = hint; + authctxt->last_key = k; + dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); + + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_char(have_sig); + if (!(datafellows & SSH_BUG_PKAUTH)) + packet_put_cstring(key_ssh_name(k)); + packet_put_string(blob, bloblen); + xfree(blob); + packet_send(); + return 1; } -int -userauth_pubkey_identity(Authctxt *authctxt, char *filename) +Key * +load_identity_file(char *filename) { - Key *k; - int i, ret, try_next; + Key *private; + char prompt[300], *passphrase; + int quit, i; struct stat st; - if (stat(filename, &st) != 0) { - debug("key does not exist: %s", filename); - return 0; + if (stat(filename, &st) < 0) { + debug3("no such identity: %s", filename); + return NULL; } - debug("try pubkey: %s", filename); - - k = key_new(KEY_DSA); - if (!load_private_key(filename, "", k, NULL)) { - int success = 0; - char *passphrase; - char prompt[300]; + private = key_load_private_type(KEY_UNSPEC, filename, "", NULL); + if (private == NULL) { + if (options.batch_mode) + return NULL; snprintf(prompt, sizeof prompt, - "Enter passphrase for %s key '%.100s': ", - key_type(k), filename); + "Enter passphrase for key '%.100s': ", filename); for (i = 0; i < options.number_of_password_prompts; i++) { passphrase = read_passphrase(prompt, 0); if (strcmp(passphrase, "") != 0) { - success = load_private_key(filename, passphrase, k, NULL); - try_next = 0; + private = key_load_private_type(KEY_UNSPEC, filename, + passphrase, NULL); + quit = 0; } else { debug2("no passphrase given, try next key"); - try_next = 1; + quit = 1; } memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); - if (success || try_next) + if (private != NULL || quit) break; debug2("bad passphrase given, try again..."); } - if (!success) { - key_free(k); - return 0; - } } - ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb); - key_free(k); + return private; +} + +int +identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, + u_char *data, int datalen) +{ + Key *private; + int idx, ret; + + idx = authctxt->last_key_hint; + if (idx < 0) + return -1; + private = load_identity_file(options.identity_files[idx]); + if (private == NULL) + return -1; + ret = key_sign(private, sigp, lenp, data, datalen); + key_free(private); return ret; } -/* sign callback */ -int agent_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, - unsigned char *data, int datalen) +int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, + u_char *data, int datalen) { return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen); } +int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp, + u_char *data, int datalen) +{ + return key_sign(key, sigp, lenp, data, datalen); +} + int userauth_pubkey_agent(Authctxt *authctxt) { static int called = 0; + int ret = 0; char *comment; Key *k; - int ret; if (called == 0) { - k = ssh_get_first_identity(authctxt->agent, &comment, 2); + if (ssh_get_num_identities(authctxt->agent, 2) == 0) + debug2("userauth_pubkey_agent: no keys at all"); called = 1; - } else { - k = ssh_get_next_identity(authctxt->agent, &comment, 2); } + k = ssh_get_next_identity(authctxt->agent, &comment, 2); if (k == NULL) { - debug2("no more DSA keys from agent"); - return 0; + debug2("userauth_pubkey_agent: no more keys"); + } else { + debug("userauth_pubkey_agent: testing agent key %s", comment); + xfree(comment); + ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1); + if (ret == 0) + key_free(k); } - debug("trying DSA agent key %s", comment); - xfree(comment); - ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); - key_free(k); + if (ret == 0) + debug2("userauth_pubkey_agent: no message sent"); return ret; } @@ -809,11 +697,32 @@ userauth_pubkey(Authctxt *authctxt) { static int idx = 0; int sent = 0; + Key *key; + char *filename; - if (authctxt->agent != NULL) - sent = userauth_pubkey_agent(authctxt); - while (sent == 0 && idx < options.num_identity_files2) - sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]); + if (authctxt->agent != NULL) { + do { + sent = userauth_pubkey_agent(authctxt); + } while(!sent && authctxt->agent->howmany > 0); + } + while (!sent && idx < options.num_identity_files) { + key = options.identity_keys[idx]; + filename = options.identity_files[idx]; + if (key == NULL) { + debug("try privkey: %s", filename); + key = load_identity_file(filename); + if (key != NULL) { + sent = sign_and_send_pubkey(authctxt, key, + key_sign_cb); + key_free(key); + } + } else if (key->type != KEY_RSA1) { + debug("try pubkey: %s", filename); + sent = send_pubkey_test(authctxt, key, + identity_sign_cb, idx); + } + idx++; + } return sent; } @@ -837,26 +746,20 @@ userauth_kbdint(Authctxt *authctxt) packet_put_cstring(options.kbd_interactive_devices ? options.kbd_interactive_devices : ""); packet_send(); - packet_write_wait(); dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); return 1; } /* - * parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send - * SSH2_MSG_USERAUTH_INFO_RESPONSE + * parse INFO_REQUEST, prompt user and send INFO_RESPONSE */ void input_userauth_info_req(int type, int plen, void *ctxt) { Authctxt *authctxt = ctxt; - char *name = NULL; - char *inst = NULL; - char *lang = NULL; - char *prompt = NULL; - char *response = NULL; - unsigned int num_prompts, i; + char *name, *inst, *lang, *prompt, *response; + u_int num_prompts, i; int echo = 0; debug2("input_userauth_info_req"); @@ -867,15 +770,13 @@ input_userauth_info_req(int type, int plen, void *ctxt) name = packet_get_string(NULL); inst = packet_get_string(NULL); lang = packet_get_string(NULL); - if (strlen(name) > 0) cli_mesg(name); - xfree(name); - if (strlen(inst) > 0) cli_mesg(inst); + xfree(name); xfree(inst); - xfree(lang); /* unused */ + xfree(lang); num_prompts = packet_get_int(); /* @@ -900,45 +801,101 @@ input_userauth_info_req(int type, int plen, void *ctxt) } packet_done(); /* done with parsing incoming message. */ + packet_inject_ignore(64); packet_send(); - packet_write_wait(); } -/* find auth method */ - -#define DELIM "," - -static char *def_authlist = "publickey,password"; -static char *authlist_current = NULL; /* clean copy used for comparison */ -static char *authname_current = NULL; /* last used auth method */ -static char *authlist_working = NULL; /* copy that gets modified by strtok_r() */ -static char *authlist_state = NULL; /* state variable for strtok_r() */ - /* - * Before starting to use a new authentication method list sent by the - * server, reset internal variables. This should also be called when - * finished processing server list to free resources. + * this will be move to an external program (ssh-keysign) ASAP. ssh-keysign + * will be setuid-root and the sbit can be removed from /usr/bin/ssh. */ -void -authmethod_clear() +int +userauth_hostbased(Authctxt *authctxt) { - if (authlist_current != NULL) { - xfree(authlist_current); - authlist_current = NULL; + Key *private = NULL; + Buffer b; + u_char *signature, *blob; + char *chost, *pkalg, *p; + const char *service; + u_int blen, slen; + int ok, i, len, found = 0; + + p = get_local_name(packet_get_connection_in()); + if (p == NULL) { + error("userauth_hostbased: cannot get local ipaddr/name"); + return 0; } - if (authlist_working != NULL) { - xfree(authlist_working); - authlist_working = NULL; + len = strlen(p) + 2; + chost = xmalloc(len); + strlcpy(chost, p, len); + strlcat(chost, ".", len); + debug2("userauth_hostbased: chost %s", chost); + /* check for a useful key */ + for (i = 0; i < authctxt->nkeys; i++) { + private = authctxt->keys[i]; + if (private && private->type != KEY_RSA1) { + found = 1; + /* we take and free the key */ + authctxt->keys[i] = NULL; + break; + } } - if (authname_current != NULL) { - xfree(authname_current); - authlist_state = NULL; + if (!found) { + xfree(chost); + return 0; + } + if (key_to_blob(private, &blob, &blen) == 0) { + key_free(private); + xfree(chost); + return 0; + } + service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : + authctxt->service; + pkalg = xstrdup(key_ssh_name(private)); + buffer_init(&b); + /* construct data */ + buffer_put_string(&b, session_id2, session_id2_len); + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->server_user); + buffer_put_cstring(&b, service); + buffer_put_cstring(&b, authctxt->method->name); + buffer_put_cstring(&b, pkalg); + buffer_put_string(&b, blob, blen); + buffer_put_cstring(&b, chost); + buffer_put_cstring(&b, authctxt->local_user); +#ifdef DEBUG_PK + buffer_dump(&b); +#endif + debug2("xxx: chost %s", chost); + ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); + key_free(private); + buffer_free(&b); + if (ok != 0) { + error("key_sign failed"); + xfree(chost); + xfree(pkalg); + return 0; } - if (authlist_state != NULL) - authlist_state = NULL; - return; + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_cstring(pkalg); + packet_put_string(blob, blen); + packet_put_cstring(chost); + packet_put_cstring(authctxt->local_user); + packet_put_string(signature, slen); + memset(signature, 's', slen); + xfree(signature); + xfree(chost); + xfree(pkalg); + + packet_send(); + return 1; } +/* find auth method */ + /* * given auth method name, if configurable options permit this method fill * in auth_ident field and return true, otherwise return false. @@ -969,62 +926,70 @@ authmethod_lookup(const char *name) return NULL; } +/* XXX internal state */ +static Authmethod *current = NULL; +static char *supported = NULL; +static char *preferred = NULL; /* * Given the authentication method list sent by the server, return the * next method we should try. If the server initially sends a nil list, - * use a built-in default list. If the server sends a nil list after - * previously sending a valid list, continue using the list originally - * sent. - */ - + * use a built-in default list. + */ Authmethod * authmethod_get(char *authlist) { - char *name = NULL, *authname_old; - Authmethod *method = NULL; - + + char *name = NULL; + int next; + /* Use a suitable default if we're passed a nil list. */ if (authlist == NULL || strlen(authlist) == 0) - authlist = def_authlist; - - if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) { - /* start over if passed a different list */ - debug3("start over, passed a different list"); - authmethod_clear(); - authlist_current = xstrdup(authlist); - authlist_working = xstrdup(authlist); - name = strtok_r(authlist_working, DELIM, &authlist_state); - } else { - /* - * try to use previously used authentication method - * or continue to use previously passed list - */ - name = (authname_current != NULL) ? - authname_current : strtok_r(NULL, DELIM, &authlist_state); - } + authlist = options.preferred_authentications; + + if (supported == NULL || strcmp(authlist, supported) != 0) { + debug3("start over, passed a different list %s", authlist); + if (supported != NULL) + xfree(supported); + supported = xstrdup(authlist); + preferred = options.preferred_authentications; + debug3("preferred %s", preferred); + current = NULL; + } else if (current != NULL && authmethod_is_enabled(current)) + return current; - while (name != NULL) { + for (;;) { + if ((name = match_list(preferred, supported, &next)) == NULL) { + debug("no more auth methods to try"); + current = NULL; + return NULL; + } + preferred += next; debug3("authmethod_lookup %s", name); - method = authmethod_lookup(name); - if (method != NULL && authmethod_is_enabled(method)) { + debug3("remaining preferred: %s", preferred); + if ((current = authmethod_lookup(name)) != NULL && + authmethod_is_enabled(current)) { debug3("authmethod_is_enabled %s", name); - break; + debug("next auth method to try is %s", name); + return current; } - name = strtok_r(NULL, DELIM, &authlist_state); - method = NULL; - } - - authname_old = authname_current; - if (method != NULL) { - debug("next auth method to try is %s", name); - authname_current = xstrdup(name); - } else { - debug("no more auth methods to try"); - authname_current = NULL; } +} - if (authname_old != NULL) - xfree(authname_old); - return (method); +#define DELIM "," +char * +authmethods_get(void) +{ + Authmethod *method = NULL; + char buf[1024]; + + buf[0] = '\0'; + for (method = authmethods; method->name != NULL; method++) { + if (authmethod_is_enabled(method)) { + if (buf[0] != '\0') + strlcat(buf, DELIM, sizeof buf); + strlcat(buf, method->name, sizeof buf); + } + } + return xstrdup(buf); } diff --git a/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8 index c8ab125..0292473 100644 --- a/crypto/openssh/sshd.8 +++ b/crypto/openssh/sshd.8 @@ -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 +.Pp +If this option is set to .Dq without-password -only password authentication is disabled for root. +password authentication is disabled for root. .Pp -Root login with RSA authentication when the +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 diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 89fb0ae..61dbf06 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -40,15 +40,22 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.132 2000/10/13 18:34:46 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.195 2001/04/15 16:58:03 markus Exp $"); RCSID("$FreeBSD$"); +#include <openssl/dh.h> +#include <openssl/bn.h> +#include <openssl/hmac.h> + +#include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" #include "xmalloc.h" #include "rsa.h" -#include "ssh.h" -#include "pty.h" +#include "sshpty.h" #include "packet.h" #include "mpaux.h" +#include "log.h" #include "servconf.h" #include "uidswap.h" #include "compat.h" @@ -56,20 +63,18 @@ RCSID("$FreeBSD$"); #include <poll.h> #include <time.h> -#include "ssh2.h" -#include <openssl/dh.h> -#include <openssl/bn.h> -#include <openssl/hmac.h> +#include "cipher.h" #include "kex.h" -#include <openssl/dsa.h> -#include <openssl/rsa.h> #include "key.h" -#include "dsa.h" #include "dh.h" - -#include "auth.h" #include "myproposal.h" #include "authfile.h" +#include "pathnames.h" +#include "atomicio.h" +#include "canohost.h" +#include "auth.h" +#include "misc.h" +#include "dispatch.h" #ifdef LIBWRAP #include <tcpd.h> @@ -86,11 +91,13 @@ int deny_severity = LOG_WARNING; #include <krb5.h> #endif /* KRB5 */ +extern char *__progname; + /* Server configuration options. */ ServerOptions options; /* Name of the server configuration file. */ -char *config_file_name = SERVER_CONFIG_FILE; +char *config_file_name = _PATH_SERVER_CONFIG_FILE; /* * Flag indicating whether IPv4 or IPv6. This can be set on the command line. @@ -109,12 +116,12 @@ int debug_flag = 0; /* Flag indicating that the daemon is being started from inetd. */ int inetd_flag = 0; +/* Flag indicating that sshd should not detach and become a daemon. */ +int no_daemon_flag = 0; + /* debug goes to stderr unless inetd_flag is set */ int log_stderr = 0; -/* argv[0] without path. */ -char *av0; - /* Saved arguments to main(). */ char **saved_argv; @@ -133,6 +140,9 @@ int num_listen_socks = 0; char *client_version_string = NULL; char *server_version_string = NULL; +/* for rekeying XXX fixme */ +Kex *xxx_kex; + /* * Any really sensitive data in the application is contained in this * structure. The idea is that this structure could be locked into memory so @@ -142,37 +152,36 @@ char *server_version_string = NULL; * not very useful. Currently, memory locking is not implemented. */ struct { - RSA *private_key; /* Private part of empheral server key. */ - RSA *host_key; /* Private part of host key. */ - Key *dsa_host_key; /* Private DSA host key. */ + Key *server_key; /* ephemeral server key */ + Key *ssh1_host_key; /* ssh1 host key */ + Key **host_keys; /* all private host keys */ + int have_ssh1_key; + int have_ssh2_key; + u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; } sensitive_data; /* - * Flag indicating whether the current session key has been used. This flag - * is set whenever the key is used, and cleared when the key is regenerated. + * Flag indicating whether the RSA server key needs to be regenerated. + * Is set in the SIGALRM handler and cleared when the key is regenerated. */ -int key_used = 0; +int key_do_regen = 0; /* This is set to true when SIGHUP is received. */ int received_sighup = 0; -/* Public side of the server key. This value is regenerated regularly with - the private key. */ -RSA *public_key; - /* session identifier, used by RSA-auth */ -unsigned char session_id[16]; +u_char session_id[16]; /* same for ssh2 */ -unsigned char *session_id2 = NULL; +u_char *session_id2 = NULL; int session_id2_len = 0; /* record remote hostname or ip */ -unsigned int utmp_len = MAXHOSTNAMELEN; +u_int utmp_len = MAXHOSTNAMELEN; /* Prototypes for various functions defined later in this file. */ -void do_ssh1_kex(); -void do_ssh2_kex(); +void do_ssh1_kex(void); +void do_ssh2_kex(void); void ssh_dh1_server(Kex *, Buffer *_kexinit, Buffer *); void ssh_dhgex_server(Kex *, Buffer *_kexinit, Buffer *); @@ -206,13 +215,12 @@ sighup_handler(int sig) * Restarts the server. */ void -sighup_restart() +sighup_restart(void) { log("Received SIGHUP; restarting."); close_listen_socks(); execv(saved_argv[0], saved_argv); - execv("/proc/curproc/file", saved_argv); - log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno)); + log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno)); exit(1); } @@ -267,35 +275,36 @@ grace_alarm_handler(int sig) * Thus there should be no concurrency control/asynchronous execution * problems. */ -/* XXX do we really want this work to be done in a signal handler ? -m */ void -key_regeneration_alarm(int sig) +generate_ephemeral_server_key(void) { - int save_errno = errno; - - /* Check if we should generate a new key. */ - if (key_used) { - /* This should really be done in the background. */ - log("Generating new %d bit RSA key.", options.server_key_bits); - - if (sensitive_data.private_key != NULL) - RSA_free(sensitive_data.private_key); - sensitive_data.private_key = RSA_new(); + u_int32_t rand = 0; + int i; - if (public_key != NULL) - RSA_free(public_key); - public_key = RSA_new(); + verbose("Generating %s%d bit RSA key.", + sensitive_data.server_key ? "new " : "", options.server_key_bits); + if (sensitive_data.server_key != NULL) + key_free(sensitive_data.server_key); + sensitive_data.server_key = key_generate(KEY_RSA1, + options.server_key_bits); + verbose("RSA key generation complete."); - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); - key_used = 0; - log("RSA key generation complete."); + for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { + if (i % 4 == 0) + rand = arc4random(); + sensitive_data.ssh1_cookie[i] = rand & 0xff; + rand >>= 8; } - /* Reschedule the alarm. */ - signal(SIGALRM, key_regeneration_alarm); - alarm(options.key_regeneration_time); + arc4random_stir(); +} + +void +key_regeneration_alarm(int sig) +{ + int save_errno = errno; + signal(SIGALRM, SIG_DFL); errno = save_errno; + key_do_regen = 1; } void @@ -330,15 +339,16 @@ sshd_exchange_identification(int sock_in, int sock_out) fatal_cleanup(); } - /* Read other side\'s version identification. */ + /* Read other side's version identification. */ + memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { - log("Did not receive ident string from %s.", get_remote_ipaddr()); + log("Did not receive identification string from %s.", + get_remote_ipaddr()); fatal_cleanup(); } if (buf[i] == '\r') { - buf[i] = '\n'; - buf[i + 1] = 0; + buf[i] = 0; /* Kludge for F-Secure Macintosh < 1.0.2 */ if (i == 12 && strncmp(buf, "SSH-1.5-W1.0", 12) == 0) @@ -346,8 +356,7 @@ sshd_exchange_identification(int sock_in, int sock_out) continue; } if (buf[i] == '\n') { - /* buf[i] == '\n' */ - buf[i + 1] = 0; + buf[i] = 0; break; } } @@ -374,6 +383,12 @@ sshd_exchange_identification(int sock_in, int sock_out) compat_datafellows(remote_version); + if (datafellows & SSH_BUG_SCANNER) { + log("scanned from %s with %s. Don't panic.", + get_remote_ipaddr(), client_version_string); + fatal_cleanup(); + } + mismatch = 0; switch(remote_major) { case 1: @@ -407,7 +422,6 @@ sshd_exchange_identification(int sock_in, int sock_out) break; } chop(server_version_string); - chop(client_version_string); debug("Local version string %.200s", server_version_string); if (mismatch) { @@ -425,18 +439,61 @@ sshd_exchange_identification(int sock_in, int sock_out) } +/* Destroy the host and server keys. They will no longer be needed. */ void destroy_sensitive_data(void) { - /* Destroy the private and public keys. They will no longer be needed. */ - if (public_key) - RSA_free(public_key); - if (sensitive_data.private_key) - RSA_free(sensitive_data.private_key); - if (sensitive_data.host_key) - RSA_free(sensitive_data.host_key); - if (sensitive_data.dsa_host_key != NULL) - key_free(sensitive_data.dsa_host_key); + int i; + + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } + for(i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; + } + } + sensitive_data.ssh1_host_key = NULL; + memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); +} + +char * +list_hostkey_types(void) +{ + static char buf[1024]; + int i; + buf[0] = '\0'; + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key == NULL) + continue; + switch(key->type) { + case KEY_RSA: + case KEY_DSA: + strlcat(buf, key_ssh_name(key), sizeof buf); + strlcat(buf, ",", sizeof buf); + break; + } + } + i = strlen(buf); + if (i > 0 && buf[i-1] == ',') + buf[i-1] = '\0'; + debug("list_hostkey_types: %s", buf); + return buf; +} + +Key * +get_hostkey_by_type(int type) +{ + int i; + for(i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key != NULL && key->type == type) + return key; + } + return NULL; } /* @@ -482,7 +539,6 @@ main(int ac, char **av) int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1; pid_t pid; socklen_t fromlen; - int silent = 0; fd_set *fdset; struct sockaddr_storage from; const char *remote_ip; @@ -494,19 +550,17 @@ main(int ac, char **av) int listen_sock, maxfd; int startup_p[2]; int startups = 0; + Key *key; + int ret, key_used = 0; - /* Save argv[0]. */ + /* Save argv. */ saved_argv = av; - if (strchr(av[0], '/')) - av0 = strrchr(av[0], '/') + 1; - else - av0 = av[0]; /* Initialize configuration options to their default values. */ initialize_server_options(&options); /* Parse command-line arguments. */ - while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:diqQ46")) != EOF) { + while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:dDeiqQ46")) != -1) { switch (opt) { case '4': IPv4or6 = AF_INET; @@ -528,11 +582,17 @@ main(int ac, char **av) exit(1); } break; + case 'D': + no_daemon_flag = 1; + break; + case 'e': + log_stderr = 1; + break; case 'i': inetd_flag = 1; break; case 'Q': - silent = 1; + /* ignored */ break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; @@ -546,7 +606,11 @@ main(int ac, char **av) fprintf(stderr, "too many ports.\n"); exit(1); } - options.ports[options.num_ports++] = atoi(optarg); + options.ports[options.num_ports++] = a2port(optarg); + if (options.ports[options.num_ports-1] == 0) { + fprintf(stderr, "Bad port number.\n"); + exit(1); + } break; case 'g': options.login_grace_time = atoi(optarg); @@ -555,7 +619,11 @@ main(int ac, char **av) options.key_regeneration_time = atoi(optarg); break; case 'h': - options.host_key_file = optarg; + if (options.num_host_key_files >= MAX_HOSTKEYS) { + fprintf(stderr, "too many host keys.\n"); + exit(1); + } + options.host_key_files[options.num_host_key_files++] = optarg; break; case 'V': client_version_string = optarg; @@ -568,33 +636,35 @@ main(int ac, char **av) case '?': default: fprintf(stderr, "sshd version %s\n", SSH_VERSION); - fprintf(stderr, "Usage: %s [options]\n", av0); + fprintf(stderr, "Usage: %s [options]\n", __progname); fprintf(stderr, "Options:\n"); - fprintf(stderr, " -f file Configuration file (default %s)\n", SERVER_CONFIG_FILE); + fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE); fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n"); fprintf(stderr, " -i Started from inetd\n"); + fprintf(stderr, " -D Do not fork into daemon mode\n"); fprintf(stderr, " -q Quiet (no logging)\n"); fprintf(stderr, " -p port Listen on the specified port (default: 22)\n"); fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n"); - fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n"); + fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n"); fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n"); fprintf(stderr, " -h file File from which to read host key (default: %s)\n", - HOST_KEY_FILE); + _PATH_HOST_KEY_FILE); fprintf(stderr, " -u len Maximum hostname length for utmp recording\n"); fprintf(stderr, " -4 Use IPv4 only\n"); fprintf(stderr, " -6 Use IPv6 only\n"); exit(1); } } + SSLeay_add_all_algorithms(); /* * Force logging to stderr until we have loaded the private host * key (unless started from inetd) */ - log_init(av0, + log_init(__progname, options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility, - !silent && !inetd_flag); + !inetd_flag); /* Read server configuration options from the configuration file. */ read_server_config(&options, config_file_name); @@ -610,44 +680,47 @@ main(int ac, char **av) debug("sshd version %.100s", SSH_VERSION); - sensitive_data.dsa_host_key = NULL; - sensitive_data.host_key = NULL; - - /* check if RSA support exists */ - if ((options.protocol & SSH_PROTO_1) && - rsa_alive() == 0) { - log("no RSA support in libssl and libcrypto. See ssl(8)"); - log("Disabling protocol version 1"); - options.protocol &= ~SSH_PROTO_1; - } - /* Load the RSA/DSA host key. It must have empty passphrase. */ - if (options.protocol & SSH_PROTO_1) { - Key k; - sensitive_data.host_key = RSA_new(); - k.type = KEY_RSA; - k.rsa = sensitive_data.host_key; - errno = 0; - if (!load_private_key(options.host_key_file, "", &k, NULL)) { - error("Could not load host key: %.200s: %.100s", - options.host_key_file, strerror(errno)); - log("Disabling protocol version 1"); - options.protocol &= ~SSH_PROTO_1; + /* load private host keys */ + sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*)); + for(i = 0; i < options.num_host_key_files; i++) + sensitive_data.host_keys[i] = NULL; + sensitive_data.server_key = NULL; + sensitive_data.ssh1_host_key = NULL; + sensitive_data.have_ssh1_key = 0; + sensitive_data.have_ssh2_key = 0; + + for(i = 0; i < options.num_host_key_files; i++) { + key = key_load_private(options.host_key_files[i], "", NULL); + sensitive_data.host_keys[i] = key; + if (key == NULL) { + error("Could not load host key: %s", + options.host_key_files[i]); + sensitive_data.host_keys[i] = NULL; + continue; } - k.rsa = NULL; - } - if (options.protocol & SSH_PROTO_2) { - sensitive_data.dsa_host_key = key_new(KEY_DSA); - if (!load_private_key(options.host_dsa_key_file, "", sensitive_data.dsa_host_key, NULL)) { - - error("Could not load DSA host key: %.200s", options.host_dsa_key_file); - log("Disabling protocol version 2"); - options.protocol &= ~SSH_PROTO_2; + switch(key->type){ + case KEY_RSA1: + sensitive_data.ssh1_host_key = key; + sensitive_data.have_ssh1_key = 1; + break; + case KEY_RSA: + case KEY_DSA: + sensitive_data.have_ssh2_key = 1; + break; } + debug("private host key: #%d type %d %s", i, key->type, + key_type(key)); + } + if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { + log("Disabling protocol version 1. Could not load host key"); + options.protocol &= ~SSH_PROTO_1; + } + if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { + log("Disabling protocol version 2. Could not load host key"); + options.protocol &= ~SSH_PROTO_2; } - if (! options.protocol & (SSH_PROTO_1|SSH_PROTO_2)) { - if (silent == 0) - fprintf(stderr, "sshd: no hostkeys available -- exiting.\n"); - log("sshd: no hostkeys available -- exiting.\n"); + if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { + log("sshd: no hostkeys available -- exiting."); exit(1); } @@ -664,11 +737,11 @@ main(int ac, char **av) * hate software patents. I dont know if this can go? Niels */ if (options.server_key_bits > - BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED && + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - SSH_KEY_BITS_RESERVED && options.server_key_bits < - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED; + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } @@ -677,14 +750,14 @@ main(int ac, char **av) /* Initialize the log (it is reinitialized below in case we forked). */ if (debug_flag && !inetd_flag) log_stderr = 1; - log_init(av0, options.log_level, options.log_facility, log_stderr); + log_init(__progname, options.log_level, options.log_facility, log_stderr); /* * If not in debugging mode, and not started from inetd, disconnect * from the controlling terminal, and fork. The original process * exits. */ - if (!debug_flag && !inetd_flag) { + if (!(debug_flag || inetd_flag || no_daemon_flag)) { #ifdef TIOCNOTTY int fd; #endif /* TIOCNOTTY */ @@ -693,7 +766,7 @@ main(int ac, char **av) /* Disconnect from the controlling tty. */ #ifdef TIOCNOTTY - fd = open("/dev/tty", O_RDWR | O_NOCTTY); + fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); if (fd >= 0) { (void) ioctl(fd, TIOCNOTTY, NULL); close(fd); @@ -701,10 +774,7 @@ main(int ac, char **av) #endif /* TIOCNOTTY */ } /* Reinitialize the log (because of the fork above). */ - log_init(av0, options.log_level, options.log_facility, log_stderr); - - /* Do not display messages to stdout in RSA code. */ - rsa_set_verbose(0); + log_init(__progname, options.log_level, options.log_facility, log_stderr); /* Initialize the random number generator. */ arc4random_stir(); @@ -712,12 +782,15 @@ main(int ac, char **av) /* Chdir to the root directory so that the current disk can be unmounted if desired. */ chdir("/"); + + /* ignore SIGPIPE */ + signal(SIGPIPE, SIG_IGN); /* Start listening for a socket, unless started from inetd. */ if (inetd_flag) { - int s1, s2; + int s1; s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */ - s2 = dup(s1); + dup(s1); sock_in = dup(0); sock_out = dup(1); startup_pipe = -1; @@ -727,16 +800,8 @@ main(int ac, char **av) * ttyfd happens to be one of those. */ debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); - - if (options.protocol & SSH_PROTO_1) { - public_key = RSA_new(); - sensitive_data.private_key = RSA_new(); - log("Generating %d bit RSA key.", options.server_key_bits); - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); - log("RSA key generation complete."); - } + if (options.protocol & SSH_PROTO_1) + generate_ephemeral_server_key(); } else { for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) @@ -800,32 +865,20 @@ main(int ac, char **av) if (!debug_flag) { /* - * Record our pid in /etc/sshd_pid to make it easier - * to kill the correct sshd. We don\'t want to do - * this before the bind above because the bind will + * Record our pid in /var/run/sshd.pid to make it + * easier to kill the correct sshd. We don't want to + * do this before the bind above because the bind will * fail if there already is a daemon, and this will * overwrite any old pid in the file. */ f = fopen(options.pid_file, "w"); if (f) { - fprintf(f, "%u\n", (unsigned int) getpid()); + fprintf(f, "%u\n", (u_int) getpid()); fclose(f); } } - if (options.protocol & SSH_PROTO_1) { - public_key = RSA_new(); - sensitive_data.private_key = RSA_new(); - - log("Generating %d bit RSA key.", options.server_key_bits); - rsa_generate_key(sensitive_data.private_key, public_key, - options.server_key_bits); - arc4random_stir(); - log("RSA key generation complete."); - - /* Schedule server key regeneration alarm. */ - signal(SIGALRM, key_regeneration_alarm); - alarm(options.key_regeneration_time); - } + if (options.protocol & SSH_PROTO_1) + generate_ephemeral_server_key(); /* Arrange to restart on SIGHUP. The handler needs listen_sock. */ signal(SIGHUP, sighup_handler); @@ -856,7 +909,7 @@ main(int ac, char **av) sighup_restart(); if (fdset != NULL) xfree(fdset); - fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask); + fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); fdset = (fd_set *)xmalloc(fdsetsz); memset(fdset, 0, fdsetsz); @@ -867,18 +920,24 @@ main(int ac, char **av) FD_SET(startup_pipes[i], fdset); /* Wait in select until there is a connection. */ - if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) { - if (errno != EINTR) - error("select: %.100s", strerror(errno)); - continue; + ret = select(maxfd+1, fdset, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) + error("select: %.100s", strerror(errno)); + if (key_used && key_do_regen) { + generate_ephemeral_server_key(); + key_used = 0; + key_do_regen = 0; } + if (ret < 0) + continue; + for (i = 0; i < options.max_startups; i++) if (startup_pipes[i] != -1 && FD_ISSET(startup_pipes[i], fdset)) { /* * the read end of the pipe is ready * if the child has closed the pipe - * after successfull authentication + * after successful authentication * or if the child has died */ close(startup_pipes[i]); @@ -919,7 +978,6 @@ main(int ac, char **av) break; } - /* * Got connection. Fork a child to handle it, unless * we are in debugging mode. @@ -958,7 +1016,7 @@ main(int ac, char **av) close_listen_socks(); sock_in = newsock; sock_out = newsock; - log_init(av0, options.log_level, options.log_facility, log_stderr); + log_init(__progname, options.log_level, options.log_facility, log_stderr); break; } } @@ -972,7 +1030,13 @@ main(int ac, char **av) close(startup_p[1]); /* Mark that the key has been used (it was "given" to the child). */ - key_used = 1; + if ((options.protocol & SSH_PROTO_1) && + key_used == 0) { + /* Schedule server key regeneration alarm. */ + signal(SIGALRM, key_regeneration_alarm); + alarm(options.key_regeneration_time); + key_used = 1; + } arc4random_stir(); @@ -1010,6 +1074,12 @@ main(int ac, char **av) linger.l_linger = 5; setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); + /* Set keepalives if requested. */ + if (options.keepalives && + setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, + sizeof(on)) < 0) + error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); + /* * Register our connection. This turns encryption off because we do * not have a key. @@ -1024,13 +1094,13 @@ main(int ac, char **av) { struct request_info req; - request_init(&req, RQ_DAEMON, av0, RQ_FILE, sock_in, NULL); + request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, NULL); fromhost(&req); if (!hosts_access(&req)) { + refuse(&req); close(sock_in); close(sock_out); - refuse(&req); } verbose("Connection from %.500s port %d", eval_client(&req), remote_port); } @@ -1052,16 +1122,17 @@ main(int ac, char **av) sshd_exchange_identification(sock_in, sock_out); /* - * Check that the connection comes from a privileged port. Rhosts- - * and Rhosts-RSA-Authentication only make sense from priviledged + * Check that the connection comes from a privileged port. + * Rhosts-Authentication only makes sense from priviledged * programs. Of course, if the intruder has root access on his local * machine, he can connect from any port. So do not use these * authentication methods from machines that you do not trust. */ if (remote_port >= IPPORT_RESERVED || remote_port < IPPORT_RESERVED / 2) { + debug("Rhosts Authentication disabled, " + "originating port not trusted."); options.rhosts_authentication = 0; - options.rhosts_rsa_authentication = 0; } #if defined(KRB4) && !defined(KRB5) if (!packet_connection_is_ipv4() && @@ -1070,6 +1141,13 @@ main(int ac, char **av) options.kerberos_authentication = 0; } #endif /* KRB4 */ +#ifdef AFS + /* If machine has AFS, set process authentication group. */ + if (k_hasafs()) { + k_setpag(); + k_unlog(); + } +#endif /* AFS */ packet_set_nonblocking(); @@ -1104,15 +1182,15 @@ main(int ac, char **av) * SSH1 key exchange */ void -do_ssh1_kex() +do_ssh1_kex(void) { int i, len; int plen, slen; int rsafail = 0; BIGNUM *session_key_int; - unsigned char session_key[SSH_SESSION_KEY_LENGTH]; - unsigned char cookie[8]; - unsigned int cipher_type, auth_mask, protocol_flags; + u_char session_key[SSH_SESSION_KEY_LENGTH]; + u_char cookie[8]; + u_int cipher_type, auth_mask, protocol_flags; u_int32_t rand = 0; /* @@ -1141,14 +1219,14 @@ do_ssh1_kex() packet_put_char(cookie[i]); /* Store our public server RSA key. */ - packet_put_int(BN_num_bits(public_key->n)); - packet_put_bignum(public_key->e); - packet_put_bignum(public_key->n); + packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); + packet_put_bignum(sensitive_data.server_key->rsa->e); + packet_put_bignum(sensitive_data.server_key->rsa->n); /* Store our public host RSA key. */ - packet_put_int(BN_num_bits(sensitive_data.host_key->n)); - packet_put_bignum(sensitive_data.host_key->e); - packet_put_bignum(sensitive_data.host_key->n); + packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); /* Put protocol flags. */ packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); @@ -1179,10 +1257,8 @@ do_ssh1_kex() if (options.afs_token_passing) auth_mask |= 1 << SSH_PASS_AFS_TOKEN; #endif -#ifdef SKEY - if (options.skey_authentication == 1) + if (options.challenge_reponse_authentication == 1) auth_mask |= 1 << SSH_AUTH_TIS; -#endif if (options.password_authentication) auth_mask |= 1 << SSH_AUTH_PASSWORD; packet_put_int(auth_mask); @@ -1191,8 +1267,9 @@ do_ssh1_kex() packet_send(); packet_write_wait(); - debug("Sent %d bit public key and %d bit host key.", - BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n)); + debug("Sent %d bit server key and %d bit host key.", + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); /* Read clients reply (cipher type and session key). */ packet_read_expect(&plen, SSH_CMSG_SESSION_KEY); @@ -1224,47 +1301,39 @@ do_ssh1_kex() * Decrypt it using our private server key and private host key (key * with larger modulus first). */ - if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) { + if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { /* Server key has bigger modulus. */ - if (BN_num_bits(sensitive_data.private_key->n) < - BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: private_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.private_key->n), - BN_num_bits(sensitive_data.host_key->n), - SSH_KEY_BITS_RESERVED); + if (BN_num_bits(sensitive_data.server_key->rsa->n) < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + SSH_KEY_BITS_RESERVED); } if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.private_key) <= 0) + sensitive_data.server_key->rsa) <= 0) rsafail++; if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.host_key) <= 0) + sensitive_data.ssh1_host_key->rsa) <= 0) rsafail++; } else { /* Host key has bigger modulus (or they are equal). */ - if (BN_num_bits(sensitive_data.host_key->n) < - BN_num_bits(sensitive_data.private_key->n) + SSH_KEY_BITS_RESERVED) { - fatal("do_connection: %s: host_key %d < private_key %d + SSH_KEY_BITS_RESERVED %d", - get_remote_ipaddr(), - BN_num_bits(sensitive_data.host_key->n), - BN_num_bits(sensitive_data.private_key->n), - SSH_KEY_BITS_RESERVED); + if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < + BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + BN_num_bits(sensitive_data.server_key->rsa->n), + SSH_KEY_BITS_RESERVED); } if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.host_key) < 0) + sensitive_data.ssh1_host_key->rsa) < 0) rsafail++; if (rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.private_key) < 0) + sensitive_data.server_key->rsa) < 0) rsafail++; } - - compute_session_id(session_id, cookie, - sensitive_data.host_key->n, - sensitive_data.private_key->n); - - /* Destroy the private and public keys. They will no longer be needed. */ - destroy_sensitive_data(); - /* * Extract session key from the decrypted integer. The key is in the * least significant 256 bits of the integer; the first byte of the @@ -1275,32 +1344,52 @@ do_ssh1_kex() len = BN_num_bytes(session_key_int); if (len < 0 || len > sizeof(session_key)) { error("do_connection: bad session key len from %s: " - "session_key_int %d > sizeof(session_key) %d", - get_remote_ipaddr(), len, sizeof(session_key)); + "session_key_int %d > sizeof(session_key) %lu", + get_remote_ipaddr(), len, (u_long)sizeof(session_key)); rsafail++; } else { memset(session_key, 0, sizeof(session_key)); BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); + + compute_session_id(session_id, cookie, + sensitive_data.ssh1_host_key->rsa->n, + sensitive_data.server_key->rsa->n); + /* + * Xor the first 16 bytes of the session key with the + * session id. + */ + for (i = 0; i < 16; i++) + session_key[i] ^= session_id[i]; } } if (rsafail) { + int bytes = BN_num_bytes(session_key_int); + char *buf = xmalloc(bytes); + MD5_CTX md; + log("do_connection: generating a fake encryption key"); - for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { - if (i % 4 == 0) - rand = arc4random(); - session_key[i] = rand & 0xff; - rand >>= 8; - } + BN_bn2bin(session_key_int, buf); + MD5_Init(&md); + MD5_Update(&md, buf, bytes); + MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); + MD5_Final(session_key, &md); + MD5_Init(&md); + MD5_Update(&md, session_key, 16); + MD5_Update(&md, buf, bytes); + MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); + MD5_Final(session_key + 16, &md); + memset(buf, 0, bytes); + xfree(buf); + for (i = 0; i < 16; i++) + session_id[i] = session_key[i] ^ session_key[i + 16]; } + /* Destroy the private and public keys. They will no longer be needed. */ + destroy_sensitive_data(); /* Destroy the decrypted integer. It is no longer needed. */ BN_clear_free(session_key_int); - /* Xor the first 16 bytes of the session key with the session id. */ - for (i = 0; i < 16; i++) - session_key[i] ^= session_id[i]; - /* Set the session key. From this on all communications will be encrypted. */ packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type); @@ -1319,51 +1408,38 @@ do_ssh1_kex() * SSH2 key exchange: diffie-hellman-group1-sha1 */ void -do_ssh2_kex() +do_ssh2_kex(void) { - Buffer *server_kexinit; - Buffer *client_kexinit; - int payload_len; - int i; Kex *kex; - char *cprop[PROPOSAL_MAX]; - -/* KEXINIT */ if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; } - server_kexinit = kex_init(myproposal); - client_kexinit = xmalloc(sizeof(*client_kexinit)); - buffer_init(client_kexinit); - - /* algorithm negotiation */ - kex_exchange_kexinit(server_kexinit, client_kexinit, cprop); - kex = kex_choose_conf(cprop, myproposal, 1); - for (i = 0; i < PROPOSAL_MAX; i++) - xfree(cprop[i]); - - switch (kex->kex_type) { - case DH_GRP1_SHA1: - ssh_dh1_server(kex, client_kexinit, server_kexinit); - break; - case DH_GEX_SHA1: - ssh_dhgex_server(kex, client_kexinit, server_kexinit); - break; - default: - fatal("Unsupported key exchange %d", kex->kex_type); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); + + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); - debug("send SSH2_MSG_NEWKEYS."); - packet_start(SSH2_MSG_NEWKEYS); - packet_send(); - packet_write_wait(); - debug("done: send SSH2_MSG_NEWKEYS."); + /* start key exchange */ + kex = kex_setup(myproposal); + kex->server = 1; + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; + kex->load_host_key=&get_hostkey_by_type; - debug("Wait SSH2_MSG_NEWKEYS."); - packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); - debug("GOT SSH2_MSG_NEWKEYS."); + xxx_kex = kex; + + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); + + session_id2 = kex->session_id; + session_id2_len = kex->session_id_len; #ifdef DEBUG_KEXDH /* send 1st encrypted/maced/compressed message */ @@ -1372,269 +1448,5 @@ do_ssh2_kex() packet_send(); packet_write_wait(); #endif - - debug("done: KEX2."); + debug("KEX done"); } - -/* - * SSH2 key exchange - */ - -/* diffie-hellman-group1-sha1 */ - -void -ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) -{ -#ifdef DEBUG_KEXDH - int i; -#endif - int payload_len, dlen; - int slen; - unsigned char *signature = NULL; - unsigned char *server_host_key_blob = NULL; - unsigned int sbloblen; - unsigned int klen, kout; - unsigned char *kbuf; - unsigned char *hash; - BIGNUM *shared_secret = 0; - DH *dh; - BIGNUM *dh_client_pub = 0; - -/* KEXDH */ - debug("Wait SSH2_MSG_KEXDH_INIT."); - packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT); - - /* key, cert */ - dh_client_pub = BN_new(); - if (dh_client_pub == NULL) - fatal("dh_client_pub == NULL"); - packet_get_bignum2(dh_client_pub, &dlen); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\ndh_client_pub= "); - BN_print_fp(stderr, dh_client_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_client_pub)); -#endif - - /* generate DH key */ - dh = dh_new_group1(); /* XXX depends on 'kex' */ - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\np= "); - BN_print_fp(stderr, dh->p); - fprintf(stderr, "\ng= "); - bn_print(dh->g); - fprintf(stderr, "\npub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); - DHparams_print_fp(stderr, dh); -#endif - if (!dh_pub_is_valid(dh, dh_client_pub)) - packet_disconnect("bad client public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_client_pub, dh); - -#ifdef DEBUG_KEXDH - debug("shared secret: len %d/%d", klen, kout); - fprintf(stderr, "shared secret == "); - for (i = 0; i< kout; i++) - fprintf(stderr, "%02x", (kbuf[i])&0xff); - fprintf(stderr, "\n"); -#endif - shared_secret = BN_new(); - - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, - &server_host_key_blob, &sbloblen); - - /* calc H */ /* XXX depends on 'kex' */ - hash = kex_hash( - client_version_string, - server_version_string, - buffer_ptr(client_kexinit), buffer_len(client_kexinit), - buffer_ptr(server_kexinit), buffer_len(server_kexinit), - (char *)server_host_key_blob, sbloblen, - dh_client_pub, - dh->pub_key, - shared_secret - ); - buffer_free(client_kexinit); - buffer_free(server_kexinit); - xfree(client_kexinit); - xfree(server_kexinit); -#ifdef DEBUG_KEXDH - fprintf(stderr, "hash == "); - for (i = 0; i< 20; i++) - fprintf(stderr, "%02x", (hash[i])&0xff); - fprintf(stderr, "\n"); -#endif - /* save session id := H */ - /* XXX hashlen depends on KEX */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); - - /* sign H */ - /* XXX hashlen depends on KEX */ - dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); - - destroy_sensitive_data(); - - /* send server hostkey, DH pubkey 'f' and singed H */ - packet_start(SSH2_MSG_KEXDH_REPLY); - packet_put_string((char *)server_host_key_blob, sbloblen); - packet_put_bignum2(dh->pub_key); /* f */ - packet_put_string((char *)signature, slen); - packet_send(); - xfree(signature); - xfree(server_host_key_blob); - packet_write_wait(); - - kex_derive_keys(kex, hash, shared_secret); - packet_set_kex(kex); - - /* have keys, free DH */ - DH_free(dh); -} - -/* diffie-hellman-group-exchange-sha1 */ - -void -ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) -{ -#ifdef DEBUG_KEXDH - int i; -#endif - int payload_len, dlen; - int slen, nbits; - unsigned char *signature = NULL; - unsigned char *server_host_key_blob = NULL; - unsigned int sbloblen; - unsigned int klen, kout; - unsigned char *kbuf; - unsigned char *hash; - BIGNUM *shared_secret = 0; - DH *dh; - BIGNUM *dh_client_pub = 0; - -/* KEXDHGEX */ - debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST."); - packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_REQUEST); - nbits = packet_get_int(); - dh = choose_dh(nbits); - - debug("Sending SSH2_MSG_KEX_DH_GEX_GROUP."); - packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); - packet_put_bignum2(dh->p); - packet_put_bignum2(dh->g); - packet_send(); - packet_write_wait(); - - debug("Wait SSH2_MSG_KEX_DH_GEX_INIT."); - packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_INIT); - - /* key, cert */ - dh_client_pub = BN_new(); - if (dh_client_pub == NULL) - fatal("dh_client_pub == NULL"); - packet_get_bignum2(dh_client_pub, &dlen); - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\ndh_client_pub= "); - BN_print_fp(stderr, dh_client_pub); - fprintf(stderr, "\n"); - debug("bits %d", BN_num_bits(dh_client_pub)); -#endif - -#ifdef DEBUG_KEXDH - fprintf(stderr, "\np= "); - BN_print_fp(stderr, dh->p); - fprintf(stderr, "\ng= "); - bn_print(dh->g); - fprintf(stderr, "\npub= "); - BN_print_fp(stderr, dh->pub_key); - fprintf(stderr, "\n"); - DHparams_print_fp(stderr, dh); -#endif - if (!dh_pub_is_valid(dh, dh_client_pub)) - packet_disconnect("bad client public DH value"); - - klen = DH_size(dh); - kbuf = xmalloc(klen); - kout = DH_compute_key(kbuf, dh_client_pub, dh); - -#ifdef DEBUG_KEXDH - debug("shared secret: len %d/%d", klen, kout); - fprintf(stderr, "shared secret == "); - for (i = 0; i< kout; i++) - fprintf(stderr, "%02x", (kbuf[i])&0xff); - fprintf(stderr, "\n"); -#endif - shared_secret = BN_new(); - - BN_bin2bn(kbuf, kout, shared_secret); - memset(kbuf, 0, klen); - xfree(kbuf); - - /* XXX precompute? */ - dsa_make_key_blob(sensitive_data.dsa_host_key, - &server_host_key_blob, &sbloblen); - - /* calc H */ /* XXX depends on 'kex' */ - hash = kex_hash_gex( - client_version_string, - server_version_string, - buffer_ptr(client_kexinit), buffer_len(client_kexinit), - buffer_ptr(server_kexinit), buffer_len(server_kexinit), - (char *)server_host_key_blob, sbloblen, - nbits, dh->p, dh->g, - dh_client_pub, - dh->pub_key, - shared_secret - ); - buffer_free(client_kexinit); - buffer_free(server_kexinit); - xfree(client_kexinit); - xfree(server_kexinit); -#ifdef DEBUG_KEXDH - fprintf(stderr, "hash == "); - for (i = 0; i< 20; i++) - fprintf(stderr, "%02x", (hash[i])&0xff); - fprintf(stderr, "\n"); -#endif - /* save session id := H */ - /* XXX hashlen depends on KEX */ - session_id2_len = 20; - session_id2 = xmalloc(session_id2_len); - memcpy(session_id2, hash, session_id2_len); - - /* sign H */ - /* XXX hashlen depends on KEX */ - dsa_sign(sensitive_data.dsa_host_key, &signature, &slen, hash, 20); - - destroy_sensitive_data(); - - /* send server hostkey, DH pubkey 'f' and singed H */ - packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); - packet_put_string((char *)server_host_key_blob, sbloblen); - packet_put_bignum2(dh->pub_key); /* f */ - packet_put_string((char *)signature, slen); - packet_send(); - xfree(signature); - xfree(server_host_key_blob); - packet_write_wait(); - - kex_derive_keys(kex, hash, shared_secret); - packet_set_kex(kex); - - /* have keys, free DH */ - DH_free(dh); -} - diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index 7da9ce7..643c3e0 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -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 diff --git a/crypto/openssh/sshlogin.c b/crypto/openssh/sshlogin.c index a8a76c6..a9e769b 100644 --- a/crypto/openssh/sshlogin.c +++ b/crypto/openssh/sshlogin.c @@ -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" diff --git a/crypto/openssh/sshpty.c b/crypto/openssh/sshpty.c index d0f2554..1544ac6 100644 --- a/crypto/openssh/sshpty.c +++ b/crypto/openssh/sshpty.c @@ -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" diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index 2940f20..39df4f9 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.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); |