diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
commit | dffaba3a2b5c9ba6db9fc9d866f39647dfae7d08 (patch) | |
tree | 067b38c5fa0e0d66b63919c6cc5f60718eb3535b |
R6.6 is the Xorg base-lineXORG-MAINXORG-STABLE
-rw-r--r-- | config.c | 199 | ||||
-rw-r--r-- | config.h | 47 | ||||
-rw-r--r-- | main.c | 1113 | ||||
-rw-r--r-- | pmconfig.cpp | 12 | ||||
-rw-r--r-- | pmdb.c | 771 | ||||
-rw-r--r-- | pmdb.h | 149 | ||||
-rw-r--r-- | pmint.h | 184 | ||||
-rw-r--r-- | proxymngr.man | 174 |
8 files changed, 2649 insertions, 0 deletions
diff --git a/config.c b/config.c new file mode 100644 index 0000000..7cc4f09 --- /dev/null +++ b/config.c @@ -0,0 +1,199 @@ +/* $Xorg: config.c,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */ + +/* +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. +*/ + +#include "pmint.h" +#include "config.h" + + +static Bool +getline ( +char **pbuf, +int *plen, +FILE *f) + +{ + int c, i; + + i = 0; + while(1) + { + if (i+2 > *plen) + { + if (*plen) + *plen *= 2; + else + *plen = BUFSIZ; + if (*pbuf) + *pbuf = (char *) realloc (*pbuf, *plen + 1); + else + *pbuf = (char *) malloc (*plen + 1); + if (! *pbuf) { + fprintf (stderr, "Memory allocation failure reading config file\n"); + return 0; + } + } + c = getc (f); + if (c == EOF) + break; + (*pbuf)[i++] = c; + if (c == '\n') { + i--; + break; + } + } + (*pbuf)[i] = '\0'; + return i; +} + + +#ifdef NEED_STRCASECMP +int +ncasecmp (str1, str2, n) + char *str1, *str2; + int n; +{ + char buf1[512],buf2[512]; + char c, *s; + register int i; + + for (i=0, s = buf1; i < n && (c = *str1++); i++) { + if (isupper(c)) + c = tolower(c); + if (i>510) + break; + *s++ = c; + } + *s = '\0'; + for (i=0, s = buf2; i < n && (c = *str2++); i++) { + if (isupper(c)) + c = tolower(c); + if (i>510) + break; + *s++ = c; + } + *s = '\0'; + return (strncmp(buf1, buf2, n)); +} +#endif /* NEED_STRCASECMP */ + + +Status +GetConfig ( + char *configFile, + char *serviceName, + Bool *managed, + char **startCommand, + char **proxyAddress) + +{ + FILE *fp; + int found = 0; + char *buf, *p; + int buflen, n; + + *startCommand = *proxyAddress = NULL; + + fp = fopen (configFile, "r"); + + if (!fp) + return 0; + + buf = NULL; + buflen = 0; + n = strlen (serviceName); + + while (!found && getline (&buf, &buflen, fp)) + { + if (buf[0] == '!') + continue; + + if (!(ncasecmp (buf, serviceName, n) == 0 && buf[n] == ' ')) + continue; + + /* found the right config line */ + p = buf + n + 1; + while (*p == ' ') + p++; + if (ncasecmp (p, "managed", 7) == 0) + { + *managed = 1; + p += 7; + } + else if (ncasecmp (p, "unmanaged", 9) == 0) + { + *managed = 0; + p += 9; + } + else + { + fprintf (stderr, "Error in config file at line \"%s\"\n", buf); + break; + } + + while (*p == ' ') + p++; + + if (*managed) + { + n = strlen (p); + *startCommand = (char *) malloc (n + 2); + if (! *startCommand) { + fprintf (stderr, + "Memory allocation failed for service \"%s\"\n", + serviceName); + break; + } + strcpy (*startCommand, p); + (*startCommand)[n] = '&'; + (*startCommand)[n + 1] = '\0'; + } + else + { + *proxyAddress = (char *) malloc (strlen (p) + 1); + if (! *proxyAddress) { + fprintf (stderr, + "Memory allocation failed for service \"%s\" at %s\n", + serviceName, p); + break; + } + strcpy (*proxyAddress, p); + } + + found = 1; + } + + if (buf) + free (buf); + + fclose (fp); + return found; +} + + + + diff --git a/config.h b/config.h new file mode 100644 index 0000000..484b2a2 --- /dev/null +++ b/config.h @@ -0,0 +1,47 @@ +/* $Xorg: config.h,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */ + +/* +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. +*/ + + +Status +GetConfig ( + char *configFile, + char *proxyService, + Bool *managed, + char **startCommand, + char **proxyAddress); + +#ifdef NEED_STRCASECMP +int +ncasecmp ( + char *str1, + char *str2, + int n); +#else +#include <string.h> +#define ncasecmp(s1,s2,n) strncasecmp(s1,s2,n) +#endif /* NEED_STRCASECMP */ @@ -0,0 +1,1113 @@ +/* $Xorg: main.c,v 1.6 2001/02/09 02:05:34 xorgcvs Exp $ */ + +/* +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. +*/ + +#include <stdlib.h> +#include "pmint.h" +#include <X11/StringDefs.h> +#include <X11/Intrinsic.h> +#include <X11/ICE/ICEmsg.h> +#include <X11/ICE/ICEproto.h> +#include <X11/PM/PMproto.h> +#include <X11/PM/PM.h> +#include "pmdb.h" +#include "config.h" +#include <assert.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <netdb.h> + +void InstallIOErrorHandler (); +void NewConnectionXtProc (); +static Status PMprotocolSetupProc (); +void PMReplyProcessMessages (); +void PMSetupProcessMessages (); +Bool HostBasedAuthProc (); + +static int PMAcceptorOpcode; +static int PMOriginatorOpcode; + +int PMversionCount = 1; +IcePaVersionRec PMReplyVersions[] = {{PM_MAJOR_VERSION, PM_MINOR_VERSION, + PMReplyProcessMessages}}; +IcePoVersionRec PMSetupVersions[] = {{PM_MAJOR_VERSION, PM_MINOR_VERSION, + PMSetupProcessMessages}}; + +char *PM_VENDOR_STRING = "The X.Org Group"; +char *PM_VENDOR_RELEASE = "Release 6.6"; + +int verbose = 0; + +XtAppContext appContext; + +#define PM_PORT "6500" + +char *configFile = NULL; + +void +Usage () +{ + fprintf (stderr, "Usage: proxymngr [-config file] [-verbose]\n"); + exit (1); +} + +void +SetCloseOnExec (fd) + int fd; +{ + int ret; +#ifdef F_SETFD +#ifdef FD_CLOEXEC + ret = fcntl (fd, F_SETFD, FD_CLOEXEC); +#else + ret = fcntl (fd, F_SETFD, 1); +#endif /* FD_CLOEXEC */ +#endif /* F_SETFD */ +} + +/* + * Main program + */ + +main (argc, argv) + +int argc; +char **argv; + +{ + IceListenObj *listenObjs; + int numTransports, i; + char errormsg[256]; + char *networkIds, *p; + + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-config") == 0) + { + if (++i < argc) + configFile = argv[i]; + else + Usage (); + } + else if (strcmp(argv[i], "-verbose") == 0) + { + verbose = 1; + } + else + Usage (); + } + + if (!configFile) + configFile = CONFIG_FILE; + + if (verbose) + fprintf (stderr, "config file = %s\n", configFile); + + /* + * Install an IO error handler. + */ + InstallIOErrorHandler (); + + /* + * Register support for PROXY_MANAGEMENT. + */ + + /* For Managed proxies, the proxy does the Setup */ + if ((PMAcceptorOpcode = IceRegisterForProtocolReply ( + PM_PROTOCOL_NAME, PM_VENDOR_STRING, PM_VENDOR_RELEASE, + PMversionCount, PMReplyVersions, + 0, /* authcount */ + NULL, /* authnames */ + NULL, /* authprocs */ + HostBasedAuthProc, + PMprotocolSetupProc, + NULL, /* protocolActivateProc */ + NULL /* IceIOErrorProc */ )) < 0) + { + fprintf (stderr, + "Could not register PROXY_MANAGEMENT protocol reply with ICE"); + exit (1); + } + + /* For Unmanaged proxies, we do the Setup + * ICElib doesn't specify that the same opCode will be returned + * so don't bet on it. + */ + if ((PMOriginatorOpcode = IceRegisterForProtocolSetup ( + PM_PROTOCOL_NAME, PM_VENDOR_STRING, PM_VENDOR_RELEASE, + PMversionCount, PMSetupVersions, + 0, /* authcount */ + NULL, /* authnames */ + NULL, /* authprocs */ + NULL /* IceIOErrorProc */ )) < 0) + { + fprintf (stderr, + "Could not register PROXY_MANAGEMENT protocol setup with ICE"); + exit (1); + } + + + if (!IceListenForWellKnownConnections ( + PM_PORT, &numTransports, &listenObjs, 256, errormsg)) + { + fprintf (stderr, "%s\n", errormsg); + exit (1); + } + + networkIds = IceComposeNetworkIdList (numTransports, listenObjs); + p = (char *) malloc(sizeof ("PROXY_MANAGER") + strlen(networkIds) + 2); + sprintf (p, "PROXY_MANAGER=%s", networkIds); + putenv (p); + printf ("%s\n", p); + free (networkIds); + + appContext = XtCreateApplicationContext (); + + InitWatchProcs (appContext); + + for (i = 0; i < numTransports; i++) + { + XtAppAddInput (appContext, + IceGetListenConnectionNumber (listenObjs[i]), + (XtPointer) XtInputReadMask, + NewConnectionXtProc, (XtPointer) listenObjs[i]); + + IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc); + + SetCloseOnExec (IceGetListenConnectionNumber (listenObjs[i])); + } + + /* + * Main loop + */ + XtAppMainLoop (appContext); +} + + +/* + * Xt callback invoked when a client attempts to connect. + */ + +/* ARGSUSED */ +void +NewConnectionXtProc (client_data, source, id) + +XtPointer client_data; +int *source; +XtInputId *id; + +{ + IceConn ice_conn; + char *connstr; + IceAcceptStatus status; + + ice_conn = IceAcceptConnection((IceListenObj) client_data, &status); + if (! ice_conn) { + if (verbose) + printf ("IceAcceptConnection failed\n"); + } else { + IceConnectStatus cstatus; + + /* + * Mark this fd to be closed upon exec + */ + SetCloseOnExec (IceConnectionNumber (ice_conn)); + + while ((cstatus = IceConnectionStatus (ice_conn))==IceConnectPending) { + XtAppProcessEvent (appContext, XtIMAll); + } + + if (cstatus == IceConnectAccepted) { + if (verbose) { + printf ("ICE Connection opened by client, IceConn fd = %d, ", + IceConnectionNumber (ice_conn)); + connstr = IceConnectionString (ice_conn); + printf ("Accept at networkId %s\n", connstr); + free (connstr); + printf ("\n"); + } + } else { + if (verbose) + { + if (cstatus == IceConnectIOError) + printf ("IO error opening ICE Connection!\n"); + else + printf ("ICE Connection rejected!\n"); + } + + IceCloseConnection (ice_conn); + } + } +} + + +/* + * See ConnectToProxy() if you change any of the pmConn structure + */ +static Status +PMprotocolSetupProc (iceConn, + majorVersion, minorVersion, vendor, release, + clientDataRet, failureReasonRet) + +IceConn iceConn; +int majorVersion; +int minorVersion; +char *vendor; +char *release; +IcePointer *clientDataRet; +char **failureReasonRet; + +{ + /* + * Allocate new pmConn. + */ + + static char standardError[] = "Could not allocate memory for new client"; + PMconn *pmConn; + + if ((pmConn = (PMconn *) malloc (sizeof (PMconn))) == NULL) + { + if (verbose) + fprintf (stderr, "%s\n", standardError); + + *failureReasonRet = standardError; + return (0); + } + + pmConn->iceConn = iceConn; + pmConn->pmOpcode = PMAcceptorOpcode; + pmConn->proto_major_version = majorVersion; + pmConn->proto_minor_version = minorVersion; + pmConn->vendor = vendor; + pmConn->release = release; + + *clientDataRet = (IcePointer) pmConn; + + return (1); +} + + +static void +SendGetProxyAddr ( + PMconn *pmConn, + char *serviceName, + char *serverAddress, + char *hostAddress, + char *startOptions, + int authLen, + char *authName, + char *authData) + +{ + IceConn iceConn = pmConn->iceConn; + pmGetProxyAddrMsg *pMsg; + char *pData; + int len; + + if (verbose) { + printf ("Sending GetProxyAddr to proxy %d, serviceName = %s, serverAddr = %s\n", + IceConnectionNumber(iceConn), serviceName, serverAddress); + printf (" hostAddr = %s, options = %s, authLen = %d\n", + hostAddress ? hostAddress : "", + startOptions ? startOptions : "", + authLen); + if (authLen > 0) + printf (" authName = %s\n", authName); + } + + len = STRING_BYTES (serviceName) + + STRING_BYTES (serverAddress) + + STRING_BYTES (hostAddress) + + STRING_BYTES (startOptions) + + (authLen > 0 ? (STRING_BYTES (authName) + authLen) : 0); + + IceGetHeaderExtra (iceConn, pmConn->pmOpcode, PM_GetProxyAddr, + SIZEOF (pmGetProxyAddrMsg), WORD64COUNT (len), + pmGetProxyAddrMsg, pMsg, pData); + + pMsg->authLen = authLen; + + STORE_STRING (pData, serviceName); + STORE_STRING (pData, serverAddress); + STORE_STRING (pData, hostAddress); + STORE_STRING (pData, startOptions); + if (authLen > 0) + { + STORE_STRING (pData, authName); + memcpy (pData, authData, authLen); + } + + IceFlush (iceConn); +} + + +void +SendGetProxyAddrReply ( + PMconn *requestor, + int status, + char *addr, + char *error) + +{ + int len = STRING_BYTES (addr) + STRING_BYTES (error); + pmGetProxyAddrReplyMsg *pReply; + char *pData; + + if (verbose) { + fputs ("Replying with ", stderr); + fputs (status == PM_Success ? "Success: " : + status == PM_Failure ? "Failure: " : + status == PM_Unable ? "Unable: " : + "?unknown status", stderr); + fputs (status == PM_Success ? addr : error, stderr); + fputc ('\n', stderr); + } + + IceGetHeaderExtra (requestor->iceConn, + requestor->pmOpcode, PM_GetProxyAddrReply, + SIZEOF (pmGetProxyAddrReplyMsg), WORD64COUNT (len), + pmGetProxyAddrReplyMsg, pReply, pData); + + pReply->status = status; + + STORE_STRING (pData, addr); + STORE_STRING (pData, error); + + IceFlush (requestor->iceConn); +} + + + +void +PMReplyProcessMessages (iceConn, clientData, opcode, length, swap) + +IceConn iceConn; +IcePointer clientData; +int opcode; +unsigned long length; +Bool swap; + +{ + PMconn *pmConn = (PMconn *) clientData; + + assert(pmConn->iceConn == iceConn); + + switch (opcode) + { + case PM_GetProxyAddr: + { + pmGetProxyAddrMsg *pMsg; + char *pData, *pStart; + char *serviceName = NULL, *serverAddress = NULL; + char *hostAddress = NULL, *startOptions = NULL; + char *authName = NULL, *authData = NULL; + int authLen; + + CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode, + length, SIZEOF (pmGetProxyAddrMsg), IceFatalToProtocol); + + IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrMsg), + pmGetProxyAddrMsg, pMsg, pStart); + + if (!IceValidIO (iceConn)) + { + IceDisposeCompleteMessage (iceConn, pStart); + return; + } + + authLen = swap ? lswaps (pMsg->authLen) : pMsg->authLen; + + pData = pStart; + + SKIP_STRING (pData, swap); /* proxy-service */ + SKIP_STRING (pData, swap); /* server-address */ + SKIP_STRING (pData, swap); /* host-address */ + SKIP_STRING (pData, swap); /* start-options */ + if (authLen > 0) + { + SKIP_STRING (pData, swap); /* auth-name */ + pData += (authLen + PAD64 (authLen)); /* auth-data */ + } + + CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode, + length, pData - pStart + SIZEOF (pmGetProxyAddrMsg), + pStart, IceFatalToProtocol); + + pData = pStart; + + EXTRACT_STRING (pData, swap, serviceName); + EXTRACT_STRING (pData, swap, serverAddress); + EXTRACT_STRING (pData, swap, hostAddress); + EXTRACT_STRING (pData, swap, startOptions); + if (authLen > 0) + { + EXTRACT_STRING (pData, swap, authName); + authData = (char *) malloc (authLen); + memcpy (authData, pData, authLen); + } + + if (serverAddress) + { + /* + * Assume that if serverAddress is something like :0 or :0.0 + * then the request is for a server on the client's host. + * + * However, the proxy handling this request may be on a + * different host than the client or the client host, + * proxy host and the server host may all be different, + * thus a serverAddress of :0 or :0.0 is not useful. + * Therefore, change serverAddrees to use the client's + * hostname. + */ + char *tmpName; + + tmpName = strchr (serverAddress, ':'); + + if (tmpName && ((serverAddress[0] == ':') || + (!strncmp (serverAddress, "unix:", 5)))) + { + struct sockaddr_in serverSock; + int retVal; + int addrLen = sizeof(serverSock); + + retVal = getpeername(IceConnectionNumber(iceConn), + (struct sockaddr *) &serverSock, + &addrLen); + if (!retVal) + { + struct hostent *hostent; + + hostent = gethostbyname (inet_ntoa(serverSock.sin_addr)); + + if (hostent && hostent->h_name) + { + int len; + char * pch = strdup (tmpName); + + len = strlen(hostent->h_name) + strlen(tmpName) + 1; + serverAddress = (char *) realloc (serverAddress, len); + sprintf (serverAddress, "%s%s", hostent->h_name, pch); + free (pch); + } + } + } + } + + if (verbose) { + printf ("Got GetProxyAddr, serviceName = %s, serverAddr = %s\n", + serviceName, serverAddress); + printf (" hostAddr = %s, options = %s, authLen = %d\n", + hostAddress, startOptions, authLen); + if (authLen > 0) + printf (" authName = %s\n", authName); + } + + IceDisposeCompleteMessage (iceConn, pStart); + + ForwardRequest (pmConn, serviceName, serverAddress, hostAddress, + startOptions, authLen, authName, authData); + + if (serviceName) + free (serviceName); + if (serverAddress) + free (serverAddress); + if (hostAddress) + free (hostAddress); + if (startOptions) + free (startOptions); + if (authName) + free (authName); + if (authData) + free (authData); + + break; + } + + case PM_StartProxy: + { + pmStartProxyMsg *pMsg; + char *pData, *pStart; + char *serviceName = NULL; + char *serverAddress; + char *hostAddress; + char *startOptions; + int authLen; + char *authName; + char *authData; + + CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode, + length, SIZEOF (pmStartProxyMsg), IceFatalToProtocol); + + IceReadCompleteMessage (iceConn, SIZEOF (pmStartProxyMsg), + pmStartProxyMsg, pMsg, pStart); + + if (!IceValidIO (iceConn)) + { + IceDisposeCompleteMessage (iceConn, pStart); + return; + } + + pData = pStart; + + SKIP_STRING (pData, swap); /* proxy-service */ + + CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode, + length, pData - pStart + SIZEOF (pmStartProxyMsg), + pStart, IceFatalToProtocol); + + pData = pStart; + + EXTRACT_STRING (pData, swap, serviceName); + + assert(serviceName); + + if (verbose) + printf ("Got StartProxy on fd %d, serviceName = %s\n", + IceConnectionNumber(iceConn), serviceName); + + IceDisposeCompleteMessage (iceConn, pStart); + + if (! ActivateProxyService (serviceName, pmConn)) { + fputs ("Configuration error: received unexpected StartProxy for service ", stderr); + fputs (serviceName, stderr); + fputc ('\n', stderr); + IceCloseConnection (iceConn); + } + else { + + /* + * Now send the GetProxyAddr message to the proxy. + */ + if (PeekRequestorQueue(pmConn, + NULL, NULL, NULL, + &serverAddress, &hostAddress, &startOptions, + &authLen, &authName, &authData)) { + SendGetProxyAddr(pmConn, + serviceName, serverAddress, + hostAddress, startOptions, + authLen, authName, authData); + } + else if (verbose) { + fputs ("Received StartProxy for service ", stderr); + fputs (serviceName, stderr); + fputs (" but no waiting GetproxyAddr requests\n", stderr); + } + } + + free (serviceName); + + break; + } + + case PM_GetProxyAddrReply: + + { + pmGetProxyAddrReplyMsg *pMsg; + char *pData, *pStart; + char *addr = NULL, *error = NULL; + + CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode, + length, SIZEOF (pmGetProxyAddrReplyMsg), IceFatalToProtocol); + + IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrReplyMsg), + pmGetProxyAddrReplyMsg, pMsg, pStart); + + if (!IceValidIO (iceConn)) + { + IceDisposeCompleteMessage (iceConn, pStart); + return; + } + + pData = pStart; + + SKIP_STRING (pData, swap); /* proxy-address */ + SKIP_STRING (pData, swap); /* failure-reason */ + + CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode, + length, pData - pStart + SIZEOF (pmGetProxyAddrReplyMsg), + pStart, IceFatalToProtocol); + + pData = pStart; + + EXTRACT_STRING (pData, swap, addr); + EXTRACT_STRING (pData, swap, error); + + if (verbose) { + printf ("Got GetProxyAddrReply from proxy %d, status = %d, ", + IceConnectionNumber(iceConn), pMsg->status); + if (pMsg->status == PM_Success) + printf ("addr = %s\n", addr); + else + printf ("error = %s\n", error); + } + + { /* Ignore any unsolicited replies so we don't get further confused */ + running_proxy *proxy = ProxyForPMconn(pmConn); + + if (!proxy || !proxy->requests) + { + if (verbose) + fprintf (stderr, "Received unsolicited GetProxyAddrReply from proxy %d; ignoring it.\n", + IceConnectionNumber(iceConn)); + + IceDisposeCompleteMessage (iceConn, pStart); + break; + } + } + + switch (pMsg->status) { + + case PM_Success: + { + /* + * Now send the GetProxyAddr reply to xfindproxy. + */ + + SendGetProxyAddrReply ( + PopRequestorQueue (pmConn, True, True /* free proxy list */), + PM_Success /* status */, addr, NULL); + + break; + } + + case PM_Unable: + { + running_proxy_list *proxyList; + char *serviceName, *serverAddress, *hostAddress, *startOptions; + PMconn *requestor; + int authLen; + char *authName; + char *authData; + + { + running_proxy *proxy = ProxyForPMconn(pmConn); + if (proxy) + proxy->refused_service = True; + else + fputs("Internal error: received GetProxyAddrReply from an unknown proxy\n", stderr); + } + + if (! PeekRequestorQueue (pmConn, &requestor, + &proxyList, &serviceName, &serverAddress, + &hostAddress, &startOptions, + &authLen, &authName, &authData)) { + if (verbose) + fputs("Received GetProxyAddrReply from a proxy with no requests\n", stderr); + + proxyList = NULL; + serviceName = "?unknown service--internal error"; + } + + if (proxyList && (proxyList->current < proxyList->count - 1)) + { + /* + * Ask the next running proxy if it can service this request. + */ + running_proxy *nextProxy; + + proxyList->current++; + nextProxy = proxyList->list[proxyList->current]; + + if (nextProxy->pmConn != NULL) { + /* send only if the proxy has started */ + SendGetProxyAddr (nextProxy->pmConn, serviceName, + serverAddress, hostAddress, startOptions, + authLen, authName, authData); + } + + PushRequestorQueue (nextProxy, requestor, proxyList, + serviceName, serverAddress, hostAddress, startOptions, + authLen, authName, authData); + + PopRequestorQueue (pmConn, False, False); + } + else + { + /* + * Start a new proxy. + */ + + running_proxy *runningProxy = NULL; + char *startCommand; + char *proxyAddress; + Bool managed; + + if (!GetConfig (configFile, serviceName, &managed, + &startCommand, &proxyAddress)) + { + SendGetProxyAddrReply (requestor, PM_Failure, + NULL, "Could not read proxy manager config file"); + } + else + { + runningProxy = StartNewProxy (serviceName, startCommand); + + if (runningProxy) + { + PushRequestorQueue (runningProxy, + requestor, proxyList, + serviceName, serverAddress, + hostAddress, startOptions, + authLen, authName, authData); + } + else + { + SendGetProxyAddrReply (pmConn, PM_Failure, + NULL, "Can't start new proxy"); + } + } + + if (startCommand) + free (startCommand); + if (proxyAddress) + free (proxyAddress); + + PopRequestorQueue (pmConn, False, + runningProxy ? False : True /* free proxy list */); + } + break; + } + + default: + if (verbose && pMsg->status != PM_Unable) + fprintf(stderr, + "Error: proxy returned unrecognized status: %d\n", + pMsg->status); + /* FALLTHROUGH */ + + case PM_Failure: + SendGetProxyAddrReply ( + PopRequestorQueue (pmConn, True, True /* free proxy list */), + pMsg->status, NULL, error); + } + + IceDisposeCompleteMessage (iceConn, pStart); + + /* see if there was more work queued for this proxy */ + { + char *serviceName, *serverAddress, *hostAddress, *startOptions; + int authLen; + char *authName, *authData; + + if (PeekRequestorQueue(pmConn, + NULL, NULL, &serviceName, + &serverAddress, &hostAddress, &startOptions, + &authLen, &authName, &authData)) { + SendGetProxyAddr(pmConn, + serviceName, serverAddress, + hostAddress, startOptions, + authLen, authName, authData); + } + } + + if (addr) + free (addr); + if (error) + free (error); + + break; + } + + case PM_Error: + { + iceErrorMsg *pMsg; + char *pStart; + + CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, PM_Error, length, + sizeof(iceErrorMsg), IceFatalToProtocol); + + IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg), + iceErrorMsg, pMsg, pStart); + + if (!IceValidIO (iceConn)) + { + IceDisposeCompleteMessage (iceConn, pStart); + return; + } + + if (swap) + { + pMsg->errorClass = lswaps (pMsg->errorClass); + pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum); + } + + fprintf(stderr, "Received ICE Error: class=0x%x\n offending minor opcode=%d, severity=%d, sequence=%d\n", + pMsg->errorClass, pMsg->offendingMinorOpcode, pMsg->severity, + pMsg->offendingSequenceNum); + + IceDisposeCompleteMessage (iceConn, pStart); + + break; + } + + default: + { + _IceErrorBadMinor (iceConn, pmConn->pmOpcode, opcode, IceCanContinue); + _IceReadSkip (iceConn, length << 3); + break; + } + } +} + +void +PMSetupProcessMessages (iceConn, clientData, opcode, length, swap, + replyWait, replyReadyRet) + +IceConn iceConn; +IcePointer clientData; +int opcode; +unsigned long length; +Bool swap; +IceReplyWaitInfo *replyWait; +Bool *replyReadyRet; + +{ + assert (replyWait == NULL); + + PMReplyProcessMessages (iceConn, clientData, opcode, length, swap); +} + + +void +ForwardRequest( requestor, serviceName, serverAddress, hostAddress, + startOptions, authLen, authName, authData ) + PMconn *requestor; + char *serviceName, *serverAddress, *hostAddress, *startOptions; + int authLen; + char *authName, *authData; +{ + running_proxy_list *proxyList; + running_proxy *runningProxy; + int pushRequest = 0; + + if ((proxyList = GetRunningProxyList ( + serviceName, serverAddress)) != NULL) + { + while (proxyList->current < proxyList->count) { + runningProxy = proxyList->list[proxyList->current]; + + if (runningProxy->pmConn != NULL) { + SendGetProxyAddr (runningProxy->pmConn, serviceName, + serverAddress, hostAddress, NULL, + authLen, authName, authData); + break; + } + proxyList->current++; + } + + pushRequest = 1; + } + else + { + Bool managed; + char *startCommand; + char *proxyAddress; + + if (!GetConfig (configFile, serviceName, &managed, + &startCommand, &proxyAddress)) + { + SendGetProxyAddrReply (requestor, PM_Failure, + NULL, "Could not find requested service"); + } + else + { + if (managed) + { + runningProxy = StartNewProxy (serviceName, startCommand); + + if (runningProxy) + pushRequest = 1; + else + { + SendGetProxyAddrReply (requestor, PM_Failure, + NULL, "Can't start new proxy"); + } + } + else + { + /* + * We have the unmanged proxy's address; now forward + * the request to it. + */ + + runningProxy = ConnectToProxy (PMOriginatorOpcode, + serviceName, proxyAddress); + + if (runningProxy) { + SendGetProxyAddr (runningProxy->pmConn, + serviceName, serverAddress, + hostAddress, startOptions, + authLen, authName, authData); + pushRequest = 1; + } + else + { + /* %%% We should reread the config file and look + * for another proxy address before giving up. + */ + SendGetProxyAddrReply (requestor, PM_Failure, + NULL, "Can't connect to proxy"); + } + } + + if (startCommand) + free (startCommand); + if (proxyAddress) + free (proxyAddress); + } + } + + if (pushRequest) + { + PushRequestorQueue (runningProxy, requestor, proxyList, + serviceName, serverAddress, hostAddress, startOptions, + authLen, authName, authData); + } +} + + +/* ARGSUSED */ +void +_XtProcessIceMsgProc (client_data, source, id) + +XtPointer client_data; +int *source; +XtInputId *id; + +{ + IceConn ice_conn = (IceConn) client_data; + IceProcessMessagesStatus status; + + status = IceProcessMessages (ice_conn, NULL, NULL); + + if (status == IceProcessMessagesIOError) + { + Bool activeReqs; + + ProxyGone (ice_conn, &activeReqs); + IceSetShutdownNegotiation (ice_conn, False); + IceCloseConnection (ice_conn); + } +} + + +void +_XtIceWatchProc (ice_conn, client_data, opening, watch_data) + +IceConn ice_conn; +IcePointer client_data; +Bool opening; +IcePointer *watch_data; + +{ + if (opening) + { + XtAppContext appContext = (XtAppContext) client_data; + void _XtProcessIceMsgProc (); + + *watch_data = (IcePointer) XtAppAddInput ( + appContext, + IceConnectionNumber (ice_conn), + (XtPointer) XtInputReadMask, + _XtProcessIceMsgProc, + (XtPointer) ice_conn); + } + else + { + XtRemoveInput ((XtInputId) *watch_data); + } +} + + +Status +InitWatchProcs (appContext) + +XtAppContext appContext; + +{ + return (IceAddConnectionWatch (_XtIceWatchProc, (IcePointer) appContext)); +} + + +/* + * The real way to handle IO errors is to check the return status + * of IceProcessMessages. xsm properly does this. + * + * Unfortunately, a design flaw exists in the ICE library in which + * a default IO error handler is invoked if no IO error handler is + * installed. This default handler exits. We must avoid this. + * + * To get around this problem, we install an IO error handler that + * does a little magic. Since a previous IO handler might have been + * installed, when we install our IO error handler, we do a little + * trick to get both the previous IO error handler and the default + * IO error handler. When our IO error handler is called, if the + * previous handler is not the default handler, we call it. This + * way, everyone's IO error handler gets called except the stupid + * default one which does an exit! + */ + +static IceIOErrorHandler prev_handler; + +void +MyIoErrorHandler (ice_conn) + +IceConn ice_conn; + +{ + if (prev_handler) + (*prev_handler) (ice_conn); +} + +void +InstallIOErrorHandler () + +{ + IceIOErrorHandler default_handler; + + prev_handler = IceSetIOErrorHandler (NULL); + default_handler = IceSetIOErrorHandler (MyIoErrorHandler); + if (prev_handler == default_handler) + prev_handler = NULL; +} + + +/* + * Since proxy manager does not authenticate connections, we disable + * authentication by always returning true in the host based auth proc. + */ + +Bool +HostBasedAuthProc (hostname) + +char *hostname; + +{ + return (1); +} diff --git a/pmconfig.cpp b/pmconfig.cpp new file mode 100644 index 0000000..1b9091d --- /dev/null +++ b/pmconfig.cpp @@ -0,0 +1,12 @@ +! $Xorg: pmconfig.cpp,v 1.3 2000/08/17 19:54:00 cpqbld Exp $ +! proxy manager config file +! +! Each line has the format: +! <serviceName> managed <startCommand> +! or +! <serviceName> unmanaged <proxyAddress> +! +lbx managed LBXPROXY +! +! substitute site-specific info +!xfwp unmanaged firewall:4444 @@ -0,0 +1,771 @@ +/* $Xorg: pmdb.c,v 1.5 2001/02/09 02:05:34 xorgcvs Exp $ */ + +/* +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. +*/ + +#include "pmint.h" +#include "pmdb.h" +#include "config.h" +#include <assert.h> +#include <stdio.h> +#include <signal.h> + +#if defined(X_NOT_POSIX) && defined(SIGNALRETURNSINT) +#define SIGVAL int +#else +#define SIGVAL void +#endif + +void SetCloseOnExec (int fd); + +static proxy_service *proxyServiceList = NULL; + +SIGVAL (*Signal (sig, handler))() + int sig; + SIGVAL (*handler)(); +{ +#ifndef X_NOT_POSIX + struct sigaction sigact, osigact; + sigact.sa_handler = handler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(sig, &sigact, &osigact); + return osigact.sa_handler; +#else + return signal(sig, handler); +#endif +} + +proxy_service * +FindProxyService ( + char *serviceName, + Bool createIf) + +{ + proxy_service *service = proxyServiceList; + int nameLen = strlen (serviceName); + + while (service) + { + if (strcmp (service->serviceName, serviceName) == 0) + return service; + else if (ncasecmp (service->serviceName, serviceName, nameLen) == 0) + return service; + else + service = service->next; + } + + if (createIf) { + service = (proxy_service *) malloc (sizeof (proxy_service)); + if (!service) + return NULL; + + service->serviceName = (char *) malloc (nameLen + 1); + if (!service->serviceName) + { + free (service); + return NULL; + } + + strcpy (service->serviceName, serviceName); + service->proxyCount = 0; + service->proxyList = NULL; + + if (proxyServiceList == NULL) + { + proxyServiceList = service; + service->next = NULL; + } + else + { + service->next = proxyServiceList; + proxyServiceList = service; + } + } + + return service; + +} + + +running_proxy * +StartNewProxy ( + char *serviceName, + char *startCommand) + +{ + proxy_service *service = FindProxyService (serviceName, True); + running_proxy *proxy; + + if (!service) + return NULL; + + proxy = (running_proxy *) malloc (sizeof (running_proxy)); + if (!proxy) + return NULL; + + proxy->active = 0; + proxy->pmConn = NULL; + proxy->requests = NULL; + proxy->servers = NULL; + proxy->refused_service = False; + + if (service->proxyList == NULL) + { + service->proxyList = proxy; + proxy->next = NULL; + } + else + { + proxy->next = service->proxyList; + service->proxyList = proxy; + } + + if (system (startCommand) == -1) + { + printf ("unable to start managed proxy: %s\n", startCommand); + service->proxyList = proxy->next; + free (proxy); + return NULL; + } + + if (verbose) { + printf ("started managed proxy: %s\n", startCommand); + printf ("waiting for StartProxy message\n"); + } + + service->proxyCount++; + + return proxy; +} + +/* + * ConnectToProxy( pmOpcode, serviceName, proxyAddress ) + * + * Connects to an unmanaged proxy to forward the GetProxyAddr request + * to it to handle. + * + * Ideally this would be non-blocking but there is no non-blocking + * variant of IceOpenConnection/IceProtocolSetup. So we sit here a while. + */ +running_proxy * +ConnectToProxy ( + int pmOpcode, + char *serviceName, + char *proxyAddress) + +{ + proxy_service *service = FindProxyService (serviceName, True); + running_proxy *proxy; + IceConn proxy_iceConn; + PMconn *pmConn; + + if (!service) + return NULL; + + { + int majorVersion, minorVersion; + char *vendor, *release; + char errorString[256]; + + /* + * IceOpenConnection will do more than one write to the proxy. + * If the proxy closes the connection before the second write, + * the second write may generate a SIGPIPE (empirically this + * happens on at least AIX). So, temporarily ignore this signal. + */ + + Signal (SIGPIPE, SIG_IGN); + + proxy_iceConn = IceOpenConnection( proxyAddress, NULL, + False, pmOpcode, + sizeof(errorString), errorString); + + Signal (SIGPIPE, SIG_DFL); + + if (! proxy_iceConn) { + printf("unable to open connection to unmanaged proxy \"%s\" at %s\n", + serviceName, proxyAddress); + return NULL; + } + + /* + * Mark this fd to be closed upon exec + */ + SetCloseOnExec (IceConnectionNumber (proxy_iceConn)); + + /* See PMprotocolSetupProc */ + pmConn = (PMconn *) malloc (sizeof (PMconn)); + + if (pmConn == NULL) { + IceCloseConnection (proxy_iceConn); + return NULL; + } + + if (IceProtocolSetup (proxy_iceConn, pmOpcode, + (IcePointer)pmConn, /* client_data */ + False, /* must_authenticate */ + &majorVersion, &minorVersion, + &vendor, &release, + sizeof(errorString), errorString) + != IceProtocolSetupSuccess) { + IceCloseConnection (proxy_iceConn); + free (pmConn); + printf ("Could not initialize proxy management protocol with\n unmanaged proxy \"%s\" at address %s:\n %s\n", + serviceName, proxyAddress, errorString); + return NULL; + } + + pmConn->iceConn = proxy_iceConn; + pmConn->pmOpcode = pmOpcode; + pmConn->proto_major_version = majorVersion; + pmConn->proto_minor_version = minorVersion; + pmConn->vendor = vendor; + pmConn->release = release; + } + + proxy = (running_proxy *) malloc (sizeof (running_proxy)); + if (!proxy) { + IceCloseConnection (proxy_iceConn); + free (pmConn); + return NULL; + } + + proxy->active = 1; + proxy->pmConn = pmConn; + proxy->requests = NULL; + proxy->servers = NULL; + proxy->refused_service = False; + + if (service->proxyList == NULL) + { + service->proxyList = proxy; + proxy->next = NULL; + } + else + { + proxy->next = service->proxyList; + service->proxyList = proxy; + } + + if (verbose) + printf ("connected to unmanaged proxy: %s at %s\n", + serviceName, proxyAddress); + + service->proxyCount++; + + return proxy; +} + + +Status +ActivateProxyService ( + char *serviceName, + PMconn *pmConn) + +{ + proxy_service *service = FindProxyService (serviceName, False); + running_proxy *proxy; + + if (!service) + return 0; + + proxy = service->proxyList; + + while (proxy) + { + if (!proxy->active) + { + proxy->active = 1; + proxy->pmConn = pmConn; + return 1; + } + else + proxy = proxy->next; + } + + return 0; +} + + +void +ProxyGone ( + IceConn proxyIceConn, + Bool *activeReqs) + +{ + proxy_service *service = proxyServiceList; + + while (service) + { + running_proxy *proxy = service->proxyList; + running_proxy *prevProxy = NULL; + + while (proxy) + { + if (proxy->pmConn && (proxy->pmConn->iceConn == proxyIceConn)) + { + server_list *server; + request_list *req; + + if (verbose) + printf ("Proxy disconnected on fd %d", + IceConnectionNumber(proxyIceConn)); + + server = proxy->servers; + if (verbose && server) + fputs (" for server", stdout); + + while (server) + { + server_list *next_server = server->next; + if (verbose) { + fputc (' ', stdout); + fputs (server->serverAddress, stdout); + } + free (server->serverAddress); + free (server); + server = next_server; + } + + if (verbose) + fputc ('\n', stdout); + + if (prevProxy == NULL) + service->proxyList = proxy->next; + else + prevProxy->next = proxy->next; + + service->proxyCount--; + + *activeReqs = proxy->requests != NULL; + req = proxy->requests; + while (req) + { + request_list *nextreq = req->next; + + if (req->requestor) { + assert (req->requestor->iceConn != NULL); + if (verbose) + printf ("Reprocessing request from fd %d for service %s at %s\n", + IceConnectionNumber (req->requestor->iceConn), + req->serviceName, req->serverAddress); + + ForwardRequest( req->requestor, + req->serviceName, req->serverAddress, + req->hostAddress, req->startOptions, + req->authLen, req->authName, + req->authData); + } + if (req->serviceName) + free (req->serviceName); + if (req->serverAddress) + free (req->serverAddress); + if (req->hostAddress) + free (req->hostAddress); + if (req->startOptions) + free (req->startOptions); + if (req->listData) + free (req->listData); /* proxyList */ + if (req->authName) + free (req->authName); + if (req->authData) + free (req->authData); + free (req); + req = nextreq; + } + + free (proxy); + return; + } + else if (proxy->requests) { + /* + * If it wasn't a proxy that disconnected, so it might + * have been a requestor. Search through all the requests + * while we're here and look for a match. If found, delete + * the request. + */ + request_list **prev_reqP = &proxy->requests; + request_list *req = proxy->requests; + while (req) { + if (req->requestor->iceConn == proxyIceConn) { + if (verbose) { + printf ("Requestor disconnected on fd %d while awaiting reply\n for service %s (%s)", + IceConnectionNumber(proxyIceConn), + req->serviceName, req->serverAddress); + if (proxy->pmConn && proxy->pmConn->iceConn) { + printf (" from proxy on fd %d\n", + IceConnectionNumber(proxy->pmConn->iceConn)); + } + else + fputc ('\n', stdout); + } + + *prev_reqP = req->next; + + if (req->serviceName) + free (req->serviceName); + if (req->serverAddress) + free (req->serverAddress); + if (req->hostAddress) + free (req->hostAddress); + if (req->startOptions) + free (req->startOptions); + if (req->listData) + free (req->listData); /* proxyList */ + if (req->authName) + free (req->authName); + if (req->authData) + free (req->authData); + free (req); + + /* return; */ /* should but only one req, but... */ + } + else + prev_reqP = &req->next; + + req = *prev_reqP; + } + } + + prevProxy = proxy; + proxy = proxy->next; + } + + service = service->next; + } +} + + +/* + * GetRuningProxyList returns a list of current proxies for a given + * service. The list is ordered, with proxies serving an address that + * matches the argument appearing first on the list and all others + * appearing at the end. If a proxy ever refused a request for additional + * service then it is excluded from the list if it doesn't match the + * server address. + */ +running_proxy_list * +GetRunningProxyList ( + char *serviceName, char *serverAddress) + +{ + proxy_service *service = FindProxyService (serviceName, False); + running_proxy **proxyList, *proxy; + running_proxy_list *runList; + int headIndex, tailIndex; + + if (!service || !service->proxyCount) + return NULL; + + runList = (running_proxy_list *) malloc (sizeof (running_proxy_list) + + service->proxyCount * sizeof (running_proxy *)); + + if (!runList) + return NULL; + + runList->count = 0; + runList->current = 0; + runList->list = proxyList = (running_proxy **) (runList + 1); + + proxy = service->proxyList; + headIndex = 0; + tailIndex = service->proxyCount - 1; + + while (proxy) + { + server_list *server = proxy->servers; + int match = 0; + + while (server) + { + if (strcmp (server->serverAddress, serverAddress) == 0) + { + match = 1; + break; + } + + server = server->next; + } + + if (match) { + proxyList[headIndex++] = proxy; + runList->count++; + } + else if (! proxy->refused_service) { + proxyList[tailIndex--] = proxy; + runList->count++; + } + + proxy = proxy->next; + } + + if (!runList->count) { + free ((char*)runList); + return NULL; + } + + /* if we didn't fill the list due to skipping proxies that had previously + * refused to service a new address, then remove the gaps in the list + * between the matched and unmatched server names + */ + if (runList->count < service->proxyCount) { + while (tailIndex < service->proxyCount - 1) + proxyList[headIndex++] = proxyList[++tailIndex]; + } + + return runList; +} + + +void +FreeProxyList (running_proxy_list *list) + +{ + free (list); +} + + +Status +PushRequestorQueue ( + running_proxy *proxy, + PMconn *requestor, + running_proxy_list *runList, + char *serviceName, + char *serverAddress, + char *hostAddress, + char *startOptions, + int authLen, + char *authName, + char *authData) + +{ + request_list *newreq = (request_list *) malloc (sizeof (request_list)); + + if (!newreq) + return 0; + + newreq->serviceName = (char *) malloc (strlen (serviceName) + 1); + newreq->serverAddress = (char *) malloc (strlen (serverAddress) + 1); + newreq->hostAddress = (char *) malloc (strlen (hostAddress) + 1); + newreq->startOptions = (char *) malloc (strlen (startOptions) + 1); + if (authLen > 0) + { + newreq->authName = (char *) malloc (strlen (authName) + 1); + newreq->authData = (char *) malloc (authLen); + } + + if (!newreq->serviceName || + !newreq->serverAddress || + !newreq->hostAddress || + !newreq->startOptions || + (authLen > 0 && (!newreq->authName || !newreq->authData))) + { + if (newreq->serviceName) + free (newreq->serviceName); + if (newreq->serverAddress) + free (newreq->serverAddress); + if (newreq->hostAddress) + free (newreq->hostAddress); + if (newreq->startOptions) + free (newreq->startOptions); + if (newreq->authName) + free (newreq->authName); + if (newreq->authData) + free (newreq->authData); + free (newreq); + return 0; + } + + strcpy (newreq->serviceName, serviceName); + strcpy (newreq->serverAddress, serverAddress); + strcpy (newreq->hostAddress, hostAddress); + strcpy (newreq->startOptions, startOptions); + if (authLen > 0) + { + strcpy (newreq->authName, authName); + memcpy (newreq->authData, authData, authLen); + } + else + { + newreq->authName = newreq->authData = NULL; + } + + newreq->requestor = requestor; + newreq->listData = (char *) runList; + newreq->authLen = authLen; + newreq->next = NULL; + + if (proxy->requests == NULL) + proxy->requests = newreq; + else + { + request_list *p = proxy->requests; + + while (p->next) + p = p->next; + + p->next = newreq; + } + + return 1; +} + + +Status +PeekRequestorQueue ( + PMconn *pmConn, + PMconn **requestor, + running_proxy_list **runList, + char **serviceName, + char **serverAddress, + char **hostAddress, + char **startOptions, + int *authLen, + char **authName, + char **authData) +{ + running_proxy *proxy = ProxyForPMconn (pmConn); + + if (proxy && proxy->requests) { + if (requestor) + *requestor = proxy->requests->requestor; + if (runList) + *runList = (running_proxy_list *) + proxy->requests->listData; + if (serviceName) + *serviceName = proxy->requests->serviceName; + if (serverAddress) + *serverAddress = proxy->requests->serverAddress; + if (hostAddress) + *hostAddress = proxy->requests->hostAddress; + if (startOptions) + *startOptions = proxy->requests->startOptions; + if (authLen) + *authLen = proxy->requests->authLen; + if (authName) + *authName = proxy->requests->authName; + if (authData) + *authData = proxy->requests->authData; + + return 1; + } + else + return 0; +} + + +running_proxy * +ProxyForPMconn ( + PMconn *pmConn) +{ + proxy_service *service = proxyServiceList; + + while (service) + { + running_proxy *proxy = service->proxyList; + + while (proxy) + { + if (proxy->pmConn == pmConn) + return proxy; + else + proxy = proxy->next; + } + + service = service->next; + } + + return NULL; +} + + +PMconn* +PopRequestorQueue ( + PMconn *pmConn, + Bool addServer, /* record this server address */ + Bool freeProxyList) +{ + running_proxy *proxy = ProxyForPMconn (pmConn); + + if (proxy) { + PMconn *requestor; + server_list *server; + request_list *nextreq; + Bool newServer = False; + + if (addServer) { + newServer = True; + server = proxy->servers; + + while (server) + { + if (strcmp (server->serverAddress, + proxy->requests->serverAddress) == 0) + { + newServer = False; + break; + } + + server = server->next; + } + + if (newServer) + { + server = (server_list *) malloc (sizeof (server_list)); + server->serverAddress = proxy->requests->serverAddress; + server->next = proxy->servers; + proxy->servers = server; + } + } + + if (!newServer) + free (proxy->requests->serverAddress); + + if (proxy->requests->serviceName) + free (proxy->requests->serviceName); + if (proxy->requests->hostAddress) + free (proxy->requests->hostAddress); + if (proxy->requests->startOptions) + free (proxy->requests->startOptions); + if (freeProxyList && proxy->requests->listData) + free (proxy->requests->listData); /* proxyList */ + if (proxy->requests->authName) + free (proxy->requests->authName); + if (proxy->requests->authData) + free (proxy->requests->authData); + + requestor = proxy->requests->requestor; + + nextreq = proxy->requests->next; + free (proxy->requests); + proxy->requests = nextreq; + + return requestor; + } + + return NULL; +} @@ -0,0 +1,149 @@ +/* $Xorg: pmdb.h,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */ + +/* +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. +*/ + + +#include <X11/ICE/ICElib.h> + + +typedef struct _server_list { + char *serverAddress; + struct _server_list *next; +} server_list; + + +typedef struct _request_list { + char *serviceName; + char *serverAddress; + char *hostAddress; + char *startOptions; + PMconn *requestor; + char *listData; + int authLen; + char *authName; + char *authData; + struct _request_list *next; +} request_list; + + +typedef struct _running_proxy { + Bool active; + PMconn *pmConn; + request_list *requests; + server_list *servers; + Bool refused_service; + struct _running_proxy *next; +} running_proxy; + + +typedef struct _proxy_service { + char *serviceName; + int proxyCount; + running_proxy *proxyList; + struct _proxy_service *next; +} proxy_service; + + +typedef struct { + int count; + int current; + running_proxy **list; +} running_proxy_list; + + + +proxy_service +*FindProxyService ( + char *serviceName, + Bool createIf); + +running_proxy * +StartNewProxy ( + char *serviceName, + char *startCommand); + +running_proxy * +ConnectToProxy ( + int pmOpcode, + char *serviceName, + char *proxyAddress); + +Status +ActivateProxyService ( + char *serviceName, + PMconn *proxy); + +void +ProxyGone ( + IceConn proxyIceConn, + Bool *activeReqs); + +running_proxy_list * +GetRunningProxyList ( + char *serviceName, + char *serverAddress); + +void +FreeProxyList ( + running_proxy_list *list); + +Status +PushRequestorQueue ( + running_proxy *proxy, + PMconn *requestor, + running_proxy_list *runList, + char *serviceName, + char *serverAddress, + char *hostAddress, + char *startOptions, + int authLen, + char *authName, + char *authData); + + +Status +PeekRequestorQueue ( + PMconn *proxy, + PMconn **requestor, + running_proxy_list **runList, + char **serviceName, + char **serverAddress, + char **hostAddress, + char **startOptions, + int *authLen, + char **authName, + char **authData); + +PMconn* +PopRequestorQueue ( + PMconn *pmConn, + Bool addServer, + Bool freeProxyList); + +running_proxy * +ProxyForPMconn( + PMconn *pmConn); @@ -0,0 +1,184 @@ +/* $Xorg: pmint.h,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */ + +/* +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. +*/ + +#include <stdio.h> +#include <X11/Xos.h> +#include <X11/Xfuncs.h> +#include <X11/Xmd.h> +#include <X11/ICE/ICElib.h> + +#define Status int +#define Bool int +#define True 1 +#define False 0 + +extern char *PM_VENDOR_STRING; +extern char *PM_VENDOR_RELEASE; + +extern int verbose; + +typedef struct { + IceConn iceConn; + int pmOpcode; + int proto_major_version; + int proto_minor_version; + char *vendor; + char *release; +} PMconn; + +extern void +SendGetProxyAddrReply ( + PMconn* /* requestor */, + int /* status */, + char* /* addr */, + char* /* error */); + +extern void +ForwardRequest( + PMconn* /* requestor */, + char* /* serviceName */, + char* /* serverAddress */, + char* /* hostAddress */, + char* /* startOptions */, + int /* authLen */, + char* /* authName */, + char* /* authData */); + + +/* + * Pad to a 64 bit boundary + */ + +#define PAD64(_bytes) ((8 - ((unsigned int) (_bytes) % 8)) % 8) + +#define PADDED_BYTES64(_bytes) (_bytes + PAD64 (_bytes)) + + +/* + * Number of 8 byte units in _bytes. + */ + +#define WORD64COUNT(_bytes) (((unsigned int) ((_bytes) + 7)) >> 3) + + +/* + * Compute the number of bytes for a STRING representation + */ + +#define STRING_BYTES(_str) (2 + (_str ? strlen (_str) : 0) + \ + PAD64 (2 + (_str ? strlen (_str) : 0))) + + + +#define SKIP_STRING(_pBuf, _swap) \ +{ \ + CARD16 _len; \ + EXTRACT_CARD16 (_pBuf, _swap, _len); \ + _pBuf += _len; \ + if (PAD64 (2 + _len)) \ + _pBuf += PAD64 (2 + _len); \ +} + +/* + * STORE macros + */ + +#define STORE_CARD16(_pBuf, _val) \ +{ \ + *((CARD16 *) _pBuf) = _val; \ + _pBuf += 2; \ +} + +#define STORE_STRING(_pBuf, _string) \ +{ \ + int _len = _string ? strlen (_string) : 0; \ + STORE_CARD16 (_pBuf, _len); \ + if (_len) { \ + memcpy (_pBuf, _string, _len); \ + _pBuf += _len; \ + } \ + if (PAD64 (2 + _len)) \ + _pBuf += PAD64 (2 + _len); \ +} + + +/* + * EXTRACT macros + */ + +#define EXTRACT_CARD16(_pBuf, _swap, _val) \ +{ \ + _val = *((CARD16 *) _pBuf); \ + _pBuf += 2; \ + if (_swap) \ + _val = lswaps (_val); \ +} + +#define EXTRACT_STRING(_pBuf, _swap, _string) \ +{ \ + CARD16 _len; \ + EXTRACT_CARD16 (_pBuf, _swap, _len); \ + _string = (char *) malloc (_len + 1); \ + memcpy (_string, _pBuf, _len); \ + _string[_len] = '\0'; \ + _pBuf += _len; \ + if (PAD64 (2 + _len)) \ + _pBuf += PAD64 (2 + _len); \ +} + + +/* + * Byte swapping + */ + +/* byte swap a long literal */ +#define lswapl(_val) ((((_val) & 0xff) << 24) |\ + (((_val) & 0xff00) << 8) |\ + (((_val) & 0xff0000) >> 8) |\ + (((_val) >> 24) & 0xff)) + +/* byte swap a short literal */ +#define lswaps(_val) ((((_val) & 0xff) << 8) | (((_val) >> 8) & 0xff)) + + +#define CHECK_AT_LEAST_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _severity) \ + if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) > _expected_len) \ + { \ + _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \ + return; \ + } + + +#define CHECK_COMPLETE_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _pStart, _severity) \ + if (((PADDED_BYTES64((_actual_len)) - SIZEOF (iceMsg)) >> 3) \ + != _expected_len) \ + { \ + _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \ + IceDisposeCompleteMessage (iceConn, _pStart); \ + return; \ + } diff --git a/proxymngr.man b/proxymngr.man new file mode 100644 index 0000000..0129d7f --- /dev/null +++ b/proxymngr.man @@ -0,0 +1,174 @@ +.\" $Xorg: proxymngr.man,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ +.\" Copyright 1996, 1998 The Open Group +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included +.\" in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall +.\" not be used in advertising or otherwise to promote the sale, use or +.\" other dealings in this Software without prior written authorization +.\" from The Open Group. +.\" +.TH PROXYMNGR 1 "Release 6.4" "X Version 11" +.SH NAME +proxymngr - proxy manager service +.SH SYNOPSIS +\fBproxymngr\fP [\fB\-config\fP \fIfilename\fP] [\fB\-timeout\fP \fIseconds\fP] [\fB\-retries\fP \fI#\fP] [\fB\-verbose\fP] +.SH DESCRIPTION +The proxy manager (proxymngr) is responsible for resolving requests from +xfindproxy (and other similar clients), starting new proxies when +appropriate, and keeping track of all of the available proxy services. +The proxy manager strives to reuse existing proxies whenever possible. +.PP +There are two types of proxies that the proxy manager deals with, \fImanaged\fP +and \fIunmanaged\fP proxies. +.PP +A \fImanaged\fP proxy is a proxy that is started ``on demand'' by the proxy manager. +.PP +An \fIunmanaged\fP proxy, on the other hand, is started either at system boot time, +or manually by a system administrator. The proxy manager is made aware of +its existence, but no attempt is made by the proxy manager to start unmanaged +proxies. +.PP +The command line options that can be specified to +.B proxymngr +are: +.PP +.TP 8 +.B \-config +Used to override the default proxymngr config file. +See below for more details about the config file. +.PP +.TP 8 +.B \-timeout +Sets the number of seconds between attempts made by the +proxy manager to find an unmanaged proxy. The default is 10. +.PP +.TP 8 +.B \-retries +Sets the maximum number of retries made by the proxy +manager to find an an unmanaged proxy. The default is 3. +.PP +.TP 8 +.B \-verbose +Causes various debugging and tracing records to be displayed as +requests are received and proxies are started. +.PP +.PP +.SH Proxy Manager Config File +.PP +The proxy manager maintains a local configuration file describing the proxy +services available. This configuration file is installed +in /usr/X11R6.4/lib/X11/proxymngr/pmconfig during the installation +of proxymngr. The location of the configuration file can be overwritten using +the \fB\-config\fP command line option. +.PP +Aside from lines starting with an exclamation point for comments, each line +of the configuration file describes either an unmanaged or managed proxy +service. +.PP +For unmanaged proxies, the format is: +.IP +<service-name> unmanaged <proxy-address> +.PP +service-name is the name of the unmanaged proxy service, and must not +contain any spaces, for example ``XFWP''. service-name is case +insenstive. +.PP +proxy-address is the network address of the unmanaged proxy. The format +of the address is specific to the service-name. For example, for the +``XFWP'' service, the proxy-address might be ``firewall.x.org:100''. +.PP +If there is more than one entry in the config file with the same +unmanaged service-name, the proxy manager will try to use the proxies +in the order presented in the config file. +.PP +For managed proxies, the format is: +.IP +<service-name> managed <command-to-start-proxy> +.PP +service-name is the name of the managed proxy service, and must not +contain any spaces, for example ``LBX''. service-name is case insensitive. +.PP +command-to-start-proxy is the command executed by the proxy manager to +start a new instance of the proxy. If command-to-start-proxy contains +spaces, the complete command should be surrounded by single quotes. +If desired, command-to-start-proxy can be used to start a proxy on a +remote machine. The specifics of the remote execution method used to +do this is not specified here. +.PP +.SH EXAMPLE +.PP +Here is a sample configuration file: +.PP +.nf +\fC +.RS +! proxy manager config file +! +! Each line has the format: +! <serviceName> managed <startCommand> +! or +! <serviceName> unmanaged <proxyAddress> +! +lbx managed /usr/X11R6.4/bin/lbxproxy +! +! substitute site-specific info +xfwp unmanaged firewall:4444 +\fP +.RE +.fi +.PP +.SH PROXY MANAGER DETAILS +.PP +When the proxy manager gets a request from xfindproxy (or another similar +client), its course of action will depend on the service-name in question. +.PP +For a managed proxy service, the proxy manager will find out if any of the +already running proxies for this service can handle a new request. If not, +the proxy manager will attempt to start up a new instance of the proxy +(using the command-to-start-proxy found in the config file). If that fails, +an error will be returned to the caller. +.PP +For an unmanaged proxy service, the proxy manager will look in the config +file to find all unmanaged proxies for this service. If there is more than +one entry in the config file with the same unmanaged service-name, the +proxy manager will try to use the proxies in the order presented in the +config file. If none of the unmanged proxies can satisfy the request, the +proxy manager will timeout for a configurable amount of time (specified by +.B \-timeout +or default of 10) and reattempt to find an unmanaged proxy willing +to satisfy the request. The number of retries can be specified by the +.B \-retries +argument, or a default of 3 will be used. If the retries fail, +the proxy manager has no choice but to return an error to the caller (since +the proxy manager can not start unmanaged proxy services). +.PP +.SH BUGS +proxy manager listen port should be configurable. +.PP +.B \-timeout +and +.B \-retries +is not implemented in proxymngr. +.PP +proxymngr does not utilize the ``options'' and ``host'' fields in the +proxy management protocol GetProxyAddr request. +.SH SEE ALSO +xfindproxy (1), xfwp (1), Proxy Management Protocol spec V1.0 +.SH AUTHOR +Ralph Mor, X Consortium |