From 3713346f3959782c5e5d1ddd0252f25fb319d732 Mon Sep 17 00:00:00 2001 From: Salvador Fandino Date: Wed, 20 Apr 2016 16:22:56 +0200 Subject: Provide support for channel endpoints being UNIX file sockets in addition to being TCP/IP sockets. --- nxcomp/ChannelEndPoint.cpp | 245 +++++++++++++++++++++ nxcomp/ChannelEndPoint.h | 61 ++++++ nxcomp/ClientProxy.cpp | 13 +- nxcomp/ClientProxy.h | 7 +- nxcomp/Loop.cpp | 528 +++++++++++++++++++++------------------------ nxcomp/Makefile.in | 1 + nxcomp/Proxy.cpp | 35 ++- nxcomp/Proxy.h | 17 +- nxcomp/ServerProxy.cpp | 25 ++- nxcomp/ServerProxy.h | 17 +- 10 files changed, 634 insertions(+), 315 deletions(-) create mode 100644 nxcomp/ChannelEndPoint.cpp create mode 100644 nxcomp/ChannelEndPoint.h diff --git a/nxcomp/ChannelEndPoint.cpp b/nxcomp/ChannelEndPoint.cpp new file mode 100644 index 000000000..cb35e52d2 --- /dev/null +++ b/nxcomp/ChannelEndPoint.cpp @@ -0,0 +1,245 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2015 Qindel Formacion y Servicios SL. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License Version 2, as */ +/* published by the Free Software Foundation. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA- */ +/* BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, you can request a copy to Qindel */ +/* or write to the Free Software Foundation, Inc., 59 Temple Place, Suite */ +/* 330, Boston, MA 02111-1307 USA */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#include +#include +#include +#include + +#include "ChannelEndPoint.h" + +#include "NXalert.h" + +ChannelEndPoint::ChannelEndPoint(const char *spec) + : defaultTCPPort_(0), defaultTCPInterface_(0), + defaultUnixPath_(NULL) { + spec_ = (spec ? strdup(spec) : NULL); +} + +void +ChannelEndPoint::setSpec(const char *spec) { + if (spec_) free(spec_); + + if (spec && strlen(spec)) + spec_ = strdup(spec); + else + spec_ = NULL; +} + +void +ChannelEndPoint::setSpec(int port) { + if (port >= 0) { + char tmp[20]; + sprintf(tmp, "%d", port); + setSpec(tmp); + } + else setSpec((char*)NULL); +} + +void +ChannelEndPoint::setDefaultTCPPort(long port) { + defaultTCPPort_ = port; +} + +void +ChannelEndPoint::setDefaultTCPInterface(int publicInterface) { + defaultTCPInterface_ = publicInterface; +} + +void +ChannelEndPoint::setDefaultUnixPath(char *path) { + if (defaultUnixPath_) free(defaultUnixPath_); + + if (path && strlen(path)) + defaultUnixPath_ = strdup(path); + else + defaultUnixPath_ = NULL; +} + +void +ChannelEndPoint::disable() { setSpec("0"); } + +bool +ChannelEndPoint::specIsPort(long *port) const { + if (port) *port = 0; + long p = -1; + if (spec_) { + char *end; + p = strtol(spec_, &end, 10); + if ((end == spec_) || (*end != '\0')) + return false; + } + + if (port) *port = p; + return true; +} + +bool +ChannelEndPoint::getUnixPath(char **unixPath) const { + + if (unixPath) *unixPath = 0; + + long p; + char *path = NULL; + + if (specIsPort(&p)) { + if (p != 1) return false; + } + else if (spec_ && (strncmp("unix:", spec_, 5) == 0)) { + path = spec_ + 5; + } + else + return false; + + if (!path || (*path == '\0')) { + path = defaultUnixPath_; + if (!path) + return false; + } + + if (unixPath) + *unixPath = strdup(path); + + return true; +} + +// FIXME!!! +static const char * +getComputerName() { + // + // Strangely enough, under some Windows OSes SMB + // service doesn't bind to localhost. Fall back + // to localhost if can't find computer name in + // the environment. In future we should try to + // bind to localhost and then try the other IPs. + // + + const char *hostname = NULL; + + #ifdef __CYGWIN32__ + + hostname = getenv("COMPUTERNAME"); + + #endif + + if (hostname == NULL) + { + hostname = "localhost"; + } + + return hostname; +} + +bool +ChannelEndPoint::getTCPHostAndPort(char **host, long *port) const { + long p; + char *h = NULL; + ssize_t h_len; + + if (host) *host = NULL; + if (port) *port = 0; + + if (specIsPort(&p)) { + h_len = 0; + } + else if (spec_ && (strncmp("tcp:", spec_, 4) == 0)) { + h = spec_ + 4; + char *colon = strrchr(h, ':'); + if (colon) { + char *end; + h_len = colon++ - h; + p = strtol(colon, &end, 10); + if ((end == colon) || (*end != '\0')) + return false; + } + else { + h_len = strlen(h); + p = 1; + } + } + else + return false; + + if (p == 1) p = defaultTCPPort_; + if (p < 1) return false; + + if (port) + *port = p; + + if (host) + *host = ( h_len + ? strndup(h, h_len) + : strdup(defaultTCPInterface_ ? getComputerName() : "localhost")); + + return true; +} + +bool +ChannelEndPoint::enabled() const { + return (getUnixPath() || getTCPHostAndPort()); +} + +long ChannelEndPoint::getTCPPort() const { + long port; + if (getTCPHostAndPort(NULL, &port)) return port; + return -1; +} + +bool +ChannelEndPoint::validateSpec() { + return (specIsPort() || getUnixPath() || getTCPHostAndPort()); +} + +ChannelEndPoint &ChannelEndPoint::operator=(const ChannelEndPoint &other) { + char *old; + defaultTCPPort_ = other.defaultTCPPort_; + defaultTCPInterface_ = other.defaultTCPInterface_; + old = defaultUnixPath_; + defaultUnixPath_ = (other.defaultUnixPath_ ? strdup(other.defaultUnixPath_) : NULL); + free(old); + old = spec_; + spec_ = (other.spec_ ? strdup(other.spec_) : NULL); + free(old); + return *this; +} + +std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint) { + if (endPoint.enabled()) { + char *unixPath, *host; + long port; + if (endPoint.getUnixPath(&unixPath)) { + os << "unix:" << unixPath; + free(unixPath); + } + else if (endPoint.getTCPHostAndPort(&host, &port)) { + os << "tcp:" << host << ":" << port; + free(host); + } + else { + os << "(invalid)"; + } + } + else { + os << "(disabled)"; + } + return os; +} diff --git a/nxcomp/ChannelEndPoint.h b/nxcomp/ChannelEndPoint.h new file mode 100644 index 000000000..5b4e75345 --- /dev/null +++ b/nxcomp/ChannelEndPoint.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2015 Qindel Formacion y Servicios SL. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License Version 2, as */ +/* published by the Free Software Foundation. */ +/* */ +/* This program is distributed in the hope that it will be useful, but */ +/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA- */ +/* BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General */ +/* Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, you can request a copy to Qindel */ +/* or write to the Free Software Foundation, Inc., 59 Temple Place, Suite */ +/* 330, Boston, MA 02111-1307 USA */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#ifndef ChannelEndPoint_H +#define ChannelEndPoint_H + +#include +#include + +class ChannelEndPoint +{ + private: + long defaultTCPPort_; + int defaultTCPInterface_; // 0=localhost, otherwise IP of public interface. + char *defaultUnixPath_; + char *spec_; + + bool specIsPort(long *port = NULL) const; + + public: + ChannelEndPoint(const char *spec = NULL); + ChannelEndPoint &operator=(const ChannelEndPoint &other); + + bool enabled() const; + bool disabled() { return !enabled(); } + void disable(); + void setSpec(const char *spec); + void setSpec(int port); + void setDefaultTCPPort(long port); + void setDefaultTCPInterface(int publicInterface); + void setDefaultUnixPath(char *path); + + bool getUnixPath(char **path = NULL) const; + bool getTCPHostAndPort(char **hostname = NULL, long *port = NULL) const; + long getTCPPort() const; + + bool validateSpec(); +}; + +std::ostream& operator<<(std::ostream& os, const ChannelEndPoint& endPoint); + +#endif diff --git a/nxcomp/ClientProxy.cpp b/nxcomp/ClientProxy.cpp index ef63bb0eb..7dd3dbbc6 100644 --- a/nxcomp/ClientProxy.cpp +++ b/nxcomp/ClientProxy.cpp @@ -68,8 +68,11 @@ void ClientProxy::handleDisplayConfiguration(const char *xServerDisplay, int xSe #endif } -void ClientProxy::handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort, - int httpServerPort, const char *fontServerPort) +void ClientProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort) { delete [] fontServerPort_; @@ -141,8 +144,8 @@ int ClientProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId // Connect on the TCP port number. // - return handleNewGenericConnectionFromProxy(channelId, channel_font, "localhost", - port, "font"); + return handleNewGenericConnectionFromProxyTCP(channelId, channel_font, "localhost", + port, "font"); } else { @@ -150,7 +153,7 @@ int ClientProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId // Connect to the Unix path. // - return handleNewGenericConnectionFromProxy(channelId, channel_font, "localhost", + return handleNewGenericConnectionFromProxyUnix(channelId, channel_font, fontServerPort_, "font"); } } diff --git a/nxcomp/ClientProxy.h b/nxcomp/ClientProxy.h index 88d345f00..d58fae77b 100644 --- a/nxcomp/ClientProxy.h +++ b/nxcomp/ClientProxy.h @@ -38,8 +38,11 @@ class ClientProxy : public Proxy virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, sockaddr *xServerAddr, unsigned int xServerAddrLength); - virtual void handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort, - int httpServerPort, const char *fontServerPort); + virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort); protected: diff --git a/nxcomp/Loop.cpp b/nxcomp/Loop.cpp index a60bfc9ae..97020d162 100644 --- a/nxcomp/Loop.cpp +++ b/nxcomp/Loop.cpp @@ -36,7 +36,7 @@ #include #include #include - +#include #include #include #include @@ -89,6 +89,7 @@ typedef int socklen_t; #include "ServerProxy.h" #include "Message.h" +#include "ChannelEndPoint.h" // // System specific defines. @@ -437,7 +438,10 @@ static int SetupDisplaySocket(int &xServerAddrFamily, sockaddr *&xServerAddr, // a new connection. // -static int ListenConnection(int port, const char *label); +static int ListenConnection(ChannelEndPoint &endPoint, const char *label); +static int ListenConnectionTCP(const char *host, long port, const char *label); +static int ListenConnectionUnix(const char *unixPath, const char *label); +static int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label); static int AcceptConnection(int fd, int domain, const char *label); // @@ -475,6 +479,8 @@ static const char *GetArg(int &argi, int argc, const char **argv); static int CheckArg(const char *type, const char *name, const char *value); static int ParseArg(const char *type, const char *name, const char *value); static int ValidateArg(const char *type, const char *name, const char *value); +static void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value, + ChannelEndPoint &endPoint); static int LowercaseArg(const char *type, const char *name, char *value); static int CheckSignal(int signal); @@ -978,12 +984,12 @@ static int connectPort = -1; // Helper channels are disabled by default. // -static int cupsPort = -1; -static int auxPort = -1; -static int smbPort = -1; -static int mediaPort = -1; -static int httpPort = -1; -static int slavePort = -1; +static ChannelEndPoint cupsPort; +static ChannelEndPoint auxPort; +static ChannelEndPoint smbPort; +static ChannelEndPoint mediaPort; +static ChannelEndPoint httpPort; +static ChannelEndPoint slavePort; // // Can be either a port number or a Unix @@ -4474,7 +4480,7 @@ int SetupServiceSockets() // Since ProtoStep7 (#issue 108) int port = atoi(fontPort); - if ((fontFD = ListenConnection(port, "font")) < 0) + if ((fontFD = ListenConnectionTCP("localhost", port, "font")) < 0) { useFontSocket = 0; } @@ -4504,56 +4510,41 @@ int SetupServiceSockets() return 1; } -int ListenConnection(int port, const char *label) +int ListenConnectionAny(sockaddr *addr, socklen_t addrlen, const char *label) { - sockaddr_in tcpAddr; - - unsigned int portTCP = port; - - int newFD = socket(AF_INET, SOCK_STREAM, PF_UNSPEC); + int newFD = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC); if (newFD == -1) { #ifdef PANIC *logofs << "Loop: PANIC! Call to socket failed for " << label - << " TCP socket. Error is " << EGET() << " '" + << " socket. Error is " << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; #endif cerr << "Error" << ": Call to socket failed for " << label - << " TCP socket. Error is " << EGET() << " '" + << " socket. Error is " << EGET() << " '" << ESTR() << "'.\n"; goto SetupSocketError; } - else if (SetReuseAddress(newFD) < 0) + if (SetReuseAddress(newFD) < 0) { + // SetReuseAddress already warns with an error goto SetupSocketError; } - tcpAddr.sin_family = AF_INET; - tcpAddr.sin_port = htons(portTCP); - if ( loopbackBind ) - { - tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - } - else - { - tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY); - } - - if (bind(newFD, (sockaddr *) &tcpAddr, sizeof(tcpAddr)) == -1) + if (bind(newFD, addr, addrlen) == -1) { #ifdef PANIC *logofs << "Loop: PANIC! Call to bind failed for " << label - << " TCP port " << port << ". Error is " << EGET() + << ". Error is " << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; #endif cerr << "Error" << ": Call to bind failed for " << label - << " TCP port " << port << ". Error is " << EGET() + << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; - goto SetupSocketError; } @@ -4561,12 +4552,12 @@ int ListenConnection(int port, const char *label) { #ifdef PANIC *logofs << "Loop: PANIC! Call to bind failed for " << label - << " TCP port " << port << ". Error is " << EGET() + << ". Error is " << EGET() << " '" << ESTR() << "'.\n" << logofs_flush; #endif cerr << "Error" << ": Call to bind failed for " << label - << " TCP port " << port << ". Error is " << EGET() + << ". Error is " << EGET() << " '" << ESTR() << "'.\n"; goto SetupSocketError; @@ -4590,6 +4581,82 @@ SetupSocketError: // HandleCleanup(); + return -1; +} + +int ListenConnectionUnix(const char *path, const char *label) +{ + + sockaddr_un unixAddr; + unixAddr.sun_family = AF_UNIX; +#ifdef UNIX_PATH_MAX + if (strlen(path) >= UNIX_PATH_MAX) +#else + if (strlen(path) >= sizeof(unixAddr.sun_path)) +#endif + { + #ifdef PANIC + *logofs << "Loop: PANIC! Socket path \"" << path << "\" for " + << label << " is too long.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Socket path \"" << path << "\" for " + << label << " is too long.\n"; + + HandleCleanup(); + return -1; + } + + strcpy(unixAddr.sun_path, path); + return ListenConnectionAny((sockaddr *)&unixAddr, sizeof(unixAddr), label); +} + +int ListenConnectionTCP(const char *host, long port, const char *label) +{ + sockaddr_in tcpAddr; + tcpAddr.sin_family = AF_INET; + tcpAddr.sin_port = htons(port); + + if (loopbackBind || + !host || + !strcmp(host, "") || + !strcmp(host, "localhost")) { + tcpAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + else if(strcmp(host, "*") == 0) { + tcpAddr.sin_addr.s_addr = htonl(INADDR_ANY); + } + else { + int ip = tcpAddr.sin_addr.s_addr = GetHostAddress(host); + if (ip == 0) + { + #ifdef PANIC + *logofs << "Loop: PANIC! Unknown " << label << " host '" << host + << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Unknown " << label << " host '" << host + << "'.\n"; + + HandleCleanup(); + return -1; + } + } + + return ListenConnectionAny((sockaddr *)&tcpAddr, sizeof(tcpAddr), label); +} + +int ListenConnection(ChannelEndPoint &endpoint, const char *label) +{ + char *unixPath, *host; + long port; + if (endpoint.getUnixPath(&unixPath)) { + return ListenConnectionUnix(unixPath, label); + } + else if (endpoint.getTCPHostAndPort(&host, &port)) { + return ListenConnectionTCP(host, port, label); + } + return -1; } static int AcceptConnection(int fd, int domain, const char *label) @@ -5521,12 +5588,12 @@ void CleanupLocal() listenPort = -1; connectPort = -1; - cupsPort = -1; - auxPort = -1; - smbPort = -1; - mediaPort = -1; - httpPort = -1; - slavePort = -1; + cupsPort.disable(); + auxPort.disable(); + smbPort.disable(); + mediaPort.disable(); + httpPort.disable(); + slavePort.disable(); *fontPort = '\0'; @@ -8070,6 +8137,35 @@ int ReadRemoteData(int fd, char *buffer, int size, char stop) return -1; } +static int +hexval(char c) { + if ((c >= '0') && (c <= '9')) + return c - '0'; + if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + return -1; +} + +static void +URLDecodeInPlace(char *str) { + if (str) { + char *to = str; + while (str[0]) { + if ((str[0] == '%') && + (hexval(str[1]) >= 0) && + (hexval(str[2]) >= 0)) { + *(to++) = hexval(str[1]) * 16 + hexval(str[2]); + str += 3; + } + else + *(to++) = *(str++); + } + *to = '\0'; + } +} + int WriteLocalData(int fd, const char *buffer, int size) { int position = 0; @@ -8357,6 +8453,7 @@ int ParseEnvironmentOptions(const char *env, int force) while (name) { value = strtok(NULL, ","); + URLDecodeInPlace(value); if (CheckArg("environment", name, value) < 0) { @@ -8750,7 +8847,7 @@ int ParseEnvironmentOptions(const char *env, int force) } else if (strcasecmp(name, "cups") == 0) { - cupsPort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, cupsPort); } else if (strcasecmp(name, "sync") == 0) { @@ -8762,25 +8859,25 @@ int ParseEnvironmentOptions(const char *env, int force) cerr << "Warning" << ": No 'sync' channel in current version. " << "Assuming 'cups' channel.\n"; - cupsPort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, cupsPort); } else if (strcasecmp(name, "keybd") == 0 || strcasecmp(name, "aux") == 0) { - auxPort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, auxPort); } else if (strcasecmp(name, "samba") == 0 || strcasecmp(name, "smb") == 0) { - smbPort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, smbPort); } else if (strcasecmp(name, "media") == 0) { - mediaPort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, mediaPort); } else if (strcasecmp(name, "http") == 0) { - httpPort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, httpPort); } else if (strcasecmp(name, "font") == 0) { @@ -8788,7 +8885,7 @@ int ParseEnvironmentOptions(const char *env, int force) } else if (strcasecmp(name, "slave") == 0) { - slavePort = ValidateArg("local", name, value); + SetAndValidateChannelEndPointArg("local", name, value, slavePort); } else if (strcasecmp(name, "mask") == 0) { @@ -11515,237 +11612,105 @@ int SetPorts() // ing, causing a loop. // - if (cupsPort <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling cups connections.\n" - << logofs_flush; - #endif - - cupsPort = 0; - - useCupsSocket = 0; - } - else - { - if (control -> ProxyMode == proxy_client) - { - if (cupsPort == 1) - { - cupsPort = DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort; - } - + useCupsSocket = 0; + if (cupsPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + cupsPort.setDefaultTCPPort(DEFAULT_NX_CUPS_PORT_OFFSET + proxyPort); useCupsSocket = 1; } else - { - if (cupsPort == 1) - { - // - // Use the well-known 631/tcp port of the - // Internet Printing Protocol. - // - - cupsPort = 631; - } - - useCupsSocket = 0; - } - - #ifdef TEST - *logofs << "Loop: Using cups port '" << cupsPort - << "'.\n" << logofs_flush; - #endif + cupsPort.setDefaultTCPPort(631); } - if (auxPort <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling auxiliary X11 connections.\n" +#ifdef TEST + *logofs << "Loop: cups port: " << cupsPort->getDebugSpec() << "\n" << logofs_flush; - #endif - - auxPort = 0; - - useAuxSocket = 0; - } - else - { - if (control -> ProxyMode == proxy_client) - { - if (auxPort == 1) - { - auxPort = DEFAULT_NX_AUX_PORT_OFFSET + proxyPort; - } +#endif + useAuxSocket = 0; + if (auxPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + auxPort.setDefaultTCPPort(DEFAULT_NX_AUX_PORT_OFFSET + proxyPort); useAuxSocket = 1; } - else - { - // - // Auxiliary X connections are always forwarded - // to the display where the session is running. - // The only value accepted is 1. - // + else { + auxPort.setDefaultTCPPort(1); - if (auxPort != 1) - { - #ifdef WARNING + if (auxPort.getTCPPort() != 1) { + +#ifdef WARNING *logofs << "Loop: WARNING! Overriding auxiliary X11 " << "port with new value '" << 1 << "'.\n" << logofs_flush; - #endif +#endif cerr << "Warning" << ": Overriding auxiliary X11 " << "port with new value '" << 1 << "'.\n"; - auxPort = 1; + auxPort.setSpec("1"); } - - useAuxSocket = 0; } - - #ifdef TEST - *logofs << "Loop: Using auxiliary X11 port '" << auxPort - << "'.\n" << logofs_flush; - #endif } - if (smbPort <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling SMB connections.\n" - << logofs_flush; - #endif - - smbPort = 0; - - useSmbSocket = 0; - } - else - { - if (control -> ProxyMode == proxy_client) - { - if (smbPort == 1) - { - smbPort = DEFAULT_NX_SMB_PORT_OFFSET + proxyPort; - } +#ifdef TEST + *logofs << "Loop: aux port: " << auxPort->getDebugSpec() << "\n" + << logofs_flush; +#endif - useSmbSocket = 1; + useSmbSocket = 0; + if (smbPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + auxPort.setDefaultTCPPort(DEFAULT_NX_SMB_PORT_OFFSET + proxyPort); + useAuxSocket = 1; } else - { - if (smbPort == 1) - { - // - // Assume the 139/tcp port used for SMB - // over NetBIOS over TCP. - // - - smbPort = 139; - } - - useSmbSocket = 0; - } - - #ifdef TEST - *logofs << "Loop: Using SMB port '" << smbPort - << "'.\n" << logofs_flush; - #endif + auxPort.setDefaultTCPPort(139); } - if (mediaPort <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling multimedia connections.\n" - << logofs_flush; - #endif - - mediaPort = 0; - useMediaSocket = 0; - } - else - { - if (control -> ProxyMode == proxy_client) - { - if (mediaPort == 1) - { - mediaPort = DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort; - } +#ifdef TEST + *logofs << "Loop: smb port: " << smbPort->getDebugSpec() << "\n" + << logofs_flush; +#endif + useMediaSocket = 0; + if (mediaPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + mediaPort.setDefaultTCPPort(DEFAULT_NX_MEDIA_PORT_OFFSET + proxyPort); useMediaSocket = 1; } - else - { - if (mediaPort == 1) - { - // - // We don't have a well-known port to - // be used for media connections. - // - - #ifdef PANIC - *logofs << "Loop: PANIC! No port specified for multimedia connections.\n" - << logofs_flush; - #endif + else if (mediaPort.getTCPPort() == 1) { +#ifdef PANIC + *logofs << "Loop: PANIC! No port specified for multimedia connections.\n" + << logofs_flush; +#endif - cerr << "Error" << ": No port specified for multimedia connections.\n"; + cerr << "Error" << ": No port specified for multimedia connections.\n"; - HandleCleanup(); - } - - useMediaSocket = 0; + HandleCleanup(); } - - #ifdef TEST - *logofs << "Loop: Using multimedia port '" << mediaPort - << "'.\n" << logofs_flush; - #endif } - if (httpPort <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling HTTP connections.\n" - << logofs_flush; - #endif - - httpPort = 0; - - useHttpSocket = 0; - } - else - { - if (control -> ProxyMode == proxy_client) - { - if (httpPort == 1) - { - httpPort = DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort; - } +#ifdef TEST + *logofs << "Loop: Using multimedia port '" << mediaPort->getDebugSpec() + << "'.\n" << logofs_flush; +#endif + useHttpSocket = 0; + if (httpPort.enabled()) { + if (control -> ProxyMode == proxy_client) { + httpPort.setDefaultTCPPort(DEFAULT_NX_HTTP_PORT_OFFSET + proxyPort); useHttpSocket = 1; } else - { - if (httpPort == 1) - { - // - // Use the well-known 80/tcp port. - // - - httpPort = 80; - } - - useHttpSocket = 0; - } - - #ifdef TEST - *logofs << "Loop: Using HTTP port '" << httpPort - << "'.\n" << logofs_flush; - #endif + httpPort.setDefaultTCPPort(80); } +#ifdef TEST + *logofs << "Loop: Using HTTP port '" << httpPort->getDebugSpec() + << "'.\n" << logofs_flush; +#endif + if (ParseFontPath(fontPort) <= 0) { #ifdef TEST @@ -11781,44 +11746,20 @@ int SetPorts() #endif } - if (slavePort <= 0) - { - #ifdef TEST - *logofs << "Loop: Disabling slave connections.\n" - << logofs_flush; - #endif - - slavePort = 0; - - useSlaveSocket = 0; - } - else - { - // - // File transfer connections can - // be originated by both sides. - // - - if (slavePort == 1) - { - if (control -> ProxyMode == proxy_client) - { - slavePort = DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort; - } - else - { - slavePort = DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort; - } - } - + useSlaveSocket = 0; + if (slavePort.enabled()) { useSlaveSocket = 1; - - #ifdef TEST - *logofs << "Loop: Using slave port '" << slavePort - << "'.\n" << logofs_flush; - #endif + if (control -> ProxyMode == proxy_client) + slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_CLIENT_OFFSET + proxyPort); + else + slavePort.setDefaultTCPPort(DEFAULT_NX_SLAVE_PORT_SERVER_OFFSET + proxyPort); } +#ifdef TEST + *logofs << "Loop: Using slave port '" << slavePort->getDebugSpec() + << "'.\n" << logofs_flush; +#endif + return 1; } @@ -14109,65 +14050,65 @@ void PrintConnectionInfo() } if (control -> ProxyMode == proxy_client && - useCupsSocket > 0 && cupsPort > 0) + useCupsSocket > 0 && cupsPort.enabled()) { cerr << "Info" << ": Listening to CUPS connections " << "on port '" << cupsPort << "'.\n"; } else if (control -> ProxyMode == proxy_server && - cupsPort > 0) + cupsPort.enabled()) { cerr << "Info" << ": Forwarding CUPS connections " << "to port '" << cupsPort << "'.\n"; } if (control -> ProxyMode == proxy_client && - useAuxSocket > 0 && auxPort > 0) + useAuxSocket > 0 && auxPort.enabled()) { cerr << "Info" << ": Listening to auxiliary X11 connections " << "on port '" << auxPort << "'.\n"; } else if (control -> ProxyMode == proxy_server && - auxPort > 0) + auxPort.enabled()) { cerr << "Info" << ": Forwarding auxiliary X11 connections " << "to display '" << displayHost << "'.\n"; } if (control -> ProxyMode == proxy_client && - useSmbSocket > 0 && smbPort > 0) + useSmbSocket > 0 && smbPort.enabled()) { cerr << "Info" << ": Listening to SMB connections " << "on port '" << smbPort << "'.\n"; } else if (control -> ProxyMode == proxy_server && - smbPort > 0) + smbPort.enabled()) { cerr << "Info" << ": Forwarding SMB connections " << "to port '" << smbPort << "'.\n"; } if (control -> ProxyMode == proxy_client && - useMediaSocket > 0 && mediaPort > 0) + useMediaSocket > 0 && mediaPort.enabled()) { cerr << "Info" << ": Listening to multimedia connections " << "on port '" << mediaPort << "'.\n"; } else if (control -> ProxyMode == proxy_server && - mediaPort > 0) + mediaPort.enabled()) { cerr << "Info" << ": Forwarding multimedia connections " << "to port '" << mediaPort << "'.\n"; } if (control -> ProxyMode == proxy_client && - useHttpSocket > 0 && httpPort > 0) + useHttpSocket > 0 && httpPort.enabled()) { cerr << "Info" << ": Listening to HTTP connections " << "on port '" << httpPort << "'.\n"; } else if (control -> ProxyMode == proxy_server && - httpPort > 0) + httpPort.enabled()) { cerr << "Info" << ": Forwarding HTTP connections " << "to port '" << httpPort << "'.\n"; @@ -14186,7 +14127,7 @@ void PrintConnectionInfo() << "to port '" << fontPort << "'.\n"; } - if (useSlaveSocket > 0 && slavePort > 0) + if (useSlaveSocket > 0 && slavePort.enabled()) { cerr << "Info" << ": Listening to slave connections " << "on port '" << slavePort << "'.\n"; @@ -14443,6 +14384,25 @@ int ParseArg(const char *type, const char *name, const char *value) return (int) result; } +void SetAndValidateChannelEndPointArg(const char *type, const char *name, const char *value, + ChannelEndPoint &endPoint) { + endPoint.setSpec(value); + if (!endPoint.validateSpec()) { + #ifdef PANIC + *logofs << "Loop: PANIC! Invalid " << type + << " option '" << name << "' with value '" + << value << "'.\n" << logofs_flush; + #endif + + cerr << "Error" << ": Invalid " << type + << " option '" << name << "' with value '" + << value << "'.\n"; + + HandleCleanup(); + } +} + + int ValidateArg(const char *type, const char *name, const char *value) { int number = atoi(value); diff --git a/nxcomp/Makefile.in b/nxcomp/Makefile.in index c2cdceead..8fc37407f 100644 --- a/nxcomp/Makefile.in +++ b/nxcomp/Makefile.in @@ -149,6 +149,7 @@ CXXSRC = Loop.cpp \ ClientChannel.cpp \ ServerChannel.cpp \ GenericChannel.cpp \ + ChannelEndPoint.cpp \ ReadBuffer.cpp \ ProxyReadBuffer.cpp \ ClientReadBuffer.cpp \ diff --git a/nxcomp/Proxy.cpp b/nxcomp/Proxy.cpp index 7655ccb40..1693590db 100644 --- a/nxcomp/Proxy.cpp +++ b/nxcomp/Proxy.cpp @@ -65,6 +65,7 @@ struct sockaddr_un #include "ClientChannel.h" #include "ServerChannel.h" #include "GenericChannel.h" +#include "ChannelEndPoint.h" // // We need to adjust some values related @@ -6053,8 +6054,36 @@ int Proxy::handleNewSlaveConnection(int clientFd) return handleNewGenericConnection(clientFd, channel_slave, "slave"); } + + int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, - const char *hostname, int port, const char *label) + ChannelEndPoint &endPoint, const char *label) +{ + char *unixPath, *host; + long port; + + if (endPoint.getUnixPath(&unixPath)) { + return handleNewGenericConnectionFromProxyUnix(channelId, type, unixPath, label); + } + + if (endPoint.getTCPHostAndPort(&host, &port)) { + return handleNewGenericConnectionFromProxyTCP(channelId, type, host, port, label); + } + + #ifdef WARNING + *logofs << "Proxy: WARNING! Refusing attempted connection " + << "to " << label << " server.\n" << logofs_flush; + #endif + + cerr << "Warning" << ": Refusing attempted connection " + << "to " << label << " server.\n"; + + return -1; +} + +int Proxy::handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type, + const char *hostname, long port, const char *label) + { if (port <= 0) { @@ -6173,8 +6202,8 @@ int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type typ return 1; } -int Proxy::handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, - const char *hostname, const char *path, const char *label) +int Proxy::handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type, + const char *path, const char *label) { if (path == NULL || *path == '\0' ) { diff --git a/nxcomp/Proxy.h b/nxcomp/Proxy.h index c0fdfcce9..87ea1ce8a 100644 --- a/nxcomp/Proxy.h +++ b/nxcomp/Proxy.h @@ -32,6 +32,7 @@ #include "Transport.h" #include "EncodeBuffer.h" #include "ProxyReadBuffer.h" +#include "ChannelEndPoint.h" // // Forward declaration as we @@ -258,8 +259,11 @@ class Proxy virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, sockaddr * xServerAddr, unsigned int xServerAddrLength) = 0; - virtual void handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort, - int httpServerPort, const char *fontServerPort) = 0; + virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort) = 0; // // Create new tunneled channels. @@ -278,10 +282,13 @@ class Proxy int handleNewGenericConnection(int clientFd, T_channel_type type, const char *label); int handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, - const char *hostname, int port, const char *label); + ChannelEndPoint &endpoint, const char *label); - int handleNewGenericConnectionFromProxy(int channelId, T_channel_type type, - const char *hostname, const char *path, const char *label); + int handleNewGenericConnectionFromProxyUnix(int channelId, T_channel_type type, + const char *path, const char *label); + + int handleNewGenericConnectionFromProxyTCP(int channelId, T_channel_type type, + const char *hostname, long port, const char *label); int handleNewSlaveConnection(int clientFd); diff --git a/nxcomp/ServerProxy.cpp b/nxcomp/ServerProxy.cpp index 0a72fc301..3060e829d 100644 --- a/nxcomp/ServerProxy.cpp +++ b/nxcomp/ServerProxy.cpp @@ -1,6 +1,7 @@ /**************************************************************************/ /* */ /* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */ +/* Copyright (c) 2015 Qindel Formacion y Servicios S.L. */ /* */ /* NXCOMP, NX protocol compression and NX extensions to this software */ /* are copyright of NoMachine. Redistribution and use of the present */ @@ -51,10 +52,10 @@ ServerProxy::ServerProxy(int proxyFd) : Proxy(proxyFd) xServerAddr_ = NULL; xServerDisplay_ = NULL; - cupsServerPort_ = -1; - smbServerPort_ = -1; - mediaServerPort_ = -1; - httpServerPort_ = -1; + cupsServerPort_ = NULL; + smbServerPort_ = NULL; + mediaServerPort_ = NULL; + httpServerPort_ = NULL; fontServerPort_ = NULL; @@ -101,8 +102,11 @@ void ServerProxy::handleDisplayConfiguration(const char *xServerDisplay, int xSe #endif } -void ServerProxy::handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort, - int httpServerPort, const char *fontServerPort) +void ServerProxy::handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort) { cupsServerPort_ = cupsServerPort; smbServerPort_ = smbServerPort; @@ -161,22 +165,23 @@ int ServerProxy::handleNewConnectionFromProxy(T_channel_type type, int channelId } case channel_cups: { - return handleNewGenericConnectionFromProxy(channelId, channel_cups, "localhost", + return handleNewGenericConnectionFromProxy(channelId, channel_cups, cupsServerPort_, "CUPS"); } case channel_smb: { - return handleNewGenericConnectionFromProxy(channelId, channel_smb, getComputerName(), + smbServerPort_.setDefaultTCPInterface(1); + return handleNewGenericConnectionFromProxy(channelId, channel_smb, smbServerPort_, "SMB"); } case channel_media: { - return handleNewGenericConnectionFromProxy(channelId, channel_media, "localhost", + return handleNewGenericConnectionFromProxy(channelId, channel_media, mediaServerPort_, "media"); } case channel_http: { - return handleNewGenericConnectionFromProxy(channelId, channel_http, getComputerName(), + return handleNewGenericConnectionFromProxy(channelId, channel_http, httpServerPort_, "HTTP"); } case channel_slave: diff --git a/nxcomp/ServerProxy.h b/nxcomp/ServerProxy.h index 54bc0f748..cc8191795 100644 --- a/nxcomp/ServerProxy.h +++ b/nxcomp/ServerProxy.h @@ -24,6 +24,7 @@ #include "Proxy.h" #include "Misc.h" +#include "ChannelEndPoint.h" // // Set the verbosity level. @@ -43,8 +44,11 @@ class ServerProxy : public Proxy virtual void handleDisplayConfiguration(const char *xServerDisplay, int xServerAddrFamily, sockaddr *xServerAddr, unsigned int xServerAddrLength); - virtual void handlePortConfiguration(int cupsServerPort, int smbServerPort, int mediaServerPort, - int httpServerPort, const char *fontServerPort); + virtual void handlePortConfiguration(ChannelEndPoint &cupsServerPort, + ChannelEndPoint &smbServerPort, + ChannelEndPoint &mediaServerPort, + ChannelEndPoint &httpServerPort, + const char *fontServerPort); protected: @@ -108,6 +112,7 @@ class ServerProxy : public Proxy private: + // FIXME: Use a ChannelEndPoint object also for the X server! int xServerAddrFamily_; sockaddr *xServerAddr_; unsigned int xServerAddrLength_; @@ -124,10 +129,10 @@ class ServerProxy : public Proxy // TCP connections. // - int cupsServerPort_; - int smbServerPort_; - int mediaServerPort_; - int httpServerPort_; + ChannelEndPoint cupsServerPort_; + ChannelEndPoint smbServerPort_; + ChannelEndPoint mediaServerPort_; + ChannelEndPoint httpServerPort_; // // It will have to be passed to the channel -- cgit v1.2.3