diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2001-04-12 19:15:27 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2001-04-12 19:15:27 +0000 |
commit | ba389b2a3f5ed7754b12e5adb28d01984188359f (patch) | |
tree | a2f7ad774a74174eba34243b70a7aef698b53f69 /usr.bin/ssh | |
parent | 5bc0aa0f59169360efd696e703a28c3915398baa (diff) |
implement HostbasedAuthentication (= RhostRSAAuthentication for ssh v2)
similar to RhostRSAAuthentication unless you enable (the experimental)
HostbasedUsesNameFromPacketOnly option. please test. :)
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r-- | usr.bin/ssh/auth-rhosts.c | 27 | ||||
-rw-r--r-- | usr.bin/ssh/auth.h | 7 | ||||
-rw-r--r-- | usr.bin/ssh/auth2.c | 161 | ||||
-rw-r--r-- | usr.bin/ssh/buffer.c | 11 | ||||
-rw-r--r-- | usr.bin/ssh/canohost.c | 57 | ||||
-rw-r--r-- | usr.bin/ssh/canohost.h | 4 | ||||
-rw-r--r-- | usr.bin/ssh/compat.c | 6 | ||||
-rw-r--r-- | usr.bin/ssh/compat.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.c | 4 | ||||
-rw-r--r-- | usr.bin/ssh/pathnames.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/readconf.c | 16 | ||||
-rw-r--r-- | usr.bin/ssh/readconf.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.c | 21 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.h | 4 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.c | 42 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect.c | 8 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect.h | 38 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect1.c | 20 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect2.c | 111 | ||||
-rw-r--r-- | usr.bin/ssh/sshd_config | 4 |
20 files changed, 454 insertions, 98 deletions
diff --git a/usr.bin/ssh/auth-rhosts.c b/usr.bin/ssh/auth-rhosts.c index c71e9b55d04..324a0f92590 100644 --- a/usr.bin/ssh/auth-rhosts.c +++ b/usr.bin/ssh/auth-rhosts.c @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rhosts.c,v 1.22 2001/04/06 21:00:06 markus Exp $"); +RCSID("$OpenBSD: auth-rhosts.c,v 1.23 2001/04/12 19:15:24 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -25,6 +25,9 @@ RCSID("$OpenBSD: auth-rhosts.c,v 1.22 2001/04/06 21:00:06 markus Exp $"); #include "canohost.h" #include "auth.h" +/* import */ +extern ServerOptions options; + /* * This function processes an rhosts-style file (.rhosts, .shosts, or * /etc/hosts.equiv). This returns true if authentication can be granted @@ -150,16 +153,31 @@ check_rhosts_file(const char *filename, const char *hostname, int auth_rhosts(struct passwd *pw, const char *client_user) { - extern ServerOptions options; - char buf[1024]; const char *hostname, *ipaddr; + int ret; + + hostname = get_canonical_hostname(options.reverse_mapping_check); + ipaddr = get_remote_ipaddr(); + ret = auth_rhosts2(pw, client_user, hostname, ipaddr); + return ret; +} + +int +auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, + const char *ipaddr) +{ + char buf[1024]; struct stat st; static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; u_int rhosts_file_index; + debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s", + client_user, hostname, ipaddr); + /* no user given */ if (pw == NULL) return 0; + /* Switch to the user's uid. */ temporarily_use_uid(pw); /* @@ -184,9 +202,6 @@ auth_rhosts(struct passwd *pw, const char *client_user) stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) return 0; - hostname = get_canonical_hostname(options.reverse_mapping_check); - ipaddr = get_remote_ipaddr(); - /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ if (pw->pw_uid != 0) { if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user, diff --git a/usr.bin/ssh/auth.h b/usr.bin/ssh/auth.h index c727519037a..500b73a3f0f 100644 --- a/usr.bin/ssh/auth.h +++ b/usr.bin/ssh/auth.h @@ -21,7 +21,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: auth.h,v 1.14 2001/03/28 22:43:31 markus Exp $ + * $OpenBSD: auth.h,v 1.15 2001/04/12 19:15:24 markus Exp $ */ #ifndef AUTH_H #define AUTH_H @@ -58,6 +58,11 @@ struct Authctxt { */ int auth_rhosts(struct passwd * pw, const char *client_user); +/* extended interface similar to auth_rhosts() */ +int +auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, + const char *ipaddr); + /* * Tries to authenticate the user using the .rhosts file and the host using * its host key. Returns true if authentication succeeds. diff --git a/usr.bin/ssh/auth2.c b/usr.bin/ssh/auth2.c index e5a266830b7..56c2be7e4fe 100644 --- a/usr.bin/ssh/auth2.c +++ b/usr.bin/ssh/auth2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth2.c,v 1.51 2001/04/06 21:00:08 markus Exp $"); +RCSID("$OpenBSD: auth2.c,v 1.52 2001/04/12 19:15:24 markus Exp $"); #include <openssl/evp.h> @@ -48,6 +48,9 @@ RCSID("$OpenBSD: auth2.c,v 1.51 2001/04/06 21:00:08 markus Exp $"); #include "uidswap.h" #include "auth-options.h" #include "misc.h" +#include "hostfile.h" +#include "canohost.h" +#include "tildexpand.h" /* import */ extern ServerOptions options; @@ -72,8 +75,11 @@ void protocol_error(int type, int plen, void *ctxt); /* helper */ Authmethod *authmethod_lookup(const char *name); -int user_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, const char *chost, + Key *key); /* auth */ void userauth_banner(void); @@ -81,6 +87,7 @@ 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,6 +103,9 @@ Authmethod authmethods[] = { {"keyboard-interactive", userauth_kbdint, &options.kbd_interactive_authentication}, + {"hostbased", + userauth_hostbased, + &options.hostbased_authentication}, {NULL, NULL, NULL} }; @@ -201,7 +211,7 @@ input_userauth_request(int type, int plen, void *ctxt) } 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; } @@ -461,6 +471,89 @@ userauth_pubkey(Authctxt *authctxt) return authenticated; } +int +userauth_hostbased(Authctxt *authctxt) +{ + Buffer b; + Key *key; + char *pkalg, *pkblob, *sig; + char *cuser, *chost; + 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; + } + buffer_init(&b); + if (datafellows & SSH_OLD_SESSIONID) { + buffer_append(&b, session_id2, session_id2_len); + } else { + buffer_put_string(&b, session_id2, session_id2_len); + } + if (datafellows & SSH_BUG_HBSERVICE) + debug("SSH_BUG_HBSERVICE"); + /* reconstruct packet */ + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->user); + buffer_put_cstring(&b, + datafellows & SSH_BUG_HBSERVICE ? + "ssh-userauth" : + authctxt->service); + buffer_put_cstring(&b, "hostbased"); + buffer_put_string(&b, pkalg, alen); + buffer_put_string(&b, pkblob, blen); + buffer_put_cstring(&b, chost); + buffer_put_cstring(&b, cuser); +#ifdef DEBUG_PK + buffer_dump(&b); +#endif + /* test for allowed key and correct signature */ + if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) && + key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) + authenticated = 1; + + buffer_clear(&b); + key_free(key); + +done: + debug2("userauth_hostbased: authenticated %d", authenticated); + xfree(pkalg); + xfree(pkblob); + xfree(cuser); + xfree(chost); + xfree(sig); + return authenticated; +} + /* get current user */ struct passwd* @@ -638,3 +731,65 @@ user_key_allowed(struct passwd *pw, Key *key) debug2("key not found"); return found_key; } + +/* return 1 if given hostkey is allowed */ +int +hostbased_key_allowed(struct passwd *pw, const char *cuser, const char *chost, + Key *key) +{ + Key *found; + const char *resolvedname, *ipaddr, *lookup; + struct stat st; + char *user_hostfile; + int host_status; + + resolvedname = get_canonical_hostname(options.reverse_mapping_check); + ipaddr = get_remote_ipaddr(); + + debug2("userauth_hostbased: resolvedname %s ipaddr %s", + resolvedname, ipaddr); + + if (options.hostbased_uses_name_from_packet_only) { + if (auth_rhosts2(pw, cuser, chost, chost) == 0) + return 0; + lookup = chost; + } else { + 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/usr.bin/ssh/buffer.c b/usr.bin/ssh/buffer.c index 377d0c09f40..044caafb5d7 100644 --- a/usr.bin/ssh/buffer.c +++ b/usr.bin/ssh/buffer.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: buffer.c,v 1.12 2001/04/07 08:55:15 markus Exp $"); +RCSID("$OpenBSD: buffer.c,v 1.13 2001/04/12 19:15:24 markus Exp $"); #include "xmalloc.h" #include "buffer.h" @@ -154,7 +154,12 @@ buffer_dump(Buffer *buffer) int i; u_char *ucp = (u_char *) buffer->buf; - for (i = buffer->offset; i < buffer->end; i++) - fprintf(stderr, " %02x", ucp[i]); + for (i = buffer->offset; i < buffer->end; i++) { + fprintf(stderr, "%02x", ucp[i]); + if ((i-buffer->offset)%16==15) + fprintf(stderr, "\r\n"); + else if ((i-buffer->offset)%2==1) + fprintf(stderr, " "); + } fprintf(stderr, "\r\n"); } diff --git a/usr.bin/ssh/canohost.c b/usr.bin/ssh/canohost.c index 453c2c6a581..dceba268bd9 100644 --- a/usr.bin/ssh/canohost.c +++ b/usr.bin/ssh/canohost.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: canohost.c,v 1.24 2001/04/05 15:48:19 stevesk Exp $"); +RCSID("$OpenBSD: canohost.c,v 1.25 2001/04/12 19:15:24 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -180,30 +180,59 @@ get_canonical_hostname(int reverse_mapping_check) * Returns the remote IP-address of socket as a string. The returned * string must be freed. */ - char * -get_peer_ipaddr(int socket) +get_socket_address(int socket, int remote, int flags) { - struct sockaddr_storage from; - socklen_t fromlen; + struct sockaddr_storage addr; + socklen_t addrlen; char ntop[NI_MAXHOST]; /* Get IP address of client. */ - fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { - debug("get_peer_ipaddr: getpeername failed: %.100s", strerror(errno)); - return NULL; + 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) { - error("get_peer_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); } +char * +get_peer_ipaddr(int socket) +{ + return get_socket_address(socket, 1, NI_NUMERICHOST); +} + +char * +get_local_ipaddr(int socket) +{ + return get_socket_address(socket, 0, NI_NUMERICHOST); +} + +char * +get_local_name(int socket) +{ + return get_socket_address(socket, 0, NI_NAMEREQD); +} + /* * Returns the IP-address of the remote host as a string. The returned * string must not be freed. diff --git a/usr.bin/ssh/canohost.h b/usr.bin/ssh/canohost.h index 89bd5c3b454..36fb345a122 100644 --- a/usr.bin/ssh/canohost.h +++ b/usr.bin/ssh/canohost.h @@ -1,4 +1,4 @@ -/* $OpenBSD: canohost.h,v 1.5 2001/04/05 15:48:19 stevesk Exp $ */ +/* $OpenBSD: canohost.h,v 1.6 2001/04/12 19:15:24 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -30,6 +30,8 @@ const char *get_remote_name_or_ip(u_int utmp_len, int reverse_mapping_check); /* Returns the ipaddr/port number of the peer of the socket. */ char * get_peer_ipaddr(int socket); int get_peer_port(int sock); +char * get_local_ipaddr(int socket); +char * get_local_name(int socket); /* Returns the port number of the remote/local host. */ int get_remote_port(void); diff --git a/usr.bin/ssh/compat.c b/usr.bin/ssh/compat.c index 356a3f3e90d..f6b9a597646 100644 --- a/usr.bin/ssh/compat.c +++ b/usr.bin/ssh/compat.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: compat.c,v 1.45 2001/04/05 11:09:16 markus Exp $"); +RCSID("$OpenBSD: compat.c,v 1.46 2001/04/12 19:15:24 markus Exp $"); #include <regex.h> @@ -77,10 +77,10 @@ compat_datafellows(const char *version) { "MindTerm", 0 }, { "^2\\.1\\.0", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| SSH_OLD_SESSIONID|SSH_BUG_DEBUG| - SSH_BUG_RSASIGMD5 }, + 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_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| diff --git a/usr.bin/ssh/compat.h b/usr.bin/ssh/compat.h index 244cd1aa7f9..fc6f3344f5a 100644 --- a/usr.bin/ssh/compat.h +++ b/usr.bin/ssh/compat.h @@ -21,7 +21,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. */ -/* RCSID("$OpenBSD: compat.h,v 1.22 2001/04/05 11:09:17 markus Exp $"); */ +/* RCSID("$OpenBSD: compat.h,v 1.23 2001/04/12 19:15:24 markus Exp $"); */ #ifndef COMPAT_H #define COMPAT_H @@ -47,6 +47,7 @@ #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); diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index 77aa8a899a0..d532bd6adbb 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -36,7 +36,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: hostfile.c,v 1.25 2001/04/06 22:12:47 stevesk Exp $"); +RCSID("$OpenBSD: hostfile.c,v 1.26 2001/04/12 19:15:24 markus Exp $"); #include "packet.h" #include "match.h" @@ -115,6 +115,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, 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. */ @@ -166,6 +167,7 @@ check_host_in_hostfile(const char *filename, const char *host, Key *key, /* 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/usr.bin/ssh/pathnames.h b/usr.bin/ssh/pathnames.h index 39edf315ca4..2f109b30ac4 100644 --- a/usr.bin/ssh/pathnames.h +++ b/usr.bin/ssh/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.4 2001/02/08 22:28:07 stevesk Exp $ */ +/* $OpenBSD: pathnames.h,v 1.5 2001/04/12 19:15:24 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -26,10 +26,11 @@ * Of these, ssh_host_key must be readable only by root, whereas ssh_config * should be world-readable. */ -#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key" #define _PATH_SERVER_CONFIG_FILE ETCDIR "/sshd_config" #define _PATH_HOST_CONFIG_FILE ETCDIR "/ssh_config" +#define _PATH_HOST_KEY_FILE ETCDIR "/ssh_host_key" #define _PATH_HOST_DSA_KEY_FILE ETCDIR "/ssh_host_dsa_key" +#define _PATH_HOST_RSA_KEY_FILE ETCDIR "/ssh_host_rsa_key" #define _PATH_DH_PRIMES ETCDIR "/primes" #define _PATH_SSH_PROGRAM "/usr/bin/ssh" diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index f95940c1eb9..4cbcac68894 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.71 2001/04/07 08:55:17 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.72 2001/04/12 19:15:25 markus Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -110,7 +110,7 @@ typedef enum { oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, - oDynamicForward, oPreferredAuthentications + oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication } OpCodes; /* Textual representations of the tokens. */ @@ -131,6 +131,8 @@ static struct { { "rsaauthentication", oRSAAuthentication }, { "pubkeyauthentication", oPubkeyAuthentication }, { "dsaauthentication", oPubkeyAuthentication }, /* alias */ + { "rhostsrsaauthentication", oRhostsRSAAuthentication }, + { "hostbaedauthentication", oHostbasedAuthentication }, { "challengeresponseauthentication", oChallengeResponseAuthentication }, { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ @@ -158,7 +160,6 @@ static struct { { "user", oUser }, { "host", oHost }, { "escapechar", oEscapeChar }, - { "rhostsrsaauthentication", oRhostsRSAAuthentication }, { "globalknownhostsfile", oGlobalKnownHostsFile }, { "userknownhostsfile", oUserKnownHostsFile }, { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, @@ -322,6 +323,10 @@ parse_flag: intptr = &options->rhosts_rsa_authentication; goto parse_flag; + case oHostbasedAuthentication: + intptr = &options->hostbased_authentication; + goto parse_flag; + case oChallengeResponseAuthentication: intptr = &options->challenge_reponse_authentication; goto parse_flag; @@ -592,7 +597,7 @@ parse_int: filename, linenum); fwd_port = atoi(arg); add_local_forward(options, fwd_port, "socks4", 0); - break; + break; case oHost: *activep = 0; @@ -710,6 +715,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; @@ -787,6 +793,8 @@ fill_default_options(Options * options) 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) diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h index 55babe80ead..680068b0934 100644 --- a/usr.bin/ssh/readconf.h +++ b/usr.bin/ssh/readconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: readconf.h,v 1.28 2001/03/10 17:51:04 markus Exp $"); */ +/* RCSID("$OpenBSD: readconf.h,v 1.29 2001/04/12 19:15:25 markus Exp $"); */ #ifndef READCONF_H #define READCONF_H @@ -38,6 +38,7 @@ typedef struct { * authentication. */ int rsa_authentication; /* Try RSA 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. */ #ifdef KRB4 diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index 4d5eb53ae85..8e876d1f12e 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -10,7 +10,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: servconf.c,v 1.74 2001/04/06 22:25:25 stevesk Exp $"); +RCSID("$OpenBSD: servconf.c,v 1.75 2001/04/12 19:15:25 markus Exp $"); #ifdef KRB4 #include <krb.h> @@ -67,6 +67,8 @@ 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->pubkey_authentication = -1; #ifdef KRB4 @@ -156,6 +158,10 @@ 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->pubkey_authentication == -1) @@ -219,7 +225,8 @@ typedef enum { sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, - sBanner, sReverseMappingCheck + sBanner, sReverseMappingCheck, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly } ServerOpCodes; /* Textual representation of the tokens. */ @@ -239,6 +246,8 @@ static struct { { "loglevel", sLogLevel }, { "rhostsauthentication", sRhostsAuthentication }, { "rhostsrsaauthentication", sRhostsRSAAuthentication }, + { "hostbasedauthentication", sHostbasedAuthentication }, + { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly }, { "rsaauthentication", sRSAAuthentication }, { "pubkeyauthentication", sPubkeyAuthentication }, { "dsaauthentication", sPubkeyAuthentication }, /* alias */ @@ -537,6 +546,14 @@ 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; diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 57d4370f1c5..9b3a60f08f7 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: servconf.h,v 1.39 2001/03/25 13:16:10 stevesk Exp $"); */ +/* RCSID("$OpenBSD: servconf.h,v 1.40 2001/04/12 19:15:25 markus Exp $"); */ #ifndef SERVCONF_H #define SERVCONF_H @@ -69,6 +69,8 @@ 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 pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ #ifdef KRB4 diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index a2b67904829..2282eb5ae76 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.111 2001/04/12 14:29:09 markus Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.112 2001/04/12 19:15:25 markus Exp $"); #include <openssl/evp.h> #include <openssl/err.h> @@ -122,8 +122,11 @@ struct sockaddr_storage hostaddr; */ volatile int received_window_change_signal = 0; -/* Host private key. */ -Key *host_private_key = NULL; +/* Private host keys. */ +struct { + Key **keys; + int nkeys; +} sensitive_data; /* Original real UID. */ uid_t original_real_uid; @@ -625,9 +628,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)) { - host_private_key = key_load_private_type(KEY_RSA1, + 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 @@ -686,11 +698,21 @@ main(int ac, char **av) 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, host, (struct sockaddr *)&hostaddr, pw); - - /* We no longer need the host private key. Clear it now. */ - if (host_private_key != NULL) - key_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(); diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index d62b3aa90dc..31d06964bb0 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/sshconnect.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect.c,v 1.103 2001/04/06 21:00:14 markus Exp $"); +RCSID("$OpenBSD: sshconnect.c,v 1.104 2001/04/12 19:15:25 markus Exp $"); #include <openssl/bn.h> @@ -730,7 +730,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, * This function does not require super-user privileges. */ void -ssh_login(Key *own_host_key, const char *orighost, +ssh_login(Key **keys, int nkeys, const char *orighost, struct sockaddr *hostaddr, struct passwd *pw) { char *host, *cp; @@ -755,10 +755,10 @@ ssh_login(Key *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, own_host_key); + ssh_userauth1(local_user, server_user, host, keys, nkeys); } } diff --git a/usr.bin/ssh/sshconnect.h b/usr.bin/ssh/sshconnect.h index 45caf739590..6610401858d 100644 --- a/usr.bin/ssh/sshconnect.h +++ b/usr.bin/ssh/sshconnect.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.h,v 1.8 2001/04/06 21:00:15 markus Exp $ */ +/* $OpenBSD: sshconnect.h,v 1.9 2001/04/12 19:15:25 markus Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -25,46 +25,30 @@ */ #ifndef SSHCONNECT_H #define SSHCONNECT_H -/* - * 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, struct passwd *pw, 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(Key *host_key, const char *host, - struct sockaddr * hostaddr, struct passwd *pw); - +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, - Key *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/usr.bin/ssh/sshconnect1.c b/usr.bin/ssh/sshconnect1.c index 3ec5ecc5140..865d04e8505 100644 --- a/usr.bin/ssh/sshconnect1.c +++ b/usr.bin/ssh/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.29 2001/03/26 08:07:09 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.30 2001/04/12 19:15:25 markus Exp $"); #include <openssl/bn.h> #include <openssl/evp.h> @@ -911,17 +911,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr) * Authenticate user */ void -ssh_userauth( - const char *local_user, - const char *server_user, - char *host, - Key *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); @@ -1000,9 +997,12 @@ ssh_userauth( * authentication. */ if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && - options.rhosts_rsa_authentication && own_host_key != NULL) { - if (try_rhosts_rsa_authentication(local_user, own_host_key)) - return; + options.rhosts_rsa_authentication) { + for (i = 0; i < nkeys; i++) { + if (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)) && diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c index da5b7147847..9a1d2576e1f 100644 --- a/usr.bin/ssh/sshconnect2.c +++ b/usr.bin/ssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.67 2001/04/05 10:42:56 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.68 2001/04/12 19:15:25 markus Exp $"); #include <openssl/bn.h> #include <openssl/md5.h> @@ -53,6 +53,7 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.67 2001/04/05 10:42:56 markus Exp $"); #include "readpass.h" #include "match.h" #include "dispatch.h" +#include "canohost.h" /* import */ extern char *client_version_string; @@ -147,15 +148,20 @@ typedef int sign_cb_fn( 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 */ @@ -175,6 +181,7 @@ 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); @@ -200,6 +207,10 @@ Authmethod authmethods[] = { userauth_kbdint, &options.kbd_interactive_authentication, &options.batch_mode}, + {"hostbased", + userauth_hostbased, + &options.hostbased_authentication, + NULL}, {"none", userauth_none, NULL, @@ -208,7 +219,8 @@ 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; @@ -242,11 +254,14 @@ ssh_userauth2(const char *server_user, char *host) /* 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"); @@ -786,6 +801,96 @@ input_userauth_info_req(int type, int plen, void *ctxt) packet_send(); } +/* + * 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. + */ +int +userauth_hostbased(Authctxt *authctxt) +{ + Key *private = NULL; + Buffer b; + u_char *signature, *blob; + char *chost, *pkalg, *p; + u_int blen, slen; + int ok, i, found = 0; + + p = get_local_name(packet_get_connection_in()); + if (p == NULL) { + error("userauth_hostbased: cannot get local ipaddr/name"); + return 0; + } + chost = xstrdup(p); + 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 (!found) { + xfree(chost); + return 0; + } + if (key_to_blob(private, &blob, &blen) == 0) { + key_free(private); + xfree(chost); + return 0; + } + pkalg = xstrdup(key_ssh_name(private)); + buffer_init(&b); + if (datafellows & SSH_OLD_SESSIONID) { + buffer_append(&b, session_id2, session_id2_len); + } else { + buffer_put_string(&b, session_id2, session_id2_len); + } + /* construct data */ + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->server_user); + buffer_put_cstring(&b, + datafellows & SSH_BUG_HBSERVICE ? + "ssh-userauth" : + authctxt->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; + } + 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 */ /* diff --git a/usr.bin/ssh/sshd_config b/usr.bin/ssh/sshd_config index 24e8f336ba5..f9a959edee7 100644 --- a/usr.bin/ssh/sshd_config +++ b/usr.bin/ssh/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.35 2001/03/25 13:16:11 stevesk Exp $ +# $OpenBSD: sshd_config,v 1.36 2001/04/12 19:15:26 markus Exp $ # This is the sshd server system-wide configuration file. See sshd(8) # for more information. @@ -35,6 +35,8 @@ 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 |