--- ../curl-7.17.0/./lib/sshentry.c	1969-12-31 16:00:00.000000000 -0800
+++ ./lib/sshentry.c	2007-10-22 22:06:03.000000000 -0700
@@ -0,0 +1,345 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sshentry.h"
+#include "strequal.h"
+
+static int ssh_host_parse_hostnames (SSH_HOST_ENTRY * s, char *line,
+				     char *end);
+static int ssh_host_parse_key (SSH_HOST_ENTRY * s, char *line,
+			       int is_base64_encoded);
+
+/** Returns zero if successful, > zero for malformed data, < 0 not supported. */
+int
+new_ssh_host_entry (SSH_HOST_ENTRY ** s, char *line)
+{
+  char *tmp = NULL;
+  SSH_HOST_ENTRY *t = NULL;
+  int i;
+
+  if (line == NULL || *line == 0)
+    return 1;
+  if (s == NULL)
+    return 2;
+
+  tmp = strchr (line, ' ');
+  if (tmp == NULL)
+    return 3;
+
+
+  t = (SSH_HOST_ENTRY *) malloc (sizeof (SSH_HOST_ENTRY));
+  t->hostname_line = NULL;
+  t->hostnames = NULL;
+  t->hostnames_size = t->bits = t->exponent = -1;
+  t->modulus = NULL;
+  t->modulus_length = -1;
+  t->ssh_version = -1;
+  t->md5 = NULL;
+
+  i = ssh_host_parse_hostnames (t, line, tmp);
+  if (i != 0) {
+    free_ssh_host_entry (t);
+    return ((i > 0) ? 4 : -1);
+  }
+
+  line = tmp + 1;
+  tmp = strchr (line, ' ');
+  if (tmp != NULL)
+    tmp = strchr (tmp + 1, ' ');
+
+  i = ssh_host_parse_key (t, line, tmp == NULL ? 1 : 0);
+  if (i != 0) {
+    free_ssh_host_entry (t);
+    return ((i > 0) ? 5 : -2);
+  }
+
+
+
+  *s = t;
+  return 0;
+}
+
+static int
+ssh_host_parse_hostnames (SSH_HOST_ENTRY * s, char *line, char *end)
+{
+  char *start;
+  char *comma = NULL;
+  int i;
+
+  /* we don't handle the hashed name format because the hashing
+   * mechanism isnt defined (at least based on the man page)
+   */
+  if (*line == '|')
+    return -1;
+  if (line == end || *line == ' ')
+    return 1;
+
+  s->hostname_line = (char *) malloc ((end - line) + 1);
+  strncpy (s->hostname_line, line, (end - line) + 1);
+  start = end = s->hostname_line + (end - line);
+  *end = 0;
+
+  s->hostnames_size = 1;
+  comma = s->hostname_line;
+  while (comma = strchr (comma, ',')) {
+    comma++;
+    if (*comma == ',' || *comma == 0) {
+      free (s->hostname_line);
+      s->hostname_line = NULL;
+      return 2;
+    }
+    s->hostnames_size++;
+  }
+  s->hostnames = (char **) malloc (sizeof (char *) * s->hostnames_size);
+
+  start = comma = s->hostname_line;
+  i = 0;
+  while (comma = strchr (comma, ',')) {
+    *comma = 0;
+    s->hostnames[i] = start;
+
+    comma++;
+    start = comma;
+    i++;
+  }
+  s->hostnames[i] = start;
+
+  return 0;
+}
+
+/** Returns the number of bytes read or -1. */
+static int
+ssh_proto_str_read (char *line, char **val, char *end)
+{
+  unsigned int len;
+
+  if (line + 4 > end)
+    return -1;
+  len = (line[0] << 24) + (line[1] << 16) + (line[2] << 8) + line[3];
+  if (line + 4 + len > end)
+    return -1;
+
+  *val = malloc (len);
+  memcpy (*val, line + 4, len);
+  return len + 4;
+}
+static int
+ssh_host_parse_key (SSH_HOST_ENTRY * s, char *line, int is_base64_encoded)
+{
+  int i, j;
+  char *tmp, *tmp2;
+  extern size_t Curl_base64_decode (const char *source,
+				    unsigned char **outptr);
+  char scratchdata[512];
+  // workaround for the MD5 stuff
+  void *ctx = (void *) scratchdata;
+
+  /* the bits, exponent, modulus format */
+  if (is_base64_encoded == 0) {
+    s->ssh_version = 1;
+    s->key_type = 0;
+    if (!isdigit (*line))
+      return -1;
+    if (sscanf (line, "%d %d ", &(s->bits), &(s->exponent)) != 2)
+      return -2;
+    /* TODO:
+     * There's probably an acceptable range...
+     */
+    if (s->bits <= 0 || s->exponent <= 0)
+      return 1;
+
+    line = strchr (line, ' ');
+    if (line == NULL)
+      return -3;
+    line++;
+    line = strchr (line, ' ');
+    if (line == NULL)
+      return -4;
+    line++;
+    /* FIXME:
+     * figure out what format modulus is in since its not clear
+     * from the man page
+     */
+    return -5;
+  }
+  else {
+    s->ssh_version = 2;
+    /* we only handle the rsa type */
+    if (strstr (line, "ssh-rsa") != line)
+      return -6;
+    s->key_type = 0;
+    line += 7;
+    if (*line != ' ')
+      return 2;
+    line++;
+    i = 0;
+    while (*line) {
+      if ((line[i] >= 0x30 && line[i] <= 0x39) ||
+	  (line[i] >= 0x41 && line[i] <= 0x5a) ||
+	  (line[i] >= 0x61 && line[i] <= 0x7a) ||
+	  (line[i] == '+') || (line[i] == '/') || (line[i] == '='))
+	i++;
+      else
+	break;
+    }
+    if (i == 0)
+      return 3;
+    tmp = malloc (sizeof (char) * (i + 5));
+    strncpy (tmp, line, i);
+    /* this should hopefully avoid any issues with reading 
+     * past the array if its malformed */
+    tmp[i] = tmp[i + 1] = tmp[i + 2] = tmp[i + 3] = tmp[i + 4] = 0;
+    i = j = Curl_base64_decode (tmp, (unsigned char **) &tmp2);
+    /* printf("Decode Size: %d\n", i); */
+    free (tmp);
+
+    if (i == 0)
+      return 4;
+
+    s->md5 = malloc (16);
+
+    MD5_Init (ctx);
+    MD5_Update (ctx, tmp2, j);
+    MD5_Final (s->md5, ctx);
+
+
+    line = tmp2;
+    i = ssh_proto_str_read (line, &tmp, tmp2 + j);
+    if (i < 0) {
+      free (tmp2);
+      return 5;
+    }
+    /* TODO: verify that its ssh-rsa -- its the only one
+     * supported
+     */
+    if (!(i == 11 && tmp[0] == 's' && tmp[1] == 's' &&
+	  tmp[2] == 'h' && tmp[3] == '-' && tmp[4] == 'r' &&
+	  tmp[5] == 's' && tmp[6] == 'a')) {
+      free (tmp);
+      free (tmp2);
+      return 8;
+    }
+
+    free (tmp);
+    line += i;
+    i = ssh_proto_str_read (line, &tmp, tmp2 + j);
+    if (i < 0) {
+      free (tmp2);
+      return 6;
+    }
+    /* TODO: verify that the exponent is valid */
+    if (i == 5)
+      s->exponent = (unsigned short) ((unsigned char) *tmp);
+    else {
+      free (tmp);
+      free (tmp2);
+      return 9;
+    }
+
+    free (tmp);
+    line += i;
+    i = ssh_proto_str_read (line, &tmp, tmp2 + j);
+    if (i < 0) {
+      free (tmp2);
+      return 7;
+    }
+
+    /* TODO: the modulus may need to be converted to
+     * big integer format
+     */
+    s->modulus_length = i - 4;
+    s->modulus = tmp;
+
+    s->bits = (s->modulus_length - 1) * 8;
+
+    free (tmp2);
+    return 0;
+  }
+}
+void
+free_ssh_host_entry (SSH_HOST_ENTRY * s)
+{
+  int i;
+  if (s == NULL)
+    return;
+
+  if (s->hostname_line != NULL) {
+    free (s->hostname_line);
+    s->hostname_line = NULL;
+  }
+/*
+	for (i=0; i < s->hostnames_size; i++) {
+		if (s->hostnames[i] != NULL) {
+			free(s->hostnames[i]);
+			s->hostnames[i] = NULL;
+		}
+	}
+*/
+  if (s->hostnames != NULL && s->hostnames_size > 0) {
+    free (s->hostnames);
+    s->hostnames = NULL;
+  }
+  s->hostnames_size = s->bits = s->exponent = -1;
+
+  if (s->modulus != NULL) {
+    free (s->modulus);
+    s->modulus = NULL;
+  }
+  s->modulus_length = -1;
+  s->ssh_version = -1;
+
+  if (s->md5 != NULL) {
+    free (s->md5);
+    s->md5 = NULL;
+  }
+
+  free (s);
+}
+
+#ifdef SSH_HOSTNAME_TESTS
+int
+ssh_unit_tests (int argc, char **argv)
+{
+  char *l[] = {
+    "closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net",
+    "cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=",
+    " cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=",
+    "",
+    ",",
+    "f, ",
+    "cvs.example.net ssh-rsa AAAA1234.....=",
+    "192.168.30.118 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwWVqxKm2Biwilakq9Ex8/tzHVQjRrzEkwlrWTDneptodVgqAzXUFQSa6Oj9AwzdDPhKe71vTv7RhXYg0ZvB1a5dIkzgCdoF/mIuTb80LvK7f0NxCaAHWODuHbwlJeMmjHV0WFsjsdOf690fPqeinD/8jfBQB950M1K3Qesib9H75gsnawF06MzZ52nC1HHi8mG2tGy2PMyP+mJs7KN1v4T+nobZ10ePe1dMqYXMdro/PB0JQmuGL7bBR5GRDEkK6nFcp2HsvuzXSeWZJcmWDdo+1n0cNg2th5VEIxrrFG5iy0CA2AXVPMqkf3VrAXGXV66dJTGtBqZ5GoxJCxDgW6w==",
+    "|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsaAAAA1234.....="
+  };
+  int s;
+  int cases = sizeof (l) / sizeof (char *);
+
+  if (argc == 2) {
+    s = atoi (argv[1]);
+    if (s >= 0 && s < cases) {
+      SSH_HOST_ENTRY *x = NULL;
+      printf ("%d\n", s = new_ssh_host_entry (&x, l[s]));
+      free_ssh_host_entry (x);
+      return s;
+    }
+  }
+}
+#endif
+/** Returns 0 for a match, non-zero otherwise. */
+int
+ssh_host_entry_match (SSH_HOST_ENTRY * x, char *host)
+{
+  /* TODO: Add pattern matching and/or DNS matching against
+   * to entries found in x
+   */
+  int i;
+  if (host == NULL || x == NULL)
+    return -1;
+
+  for (i = 0; i < x->hostnames_size; i++)
+    if (curl_strequal (x->hostnames[i], host))
+      return 0;
+
+  return 1;
+}
--- ../curl-7.17.0/./lib/ssh.c	2007-09-02 14:53:15.000000000 -0700
+++ ./lib/ssh.c	2007-10-22 22:25:21.000000000 -0700
@@ -106,6 +106,8 @@
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
 #include "multiif.h"
 
+#include "sshentry.h"
+
 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
 #include "inet_ntoa_r.h"
 #endif
@@ -307,8 +309,9 @@
   struct SSHPROTO *sftp_scp = data->reqdata.proto.ssh;
   struct ssh_conn *sshc = &conn->proto.sshc;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-#ifdef CURL_LIBSSH2_DEBUG
   const char *fingerprint;
+#ifdef CURL_LIBSSH2_DEBUG
+  /* const char *fingerprint; */
 #endif /* CURL_LIBSSH2_DEBUG */
   int rc;
   long err;
@@ -357,6 +360,69 @@
     case SSH_AUTHLIST:
       /* TBD - methods to check the host keys need to be done */
 
+      /* To ponder about: should really the lib be messing about with the
+         HOME environment variable etc? */
+      {
+        char * home = curl_getenv("HOME");
+        if (data->set.str[STRING_SSH_KNOWNHOSTS_FILE])
+           sshc->knownhosts = aprintf("%s", 
+              data->set.str[STRING_SSH_KNOWNHOSTS_FILE]);
+        else if (home)
+           sshc->knownhosts = aprintf("%s/.ssh/known_hosts", home);
+        Curl_safefree(home);
+        home = NULL; 
+      }
+
+      if (sshc->knownhosts != NULL) {
+        FILE * fl = fopen(sshc->knownhosts, "r");
+        SSH_HOST_ENTRY * x = NULL;
+        if (fl) {
+           /** 8K per authorized keys format (in man page sshd) */
+           char tmp[8192+1];
+           while (fgets(tmp, 8192, fl) != NULL) {
+              if ((rc = new_ssh_host_entry(&x, tmp)) == 0 &&
+                 ssh_host_entry_match(x, conn->host.name) == 0)
+                 break;
+              free_ssh_host_entry(x);
+              x = NULL;
+           }
+           fclose(fl);
+           fl = NULL;
+        }
+        /** this basically causes it to fail if it cant find
+         * a hostname that remotely matches
+         */
+        if (rc != 0) {
+          failf(data, "Authentication failure");
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualCode = CURLE_FAILED_INIT;
+          break;
+        }
+        /** TODO: See about checking the key directly, not the
+         * checksum of it.
+         */
+        fingerprint = libssh2_hostkey_hash(sftp_scp->ssh_session,
+                                           LIBSSH2_HOSTKEY_HASH_MD5);
+        if (x != NULL) {
+          /* FIXME:
+           * allows us to use the external md5 functions 
+           */
+          for (rc=0; rc < 16; rc++)
+            if (x->md5[rc] != fingerprint[rc]) {
+              rc = -1; 
+              break;
+            }
+          if (rc == -1) {
+            failf(data, "Authentication failure");
+            state(conn, SSH_SESSION_FREE);
+            sshc->actualCode = CURLE_FAILED_INIT;
+            break;
+          }
+          free_ssh_host_entry(x);
+        }
+      } 
+
+
       /*
        * Figure out authentication methods
        * NB: As soon as we have provided a username to an openssh server we
@@ -431,6 +497,7 @@
           break;
         }
 
+
         sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
         if (!sshc->passphrase)
           sshc->passphrase = "";
--- ../curl-7.17.0/./lib/url.c	2007-09-02 14:53:15.000000000 -0700
+++ ./lib/url.c	2007-10-18 22:16:03.000000000 -0700
@@ -1830,6 +1830,14 @@
                             va_arg(param, char *));
     break;
 
+  case CURLOPT_SSH_KNOWNHOSTS_FILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/known_hosts file
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS_FILE],
+                            va_arg(param, char *));
+    break;
+
   case CURLOPT_HTTP_TRANSFER_DECODING:
     /*
      * disable libcurl transfer encoding is used
--- ../curl-7.17.0/./src/main.c	2007-09-02 14:53:16.000000000 -0700
+++ ./src/main.c	2007-10-22 22:31:10.000000000 -0700
@@ -407,6 +407,7 @@
   char *key_type;
   char *key_passwd;
   char *pubkey;
+  char *knownhosts;
   char *engine;
   bool list_engines;
   bool crlf;
@@ -1535,6 +1536,7 @@
     {"Ef","engine",      TRUE},
     {"Eg","capath ",     TRUE},
     {"Eh","pubkey",      TRUE},
+    {"Ej","known_hosts", TRUE},
     {"f", "fail",        FALSE},
     {"F", "form",        TRUE},
     {"Fs","form-string", TRUE},
@@ -2144,6 +2146,9 @@
       case 'h': /* --pubkey public key file */
         GetStr(&config->pubkey, nextarg);
         break;
+      case 'j': /* --known_hosts known hosts file */
+        GetStr(&config->knownhosts, nextarg);
+        break;
       default: /* certificate file */
         {
           char *ptr = strchr(nextarg, ':');
@@ -3303,6 +3308,8 @@
     free(config->key_type);
   if (config->pubkey)
     free(config->pubkey);
+  if (config->knownhosts)
+    free(config->knownhosts);
   if (config->referer)
     free(config->referer);
 
@@ -4190,6 +4197,7 @@
 	/* SSH private key uses the same command-line option as SSL private key */
         my_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
         my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
+        my_setopt(curl, CURLOPT_SSH_KNOWNHOSTS_FILE, config->knownhosts);
 
         /* default to strict verifyhost */
         my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
--- ../curl-7.17.0/./lib/sshentry.h	1969-12-31 16:00:00.000000000 -0800
+++ ./lib/sshentry.h	2007-10-22 22:01:11.000000000 -0700
@@ -0,0 +1,36 @@
+#ifndef __SSHENTRY_H
+#define __SSHENTRY_H
+
+/** this option provides the unit test cases which can be called
+ * directly from main if needed
+#define SSH_HOSTNAME_TESTS
+ */
+
+/**
+ * The format of this is described here:
+ * http://www.openbsd.org/cgi-bin/man.cgi?query=sshd&sektion=8
+ * and is parsed based on a mixture of the actual implementation
+ * as well as the man page itself.
+ */
+typedef struct ssh_knownhost_entry
+{
+  char *hostname_line;
+  char **hostnames;
+  int hostnames_size;
+/* pretty much always zero for ssh_rsa although there could be others */
+  int key_type;
+  unsigned short bits;
+  unsigned short exponent;
+  char *modulus;
+  int modulus_length;
+/* version 1, version 2... */
+  int ssh_version;
+/* points to sixteen bytes of checksum or nothing */
+  char *md5;
+} SSH_HOST_ENTRY;
+
+
+int new_ssh_host_entry (SSH_HOST_ENTRY ** s, char *line);
+void free_ssh_host_entry (SSH_HOST_ENTRY * s);
+int ssh_host_entry_match (SSH_HOST_ENTRY * x, char *host);
+#endif
--- ../curl-7.17.0/./lib/urldata.h	2007-09-02 14:53:15.000000000 -0700
+++ ./lib/urldata.h	2007-10-18 22:37:23.000000000 -0700
@@ -496,6 +496,7 @@
    struct */
 struct ssh_conn {
   const char *authlist; /* List of auth. methods, managed by libssh2 */
+  char * knownhosts; /* file name containing known hosts */
 #ifdef USE_LIBSSH2
   const char *passphrase;
   char *rsa_pub;
@@ -1276,6 +1277,7 @@
   STRING_USERAGENT,       /* User-Agent string */
   STRING_USERPWD,         /* <user:password>, if used */
 
+  STRING_SSH_KNOWNHOSTS_FILE, /* path to the known hosts file for host auth */
   /* -- end of strings -- */
   STRING_LAST /* not used, just an end-of-list marker */
 };
--- ../curl-7.17.0/./lib/ca-bundle.h	2007-09-13 13:22:53.000000000 -0700
+++ ./lib/ca-bundle.h	2007-10-18 23:48:40.000000000 -0700
@@ -1 +1,2 @@
-/* ca bundle path set in here*/
+/* This file is generated automatically */
+#define CURL_CA_BUNDLE "/home/jrl/software/share/curl/curl-ca-bundle.crt"
--- ../curl-7.17.0/./include/curl/curl.h	2007-09-02 14:53:15.000000000 -0700
+++ ./include/curl/curl.h	2007-10-18 22:12:29.000000000 -0700
@@ -1124,6 +1124,7 @@
   CINIT(NEW_FILE_PERMS, LONG, 159),
   CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
 
+  CINIT(SSH_KNOWNHOSTS_FILE, OBJECTPOINT, 162),
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
--- ../curl-7.17.0/./lib/Makefile.in	2007-09-02 14:53:28.000000000 -0700
+++ ./lib/Makefile.in	2007-10-18 20:32:59.000000000 -0700
@@ -70,7 +70,7 @@
 	strerror.lo hostares.lo hostasyn.lo hostip4.lo hostip6.lo \
 	hostsyn.lo hostthre.lo inet_ntop.lo parsedate.lo select.lo \
 	gtls.lo sslgen.lo tftp.lo splay.lo strdup.lo socks.lo ssh.lo \
-	nss.lo qssl.lo
+	nss.lo qssl.lo sshentry.lo
 am__objects_2 =
 am_libcurl_la_OBJECTS = $(am__objects_1) $(am__objects_2)
 libcurl_la_OBJECTS = $(am_libcurl_la_OBJECTS)
--- ../curl-7.17.0/./lib/Makefile.inc	2007-08-11 13:51:23.000000000 -0700
+++ ./lib/Makefile.inc	2007-10-18 20:23:43.000000000 -0700
@@ -9,7 +9,7 @@
   http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c	\
   hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c	\
   inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c	\
-  strdup.c socks.c ssh.c nss.c qssl.c
+  strdup.c socks.c ssh.c nss.c qssl.c sshentry.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h	\
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
