1
2/*
3Copyright 1996, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26*/
27
28#include <stdlib.h>
29#include "pmint.h"
30#include <X11/StringDefs.h>
31#include <X11/Intrinsic.h>
32#include <X11/ICE/ICEmsg.h>
33#include <X11/ICE/ICEproto.h>
34#include <X11/PM/PMproto.h>
35#include <X11/PM/PM.h>
36#include "pmdb.h"
37#include "config.h"
38#include <assert.h>
39
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <sys/socket.h>
43#include <netdb.h>
44
45static int PMprotocolSetupProc ( IceConn iceConn, int majorVersion,
46				 int minorVersion, char *vendor,
47				 char *release, IcePointer *clientDataRet,
48				 char **failureReasonRet );
49static void SendGetProxyAddr ( PMconn *pmConn, char *serviceName,
50			       char *serverAddress, char *hostAddress,
51			       char *startOptions, int authLen,
52			       char *authName, char *authData );
53
54static int PMAcceptorOpcode;
55static int PMOriginatorOpcode;
56
57static int PMversionCount = 1;
58static IcePaVersionRec	PMReplyVersions[] = {{PM_MAJOR_VERSION, PM_MINOR_VERSION,
59				      PMReplyProcessMessages}};
60static IcePoVersionRec	PMSetupVersions[] = {{PM_MAJOR_VERSION, PM_MINOR_VERSION,
61				      PMSetupProcessMessages}};
62
63const char *PM_VENDOR_STRING = XVENDORNAME;
64const char *PM_VENDOR_RELEASE = XORG_RELEASE;
65
66int verbose = 0;
67
68static XtAppContext	appContext;
69
70#define PM_PORT "6500"
71
72static const char *configFile = NULL;
73
74void
75Usage(void)
76{
77    fprintf (stderr, "Usage: proxymngr [-config file] [-verbose]\n");
78    exit (1);
79}
80
81void
82SetCloseOnExec(int fd)
83{
84#ifdef F_SETFD
85#ifdef FD_CLOEXEC
86    (void) fcntl (fd, F_SETFD, FD_CLOEXEC);
87#else
88    (void) fcntl (fd, F_SETFD, 1);
89#endif /* FD_CLOEXEC */
90#endif /* F_SETFD */
91}
92
93/*
94 * Main program
95 */
96
97int
98main (int argc, char *argv[])
99{
100    IceListenObj *listenObjs;
101    int		numTransports, i;
102    char	errormsg[256];
103    char	*networkIds, *p;
104
105    for (i = 1; i < argc; i++)
106    {
107	if (strcmp (argv[i], "-config") == 0)
108	{
109	    if (++i < argc)
110	        configFile = argv[i];
111	    else
112		Usage ();
113	}
114	else if (strcmp(argv[i], "-verbose") == 0)
115	{
116	    verbose = 1;
117	}
118	else
119	    Usage ();
120    }
121
122    if (!configFile)
123	configFile = CONFIG_FILE;
124
125    if (verbose)
126	fprintf (stderr, "config file = %s\n", configFile);
127
128    /*
129     * Install an IO error handler.
130     */
131    InstallIOErrorHandler ();
132
133    /*
134     * Register support for PROXY_MANAGEMENT.
135     */
136
137    /* For Managed proxies, the proxy does the Setup */
138    if ((PMAcceptorOpcode = IceRegisterForProtocolReply (
139	PM_PROTOCOL_NAME, PM_VENDOR_STRING, PM_VENDOR_RELEASE,
140	PMversionCount, PMReplyVersions,
141	0, /* authcount */
142	NULL, /* authnames */
143        NULL, /* authprocs */
144        HostBasedAuthProc,
145	PMprotocolSetupProc,
146	NULL, /* protocolActivateProc */
147	NULL  /* IceIOErrorProc */ )) < 0)
148    {
149	fprintf (stderr,
150	    "Could not register PROXY_MANAGEMENT protocol reply with ICE");
151	exit (1);
152    }
153
154    /* For Unmanaged proxies, we do the Setup
155     * ICElib doesn't specify that the same opCode will be returned
156     * so don't bet on it.
157     */
158    if ((PMOriginatorOpcode = IceRegisterForProtocolSetup (
159	PM_PROTOCOL_NAME, PM_VENDOR_STRING, PM_VENDOR_RELEASE,
160	PMversionCount, PMSetupVersions,
161	0, /* authcount */
162	NULL, /* authnames */
163        NULL, /* authprocs */
164	NULL  /* IceIOErrorProc */ )) < 0)
165    {
166	fprintf (stderr,
167	    "Could not register PROXY_MANAGEMENT protocol setup with ICE");
168	exit (1);
169    }
170
171
172    if (!IceListenForWellKnownConnections (
173	PM_PORT, &numTransports, &listenObjs, 256, errormsg))
174    {
175	fprintf (stderr, "%s\n", errormsg);
176	exit (1);
177    }
178
179    networkIds = IceComposeNetworkIdList (numTransports, listenObjs);
180    p = malloc (sizeof ("PROXY_MANAGER") + strlen(networkIds) + 2);
181    sprintf (p, "PROXY_MANAGER=%s", networkIds);
182    putenv (p);
183    printf ("%s\n", p);
184    free (networkIds);
185
186    appContext = XtCreateApplicationContext ();
187
188    InitWatchProcs (appContext);
189
190    for (i = 0; i < numTransports; i++)
191    {
192	XtAppAddInput (appContext,
193	    IceGetListenConnectionNumber (listenObjs[i]),
194	    (XtPointer) XtInputReadMask,
195	    NewConnectionXtProc, (XtPointer) listenObjs[i]);
196
197	IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc);
198
199        SetCloseOnExec (IceGetListenConnectionNumber (listenObjs[i]));
200    }
201
202    /*
203     * Main loop
204     */
205    XtAppMainLoop (appContext);
206    exit (0);
207}
208
209
210/*
211 * Xt callback invoked when a client attempts to connect.
212 */
213
214/* ARGSUSED */
215void
216NewConnectionXtProc(XtPointer client_data, int *source, XtInputId *id)
217{
218    IceConn 	ice_conn;
219    char	*connstr;
220    IceAcceptStatus status;
221
222    ice_conn = IceAcceptConnection((IceListenObj) client_data, &status);
223    if (! ice_conn) {
224	if (verbose)
225	    printf ("IceAcceptConnection failed\n");
226    } else {
227	IceConnectStatus cstatus;
228
229        /*
230	 * Mark this fd to be closed upon exec
231	 */
232        SetCloseOnExec (IceConnectionNumber (ice_conn));
233
234	while ((cstatus = IceConnectionStatus (ice_conn))==IceConnectPending) {
235	    XtAppProcessEvent (appContext, XtIMAll);
236	}
237
238	if (cstatus == IceConnectAccepted) {
239	    if (verbose) {
240		printf ("ICE Connection opened by client, IceConn fd = %d, ",
241			IceConnectionNumber (ice_conn));
242		connstr = IceConnectionString (ice_conn);
243		printf ("Accept at networkId %s\n", connstr);
244		free (connstr);
245		printf ("\n");
246	    }
247	} else {
248	    if (verbose)
249	    {
250		if (cstatus == IceConnectIOError)
251		    printf ("IO error opening ICE Connection!\n");
252		else
253		    printf ("ICE Connection rejected!\n");
254	    }
255
256	    IceCloseConnection (ice_conn);
257	}
258    }
259}
260
261
262/*
263 * See ConnectToProxy() if you change any of the pmConn structure
264 */
265static Status
266PMprotocolSetupProc(IceConn iceConn, int majorVersion, int minorVersion,
267		    char *vendor, char *release, IcePointer *clientDataRet,
268		    char **failureReasonRet)
269
270{
271    /*
272     * Allocate new pmConn.
273     */
274
275    static char standardError[] = "Could not allocate memory for new client";
276    PMconn *pmConn;
277
278    if ((pmConn = malloc (sizeof (PMconn))) == NULL)
279    {
280	if (verbose)
281	    fprintf (stderr, "%s\n", standardError);
282
283	*failureReasonRet = standardError;
284	return (0);
285    }
286
287    pmConn->iceConn = iceConn;
288    pmConn->pmOpcode = PMAcceptorOpcode;
289    pmConn->proto_major_version = majorVersion;
290    pmConn->proto_minor_version = minorVersion;
291    pmConn->vendor = vendor;
292    pmConn->release = release;
293
294    *clientDataRet = (IcePointer) pmConn;
295
296    return (1);
297}
298
299
300static void
301SendGetProxyAddr (
302    PMconn *pmConn,
303    char *serviceName,
304    char *serverAddress,
305    char *hostAddress,
306    char *startOptions,
307    int authLen,
308    char *authName,
309    char *authData)
310
311{
312    IceConn iceConn = pmConn->iceConn;
313    pmGetProxyAddrMsg *pMsg;
314    char *pData;
315    int len;
316
317    if (verbose) {
318	printf ("Sending GetProxyAddr to proxy %d, serviceName = %s, serverAddr = %s\n",
319		IceConnectionNumber(iceConn), serviceName, serverAddress);
320	printf ("  hostAddr = %s, options = %s, authLen = %d\n",
321		hostAddress ? hostAddress : "",
322		startOptions ? startOptions : "",
323		authLen);
324	if (authLen > 0)
325	    printf ("  authName = %s\n", authName);
326    }
327
328    len = STRING_BYTES (serviceName) +
329	  STRING_BYTES (serverAddress) +
330	  STRING_BYTES (hostAddress) +
331	  STRING_BYTES (startOptions) +
332	  (authLen > 0 ? (STRING_BYTES (authName) + authLen) : 0);
333
334    IceGetHeaderExtra (iceConn, pmConn->pmOpcode, PM_GetProxyAddr,
335	  SIZEOF (pmGetProxyAddrMsg), WORD64COUNT (len),
336	  pmGetProxyAddrMsg, pMsg, pData);
337
338    pMsg->authLen = authLen;
339
340    STORE_STRING (pData, serviceName);
341    STORE_STRING (pData, serverAddress);
342    STORE_STRING (pData, hostAddress);
343    STORE_STRING (pData, startOptions);
344    if (authLen > 0)
345    {
346	STORE_STRING (pData, authName);
347	memcpy (pData, authData, authLen);
348    }
349
350    IceFlush (iceConn);
351}
352
353
354void
355SendGetProxyAddrReply (
356    PMconn *requestor,
357    int status,
358    const char *addr,
359    const char *error)
360
361{
362    int len = STRING_BYTES (addr) + STRING_BYTES (error);
363    pmGetProxyAddrReplyMsg *pReply;
364    char *pData;
365
366    if (verbose) {
367	fputs ("Replying with ", stderr);
368	fputs (status == PM_Success ? "Success: " :
369	       status == PM_Failure ? "Failure: " :
370	       status == PM_Unable  ? "Unable: "  :
371	       "?unknown status", stderr);
372	fputs (status == PM_Success ? addr : error, stderr);
373	fputc ('\n', stderr);
374    }
375
376    IceGetHeaderExtra (requestor->iceConn,
377	requestor->pmOpcode, PM_GetProxyAddrReply,
378	SIZEOF (pmGetProxyAddrReplyMsg), WORD64COUNT (len),
379	pmGetProxyAddrReplyMsg, pReply, pData);
380
381    pReply->status = status;
382
383    STORE_STRING (pData, addr);
384    STORE_STRING (pData, error);
385
386    IceFlush (requestor->iceConn);
387}
388
389
390
391void
392PMReplyProcessMessages(IceConn iceConn, IcePointer clientData, int opcode,
393		       unsigned long length, Bool swap)
394
395{
396    PMconn *pmConn = (PMconn *) clientData;
397
398    assert(pmConn->iceConn == iceConn);
399
400    switch (opcode)
401    {
402    case PM_GetProxyAddr:
403    {
404	pmGetProxyAddrMsg 	*pMsg;
405	char 			*pData, *pStart;
406	char			*serviceName = NULL, *serverAddress = NULL;
407	char			*hostAddress = NULL, *startOptions = NULL;
408	char			*authName = NULL, *authData = NULL;
409	int			authLen;
410
411#if 0 /* No-op */
412	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
413	    length, SIZEOF (pmGetProxyAddrMsg), IceFatalToProtocol);
414#endif
415
416	IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrMsg),
417	    pmGetProxyAddrMsg, pMsg, pStart);
418
419	if (!IceValidIO (iceConn))
420	{
421	    IceDisposeCompleteMessage (iceConn, pStart);
422	    return;
423	}
424
425	authLen = swap ? lswaps (pMsg->authLen) : pMsg->authLen;
426
427	pData = pStart;
428
429	SKIP_STRING (pData, swap);	/* proxy-service */
430	SKIP_STRING (pData, swap);	/* server-address */
431	SKIP_STRING (pData, swap);	/* host-address */
432	SKIP_STRING (pData, swap);	/* start-options */
433	if (authLen > 0)
434	{
435	    SKIP_STRING (pData, swap);		    /* auth-name */
436	    pData += (authLen +  PAD64 (authLen));  /* auth-data */
437	}
438
439	CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
440	   length, pData - pStart + SIZEOF (pmGetProxyAddrMsg),
441	   pStart, IceFatalToProtocol);
442
443	pData = pStart;
444
445	EXTRACT_STRING (pData, swap, serviceName);
446	EXTRACT_STRING (pData, swap, serverAddress);
447	EXTRACT_STRING (pData, swap, hostAddress);
448	EXTRACT_STRING (pData, swap, startOptions);
449	if (authLen > 0)
450	{
451	    EXTRACT_STRING (pData, swap, authName);
452	    authData = malloc (authLen);
453	    memcpy (authData, pData, authLen);
454	}
455
456	if (serverAddress)
457	{
458	    /*
459	     * Assume that if serverAddress is something like :0 or :0.0
460	     * then the request is for a server on the client's host.
461	     *
462	     * However, the proxy handling this request may be on a
463	     * different host than the client or the client host,
464	     * proxy host and the server host may all be different,
465	     * thus a serverAddress of :0 or :0.0 is not useful.
466	     * Therefore, change serverAddress to use the client's
467	     * hostname.
468	     */
469	    char		*tmpName;
470
471	    tmpName = strrchr (serverAddress, ':');
472
473	    if (tmpName && ((tmpName == serverAddress) ||
474			    (!strncmp (serverAddress, "unix:", 5))))
475	    {
476#if defined(IPv6) && defined(AF_INET6)
477		struct sockaddr_storage	serverSock;
478#else
479		struct sockaddr_in	serverSock;
480#endif
481		int 			retVal;
482		int 			addrLen = sizeof(serverSock);
483
484		retVal = getpeername(IceConnectionNumber(iceConn),
485				     (struct sockaddr *) &serverSock,
486				     (void *) &addrLen);
487		if (!retVal)
488		{
489		    char *canonname = NULL;
490#if defined(IPv6) && defined(AF_INET6)
491		    char hostname[NI_MAXHOST];
492		    struct addrinfo *ai = NULL, hints;
493
494		    if (getnameinfo((struct sockaddr *) &serverSock,
495		      addrLen, hostname, sizeof(hostname), NULL, 0, 0) == 0) {
496			(void)memset(&hints, 0, sizeof(hints));
497			hints.ai_flags = AI_CANONNAME;
498			if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) {
499			    canonname = ai->ai_canonname;
500			}
501		    }
502#else
503		    struct hostent *hostent;
504
505		    hostent = gethostbyname (inet_ntoa(serverSock.sin_addr));
506
507		    if (hostent && hostent->h_name)
508			canonname = hostent->h_name;
509#endif
510		    if (canonname)
511		    {
512			int		len;
513			char		* pch = strdup (tmpName);
514
515			len = strlen(canonname) + strlen(tmpName) + 1;
516			serverAddress = realloc (serverAddress, len);
517			sprintf (serverAddress, "%s%s", canonname, pch);
518			free (pch);
519		    }
520#if defined(IPv6) && defined(AF_INET6)
521		    if (ai != NULL)
522			freeaddrinfo(ai);
523#endif
524		}
525	    }
526	}
527
528	if (verbose) {
529	    printf ("Got GetProxyAddr, serviceName = %s, serverAddr = %s\n",
530		    serviceName, serverAddress);
531	    printf ("  hostAddr = %s, options = %s, authLen = %d\n",
532		    hostAddress, startOptions, authLen);
533	    if (authLen > 0)
534		printf ("  authName = %s\n", authName);
535	}
536
537	IceDisposeCompleteMessage (iceConn, pStart);
538
539	ForwardRequest (pmConn, serviceName, serverAddress, hostAddress,
540			startOptions, authLen, authName, authData);
541
542	free (serviceName);
543	free (serverAddress);
544	free (hostAddress);
545	free (startOptions);
546	free (authName);
547	free (authData);
548
549	break;
550    }
551
552    case PM_StartProxy:
553    {
554	pmStartProxyMsg *pMsg;
555	char 		*pData, *pStart;
556	char		*serviceName = NULL;
557	char		*serverAddress;
558	char		*hostAddress;
559	char		*startOptions;
560	int		authLen;
561	char		*authName;
562	char		*authData;
563
564#if 0 /* No-op */
565	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
566	    length, SIZEOF (pmStartProxyMsg), IceFatalToProtocol);
567#endif
568
569	IceReadCompleteMessage (iceConn, SIZEOF (pmStartProxyMsg),
570	    pmStartProxyMsg, pMsg, pStart);
571
572	if (!IceValidIO (iceConn))
573	{
574	    IceDisposeCompleteMessage (iceConn, pStart);
575	    return;
576	}
577
578	pData = pStart;
579
580	SKIP_STRING (pData, swap);	/* proxy-service */
581
582	CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
583	   length, pData - pStart + SIZEOF (pmStartProxyMsg),
584	   pStart, IceFatalToProtocol);
585
586	pData = pStart;
587
588	EXTRACT_STRING (pData, swap, serviceName);
589
590	assert(serviceName);
591
592	if (verbose)
593	    printf ("Got StartProxy on fd %d, serviceName = %s\n",
594		    IceConnectionNumber(iceConn), serviceName);
595
596	IceDisposeCompleteMessage (iceConn, pStart);
597
598	if (! ActivateProxyService (serviceName, pmConn)) {
599	    fputs ("Configuration error: received unexpected StartProxy for service ", stderr);
600	    fputs (serviceName, stderr);
601	    fputc ('\n', stderr);
602	    IceCloseConnection (iceConn);
603	}
604	else {
605
606	    /*
607	     * Now send the GetProxyAddr message to the proxy.
608	     */
609	    if (PeekRequestorQueue(pmConn,
610				   NULL, NULL, NULL,
611				   &serverAddress, &hostAddress, &startOptions,
612				   &authLen, &authName, &authData)) {
613		SendGetProxyAddr(pmConn,
614				 serviceName, serverAddress,
615				 hostAddress, startOptions,
616				 authLen, authName, authData);
617	    }
618	    else if (verbose) {
619		    fputs ("Received StartProxy for service ", stderr);
620		    fputs (serviceName, stderr);
621		    fputs (" but no waiting GetproxyAddr requests\n", stderr);
622	    }
623	}
624
625	free (serviceName);
626
627	break;
628    }
629
630    case PM_GetProxyAddrReply:
631
632    {
633	pmGetProxyAddrReplyMsg 	*pMsg;
634	char			*pData, *pStart;
635	char			*addr = NULL, *error = NULL;
636
637#if 0 /* No-op */
638	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
639	    length, SIZEOF (pmGetProxyAddrReplyMsg), IceFatalToProtocol);
640#endif
641
642	IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrReplyMsg),
643	    pmGetProxyAddrReplyMsg, pMsg, pStart);
644
645	if (!IceValidIO (iceConn))
646	{
647	    IceDisposeCompleteMessage (iceConn, pStart);
648	    return;
649	}
650
651	pData = pStart;
652
653	SKIP_STRING (pData, swap);		/* proxy-address */
654	SKIP_STRING (pData, swap);		/* failure-reason */
655
656	CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
657	    length, pData - pStart + SIZEOF (pmGetProxyAddrReplyMsg),
658	    pStart, IceFatalToProtocol);
659
660	pData = pStart;
661
662	EXTRACT_STRING (pData, swap, addr);
663	EXTRACT_STRING (pData, swap, error);
664
665	if (verbose) {
666	    printf ("Got GetProxyAddrReply from proxy %d, status = %d, ",
667		    IceConnectionNumber(iceConn), pMsg->status);
668	    if (pMsg->status == PM_Success)
669		printf ("addr = %s\n", addr);
670	    else
671		printf ("error = %s\n", error);
672	}
673
674	{ /* Ignore any unsolicited replies so we don't get further confused */
675	    running_proxy *proxy = ProxyForPMconn(pmConn);
676
677	    if (!proxy || !proxy->requests)
678	    {
679		if (verbose)
680		    fprintf (stderr, "Received unsolicited GetProxyAddrReply from proxy %d; ignoring it.\n",
681			     IceConnectionNumber(iceConn));
682
683		IceDisposeCompleteMessage (iceConn, pStart);
684		break;
685	    }
686	}
687
688	switch (pMsg->status) {
689
690	case PM_Success:
691	{
692	    /*
693	     * Now send the GetProxyAddr reply to xfindproxy.
694	     */
695
696	    SendGetProxyAddrReply (
697		PopRequestorQueue (pmConn, True, True /* free proxy list */),
698		PM_Success /* status */, addr, NULL);
699
700	    break;
701	}
702
703	case PM_Unable:
704	{
705	    running_proxy_list *proxyList;
706	    char *serviceName, *serverAddress, *hostAddress, *startOptions;
707	    PMconn *requestor;
708	    int authLen;
709	    char *authName;
710	    char *authData;
711
712	    {
713		running_proxy *proxy = ProxyForPMconn(pmConn);
714		if (proxy)
715		    proxy->refused_service = True;
716		else
717		    fputs("Internal error: received GetProxyAddrReply from an unknown proxy\n", stderr);
718	    }
719
720	    if (! PeekRequestorQueue (pmConn, &requestor,
721				      &proxyList, &serviceName, &serverAddress,
722				      &hostAddress, &startOptions,
723				      &authLen, &authName, &authData)) {
724		if (verbose)
725		    fputs("Received GetProxyAddrReply from a proxy with no requests\n", stderr);
726
727		proxyList = NULL;
728		serviceName = "?unknown service--internal error";
729	    }
730
731	    if (proxyList && (proxyList->current < proxyList->count - 1))
732	    {
733		/*
734		 * Ask the next running proxy if it can service this request.
735		 */
736		running_proxy *nextProxy;
737
738		proxyList->current++;
739		nextProxy = proxyList->list[proxyList->current];
740
741		if (nextProxy->pmConn != NULL) {
742		    /* send only if the proxy has started */
743		    SendGetProxyAddr (nextProxy->pmConn, serviceName,
744				      serverAddress, hostAddress, startOptions,
745				      authLen, authName, authData);
746		}
747
748		PushRequestorQueue (nextProxy, requestor, proxyList,
749	            serviceName, serverAddress, hostAddress, startOptions,
750		    authLen, authName, authData);
751
752		PopRequestorQueue (pmConn, False, False);
753	    }
754	    else
755	    {
756		/*
757		 * Start a new proxy.
758		 */
759
760		running_proxy *runningProxy = NULL;
761		char *startCommand;
762		char *proxyAddress;
763		Bool managed;
764
765		if (!GetConfig (configFile, serviceName, &managed,
766	            &startCommand, &proxyAddress))
767		{
768		    SendGetProxyAddrReply (requestor, PM_Failure,
769		        NULL, "Could not read proxy manager config file");
770		}
771		else
772		{
773		    runningProxy = StartNewProxy (serviceName, startCommand);
774
775		    if (runningProxy)
776		    {
777			PushRequestorQueue (runningProxy,
778			    requestor, proxyList,
779			    serviceName, serverAddress,
780			    hostAddress, startOptions,
781			    authLen, authName, authData);
782		    }
783		    else
784		    {
785			SendGetProxyAddrReply (pmConn, PM_Failure,
786		            NULL, "Can't start new proxy");
787		    }
788		}
789
790		free (startCommand);
791		free (proxyAddress);
792
793		PopRequestorQueue (pmConn, False,
794		    runningProxy ? False : True /* free proxy list */);
795	    }
796	    break;
797	}
798
799	default:
800	    if (verbose && pMsg->status != PM_Unable)
801		fprintf(stderr,
802			"Error: proxy returned unrecognized status: %d\n",
803			pMsg->status);
804	    /* FALLTHROUGH */
805
806	case PM_Failure:
807	    SendGetProxyAddrReply (
808		PopRequestorQueue (pmConn, True, True /* free proxy list */),
809		pMsg->status, NULL, error);
810	}
811
812	IceDisposeCompleteMessage (iceConn, pStart);
813
814	/* see if there was more work queued for this proxy */
815	{
816	    char *serviceName, *serverAddress, *hostAddress, *startOptions;
817	    int authLen;
818	    char *authName, *authData;
819
820	    if (PeekRequestorQueue(pmConn,
821				   NULL, NULL, &serviceName,
822				   &serverAddress, &hostAddress, &startOptions,
823				   &authLen, &authName, &authData)) {
824		SendGetProxyAddr(pmConn,
825				 serviceName, serverAddress,
826				 hostAddress, startOptions,
827				 authLen, authName, authData);
828	    }
829	}
830
831	free (addr);
832	free (error);
833
834	break;
835    }
836
837    case PM_Error:
838    {
839	iceErrorMsg *pMsg;
840	char *pStart;
841
842	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, PM_Error, length,
843			     sizeof(iceErrorMsg), IceFatalToProtocol);
844
845	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
846				iceErrorMsg, pMsg, pStart);
847
848	if (!IceValidIO (iceConn))
849	{
850	    IceDisposeCompleteMessage (iceConn, pStart);
851	    return;
852	}
853
854	if (swap)
855	{
856	    pMsg->errorClass = lswaps (pMsg->errorClass);
857	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
858	}
859
860	fprintf(stderr, "Received ICE Error: class=0x%x\n  offending minor opcode=%d, severity=%d, sequence=%d\n",
861		pMsg->errorClass, pMsg->offendingMinorOpcode, pMsg->severity,
862		(int)pMsg->offendingSequenceNum);
863
864	IceDisposeCompleteMessage (iceConn, pStart);
865
866	break;
867    }
868
869    default:
870    {
871	_IceErrorBadMinor (iceConn, pmConn->pmOpcode, opcode, IceCanContinue);
872	_IceReadSkip (iceConn, length << 3);
873	break;
874    }
875    }
876}
877
878void
879PMSetupProcessMessages(IceConn iceConn, IcePointer clientData, int opcode,
880		       unsigned long length, Bool swap,
881		       IceReplyWaitInfo *replyWait, Bool *replyReadyRet)
882
883{
884    assert (replyWait == NULL);
885
886    PMReplyProcessMessages (iceConn, clientData, opcode, length, swap);
887}
888
889
890void
891ForwardRequest(PMconn *requestor, char *serviceName, char *serverAddress,
892	       char *hostAddress, char *startOptions, int authLen,
893	       char *authName, char *authData)
894{
895    running_proxy_list	*proxyList;
896    running_proxy	*runningProxy = NULL;
897    int			pushRequest = 0;
898
899    if ((proxyList = GetRunningProxyList (
900	serviceName, serverAddress)) != NULL)
901    {
902	while (proxyList->current < proxyList->count) {
903	    runningProxy = proxyList->list[proxyList->current];
904
905	    if (runningProxy->pmConn != NULL) {
906		SendGetProxyAddr (runningProxy->pmConn, serviceName,
907				  serverAddress, hostAddress, NULL,
908				  authLen, authName, authData);
909		break;
910	    }
911	    proxyList->current++;
912	}
913
914	pushRequest = 1;
915    }
916    else
917    {
918	Bool managed;
919	char *startCommand;
920	char *proxyAddress;
921
922	if (!GetConfig (configFile, serviceName, &managed,
923	    &startCommand, &proxyAddress))
924	{
925	    SendGetProxyAddrReply (requestor, PM_Failure,
926		NULL, "Could not find requested service");
927	}
928	else
929	{
930	    if (managed)
931	    {
932		runningProxy = StartNewProxy (serviceName, startCommand);
933
934		if (runningProxy)
935		    pushRequest = 1;
936		else
937		{
938		    SendGetProxyAddrReply (requestor, PM_Failure,
939			NULL, "Can't start new proxy");
940		}
941	    }
942	    else
943	    {
944		/*
945		 * We have the unmanged proxy's address; now forward
946		 * the request to it.
947		 */
948
949		runningProxy = ConnectToProxy (PMOriginatorOpcode,
950					       serviceName, proxyAddress);
951
952		if (runningProxy) {
953		    SendGetProxyAddr (runningProxy->pmConn,
954				      serviceName, serverAddress,
955				      hostAddress, startOptions,
956				      authLen, authName, authData);
957		    pushRequest = 1;
958		}
959		else
960		{
961		    /* %%% We should reread the config file and look
962		     * for another proxy address before giving up.
963		     */
964		    SendGetProxyAddrReply (requestor, PM_Failure,
965			NULL, "Can't connect to proxy");
966		}
967	    }
968
969	    free (startCommand);
970	    free (proxyAddress);
971	}
972    }
973
974    if (pushRequest)
975    {
976	PushRequestorQueue (runningProxy, requestor, proxyList,
977	    serviceName, serverAddress, hostAddress, startOptions,
978	    authLen, authName, authData);
979    }
980}
981
982
983/* ARGSUSED */
984void
985_XtProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id)
986{
987    IceConn			ice_conn = (IceConn) client_data;
988    IceProcessMessagesStatus	status;
989
990    status = IceProcessMessages (ice_conn, NULL, NULL);
991
992    if (status == IceProcessMessagesIOError)
993    {
994	Bool activeReqs;
995
996	ProxyGone (ice_conn, &activeReqs);
997	IceSetShutdownNegotiation (ice_conn, False);
998	IceCloseConnection (ice_conn);
999    }
1000}
1001
1002
1003void
1004_XtIceWatchProc(IceConn ice_conn, IcePointer client_data,
1005		Bool opening, IcePointer *watch_data)
1006
1007{
1008    if (opening)
1009    {
1010	XtAppContext appContext = (XtAppContext) client_data;
1011
1012	*watch_data = (IcePointer) XtAppAddInput (
1013	    appContext,
1014	    IceConnectionNumber (ice_conn),
1015            (XtPointer) XtInputReadMask,
1016	    _XtProcessIceMsgProc,
1017	    (XtPointer) ice_conn);
1018    }
1019    else
1020    {
1021	XtRemoveInput ((XtInputId) *watch_data);
1022    }
1023}
1024
1025
1026Status
1027InitWatchProcs(XtAppContext appContext)
1028
1029{
1030    return (IceAddConnectionWatch (_XtIceWatchProc, (IcePointer) appContext));
1031}
1032
1033
1034/*
1035 * The real way to handle IO errors is to check the return status
1036 * of IceProcessMessages.  xsm properly does this.
1037 *
1038 * Unfortunately, a design flaw exists in the ICE library in which
1039 * a default IO error handler is invoked if no IO error handler is
1040 * installed.  This default handler exits.  We must avoid this.
1041 *
1042 * To get around this problem, we install an IO error handler that
1043 * does a little magic.  Since a previous IO handler might have been
1044 * installed, when we install our IO error handler, we do a little
1045 * trick to get both the previous IO error handler and the default
1046 * IO error handler.  When our IO error handler is called, if the
1047 * previous handler is not the default handler, we call it.  This
1048 * way, everyone's IO error handler gets called except the stupid
1049 * default one which does an exit!
1050 */
1051
1052static IceIOErrorHandler prev_handler;
1053
1054void
1055MyIoErrorHandler(IceConn ice_conn)
1056{
1057    if (prev_handler)
1058	(*prev_handler) (ice_conn);
1059}
1060
1061void
1062InstallIOErrorHandler(void)
1063{
1064    IceIOErrorHandler default_handler;
1065
1066    prev_handler = IceSetIOErrorHandler (NULL);
1067    default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
1068    if (prev_handler == default_handler)
1069	prev_handler = NULL;
1070}
1071
1072
1073/*
1074 * Since proxy manager does not authenticate connections, we disable
1075 * authentication by always returning true in the host based auth proc.
1076 */
1077
1078Bool
1079HostBasedAuthProc(char *hostname)
1080{
1081    return (1);
1082}
1083