This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository libx2goclient. commit 89dff4d6f8c3966724287c4efb986876d6dd925f Author: Mihai Moldovan <ionic@ionic.de> Date: Sat Jul 27 13:51:54 2019 +0200 src/x2goclient-network-ssh.c: continue implementation of x2goclient_network_ssh_parse_sockspec(). Additionally, start splitting the function up, because it's getting pretty complicated. --- src/x2goclient-network-ssh.c | 167 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 135 insertions(+), 32 deletions(-) diff --git a/src/x2goclient-network-ssh.c b/src/x2goclient-network-ssh.c index 4b95b6d..702f279 100644 --- a/src/x2goclient-network-ssh.c +++ b/src/x2goclient-network-ssh.c @@ -24,12 +24,20 @@ #include <sys/socket.h> #include <sys/un.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <errno.h> #include <glib.h> #include <glib/gi18n.h> #include <glib/gprintf.h> +#include <glib/gstdio.h> #include <gmodule.h> #include <gio/gio.h> +#include <gio/gunixsocketaddress.h> #ifdef HAVE_CONFIG_H #include "config.h" @@ -57,36 +65,87 @@ struct _X2GoClientNetworkSSH { G_DEFINE_TYPE (X2GoClientNetworkSSH, x2goclient_network_ssh, X2GOCLIENT_TYPE_NETWORK); -static GSocketAddress* x2goclient_network_ssh_parse_sockspec (X2GoClientNetworkSSH *self, const GString *sockspec) { +static GSocketAddress* x2goclient_network_ssh_parse_sockspec_unix_socket (const GString *sockspec) { GSocketAddress *ret = NULL; - if (sockspec) { + /* + * N.B.: do *not* sanitize the string, since UNIX sockets are allowed to + * start and end on whitespace. + */ + gboolean is_socket = FALSE; + GUnixSocketAddressType socket_type = G_UNIX_SOCKET_ADDRESS_PATH; + + /* Max. path len without terminating NULL byte */ + if ((sizeof (((struct sockaddr_un*)(NULL))->sun_path) - 1) >= sockspec->len) { + /* Smells like a UNIX socket so far. */ + if (0 == sockspec->str[0]) { + /* + * Abstract UNIX sockets are specified with a preceding NULL byte. + * We can't check for them, since they have no equivalent on the file + * system. + * + * Encountering this means that we have to trust the socket exists. + */ + is_socket = TRUE; + socket_type = G_UNIX_SOCKET_ADDRESS_ABSTRACT; + } + else { + /* Check if such a file exists on the file system. */ + GStatBuf tmp_stat_buf = { 0 }; + if (0 == g_stat (sockspec->str, &tmp_stat_buf)) { + /* File exists, let's check if this is a socket. */ + if ((tmp_stat_buf.st_mode & S_IFMT) == S_IFSOCK) { + is_socket = TRUE; + } + } + } + + if (is_socket) { + ret = g_unix_socket_address_new_with_type (sockspec->str, sockspec->len, socket_type); + } + } + + return (ret); +} + +static gint32 x2goclient_network_ssh_parse_sockspec_port (const GString *portspec) { + gint32 ret = -1; + + if (':' == portspec->str[0]) { /* - * Check if it's possibly a UNIX socket. - * - * N.B.: do *not* sanitize the string, since UNIX sockets are allowed to - * start and end on whitespace. + * In the worst case, portspec->str[1] will point to a terminating NULL + * character, but that's non-critical. */ - gboolean is_abstract = FALSE; - - /* Max. path len without terminating NULL byte */ - if ((sizeof (((struct sockaddr_un*)(NULL))->sun_path) - 1) >= sockspec->len) { - /* Smells like a UNIX socket so far. */ - if (0 == sockspec->str[0]) { - /* - * Abstract UNIX sockets are specified with a preceding NULL byte. - * We can't check for them, since they have no equivalent on the file - * system. - * - * Encountering this means that we have to trust the socket exists. - */ - is_abstract = TRUE; - } - else { - /* Check if such a file exists on the file system. */ - ... /* Parse error is fine here. */ - } + errno = 0; + long long conv = strtoll (portspec->str + 1, NULL, 10); + + if (0 != errno) { + g_log (NULL, G_LOG_LEVEL_WARNING, "Unable to convert port specifier, invalid input."); } + else if ((1 << 16) <= conv) { + g_log (NULL, G_LOG_LEVEL_WARNING, "Port specifier out of range (too big), invalid input."); + } + else if (0 >= conv) { + g_log (NULL, G_LOG_LEVEL_WARNING, "Port specifier out of range (negative or zero), invalid input."); + } + else { + ret = conv; + } + } + else { + /* No specifier found, assume default port. */ + ret = 0; + } + + return (ret); +} + +static GSocketAddress* x2goclient_network_ssh_parse_sockspec (X2GoClientNetworkSSH *self, const GString *sockspec) { + GSocketAddress *ret = NULL; + + if (sockspec) { + /* Check if it's possibly a UNIX socket. */ + ret = x2goclient_network_ssh_parse_sockspec_unix_socket (sockspec); if (!ret) { /* Must be not a UNIX socket, continue checking for IPv6 addresses. */ @@ -94,20 +153,64 @@ static GSocketAddress* x2goclient_network_ssh_parse_sockspec (X2GoClientNetworkS /* We're free to sanitize the string now. */ g_strstrip (sockspec->str); + gboolean could_be_v6 = FALSE; gboolean is_v6 = FALSE; - gchar *v6_end = NULL; + gchar *tmp_start = sockspec->str; + gchar *tmp_end = NULL; + GString *v6_address = NULL; + GString *address = NULL; + guint16 port = 0; /* - * As a very common convention, IPv6 address have to be encapsulated in - * brackets, check for that. + * As a very common convention, IPv6 addresses have to be encapsulated in + * brackets if an additional port is specified, check for that. */ - if ('[' == sockspec->str[0]) { - v6_end = g_strstr_len (sockspec->str, -1, "]"); + if ('[' == tmp_start[0]) { + tmp_end = g_strstr_len (tmp_start, -1, "]"); + + if (tmp_end) { + /* + * Looks like a bracket-encapsulated IPv6 address so far. + * See if that checks out. + */ + could_be_v6 = TRUE; + ++tmp_start; + --tmp_end; + + v6_address = g_string_new_len (tmp_start, tmp_end - tmp_start); + } + } + else { + v6_address = g_string_new_len (tmp_start, sockspec->len); + } - if (v6_end) { - is_v6 = TRUE; + /* Check for an IPv6 address first. */ + char binary_rep[128] = { 0 }; + is_v6 = (1 == inet_pton (AF_INET6, v6_address->str, &binary_rep)); + + if (is_v6) { + /* Passed a valid IPv6 address. */ + if (tmp_end) { + /* + * Specification in brackets, so check if there's a port specifier. + * + * tmp_end points to the last part of the address, so tmp_end + 1 + * will point to the terminating bracket. tmp_end + 2 can, in the + * worst case, point to the terminating NULL character, which is + * fine. + */ + GString *portspec = g_string_new (tmp_end + 2); + gint32 port_parse = x2goclient_network_ssh_parse_sockspec_port (portspec); + g_string_free (portspec, TRUE); + portspec = NULL; + } + else { + address = g_string_new (v6_address->str); } } + else { + /* */ + } } } -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/libx2goclient.git