From cab80f75b2ddfdfdb7cfa50f8f98dd356a430bdf Mon Sep 17 00:00:00 2001 From: mouring Date: Sun, 11 Mar 2001 01:49:19 +0000 Subject: [PATCH] - markus@cvs.openbsd.org 2001/03/10 17:51:04 [kex.c match.c match.h readconf.c readconf.h sshconnect2.c] add PreferredAuthentications --- ChangeLog | 4 ++ kex.c | 53 +++----------------- match.c | 69 +++++++++++++++++++++++++- match.h | 8 ++- readconf.c | 12 ++++- readconf.h | 3 +- sshconnect2.c | 132 +++++++++++++++++++++----------------------------- 7 files changed, 154 insertions(+), 127 deletions(-) diff --git a/ChangeLog b/ChangeLog index 89d5ccd3..a309e41e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,10 @@ handle password padding (newer OSU is fixed) - tim@mindrot.org 2001/03/10 16:33:42 [configure.in Makefile.in sshd_config] make sure $bindir is in USER_PATH so scp will work + - OpenBSD CVS Sync + - markus@cvs.openbsd.org 2001/03/10 17:51:04 + [kex.c match.c match.h readconf.c readconf.h sshconnect2.c] + add PreferredAuthentications 20010310 - OpenBSD CVS Sync diff --git a/kex.c b/kex.c index 308ffb1b..78e108e9 100644 --- a/kex.c +++ b/kex.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: kex.c,v 1.22 2001/03/05 17:17:20 markus Exp $"); +RCSID("$OpenBSD: kex.c,v 1.23 2001/03/10 17:51:04 markus Exp $"); #include #include @@ -42,6 +42,7 @@ RCSID("$OpenBSD: kex.c,v 1.22 2001/03/05 17:17:20 markus Exp $"); #include "key.h" #include "log.h" #include "mac.h" +#include "match.h" #define KEX_COOKIE_LEN 16 @@ -372,49 +373,10 @@ derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) return digest; } -#define NKEYS 6 - -#define MAX_PROP 20 -#define SEP "," - -char * -get_match(char *client, char *server) -{ - char *sproposals[MAX_PROP]; - char *c, *s, *p, *ret, *cp, *sp; - int i, j, nproposals; - - c = cp = xstrdup(client); - s = sp = xstrdup(server); - - for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; - (p = strsep(&sp, SEP)), i++) { - if (i < MAX_PROP) - sproposals[i] = p; - else - break; - } - nproposals = i; - - for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; - (p = strsep(&cp, SEP)), i++) { - for (j = 0; j < nproposals; j++) { - if (strcmp(p, sproposals[j]) == 0) { - ret = xstrdup(p); - xfree(c); - xfree(s); - return ret; - } - } - } - xfree(c); - xfree(s); - return NULL; -} void choose_enc(Enc *enc, char *client, char *server) { - char *name = get_match(client, server); + char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching cipher found: client %s server %s", client, server); enc->cipher = cipher_by_name(name); @@ -428,7 +390,7 @@ choose_enc(Enc *enc, char *client, char *server) void choose_mac(Mac *mac, char *client, char *server) { - char *name = get_match(client, server); + char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching mac found: client %s server %s", client, server); if (mac_init(mac, name) < 0) @@ -443,7 +405,7 @@ choose_mac(Mac *mac, char *client, char *server) void choose_comp(Comp *comp, char *client, char *server) { - char *name = get_match(client, server); + char *name = match_list(client, server, NULL); if (name == NULL) fatal("no matching comp found: client %s server %s", client, server); if (strcmp(name, "zlib") == 0) { @@ -458,7 +420,7 @@ choose_comp(Comp *comp, char *client, char *server) void choose_kex(Kex *k, char *client, char *server) { - k->name = get_match(client, server); + k->name = match_list(client, server, NULL); if (k->name == NULL) fatal("no kex alg"); if (strcmp(k->name, KEX_DH1) == 0) { @@ -471,7 +433,7 @@ choose_kex(Kex *k, char *client, char *server) void choose_hostkeyalg(Kex *k, char *client, char *server) { - char *hostkeyalg = get_match(client, server); + char *hostkeyalg = match_list(client, server, NULL); if (hostkeyalg == NULL) fatal("no hostkey alg"); k->hostkey_type = key_type_from_name(hostkeyalg); @@ -524,6 +486,7 @@ kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server return k; } +#define NKEYS 6 int kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret) { diff --git a/match.c b/match.c index 81030da6..ebb562ab 100644 --- a/match.c +++ b/match.c @@ -10,11 +10,35 @@ * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". */ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * 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. + */ #include "includes.h" -RCSID("$OpenBSD: match.c,v 1.11 2001/01/21 19:05:52 markus Exp $"); +RCSID("$OpenBSD: match.c,v 1.12 2001/03/10 17:51:04 markus Exp $"); #include "match.h" +#include "xmalloc.h" /* * Returns true if the given string matches the pattern (which may contain ? @@ -137,3 +161,46 @@ match_hostname(const char *host, const char *pattern, u_int len) */ return got_positive; } + + +#define MAX_PROP 20 +#define SEP "," +char * +match_list(const char *client, const char *server, u_int *next) +{ + char *sproposals[MAX_PROP]; + char *c, *s, *p, *ret, *cp, *sp; + int i, j, nproposals; + + c = cp = xstrdup(client); + s = sp = xstrdup(server); + + for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&sp, SEP)), i++) { + if (i < MAX_PROP) + sproposals[i] = p; + else + break; + } + nproposals = i; + + for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&cp, SEP)), i++) { + for (j = 0; j < nproposals; j++) { + if (strcmp(p, sproposals[j]) == 0) { + ret = xstrdup(p); + if (next != NULL) + *next = (cp == NULL) ? + strlen(c) : cp - c; + xfree(c); + xfree(s); + return ret; + } + } + } + if (next != NULL) + *next = strlen(c); + xfree(c); + xfree(s); + return NULL; +} diff --git a/match.h b/match.h index 285ad55f..09c93116 100644 --- a/match.h +++ b/match.h @@ -1,4 +1,4 @@ -/* $OpenBSD: match.h,v 1.6 2001/01/29 01:58:17 niklas Exp $ */ +/* $OpenBSD: match.h,v 1.7 2001/03/10 17:51:04 markus Exp $ */ /* * Author: Tatu Ylonen @@ -30,4 +30,10 @@ int match_pattern(const char *s, const char *pattern); */ int match_hostname(const char *host, const char *pattern, u_int len); +/* + * Returns first item from client-list that is also supported by server-list, + * caller must xfree() returned string. + */ +char *match_list(const char *client, const char *server, u_int *next); + #endif diff --git a/readconf.c b/readconf.c index 2b298147..33d40e8c 100644 --- a/readconf.c +++ b/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.66 2001/03/10 12:53:52 deraadt Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.67 2001/03/10 17:51:04 markus Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -109,7 +109,8 @@ typedef enum { oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, - oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias + oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, + oPreferredAuthentications } OpCodes; /* Textual representations of the tokens. */ @@ -171,6 +172,7 @@ static struct { { "keepalive", oKeepAlives }, { "numberofpasswordprompts", oNumberOfPasswordPrompts }, { "loglevel", oLogLevel }, + { "preferredauthentications", oPreferredAuthentications }, { NULL, 0 } }; @@ -446,6 +448,10 @@ parse_string: 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(""); @@ -722,6 +728,7 @@ initialize_options(Options * options) options->num_local_forwards = 0; options->num_remote_forwards = 0; options->log_level = (LogLevel) - 1; + options->preferred_authentications = NULL; } /* @@ -837,4 +844,5 @@ fill_default_options(Options * options) /* 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/readconf.h b/readconf.h index 97615620..55babe80 100644 --- a/readconf.h +++ b/readconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: readconf.h,v 1.27 2001/03/08 21:42:32 markus Exp $"); */ +/* RCSID("$OpenBSD: readconf.h,v 1.28 2001/03/10 17:51:04 markus Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -82,6 +82,7 @@ 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/DSA identities. */ char *identity_files[SSH_MAX_IDENTITY_FILES]; diff --git a/sshconnect2.c b/sshconnect2.c index 646bb18f..19d079bd 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.52 2001/03/10 12:48:27 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.53 2001/03/10 17:51:04 markus Exp $"); #include #include @@ -51,6 +51,7 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.52 2001/03/10 12:48:27 markus Exp $"); #include "log.h" #include "readconf.h" #include "readpass.h" +#include "match.h" void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); @@ -498,9 +499,9 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback); void clear_auth_state(Authctxt *authctxt); -void authmethod_clear(void); Authmethod *authmethod_get(char *authlist); Authmethod *authmethod_lookup(const char *name); +char *authmethods_get(void); Authmethod authmethods[] = { {"publickey", @@ -551,6 +552,9 @@ ssh_userauth2(const char *server_user, char *host) 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; @@ -561,7 +565,6 @@ ssh_userauth2(const char *server_user, char *host) authctxt.authlist = NULL; if (authctxt.method == NULL) fatal("ssh_userauth2: internal error: cannot send userauth none request"); - authmethod_clear(); /* initial userauth request */ userauth_none(&authctxt); @@ -1106,39 +1109,6 @@ input_userauth_info_req(int type, int plen, void *ctxt) /* 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. - */ -void -authmethod_clear(void) -{ - if (authlist_current != NULL) { - xfree(authlist_current); - authlist_current = NULL; - } - if (authlist_working != NULL) { - xfree(authlist_working); - authlist_working = NULL; - } - if (authname_current != NULL) { - xfree(authname_current); - authname_current = NULL; - } - if (authlist_state != NULL) - authlist_state = NULL; - return; -} - /* * given auth method name, if configurable options permit this method fill * in auth_ident field and return true, otherwise return false. @@ -1169,62 +1139,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); } -- 2.45.1