2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: xdmcp.c /main/5 1998/04/06 13:36:04 mgreess $ */
24 /* (c) Copyright 1997 The Open Group */
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. *
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]
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]
46 * Merge in dtlogin changes to WaitForSomething() to support command
48 * [1995/04/14 17:40:05 Peter_Derr]
50 * Use R6 xdm code to handle XDMCP
51 * [1995/04/10 19:24:11 Peter_Derr]
57 Copyright (c) 1988 X Consortium
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:
67 The above copyright notice and this permission notice shall be included
68 in all copies or substantial portions of the Software.
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.
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.
86 * xdm - display manager daemon
87 * Author: Keith Packard, MIT X Consortium
89 * xdmcp.c - Support for XDMCP
95 # include <X11/Xfuncs.h>
96 # include <sys/types.h>
99 #include <sys/socket.h>
100 #include <netinet/in.h>
104 #ifdef X_NOT_STDC_ENV
106 extern Time_t time ();
109 #define Time_t time_t
112 #define getString(name,len) ((name = malloc (len + 1)) ? 1 : 0)
115 * interface to policy routines
118 extern ARRAY8Ptr ChooseAuthentication ();
119 extern int SelectConnectionTypeIndex ();
121 void query_respond (struct sockaddr *from, int fromlen, int length);
122 void broadcast_respond (struct sockaddr *from, int fromlen, int length);
123 void forward_respond (struct sockaddr *from, int fromlen, int length);
124 void request_respond (struct sockaddr *from, int fromlen, int length);
125 void send_willing (struct sockaddr *from, int fromlen, ARRAY8Ptr authenticationName, ARRAY8Ptr status);
126 void send_unwilling (struct sockaddr *from, int fromlen, ARRAY8Ptr authenticationName, ARRAY8Ptr status);
127 void send_accept (struct sockaddr *to, int tolen, CARD32 sessionID, ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData, ARRAY8Ptr authorizationName, ARRAY8Ptr authorizationData);
128 void manage (struct sockaddr *from, int fromlen, int length);
129 void send_decline (struct sockaddr *to, int tolen, ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData, ARRAY8Ptr status);
130 void send_failed (struct sockaddr *from, int fromlen, char *name, CARD32 sessionID, char *reason);
131 void send_refuse (struct sockaddr *from, int fromlen, CARD32 sessionID);
132 void send_alive (struct sockaddr *from, int fromlen, int length);
139 FD_TYPE WellKnownSocketsMask;
140 int WellKnownSocketsMax;
142 #define pS(s) ((s) ? ((char *) (s)) : "empty string")
145 DestroyWellKnownSockets (void)
160 AnyWellKnownSockets (void)
162 return xdmcpFd != -1 || chooserFd != -1;
165 static XdmcpBuffer buffer;
169 sendForward (CARD16 connectionType, ARRAY8Ptr address, char *closure)
172 struct sockaddr_in in_addr;
176 struct sockaddr *addr;
179 switch (connectionType)
183 addr = (struct sockaddr *) &in_addr;
184 bzero ((char *) &in_addr, sizeof (in_addr));
186 in_addr.sin_len = sizeof(in_addr);
188 in_addr.sin_family = AF_INET;
189 in_addr.sin_port = htons ((short) XDM_UDP_PORT);
190 if (address->length != 4)
192 memmove( (char *) &in_addr.sin_addr, address->data, address->length);
193 addrlen = sizeof (struct sockaddr_in);
202 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)addr, addrlen);
206 extern char *NetaddrAddress();
207 extern char *NetaddrPort();
210 ClientAddress (struct sockaddr *from, ARRAY8Ptr addr, ARRAY8Ptr port, CARD16 *type)
215 data = NetaddrPort(from, &length);
216 XdmcpAllocARRAY8 (port, length);
217 memmove( port->data, data, length);
218 port->length = length;
220 family = ConvertAddr((char *)from, &length, &data);
222 XdmcpAllocARRAY8 (addr, length);
223 memmove( addr->data, data, length);
224 addr->length = length;
230 all_query_respond (struct sockaddr *from, int fromlen, ARRAYofARRAY8Ptr authenticationNames, xdmOpCode type)
232 ARRAY8Ptr authenticationName;
235 CARD16 connectionType;
239 family = ConvertAddr((char *)from, &length, (char **) &(addr.data));
241 addr.length = length; /* convert int to short */
242 Debug ("all_query_respond: conntype=%d, addr=%lx, len=%d\n",
243 family, *(addr.data), addr.length);
246 connectionType = family;
248 if (type == INDIRECT_QUERY)
249 RememberIndirectClient (&addr, connectionType);
251 ForgetIndirectClient (&addr, connectionType);
253 authenticationName = ChooseAuthentication (authenticationNames);
254 if (Willing (&addr, connectionType, authenticationName, &status, type))
255 send_willing (from, fromlen, authenticationName, &status);
258 send_unwilling (from, fromlen, authenticationName, &status);
259 XdmcpDisposeARRAY8 (&status);
263 indirect_respond (struct sockaddr *from, int fromlen, int length)
265 ARRAYofARRAY8 queryAuthenticationNames;
266 ARRAY8 clientAddress;
268 CARD16 connectionType;
274 Debug ("Indirect respond %d\n", length);
275 if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
278 for (i = 0; i < (int)queryAuthenticationNames.length; i++)
279 expectedLen += 2 + queryAuthenticationNames.data[i].length;
280 if (length == expectedLen)
282 ClientAddress (from, &clientAddress, &clientPort, &connectionType);
284 * set up the forward query packet
286 header.version = XDM_PROTOCOL_VERSION;
287 header.opcode = (CARD16) FORWARD_QUERY;
289 header.length += 2 + clientAddress.length;
290 header.length += 2 + clientPort.length;
292 for (i = 0; i < (int)queryAuthenticationNames.length; i++)
293 header.length += 2 + queryAuthenticationNames.data[i].length;
294 XdmcpWriteHeader (&buffer, &header);
295 XdmcpWriteARRAY8 (&buffer, &clientAddress);
296 XdmcpWriteARRAY8 (&buffer, &clientPort);
297 XdmcpWriteARRAYofARRAY8 (&buffer, &queryAuthenticationNames);
299 localHostAsWell = ForEachMatchingIndirectHost (&clientAddress, connectionType, sendForward, (char *) 0);
301 XdmcpDisposeARRAY8 (&clientAddress);
302 XdmcpDisposeARRAY8 (&clientPort);
304 all_query_respond (from, fromlen, &queryAuthenticationNames,
309 Debug ("Indirect length error got %d expect %d\n", length, expectedLen);
311 XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
315 ProcessRequestSocket (void)
318 struct sockaddr_in addr;
319 int addrlen = sizeof addr;
321 Debug ("ProcessRequestSocket\n");
322 bzero ((char *) &addr, sizeof (addr));
323 if (!XdmcpFill (xdmcpFd, &buffer, (XdmcpNetaddr)&addr, &addrlen)) {
324 Debug ("XdmcpFill failed\n");
327 if (!XdmcpReadHeader (&buffer, &header)) {
328 Debug ("XdmcpReadHeader failed\n");
331 if (header.version != XDM_PROTOCOL_VERSION) {
332 Debug ("XDMCP header version read was %d, expected %d\n",
333 header.version, XDM_PROTOCOL_VERSION);
336 Debug ("header: %d %d %d\n", header.version, header.opcode, header.length);
337 switch (header.opcode)
339 case BROADCAST_QUERY:
340 broadcast_respond ((struct sockaddr *)&addr, addrlen, header.length);
343 query_respond ((struct sockaddr *)&addr, addrlen, header.length);
346 indirect_respond ((struct sockaddr *)&addr, addrlen, header.length);
349 forward_respond ((struct sockaddr *)&addr, addrlen, header.length);
352 request_respond ((struct sockaddr *)&addr, addrlen, header.length);
355 manage ((struct sockaddr *)&addr, addrlen, header.length);
358 send_alive ((struct sockaddr *)&addr, addrlen, header.length);
364 * dtlogin changes to WaitForSomething () merged in to support command line
367 void WaitForSomething (void)
370 struct timeval timeout, *ptimeout;
372 extern int Rescan, ChildReady, wakeupTime;
374 Debug ("WaitForSomething\n");
375 if (AnyWellKnownSockets () && !ChildReady || wakeupTime > 0 ) {
376 reads = WellKnownSocketsMask;
378 if (wakeupTime >= 0 ) {
379 timeout.tv_sec = wakeupTime;
380 timeout.tv_usec = 10;
382 Debug("Setting timer on select() for %d seconds.\n", wakeupTime);
388 nready = select (WellKnownSocketsMax + 1, (int *) &reads, 0, 0, ptimeout);
390 nready = select (WellKnownSocketsMax + 1, &reads, 0, 0, ptimeout);
392 Debug ("select returns %d. Rescan: %d ChildReady: %d\n",
393 nready, Rescan, ChildReady);
396 if (xdmcpFd >= 0 && FD_ISSET (xdmcpFd, &reads))
397 ProcessRequestSocket ();
398 if (chooserFd >= 0 && FD_ISSET (chooserFd, &reads))
399 ProcessChooserSocket (chooserFd);
412 * respond to a request on the UDP socket.
415 static ARRAY8 Hostname;
418 registerHostname (char *name, int namelen)
422 if (!XdmcpReallocARRAY8 (&Hostname, namelen))
424 for (i = 0; i < namelen; i++)
425 Hostname.data[i] = name[i];
429 direct_query_respond (struct sockaddr *from, int fromlen, int length, xdmOpCode type)
431 ARRAYofARRAY8 queryAuthenticationNames;
435 if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
438 for (i = 0; i < (int)queryAuthenticationNames.length; i++)
439 expectedLen += 2 + queryAuthenticationNames.data[i].length;
440 if (length == expectedLen)
441 all_query_respond (from, fromlen, &queryAuthenticationNames, type);
442 XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
446 query_respond (struct sockaddr *from, int fromlen, int length)
448 Debug ("Query respond %d\n", length);
449 direct_query_respond (from, fromlen, length, QUERY);
453 broadcast_respond (struct sockaddr *from, int fromlen, int length)
455 direct_query_respond (from, fromlen, length, BROADCAST_QUERY);
458 /* computes an X display name */
459 #if NeedWidePrototypes
461 NetworkAddressToName(int connectionType, ARRAY8Ptr connectionAddress, int displayNumber)
464 NetworkAddressToName(CARD16 connectionType, ARRAY8Ptr connectionAddress, CARD16 displayNumber)
467 switch (connectionType)
472 struct hostent *hostent;
474 char *localhost, *localHostname();
476 data = connectionAddress->data;
477 hostent = gethostbyaddr ((char *)data,
478 connectionAddress->length, AF_INET);
480 localhost = localHostname ();
483 * protect against bogus host names
485 if (hostent && hostent->h_name && hostent->h_name[0]
486 && (hostent->h_name[0] != '.'))
488 if (!strcmp (localhost, hostent->h_name))
490 if (!getString (name, 10))
492 sprintf (name, ":%d", displayNumber);
496 if (removeDomainname)
498 char *localDot, *remoteDot;
500 /* check for a common domain name. This
501 * could reduce names by recognising common
502 * super-domain names as well, but I don't think
503 * this is as useful, and will confuse more
506 if ((localDot = strchr(localhost, '.')) &&
507 (remoteDot = strchr(hostent->h_name, '.')))
509 /* smash the name in place; it won't
512 if (!strcmp (localDot+1, remoteDot+1))
517 if (!getString (name, strlen (hostent->h_name) + 10))
519 sprintf (name, "%s:%d", hostent->h_name, displayNumber);
524 if (!getString (name, 25))
526 sprintf(name, "%d.%d.%d.%d:%d",
527 data[0], data[1], data[2], data[3], displayNumber);
542 forward_respond (struct sockaddr *from, int fromlen, int length)
544 ARRAY8 clientAddress;
546 ARRAYofARRAY8 authenticationNames;
547 struct sockaddr *client;
552 Debug ("Forward respond %d\n", length);
553 clientAddress.length = 0;
554 clientAddress.data = 0;
555 clientPort.length = 0;
557 authenticationNames.length = 0;
558 authenticationNames.data = 0;
559 if (XdmcpReadARRAY8 (&buffer, &clientAddress) &&
560 XdmcpReadARRAY8 (&buffer, &clientPort) &&
561 XdmcpReadARRAYofARRAY8 (&buffer, &authenticationNames))
564 expectedLen += 2 + clientAddress.length;
565 expectedLen += 2 + clientPort.length;
566 expectedLen += 1; /* authenticationNames */
567 for (i = 0; i < (int)authenticationNames.length; i++)
568 expectedLen += 2 + authenticationNames.data[i].length;
569 if (length == expectedLen)
574 for (i = 0; i < (int)clientPort.length; i++)
575 j = j * 256 + clientPort.data[i];
576 Debug ("Forward client address (port %d)", j);
577 for (i = 0; i < (int)clientAddress.length; i++)
578 Debug (" %d", clientAddress.data[i]);
580 switch (from->sa_family)
585 static struct sockaddr_in in_addr;
587 if (clientAddress.length != 4 ||
588 clientPort.length != 2)
592 bzero ((char *) &in_addr, sizeof (in_addr));
594 in_addr.sin_len = sizeof(in_addr);
596 in_addr.sin_family = AF_INET;
597 memmove( &in_addr.sin_addr, clientAddress.data, 4);
598 memmove( (char *) &in_addr.sin_port, clientPort.data, 2);
599 client = (struct sockaddr *) &in_addr;
600 clientlen = sizeof (in_addr);
607 static struct sockaddr_un un_addr;
609 if (clientAddress.length >= sizeof (un_addr.sun_path))
611 bzero ((char *) &un_addr, sizeof (un_addr));
612 un_addr.sun_family = AF_UNIX;
613 memmove( un_addr.sun_path, clientAddress.data, clientAddress.length);
614 un_addr.sun_path[clientAddress.length] = '\0';
615 client = (struct sockaddr *) &un_addr;
617 un_addr.sun_len = strlen(un_addr.sun_path);
618 clientlen = SUN_LEN(&un_addr);
620 clientlen = sizeof (un_addr);
634 all_query_respond (client, clientlen, &authenticationNames,
639 Debug ("Forward length error got %d expect %d\n", length, expectedLen);
643 XdmcpDisposeARRAY8 (&clientAddress);
644 XdmcpDisposeARRAY8 (&clientPort);
645 XdmcpDisposeARRAYofARRAY8 (&authenticationNames);
649 send_willing (struct sockaddr *from, int fromlen, ARRAY8Ptr authenticationName, ARRAY8Ptr status)
653 Debug ("Send willing %*.*s %*.*s\n", authenticationName->length,
654 authenticationName->length,
655 pS(authenticationName->data),
659 header.version = XDM_PROTOCOL_VERSION;
660 header.opcode = (CARD16) WILLING;
661 header.length = 6 + authenticationName->length +
662 Hostname.length + status->length;
663 XdmcpWriteHeader (&buffer, &header);
664 XdmcpWriteARRAY8 (&buffer, authenticationName);
665 XdmcpWriteARRAY8 (&buffer, &Hostname);
666 XdmcpWriteARRAY8 (&buffer, status);
667 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)from, fromlen);
671 send_unwilling (struct sockaddr *from, int fromlen, ARRAY8Ptr authenticationName, ARRAY8Ptr status)
675 Debug ("Send unwilling %*.*s %*.*s\n", authenticationName->length,
676 authenticationName->length,
677 pS(authenticationName->data),
681 header.version = XDM_PROTOCOL_VERSION;
682 header.opcode = (CARD16) UNWILLING;
683 header.length = 4 + Hostname.length + status->length;
684 XdmcpWriteHeader (&buffer, &header);
685 XdmcpWriteARRAY8 (&buffer, &Hostname);
686 XdmcpWriteARRAY8 (&buffer, status);
687 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)from, fromlen);
690 static unsigned long globalSessionID;
692 #define NextSessionID() (++globalSessionID)
695 init_session_id(void)
697 /* Set randomly so we are unlikely to reuse id's from a previous
698 * incarnation so we don't say "Alive" to those displays.
699 * Start with low digits 0 to make debugging easier.
701 globalSessionID = (time((Time_t)0)&0x7fff) * 16000;
704 static ARRAY8 outOfMemory = { (CARD16) 13, (CARD8Ptr) "Out of memory" };
705 static ARRAY8 noValidAddr = { (CARD16) 16, (CARD8Ptr) "No valid address" };
706 static ARRAY8 noValidAuth = { (CARD16) 22, (CARD8Ptr) "No valid authorization" };
707 static ARRAY8 noAuthentic = { (CARD16) 29, (CARD8Ptr) "XDM has no authentication key" };
710 request_respond (struct sockaddr *from, int fromlen, int length)
712 CARD16 displayNumber;
713 ARRAY16 connectionTypes;
714 ARRAYofARRAY8 connectionAddresses;
715 ARRAY8 authenticationName;
716 ARRAY8 authenticationData;
717 ARRAYofARRAY8 authorizationNames;
718 ARRAY8 manufacturerDisplayID;
722 struct protoDisplay *pdpy;
723 ARRAY8 authorizationName, authorizationData;
724 ARRAY8Ptr connectionAddress;
726 Debug ("Request respond %d\n", length);
727 connectionTypes.data = 0;
728 connectionAddresses.data = 0;
729 authenticationName.data = 0;
730 authenticationData.data = 0;
731 authorizationNames.data = 0;
732 authorizationName.length = 0;
733 authorizationData.length = 0;
734 manufacturerDisplayID.data = 0;
735 if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
736 XdmcpReadARRAY16 (&buffer, &connectionTypes) &&
737 XdmcpReadARRAYofARRAY8 (&buffer, &connectionAddresses) &&
738 XdmcpReadARRAY8 (&buffer, &authenticationName) &&
739 XdmcpReadARRAY8 (&buffer, &authenticationData) &&
740 XdmcpReadARRAYofARRAY8 (&buffer, &authorizationNames) &&
741 XdmcpReadARRAY8 (&buffer, &manufacturerDisplayID))
744 expectlen += 2; /* displayNumber */
745 expectlen += 1 + 2*connectionTypes.length; /* connectionTypes */
746 expectlen += 1; /* connectionAddresses */
747 for (i = 0; i < (int)connectionAddresses.length; i++)
748 expectlen += 2 + connectionAddresses.data[i].length;
749 expectlen += 2 + authenticationName.length; /* authenticationName */
750 expectlen += 2 + authenticationData.length; /* authenticationData */
751 expectlen += 1; /* authoriationNames */
752 for (i = 0; i < (int)authorizationNames.length; i++)
753 expectlen += 2 + authorizationNames.data[i].length;
754 expectlen += 2 + manufacturerDisplayID.length; /* displayID */
755 if (expectlen != length)
757 Debug ("Request length error got %d expect %d\n", length, expectlen);
760 if (connectionTypes.length == 0 ||
761 connectionAddresses.length != connectionTypes.length)
763 reason = &noValidAddr;
767 pdpy = FindProtoDisplay (from, fromlen, displayNumber);
770 /* Check this Display against the Manager's policy */
771 reason = Accept (from, fromlen, displayNumber);
775 /* Check the Display's stream services against Manager's policy */
776 i = SelectConnectionTypeIndex (&connectionTypes,
777 &connectionAddresses);
779 reason = &noValidAddr;
783 /* The Manager considers this a new session */
784 connectionAddress = &connectionAddresses.data[i];
785 pdpy = NewProtoDisplay (from, fromlen, displayNumber,
786 connectionTypes.data[i], connectionAddress,
788 Debug ("NewProtoDisplay 0x%x\n", pdpy);
790 reason = &outOfMemory;
794 if (authorizationNames.length == 0)
797 j = SelectAuthorizationTypeIndex (&authenticationName,
798 &authorizationNames);
801 reason = &noValidAuth;
804 if (!CheckAuthentication (pdpy,
805 &manufacturerDisplayID,
807 &authenticationData))
809 reason = &noAuthentic;
812 if (j < (int)authorizationNames.length)
815 SetProtoDisplayAuthorization (pdpy,
816 (unsigned short) authorizationNames.data[j].length,
817 (char *) authorizationNames.data[j].data);
818 auth = pdpy->xdmcpAuthorization;
820 auth = pdpy->fileAuthorization;
823 authorizationName.length = auth->name_length;
824 authorizationName.data = (CARD8Ptr) auth->name;
825 authorizationData.length = auth->data_length;
826 authorizationData.data = (CARD8Ptr) auth->data;
831 send_accept (from, fromlen, pdpy->sessionID,
840 send_decline (from, fromlen, &authenticationName,
844 DisposeProtoDisplay (pdpy);
848 XdmcpDisposeARRAY16 (&connectionTypes);
849 XdmcpDisposeARRAYofARRAY8 (&connectionAddresses);
850 XdmcpDisposeARRAY8 (&authenticationName);
851 XdmcpDisposeARRAY8 (&authenticationData);
852 XdmcpDisposeARRAYofARRAY8 (&authorizationNames);
853 XdmcpDisposeARRAY8 (&manufacturerDisplayID);
857 send_accept (struct sockaddr *to, int tolen, CARD32 sessionID, ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData, ARRAY8Ptr authorizationName, ARRAY8Ptr authorizationData)
861 Debug ("Accept Session ID %d\n", sessionID);
862 header.version = XDM_PROTOCOL_VERSION;
863 header.opcode = (CARD16) ACCEPT;
864 header.length = 4; /* session ID */
865 header.length += 2 + authenticationName->length;
866 header.length += 2 + authenticationData->length;
867 header.length += 2 + authorizationName->length;
868 header.length += 2 + authorizationData->length;
869 XdmcpWriteHeader (&buffer, &header);
870 XdmcpWriteCARD32 (&buffer, sessionID);
871 XdmcpWriteARRAY8 (&buffer, authenticationName);
872 XdmcpWriteARRAY8 (&buffer, authenticationData);
873 XdmcpWriteARRAY8 (&buffer, authorizationName);
874 XdmcpWriteARRAY8 (&buffer, authorizationData);
875 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)to, tolen);
879 send_decline (struct sockaddr *to, int tolen, ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData, ARRAY8Ptr status)
883 Debug ("Decline %*.*s\n", status->length, status->length, pS(status->data));
884 header.version = XDM_PROTOCOL_VERSION;
885 header.opcode = (CARD16) DECLINE;
887 header.length += 2 + status->length;
888 header.length += 2 + authenticationName->length;
889 header.length += 2 + authenticationData->length;
890 XdmcpWriteHeader (&buffer, &header);
891 XdmcpWriteARRAY8 (&buffer, status);
892 XdmcpWriteARRAY8 (&buffer, authenticationName);
893 XdmcpWriteARRAY8 (&buffer, authenticationData);
894 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)to, tolen);
898 manage (struct sockaddr *from, int fromlen, int length)
901 CARD16 displayNumber;
904 struct protoDisplay *pdpy;
908 XdmcpNetaddr from_save;
909 ARRAY8 clientAddress, clientPort;
910 CARD16 connectionType;
912 Debug ("Manage %d\n", length);
913 displayClass.data = 0;
914 displayClass.length = 0;
915 if (XdmcpReadCARD32 (&buffer, &sessionID) &&
916 XdmcpReadCARD16 (&buffer, &displayNumber) &&
917 XdmcpReadARRAY8 (&buffer, &displayClass))
919 expectlen = 4 + /* session ID */
920 2 + /* displayNumber */
921 2 + displayClass.length; /* displayClass */
922 if (expectlen != length)
924 Debug ("Manage length error got %d expect %d\n", length, expectlen);
927 pdpy = FindProtoDisplay (from, fromlen, displayNumber);
928 Debug ("Manage Session ID %d, pdpy 0x%x\n", sessionID, pdpy);
929 if (!pdpy || pdpy->sessionID != sessionID)
932 * We may have already started a session for this display
933 * but it hasn't seen the response in the form of an
934 * XOpenDisplay() yet. So check if it is in the list of active
935 * displays, and if so check that the session id's match.
936 * If all this is true, then we have a duplicate request that
940 && (d = FindDisplayByAddress(from, fromlen, displayNumber))
941 && d->sessionID == sessionID) {
942 Debug("manage: got duplicate pkt, ignoring\n");
945 Debug ("Session ID %d refused\n", sessionID);
947 Debug ("Existing Session ID %d\n", pdpy->sessionID);
948 send_refuse (from, fromlen, sessionID);
952 name = NetworkAddressToName (pdpy->connectionType,
953 &pdpy->connectionAddress,
954 pdpy->displayNumber);
955 Debug ("Computed display name: %s\n", name);
958 send_failed (from, fromlen, "(no name)", sessionID, "out of memory");
961 d = FindDisplayByName (name);
964 extern void StopDisplay ();
966 Debug ("Terminating active session for %s\n", d->name);
969 class = malloc (displayClass.length + 1);
972 send_failed (from, fromlen, name, sessionID, "out of memory");
975 if (displayClass.length)
977 memmove( class, displayClass.data, displayClass.length);
978 class[displayClass.length] = '\0';
982 free ((char *) class);
983 class = (char *) NULL;
985 from_save = (XdmcpNetaddr) malloc (fromlen);
988 send_failed (from, fromlen, name, sessionID, "out of memory");
991 memmove( from_save, from, fromlen);
992 d = NewDisplay (name, class);
995 free ((char *) from_save);
996 send_failed (from, fromlen, name, sessionID, "out of memory");
999 d->displayType.location = Foreign;
1000 d->displayType.lifetime = Transient;
1001 d->displayType.origin = FromXDMCP;
1002 d->sessionID = pdpy->sessionID;
1003 d->from = (struct sockaddr *)from_save;
1004 d->fromlen = fromlen;
1005 d->displayNumber = pdpy->displayNumber;
1008 #endif /* BYPASSLOGIN */
1009 ClientAddress (from, &clientAddress, &clientPort, &connectionType);
1011 if (IsIndirectClient (&clientAddress, connectionType))
1013 Debug ("IsIndirectClient\n");
1014 ForgetIndirectClient (&clientAddress, connectionType);
1015 if (UseChooser (&clientAddress, connectionType))
1018 Debug ("Use chooser for %s\n", d->name);
1021 d->clientAddr = clientAddress;
1022 d->connectionType = connectionType;
1023 XdmcpDisposeARRAY8 (&clientPort);
1024 if (pdpy->fileAuthorization)
1026 d->authorizations = (Xauth **) malloc (sizeof (Xauth *));
1027 if (!d->authorizations)
1029 free ((char *) from_save);
1031 send_failed (from, fromlen, name, sessionID, "out of memory");
1034 d->authorizations[0] = pdpy->fileAuthorization;
1036 pdpy->fileAuthorization = 0;
1038 DisposeProtoDisplay (pdpy);
1039 Debug ("Starting display %s,%s\n", d->name, d->class);
1044 XdmcpDisposeARRAY8 (&displayClass);
1045 if (name) free ((char*) name);
1046 if (class) free ((char*) class);
1050 SendFailed (struct display *d, char *reason)
1052 Debug ("Display start failed, sending Failed\n");
1053 send_failed (d->from, d->fromlen, d->name, d->sessionID, reason);
1057 send_failed (struct sockaddr *from, int fromlen, char *name, CARD32 sessionID, char *reason)
1059 static char buf[256];
1063 sprintf (buf, "Session %d failed for display %s: %s",
1064 sessionID, name, reason);
1065 Debug ("Send failed %d %s\n", sessionID, buf);
1066 status.length = strlen (buf);
1067 status.data = (CARD8Ptr) buf;
1068 header.version = XDM_PROTOCOL_VERSION;
1069 header.opcode = (CARD16) FAILED;
1070 header.length = 6 + status.length;
1071 XdmcpWriteHeader (&buffer, &header);
1072 XdmcpWriteCARD32 (&buffer, sessionID);
1073 XdmcpWriteARRAY8 (&buffer, &status);
1074 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)from, fromlen);
1078 send_refuse (struct sockaddr *from, int fromlen, CARD32 sessionID)
1082 Debug ("Send refuse %d\n", sessionID);
1083 header.version = XDM_PROTOCOL_VERSION;
1084 header.opcode = (CARD16) REFUSE;
1086 XdmcpWriteHeader (&buffer, &header);
1087 XdmcpWriteCARD32 (&buffer, sessionID);
1088 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)from, fromlen);
1092 send_alive (struct sockaddr *from, int fromlen, int length)
1095 CARD16 displayNumber;
1099 CARD32 sendSessionID;
1101 Debug ("Send alive\n");
1102 if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
1103 XdmcpReadCARD32 (&buffer, &sessionID))
1107 d = FindDisplayBySessionID (sessionID);
1109 d = FindDisplayByAddress (from, fromlen, displayNumber);
1113 if (d && d->status == running)
1115 if (d->sessionID == sessionID)
1117 sendSessionID = d->sessionID;
1119 header.version = XDM_PROTOCOL_VERSION;
1120 header.opcode = (CARD16) ALIVE;
1122 Debug ("alive: %d %d\n", sendRunning, sendSessionID);
1123 XdmcpWriteHeader (&buffer, &header);
1124 XdmcpWriteCARD8 (&buffer, sendRunning);
1125 XdmcpWriteCARD32 (&buffer, sendSessionID);
1126 XdmcpFlush (xdmcpFd, &buffer, (XdmcpNetaddr)from, fromlen);
1131 #if NeedWidePrototypes
1133 NetworkAddressToHostname (int connectionType, ARRAY8Ptr connectionAddress)
1136 NetworkAddressToHostname (CARD16 connectionType, ARRAY8Ptr connectionAddress)
1141 switch (connectionType)
1143 case FamilyInternet:
1145 struct hostent *hostent;
1149 hostent = gethostbyaddr ((char *)connectionAddress->data,
1150 connectionAddress->length, AF_INET);
1153 local_name = hostent->h_name;
1155 /* can't get name, so use emergency fallback */
1156 sprintf(dotted, "%d.%d.%d.%d",
1157 connectionAddress->data[0],
1158 connectionAddress->data[1],
1159 connectionAddress->data[2],
1160 connectionAddress->data[3]);
1161 local_name = dotted;
1163 LogError ((unsigned char *)"Cannot convert Internet address %s to host name\n",
1166 if (!getString (name, strlen (local_name)))
1168 strcpy (name, local_name);
1182 HostnameToNetworkAddress (char *name, CARD16 connectionType, ARRAY8Ptr connectionAddress)
1184 switch (connectionType)
1186 case FamilyInternet:
1188 struct hostent *hostent;
1190 hostent = gethostbyname (name);
1193 if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
1195 memmove( connectionAddress->data, hostent->h_addr, hostent->h_length);
1207 * converts a display name into a network address, using
1208 * the same rules as XOpenDisplay (algorithm cribbed from there)
1212 NameToNetworkAddress(char *name, CARD16Ptr connectionTypep, ARRAY8Ptr connectionAddress, CARD16Ptr displayNumber)
1214 char *colon, *display_number;
1215 char hostname[1024];
1218 CARD16 connectionType;
1220 colon = strchr(name, ':');
1225 if (colon - name > sizeof (hostname))
1227 strncpy (hostname, name, colon - name);
1228 hostname[colon - name] = '\0';
1232 strcpy (hostname, localHostname ());
1234 if (colon[1] == ':')
1243 display_number = colon + 1;
1244 while (*display_number && *display_number != '.')
1246 if (!isascii (*display_number) || !isdigit(*display_number))
1249 if (display_number == colon + 1)
1251 number = atoi (colon + 1);
1254 connectionType = FamilyDECnet;
1257 connectionType = FamilyInternet;
1258 if (!HostnameToNetworkAddress (hostname, connectionType, connectionAddress))
1260 *displayNumber = number;
1261 *connectionTypep = connectionType;