Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtlogin / xdmcp.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: xdmcp.c /main/5 1998/04/06 13:36:04 mgreess $ */
24 /* (c) Copyright 1997 The Open Group */
25 /*                                                                      *
26  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
27  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
28  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
29  * (c) Copyright 1993, 1994 Novell, Inc.                                *
30  */
31
32 /*
33  * @DEC_COPYRIGHT@
34  */
35 /*
36  * HISTORY
37  * $Log$
38  * Revision 1.1.2.3  1995/06/06  20:25:54  Chris_Beute
39  *      Code snapshot merge from March 15 and SIA changes
40  *      [1995/05/31  20:17:42  Chris_Beute]
41  *
42  * Revision 1.1.2.2  1995/04/21  13:05:47  Peter_Derr
43  *      dtlogin auth key fixes from deltacde
44  *      [1995/04/14  18:03:44  Peter_Derr]
45  * 
46  *      Merge in dtlogin changes to WaitForSomething() to support command
47  *      line console login.
48  *      [1995/04/14  17:40:05  Peter_Derr]
49  * 
50  *      Use R6 xdm code to handle XDMCP
51  *      [1995/04/10  19:24:11  Peter_Derr]
52  * 
53  * $EndLog$
54  */
55 /*
56
57 Copyright (c) 1988  X Consortium
58
59 Permission is hereby granted, free of charge, to any person obtaining
60 a copy of this software and associated documentation files (the
61 "Software"), to deal in the Software without restriction, including
62 without limitation the rights to use, copy, modify, merge, publish,
63 distribute, sublicense, and/or sell copies of the Software, and to
64 permit persons to whom the Software is furnished to do so, subject to
65 the following conditions:
66
67 The above copyright notice and this permission notice shall be included
68 in all copies or substantial portions of the Software.
69
70 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
71 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
74 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
75 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
76 OTHER DEALINGS IN THE SOFTWARE.
77
78 Except as contained in this notice, the name of the X Consortium shall
79 not be used in advertising or otherwise to promote the sale, use or
80 other dealings in this Software without prior written authorization
81 from the X Consortium.
82
83 */
84
85 /*
86  * xdm - display manager daemon
87  * Author:  Keith Packard, MIT X Consortium
88  *
89  * xdmcp.c - Support for XDMCP
90  */
91
92 # include "dm.h"
93
94 # include       <X11/X.h>
95 # include       <X11/Xfuncs.h>
96 # include       <sys/types.h>
97 # include       <ctype.h>
98
99 #include        <sys/socket.h>
100 #include        <netinet/in.h>
101 #include        <sys/un.h>
102 #include        <netdb.h>
103
104 #ifdef X_NOT_STDC_ENV
105 #define Time_t long
106 extern Time_t time ();
107 #else
108 #include <time.h>
109 #define Time_t time_t
110 #endif
111
112 #define getString(name,len)     ((name = malloc (len + 1)) ? 1 : 0)
113
114 /*
115  * interface to policy routines
116  */
117
118 extern ARRAY8Ptr        ChooseAuthentication ();
119 extern int              SelectConnectionTypeIndex ();
120
121 int     xdmcpFd = -1;
122 int     chooserFd = -1;
123
124 FD_TYPE WellKnownSocketsMask;
125 int     WellKnownSocketsMax;
126
127 #define pS(s)   ((s) ? ((char *) (s)) : "empty string")
128
129 void DestroyWellKnownSockets ()
130 {
131     if (xdmcpFd != -1)
132     {
133         close (xdmcpFd);
134         xdmcpFd = -1;
135     }
136     if (chooserFd != -1)
137     {
138         close (chooserFd);
139         chooserFd = -1;
140     }
141 }
142
143 AnyWellKnownSockets ()
144 {
145     return xdmcpFd != -1 || chooserFd != -1;
146 }
147
148 static XdmcpBuffer      buffer;
149
150 /*ARGSUSED*/
151 static int
152 sendForward (connectionType, address, closure)
153     CARD16      connectionType;
154     ARRAY8Ptr   address;
155     char        *closure;
156 {
157 #ifdef AF_INET
158     struct sockaddr_in      in_addr;
159 #endif
160 #ifdef AF_DECnet
161 #endif
162     struct sockaddr         *addr;
163     int                     addrlen;
164
165     switch (connectionType)
166     {
167 #ifdef AF_INET
168     case FamilyInternet:
169         addr = (struct sockaddr *) &in_addr;
170         bzero ((char *) &in_addr, sizeof (in_addr));
171 #ifdef BSD44SOCKETS
172         in_addr.sin_len = sizeof(in_addr);
173 #endif
174         in_addr.sin_family = AF_INET;
175         in_addr.sin_port = htons ((short) XDM_UDP_PORT);
176         if (address->length != 4)
177             return 0;
178         memmove( (char *) &in_addr.sin_addr, address->data, address->length);
179         addrlen = sizeof (struct sockaddr_in);
180         break;
181 #endif
182 #ifdef AF_DECnet
183     case FamilyDECnet:
184 #endif
185     default:
186         return 0;
187     }
188     XdmcpFlush (xdmcpFd, &buffer, addr, addrlen);
189     return 0;
190 }
191
192 extern char *NetaddrAddress();
193 extern char *NetaddrPort();
194
195 static void
196 ClientAddress (from, addr, port, type)
197     struct sockaddr *from;
198     ARRAY8Ptr       addr, port; /* return */
199     CARD16          *type;      /* return */
200 {
201     int length, family;
202     char *data;
203
204     data = NetaddrPort(from, &length);
205     XdmcpAllocARRAY8 (port, length);
206     memmove( port->data, data, length);
207     port->length = length;
208
209     family = ConvertAddr((char *)from, &length, &data);
210
211     XdmcpAllocARRAY8 (addr, length);
212     memmove( addr->data, data, length);
213     addr->length = length;
214
215     *type = family;
216 }
217
218 static void
219 all_query_respond (from, fromlen, authenticationNames, type)
220     struct sockaddr     *from;
221     int                 fromlen;
222     ARRAYofARRAY8Ptr    authenticationNames;
223     xdmOpCode           type;
224 {
225     ARRAY8Ptr   authenticationName;
226     ARRAY8      status;
227     ARRAY8      addr;
228     CARD16      connectionType;
229     int         family;
230     int         length;
231
232     family = ConvertAddr((char *)from, &length, (char **) &(addr.data));
233
234     addr.length = length;       /* convert int to short */
235     Debug ("all_query_respond: conntype=%d, addr=%lx, len=%d\n",
236            family, *(addr.data), addr.length);
237     if (family < 0)
238         return;
239     connectionType = family;
240
241     if (type == INDIRECT_QUERY)
242         RememberIndirectClient (&addr, connectionType);
243     else
244         ForgetIndirectClient (&addr, connectionType);
245
246     authenticationName = ChooseAuthentication (authenticationNames);
247     if (Willing (&addr, connectionType, authenticationName, &status, type))
248         send_willing (from, fromlen, authenticationName, &status);
249     else
250         if (type == QUERY)
251             send_unwilling (from, fromlen, authenticationName, &status);
252     XdmcpDisposeARRAY8 (&status);
253 }
254
255 static void
256 indirect_respond (from, fromlen, length)
257     struct sockaddr *from;
258     int             fromlen;
259     int             length;
260 {
261     ARRAYofARRAY8   queryAuthenticationNames;
262     ARRAY8          clientAddress;
263     ARRAY8          clientPort;
264     CARD16          connectionType;
265     int             expectedLen;
266     int             i;
267     XdmcpHeader     header;
268     int             localHostAsWell;
269     
270     Debug ("Indirect respond %d\n", length);
271     if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
272         return;
273     expectedLen = 1;
274     for (i = 0; i < (int)queryAuthenticationNames.length; i++)
275         expectedLen += 2 + queryAuthenticationNames.data[i].length;
276     if (length == expectedLen)
277     {
278         ClientAddress (from, &clientAddress, &clientPort, &connectionType);
279         /*
280          * set up the forward query packet
281          */
282         header.version = XDM_PROTOCOL_VERSION;
283         header.opcode = (CARD16) FORWARD_QUERY;
284         header.length = 0;
285         header.length += 2 + clientAddress.length;
286         header.length += 2 + clientPort.length;
287         header.length += 1;
288         for (i = 0; i < (int)queryAuthenticationNames.length; i++)
289             header.length += 2 + queryAuthenticationNames.data[i].length;
290         XdmcpWriteHeader (&buffer, &header);
291         XdmcpWriteARRAY8 (&buffer, &clientAddress);
292         XdmcpWriteARRAY8 (&buffer, &clientPort);
293         XdmcpWriteARRAYofARRAY8 (&buffer, &queryAuthenticationNames);
294
295         localHostAsWell = ForEachMatchingIndirectHost (&clientAddress, connectionType, sendForward, (char *) 0);
296         
297         XdmcpDisposeARRAY8 (&clientAddress);
298         XdmcpDisposeARRAY8 (&clientPort);
299         if (localHostAsWell)
300             all_query_respond (from, fromlen, &queryAuthenticationNames,
301                            INDIRECT_QUERY);
302     }
303     else
304     {
305         Debug ("Indirect length error got %d expect %d\n", length, expectedLen);
306     }
307     XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
308 }
309
310 static void
311 ProcessRequestSocket ()
312 {
313     XdmcpHeader         header;
314     struct sockaddr_in  addr;
315     int                 addrlen = sizeof addr;
316
317     Debug ("ProcessRequestSocket\n");
318     bzero ((char *) &addr, sizeof (addr));
319     if (!XdmcpFill (xdmcpFd, &buffer, &addr, &addrlen)) {
320         Debug ("XdmcpFill failed\n");
321         return;
322     }
323     if (!XdmcpReadHeader (&buffer, &header)) {
324         Debug ("XdmcpReadHeader failed\n");
325         return;
326     }
327     if (header.version != XDM_PROTOCOL_VERSION) {
328         Debug ("XDMCP header version read was %d, expected %d\n",
329                header.version, XDM_PROTOCOL_VERSION);
330         return;
331     }
332     Debug ("header: %d %d %d\n", header.version, header.opcode, header.length);
333     switch (header.opcode)
334     {
335     case BROADCAST_QUERY:
336         broadcast_respond (&addr, addrlen, header.length);
337         break;
338     case QUERY:
339         query_respond (&addr, addrlen, header.length);
340         break;
341     case INDIRECT_QUERY:
342         indirect_respond (&addr, addrlen, header.length);
343         break;
344     case FORWARD_QUERY:
345         forward_respond (&addr, addrlen, header.length);
346         break;
347     case REQUEST:
348         request_respond (&addr, addrlen, header.length);
349         break;
350     case MANAGE:
351         manage (&addr, addrlen, header.length);
352         break;
353     case KEEPALIVE:
354         send_alive (&addr, addrlen, header.length);
355         break;
356     }
357 }
358
359 /*
360  * dtlogin changes to WaitForSomething () merged in to support command line
361  * login.
362  */
363 void WaitForSomething ()
364 {
365     FD_TYPE     reads;
366     struct timeval      timeout, *ptimeout;
367     int nready;
368     extern int Rescan, ChildReady, wakeupTime;
369
370     Debug ("WaitForSomething\n");
371     if (AnyWellKnownSockets () && !ChildReady || wakeupTime > 0 ) {
372         reads = WellKnownSocketsMask;
373
374         if (wakeupTime >= 0 ) {
375             timeout.tv_sec  = wakeupTime;
376             timeout.tv_usec = 10;
377             ptimeout = &timeout;
378             Debug("Setting timer on select() for %d seconds.\n", wakeupTime);
379         }
380         else
381             ptimeout = NULL;
382
383 #ifdef __hpux
384         nready = select (WellKnownSocketsMax + 1, (int *) &reads, 0, 0, ptimeout);
385 #else
386         nready = select (WellKnownSocketsMax + 1, &reads, 0, 0, ptimeout);
387 #endif
388         Debug ("select returns %d.  Rescan: %d  ChildReady: %d\n",
389                 nready, Rescan, ChildReady);
390         if (nready > 0)
391         {
392             if (xdmcpFd >= 0 && FD_ISSET (xdmcpFd, &reads))
393                 ProcessRequestSocket ();
394             if (chooserFd >= 0 && FD_ISSET (chooserFd, &reads))
395                 ProcessChooserSocket (chooserFd);
396         }
397         if (ChildReady)
398         {
399             WaitForChild ();
400         }
401         else
402             StartDisplays();
403     } else
404         WaitForChild ();
405 }
406
407 /*
408  * respond to a request on the UDP socket.
409  */
410
411 static ARRAY8   Hostname;
412
413 void
414 registerHostname (name, namelen)
415     char    *name;
416     int     namelen;
417 {
418     int i;
419
420     if (!XdmcpReallocARRAY8 (&Hostname, namelen))
421         return;
422     for (i = 0; i < namelen; i++)
423         Hostname.data[i] = name[i];
424 }
425
426 static void
427 direct_query_respond (from, fromlen, length, type)
428     struct sockaddr *from;
429     int             fromlen;
430     int             length;
431     xdmOpCode       type;
432 {
433     ARRAYofARRAY8   queryAuthenticationNames;
434     int             expectedLen;
435     int             i;
436     
437     if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
438         return;
439     expectedLen = 1;
440     for (i = 0; i < (int)queryAuthenticationNames.length; i++)
441         expectedLen += 2 + queryAuthenticationNames.data[i].length;
442     if (length == expectedLen)
443         all_query_respond (from, fromlen, &queryAuthenticationNames, type);
444     XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
445 }
446
447 query_respond (from, fromlen, length)
448     struct sockaddr *from;
449     int             fromlen;
450     int             length;
451 {
452     Debug ("Query respond %d\n", length);
453     direct_query_respond (from, fromlen, length, QUERY);
454 }
455
456 broadcast_respond (from, fromlen, length)
457     struct sockaddr *from;
458     int             fromlen;
459     int             length;
460 {
461     direct_query_respond (from, fromlen, length, BROADCAST_QUERY);
462 }
463
464 /* computes an X display name */
465
466 char *
467 NetworkAddressToName(connectionType, connectionAddress, displayNumber)
468 #if NeedWidePrototypes
469     int connectionType;
470 #else
471     CARD16 connectionType;
472 #endif
473     ARRAY8Ptr   connectionAddress;
474 #if NeedWidePrototypes
475     int displayNumber;
476 #else
477     CARD16 displayNumber;
478 #endif
479 {
480     switch (connectionType)
481     {
482     case FamilyInternet:
483         {
484             CARD8               *data;
485             struct hostent      *hostent;
486             char                *name;
487             char                *localhost, *localHostname();
488
489             data = connectionAddress->data;
490             hostent = gethostbyaddr ((char *)data,
491                                      connectionAddress->length, AF_INET);
492
493             localhost = localHostname ();
494
495             /* 
496              * protect against bogus host names 
497              */
498             if (hostent && hostent->h_name && hostent->h_name[0]
499                         && (hostent->h_name[0] != '.'))
500             {
501                 if (!strcmp (localhost, hostent->h_name))
502                 {
503                     if (!getString (name, 10))
504                         return 0;
505                     sprintf (name, ":%d", displayNumber);
506                 }
507                 else
508                 {
509                     if (removeDomainname)
510                     {
511                         char    *localDot, *remoteDot;
512     
513                         /* check for a common domain name.  This
514                          * could reduce names by recognising common
515                          * super-domain names as well, but I don't think
516                          * this is as useful, and will confuse more
517                          * people
518                          */
519                         if ((localDot = strchr(localhost, '.')) &&
520                             (remoteDot = strchr(hostent->h_name, '.')))
521                         {
522                             /* smash the name in place; it won't
523                              * be needed later.
524                              */
525                             if (!strcmp (localDot+1, remoteDot+1))
526                                 *remoteDot = '\0';
527                         }
528                     }
529
530                     if (!getString (name, strlen (hostent->h_name) + 10))
531                         return 0;
532                     sprintf (name, "%s:%d", hostent->h_name, displayNumber);
533                 }
534             }
535             else
536             {
537                 if (!getString (name, 25))
538                     return 0;
539                 sprintf(name, "%d.%d.%d.%d:%d",
540                         data[0], data[1], data[2], data[3], displayNumber);
541             }
542             return name;
543         }
544 #ifdef DNET
545     case FamilyDECnet:
546         return NULL;
547 #endif /* DNET */
548     default:
549         return NULL;
550     }
551 }
552
553 /*ARGSUSED*/
554 forward_respond (from, fromlen, length)
555     struct sockaddr     *from;
556     int                 fromlen;
557     int                 length;
558 {
559     ARRAY8          clientAddress;
560     ARRAY8          clientPort;
561     ARRAYofARRAY8   authenticationNames;
562     struct sockaddr *client;
563     int             clientlen;
564     int             expectedLen;
565     int             i;
566     
567     Debug ("Forward respond %d\n", length);
568     clientAddress.length = 0;
569     clientAddress.data = 0;
570     clientPort.length = 0;
571     clientPort.data = 0;
572     authenticationNames.length = 0;
573     authenticationNames.data = 0;
574     if (XdmcpReadARRAY8 (&buffer, &clientAddress) &&
575         XdmcpReadARRAY8 (&buffer, &clientPort) &&
576         XdmcpReadARRAYofARRAY8 (&buffer, &authenticationNames))
577     {
578         expectedLen = 0;
579         expectedLen += 2 + clientAddress.length;
580         expectedLen += 2 + clientPort.length;
581         expectedLen += 1;           /* authenticationNames */
582         for (i = 0; i < (int)authenticationNames.length; i++)
583             expectedLen += 2 + authenticationNames.data[i].length;
584         if (length == expectedLen)
585         {
586             int j;
587
588             j = 0;
589             for (i = 0; i < (int)clientPort.length; i++)
590                 j = j * 256 + clientPort.data[i];
591             Debug ("Forward client address (port %d)", j);
592             for (i = 0; i < (int)clientAddress.length; i++)
593                 Debug (" %d", clientAddress.data[i]);
594             Debug ("\n");
595             switch (from->sa_family)
596             {
597 #ifdef AF_INET
598             case AF_INET:
599                 {
600                     struct sockaddr_in  in_addr;
601
602                     if (clientAddress.length != 4 ||
603                         clientPort.length != 2)
604                     {
605                         goto badAddress;
606                     }
607                     bzero ((char *) &in_addr, sizeof (in_addr));
608 #ifdef BSD44SOCKETS
609                     in_addr.sin_len = sizeof(in_addr);
610 #endif
611                     in_addr.sin_family = AF_INET;
612                     memmove( &in_addr.sin_addr, clientAddress.data, 4);
613                     memmove( (char *) &in_addr.sin_port, clientPort.data, 2);
614                     client = (struct sockaddr *) &in_addr;
615                     clientlen = sizeof (in_addr);
616                 }
617                 break;
618 #endif
619 #ifdef AF_UNIX
620             case AF_UNIX:
621                 {
622                     struct sockaddr_un  un_addr;
623
624                     if (clientAddress.length >= sizeof (un_addr.sun_path))
625                         goto badAddress;
626                     bzero ((char *) &un_addr, sizeof (un_addr));
627                     un_addr.sun_family = AF_UNIX;
628                     memmove( un_addr.sun_path, clientAddress.data, clientAddress.length);
629                     un_addr.sun_path[clientAddress.length] = '\0';
630                     client = (struct sockaddr *) &un_addr;
631 #ifdef BSD44SOCKETS
632                     un_addr.sun_len = strlen(un_addr.sun_path);
633                     clientlen = SUN_LEN(&un_addr);
634 #else
635                     clientlen = sizeof (un_addr);
636 #endif
637                 }
638                 break;
639 #endif
640 #ifdef AF_CHAOS
641             case AF_CHAOS:
642                 goto badAddress;
643 #endif
644 #ifdef AF_DECnet
645             case AF_DECnet:
646                 goto badAddress;
647 #endif
648             }
649             all_query_respond (client, clientlen, &authenticationNames,
650                                FORWARD_QUERY);
651         }
652         else
653         {
654             Debug ("Forward length error got %d expect %d\n", length, expectedLen);
655         }
656     }
657 badAddress:
658     XdmcpDisposeARRAY8 (&clientAddress);
659     XdmcpDisposeARRAY8 (&clientPort);
660     XdmcpDisposeARRAYofARRAY8 (&authenticationNames);
661 }
662
663 send_willing (from, fromlen, authenticationName, status)
664     struct sockaddr *from;
665     int             fromlen;
666     ARRAY8Ptr       authenticationName;
667     ARRAY8Ptr       status;
668 {
669     XdmcpHeader header;
670
671     Debug ("Send willing %*.*s %*.*s\n", authenticationName->length,
672                                          authenticationName->length,
673                                          pS(authenticationName->data),
674                                          status->length,
675                                          status->length,
676                                          pS(status->data));
677     header.version = XDM_PROTOCOL_VERSION;
678     header.opcode = (CARD16) WILLING;
679     header.length = 6 + authenticationName->length +
680                     Hostname.length + status->length;
681     XdmcpWriteHeader (&buffer, &header);
682     XdmcpWriteARRAY8 (&buffer, authenticationName);
683     XdmcpWriteARRAY8 (&buffer, &Hostname);
684     XdmcpWriteARRAY8 (&buffer, status);
685     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
686 }
687
688 send_unwilling (from, fromlen, authenticationName, status)
689     struct sockaddr *from;
690     int             fromlen;
691     ARRAY8Ptr       authenticationName;
692     ARRAY8Ptr       status;
693 {
694     XdmcpHeader header;
695
696     Debug ("Send unwilling %*.*s %*.*s\n", authenticationName->length,
697                                          authenticationName->length,
698                                          pS(authenticationName->data),
699                                          status->length,
700                                          status->length,
701                                          pS(status->data));
702     header.version = XDM_PROTOCOL_VERSION;
703     header.opcode = (CARD16) UNWILLING;
704     header.length = 4 + Hostname.length + status->length;
705     XdmcpWriteHeader (&buffer, &header);
706     XdmcpWriteARRAY8 (&buffer, &Hostname);
707     XdmcpWriteARRAY8 (&buffer, status);
708     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
709 }
710
711 static unsigned long    globalSessionID;
712
713 #define NextSessionID()    (++globalSessionID)
714
715 void init_session_id()
716 {
717     /* Set randomly so we are unlikely to reuse id's from a previous
718      * incarnation so we don't say "Alive" to those displays.
719      * Start with low digits 0 to make debugging easier.
720      */
721     globalSessionID = (time((Time_t)0)&0x7fff) * 16000;
722 }
723     
724 static ARRAY8 outOfMemory = { (CARD16) 13, (CARD8Ptr) "Out of memory" };
725 static ARRAY8 noValidAddr = { (CARD16) 16, (CARD8Ptr) "No valid address" };
726 static ARRAY8 noValidAuth = { (CARD16) 22, (CARD8Ptr) "No valid authorization" };
727 static ARRAY8 noAuthentic = { (CARD16) 29, (CARD8Ptr) "XDM has no authentication key" };
728
729 request_respond (from, fromlen, length)
730     struct sockaddr *from;
731     int             fromlen;
732     int             length;
733 {
734     CARD16          displayNumber;
735     ARRAY16         connectionTypes;
736     ARRAYofARRAY8   connectionAddresses;
737     ARRAY8          authenticationName;
738     ARRAY8          authenticationData;
739     ARRAYofARRAY8   authorizationNames;
740     ARRAY8          manufacturerDisplayID;
741     ARRAY8Ptr       reason;
742     int             expectlen;
743     int             i, j;
744     struct protoDisplay  *pdpy;
745     ARRAY8          authorizationName, authorizationData;
746     ARRAY8Ptr       connectionAddress;
747
748     Debug ("Request respond %d\n", length);
749     connectionTypes.data = 0;
750     connectionAddresses.data = 0;
751     authenticationName.data = 0;
752     authenticationData.data = 0;
753     authorizationNames.data = 0;
754     authorizationName.length = 0;
755     authorizationData.length = 0;
756     manufacturerDisplayID.data = 0;
757     if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
758         XdmcpReadARRAY16 (&buffer, &connectionTypes) &&
759         XdmcpReadARRAYofARRAY8 (&buffer, &connectionAddresses) &&
760         XdmcpReadARRAY8 (&buffer, &authenticationName) &&
761         XdmcpReadARRAY8 (&buffer, &authenticationData) &&
762         XdmcpReadARRAYofARRAY8 (&buffer, &authorizationNames) &&
763         XdmcpReadARRAY8 (&buffer, &manufacturerDisplayID))
764     {
765         expectlen = 0;
766         expectlen += 2;                             /* displayNumber */
767         expectlen += 1 + 2*connectionTypes.length;  /* connectionTypes */
768         expectlen += 1;                             /* connectionAddresses */
769         for (i = 0; i < (int)connectionAddresses.length; i++)
770             expectlen += 2 + connectionAddresses.data[i].length;
771         expectlen += 2 + authenticationName.length; /* authenticationName */
772         expectlen += 2 + authenticationData.length; /* authenticationData */
773         expectlen += 1;                             /* authoriationNames */
774         for (i = 0; i < (int)authorizationNames.length; i++)
775             expectlen += 2 + authorizationNames.data[i].length;
776         expectlen += 2 + manufacturerDisplayID.length;  /* displayID */
777         if (expectlen != length)
778         {
779             Debug ("Request length error got %d expect %d\n", length, expectlen);
780             goto abort;
781         }
782         if (connectionTypes.length == 0 ||
783             connectionAddresses.length != connectionTypes.length)
784         {
785             reason = &noValidAddr;
786             pdpy = 0;
787             goto decline;
788         }
789         pdpy = FindProtoDisplay (from, fromlen, displayNumber);
790         if (!pdpy) {
791
792             /* Check this Display against the Manager's policy */
793             reason = Accept (from, fromlen, displayNumber);
794             if (reason)
795                 goto decline;
796
797             /* Check the Display's stream services against Manager's policy */
798             i = SelectConnectionTypeIndex (&connectionTypes,
799                                            &connectionAddresses);
800             if (i < 0) {
801                 reason = &noValidAddr;
802                 goto decline;
803             }
804         
805             /* The Manager considers this a new session */
806             connectionAddress = &connectionAddresses.data[i];
807             pdpy = NewProtoDisplay (from, fromlen, displayNumber,
808                                     connectionTypes.data[i], connectionAddress,
809                                     NextSessionID());
810             Debug ("NewProtoDisplay 0x%x\n", pdpy);
811             if (!pdpy) {
812                 reason = &outOfMemory;
813                 goto decline;
814             }
815         }
816         if (authorizationNames.length == 0)
817             j = 0;
818         else
819             j = SelectAuthorizationTypeIndex (&authenticationName,
820                                               &authorizationNames);
821         if (j < 0)
822         {
823             reason = &noValidAuth;
824             goto decline;
825         }
826         if (!CheckAuthentication (pdpy,
827                                   &manufacturerDisplayID,
828                                   &authenticationName,
829                                   &authenticationData))
830         {
831             reason = &noAuthentic;
832             goto decline;
833         }
834         if (j < (int)authorizationNames.length)
835         {
836             Xauth   *auth;
837             SetProtoDisplayAuthorization (pdpy,
838                 (unsigned short) authorizationNames.data[j].length,
839                 (char *) authorizationNames.data[j].data);
840             auth = pdpy->xdmcpAuthorization;
841             if (!auth)
842                 auth = pdpy->fileAuthorization;
843             if (auth)
844             {
845                 authorizationName.length = auth->name_length;
846                 authorizationName.data = (CARD8Ptr) auth->name;
847                 authorizationData.length = auth->data_length;
848                 authorizationData.data = (CARD8Ptr) auth->data;
849             }
850         }
851         if (pdpy)
852         {
853             send_accept (from, fromlen, pdpy->sessionID,
854                                         &authenticationName,
855                                         &authenticationData,
856                                         &authorizationName,
857                                         &authorizationData);
858         }
859         else
860         {
861 decline:    ;
862             send_decline (from, fromlen, &authenticationName,
863                                  &authenticationData,
864                                  reason);
865             if (pdpy)
866                 DisposeProtoDisplay (pdpy);
867         }
868     }
869 abort:
870     XdmcpDisposeARRAY16 (&connectionTypes);
871     XdmcpDisposeARRAYofARRAY8 (&connectionAddresses);
872     XdmcpDisposeARRAY8 (&authenticationName);
873     XdmcpDisposeARRAY8 (&authenticationData);
874     XdmcpDisposeARRAYofARRAY8 (&authorizationNames);
875     XdmcpDisposeARRAY8 (&manufacturerDisplayID);
876 }
877
878 send_accept (to, tolen, sessionID,
879              authenticationName, authenticationData,
880              authorizationName, authorizationData)
881     struct sockaddr *to;
882     int             tolen;
883     CARD32          sessionID;
884     ARRAY8Ptr       authenticationName, authenticationData;
885     ARRAY8Ptr       authorizationName, authorizationData;
886 {
887     XdmcpHeader header;
888
889     Debug ("Accept Session ID %d\n", sessionID);
890     header.version = XDM_PROTOCOL_VERSION;
891     header.opcode = (CARD16) ACCEPT;
892     header.length = 4;                      /* session ID */
893     header.length += 2 + authenticationName->length;
894     header.length += 2 + authenticationData->length;
895     header.length += 2 + authorizationName->length;
896     header.length += 2 + authorizationData->length;
897     XdmcpWriteHeader (&buffer, &header);
898     XdmcpWriteCARD32 (&buffer, sessionID);
899     XdmcpWriteARRAY8 (&buffer, authenticationName);
900     XdmcpWriteARRAY8 (&buffer, authenticationData);
901     XdmcpWriteARRAY8 (&buffer, authorizationName);
902     XdmcpWriteARRAY8 (&buffer, authorizationData);
903     XdmcpFlush (xdmcpFd, &buffer, to, tolen);
904 }
905    
906 send_decline (to, tolen, authenticationName, authenticationData, status)
907     struct sockaddr *to;
908     int             tolen;
909     ARRAY8Ptr       authenticationName, authenticationData;
910     ARRAY8Ptr       status;
911 {
912     XdmcpHeader header;
913
914     Debug ("Decline %*.*s\n", status->length, status->length, pS(status->data));
915     header.version = XDM_PROTOCOL_VERSION;
916     header.opcode = (CARD16) DECLINE;
917     header.length = 0;
918     header.length += 2 + status->length;
919     header.length += 2 + authenticationName->length;
920     header.length += 2 + authenticationData->length;
921     XdmcpWriteHeader (&buffer, &header);
922     XdmcpWriteARRAY8 (&buffer, status);
923     XdmcpWriteARRAY8 (&buffer, authenticationName);
924     XdmcpWriteARRAY8 (&buffer, authenticationData);
925     XdmcpFlush (xdmcpFd, &buffer, to, tolen);
926 }
927
928 manage (from, fromlen, length)
929     struct sockaddr *from;
930     int             fromlen;
931     int             length;
932 {
933     CARD32              sessionID;
934     CARD16              displayNumber;
935     ARRAY8              displayClass;
936     int                 expectlen;
937     struct protoDisplay *pdpy;
938     struct display      *d;
939     char                *name = NULL;
940     char                *class = NULL;
941     XdmcpNetaddr        from_save;
942     ARRAY8              clientAddress, clientPort;
943     CARD16              connectionType;
944
945     Debug ("Manage %d\n", length);
946     displayClass.data = 0;
947     displayClass.length = 0;
948     if (XdmcpReadCARD32 (&buffer, &sessionID) &&
949         XdmcpReadCARD16 (&buffer, &displayNumber) &&
950         XdmcpReadARRAY8 (&buffer, &displayClass))
951     {
952         expectlen = 4 +                         /* session ID */
953                     2 +                         /* displayNumber */
954                     2 + displayClass.length;    /* displayClass */
955         if (expectlen != length)
956         {
957             Debug ("Manage length error got %d expect %d\n", length, expectlen);
958             goto abort;
959         }
960         pdpy = FindProtoDisplay (from, fromlen, displayNumber);
961         Debug ("Manage Session ID %d, pdpy 0x%x\n", sessionID, pdpy);
962         if (!pdpy || pdpy->sessionID != sessionID)
963         {
964             /*
965              * We may have already started a session for this display
966              * but it hasn't seen the response in the form of an
967              * XOpenDisplay() yet. So check if it is in the list of active
968              * displays, and if so check that the session id's match.
969              * If all this is true, then we have a duplicate request that
970              * can be ignored.
971              */
972             if (!pdpy 
973                 && (d = FindDisplayByAddress(from, fromlen, displayNumber))
974                 && d->sessionID == sessionID) {
975                      Debug("manage: got duplicate pkt, ignoring\n");
976                      goto abort;
977             }
978             Debug ("Session ID %d refused\n", sessionID);
979             if (pdpy)
980                 Debug ("Existing Session ID %d\n", pdpy->sessionID);
981             send_refuse (from, fromlen, sessionID);
982         }
983         else
984         {
985             name = NetworkAddressToName (pdpy->connectionType,
986                                          &pdpy->connectionAddress,
987                                          pdpy->displayNumber);
988             Debug ("Computed display name: %s\n", name);
989             if (!name)
990             {
991                 send_failed (from, fromlen, "(no name)", sessionID, "out of memory");
992                 goto abort;
993             }
994             d = FindDisplayByName (name);
995             if (d)
996             {
997                 extern void StopDisplay ();
998
999                 Debug ("Terminating active session for %s\n", d->name);
1000                 StopDisplay (d);
1001             }
1002             class = malloc (displayClass.length + 1);
1003             if (!class)
1004             {
1005                 send_failed (from, fromlen, name, sessionID, "out of memory");
1006                 goto abort;
1007             }
1008             if (displayClass.length)
1009             {
1010                 memmove( class, displayClass.data, displayClass.length);
1011                 class[displayClass.length] = '\0';
1012             }
1013             else
1014             {
1015                 free ((char *) class);
1016                 class = (char *) NULL;
1017             }
1018             from_save = (XdmcpNetaddr) malloc (fromlen);
1019             if (!from_save)
1020             {
1021                 send_failed (from, fromlen, name, sessionID, "out of memory");
1022                 goto abort;
1023             }
1024             memmove( from_save, from, fromlen);
1025             d = NewDisplay (name, class);
1026             if (!d)
1027             {
1028                 free ((char *) from_save);
1029                 send_failed (from, fromlen, name, sessionID, "out of memory");
1030                 goto abort;
1031             }
1032             d->displayType.location = Foreign;
1033             d->displayType.lifetime = Transient;
1034             d->displayType.origin = FromXDMCP;
1035             d->sessionID = pdpy->sessionID;
1036             d->from = (struct sockaddr *)from_save;
1037             d->fromlen = fromlen;
1038             d->displayNumber = pdpy->displayNumber;
1039 #ifdef BYPASSLOGIN
1040             d->bypassLogin = 0;
1041 #endif /* BYPASSLOGIN */
1042             ClientAddress (from, &clientAddress, &clientPort, &connectionType);
1043             d->useChooser = 0;
1044             if (IsIndirectClient (&clientAddress, connectionType))
1045             {
1046                 Debug ("IsIndirectClient\n");
1047                 ForgetIndirectClient (&clientAddress, connectionType);
1048                 if (UseChooser (&clientAddress, connectionType))
1049                 {
1050                     d->useChooser = 1;
1051                     Debug ("Use chooser for %s\n", d->name);
1052                 }
1053             }
1054             d->clientAddr = clientAddress;
1055             d->connectionType = connectionType;
1056             XdmcpDisposeARRAY8 (&clientPort);
1057             if (pdpy->fileAuthorization)
1058             {
1059                 d->authorizations = (Xauth **) malloc (sizeof (Xauth *));
1060                 if (!d->authorizations)
1061                 {
1062                     free ((char *) from_save);
1063                     free ((char *) d);
1064                     send_failed (from, fromlen, name, sessionID, "out of memory");
1065                     goto abort;
1066                 }
1067                 d->authorizations[0] = pdpy->fileAuthorization;
1068                 d->authNum = 1;
1069                 pdpy->fileAuthorization = 0;
1070             }
1071             DisposeProtoDisplay (pdpy);
1072             Debug ("Starting display %s,%s\n", d->name, d->class);
1073             StartDisplay (d);
1074         }
1075     }
1076 abort:
1077     XdmcpDisposeARRAY8 (&displayClass);
1078     if (name) free ((char*) name);
1079     if (class) free ((char*) class);
1080 }
1081
1082 void SendFailed (d, reason)
1083     struct display  *d;
1084     char            *reason;
1085 {
1086     Debug ("Display start failed, sending Failed\n");
1087     send_failed (d->from, d->fromlen, d->name, d->sessionID, reason);
1088 }
1089
1090 send_failed (from, fromlen, name, sessionID, reason)
1091     struct sockaddr *from;
1092     int             fromlen;
1093     char            *name;
1094     CARD32          sessionID;
1095     char            *reason;
1096 {
1097     static char buf[256];
1098     XdmcpHeader header;
1099     ARRAY8      status;
1100
1101     sprintf (buf, "Session %d failed for display %s: %s",
1102              sessionID, name, reason);
1103     Debug ("Send failed %d %s\n", sessionID, buf);
1104     status.length = strlen (buf);
1105     status.data = (CARD8Ptr) buf;
1106     header.version = XDM_PROTOCOL_VERSION;
1107     header.opcode = (CARD16) FAILED;
1108     header.length = 6 + status.length;
1109     XdmcpWriteHeader (&buffer, &header);
1110     XdmcpWriteCARD32 (&buffer, sessionID);
1111     XdmcpWriteARRAY8 (&buffer, &status);
1112     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
1113 }
1114
1115 send_refuse (from, fromlen, sessionID)
1116     struct sockaddr *from;
1117     int             fromlen;
1118     CARD32          sessionID;
1119 {
1120     XdmcpHeader header;
1121
1122     Debug ("Send refuse %d\n", sessionID);
1123     header.version = XDM_PROTOCOL_VERSION;
1124     header.opcode = (CARD16) REFUSE;
1125     header.length = 4;
1126     XdmcpWriteHeader (&buffer, &header);
1127     XdmcpWriteCARD32 (&buffer, sessionID);
1128     XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
1129 }
1130
1131 send_alive (from, fromlen, length)
1132     struct sockaddr *from;
1133     int             fromlen;
1134     int             length;
1135 {
1136     CARD32              sessionID;
1137     CARD16              displayNumber;
1138     struct display      *d;
1139     XdmcpHeader         header;
1140     CARD8               sendRunning;
1141     CARD32              sendSessionID;
1142
1143     Debug ("Send alive\n");
1144     if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
1145         XdmcpReadCARD32 (&buffer, &sessionID))
1146     {
1147         if (length == 6)
1148         {
1149             d = FindDisplayBySessionID (sessionID);
1150             if (!d) {
1151                 d = FindDisplayByAddress (from, fromlen, displayNumber);
1152             }
1153             sendRunning = 0;
1154             sendSessionID = 0;
1155             if (d && d->status == running)
1156             {
1157                 if (d->sessionID == sessionID)
1158                     sendRunning = 1;
1159                 sendSessionID = d->sessionID;
1160             }
1161             header.version = XDM_PROTOCOL_VERSION;
1162             header.opcode = (CARD16) ALIVE;
1163             header.length = 5;
1164             Debug ("alive: %d %d\n", sendRunning, sendSessionID);
1165             XdmcpWriteHeader (&buffer, &header);
1166             XdmcpWriteCARD8 (&buffer, sendRunning);
1167             XdmcpWriteCARD32 (&buffer, sendSessionID);
1168             XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
1169         }
1170     }
1171 }
1172
1173 char *
1174 NetworkAddressToHostname (connectionType, connectionAddress)
1175 #if NeedWidePrototypes
1176     int connectionType;
1177 #else
1178     CARD16 connectionType;
1179 #endif
1180     ARRAY8Ptr   connectionAddress;
1181 {
1182     char    *name = 0;
1183
1184     switch (connectionType)
1185     {
1186     case FamilyInternet:
1187         {
1188             struct hostent      *hostent;
1189             char dotted[20];
1190             char *local_name;
1191
1192             hostent = gethostbyaddr ((char *)connectionAddress->data,
1193                                      connectionAddress->length, AF_INET);
1194
1195             if (hostent)
1196                 local_name = hostent->h_name;
1197             else {
1198                 /* can't get name, so use emergency fallback */
1199                 sprintf(dotted, "%d.%d.%d.%d",
1200                         connectionAddress->data[0],
1201                         connectionAddress->data[1],
1202                         connectionAddress->data[2],
1203                         connectionAddress->data[3]);
1204                 local_name = dotted;
1205
1206                 LogError ((unsigned char *)"Cannot convert Internet address %s to host name\n",
1207                           dotted);
1208             }
1209             if (!getString (name, strlen (local_name)))
1210                 break;
1211             strcpy (name, local_name);
1212             break;
1213         }
1214 #ifdef DNET
1215     case FamilyDECnet:
1216         break;
1217 #endif /* DNET */
1218     default:
1219         break;
1220     }
1221     return name;
1222 }
1223
1224 static
1225 HostnameToNetworkAddress (name, connectionType, connectionAddress)
1226 char        *name;
1227 CARD16      connectionType;
1228 ARRAY8Ptr   connectionAddress;
1229 {
1230     switch (connectionType)
1231     {
1232     case FamilyInternet:
1233         {
1234             struct hostent      *hostent;
1235
1236             hostent = gethostbyname (name);
1237             if (!hostent)
1238                 return FALSE;
1239             if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
1240                 return FALSE;
1241             memmove( connectionAddress->data, hostent->h_addr, hostent->h_length);
1242             return TRUE;
1243         }
1244 #ifdef DNET
1245     case FamilyDECnet:
1246         return FALSE;
1247 #endif
1248     }
1249     return FALSE;
1250 }
1251
1252 /*
1253  * converts a display name into a network address, using
1254  * the same rules as XOpenDisplay (algorithm cribbed from there)
1255  */
1256
1257 static
1258 NameToNetworkAddress(name, connectionTypep, connectionAddress, displayNumber)
1259 char        *name;
1260 CARD16Ptr   connectionTypep;
1261 ARRAY8Ptr   connectionAddress;
1262 CARD16Ptr   displayNumber;
1263 {
1264     char    *colon, *display_number;
1265     char    hostname[1024];
1266     int     dnet = FALSE;
1267     CARD16  number;
1268     CARD16  connectionType;
1269
1270     colon = strchr(name, ':');
1271     if (!colon)
1272         return FALSE;
1273     if (colon != name)
1274     {
1275         if (colon - name > sizeof (hostname))
1276             return FALSE;
1277         strncpy (hostname, name, colon - name);
1278         hostname[colon - name] = '\0';
1279     }
1280     else
1281     {
1282         strcpy (hostname, localHostname ());
1283     }
1284     if (colon[1] == ':')
1285     {
1286         dnet = TRUE;
1287         colon++;
1288     }
1289 #ifndef DNETCONN
1290     if (dnet)
1291         return FALSE;
1292 #endif
1293     display_number = colon + 1;
1294     while (*display_number && *display_number != '.')
1295     {
1296         if (!isascii (*display_number) || !isdigit(*display_number))
1297             return FALSE;
1298     }
1299     if (display_number == colon + 1)
1300         return FALSE;
1301     number = atoi (colon + 1);
1302 #ifdef DNETCONN
1303     if (dnet)
1304         connectionType = FamilyDECnet;
1305     else
1306 #endif
1307         connectionType = FamilyInternet;
1308     if (!HostnameToNetworkAddress (hostname, connectionType, connectionAddress))
1309         return FALSE;
1310     *displayNumber = number;
1311     *connectionTypep = connectionType;
1312     return TRUE;
1313 }