Patch forwarded to the libssh2 list for Johnny Luong.

---------- Forwarded message ----------
Date: Wed, 28 Nov 2007 21:23:07 -0800
From: Johnny Luong <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: Re: patch for ssh user known_hosts

Hi Daniel,

Could you forward this to the libssh mailing list?  I've tried sending a patch
to the list before and it doesn't quite work the way I thought it would.  This
patch applies cleanly to both the 0.18 version and 0.17 version.

Best Regards,
Johnny Luong
--- ../../libssh2-0.17/src/libssh2_priv.h       2007-08-06 13:41:31.000000000 
-0700

+++ libssh2_priv.h      2007-11-28 20:39:08.000000000 -0800

@@ -933,6 +933,30 @@

     int (*dtor) (LIBSSH2_SESSION * session, void **abstract);

 };

 

+/**

+ * 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;

+    /* NUL-terminated list of hostnames */

+    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;

+} LIBSSH2_KNOWNHOSTS;

+

 #define LIBSSH2_DBG_TRANS   1

 #define LIBSSH2_DBG_KEX     2

 #define LIBSSH2_DBG_AUTH    3

@@ -1141,4 +1165,32 @@

 int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,

                                 unsigned char **i, unsigned int *ilen);

 

+/* sshentry.c */

+/** @fn int libssh2_new_host_entry(LIBSSH2_SESSION * session,

+    LIBSSH2_KNOWNHOSTS ** s, char *line)

+ * Allocates and parses a ssh host entry as provided by the

+ * NUL-terminated line.

+ * @param session An existing ssh session

+ * @param s the ssh_host_entry handle (of a ptr)

+ * @param line an ascii nul-terminated line containing the public key

+ * @return zero if successful, non-zero otherwise

+ */

+int libssh2_new_host_entry(LIBSSH2_SESSION *, LIBSSH2_KNOWNHOSTS **, char *);

+

+/** @fn void libssh2_free_host_entry(LIBSSH2_SESSION * session, 

+    LIBSSH2_KNOWNHOSTS *s)

+ * Deallocates any memory used by this struct.

+ * @param session An existing ssh session

+ * @param s the ssh_host_entry ptr

+ */

+void libssh2_free_host_entry(LIBSSH2_SESSION *, LIBSSH2_KNOWNHOSTS *);

+

+/** @fn int libssh2_host_entry_match(LIBSSH2_KNOWNHOSTS * x, char *host)

+ * Attempts to find out if the hostname provided matches one of the

+ * hostname entries in the LIBSSH2_KNOWNHOSTS.

+ * @param x the ssh_host_entry ptr

+ * @param host the hostname you are trying to match

+ * @return zero if match, non-zero otherwise

+ */ 

+int libssh2_host_entry_match(LIBSSH2_KNOWNHOSTS *, char *);

 #endif /* LIBSSH2_H */

--- ../../libssh2-0.17/src/Makefile.am  2007-07-28 15:59:21.000000000 -0700

+++ Makefile.am 2007-11-28 21:03:08.000000000 -0800

@@ -3,7 +3,7 @@

 

 libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c    \

 misc.c packet.c publickey.c scp.c session.c sftp.c userauth.c          \

-libssh2_priv.h openssl.h libgcrypt.h pem.c transport.c

+libssh2_priv.h openssl.h libgcrypt.h pem.c transport.c sshentry.c

 

 if LIBGCRYPT

 libssh2_la_SOURCES += libgcrypt.c

--- ../../libssh2-0.17/src/sshentry.c   1969-12-31 16:00:00.000000000 -0800

+++ sshentry.c  2007-11-28 20:58:47.000000000 -0800

@@ -0,0 +1,393 @@

+#include <stdio.h>

+#include <stdlib.h>

+#include <string.h>

+#include <ctype.h>

+

+#include "libssh2_priv.h"

+

+static int 

+ssh_host_parse_hostnames (LIBSSH2_SESSION * session,

+  LIBSSH2_KNOWNHOSTS * s, 

+  char *line,

+  char *end

+);

+

+static int 

+ssh_host_parse_key (LIBSSH2_SESSION * session,

+  LIBSSH2_KNOWNHOSTS * s, 

+  char *line,

+  int is_base64_encoded

+);

+

+/* Returns zero if successful, > zero for malformed data, < 0 not supported. */

+int 

+libssh2_new_host_entry(LIBSSH2_SESSION * session, 

+  LIBSSH2_KNOWNHOSTS ** s, 

+  char *line

+)

+{

+  char *tmp = NULL;

+  LIBSSH2_KNOWNHOSTS *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 = (LIBSSH2_KNOWNHOSTS *) 

+    LIBSSH2_ALLOC(session, sizeof(LIBSSH2_KNOWNHOSTS));

+

+  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 (session, t, line, tmp);

+  if (i != 0) {

+    libssh2_free_host_entry (session, t);

+    return ((i > 0) ? 4 : -1);

+  }

+

+  line = tmp + 1;

+  tmp = strchr (line, ' ');

+  if (tmp != NULL)

+    tmp = strchr (tmp + 1, ' ');

+

+  i = ssh_host_parse_key (session, t, line, tmp == NULL ? 1 : 0);

+  if (i != 0) {

+    libssh2_free_host_entry (session, t);

+    return ((i > 0) ? 5 : -2);

+  }

+

+  *s = t;

+  return 0;

+}

+

+static int

+ssh_host_parse_hostnames (LIBSSH2_SESSION * session,

+  LIBSSH2_KNOWNHOSTS * s, 

+  char *line, 

+  char *end

+)

+{

+  char *start;

+  char *comma = NULL;

+  int i;

+

+  /* TODO: 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 *) LIBSSH2_ALLOC (session, (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, ',')) != NULL) {

+    comma++;

+    if (*comma == ',' || *comma == 0) {

+      LIBSSH2_FREE (session, s->hostname_line);

+      s->hostname_line = NULL;

+      return 2;

+    }

+    s->hostnames_size++;

+  }

+  s->hostnames = (char **) LIBSSH2_ALLOC 

+    (session, sizeof (char *) * s->hostnames_size);

+

+  start = comma = s->hostname_line;

+  i = 0;

+  while ((comma = strchr (comma, ',')) != NULL) {

+    *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 (LIBSSH2_SESSION * session, 

+  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 = LIBSSH2_ALLOC (session, len);

+  memcpy (*val, line + 4, len);

+  return len + 4;

+}

+static int

+ssh_host_parse_key (LIBSSH2_SESSION * session,

+  LIBSSH2_KNOWNHOSTS * 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 */

+  libssh2_md5_ctx ctx;

+  /* 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, "%hd %hd ", &(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++;

+    /* TODO:

+     * 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 = LIBSSH2_ALLOC (session, 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);

+*/

+

+/* FIXME: 

+ * Must use a base64 decoder implementation in order to decode stuff. 

+ */

+    {

+       /* TODO: rework the api interface instead of making a local instance */

+       i = libssh2_base64_decode(session, &tmp2, &j, tmp, strlen(tmp));

+       LIBSSH2_FREE(session, tmp);

+       if (i != 0)

+          return 4;

+

+    }

+

+    /* printf("Decode Size: %d\n", i); */

+    /* free (tmp); */

+

+

+#if LIBSSH2_MD5

+    s->md5 = LIBSSH2_ALLOC (session, 16);

+

+    libssh2_md5_init (&ctx);

+    libssh2_md5_update (ctx, tmp2, j);

+    libssh2_md5_final (ctx, s->md5);

+/*

+    MD5_Init (ctx);

+    MD5_Update (ctx, tmp2, j);

+    MD5_Final (s->md5, ctx);

+*/

+#endif

+

+

+    line = tmp2;

+    i = ssh_proto_str_read (session, line, &tmp, tmp2 + j);

+    if (i < 0) {

+      LIBSSH2_FREE (session, 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;

+    }

+

+    LIBSSH2_FREE (session, tmp);

+    line += i;

+    i = ssh_proto_str_read (session, line, &tmp, tmp2 + j);

+    if (i < 0) {

+      LIBSSH2_FREE (session, tmp2);

+      return 6;

+    }

+    /* TODO: verify that the exponent is valid */

+    if (i == 5)

+      s->exponent = (unsigned short) ((unsigned char) *tmp);

+    else {

+      LIBSSH2_FREE (session, tmp);

+      LIBSSH2_FREE (session, tmp2);

+      return 9;

+    }

+

+    LIBSSH2_FREE (session, tmp);

+    line += i;

+    i = ssh_proto_str_read (session, line, &tmp, tmp2 + j);

+    if (i < 0) {

+      LIBSSH2_FREE (session, 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;

+

+    LIBSSH2_FREE (session, tmp2);

+    return 0;

+  }

+}

+void

+libssh2_free_host_entry(LIBSSH2_SESSION * session, LIBSSH2_KNOWNHOSTS * s)

+{

+  /* int i; */

+  if (s == NULL)

+    return;

+

+  if (s->hostname_line != NULL) {

+    LIBSSH2_FREE (session, 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) {

+    LIBSSH2_FREE (session, s->hostnames);

+    s->hostnames = NULL;

+  }

+  s->hostnames_size = s->bits = s->exponent = -1;

+

+  if (s->modulus != NULL) {

+    LIBSSH2_FREE (session, s->modulus);

+    s->modulus = NULL;

+  }

+  s->modulus_length = -1;

+  s->ssh_version = -1;

+

+  if (s->md5 != NULL) {

+    LIBSSH2_FREE (session, s->md5);

+    s->md5 = NULL;

+  }

+

+  LIBSSH2_FREE (session, 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) {

+      LIBSSH2_KNOWNHOSTS *x = NULL;

+      printf ("%d\n", s = new_ssh_host_entry (&x, l[s]));

+      libssh2_free_host_entry (x);

+      return s;

+    }

+  }

+}

+#endif

+/** Returns 0 for a match, non-zero otherwise. */

+int

+ssh_host_entry_match (LIBSSH2_KNOWNHOSTS * 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;

+

+  /* FIXME: this should use a case-insensitive compare as dns hostnames

+   * are generally case insensitive anyways 

+   */

+  for (i = 0; i < x->hostnames_size; i++)

+    if (!strcmp (x->hostnames[i], host))

+      return 0;

+

+  return 1;

+}

--- ../../libssh2-0.17/src/Makefile.in  2007-07-31 03:02:52.000000000 -0700

+++ Makefile.in 2007-11-28 21:02:50.000000000 -0800

@@ -65,12 +65,12 @@

 am__libssh2_la_SOURCES_DIST = channel.c comp.c crypt.c hostkey.c kex.c \

        mac.c misc.c packet.c publickey.c scp.c session.c sftp.c \

        userauth.c libssh2_priv.h openssl.h libgcrypt.h pem.c \

-       transport.c libgcrypt.c openssl.c

+       transport.c libgcrypt.c openssl.c sshentry.c

 @[EMAIL PROTECTED] = libgcrypt.lo

 @[EMAIL PROTECTED] = openssl.lo

 am_libssh2_la_OBJECTS = channel.lo comp.lo crypt.lo hostkey.lo kex.lo \

        mac.lo misc.lo packet.lo publickey.lo scp.lo session.lo \

-       sftp.lo userauth.lo pem.lo transport.lo $(am__objects_1) \

+       sftp.lo userauth.lo pem.lo transport.lo sshentry.lo $(am__objects_1) \

        $(am__objects_2)

 libssh2_la_OBJECTS = $(am_libssh2_la_OBJECTS)

 DEFAULT_INCLUDES = 

-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell.  From the desktop to the data center, Linux is going
mainstream.  Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
libssh2-devel mailing list
libssh2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libssh2-devel

Reply via email to