Home | History | Annotate | Line # | Download | only in xdm
      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  * choose.c
     31  *
     32  * xdm interface to chooser program
     33  */
     34 
     35 #include "dm.h"
     36 #include "dm_error.h"
     37 
     38 #ifdef XDMCP
     39 
     40 # include <X11/X.h>
     41 # include <sys/types.h>
     42 
     43 # include "dm_socket.h"
     44 # include <arpa/inet.h>
     45 # include <sys/un.h>
     46 
     47 # include <ctype.h>
     48 # include <errno.h>
     49 
     50 # ifdef HAVE_SETPROCTITLE
     51 #  include <unistd.h>
     52 # endif
     53 
     54 # include <time.h>
     55 # define Time_t time_t
     56 
     57 static int
     58 FormatBytes (
     59     unsigned char *data,
     60     int	    length,
     61     char    *buf,
     62     int	    buflen)
     63 {
     64     int	    i;
     65     static char	    HexChars[] = "0123456789abcdef";
     66 
     67     if (buflen < length * 2 + 1)
     68 	return 0;
     69     for (i = 0; i < length; i++)
     70     {
     71 	*buf++ = HexChars[(data[i] >> 4) & 0xf];
     72 	*buf++ = HexChars[(data[i]) & 0xf];
     73     }
     74     *buf++ = '\0';
     75     return 1;
     76 }
     77 
     78 static int
     79 FormatARRAY8 (
     80     ARRAY8Ptr	a,
     81     char	*buf,
     82     int		buflen)
     83 {
     84     return FormatBytes (a->data, a->length, buf, buflen);
     85 }
     86 
     87 /* Converts an Internet address in ARRAY8 format to a string in
     88    familiar dotted address notation, e.g., "18.24.0.11"
     89    Returns 1 if successful, 0 if not.
     90    */
     91 static int
     92 ARRAY8ToDottedDecimal (
     93     ARRAY8Ptr	a,
     94     char	*buf,
     95     int		buflen)
     96 {
     97     int outlen;
     98     if (a->length != 4)
     99 	return 0;
    100     outlen = snprintf(buf, buflen, "%d.%d.%d.%d",
    101 		      a->data[0], a->data[1], a->data[2], a->data[3]);
    102     if (outlen >= buflen) {
    103 	return 0;
    104     }
    105     return 1;
    106 }
    107 
    108 typedef struct _IndirectUsers {
    109     struct _IndirectUsers   *next;
    110     ARRAY8	client;
    111     CARD16	connectionType;
    112 } IndirectUsersRec, *IndirectUsersPtr;
    113 
    114 static IndirectUsersPtr	indirectUsers;
    115 
    116 int
    117 RememberIndirectClient (
    118     ARRAY8Ptr	clientAddress,
    119     CARD16	connectionType)
    120 {
    121     IndirectUsersPtr	i;
    122 
    123     for (i = indirectUsers; i; i = i->next)
    124 	if (XdmcpARRAY8Equal (clientAddress, &i->client) &&
    125 	    connectionType == i->connectionType)
    126 	    return 1;
    127     i = malloc (sizeof (IndirectUsersRec));
    128     if (!i)
    129     {
    130 	LogOutOfMem ("RememberIndirectClient\n");
    131 	return 0;
    132     }
    133     if (!XdmcpCopyARRAY8 (clientAddress, &i->client))
    134     {
    135 	free (i);
    136 	return 0;
    137     }
    138     i->connectionType = connectionType;
    139     i->next = indirectUsers;
    140     indirectUsers = i;
    141     return 1;
    142 }
    143 
    144 void
    145 ForgetIndirectClient (
    146     ARRAY8Ptr	clientAddress,
    147     CARD16	connectionType)
    148 {
    149     IndirectUsersPtr	i, prev;
    150 
    151     prev = NULL;
    152     for (i = indirectUsers; i; i = i->next)
    153     {
    154 	if (XdmcpARRAY8Equal (clientAddress, &i->client) &&
    155 	    connectionType == i->connectionType)
    156 	{
    157 	    if (prev)
    158 		prev->next = i->next;
    159 	    else
    160 		indirectUsers = i->next;
    161 	    XdmcpDisposeARRAY8 (&i->client);
    162 	    free (i);
    163 	    break;
    164 	}
    165 	prev = i;
    166     }
    167 }
    168 
    169 int
    170 IsIndirectClient (
    171     ARRAY8Ptr	clientAddress,
    172     CARD16	connectionType)
    173 {
    174     IndirectUsersPtr	i;
    175 
    176     for (i = indirectUsers; i; i = i->next)
    177 	if (XdmcpARRAY8Equal (clientAddress, &i->client) &&
    178 	    connectionType == i->connectionType)
    179 	    return 1;
    180     return 0;
    181 }
    182 
    183 static int
    184 FormatChooserArgument (char *buf, int len)
    185 {
    186     unsigned char   addr_buf[1024];
    187     int		    addr_len = sizeof (addr_buf);
    188     unsigned char   result_buf[1024];
    189     int		    result_len = 0;
    190     int		    netfamily;
    191 
    192     if (GetChooserAddr ((char *)addr_buf, &addr_len) == -1)
    193     {
    194 	LogError ("Cannot get return address for chooser socket\n");
    195 	Debug ("Cannot get chooser socket address\n");
    196 	return 0;
    197     }
    198     netfamily = NetaddrFamily((XdmcpNetaddr)addr_buf);
    199     switch (netfamily) {
    200     case AF_INET:
    201 # ifdef IPv6
    202     case AF_INET6:
    203 # endif
    204 	{
    205 	    char *port;
    206 	    int portlen;
    207 	    ARRAY8Ptr localAddress = getLocalAddress ();
    208 
    209 # ifdef IPv6
    210 	    if (localAddress->length == 16)
    211 		netfamily = AF_INET6;
    212 	    else
    213 		netfamily = AF_INET;
    214 # endif
    215 
    216 	    port = NetaddrPort((XdmcpNetaddr)addr_buf, &portlen);
    217 	    if (port == NULL) {
    218 		LogError ("Cannot get port for chooser socket\n");
    219 		return 0;
    220 	    }
    221 	    result_buf[0] = netfamily >> 8;
    222 	    result_buf[1] = netfamily & 0xFF;
    223 	    result_buf[2] = port[0];
    224 	    result_buf[3] = port[1];
    225 	    memcpy(result_buf+4, localAddress->data, localAddress->length);
    226 	    result_len = 4 + localAddress->length;
    227 	}
    228 	break;
    229     default:
    230 	Debug ("Chooser family %d isn't known\n", netfamily);
    231 	return 0;
    232     }
    233 
    234     return FormatBytes (result_buf, result_len, buf, len);
    235 }
    236 
    237 typedef struct _Choices {
    238     struct _Choices *next;
    239     ARRAY8	    client;
    240     CARD16	    connectionType;
    241     ARRAY8	    choice;
    242     Time_t	    time;
    243 } ChoiceRec, *ChoicePtr;
    244 
    245 static ChoicePtr   choices;
    246 
    247 ARRAY8Ptr
    248 IndirectChoice (
    249     ARRAY8Ptr	clientAddress,
    250     CARD16	connectionType)
    251 {
    252     ChoicePtr	c, next, prev;
    253     Time_t	now;
    254 
    255     now = time ((Time_t*)0);
    256     prev = NULL;
    257     for (c = choices; c; c = next)
    258     {
    259 	next = c->next;
    260 	Debug ("Choice checking timeout: %ld >? %d\n",
    261 	    (long)(now - c->time), choiceTimeout);
    262 	if (now - c->time > (Time_t)choiceTimeout)
    263 	{
    264 	    Debug ("Timeout choice %ld > %d\n",
    265 		(long)(now - c->time), choiceTimeout);
    266 	    if (prev)
    267 		prev->next = next;
    268 	    else
    269 		choices = next;
    270 	    XdmcpDisposeARRAY8 (&c->client);
    271 	    XdmcpDisposeARRAY8 (&c->choice);
    272 	    free (c);
    273 	}
    274 	else
    275 	{
    276 	    if (XdmcpARRAY8Equal (clientAddress, &c->client) &&
    277 		connectionType == c->connectionType)
    278 		return &c->choice;
    279 	    prev = c;
    280 	}
    281     }
    282     return NULL;
    283 }
    284 
    285 static int
    286 RegisterIndirectChoice (
    287     ARRAY8Ptr	clientAddress,
    288     CARD16      connectionType,
    289     ARRAY8Ptr	choice)
    290 {
    291     ChoicePtr	c;
    292     int		insert;
    293 
    294     Debug ("Got indirect choice back\n");
    295     for (c = choices; c; c = c->next) {
    296 	if (XdmcpARRAY8Equal (clientAddress, &c->client) &&
    297 	    connectionType == c->connectionType) {
    298 	    break;
    299 	}
    300     }
    301     insert = 0;
    302     if (!c)
    303     {
    304 	c = malloc (sizeof (ChoiceRec));
    305 	insert = 1;
    306 	if (!c)
    307 	    return 0;
    308 	c->connectionType = connectionType;
    309 	if (!XdmcpCopyARRAY8 (clientAddress, &c->client))
    310 	{
    311 	    free (c);
    312 	    return 0;
    313 	}
    314     }
    315     else
    316     {
    317 	XdmcpDisposeARRAY8 (&c->choice);
    318     }
    319     if (!XdmcpCopyARRAY8 (choice, &c->choice))
    320     {
    321 	XdmcpDisposeARRAY8 (&c->client);
    322 	free (c);
    323 	return 0;
    324     }
    325     if (insert)
    326     {
    327 	c->next = choices;
    328 	choices = c;
    329     }
    330     c->time = time ((Time_t *) 0);
    331     return 1;
    332 }
    333 
    334 # ifdef notdef
    335 static
    336 RemoveIndirectChoice (clientAddress, connectionType)
    337     ARRAY8Ptr	clientAddress;
    338     CARD16	connectionType;
    339 {
    340     ChoicePtr	c, prev;
    341 
    342     prev = 0;
    343     for (c = choices; c; c = c->next)
    344     {
    345 	if (XdmcpARRAY8Equal (clientAddress, &c->client) &&
    346 	    connectionType == c->connectionType)
    347 	{
    348 	    if (prev)
    349 		prev->next = c->next;
    350 	    else
    351 		choices = c->next;
    352 	    XdmcpDisposeARRAY8 (&c->client);
    353 	    XdmcpDisposeARRAY8 (&c->choice);
    354 	    free (c);
    355 	    return;
    356 	}
    357 	prev = c;
    358     }
    359 }
    360 # endif
    361 
    362 /*ARGSUSED*/
    363 static void
    364 AddChooserHost (
    365     CARD16	connectionType,
    366     ARRAY8Ptr	addr,
    367     char	*closure)
    368 {
    369     char	***argp;
    370     char	hostbuf[1024];
    371 
    372     argp = (char ***) closure;
    373     if (addr->length == strlen ("BROADCAST") &&
    374 	!strncmp ((char *)addr->data, "BROADCAST", addr->length))
    375     {
    376 	*argp = parseArgs (*argp, "BROADCAST");
    377     }
    378 # ifdef IPv6
    379     else if ( (addr->length == 16) &&
    380       (inet_ntop(AF_INET6, addr->data, hostbuf, sizeof(hostbuf))))
    381     {
    382 	*argp = parseArgs (*argp, hostbuf);
    383     }
    384 # endif
    385     else if (ARRAY8ToDottedDecimal (addr, hostbuf, sizeof (hostbuf)))
    386     {
    387 	*argp = parseArgs (*argp, hostbuf);
    388     }
    389 }
    390 
    391 void
    392 ProcessChooserSocket (int fd)
    393 {
    394     int client_fd;
    395     char	buf[1024];
    396     int		len;
    397     XdmcpBuffer	buffer;
    398     ARRAY8	clientAddress = {0, NULL};
    399     CARD16	connectionType;
    400     ARRAY8	choice = {0, NULL};
    401 
    402     Debug ("Process chooser socket\n");
    403     len = sizeof (buf);
    404     client_fd = accept (fd, (struct sockaddr *)buf, (void *)&len);
    405     if (client_fd == -1)
    406     {
    407 	LogError ("Cannot accept chooser connection\n");
    408 	return;
    409     }
    410     Debug ("Accepted %d\n", client_fd);
    411 
    412     len = read (client_fd, buf, sizeof (buf));
    413     Debug ("Read returns %d\n", len);
    414     if (len > 0)
    415     {
    416 	buffer.data = (BYTE *) buf;
    417 	buffer.size = sizeof (buf);
    418 	buffer.count = len;
    419 	buffer.pointer = 0;
    420 	if (XdmcpReadARRAY8 (&buffer, &clientAddress)) {
    421 	    if (XdmcpReadCARD16 (&buffer, &connectionType)) {
    422 		if (XdmcpReadARRAY8 (&buffer, &choice)) {
    423 		    Debug ("Read from chooser successfully\n");
    424 		    RegisterIndirectChoice (&clientAddress, connectionType, &choice);
    425 		    XdmcpDisposeARRAY8 (&choice);
    426 		} else {
    427 		    LogError ("Invalid choice response length %d\n", len);
    428 		}
    429 	    } else {
    430 		LogError ("Invalid choice response length %d\n", len);
    431 	    }
    432 	    XdmcpDisposeARRAY8 (&clientAddress);
    433 	} else {
    434 	    LogError ("Invalid choice response length %d\n", len);
    435 	}
    436     }
    437     else
    438     {
    439 	LogError ("Choice response read error: %s\n", _SysErrorMsg(errno));
    440     }
    441 
    442     close (client_fd);
    443 }
    444 
    445 void
    446 RunChooser (struct display *d)
    447 {
    448     char    **args;
    449     char    buf[1024];
    450     char    **env;
    451 
    452     Debug ("RunChooser %s\n", d->name);
    453 # ifndef HAVE_SETPROCTITLE
    454     SetTitle (d->name, "chooser", (char *) 0);
    455 # else
    456     setproctitle("chooser %s", d->name);
    457 # endif
    458     LoadXloginResources (d);
    459     args = parseArgs ((char **) 0, d->chooser);
    460     strcpy (buf, "-xdmaddress ");
    461     if (FormatChooserArgument (buf + strlen (buf), sizeof (buf) - strlen (buf)))
    462 	args = parseArgs (args, buf);
    463     strcpy (buf, "-clientaddress ");
    464     if (FormatARRAY8 (&d->clientAddr, buf + strlen (buf), sizeof (buf) - strlen (buf)))
    465 	args = parseArgs (args, buf);
    466     snprintf (buf, sizeof(buf), "-connectionType %d", d->connectionType);
    467     args = parseArgs (args, buf);
    468     ForEachChooserHost (&d->clientAddr, d->connectionType, AddChooserHost,
    469 			(char *) &args);
    470     env = systemEnv (d, (char *) 0, (char *) 0);
    471     Debug ("Running %s\n", args[0]);
    472     execute (args, env);
    473     Debug ("Couldn't run %s\n", args[0]);
    474     LogError ("Cannot execute %s\n", args[0]);
    475     exit (REMANAGE_DISPLAY);
    476 }
    477 
    478 #endif /* XDMCP */
    479