From 08f4a544063d5c2ff90105e54bc0510bbaf4a7a1 Mon Sep 17 00:00:00 2001
From: unknown <jkovacic@.(none)>
Date: Mon, 19 Sep 2011 17:37:04 +0200
Subject: [PATCH] Added libssh2_session_supported_algs()

---
 docs/libssh2_session_supported_algs.3 |   29 +++++++++++++
 include/libssh2.h                     |    7 +++
 src/comp.c                            |   10 ++++
 src/kex.c                             |   75 +++++++++++++++++++++++++++++++++
 4 files changed, 121 insertions(+), 0 deletions(-)
 create mode 100644 docs/libssh2_session_supported_algs.3

diff --git a/docs/libssh2_session_supported_algs.3 b/docs/libssh2_session_supported_algs.3
new file mode 100644
index 0000000..8b8ffd0
--- /dev/null
+++ b/docs/libssh2_session_supported_algs.3
@@ -0,0 +1,29 @@
+.TH libssh2_session_supported_algs 3 "19 Sep 2011" "libssh2 1.4.0" "libssh2 manual"
+.SH NAME
+libssh2_session_supported_algs - get a list of supported algorithms for the given method_type
+.SH SYNOPSIS
+#include <libssh2.h>
+
+int libssh2_session_supported_algs(int method_type, char** algs, unsigned int nalgs);
+.SH DESCRIPTION
+Get a list of supported algorithms for each method_type. The method_type parameter is equivalent 
+to method_type in \fIlibssh2_session_method_pref(3)\fP. Algs must be user preallocated array of pointers to strings
+(e.g. char* methods[N_METHODS]) and nalgs is a number of preallocated elemnts in this array.
+If successful, the function will fill this array with supported algorithms (the same names as defined in RFC 4253)
+and terminate it with a NULL pointer.
+.SH RETURN VALUE
+On success, a number of returned algorithms (i.e a positive number will be returned).
+In case of a failure, an error code (a negative number, see below) is returned.
+.SH ERRORS
+\fILIBSSH2_ERROR_BAD_USE\fP - Invalid value of nalgs.
+
+\fILIBSSH2_ERROR_METHOD_NOT_SUPPORTED\fP -  Unknown method type.
+
+\fILIBSSH2_ERROR_INVAL\fP - Internal error (normally should not occur).
+
+\fILIBSSH2_ERROR_BUFFER_TOO_SMALL\fP - Preallocated buffer algs is too short.
+.SH AVAILABILITY
+Added in 1.4.0
+.SH SEE ALSO
+.BR libssh2_session_methods(3),
+.BR libssh2_session_method_pref()(3),
diff --git a/include/libssh2.h b/include/libssh2.h
index 8dc547c..0b84083 100644
--- a/include/libssh2.h
+++ b/include/libssh2.h
@@ -489,6 +489,13 @@ LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag,
                                      int value);
 LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session);
 
+/*
+    Retrieve a list of supported algorithms for given method_type (see ibssh2_session_method_pref)
+        algs  - user preallocated array of pointers to string which will be filled (and NULL terminated) in by the function
+		nalgs - number of reserved elements in algs, incl. the NULL termination
+*/
+LIBSSH2_API int libssh2_session_supported_algs(int method_type, char** algs, unsigned int nalgs);
+
 /* Userauth API */
 LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session,
                                         const char *username,
diff --git a/src/comp.c b/src/comp.c
index 0296f62..47c056f 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -383,6 +383,16 @@ static const LIBSSH2_COMP_METHOD *no_comp_methods[] = {
 const LIBSSH2_COMP_METHOD **
 _libssh2_comp_methods(LIBSSH2_SESSION *session)
 {
+    /* 
+       Looks like the original implementation expects a non-NULL session only.
+       When asking for supported algorithms, however, session will typically be NULL,
+       so the following is necessary to avoid NULL dereferrencing caused core dumps.
+    */
+    if ( NULL==session )
+    {
+        return comp_methods;
+    }
+	
     if(session->flag.compress)
         return comp_methods;
     else
diff --git a/src/kex.c b/src/kex.c
index d26b5f3..9614bf9 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -1896,3 +1896,78 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
     return 0;
 }
 
+/*
+ * libssh2_session_supported_algs()
+ * returns a number of returned algorithms (a positive number) on success,
+ * a negative number on failure
+ */
+
+LIBSSH2_API int libssh2_session_supported_algs(int method_type, char** algs, unsigned int nalgs)
+{
+    /*
+        TODO: do more appropriate error codes exist?
+    */
+    unsigned int i;
+    unsigned int ialg;
+    const LIBSSH2_COMMON_METHOD **mlist;
+
+    if ( nalgs<=0 )
+    {
+        return LIBSSH2_ERROR_BAD_USE; /* invalid nalgs */
+    }
+
+    switch (method_type)
+    {
+        case LIBSSH2_METHOD_KEX:
+            mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
+            break;
+
+        case LIBSSH2_METHOD_HOSTKEY:
+            mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
+            break;
+
+        case LIBSSH2_METHOD_CRYPT_CS:
+        case LIBSSH2_METHOD_CRYPT_SC:
+            mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();			
+            break;
+
+        case LIBSSH2_METHOD_MAC_CS:
+        case LIBSSH2_METHOD_MAC_SC:
+            mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods();
+            break;
+
+        case LIBSSH2_METHOD_COMP_CS:
+        case LIBSSH2_METHOD_COMP_SC:
+            mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods(NULL);
+            break;
+
+        default:
+            return LIBSSH2_ERROR_METHOD_NOT_SUPPORTED;  /* unknown method type */
+    }  /* switch */
+
+    if ( NULL==mlist )
+    {
+        return LIBSSH2_ERROR_INVAL; /* weird situation */
+    }
+
+
+    for ( i=0, ialg=0; ialg<nalgs-1 && NULL!=mlist[i]; i++ )
+    {
+        if ( NULL==mlist[i]->name )
+        {
+            /* probably this shouldn't occur but handle it gently anyway */
+            continue;
+        }
+
+        algs[ialg++] = mlist[i]->name;
+    } /* for i, ialg */
+
+    /* as mentioned, the returned list is NULL terminated */
+    algs[ialg] = NULL;
+    if ( ialg == nalgs-1 )
+    {
+        return LIBSSH2_ERROR_BUFFER_TOO_SMALL;  /* buffer too short */ 
+    }
+
+    return ialg;
+}
-- 
1.7.6.msysgit.0

