From 00abf43ddb90e099dc343643934bf5565da5c0f4 Mon Sep 17 00:00:00 2001
From: Alexander Lamaison <awl03@doc.ic.ac.uk>
Date: Tue, 23 Feb 2010 21:55:26 +0000
Subject: [PATCH] Call libssh2_error for ever knownhost API failure.

The libssh2 API calls should set the last error code and a message when
returning a failure by calling libssh2_error.  This changeset adds these
calls to the libssh2_knownhost_* API.

It also changes libssh2_base64_decode to work this way and changes the
return value of the libssh2_knownhost_check function to be negative on
failure which matches the other APIs.
---
 include/libssh2.h |    4 +-
 src/knownhost.c   |  152 ++++++++++++++++++++++++++++++++++++++++++-----------
 src/misc.c        |    4 ++
 3 files changed, 127 insertions(+), 33 deletions(-)

diff --git a/include/libssh2.h b/include/libssh2.h
index 5c24d26..bc8a85f 100644
--- a/include/libssh2.h
+++ b/include/libssh2.h
@@ -773,14 +773,14 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
  *
  * Returns:
  *
- * LIBSSH2_KNOWNHOST_CHECK_* values, see below
+ * LIBSSH2_KNOWNHOST_CHECK_* values, see below, or a negative value if there
+ * is an unexpected failure.
  *
  */
 
 #define LIBSSH2_KNOWNHOST_CHECK_MATCH    0
 #define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1
 #define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2
-#define LIBSSH2_KNOWNHOST_CHECK_FAILURE  3
 
 LIBSSH2_API int
 libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
diff --git a/src/knownhost.c b/src/knownhost.c
index 64c008d..3d05a5b 100644
--- a/src/knownhost.c
+++ b/src/knownhost.c
@@ -84,8 +84,12 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session)
     LIBSSH2_KNOWNHOSTS *knh =
         LIBSSH2_ALLOC(session, sizeof(struct _LIBSSH2_KNOWNHOSTS));
 
-    if(!knh)
+    if(!knh) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for known-hosts "
+                      "collection", 0);
         return NULL;
+    }
 
     knh->session = session;
 
@@ -144,16 +148,22 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
     struct known_host *entry =
         LIBSSH2_ALLOC(hosts->session, sizeof(struct known_host));
     size_t hostlen = strlen(host);
-    int rc = LIBSSH2_ERROR_ALLOC;
+    int rc;
     char *ptr;
     unsigned int ptrlen;
 
-    if(!entry)
-        return rc;
+    if(!entry) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for known host entry", 0);
+        return LIBSSH2_ERROR_ALLOC;
+    }
 
-    if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK))
+    if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) {
         /* make sure we have a key type set */
+        libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL,
+                      "No key type set", 0);
         return LIBSSH2_ERROR_INVAL;
+    }
 
     memset(entry, 0, sizeof(struct known_host));
 
@@ -163,8 +173,12 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
     case LIBSSH2_KNOWNHOST_TYPE_PLAIN:
     case LIBSSH2_KNOWNHOST_TYPE_CUSTOM:
         entry->name = LIBSSH2_ALLOC(hosts->session, hostlen+1);
-        if(!entry->name)
+        if(!entry->name) {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for host name", 0);
+            rc = LIBSSH2_ERROR_ALLOC;
             goto error;
+        }
         memcpy(entry->name, host, hostlen+1);
         break;
     case LIBSSH2_KNOWNHOST_TYPE_SHA1:
@@ -183,6 +197,8 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
         entry->salt_len = ptrlen;
         break;
     default:
+        libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Unknown host name type", 0);
         rc = LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
         goto error;
     }
@@ -192,8 +208,12 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
         if(!keylen)
             keylen = strlen(key);
         entry->key = LIBSSH2_ALLOC(hosts->session, keylen+1);
-        if(!entry->key)
+        if(!entry->key) {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for key", 0);
+            rc = LIBSSH2_ERROR_ALLOC;
             goto error;
+        }
         memcpy(entry->key, key, keylen+1);
         entry->key[keylen]=0; /* force a terminating zero trailer */
     }
@@ -201,8 +221,13 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
         /* key is raw, we base64 encode it and store it as such */
         size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
                                              &ptr);
-        if(!nlen)
+        if(!nlen) {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for base64-encoded "
+                          "key", 0);
+            rc = LIBSSH2_ERROR_ALLOC;
             goto error;
+        }
 
         entry->key = ptr;
     }
@@ -232,10 +257,10 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts,
  *
  * Returns:
  *
- * LIBSSH2_KNOWNHOST_CHECK_FAILURE
  * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND
  * LIBSSH2_KNOWNHOST_CHECK_MATCH
  * LIBSSH2_KNOWNHOST_CHECK_MISMATCH
+ * [negative value] - unexpected failure
  */
 LIBSSH2_API int
 libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
@@ -257,8 +282,12 @@ libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts,
         /* we got a raw key input, convert it to base64 for the checks below */
         size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen,
                                              &keyalloc);
-        if(!nlen)
-            return LIBSSH2_KNOWNHOST_CHECK_FAILURE;
+        if(!nlen) {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for base64-encoded "
+                          "key", 0);
+            return LIBSSH2_ERROR_ALLOC;
+        }
 
         /* make the key point to this */
         key = keyalloc;
@@ -344,9 +373,13 @@ libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts,
                       struct libssh2_knownhost *entry)
 {
     struct known_host *node;
-    if(!entry || (entry->magic != KNOWNHOST_MAGIC))
-        /* check that this was retrieved the right way or get out */
+    
+    /* check that this was retrieved the right way or get out */
+    if(!entry || (entry->magic != KNOWNHOST_MAGIC)) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL,
+                      "Invalid host information", 0);
         return LIBSSH2_ERROR_INVAL;
+    }
 
     /* get the internal node pointer */
     node = entry->node;
@@ -440,8 +473,13 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
         if(*p=='|') {
             const char *hash = NULL;
             size_t saltlen = p - salt;
-            if(saltlen >= (sizeof(saltbuf)-1))
-                return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED; /* weird length */
+            if(saltlen >= (sizeof(saltbuf)-1)) { /* weird length */
+                libssh2_error(hosts->session,
+                              LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                              "Failed to parse known_hosts line (unexpectedly "
+                              "long salt)", 0);
+                return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+            }
 
             memcpy(saltbuf, salt, saltlen);
             saltbuf[saltlen] = 0; /* zero terminate */
@@ -457,11 +495,16 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
             return 0;
     }
 
-    /* make some checks that the lenghts seem sensible */
+    /* make some checks that the lengths seem sensible */
     if((keylen < 20) ||
        (seplen >= sizeof(hostbuf)-1) ||
-       (hostlen >= sizeof(hostbuf)-1))
-        return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+       (hostlen >= sizeof(hostbuf)-1)) {
+            libssh2_error(hosts->session,
+                          LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                          "Failed to parse known_hosts line (unexpected "
+                          "length)", 0);
+            return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+        }
 
     switch(key[0]) {
     case '0': case '1': case '2': case '3': case '4':
@@ -480,8 +523,13 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
             type |= LIBSSH2_KNOWNHOST_KEY_SSHDSS;
         else if(!strncmp(key, "ssh-rsa", 7))
             type |= LIBSSH2_KNOWNHOST_KEY_SSHRSA;
-        else
-            return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED; /* unknown key type */
+        else {
+            /* unknown key type */
+            libssh2_error(hosts->session,
+                          LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                          "Unknown key type", 0);
+            return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+        }
 
         key += 7;
         keylen -= 7;
@@ -494,6 +542,9 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts,
         break;
 
     default: /* unknown key format */
+        libssh2_error(hosts->session,
+                      LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Unknown key format", 0);
         return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
     }
 
@@ -560,8 +611,11 @@ libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts,
     size_t keylen;
     int rc;
 
-    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
+    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Unsupported type of known-host information store", 0);
         return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+    }
 
     cp = line;
 
@@ -593,8 +647,11 @@ libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts,
     }
 
     if(!*cp || !len)
-        /* illegal line */
+        /* illegal line */ {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Failed to parse known_hosts line", 0);
         return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+    }
 
     keyp = cp; /* the key starts here */
     keylen = len;
@@ -634,8 +691,11 @@ libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts,
     int num = 0;
     char buf[2048];
 
-    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
+    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Unsupported type of known-host information store", 0);
         return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+    }
 
     file = fopen(filename, "r");
     if(file) {
@@ -646,8 +706,11 @@ libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts,
         }
         fclose(file);
     }
-    else
+    else {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_FILE,
+                      "Failed to open file", 0);
         return LIBSSH2_ERROR_FILE;
+    }
     return num;
 }
 
@@ -681,8 +744,11 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
 
     /* we only support this single file type for now, bail out on all other
        attempts */
-    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
+    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Unsupported type of known-host information store", 0);
         return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+    }
 
     tindex = (node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) >>
         LIBSSH2_KNOWNHOST_KEY_SHIFT;
@@ -696,14 +762,21 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
         char *saltalloc;
         nlen = _libssh2_base64_encode(hosts->session, node->name,
                                       node->name_len, &namealloc);
-        if(!nlen)
+        if(!nlen) {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for base64-encoded "
+                          "host name", 0);
             return LIBSSH2_ERROR_ALLOC;
+        }
 
         nlen = _libssh2_base64_encode(hosts->session,
                                       node->salt, node->salt_len,
                                       &saltalloc);
         if(!nlen) {
             free(namealloc);
+            libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for base64-encoded "
+                          "salt", 0);
             return LIBSSH2_ERROR_ALLOC;
         }
 
@@ -713,8 +786,11 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
         if(nlen <= buflen)
             sprintf(buf, "|1|%s|%s%s %s\n", saltalloc, namealloc, keytype,
                     node->key);
-        else
+        else {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
+                          "Known-host write buffer too small", 0);
             rc = LIBSSH2_ERROR_BUFFER_TOO_SMALL;
+        }
 
         free(namealloc);
         free(saltalloc);
@@ -725,8 +801,11 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
         if(nlen <= buflen)
             /* these types have the plain name */
             sprintf(buf, "%s%s %s\n", node->name, keytype, node->key);
-        else
+        else {
+            libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
+                          "Known-host write buffer too small", 0);
             rc = LIBSSH2_ERROR_BUFFER_TOO_SMALL;
+        }
     }
 
     /* we report the full length of the data with the trailing zero excluded */
@@ -752,8 +831,11 @@ libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts,
 {
     struct known_host *node;
 
-    if(known->magic != KNOWNHOST_MAGIC)
+    if(known->magic != KNOWNHOST_MAGIC) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL,
+                      "Invalid host information", 0);
         return LIBSSH2_ERROR_INVAL;
+    }
 
     node = known->node;
 
@@ -776,12 +858,18 @@ libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts,
 
     /* we only support this single file type for now, bail out on all other
        attempts */
-    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH)
+    if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "Unsupported type of known-host information store", 0);
         return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;
+    }
 
     file = fopen(filename, "w");
-    if(!file)
+    if(!file) {
+        libssh2_error(hosts->session, LIBSSH2_ERROR_FILE,
+                      "Failed to open file", 0);
         return LIBSSH2_ERROR_FILE;
+    }
 
     for(node = _libssh2_list_first(&hosts->head);
         node;
@@ -796,6 +884,8 @@ libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts,
         nwrote = fwrite(buffer, 1, wrote, file);
         if(nwrote != wrote) {
             /* failed to write the whole thing, bail out */
+            libssh2_error(hosts->session, LIBSSH2_ERROR_FILE,
+                          "Write failed", 0);
             rc = LIBSSH2_ERROR_FILE;
             break;
         }
diff --git a/src/misc.c b/src/misc.c
index 44e68e1..52e44e0 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -189,6 +189,8 @@ libssh2_base64_decode(LIBSSH2_SESSION *session, char **data,
     *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
     d = (unsigned char *) *data;
     if (!d) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for base64 decoding", 0);
         return -1;
     }
 
@@ -217,6 +219,8 @@ libssh2_base64_decode(LIBSSH2_SESSION *session, char **data,
         /* Invalid -- We have a byte which belongs exclusively to a partial
            octet */
         LIBSSH2_FREE(session, *data);
+        libssh2_error(session, LIBSSH2_ERROR_INVAL,
+                      "Invalid data (byte belonging to partial octet)", 0);
         return -1;
     }
 
-- 
1.6.5.1.1367.gcd48


