main.c revision b3078add
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
63char *PM_VENDOR_STRING = XVENDORNAME;
64char *PM_VENDOR_RELEASE = XORG_RELEASE;
65
66int verbose = 0;
67
68static XtAppContext	appContext;
69
70#define PM_PORT "6500"
71
72static 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 = (char *) 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 = (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    char *addr,
359    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 = (char *) 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 = (char *) 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	if (serviceName)
543	    free (serviceName);
544	if (serverAddress)
545	    free (serverAddress);
546	if (hostAddress)
547	    free (hostAddress);
548	if (startOptions)
549	    free (startOptions);
550	if (authName)
551	    free (authName);
552	if (authData)
553	    free (authData);
554
555	break;
556    }
557
558    case PM_StartProxy:
559    {
560	pmStartProxyMsg *pMsg;
561	char 		*pData, *pStart;
562	char		*serviceName = NULL;
563	char		*serverAddress;
564	char		*hostAddress;
565	char		*startOptions;
566	int		authLen;
567	char		*authName;
568	char		*authData;
569
570#if 0 /* No-op */
571	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
572	    length, SIZEOF (pmStartProxyMsg), IceFatalToProtocol);
573#endif
574
575	IceReadCompleteMessage (iceConn, SIZEOF (pmStartProxyMsg),
576	    pmStartProxyMsg, pMsg, pStart);
577
578	if (!IceValidIO (iceConn))
579	{
580	    IceDisposeCompleteMessage (iceConn, pStart);
581	    return;
582	}
583
584	pData = pStart;
585
586	SKIP_STRING (pData, swap);	/* proxy-service */
587
588	CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
589	   length, pData - pStart + SIZEOF (pmStartProxyMsg),
590	   pStart, IceFatalToProtocol);
591
592	pData = pStart;
593
594	EXTRACT_STRING (pData, swap, serviceName);
595
596	assert(serviceName);
597
598	if (verbose)
599	    printf ("Got StartProxy on fd %d, serviceName = %s\n",
600		    IceConnectionNumber(iceConn), serviceName);
601
602	IceDisposeCompleteMessage (iceConn, pStart);
603
604	if (! ActivateProxyService (serviceName, pmConn)) {
605	    fputs ("Configuration error: received unexpected StartProxy for service ", stderr);
606	    fputs (serviceName, stderr);
607	    fputc ('\n', stderr);
608	    IceCloseConnection (iceConn);
609	}
610	else {
611
612	    /*
613	     * Now send the GetProxyAddr message to the proxy.
614	     */
615	    if (PeekRequestorQueue(pmConn,
616				   NULL, NULL, NULL,
617				   &serverAddress, &hostAddress, &startOptions,
618				   &authLen, &authName, &authData)) {
619		SendGetProxyAddr(pmConn,
620				 serviceName, serverAddress,
621				 hostAddress, startOptions,
622				 authLen, authName, authData);
623	    }
624	    else if (verbose) {
625		    fputs ("Received StartProxy for service ", stderr);
626		    fputs (serviceName, stderr);
627		    fputs (" but no waiting GetproxyAddr requests\n", stderr);
628	    }
629	}
630
631	free (serviceName);
632
633	break;
634    }
635
636    case PM_GetProxyAddrReply:
637
638    {
639	pmGetProxyAddrReplyMsg 	*pMsg;
640	char			*pData, *pStart;
641	char			*addr = NULL, *error = NULL;
642
643#if 0 /* No-op */
644	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
645	    length, SIZEOF (pmGetProxyAddrReplyMsg), IceFatalToProtocol);
646#endif
647
648	IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrReplyMsg),
649	    pmGetProxyAddrReplyMsg, pMsg, pStart);
650
651	if (!IceValidIO (iceConn))
652	{
653	    IceDisposeCompleteMessage (iceConn, pStart);
654	    return;
655	}
656
657	pData = pStart;
658
659	SKIP_STRING (pData, swap);		/* proxy-address */
660	SKIP_STRING (pData, swap);		/* failure-reason */
661
662	CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
663	    length, pData - pStart + SIZEOF (pmGetProxyAddrReplyMsg),
664	    pStart, IceFatalToProtocol);
665
666	pData = pStart;
667
668	EXTRACT_STRING (pData, swap, addr);
669	EXTRACT_STRING (pData, swap, error);
670
671	if (verbose) {
672	    printf ("Got GetProxyAddrReply from proxy %d, status = %d, ",
673		    IceConnectionNumber(iceConn), pMsg->status);
674	    if (pMsg->status == PM_Success)
675		printf ("addr = %s\n", addr);
676	    else
677		printf ("error = %s\n", error);
678	}
679
680	{ /* Ignore any unsolicited replies so we don't get further confused */
681	    running_proxy *proxy = ProxyForPMconn(pmConn);
682
683	    if (!proxy || !proxy->requests)
684	    {
685		if (verbose)
686		    fprintf (stderr, "Received unsolicited GetProxyAddrReply from proxy %d; ignoring it.\n",
687			     IceConnectionNumber(iceConn));
688
689		IceDisposeCompleteMessage (iceConn, pStart);
690		break;
691	    }
692	}
693
694	switch (pMsg->status) {
695
696	case PM_Success:
697	{
698	    /*
699	     * Now send the GetProxyAddr reply to xfindproxy.
700	     */
701
702	    SendGetProxyAddrReply (
703		PopRequestorQueue (pmConn, True, True /* free proxy list */),
704		PM_Success /* status */, addr, NULL);
705
706	    break;
707	}
708
709	case PM_Unable:
710	{
711	    running_proxy_list *proxyList;
712	    char *serviceName, *serverAddress, *hostAddress, *startOptions;
713	    PMconn *requestor;
714	    int authLen;
715	    char *authName;
716	    char *authData;
717
718	    {
719		running_proxy *proxy = ProxyForPMconn(pmConn);
720		if (proxy)
721		    proxy->refused_service = True;
722		else
723		    fputs("Internal error: received GetProxyAddrReply from an unknown proxy\n", stderr);
724	    }
725
726	    if (! PeekRequestorQueue (pmConn, &requestor,
727				      &proxyList, &serviceName, &serverAddress,
728				      &hostAddress, &startOptions,
729				      &authLen, &authName, &authData)) {
730		if (verbose)
731		    fputs("Received GetProxyAddrReply from a proxy with no requests\n", stderr);
732
733		proxyList = NULL;
734		serviceName = "?unknown service--internal error";
735	    }
736
737	    if (proxyList && (proxyList->current < proxyList->count - 1))
738	    {
739		/*
740		 * Ask the next running proxy if it can service this request.
741		 */
742		running_proxy *nextProxy;
743
744		proxyList->current++;
745		nextProxy = proxyList->list[proxyList->current];
746
747		if (nextProxy->pmConn != NULL) {
748		    /* send only if the proxy has started */
749		    SendGetProxyAddr (nextProxy->pmConn, serviceName,
750				      serverAddress, hostAddress, startOptions,
751				      authLen, authName, authData);
752		}
753
754		PushRequestorQueue (nextProxy, requestor, proxyList,
755	            serviceName, serverAddress, hostAddress, startOptions,
756		    authLen, authName, authData);
757
758		PopRequestorQueue (pmConn, False, False);
759	    }
760	    else
761	    {
762		/*
763		 * Start a new proxy.
764		 */
765
766		running_proxy *runningProxy = NULL;
767		char *startCommand;
768		char *proxyAddress;
769		Bool managed;
770
771		if (!GetConfig (configFile, serviceName, &managed,
772	            &startCommand, &proxyAddress))
773		{
774		    SendGetProxyAddrReply (requestor, PM_Failure,
775		        NULL, "Could not read proxy manager config file");
776		}
777		else
778		{
779		    runningProxy = StartNewProxy (serviceName, startCommand);
780
781		    if (runningProxy)
782		    {
783			PushRequestorQueue (runningProxy,
784			    requestor, proxyList,
785			    serviceName, serverAddress,
786			    hostAddress, startOptions,
787			    authLen, authName, authData);
788		    }
789		    else
790		    {
791			SendGetProxyAddrReply (pmConn, PM_Failure,
792		            NULL, "Can't start new proxy");
793		    }
794		}
795
796		if (startCommand)
797		    free (startCommand);
798		if (proxyAddress)
799		    free (proxyAddress);
800
801		PopRequestorQueue (pmConn, False,
802		    runningProxy ? False : True /* free proxy list */);
803	    }
804	    break;
805	}
806
807	default:
808	    if (verbose && pMsg->status != PM_Unable)
809		fprintf(stderr,
810			"Error: proxy returned unrecognized status: %d\n",
811			pMsg->status);
812	    /* FALLTHROUGH */
813
814	case PM_Failure:
815	    SendGetProxyAddrReply (
816		PopRequestorQueue (pmConn, True, True /* free proxy list */),
817		pMsg->status, NULL, error);
818	}
819
820	IceDisposeCompleteMessage (iceConn, pStart);
821
822	/* see if there was more work queued for this proxy */
823	{
824	    char *serviceName, *serverAddress, *hostAddress, *startOptions;
825	    int authLen;
826	    char *authName, *authData;
827
828	    if (PeekRequestorQueue(pmConn,
829				   NULL, NULL, &serviceName,
830				   &serverAddress, &hostAddress, &startOptions,
831				   &authLen, &authName, &authData)) {
832		SendGetProxyAddr(pmConn,
833				 serviceName, serverAddress,
834				 hostAddress, startOptions,
835				 authLen, authName, authData);
836	    }
837	}
838
839	if (addr)
840	    free (addr);
841	if (error)
842	    free (error);
843
844	break;
845    }
846
847    case PM_Error:
848    {
849	iceErrorMsg *pMsg;
850	char *pStart;
851
852	CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, PM_Error, length,
853			     sizeof(iceErrorMsg), IceFatalToProtocol);
854
855	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
856				iceErrorMsg, pMsg, pStart);
857
858	if (!IceValidIO (iceConn))
859	{
860	    IceDisposeCompleteMessage (iceConn, pStart);
861	    return;
862	}
863
864	if (swap)
865	{
866	    pMsg->errorClass = lswaps (pMsg->errorClass);
867	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
868	}
869
870	fprintf(stderr, "Received ICE Error: class=0x%x\n  offending minor opcode=%d, severity=%d, sequence=%d\n",
871		pMsg->errorClass, pMsg->offendingMinorOpcode, pMsg->severity,
872		(int)pMsg->offendingSequenceNum);
873
874	IceDisposeCompleteMessage (iceConn, pStart);
875
876	break;
877    }
878
879    default:
880    {
881	_IceErrorBadMinor (iceConn, pmConn->pmOpcode, opcode, IceCanContinue);
882	_IceReadSkip (iceConn, length << 3);
883	break;
884    }
885    }
886}
887
888void
889PMSetupProcessMessages(IceConn iceConn, IcePointer clientData, int opcode,
890		       unsigned long length, Bool swap,
891		       IceReplyWaitInfo *replyWait, Bool *replyReadyRet)
892
893{
894    assert (replyWait == NULL);
895
896    PMReplyProcessMessages (iceConn, clientData, opcode, length, swap);
897}
898
899
900void
901ForwardRequest(PMconn *requestor, char *serviceName, char *serverAddress,
902	       char *hostAddress, char *startOptions, int authLen,
903	       char *authName, char *authData)
904{
905    running_proxy_list	*proxyList;
906    running_proxy	*runningProxy = NULL;
907    int			pushRequest = 0;
908
909    if ((proxyList = GetRunningProxyList (
910	serviceName, serverAddress)) != NULL)
911    {
912	while (proxyList->current < proxyList->count) {
913	    runningProxy = proxyList->list[proxyList->current];
914
915	    if (runningProxy->pmConn != NULL) {
916		SendGetProxyAddr (runningProxy->pmConn, serviceName,
917				  serverAddress, hostAddress, NULL,
918				  authLen, authName, authData);
919		break;
920	    }
921	    proxyList->current++;
922	}
923
924	pushRequest = 1;
925    }
926    else
927    {
928	Bool managed;
929	char *startCommand;
930	char *proxyAddress;
931
932	if (!GetConfig (configFile, serviceName, &managed,
933	    &startCommand, &proxyAddress))
934	{
935	    SendGetProxyAddrReply (requestor, PM_Failure,
936		NULL, "Could not find requested service");
937	}
938	else
939	{
940	    if (managed)
941	    {
942		runningProxy = StartNewProxy (serviceName, startCommand);
943
944		if (runningProxy)
945		    pushRequest = 1;
946		else
947		{
948		    SendGetProxyAddrReply (requestor, PM_Failure,
949			NULL, "Can't start new proxy");
950		}
951	    }
952	    else
953	    {
954		/*
955		 * We have the unmanged proxy's address; now forward
956		 * the request to it.
957		 */
958
959		runningProxy = ConnectToProxy (PMOriginatorOpcode,
960					       serviceName, proxyAddress);
961
962		if (runningProxy) {
963		    SendGetProxyAddr (runningProxy->pmConn,
964				      serviceName, serverAddress,
965				      hostAddress, startOptions,
966				      authLen, authName, authData);
967		    pushRequest = 1;
968		}
969		else
970		{
971		    /* %%% We should reread the config file and look
972		     * for another proxy address before giving up.
973		     */
974		    SendGetProxyAddrReply (requestor, PM_Failure,
975			NULL, "Can't connect to proxy");
976		}
977	    }
978
979	    if (startCommand)
980		free (startCommand);
981	    if (proxyAddress)
982		free (proxyAddress);
983	}
984    }
985
986    if (pushRequest)
987    {
988	PushRequestorQueue (runningProxy, requestor, proxyList,
989	    serviceName, serverAddress, hostAddress, startOptions,
990	    authLen, authName, authData);
991    }
992}
993
994
995/* ARGSUSED */
996void
997_XtProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id)
998{
999    IceConn			ice_conn = (IceConn) client_data;
1000    IceProcessMessagesStatus	status;
1001
1002    status = IceProcessMessages (ice_conn, NULL, NULL);
1003
1004    if (status == IceProcessMessagesIOError)
1005    {
1006	Bool activeReqs;
1007
1008	ProxyGone (ice_conn, &activeReqs);
1009	IceSetShutdownNegotiation (ice_conn, False);
1010	IceCloseConnection (ice_conn);
1011    }
1012}
1013
1014
1015void
1016_XtIceWatchProc(IceConn ice_conn, IcePointer client_data,
1017		Bool opening, IcePointer *watch_data)
1018
1019{
1020    if (opening)
1021    {
1022	XtAppContext appContext = (XtAppContext) client_data;
1023
1024	*watch_data = (IcePointer) XtAppAddInput (
1025	    appContext,
1026	    IceConnectionNumber (ice_conn),
1027            (XtPointer) XtInputReadMask,
1028	    _XtProcessIceMsgProc,
1029	    (XtPointer) ice_conn);
1030    }
1031    else
1032    {
1033	XtRemoveInput ((XtInputId) *watch_data);
1034    }
1035}
1036
1037
1038Status
1039InitWatchProcs(XtAppContext appContext)
1040
1041{
1042    return (IceAddConnectionWatch (_XtIceWatchProc, (IcePointer) appContext));
1043}
1044
1045
1046/*
1047 * The real way to handle IO errors is to check the return status
1048 * of IceProcessMessages.  xsm properly does this.
1049 *
1050 * Unfortunately, a design flaw exists in the ICE library in which
1051 * a default IO error handler is invoked if no IO error handler is
1052 * installed.  This default handler exits.  We must avoid this.
1053 *
1054 * To get around this problem, we install an IO error handler that
1055 * does a little magic.  Since a previous IO handler might have been
1056 * installed, when we install our IO error handler, we do a little
1057 * trick to get both the previous IO error handler and the default
1058 * IO error handler.  When our IO error handler is called, if the
1059 * previous handler is not the default handler, we call it.  This
1060 * way, everyone's IO error handler gets called except the stupid
1061 * default one which does an exit!
1062 */
1063
1064static IceIOErrorHandler prev_handler;
1065
1066void
1067MyIoErrorHandler(IceConn ice_conn)
1068{
1069    if (prev_handler)
1070	(*prev_handler) (ice_conn);
1071}
1072
1073void
1074InstallIOErrorHandler(void)
1075{
1076    IceIOErrorHandler default_handler;
1077
1078    prev_handler = IceSetIOErrorHandler (NULL);
1079    default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
1080    if (prev_handler == default_handler)
1081	prev_handler = NULL;
1082}
1083
1084
1085/*
1086 * Since proxy manager does not authenticate connections, we disable
1087 * authentication by always returning true in the host based auth proc.
1088 */
1089
1090Bool
1091HostBasedAuthProc(char *hostname)
1092{
1093    return (1);
1094}
1095