1 /*
2  *
3 Copyright 1990, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24  *
25  * Author:  Keith Packard, MIT X Consortium
26  */
27 
28 
29 /*
30  * Chooser - display a menu of names and let the user select one
31  */
32 
33 /*
34  * Layout:
35  *
36  *  +--------------------------------------------------+
37  *  |             +------------------+                 |
38  *  |             |      Label       |                 |
39  *  |             +------------------+                 |
40  *  |    +-+--------------+                            |
41  *  |    |^| name-1       |                            |
42  *  |    ||| name-2       |                            |
43  *  |    |v| name-3       |                            |
44  *  |    | | name-4       |                            |
45  *  |    | | name-5       |                            |
46  *  |    | | name-6       |                            |
47  *  |    +----------------+                            |
48  *  |    cancel  accept  ping                          |
49  *  +--------------------------------------------------+
50  */
51 
52 #include    <X11/Intrinsic.h>
53 #include    <X11/StringDefs.h>
54 #include    <X11/Xatom.h>
55 
56 #include    <X11/Xaw/Paned.h>
57 #include    <X11/Xaw/Label.h>
58 #include    <X11/Xaw/Viewport.h>
59 #include    <X11/Xaw/List.h>
60 #include    <X11/Xaw/Box.h>
61 #include    <X11/Xaw/Command.h>
62 
63 #include    "dm.h"
64 
65 #include    <X11/Xdmcp.h>
66 
67 #include    <sys/types.h>
68 #include    <stdio.h>
69 #include    <ctype.h>
70 
71 #ifdef USE_XINERAMA
72 # include    <X11/extensions/Xinerama.h>
73 #endif
74 
75 #if defined(SVR4)
76 # include    <sys/sockio.h>
77 #endif
78 #if defined(SVR4) && defined(PowerMAX_OS)
79 # include    <sys/stropts.h>
80 #endif
81 #if defined(SYSV) && defined(i386)
82 # include    <sys/stream.h>
83 #endif
84 
85 #include    "dm_socket.h"
86 
87 #include    <arpa/inet.h>
88 
89 #include    <sys/ioctl.h>
90 
91 #ifdef HAVE_SYS_PARAM_H
92 # include <sys/param.h>
93 # ifdef BSD
94 #  if (BSD >= 199103)
95 #   define VARIABLE_IFREQ
96 #  endif
97 # endif
98 #endif
99 
100 #ifdef XKB
101 # include <X11/extensions/XKBbells.h>
102 #endif
103 
104 #define BROADCAST_HOSTNAME  "BROADCAST"
105 
106 #ifndef ishexdigit
107 # define ishexdigit(c)	(isdigit(c) || ('a' <= (c) && (c) <= 'f'))
108 #endif
109 
110 #ifdef hpux
111 # include <sys/utsname.h>
112 # ifdef HAS_IFREQ
113 #  include <net/if.h>
114 # endif
115 #else
116 # ifdef __convex__
117 #  include <sync/queue.h>
118 #  include <sync/sema.h>
119 # endif
120 # include <net/if.h>
121 #endif /* hpux */
122 
123 #include    <netdb.h>
124 #include    <X11/keysym.h>
125 
126 static int FromHex (char *s, char *d, int len);
127 static int oldline;
128 
129 static Widget	    toplevel, label, viewport, paned, list, box, cancel, acceptit, ping;
130 
131 static void	CvtStringToARRAY8(
132     XrmValuePtr	args,
133     Cardinal	*num_args,
134     XrmValuePtr	fromVal,
135     XrmValuePtr	toVal);
136 
137 static struct _app_resources {
138     ARRAY8Ptr   xdmAddress;
139     ARRAY8Ptr	clientAddress;
140     int		connectionType;
141 } app_resources;
142 
143 #define offset(field) XtOffsetOf(struct _app_resources, field)
144 
145 #define XtRARRAY8   "ARRAY8"
146 
147 static XtResource  resources[] = {
148     {"xdmAddress",	"XdmAddress",  XtRARRAY8,	sizeof (ARRAY8Ptr),
149 	offset (xdmAddress),	    XtRString,	NULL },
150     {"clientAddress",	"ClientAddress",  XtRARRAY8,	sizeof (ARRAY8Ptr),
151 	offset (clientAddress),	    XtRString,	NULL },
152     {"connectionType",	"ConnectionType",   XtRInt,	sizeof (int),
153 	offset (connectionType),    XtRImmediate,	(XtPointer) 0 }
154 };
155 #undef offset
156 
157 static XrmOptionDescRec options[] = {
158     { "-xdmaddress",	"*xdmAddress",	    XrmoptionSepArg,	NULL },
159     { "-clientaddress",	"*clientAddress",   XrmoptionSepArg,	NULL },
160     { "-connectionType","*connectionType",  XrmoptionSepArg,	NULL },
161 };
162 
163 typedef struct _hostAddr {
164     struct _hostAddr	*next;
165     struct sockaddr	*addr;
166     int			addrlen;
167     xdmOpCode		type;
168 } HostAddr;
169 
170 static HostAddr    *hostAddrdb;
171 
172 typedef struct _hostName {
173     struct _hostName	*next;
174     char		*fullname;
175     int			willing;
176     ARRAY8		hostname, status;
177     CARD16		connectionType;
178     ARRAY8		hostaddr;
179 } HostName;
180 
181 static HostName    *hostNamedb;
182 
183 static int  socketFD;
184 #if defined(IPv6) && defined(AF_INET6)
185 static int  socket6FD;
186 #endif
187 
188 static int  pingTry;
189 
190 #define PING_INTERVAL	2000
191 #define TRIES		3
192 
193 static XdmcpBuffer	directBuffer, broadcastBuffer;
194 static XdmcpBuffer	buffer;
195 
196 #if (defined(SVR4) && !defined(sun) && !defined(__sgi) && !defined(NCR)) && defined(SIOCGIFCONF)
197 
198 /* Deal with different SIOCGIFCONF ioctl semantics on these OSs */
199 
200 static int
ifioctl(int fd,int cmd,char * arg)201 ifioctl (int fd, int cmd, char *arg)
202 {
203     struct strioctl ioc;
204     int ret;
205 
206     bzero((char *) &ioc, sizeof(ioc));
207     ioc.ic_cmd = cmd;
208     ioc.ic_timout = 0;
209     if (cmd == SIOCGIFCONF)
210     {
211 	ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
212 	ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
213     }
214     else
215     {
216 	ioc.ic_len = sizeof(struct ifreq);
217 	ioc.ic_dp = arg;
218     }
219     ret = ioctl(fd, I_STR, (char *) &ioc);
220     if (ret >= 0 && cmd == SIOCGIFCONF)
221 	((struct ifconf *) arg)->ifc_len = ioc.ic_len;
222     return(ret);
223 }
224 #else /* (SVR4 && !sun && !NCR) && SIOCGIFCONF */
225 # define ifioctl ioctl
226 #endif /* (SVR4 && !sun && !NCR) && SIOCGIFCONF */
227 
228 
229 /* ARGSUSED */
230 static void
PingHosts(XtPointer closure,XtIntervalId * id)231 PingHosts (XtPointer closure, XtIntervalId *id)
232 {
233     HostAddr	*hosts;
234     int		 sfd = socketFD;
235 
236     for (hosts = hostAddrdb; hosts; hosts = hosts->next)
237     {
238 #if defined(IPv6) && defined(AF_INET6)
239 	if ( ((struct sockaddr *) hosts->addr)->sa_family == AF_INET6 )
240 	    sfd = socket6FD;
241 	else
242 	    sfd = socketFD;
243 #endif
244 	if (hosts->type == QUERY)
245 	    XdmcpFlush (sfd, &directBuffer,
246 			(XdmcpNetaddr) hosts->addr, hosts->addrlen);
247 	else
248 	    XdmcpFlush (sfd, &broadcastBuffer,
249 			(XdmcpNetaddr) hosts->addr, hosts->addrlen);
250     }
251     if (++pingTry < TRIES)
252 	XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0);
253 }
254 
255 char	**NameTable;
256 int	NameTableSize;
257 
258 static int
HostnameCompare(const void * a,const void * b)259 HostnameCompare (const void *a, const void *b)
260 {
261     return strcmp (*(char **)a, *(char **)b);
262 }
263 
264 static void
RebuildTable(int size)265 RebuildTable (int size)
266 {
267     char	**newTable = NULL;
268     HostName	*names;
269     int		i;
270 
271     if (size)
272     {
273 	newTable = malloc (size * sizeof (char *));
274 	if (!newTable)
275 	    return;
276 	for (names = hostNamedb, i = 0; names; names = names->next, i++)
277 	    newTable[i] = names->fullname;
278 	qsort (newTable, size, sizeof (char *), HostnameCompare);
279     }
280     XawListChange (list, newTable, size, 0, TRUE);
281     free (NameTable);
282     NameTable = newTable;
283     NameTableSize = size;
284 }
285 
286 static int
AddHostname(ARRAY8Ptr hostname,ARRAY8Ptr status,struct sockaddr * addr,int willing)287 AddHostname (ARRAY8Ptr hostname, ARRAY8Ptr status, struct sockaddr *addr, int willing)
288 {
289     HostName	*new, **names, *name;
290     ARRAY8	hostAddr = {0, NULL};
291     CARD16	connectionType;
292     int		fulllen;
293 
294     switch (addr->sa_family)
295     {
296     case AF_INET:
297 	hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr;
298 	hostAddr.length = 4;
299 	connectionType = FamilyInternet;
300 	break;
301 #if defined(IPv6) && defined(AF_INET6)
302     case AF_INET6:
303 	hostAddr.data = (CARD8 *) &((struct sockaddr_in6 *) addr)->sin6_addr;
304 	hostAddr.length = 16;
305 	connectionType = FamilyInternet6;
306 	break;
307 #endif
308     default:
309 	hostAddr.data = (CARD8 *) "";
310 	hostAddr.length = 0;
311 	connectionType = FamilyLocal;
312 	break;
313     }
314     for (names = &hostNamedb; *names; names = & (*names)->next)
315     {
316 	name = *names;
317 	if (connectionType == name->connectionType &&
318 	    XdmcpARRAY8Equal (&hostAddr, &name->hostaddr))
319 	{
320 	    if (XdmcpARRAY8Equal (status, &name->status))
321 	    {
322 		return 0;
323 	    }
324 	    break;
325 	}
326     }
327     if (!*names)
328     {
329 	new = malloc (sizeof (HostName));
330 	if (!new)
331 	    return 0;
332 	if (hostname->length)
333 	{
334 	    switch (addr->sa_family)
335 	    {
336 	    case AF_INET:
337 #if defined(IPv6) && defined(AF_INET6)
338 	    case AF_INET6:
339 #endif
340 		{
341 		    struct hostent  *hostent;
342 		    char	    *host;
343 
344 		    hostent = gethostbyaddr ((char *)hostAddr.data, hostAddr.length, addr->sa_family);
345 		    if (hostent)
346 		    {
347 			XdmcpDisposeARRAY8 (hostname);
348 			host = (char *)hostent->h_name;
349 			XdmcpAllocARRAY8 (hostname, strlen (host));
350 			memmove( hostname->data, host, hostname->length);
351 		    }
352 		}
353 	    }
354 	}
355 	if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length))
356 	{
357 	    free (new->fullname);
358 	    free (new);
359 	    return 0;
360 	}
361 	memmove( new->hostaddr.data, hostAddr.data, hostAddr.length);
362 	new->connectionType = connectionType;
363 	new->hostname = *hostname;
364 
365 	*names = new;
366 	new->next = NULL;
367 	NameTableSize++;
368     }
369     else
370     {
371 	new = *names;
372 	free (new->fullname);
373 	XdmcpDisposeARRAY8 (&new->status);
374 	XdmcpDisposeARRAY8 (hostname);
375     }
376     new->willing = willing;
377     new->status = *status;
378 
379     hostname = &new->hostname;
380     fulllen = hostname->length;
381     if (fulllen < 30)
382 	fulllen = 30;
383     fulllen += status->length + 10;
384     new->fullname = malloc (fulllen);
385     if (!new->fullname)
386     {
387 	new->fullname = "Unknown";
388     }
389     else
390     {
391 	snprintf(new->fullname, fulllen, "%-30.*s %*.*s",
392 		 hostname->length, hostname->data,
393 		 status->length, status->length, status->data);
394     }
395     RebuildTable (NameTableSize);
396     return 1;
397 }
398 
399 static void
DisposeHostname(HostName * host)400 DisposeHostname (HostName *host)
401 {
402     XdmcpDisposeARRAY8 (&host->hostname);
403     XdmcpDisposeARRAY8 (&host->hostaddr);
404     XdmcpDisposeARRAY8 (&host->status);
405     free (host->fullname);
406     free (host);
407 }
408 
409 static void
EmptyHostnames(void)410 EmptyHostnames (void)
411 {
412     HostName	*hosts, *next;
413 
414     for (hosts = hostNamedb; hosts; hosts = next)
415     {
416 	next = hosts->next;
417 	DisposeHostname (hosts);
418     }
419     NameTableSize = 0;
420     hostNamedb = NULL;
421     RebuildTable (NameTableSize);
422 }
423 
424 /* ARGSUSED */
425 static void
ReceivePacket(XtPointer closure,int * source,XtInputId * id)426 ReceivePacket (XtPointer closure, int *source, XtInputId *id)
427 {
428     XdmcpHeader	    header;
429     ARRAY8	    authenticationName = {0, NULL};
430     ARRAY8	    hostname = {0, NULL};
431     ARRAY8	    status = {0, NULL};
432     int		    saveHostname = 0;
433 #if defined(IPv6) && defined(AF_INET6)
434     struct sockaddr_storage addr;
435 #else
436     struct sockaddr addr;
437 #endif
438     int		    addrlen;
439     int		    sfd = * (int *) closure;
440 
441     addrlen = sizeof (addr);
442     if (!XdmcpFill (sfd, &buffer, (XdmcpNetaddr) &addr, &addrlen))
443 	return;
444     if (!XdmcpReadHeader (&buffer, &header))
445 	return;
446     if (header.version != XDM_PROTOCOL_VERSION)
447 	return;
448     switch (header.opcode) {
449     case WILLING:
450 	if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
451 	    XdmcpReadARRAY8 (&buffer, &hostname) &&
452 	    XdmcpReadARRAY8 (&buffer, &status))
453 	{
454 	    if (header.length == 6 + authenticationName.length +
455 		hostname.length + status.length)
456 	    {
457 		if (AddHostname (&hostname, &status, (struct sockaddr *) &addr,
458 				 header.opcode == (int) WILLING))
459 		    saveHostname = 1;
460 	    }
461 	}
462 	XdmcpDisposeARRAY8 (&authenticationName);
463 	break;
464     case UNWILLING:
465 	if (XdmcpReadARRAY8 (&buffer, &hostname) &&
466 	    XdmcpReadARRAY8 (&buffer, &status))
467 	{
468 	    if (header.length == 4 + hostname.length + status.length)
469 	    {
470 		if (AddHostname (&hostname, &status, (struct sockaddr *) &addr,
471 				 header.opcode == (int) WILLING))
472 		    saveHostname = 1;
473 
474 	    }
475 	}
476 	break;
477     default:
478 	break;
479     }
480     if (!saveHostname)
481     {
482 	XdmcpDisposeARRAY8 (&hostname);
483 	XdmcpDisposeARRAY8 (&status);
484     }
485 }
486 
487 static void
RegisterHostaddr(struct sockaddr * addr,int len,xdmOpCode type)488 RegisterHostaddr (struct sockaddr *addr, int len, xdmOpCode type)
489 {
490     HostAddr		*host, **prev;
491 
492     host = malloc (sizeof (HostAddr));
493     if (!host)
494 	return;
495     host->addr = malloc (len);
496     if (!host->addr)
497     {
498 	free (host);
499 	return;
500     }
501     memmove( (char *) host->addr, (char *) addr, len);
502     host->addrlen = len;
503     host->type = type;
504     for (prev = &hostAddrdb; *prev; prev = &(*prev)->next)
505 	;
506     *prev = host;
507     host->next = NULL;
508 }
509 
510 /*
511  * Register the address for this host.
512  * Called with each of the names on the command line.
513  * The special name "BROADCAST" looks up all the broadcast
514  *  addresses on the local host.
515  */
516 
517 /* Handle variable length ifreq in BNR2 and later */
518 #ifdef VARIABLE_IFREQ
519 # define ifr_size(p) (sizeof (struct ifreq) + \
520 		     (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
521 		      p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
522 #else
523 # define ifr_size(p) (sizeof (struct ifreq))
524 #endif
525 
526 static void
RegisterHostname(char * name)527 RegisterHostname (char *name)
528 {
529 #if !defined(IPv6) || !defined(AF_INET6)
530     struct hostent	*hostent;
531 #endif
532     struct sockaddr_in	in_addr;
533     struct ifconf	ifc;
534     register struct ifreq *ifr;
535     struct sockaddr	broad_addr;
536     char		buf[2048], *cp, *cplim;
537 
538     if (!strcmp (name, BROADCAST_HOSTNAME))
539     {
540 	ifc.ifc_len = sizeof (buf);
541 	ifc.ifc_buf = buf;
542 	if (ifioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0)
543 	    return;
544 
545 	cplim = (char *) ifc.ifc_req + ifc.ifc_len;
546 
547 	for (cp = (char *) ifc.ifc_req; cp < cplim; cp += ifr_size (ifr))
548 	{
549 	    ifr = (struct ifreq *) cp;
550 	    if (ifr->ifr_addr.sa_family != AF_INET)
551 		continue;
552 
553 	    broad_addr = ifr->ifr_addr;
554 	    ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
555 		htonl (INADDR_BROADCAST);
556 #ifdef SIOCGIFBRDADDR
557 	    {
558 		struct ifreq    broad_req;
559 
560 		broad_req = *ifr;
561 		if (ifioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
562 		    (broad_req.ifr_flags & IFF_BROADCAST) &&
563 		    (broad_req.ifr_flags & IFF_UP)
564 		    )
565 		{
566 		    broad_req = *ifr;
567 		    if (ifioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1)
568 			broad_addr = broad_req.ifr_addr;
569 		    else
570 			continue;
571 		}
572 		else
573 		    continue;
574 	    }
575 #endif
576 	    in_addr = *((struct sockaddr_in *) &broad_addr);
577 	    in_addr.sin_port = htons (XDM_UDP_PORT);
578 #ifdef BSD44SOCKETS
579 	    in_addr.sin_len = sizeof(in_addr);
580 #endif
581 	    RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
582 			      BROADCAST_QUERY);
583 	}
584     }
585     else
586     {
587 	/* address as hex string, e.g., "12180022" (deprecated) */
588 	if (strlen(name) == 8 &&
589 	    FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0)
590 	{
591 	    in_addr.sin_family = AF_INET;
592 	    in_addr.sin_port = htons (XDM_UDP_PORT);
593 #ifdef BSD44SOCKETS
594 	    in_addr.sin_len = sizeof(in_addr);
595 #endif
596 	    RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
597 				QUERY);
598 	}
599 #if defined(IPv6) && defined(AF_INET6)
600 	else {
601 	    char sport[8];
602 	    struct addrinfo *ai, *nai, hints;
603 	    bzero(&hints,sizeof(hints));
604 	    hints.ai_socktype = SOCK_DGRAM;
605 	    snprintf(sport, sizeof(sport), "%d", XDM_UDP_PORT);
606 	    if (getaddrinfo(name, sport, &hints, &ai) == 0) {
607 		for (nai = ai ; nai != NULL ; nai = nai->ai_next) {
608 		    if ((nai->ai_family == AF_INET) ||
609 		        (nai->ai_family == AF_INET6)) {
610 			if (((nai->ai_family == AF_INET) &&
611 			  IN_MULTICAST(((struct sockaddr_in *) nai->ai_addr)
612 			    ->sin_addr.s_addr))
613 			  || ((nai->ai_family == AF_INET6) &&
614 			    IN6_IS_ADDR_MULTICAST(
615 				&((struct sockaddr_in6 *) nai->ai_addr)
616 				  ->sin6_addr)))
617 			{
618 			    RegisterHostaddr(nai->ai_addr, nai->ai_addrlen,
619 			      BROADCAST_QUERY);
620 			} else {
621 			    RegisterHostaddr(nai->ai_addr, nai->ai_addrlen,
622 			      QUERY);
623 			}
624 		    }
625 		}
626 		freeaddrinfo(ai);
627 	    }
628 	}
629 #else
630 	/* Per RFC 1123, check first for IP address in dotted-decimal form */
631 	else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1)
632 	    in_addr.sin_family = AF_INET;
633 	else
634 	{
635 	    hostent = gethostbyname (name);
636 	    if (!hostent)
637 		return;
638 	    if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
639 		return;
640 	    in_addr.sin_family = hostent->h_addrtype;
641 	    memmove( &in_addr.sin_addr, hostent->h_addr, 4);
642 	}
643 	in_addr.sin_port = htons (XDM_UDP_PORT);
644 # ifdef BSD44SOCKETS
645 	in_addr.sin_len = sizeof(in_addr);
646 # endif
647 	RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
648 			  QUERY);
649 #endif /* IPv6 */
650     }
651 }
652 
653 static ARRAYofARRAY8	AuthenticationNames;
654 
655 static int
InitXDMCP(char ** argv)656 InitXDMCP (char **argv)
657 {
658     int	soopts = 1;
659     XdmcpHeader	header;
660     int	i;
661 
662     header.version = XDM_PROTOCOL_VERSION;
663     header.opcode = (CARD16) BROADCAST_QUERY;
664     header.length = 1;
665     for (i = 0; i < (int)AuthenticationNames.length; i++)
666 	header.length += 2 + AuthenticationNames.data[i].length;
667     XdmcpWriteHeader (&broadcastBuffer, &header);
668     XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames);
669 
670     header.version = XDM_PROTOCOL_VERSION;
671     header.opcode = (CARD16) QUERY;
672     header.length = 1;
673     for (i = 0; i < (int)AuthenticationNames.length; i++)
674 	header.length += 2 + AuthenticationNames.data[i].length;
675     XdmcpWriteHeader (&directBuffer, &header);
676     XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames);
677     if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
678 	return 0;
679 #if defined(IPv6) && defined(AF_INET6)
680     socket6FD = socket (AF_INET6, SOCK_DGRAM, 0);
681 #endif
682 #ifdef SO_BROADCAST
683     soopts = 1;
684     if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0)
685 	perror ("setsockopt");
686 #endif
687 
688     XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket,
689 		(XtPointer) &socketFD);
690 #if defined(IPv6) && defined(AF_INET6)
691     if (socket6FD != -1)
692     XtAddInput (socket6FD, (XtPointer) XtInputReadMask, ReceivePacket,
693 		(XtPointer) &socket6FD);
694 #endif
695     while (*argv)
696     {
697 	RegisterHostname (*argv);
698 	++argv;
699     }
700     pingTry = 0;
701     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
702     return 1;
703 }
704 
705 static void
Choose(HostName * h)706 Choose (HostName *h)
707 {
708     if (app_resources.xdmAddress)
709     {
710 	struct sockaddr_in  in_addr;
711 #if defined(IPv6) && defined(AF_INET6)
712 	struct sockaddr_in6 in6_addr;
713 #endif
714 	struct sockaddr	*addr = NULL;
715 	int		family;
716 	int		len = 0;
717 	int		fd;
718 	char		buf[1024];
719 	XdmcpBuffer	buffer;
720 	char		*xdm;
721 
722 	xdm = (char *) app_resources.xdmAddress->data;
723 	family = (xdm[0] << 8) + xdm[1];
724 	switch (family) {
725 	case AF_INET:
726 #ifdef BSD44SOCKETS
727 	    in_addr.sin_len = sizeof(in_addr);
728 #endif
729 	    in_addr.sin_family = family;
730 	    memmove( &in_addr.sin_port, xdm + 2, 2);
731 	    memmove( &in_addr.sin_addr, xdm + 4, 4);
732 	    addr = (struct sockaddr *) &in_addr;
733 	    len = sizeof (in_addr);
734 	    break;
735 #if defined(IPv6) && defined(AF_INET6)
736 	case AF_INET6:
737 	    bzero(&in6_addr, sizeof(in6_addr));
738 # ifdef SIN6_LEN
739 	    in6_addr.sin6_len = sizeof(in6_addr);
740 # endif
741 	    in6_addr.sin6_family = family;
742 	    memmove( &in6_addr.sin6_port, xdm + 2, 2);
743 	    memmove( &in6_addr.sin6_addr, xdm + 4, 16);
744 	    addr = (struct sockaddr *) &in6_addr;
745 	    len = sizeof (in6_addr);
746 	    break;
747 #endif
748 	}
749 	if ((fd = socket (family, SOCK_STREAM, 0)) == -1)
750 	{
751 	    fprintf (stderr, "Cannot create response socket\n");
752 	    exit (REMANAGE_DISPLAY);
753 	}
754 	if (connect (fd, addr, len) == -1)
755 	{
756 	    fprintf (stderr, "Cannot connect to xdm\n");
757 	    exit (REMANAGE_DISPLAY);
758 	}
759 	buffer.data = (BYTE *) buf;
760 	buffer.size = sizeof (buf);
761 	buffer.pointer = 0;
762 	buffer.count = 0;
763 	XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress);
764 	XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType);
765 	XdmcpWriteARRAY8 (&buffer, &h->hostaddr);
766 	write (fd, (char *)buffer.data, buffer.pointer);
767 	close (fd);
768     }
769     else
770     {
771 	int i;
772 
773 	printf ("%u\n", h->connectionType);
774 	for (i = 0; i < (int)h->hostaddr.length; i++)
775 	    printf ("%u%s", h->hostaddr.data[i],
776 		    i == h->hostaddr.length - 1 ? "\n" : " ");
777     }
778 }
779 
780 /*
781   next_line returns the next line in a list
782   across the list end.
783   (0, 1, 2, 3, 0, 1, 2, 3 ....)
784 */
785 
786 static int
next_line(unsigned int current,unsigned int size,int event)787 next_line(unsigned int current, unsigned int size, int event)
788 {
789   switch(event) {
790     case Button5:
791       return (current + 1) % size;
792     case Button4:
793       return (current + size - 1) % size;
794     case XK_Down:
795       return (current + 1) % size;
796     case XK_Up:
797       return (current + size - 1) % size;
798   }
799   return -1;
800 }
801 
802 /*
803   Hostselect selects a given chooser line.
804   Returns 1 when host is willing and 0 if not
805 */
806 
807 static int
Hostselect(int line)808 Hostselect (int line)
809 {
810   XawListReturnStruct	*r;
811   HostName		*h;
812 
813   /* Assume the next host is willing */
814   XawListHighlight (list,line);
815   r = XawListShowCurrent (list);
816   /* copied from DoCheckWilling */
817   for (h = hostNamedb; h; h = h->next)
818   {
819     if (!strcmp (r->string, h->fullname))
820     {
821       if (!h->willing)
822 	XawListUnhighlight (list);
823       else
824       {
825 	/* Scroll viewport to make sure new selection is visible */
826 	Arg		size[2];
827 	Dimension	height, portheight;
828 	Position	y;
829 	int		lineheight, liney;
830 
831 	XtSetArg (size[0], XtNheight, &height);
832 	XtSetArg (size[1], XtNy, &y);
833 	XtGetValues (list, size, (Cardinal) 2);
834 
835 	XtSetArg (size[0], XtNheight, &portheight);
836 	XtGetValues (viewport, size, (Cardinal) 1);
837 
838 	lineheight = height / NameTableSize;
839 	liney = lineheight * line;
840 
841 	if ((y + liney) < 0) {
842 	    XawViewportSetCoordinates(viewport, 0, liney);
843 	} else if ((y + liney + lineheight) > portheight) {
844 	    XawViewportSetCoordinates(viewport, 0,
845 				      (liney + lineheight) - portheight);
846 	}
847 
848 	XtFree((char *) r);
849 	return 1;
850       }
851     }
852   }
853   XtFree((char *) r);
854   return 0;
855 }
856 
857 /*
858   Selectfirst selects the first willing host
859   in the chooser list (so you can select a host without
860   presence of mouse, but with pressing space or return,
861   or XK_Down / XK_Up
862 */
863 
864 static void
Selectfirst(void)865 Selectfirst (void)
866 {
867   int line;
868 
869   for (line = 0; line < NameTableSize; line++)
870   {
871     if (Hostselect(line))
872       return;
873   }
874   return;
875 }
876 
877 /*
878   Storeold stores the selected line into global int oldentry
879 */
880 
881 static void
Storeold(Widget w,XEvent * event,String * params,Cardinal * num_params)882 Storeold (Widget w, XEvent *event, String *params, Cardinal *num_params)
883 {
884   XawListReturnStruct	*r = XawListShowCurrent(list);
885 
886   oldline = r->list_index;
887   XtFree((char *) r);
888 }
889 
890 /*
891   Setold restores the global int oldentry
892   when you try to select a host with your mouse
893   who is unwilling as follows:
894   <Btn1Down>:     Store() Set() CheckWilling() Setold() \n\
895 */
896 
897 static void
Setold(Widget w,XEvent * event,String * params,Cardinal * num_params)898 Setold (Widget w, XEvent *event, String *params, Cardinal *num_params)
899 {
900 
901   if ( (XawListShowCurrent(list))->list_index == XAW_LIST_NONE && oldline != XAW_LIST_NONE)
902     XawListHighlight (list, oldline);
903 }
904 
905 /*
906   HostCycle tries to select the next willing host across
907   the list end and will stop at the first found willing host
908   or after trying all entries.
909 */
910 
911 static void
HostCycle(unsigned int line,unsigned int size,KeySym keysym)912 HostCycle(unsigned int line, unsigned int size, KeySym keysym)
913 {
914   unsigned int newline = line;
915   /* Do it only once around the chooser list, either direction */
916   while ( (newline = next_line(newline,size,keysym)) != line && newline != -1)
917   {
918     if (Hostselect(newline))
919       return;
920   }
921   /* No other willing host could be found, stay at the old one*/
922   XawListHighlight (list, line);
923   return;
924 }
925 
926 /*
927   Switch_Key handles XK_Up and XK_Down
928   and highlights an appropriate line in the chooser list.
929 */
930 
931 static void
Switch_Key(Widget w,XEvent * event,String * params,Cardinal * num_params)932 Switch_Key (Widget w, XEvent *event, String *params, Cardinal *num_params)
933 {
934   char strbuf[128];
935   KeySym keysym = 0;
936   static XComposeStatus compose_status = {NULL, 0};
937   XawListReturnStruct	*r;
938 
939   XLookupString (&event->xkey, strbuf, sizeof (strbuf),
940                            &keysym, &compose_status);
941 
942   if (keysym != XK_Up && keysym != XK_Down)
943     return;
944 
945   r = XawListShowCurrent (list);
946 
947   if (r->list_index == XAW_LIST_NONE)
948     Selectfirst();
949   else
950     HostCycle(r->list_index,NameTableSize,keysym);
951 
952   XtFree((char *) r);
953   return;
954 }
955 
956 
957 
958 /*
959   Switch_Btn handles ScrollWheel Forward (Button5) and Backward
960   (Button4) and highlights an appropriate line in the chooser list.
961 */
962 
963 static void
Switch_Btn(Widget w,XEvent * event,String * params,Cardinal * num_params)964 Switch_Btn (Widget w, XEvent *event, String *params, Cardinal *num_params)
965 {
966     XawListReturnStruct	*r;
967     r = XawListShowCurrent (list);
968 
969     if (r->list_index == XAW_LIST_NONE)
970       Selectfirst();
971     else
972       HostCycle(r->list_index,NameTableSize,event->xbutton.button);
973 
974     XtFree((char *) r);
975     return;
976 }
977 
978 
979 /* ARGSUSED */
980 static void
DoAccept(Widget w,XEvent * event,String * params,Cardinal * num_params)981 DoAccept (Widget w, XEvent *event, String *params, Cardinal *num_params)
982 {
983     XawListReturnStruct	*r;
984     HostName		*h;
985 
986     r = XawListShowCurrent (list);
987     if (r->list_index == XAW_LIST_NONE)
988 #ifdef XKB
989 	XkbStdBell(XtDisplay(toplevel),XtWindow(w),0,XkbBI_MinorError);
990 #else
991 	XBell (XtDisplay (toplevel), 0);
992 #endif
993     else
994     {
995 	for (h = hostNamedb; h; h = h->next)
996 	    if (!strcmp (r->string, h->fullname))
997 	    {
998 		Choose (h);
999 	    }
1000 	exit (OBEYSESS_DISPLAY);
1001     }
1002     XtFree((char *) r);
1003 }
1004 
1005 /* ARGSUSED */
1006 static void
DoCheckWilling(Widget w,XEvent * event,String * params,Cardinal * num_params)1007 DoCheckWilling (Widget w, XEvent *event, String *params, Cardinal *num_params)
1008 {
1009     XawListReturnStruct	*r;
1010     HostName		*h;
1011 
1012     r = XawListShowCurrent (list);
1013     if (r->list_index != XAW_LIST_NONE) {
1014 	for (h = hostNamedb; h; h = h->next)
1015 	    if (!strcmp (r->string, h->fullname))
1016 		if (!h->willing)
1017 		    XawListUnhighlight (list);
1018     }
1019     XtFree((char *) r);
1020 }
1021 
1022 /* ARGSUSED */
1023 _X_NORETURN
1024 static void
DoCancel(Widget w,XEvent * event,String * params,Cardinal * num_params)1025 DoCancel (Widget w, XEvent *event, String *params, Cardinal *num_params)
1026 {
1027     exit (OBEYSESS_DISPLAY);
1028 }
1029 
1030 /* ARGSUSED */
1031 static void
DoPing(Widget w,XEvent * event,String * params,Cardinal * num_params)1032 DoPing (Widget w, XEvent *event, String *params, Cardinal *num_params)
1033 {
1034     EmptyHostnames ();
1035     pingTry = 0;
1036     PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
1037 }
1038 
1039 static XtActionsRec app_actions[] = {
1040     { "Accept",	      DoAccept },
1041     { "Cancel",	      DoCancel },
1042     { "CheckWilling", DoCheckWilling },
1043     { "Ping",	      DoPing },
1044     { "KeySwitch",    Switch_Key },
1045     { "BtnSwitch",    Switch_Btn },
1046     { "Store",	      Storeold },
1047     { "Setold",	      Setold },
1048 };
1049 
1050 int
main(int argc,char ** argv)1051 main (int argc, char **argv)
1052 {
1053     Arg		position[3];
1054     Dimension   width, height;
1055     Position	x, y;
1056 #ifdef USE_XINERAMA
1057     XineramaScreenInfo *screens;
1058     int                 s_num;
1059 #endif
1060 
1061 
1062     toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv);
1063 
1064     XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0);
1065 
1066     XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources,
1067 			       XtNumber (resources), NULL, (Cardinal) 0);
1068 
1069     XtAddActions (app_actions, XtNumber (app_actions));
1070     paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0);
1071     label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0);
1072     viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0);
1073     list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0);
1074     box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0);
1075     cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0);
1076     acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0);
1077     ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0);
1078 
1079     /*
1080      * center ourselves on the screen
1081      */
1082     XtSetMappedWhenManaged(toplevel, FALSE);
1083     XtRealizeWidget (toplevel);
1084 
1085     XtSetArg (position[0], XtNwidth, &width);
1086     XtSetArg (position[1], XtNheight, &height);
1087     XtGetValues (toplevel, position, (Cardinal) 2);
1088 #ifdef USE_XINERAMA
1089     if (
1090 	XineramaIsActive(XtDisplay(toplevel)) &&
1091 	(screens = XineramaQueryScreens(XtDisplay(toplevel), &s_num)) != NULL
1092        )
1093     {
1094 	x = (Position)(screens[0].x_org + (screens[0].width - width) / 2);
1095 	y = (Position)(screens[0].y_org + (screens[0].height - height) / 3);
1096 
1097 	XFree(screens);
1098     }
1099     else
1100 #endif
1101     {
1102 	x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2;
1103 	y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3;
1104     }
1105     XtSetArg (position[0], XtNx, x);
1106     XtSetArg (position[1], XtNy, y);
1107     XtSetValues (toplevel, position, (Cardinal) 2);
1108 
1109     /*
1110      * Run
1111      */
1112     XtMapWidget(toplevel);
1113     InitXDMCP (argv + 1);
1114     XtMainLoop ();
1115     exit(0);
1116     /*NOTREACHED*/
1117 }
1118 
1119 /* Converts the hex string s of length len into the byte array d.
1120    Returns 0 if s was a legal hex string, 1 otherwise.
1121    */
1122 static int
FromHex(char * s,char * d,int len)1123 FromHex (char *s, char *d, int len)
1124 {
1125     int	t;
1126     int ret = len&1;		/* odd-length hex strings are illegal */
1127     while (len >= 2)
1128     {
1129 #define HexChar(c)  ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
1130 
1131 	if (!ishexdigit(*s))
1132 	    ret = 1;
1133 	t = HexChar (*s) << 4;
1134 	s++;
1135 	if (!ishexdigit(*s))
1136 	    ret = 1;
1137 	t += HexChar (*s);
1138 	s++;
1139 	*d++ = t;
1140 	len -= 2;
1141     }
1142     return ret;
1143 }
1144 
1145 /*ARGSUSED*/
1146 static void
CvtStringToARRAY8(XrmValuePtr args,Cardinal * num_args,XrmValuePtr fromVal,XrmValuePtr toVal)1147 CvtStringToARRAY8 (XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal, XrmValuePtr toVal)
1148 {
1149     static ARRAY8Ptr	dest;
1150     char	*s;
1151     int		len;
1152 
1153     dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8));
1154     len = fromVal->size;
1155     s = (char *) fromVal->addr;
1156     if (!XdmcpAllocARRAY8 (dest, len >> 1))
1157 	XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8);
1158     else
1159     {
1160 	FromHex (s, (char *) dest->data, len);
1161     }
1162     toVal->addr = (caddr_t) &dest;
1163     toVal->size = sizeof (ARRAY8Ptr);
1164 }
1165