1/* $Xorg: xfindproxy.c,v 1.4 2001/02/09 02:05:42 xorgcvs Exp $ */
2
3/*
4Copyright 1996, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included
13in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall
24not be used in advertising or otherwise to promote the sale, use or
25other dealings in this Software without prior written authorization
26from The Open Group.
27*/
28/* $XFree86: xc/programs/xfindproxy/xfindproxy.c,v 1.8tsi Exp $ */
29
30#ifdef HAVE_CONFIG_H
31# include "config.h"
32#endif
33
34#include <stdio.h>
35#include <X11/Xos.h>
36#include <X11/Xfuncs.h>
37#include <X11/Xmd.h>
38#include <X11/StringDefs.h>
39#include <X11/Intrinsic.h>
40#include <X11/ICE/ICElib.h>
41#include <X11/ICE/ICEmsg.h>
42#include <X11/ICE/ICEproto.h>
43#include <X11/PM/PM.h>
44#include <X11/PM/PMproto.h>
45#include "xfindproxy.h"
46
47#include <stdlib.h>
48#include <ctype.h>
49
50static void PMprocessMessages(IceConn iceConn, IcePointer clientData,
51			      int opcode, unsigned long length, Bool swap,
52			      IceReplyWaitInfo *replyWait,
53			      Bool *replyReadyRet);
54static void _XtProcessIceMsgProc(XtPointer client_data, int *source,
55				 XtInputId *id);
56static void _XtIceWatchProc(IceConn ice_conn, IcePointer client_data,
57			    Bool opening, IcePointer *watch_data);
58static Status InitWatchProcs(XtAppContext appContext);
59
60static int PMopcode;
61
62static int PMversionCount = 1;
63static IcePoVersionRec PMversions[] =
64                {{PM_MAJOR_VERSION, PM_MINOR_VERSION, PMprocessMessages}};
65
66typedef struct {
67    int		status;
68    char	*addr;
69    char	*error;
70} GetProxyAddrReply;
71
72
73static int
74cvthexkey(const char *hexstr, char **ptrp) /* turn hex key string into octets */
75{
76    unsigned int i;
77    unsigned int len = 0;
78    char *retval;
79    const char *s;
80    unsigned char *us;
81    char c;
82    char savec = '\0';
83
84    /* count */
85    for (s = hexstr; *s; s++) {
86	if (!isascii(*s)) return -1;
87	if (isspace(*s)) continue;
88	if (!isxdigit(*s)) return -1;
89	len++;
90    }
91
92    /* if odd then there was an error */
93    if ((len & 1) == 1) return -1;
94
95
96    /* now we know that the input is good */
97    len >>= 1;
98    retval = malloc (len);
99    if (!retval)
100	return -1;
101
102    for (us = (unsigned char *) retval, i = len; i > 0; hexstr++) {
103	c = *hexstr;
104	if (isspace(c)) continue;	 /* already know it is ascii */
105	if (isupper(c))
106	    c = (char) tolower(c);
107	if (savec) {
108#define atoh(c) ((c) - (((c) >= '0' && (c) <= '9') ? '0' : ('a'-10)))
109	    *us = (unsigned char)((atoh(savec) << 4) + atoh(c));
110#undef atoh
111	    savec = 0;		/* ready for next character */
112	    us++;
113	    i--;
114	} else {
115	    savec = c;
116	}
117    }
118    *ptrp = retval;
119    return (int) len;
120}
121
122static void _X_NORETURN
123usage (void)
124{
125    fprintf (stderr,
126	     "usage: xfindproxy -server serverAddr -name serviceName"
127	     " [-manager managerAddr]\n"
128	     "                  [-auth] [-host hostAddr] [-options opts]\n"
129	     "-manager can be omitted only if PROXY_MANAGER is in the environment\n"
130	     "       xfindproxy -version\n");
131    exit (1);
132}
133
134
135int
136main(int argc, char *argv[])
137{
138    static XtAppContext 	appContext;
139    IceConn			iceConn;
140    IceProtocolSetupStatus	setupstat;
141    char			*vendor = NULL;
142    char			*release = NULL;
143    pmGetProxyAddrMsg		*pMsg;
144    char 			*pData;
145    int				i;
146    size_t			len;
147    IceReplyWaitInfo		replyWait;
148    GetProxyAddrReply		reply;
149    int				majorVersion, minorVersion;
150    Bool			gotReply, ioErrorOccured;
151    char			errorString[255];
152    char			*serviceName = NULL, *serverAddress = NULL;
153    char			*hostAddress = NULL, *startOptions = NULL;
154    char			*managerAddress = NULL;
155    Bool			haveAuth = 0;
156    char			authName[40];
157    char			authData[128];
158    char			*authDataBinary = NULL;
159    int				authLen = 0;
160
161    for (i = 1; i < argc; i++)
162    {
163	if (argv[i][0] == '-')
164	{
165	    switch (argv[i][1])
166	    {
167	    case 'a':					/* -auth */
168		haveAuth = 1;
169		continue;
170
171	    case 'm':					/* -manager */
172		if (++i >= argc) goto usage;
173		managerAddress = (char *) XtNewString (argv[i]);
174		continue;
175
176	    case 's':					/* -server */
177		if (++i >= argc) goto usage;
178		serverAddress = (char *) XtNewString (argv[i]);
179		continue;
180
181	    case 'n':					/* -name */
182		if (++i >= argc) goto usage;
183		serviceName = XtNewString (argv[i]);
184		continue;
185
186	    case 'h':					/* -host */
187		if (++i >= argc) goto usage;
188		hostAddress = XtNewString (argv[i]);
189		continue;
190
191	    case 'o':					/* -options */
192		if (++i >= argc) goto usage;
193		startOptions = XtNewString (argv[i]);
194		continue;
195
196	    case 'v':
197		puts(PACKAGE_STRING);
198		exit(0);
199	    }
200	}
201
202    usage:
203	if (i >= argc)
204	    fprintf (stderr, "%s: %s requires an argument\n",
205		     argv[0], argv[i-1]);
206	else
207	    fprintf (stderr, "%s: unrecognized argument '%s'\n",
208		     argv[0], argv[i]);
209	usage();
210    }
211
212    if (serviceName == NULL) {
213	fprintf (stderr, "%s: -name serviceName must be specified\n", argv[0]);
214	usage();
215    }
216    if (serverAddress == NULL) {
217	fprintf (stderr, "%s: -server serverAddr must be specified\n", argv[0]);
218	usage();
219    }
220
221    if (managerAddress == NULL) {
222	managerAddress = getenv("PROXY_MANAGER");
223	if (managerAddress == NULL) {
224	    fprintf (stderr, "Error: -manager option must be specified when PROXY_MANAGER is not in the environment\n");
225	    exit (1);
226	}
227    }
228
229    /*
230     * Register support for PROXY_MANAGEMENT.
231     */
232
233    if ((PMopcode = IceRegisterForProtocolSetup (
234	PM_PROTOCOL_NAME,
235	"XC", "1.0",
236	PMversionCount, PMversions,
237	0, /* authcount */
238	NULL, /* authnames */
239        NULL, /* authprocs */
240	NULL  /* IceIOErrorProc */ )) < 0)
241    {
242	fprintf (stderr,
243	    "Could not register PROXY_MANAGEMENT protocol with ICE");
244	exit (1);
245    }
246
247
248    appContext = XtCreateApplicationContext ();
249
250    InitWatchProcs (appContext);
251
252    if ((iceConn = IceOpenConnection (
253	managerAddress, NULL, 0, 0, 256, errorString)) == NULL)
254    {
255	fprintf (stderr,
256	    "Could not open ICE connection to proxy manager: %s", errorString);
257	exit (1);
258    }
259
260    setupstat = IceProtocolSetup (iceConn, PMopcode, NULL,
261	False /* mustAuthenticate */,
262	&majorVersion, &minorVersion,
263	&vendor, &release, 256, errorString);
264
265    if (setupstat != IceProtocolSetupSuccess)
266    {
267	IceCloseConnection (iceConn);
268	fprintf (stderr,
269	    "Could not initialize proxy management protocol: %s\n",
270	    errorString);
271	exit (1);
272    }
273
274
275    /*
276     * If auth data is supplied, read it from stdin.
277     */
278
279    if (haveAuth)
280    {
281	fgets (authName, sizeof (authName), stdin);
282	fgets (authData, sizeof (authData), stdin);
283
284	for (i = 0; i < strlen (authName); i++)
285	    if (authName[i] == '\n')
286	    {
287		authName[i] = '\0';
288		break;
289	    }
290	for (i = 0; i < strlen (authData); i++)
291	    if (authData[i] == '\n')
292	    {
293		authData[i] = '\0';
294		break;
295	    }
296
297	/*
298	 * Convert the hex auth data to binary.
299	 */
300
301	authLen = cvthexkey (authData, &authDataBinary);
302
303	if (authLen == -1)
304	{
305	    fprintf (stderr, "Could not convert hex auth data to binary\n");
306	    exit (1);
307	}
308    }
309
310
311    /*
312     * Now send the GetProxyAddr request.
313     */
314
315    len = STRING_BYTES (serviceName) +
316	  STRING_BYTES (serverAddress) +
317	  STRING_BYTES (hostAddress) +
318	  STRING_BYTES (startOptions) +
319	  (authLen > 0 ? (STRING_BYTES (authName) + authLen) : 0);
320
321    IceGetHeaderExtra (iceConn, PMopcode, PM_GetProxyAddr,
322	SIZEOF (pmGetProxyAddrMsg), WORD64COUNT (len),
323	pmGetProxyAddrMsg, pMsg, pData);
324
325    pMsg->authLen = (CARD16) authLen;
326
327    STORE_STRING (pData, serviceName);
328    STORE_STRING (pData, serverAddress);
329    STORE_STRING (pData, hostAddress);
330    STORE_STRING (pData, startOptions);
331    if (authLen > 0)
332    {
333	STORE_STRING (pData, authName);
334	memcpy (pData, authDataBinary, authLen);
335    }
336
337    IceFlush (iceConn);
338
339    replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn);
340    replyWait.major_opcode_of_request = PMopcode;
341    replyWait.minor_opcode_of_request = PM_GetProxyAddr;
342    replyWait.reply = (IcePointer) &reply;
343
344    gotReply = False;
345    ioErrorOccured = False;
346
347    while (!gotReply && !ioErrorOccured)
348    {
349	ioErrorOccured = (IceProcessMessages (
350	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
351
352	if (ioErrorOccured)
353	{
354	    fprintf (stderr, "IO error occured\n");
355	    exit (1);
356	}
357	else if (gotReply)
358	{
359	    if (reply.status == PM_Success)
360	    {
361		fprintf (stdout, "%s\n", reply.addr);
362		exit (0);
363	    }
364	    else
365	    {
366		fprintf (stderr, "Error from proxy manager: %s\n",
367		    reply.error);
368		exit (1);
369	    }
370	}
371    }
372    /*NOTREACHED*/
373    exit(0);
374}
375
376
377
378static void
379PMprocessMessages(IceConn iceConn, IcePointer clientData, int opcode,
380		  unsigned long length, Bool swap,
381		  IceReplyWaitInfo *replyWait, Bool *replyReadyRet)
382{
383    if (replyWait)
384	*replyReadyRet = False;
385
386    switch (opcode)
387    {
388    case PM_GetProxyAddrReply:
389
390	if (!replyWait ||
391	    replyWait->minor_opcode_of_request != PM_GetProxyAddr)
392	{
393	    _IceReadSkip (iceConn, length << 3);
394
395	    _IceErrorBadState (iceConn, PMopcode,
396		PM_GetProxyAddrReply, IceFatalToProtocol);
397	}
398        else
399	{
400	    pmGetProxyAddrReplyMsg 	*pMsg;
401	    char			*pData, *pStart;
402	    GetProxyAddrReply 	*reply =
403		(GetProxyAddrReply *) (replyWait->reply);
404
405#if 0 /* No-op */
406	    CHECK_AT_LEAST_SIZE (iceConn, PMopcode, opcode,
407		length, SIZEOF (pmGetProxyAddrReplyMsg), IceFatalToProtocol);
408#endif
409
410	    IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrReplyMsg),
411		pmGetProxyAddrReplyMsg, pMsg, pStart);
412
413	    if (!IceValidIO (iceConn))
414	    {
415		IceDisposeCompleteMessage (iceConn, pStart);
416		return;
417	    }
418
419	    pData = pStart;
420
421	    SKIP_STRING (pData, swap);		/* proxy-address */
422	    SKIP_STRING (pData, swap);		/* failure-reason */
423
424	    CHECK_COMPLETE_SIZE (iceConn, PMopcode, opcode,
425		length, pData - pStart + SIZEOF (pmGetProxyAddrReplyMsg),
426		pStart, IceFatalToProtocol);
427
428	    pData = pStart;
429
430	    EXTRACT_STRING (pData, swap, reply->addr);
431	    EXTRACT_STRING (pData, swap, reply->error);
432
433	    reply->status = pMsg->status;
434	    *replyReadyRet = True;
435
436	    IceDisposeCompleteMessage (iceConn, pStart);
437	}
438	break;
439
440    default:
441    {
442	_IceErrorBadMinor (iceConn, PMopcode, opcode, IceCanContinue);
443	_IceReadSkip (iceConn, length << 3);
444	break;
445    }
446    }
447}
448
449
450static void
451_XtProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id)
452{
453    IceConn			ice_conn = (IceConn) client_data;
454    IceProcessMessagesStatus	status;
455
456    status = IceProcessMessages (ice_conn, NULL, NULL);
457
458    if (status == IceProcessMessagesIOError)
459    {
460	fprintf (stderr, "IO error occured\n");
461	exit (1);
462    }
463}
464
465
466static void
467_XtIceWatchProc(IceConn ice_conn, IcePointer client_data,
468		Bool opening, IcePointer *watch_data)
469{
470    if (opening)
471    {
472	XtAppContext appContext = (XtAppContext) client_data;
473
474	*watch_data = (IcePointer) XtAppAddInput (
475	    appContext,
476	    IceConnectionNumber (ice_conn),
477            (XtPointer) XtInputReadMask,
478	    _XtProcessIceMsgProc,
479	    (XtPointer) ice_conn);
480    }
481    else
482    {
483	XtRemoveInput ((XtInputId) *watch_data);
484    }
485}
486
487
488static Status
489InitWatchProcs(XtAppContext appContext)
490{
491    return (IceAddConnectionWatch (_XtIceWatchProc, (IcePointer) appContext));
492}
493