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@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