[X2Go-Commits] [libx2goclient] 09/09: src/x2goclient-openssh-version: x2goclient_openssh_version_parse ().

git-admin at x2go.org git-admin at x2go.org
Sat Apr 4 17:55:27 CEST 2020


This is an automated email from the git hooks/post-receive script.

x2go pushed a commit to branch master
in repository libx2goclient.

commit 19ca40073e7e02d3167f9e01afa2fc506393a92e
Author: Mihai Moldovan <ionic at ionic.de>
Date:   Sat Apr 4 17:54:52 2020 +0200

    src/x2goclient-openssh-version: x2goclient_openssh_version_parse ().
    
    Parses the OpenSSH version string into a version struct for later use.
---
 src/x2goclient-openssh-version.c | 245 +++++++++++++++++++++++++++++++++++++++
 src/x2goclient-openssh-version.h |  30 +++++
 2 files changed, 275 insertions(+)

diff --git a/src/x2goclient-openssh-version.c b/src/x2goclient-openssh-version.c
index 3ea53db..6fb193a 100644
--- a/src/x2goclient-openssh-version.c
+++ b/src/x2goclient-openssh-version.c
@@ -22,11 +22,15 @@
    Boston, MA  02110-1301, USA.
  */
 
+#include <glib.h>
+#include <glib/gprintf.h>
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "x2goclient-openssh-version.h"
+#include "x2goclient-utils.h"
 
 X2GoClientOpenSSHVersion* x2goclient_openssh_version_new (void) {
   return (g_slice_new0 (X2GoClientOpenSSHVersion));
@@ -46,3 +50,244 @@ static X2GoClientOpenSSHVersion* x2goclient_openssh_version_copy (X2GoClientOpen
 }
 
 G_DEFINE_BOXED_TYPE (X2GoClientOpenSSHVersion, x2goclient_openssh_version, &x2goclient_openssh_version_copy, &x2goclient_openssh_version_free)
+
+void x2goclient_openssh_version_parse (X2GoClientOpenSSHVersion *openssh_version, const gchar *version_string, GError **gerr) {
+  /* Basic sanity checks on struct and string. */
+  if (!(openssh_version)) {
+    g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_INVALID_STRUCT, "No version struct passed, cannot store extracted information.");
+    return;
+  }
+
+  if (!(version_string)) {
+    g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_INVALID_VERSION_STRING, "No version string passed, cannot extract information.");
+    return;
+  }
+
+  X2GoClientOpenSSHVersion *struct_work_copy = x2goclient_openssh_version_copy (openssh_version);
+
+  /*
+   * We expect the version string to have a more-or-less fixed format, such as:
+   *
+   * OpenSSH_<major>.<minor>p<patch><additional data>[,<whitespace><end of line>]
+   */
+  /* Start with the fixed preamble. */
+  const gchar *tmp = version_string;
+  if (!(g_str_has_prefix (tmp, "OpenSSH_"))) {
+    g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_INVALID_PREAMBLE, "Preamble in version string does not match expected value 'OpenSSH_'.");
+
+    x2goclient_openssh_version_free (struct_work_copy);
+    struct_work_copy = NULL;
+
+    return;
+  }
+
+  /* Skip preamble, scan for major version number separator (dot). */
+  tmp += 8;
+  const gchar *dot_search = g_strstr_len (tmp, -1, ".");
+  if (!(dot_search)) {
+    g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_NO_MAJOR_SEPARATOR, "Version string does not contain major version number separator.");
+
+    x2goclient_openssh_version_free (struct_work_copy);
+    struct_work_copy = NULL;
+
+    return;
+  }
+
+  g_assert (tmp < dot_search);
+
+  /* Sanity check on major version number - must be numeric/all digits. */
+  const gchar *int_search = NULL;
+  for (int_search = tmp; int_search < dot_search; ++int_search) {
+    if (!(g_ascii_isdigit (*int_search))) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_NOT_NUMERIC, "Major version number is not numeric.");
+
+      x2goclient_openssh_version_free (struct_work_copy);
+      struct_work_copy = NULL;
+
+      return;
+    }
+  }
+
+  /* Copy and convert major version number. */
+  gchar *tmp_copy = g_strndup (tmp, dot_search - tmp);
+  struct_work_copy->major = -1;
+
+  _Bool conv_err = TRUE,
+        min_err = TRUE,
+        max_err = TRUE;
+  const gchar *end = NULL;
+  long long conv = x2goclient_str_to_int (tmp_copy, TRUE, 0, TRUE, G_MAXUINT32, &end, &conv_err, &min_err, &max_err);
+
+  if (conv_err) {
+    if (min_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_UNDERFLOW, "Major version number is too small to fit into long long type.");
+    }
+    else if (max_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_OVERFLOW, "Major version number is too big to fit into long long type.");
+    }
+    else {
+      end = NULL;
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_NOT_NUMERIC, "Major version number is not numeric.");
+    }
+  }
+  else {
+    if (min_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_NEGATIVE, "Major version number is not numeric.");
+    }
+    else if (max_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_TOO_BIG, "Major version number is too big.");
+    }
+    else {
+      struct_work_copy->major = conv;
+    }
+  }
+
+  if (end) {
+    /* Map end pointer to original string. */
+    tmp += (end - tmp_copy);
+  }
+
+  g_free (tmp_copy);
+  tmp_copy = NULL;
+
+  if (0 > struct_work_copy->major) {
+    x2goclient_openssh_version_free (struct_work_copy);
+    struct_work_copy = NULL;
+
+    return;
+  }
+
+  /* Copy and convert minor version number. */
+  tmp_copy = g_strdup (tmp);
+  struct_work_copy->minor = -1;
+
+  conv_err = min_err = max_err = TRUE;
+  end = NULL;
+  conv = x2goclient_str_to_int (tmp_copy, TRUE, 0, TRUE, G_MAXUINT32, &end, &conv_err, &min_err, &max_err);
+
+  if (conv_err) {
+    if (min_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_UNDERFLOW, "Minor version number is too small to fit into long long type.");
+    }
+    else if (max_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_OVERFLOW, "Minor version number is too big to fit into long long type.");
+    }
+    else {
+      end = NULL;
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_NOT_NUMERIC, "Minor version number is not numeric.");
+    }
+  }
+  else {
+    if (min_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_NEGATIVE, "Minor version number is not numeric.");
+    }
+    else if (max_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_TOO_BIG, "Minor version number is too big.");
+    }
+    else {
+      struct_work_copy->minor = conv;
+    }
+  }
+
+  if (end) {
+    /* Map end pointer to original string. */
+    tmp += (end - tmp_copy);
+  }
+
+  g_free (tmp_copy);
+  tmp_copy = NULL;
+
+  /*
+   * Handle error and additionally scan for the next character which MUST be a
+   * 'p' according to our scheme.
+   */
+  if ((0 > struct_work_copy->minor) || ('p' != *tmp)) {
+    x2goclient_openssh_version_free (struct_work_copy);
+    struct_work_copy = NULL;
+
+    return;
+  }
+  else {
+    /* Skip 'p' character. */
+    ++tmp;
+  }
+
+  /* Copy and convert patch version number. */
+  tmp_copy = g_strdup (tmp);
+  struct_work_copy->patch = -1;
+
+  conv_err = min_err = max_err = TRUE;
+  end = NULL;
+  conv = x2goclient_str_to_int (tmp_copy, TRUE, 0, TRUE, G_MAXUINT32, &end, &conv_err, &min_err, &max_err);
+
+  if (conv_err) {
+    if (min_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_UNDERFLOW, "Patch version number is too small to fit into long long type.");
+    }
+    else if (max_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_OVERFLOW, "Patch version number is too big to fit into long long type.");
+    }
+    else {
+      end = NULL;
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_NOT_NUMERIC, "Patch version number is not numeric.");
+    }
+  }
+  else {
+    if (min_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_NEGATIVE, "Patch version number is not numeric.");
+    }
+    else if (max_err) {
+      g_set_error_literal (gerr, X2GOCLIENT_OPENSSH_VERSION_ERROR, X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_TOO_BIG, "Patch version number is too big.");
+    }
+    else {
+      struct_work_copy->patch = conv;
+    }
+  }
+
+  if (end) {
+    /* Map end pointer to original string. */
+    tmp += (end - tmp_copy);
+  }
+
+  g_free (tmp_copy);
+  tmp_copy = NULL;
+
+  if (0 > struct_work_copy->patch) {
+    x2goclient_openssh_version_free (struct_work_copy);
+    struct_work_copy = NULL;
+
+    return;
+  }
+
+  /* Scan for a comma which should follow any additional version data. */
+  end = g_strstr_len (tmp, -1, ",");
+  if (!(end)) {
+    /*
+     * Alternatively, scan for whitespace and we'll treat that as the
+     * additional version data separator.
+     */
+    end = g_strstr_len (tmp, -1, " \t");
+
+    if (!(end)) {
+      /*
+       * No separator means or trailing whitespace means that we'll have to
+       * fast-forward to the actual end.
+       */
+      end = (tmp + (strlen (tmp)));
+    }
+  }
+
+  if ((end) && (0 < (end - tmp))) {
+    /* If we have additional data, copy it. */
+    g_strlcpy (struct_work_copy->addon, tmp, (end - tmp));
+  }
+
+  /* Not having additional data is not an error. */
+
+  /* Copy the struct. */
+  *openssh_version = *struct_work_copy;
+
+  /* Lastly, free data. */
+  x2goclient_openssh_version_free (struct_work_copy);
+  struct_work_copy = NULL;
+}
diff --git a/src/x2goclient-openssh-version.h b/src/x2goclient-openssh-version.h
index af6aebe..fcb5f83 100644
--- a/src/x2goclient-openssh-version.h
+++ b/src/x2goclient-openssh-version.h
@@ -45,6 +45,36 @@ GType x2goclient_openssh_version_get_type (void) G_GNUC_CONST;
 X2GoClientOpenSSHVersion* x2goclient_openssh_version_new (void);
 void x2goclient_openssh_version_free (X2GoClientOpenSSHVersion *openssh_version);
 
+/*
+ * Error handling helpers.
+ */
+#define X2GOCLIENT_OPENSSH_VERSION_ERROR g_quark_from_static_string ("x2goclient-openssh-version")
+
+enum {
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_INVALID_STRUCT = 0,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_INVALID_VERSION_STRING,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_INVALID_PREAMBLE,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_NO_MAJOR_SEPARATOR,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_NOT_NUMERIC,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_UNDERFLOW,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_OVERFLOW,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_TOO_BIG,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MAJOR_NEGATIVE,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_NOT_NUMERIC,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_UNDERFLOW,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_OVERFLOW,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_TOO_BIG,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_MINOR_NEGATIVE,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_NOT_NUMERIC,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_UNDERFLOW,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_OVERFLOW,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_TOO_BIG,
+  X2GOCLIENT_OPENSSH_VERSION_ERROR_PATCH_NEGATIVE,
+};
+
+
+void x2goclient_openssh_version_parse (X2GoClientOpenSSHVersion *openssh_version, const gchar *version_string, GError **gerr);
+
 G_END_DECLS
 
 #endif /* x2goclient_openssh_version_h */

--
Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/libx2goclient.git


More information about the x2go-commits mailing list