~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kdm/backend/choose.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright 1990, 1998  The Open Group
 
4
Copyright 2002-2004 Oswald Buddenhagen <ossi@kde.org>
 
5
 
 
6
Permission to use, copy, modify, distribute, and sell this software and its
 
7
documentation for any purpose is hereby granted without fee, provided that
 
8
the above copyright notice appear in all copies and that both that
 
9
copyright notice and this permission notice appear in supporting
 
10
documentation.
 
11
 
 
12
The above copyright notice and this permission notice shall be included
 
13
in all copies or substantial portions of the Software.
 
14
 
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
16
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
19
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
21
OTHER DEALINGS IN THE SOFTWARE.
 
22
 
 
23
Except as contained in this notice, the name of a copyright holder shall
 
24
not be used in advertising or otherwise to promote the sale, use or
 
25
other dealings in this Software without prior written authorization
 
26
from the copyright holder.
 
27
 
 
28
*/
 
29
 
 
30
/*
 
31
 * xdm - display manager daemon
 
32
 * Author: Keith Packard, MIT X Consortium
 
33
 *
 
34
 * chooser backend
 
35
 */
 
36
 
 
37
#include "dm.h"
 
38
#include "dm_error.h"
 
39
#include "dm_socket.h"
 
40
 
 
41
#include <ctype.h>
 
42
#include <sys/ioctl.h>
 
43
#ifdef HAVE_SYS_SOCKIO_H
 
44
# include <sys/sockio.h>
 
45
#endif
 
46
#ifndef __GNU__
 
47
# include <net/if.h>
 
48
#endif
 
49
#include <arpa/inet.h>
 
50
#include <netdb.h>
 
51
 
 
52
#ifdef STREAMSCONN
 
53
# ifdef WINTCP /* NCR with Wollongong TCP */
 
54
#  include <netinet/ip.h>
 
55
# endif
 
56
# include <stropts.h>
 
57
# include <tiuser.h>
 
58
# include <netconfig.h>
 
59
# include <netdir.h>
 
60
#endif
 
61
 
 
62
typedef struct _Choices {
 
63
    struct _Choices *next;
 
64
    ARRAY8 client;
 
65
    ARRAY8 port;
 
66
    CARD16 connectionType;
 
67
    ARRAY8 choice;
 
68
    time_t timeout;
 
69
} ChoiceRec, *ChoicePtr;
 
70
 
 
71
static ChoicePtr choices;
 
72
 
 
73
time_t
 
74
disposeIndirectHosts()
 
75
{
 
76
    ChoicePtr c;
 
77
 
 
78
    while (choices) {
 
79
        if (choices->timeout > now)
 
80
            return choices->timeout;
 
81
        debug("timing out indirect host\n");
 
82
        c = choices;
 
83
        choices = c->next;
 
84
        XdmcpDisposeARRAY8(&c->client);
 
85
        XdmcpDisposeARRAY8(&c->port);
 
86
        XdmcpDisposeARRAY8(&c->choice);
 
87
        free(c);
 
88
    }
 
89
    return TO_INF;
 
90
}
 
91
 
 
92
ARRAY8Ptr
 
93
indirectChoice(ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
 
94
               CARD16 connectionType)
 
95
{
 
96
    ChoicePtr c;
 
97
 
 
98
    debug("have indirect choice?\n");
 
99
    for (c = choices; c; c = c->next)
 
100
        if (XdmcpARRAY8Equal(clientAddress, &c->client) &&
 
101
            XdmcpARRAY8Equal(clientPort, &c->port) &&
 
102
            connectionType == c->connectionType)
 
103
        {
 
104
            debug(c->choice.data ? "  yes\n" : "  not yet\n");
 
105
            return c->choice.data ? &c->choice : 0;
 
106
        }
 
107
    debug("  host not registered\n");
 
108
    return 0;
 
109
}
 
110
 
 
111
int
 
112
checkIndirectChoice(ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
 
113
                    CARD16 connectionType)
 
114
{
 
115
    ChoicePtr c, *cp;
 
116
    int uc;
 
117
 
 
118
    debug("checkIndirectChoice\n");
 
119
    for (cp = &choices; (c = *cp); cp = &c->next) {
 
120
        if (XdmcpARRAY8Equal(clientAddress, &c->client) &&
 
121
            XdmcpARRAY8Equal(clientPort, &c->port) &&
 
122
            connectionType == c->connectionType)
 
123
        {
 
124
            *cp = c->next;
 
125
            if (c->choice.data) {
 
126
                XdmcpDisposeARRAY8(&c->choice);
 
127
                debug("  choice already made\n");
 
128
                uc = False;
 
129
            } else {
 
130
                uc = True;
 
131
            }
 
132
            XdmcpDisposeARRAY8(&c->port);
 
133
            XdmcpDisposeARRAY8(&c->client);
 
134
            free(c);
 
135
            return uc;
 
136
        }
 
137
    }
 
138
    debug("  host not registered\n");
 
139
    return False;
 
140
}
 
141
 
 
142
void
 
143
registerIndirectChoice(ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
 
144
                       CARD16 connectionType, ARRAY8Ptr choice)
 
145
{
 
146
    ChoicePtr c, *cp;
 
147
 
 
148
    debug("registering indirect %s\n", choice ? "choice" : "client");
 
149
    for (cp = &choices; (c = *cp); cp = &c->next) {
 
150
        if (XdmcpARRAY8Equal(clientAddress, &c->client) &&
 
151
            XdmcpARRAY8Equal(clientPort, &c->port) &&
 
152
            connectionType == c->connectionType)
 
153
        {
 
154
            *cp = c->next;
 
155
            while (*cp)
 
156
                cp = &(*cp)->next;
 
157
            if (choice)
 
158
                XdmcpDisposeARRAY8(&c->choice);
 
159
            debug("  replacing existing\n");
 
160
            goto found;
 
161
        }
 
162
    }
 
163
 
 
164
    if (!(c = Malloc(sizeof(ChoiceRec))))
 
165
        return;
 
166
    if (!XdmcpCopyARRAY8(clientAddress, &c->client)) {
 
167
        free(c);
 
168
        return;
 
169
    }
 
170
    if (!XdmcpCopyARRAY8(clientPort, &c->port)) {
 
171
        XdmcpDisposeARRAY8(&c->client);
 
172
        free(c);
 
173
        return;
 
174
    }
 
175
    c->connectionType = connectionType;
 
176
    c->choice.data = 0;
 
177
  found:
 
178
    if (choice && !XdmcpCopyARRAY8(choice, &c->choice)) {
 
179
        XdmcpDisposeARRAY8(&c->port);
 
180
        XdmcpDisposeARRAY8(&c->client);
 
181
        free(c);
 
182
        return;
 
183
    }
 
184
    c->timeout = now + choiceTimeout;
 
185
    c->next = 0;
 
186
    *cp = c;
 
187
}
 
188
 
 
189
 
 
190
/* ####################### */
 
191
 
 
192
 
 
193
typedef struct _HostAddr {
 
194
    struct _HostAddr *next;
 
195
    struct sockaddr *addr;
 
196
    int addrlen;
 
197
    xdmOpCode type;
 
198
} HostAddr;
 
199
 
 
200
static HostAddr *hostAddrdb;
 
201
 
 
202
typedef struct _HostName {
 
203
    struct _HostName *next;
 
204
    unsigned willing:1, alive:1;
 
205
    ARRAY8 hostname, status;
 
206
    CARD16 connectionType;
 
207
    ARRAY8 hostaddr;
 
208
} HostName;
 
209
 
 
210
static HostName *hostNamedb;
 
211
 
 
212
static XdmcpBuffer directBuffer, broadcastBuffer;
 
213
static XdmcpBuffer buffer;
 
214
 
 
215
static int socketFD;
 
216
#if defined(IPv6) && defined(AF_INET6)
 
217
static int socket6FD;
 
218
#endif
 
219
 
 
220
 
 
221
static void
 
222
doPingHosts()
 
223
{
 
224
    HostAddr *hosts;
 
225
 
 
226
    for (hosts = hostAddrdb; hosts; hosts = hosts->next)
 
227
#if defined(IPv6) && defined(AF_INET6)
 
228
        XdmcpFlush(hosts->addr->sa_family == AF_INET6 ? socket6FD : socketFD,
 
229
#else
 
230
        XdmcpFlush(socketFD,
 
231
#endif
 
232
                   hosts->type == QUERY ? &directBuffer : &broadcastBuffer,
 
233
                   (XdmcpNetaddr)hosts->addr, hosts->addrlen);
 
234
}
 
235
 
 
236
static int
 
237
addHostname(ARRAY8Ptr hostname, ARRAY8Ptr status,
 
238
            struct sockaddr *addr, int will)
 
239
{
 
240
    HostName **names, *name;
 
241
    ARRAY8 hostAddr;
 
242
    CARD16 connectionType;
 
243
 
 
244
    switch (addr->sa_family) {
 
245
    case AF_INET:
 
246
        hostAddr.data = (CARD8 *)&((struct sockaddr_in *)addr)->sin_addr;
 
247
        hostAddr.length = 4;
 
248
        connectionType = FamilyInternet;
 
249
        break;
 
250
#if defined(IPv6) && defined(AF_INET6)
 
251
    case AF_INET6:
 
252
        hostAddr.data = (CARD8 *)&((struct sockaddr_in6 *)addr)->sin6_addr;
 
253
        hostAddr.length = 16;
 
254
        connectionType = FamilyInternet6;
 
255
        break;
 
256
#endif
 
257
    default:
 
258
        hostAddr.data = (CARD8 *)"";
 
259
        hostAddr.length = 0;
 
260
        connectionType = FamilyLocal;
 
261
        break;
 
262
    }
 
263
    for (names = &hostNamedb; *names; names = &(*names)->next) {
 
264
        name = *names;
 
265
        if (connectionType == name->connectionType &&
 
266
            XdmcpARRAY8Equal(&hostAddr, &name->hostaddr))
 
267
        {
 
268
            if (XdmcpARRAY8Equal(status, &name->status))
 
269
                return False;
 
270
            XdmcpDisposeARRAY8(&name->status);
 
271
            XdmcpDisposeARRAY8(hostname);
 
272
 
 
273
            gSendInt(G_Ch_ChangeHost);
 
274
            goto gotold;
 
275
        }
 
276
    }
 
277
    if (!(name = Malloc(sizeof(*name))))
 
278
        return False;
 
279
    if (hostname->length) {
 
280
        switch (addr->sa_family) {
 
281
        case AF_INET:
 
282
#if defined(IPv6) && defined(AF_INET6)
 
283
        case AF_INET6:
 
284
#endif
 
285
            {
 
286
                struct hostent *hostent;
 
287
                char *host;
 
288
 
 
289
                hostent = gethostbyaddr((char *)hostAddr.data,
 
290
                                        hostAddr.length, addr->sa_family);
 
291
                if (hostent) {
 
292
                    XdmcpDisposeARRAY8(hostname);
 
293
                    host = hostent->h_name;
 
294
                    XdmcpAllocARRAY8(hostname, strlen(host));
 
295
                    memmove(hostname->data, host, hostname->length);
 
296
                }
 
297
            }
 
298
        }
 
299
    }
 
300
    if (!XdmcpAllocARRAY8(&name->hostaddr, hostAddr.length)) {
 
301
        free(name);
 
302
        return False;
 
303
    }
 
304
    memmove(name->hostaddr.data, hostAddr.data, hostAddr.length);
 
305
    name->connectionType = connectionType;
 
306
    name->hostname = *hostname;
 
307
 
 
308
    *names = name;
 
309
    name->next = 0;
 
310
 
 
311
    gSendInt(G_Ch_AddHost);
 
312
  gotold:
 
313
    name->alive = True;
 
314
    name->willing = will;
 
315
    name->status = *status;
 
316
 
 
317
    gSendInt((int)(long)name); /* just an id */
 
318
    gSendNStr((char *)name->hostname.data, name->hostname.length);
 
319
    gSendNStr((char *)name->status.data, name->status.length);
 
320
    gSendInt(will);
 
321
 
 
322
    return True;
 
323
}
 
324
 
 
325
static void
 
326
disposeHostname(HostName *host)
 
327
{
 
328
    XdmcpDisposeARRAY8(&host->hostname);
 
329
    XdmcpDisposeARRAY8(&host->hostaddr);
 
330
    XdmcpDisposeARRAY8(&host->status);
 
331
    free(host);
 
332
}
 
333
 
 
334
static void
 
335
emptyHostnames(void)
 
336
{
 
337
    HostName *host, *nhost;
 
338
 
 
339
    for (host = hostNamedb; host; host = nhost) {
 
340
        nhost = host->next;
 
341
        disposeHostname(host);
 
342
    }
 
343
    hostNamedb = 0;
 
344
}
 
345
 
 
346
static void
 
347
receivePacket(int sfd)
 
348
{
 
349
    XdmcpHeader header;
 
350
    ARRAY8 authenticationName;
 
351
    ARRAY8 hostname;
 
352
    ARRAY8 status;
 
353
    int saveHostname = False;
 
354
#if defined(IPv6) && defined(AF_INET6)
 
355
    struct sockaddr_storage addr;
 
356
#else
 
357
    struct sockaddr addr;
 
358
#endif
 
359
    int addrlen;
 
360
 
 
361
    addrlen = sizeof(addr);
 
362
    if (!XdmcpFill(sfd, &buffer, (XdmcpNetaddr)&addr, &addrlen))
 
363
        return;
 
364
    if (!XdmcpReadHeader(&buffer, &header))
 
365
        return;
 
366
    if (header.version != XDM_PROTOCOL_VERSION)
 
367
        return;
 
368
    hostname.data = 0;
 
369
    status.data = 0;
 
370
    authenticationName.data = 0;
 
371
    switch (header.opcode) {
 
372
    case WILLING:
 
373
        if (XdmcpReadARRAY8(&buffer, &authenticationName) &&
 
374
            XdmcpReadARRAY8(&buffer, &hostname) &&
 
375
            XdmcpReadARRAY8(&buffer, &status))
 
376
        {
 
377
            if (header.length == 6 + authenticationName.length +
 
378
                                 hostname.length + status.length)
 
379
                if (addHostname(&hostname, &status,
 
380
                                (struct sockaddr *)&addr, True))
 
381
                    saveHostname = True;
 
382
        }
 
383
        XdmcpDisposeARRAY8(&authenticationName);
 
384
        break;
 
385
    case UNWILLING:
 
386
        if (XdmcpReadARRAY8(&buffer, &hostname) &&
 
387
            XdmcpReadARRAY8(&buffer, &status))
 
388
        {
 
389
            if (header.length == 4 + hostname.length + status.length)
 
390
                if (addHostname(&hostname, &status,
 
391
                                (struct sockaddr *)&addr, False))
 
392
                    saveHostname = True;
 
393
        }
 
394
        break;
 
395
    default:
 
396
        break;
 
397
    }
 
398
    if (!saveHostname) {
 
399
        XdmcpDisposeARRAY8(&hostname);
 
400
        XdmcpDisposeARRAY8(&status);
 
401
    }
 
402
}
 
403
 
 
404
static void
 
405
addHostaddr(HostAddr **hosts, struct sockaddr *addr, int len, xdmOpCode type)
 
406
{
 
407
    HostAddr *host;
 
408
 
 
409
    debug("adding host %[*hhu, type %d\n", len, addr, type);
 
410
    for (host = *hosts; host; host = host->next)
 
411
        if (host->type == type && host->addr->sa_family == addr->sa_family)
 
412
            switch (addr->sa_family) {
 
413
            case AF_INET: {
 
414
                struct sockaddr_in *na = (struct sockaddr_in *)addr;
 
415
                struct sockaddr_in *oa = (struct sockaddr_in *)host->addr;
 
416
                if (na->sin_port == oa->sin_port &&
 
417
                        na->sin_addr.s_addr == oa->sin_addr.s_addr)
 
418
                    return;
 
419
                break; }
 
420
#if defined(IPv6) && defined(AF_INET6)
 
421
            case AF_INET6: {
 
422
                struct sockaddr_in6 *na = (struct sockaddr_in6 *)addr;
 
423
                struct sockaddr_in6 *oa = (struct sockaddr_in6 *)host->addr;
 
424
                if (na->sin6_port == oa->sin6_port &&
 
425
                        !memcmp(&na->sin6_addr, &oa->sin6_addr, 16))
 
426
                    return;
 
427
                break; }
 
428
#endif
 
429
            default: /* ... */
 
430
                break;
 
431
            }
 
432
    debug(" not dupe\n");
 
433
    if (!(host = Malloc(sizeof(*host))))
 
434
        return;
 
435
    if (!(host->addr = Malloc(len))) {
 
436
        free(host);
 
437
        return;
 
438
    }
 
439
    memcpy(host->addr, addr, len);
 
440
    host->addrlen = len;
 
441
    host->type = type;
 
442
    host->next = *hosts;
 
443
    *hosts = host;
 
444
}
 
445
 
 
446
static void
 
447
registerHostaddr(struct sockaddr *addr, int len, xdmOpCode type)
 
448
{
 
449
    addHostaddr(&hostAddrdb, addr, len, type);
 
450
}
 
451
 
 
452
static void
 
453
emptyPingHosts(void)
 
454
{
 
455
    HostAddr *host, *nhost;
 
456
 
 
457
    for (host = hostAddrdb; host; host = nhost) {
 
458
        nhost = host->next;
 
459
        free(host->addr);
 
460
        free(host);
 
461
    }
 
462
    hostAddrdb = 0;
 
463
}
 
464
 
 
465
/* Handle variable length ifreq in BNR2 and later */
 
466
#ifdef VARIABLE_IFREQ
 
467
# define ifr_size(p) \
 
468
    (sizeof(struct ifreq) + \
 
469
     (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \
 
470
      p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0))
 
471
#else
 
472
# define ifr_size(p) (sizeof(struct ifreq))
 
473
#endif
 
474
 
 
475
#define IFC_REQ(ifc) ifc.ifc_req
 
476
 
 
477
#ifndef SYSV_SIOCGIFCONF
 
478
# define ifioctl ioctl
 
479
#endif
 
480
 
 
481
static void
 
482
registerBroadcastForPing(void)
 
483
{
 
484
    struct sockaddr_in in_addr;
 
485
 
 
486
#ifdef __GNU__
 
487
    in_addr.sin_addr.s_addr = htonl(0xFFFFFFFF);
 
488
    in_addr.sin_port = htons(XDM_UDP_PORT);
 
489
    registerHostaddr((struct sockaddr *)&in_addr, sizeof(in_addr),
 
490
                     BROADCAST_QUERY);
 
491
#else /* __GNU__ */
 
492
    struct ifconf ifc;
 
493
    register struct ifreq *ifr;
 
494
    struct sockaddr broad_addr;
 
495
    char buf[2048], *cp, *cplim;
 
496
# ifdef WINTCP /* NCR with Wollongong TCP */
 
497
    int ipfd;
 
498
    struct ifconf *ifcp;
 
499
    struct strioctl ioc;
 
500
    int n;
 
501
 
 
502
    ifcp = (struct ifconf *)buf;
 
503
    ifcp->ifc_buf = buf + 4;
 
504
    ifcp->ifc_len = sizeof(buf) - 4;
 
505
 
 
506
    if ((ipfd = open("/dev/ip", O_RDONLY)) < 0) {
 
507
        t_error("RegisterBroadcastForPing() t_open(/dev/ip) failed");
 
508
        return;
 
509
    }
 
510
 
 
511
    ioc.ic_cmd = IPIOC_GETIFCONF;
 
512
    ioc.ic_timout = 60;
 
513
    ioc.ic_len = sizeof(buf);
 
514
    ioc.ic_dp = (char *)ifcp;
 
515
 
 
516
    if (ioctl(ipfd, (int)I_STR, (char *)&ioc) < 0) {
 
517
        perror("RegisterBroadcastForPing() ioctl(I_STR(IPIOC_GETIFCONF)) failed");
 
518
        close(ipfd);
 
519
        return;
 
520
    }
 
521
 
 
522
    for (ifr = ifcp->ifc_req, n = ifcp->ifc_len / sizeof(struct ifreq); --n >= 0; ifr++)
 
523
# else /* WINTCP */
 
524
    ifc.ifc_len = sizeof(buf);
 
525
    ifc.ifc_buf = buf;
 
526
    if (ifioctl(socketFD, (int)SIOCGIFCONF, (char *)&ifc) < 0)
 
527
        return;
 
528
 
 
529
    cplim = (char *)IFC_REQ(ifc) + ifc.ifc_len;
 
530
 
 
531
    for (cp = (char *)IFC_REQ(ifc); cp < cplim; cp += ifr_size(ifr))
 
532
# endif /* WINTCP */
 
533
    {
 
534
# ifndef WINTCP
 
535
        ifr = (struct ifreq *)cp;
 
536
# endif
 
537
        if (ifr->ifr_addr.sa_family != AF_INET)
 
538
            continue;
 
539
 
 
540
        broad_addr = ifr->ifr_addr;
 
541
        ((struct sockaddr_in *)&broad_addr)->sin_addr.s_addr =
 
542
            htonl(INADDR_BROADCAST);
 
543
# ifdef SIOCGIFBRDADDR
 
544
        {
 
545
            struct ifreq broad_req;
 
546
 
 
547
            broad_req = *ifr;
 
548
#  ifdef WINTCP /* NCR with Wollongong TCP */
 
549
            ioc.ic_cmd = IPIOC_GETIFFLAGS;
 
550
            ioc.ic_timout = 0;
 
551
            ioc.ic_len = sizeof(broad_req);
 
552
            ioc.ic_dp = (char *)&broad_req;
 
553
 
 
554
            if (ioctl(ipfd, I_STR, (char *)&ioc) != -1 &&
 
555
#  else /* WINTCP */
 
556
            if (ifioctl(socketFD, SIOCGIFFLAGS, (char *)&broad_req) != -1 &&
 
557
#  endif /* WINTCP */
 
558
                    (broad_req.ifr_flags & IFF_BROADCAST) &&
 
559
                    (broad_req.ifr_flags & IFF_UP))
 
560
            {
 
561
                broad_req = *ifr;
 
562
#  ifdef WINTCP /* NCR with Wollongong TCP */
 
563
                ioc.ic_cmd = IPIOC_GETIFBRDADDR;
 
564
                ioc.ic_timout = 0;
 
565
                ioc.ic_len = sizeof(broad_req);
 
566
                ioc.ic_dp = (char *)&broad_req;
 
567
 
 
568
                if (ioctl(ipfd, I_STR, (char *)&ioc) != -1)
 
569
#  else /* WINTCP */
 
570
                if (ifioctl(socketFD, SIOCGIFBRDADDR, (char *)&broad_req) != -1)
 
571
#  endif /* WINTCP */
 
572
                    broad_addr = broad_req.ifr_addr;
 
573
                else
 
574
                    continue;
 
575
            } else
 
576
                continue;
 
577
        }
 
578
# endif
 
579
        in_addr = *((struct sockaddr_in *)&broad_addr);
 
580
        in_addr.sin_port = htons(XDM_UDP_PORT);
 
581
# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
 
582
        in_addr.sin_len = sizeof(in_addr);
 
583
# endif
 
584
        registerHostaddr((struct sockaddr *)&in_addr, sizeof(in_addr),
 
585
                         BROADCAST_QUERY);
 
586
    }
 
587
#endif
 
588
}
 
589
 
 
590
static int
 
591
makeSockAddrs(const char *name, HostAddr **hosts)
 
592
{
 
593
#if defined(IPv6) && defined(AF_INET6)
 
594
    struct addrinfo *ai, *nai, hints;
 
595
    bzero(&hints, sizeof(hints));
 
596
    hints.ai_socktype = SOCK_DGRAM;
 
597
    if (getaddrinfo(name, stringify(XDM_UDP_PORT), &hints, &ai))
 
598
        return False;
 
599
    for (nai = ai; nai; nai = nai->ai_next)
 
600
        if ((nai->ai_family == AF_INET) || (nai->ai_family == AF_INET6))
 
601
            addHostaddr(hosts, nai->ai_addr, nai->ai_addrlen,
 
602
                        (nai->ai_family == AF_INET ?
 
603
                         IN_MULTICAST(((struct sockaddr_in *)nai->ai_addr)->sin_addr.s_addr) :
 
604
                         IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)nai->ai_addr)->sin6_addr)) ?
 
605
                        BROADCAST_QUERY : QUERY);
 
606
#else
 
607
    struct sockaddr_in in_addr;
 
608
    /* Per RFC 1123, check first for IP address in dotted-decimal form */
 
609
    if ((in_addr.sin_addr.s_addr = inet_addr(name)) == (unsigned)-1) {
 
610
        struct hostent *hostent;
 
611
        if (!(hostent = gethostbyname(name)) ||
 
612
                hostent->h_addrtype != AF_INET)
 
613
            return False;
 
614
        memcpy(&in_addr.sin_addr, hostent->h_addr, 4);
 
615
    }
 
616
    in_addr.sin_family = AF_INET;
 
617
    in_addr.sin_port = htons(XDM_UDP_PORT);
 
618
# ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
 
619
    in_addr.sin_len = sizeof(in_addr);
 
620
# endif
 
621
    addHostaddr(hosts, (struct sockaddr *)&in_addr, sizeof(in_addr),
 
622
# ifdef IN_MULTICAST
 
623
                IN_MULTICAST(in_addr.sin_addr.s_addr) ?
 
624
                BROADCAST_QUERY :
 
625
# endif
 
626
                QUERY);
 
627
#endif
 
628
    return True;
 
629
}
 
630
 
 
631
/*
 
632
 * Register the address for this host.
 
633
 * Called for interactively specified hosts.
 
634
 * The special names "BROADCAST" and "*" look up all the broadcast
 
635
 *  addresses on the local host.
 
636
 */
 
637
 
 
638
static int
 
639
registerForPing(const char *name)
 
640
{
 
641
    debug("manual host registration: %s\n", name);
 
642
    if (!strcmp(name, "BROADCAST") || !strcmp(name, "*"))
 
643
        registerBroadcastForPing();
 
644
    else if (!makeSockAddrs(name, &hostAddrdb))
 
645
        return False;
 
646
    return True;
 
647
}
 
648
 
 
649
/*ARGSUSED*/
 
650
static void
 
651
addChooserHost(CARD16 connectionType,
 
652
               ARRAY8Ptr addr,
 
653
               char *closure ATTR_UNUSED)
 
654
{
 
655
    if (connectionType == FamilyBroadcast) {
 
656
        registerBroadcastForPing();
 
657
        return;
 
658
    }
 
659
    debug("internal host registration: %[*hhu, family %hx\n",
 
660
          addr->length, addr->data, connectionType);
 
661
    if (connectionType == FamilyInternet) {
 
662
        struct sockaddr_in in_addr;
 
663
        in_addr.sin_family = AF_INET;
 
664
        memmove(&in_addr.sin_addr, addr->data, 4);
 
665
        in_addr.sin_port = htons(XDM_UDP_PORT);
 
666
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
 
667
        in_addr.sin_len = sizeof(in_addr);
 
668
#endif
 
669
        registerHostaddr((struct sockaddr *)&in_addr, sizeof(in_addr),
 
670
#ifdef IN_MULTICAST
 
671
                         IN_MULTICAST(in_addr.sin_addr.s_addr) ?
 
672
                         BROADCAST_QUERY :
 
673
#endif
 
674
                         QUERY);
 
675
#if defined(IPv6) && defined(AF_INET6)
 
676
    } else if (connectionType == FamilyInternet6) {
 
677
        struct sockaddr_in6 in6_addr;
 
678
        in6_addr.sin6_family = AF_INET6;
 
679
        memmove(&in6_addr.sin6_addr, addr->data, 16);
 
680
        in6_addr.sin6_port = htons(XDM_UDP_PORT);
 
681
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
 
682
        in6_addr.sin6_len = sizeof(in6_addr);
 
683
#endif
 
684
        registerHostaddr((struct sockaddr *)&in6_addr, sizeof(in6_addr),
 
685
                         IN6_IS_ADDR_MULTICAST(&in6_addr.sin6_addr) ?
 
686
                         BROADCAST_QUERY : QUERY);
 
687
#endif
 
688
    }
 
689
}
 
690
 
 
691
static ARRAYofARRAY8 AuthenticationNames;
 
692
 
 
693
#if 0
 
694
static void
 
695
registerAuthenticationName(char *name, int namelen)
 
696
{
 
697
    ARRAY8Ptr authName;
 
698
    if (!XdmcpReallocARRAYofARRAY8(&AuthenticationNames,
 
699
                                   AuthenticationNames.length + 1))
 
700
        return;
 
701
    authName = &AuthenticationNames.data[AuthenticationNames.length - 1];
 
702
    if (!XdmcpAllocARRAY8(authName, namelen))
 
703
        return;
 
704
    memmove(authName->data, name, namelen);
 
705
}
 
706
#endif
 
707
 
 
708
static int
 
709
initXDMCP()
 
710
{
 
711
    XdmcpHeader header;
 
712
#if 0
 
713
    int i;
 
714
#endif
 
715
#ifndef STREAMSCONN
 
716
#ifdef SO_BROADCAST
 
717
    int soopts;
 
718
#endif
 
719
#endif
 
720
 
 
721
    header.version = XDM_PROTOCOL_VERSION;
 
722
    header.length = 1;
 
723
#if 0
 
724
    for (i = 0; i < (int)AuthenticationNames.length; i++)
 
725
        header.length += 2 + AuthenticationNames.data[i].length;
 
726
#endif
 
727
 
 
728
    header.opcode = (CARD16)BROADCAST_QUERY;
 
729
    XdmcpWriteHeader(&broadcastBuffer, &header);
 
730
    XdmcpWriteARRAYofARRAY8(&broadcastBuffer, &AuthenticationNames);
 
731
 
 
732
    header.opcode = (CARD16)QUERY;
 
733
    XdmcpWriteHeader(&directBuffer, &header);
 
734
    XdmcpWriteARRAYofARRAY8(&directBuffer, &AuthenticationNames);
 
735
 
 
736
#if defined(STREAMSCONN)
 
737
    if ((socketFD = t_open("/dev/udp", O_RDWR, 0)) < 0)
 
738
        return 0;
 
739
 
 
740
    if (t_bind(socketFD, 0, 0) < 0) {
 
741
        t_close(socketFD);
 
742
        return False;
 
743
    }
 
744
 
 
745
    /*
 
746
     * This part of the code looks contrived. It will actually fit in nicely
 
747
     * when the CLTS part of Xtrans is implemented.
 
748
     */
 
749
    {
 
750
        struct netconfig *nconf;
 
751
 
 
752
        if (!(nconf = getnetconfigent("udp"))) {
 
753
            t_unbind(socketFD);
 
754
            t_close(socketFD);
 
755
            return False;
 
756
        }
 
757
 
 
758
        if (netdir_options(nconf, ND_SET_BROADCAST, socketFD, 0)) {
 
759
            freenetconfigent(nconf);
 
760
            t_unbind(socketFD);
 
761
            t_close(socketFD);
 
762
            return False;
 
763
        }
 
764
 
 
765
        freenetconfigent(nconf);
 
766
    }
 
767
#else
 
768
    if ((socketFD = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
 
769
        return False;
 
770
#if defined(IPv6) && defined(AF_INET6)
 
771
    socket6FD = socket(AF_INET6, SOCK_DGRAM, 0);
 
772
#endif
 
773
# ifdef SO_BROADCAST
 
774
    soopts = 1;
 
775
    if (setsockopt(socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
 
776
                   sizeof(soopts)) < 0)
 
777
        perror("setsockopt");
 
778
# endif
 
779
#endif
 
780
 
 
781
    return True;
 
782
}
 
783
 
 
784
static void ATTR_NORETURN
 
785
chooseHost(int hid)
 
786
{
 
787
    HostName *h;
 
788
#if defined(IPv6) && defined(AF_INET6)
 
789
    char addr[64];
 
790
#endif
 
791
 
 
792
    for (h = hostNamedb; h; h = h->next)
 
793
        if ((int)(long)h == hid) {
 
794
            gSet(&mstrtalk);
 
795
            if ((td->displayType & d_location) == dLocal) {
 
796
                gSendInt(D_RemoteHost);
 
797
#if defined(IPv6) && defined(AF_INET6)
 
798
                switch (h->connectionType) {
 
799
                case FamilyInternet6:
 
800
                    inet_ntop(AF_INET6, h->hostaddr.data, addr, sizeof(addr));
 
801
                    break;
 
802
                default: /* FamilyInternet */
 
803
                    inet_ntop(AF_INET, h->hostaddr.data, addr, sizeof(addr));
 
804
                    break;
 
805
                }
 
806
                gSendStr(addr);
 
807
#else
 
808
                gSendStr(inet_ntoa(*(struct in_addr *)h->hostaddr.data));
 
809
#endif
 
810
                sessionExit(EX_REMOTE);
 
811
            } else {
 
812
                gSendInt(D_ChooseHost);
 
813
                gSendArr(td->clientAddr.length, (char *)td->clientAddr.data);
 
814
                gSendArr(td->clientPort.length, (char *)td->clientPort.data);
 
815
                gSendInt(td->connectionType);
 
816
                gSendArr(h->hostaddr.length, (char *)h->hostaddr.data);
 
817
                goto bout;
 
818
            }
 
819
            break;
 
820
        }
 
821
/*        logError("Internal error: chose unexisting host\n"); */
 
822
  bout:
 
823
    sessionExit(EX_NORMAL);
 
824
}
 
825
 
 
826
static void
 
827
directChooseHost(const char *name)
 
828
{
 
829
    HostAddr *hosts = 0;
 
830
 
 
831
    if (!makeSockAddrs(name, &hosts))
 
832
        return;
 
833
    gSendInt(G_Ch_Exit);
 
834
    gSet(&mstrtalk);
 
835
    if ((td->displayType & d_location) == dLocal) {
 
836
        gSendInt(D_RemoteHost);
 
837
        gSendStr(name);
 
838
        sessionExit(EX_REMOTE);
 
839
    } else {
 
840
        gSendInt(D_ChooseHost);
 
841
        gSendArr(td->clientAddr.length, (char *)td->clientAddr.data);
 
842
        gSendArr(td->clientPort.length, (char *)td->clientPort.data);
 
843
        gSendInt(td->connectionType);
 
844
        gSendArr(hosts->addrlen, (char *)hosts->addr);
 
845
        sessionExit(EX_NORMAL);
 
846
    }
 
847
}
 
848
 
 
849
#define PING_TRIES 3
 
850
 
 
851
int
 
852
doChoose()
 
853
{
 
854
    HostName **hp, *h;
 
855
    char *host, **hostp;
 
856
    struct timeval *to, tnow, nextPing;
 
857
    int pingTry, n, cmd;
 
858
    fd_set rfds;
 
859
    static int xdmcpInited;
 
860
 
 
861
    openGreeter();
 
862
    gSendInt(G_Choose);
 
863
    switch (cmd = ctrlGreeterWait(True)) {
 
864
    case G_Ready:
 
865
        break;
 
866
    default: /* error */
 
867
        return cmd;
 
868
    }
 
869
 
 
870
    if (!xdmcpInited) {
 
871
        if (!initXDMCP())
 
872
            sessionExit(EX_UNMANAGE_DPY);
 
873
        xdmcpInited = True;
 
874
    }
 
875
    if ((td->displayType & d_location) == dLocal) {
 
876
        /* XXX the config reader should do the lookup already */
 
877
        for (hostp = td->chooserHosts; *hostp; hostp++)
 
878
            if (!registerForPing(*hostp))
 
879
                logError("Unknown host %\"s specified for local chooser preload of display %s\n", *hostp, td->name);
 
880
    } else
 
881
        forEachChooserHost(&td->clientAddr, td->connectionType,
 
882
                           addChooserHost, 0);
 
883
 
 
884
    gSendInt(0); /* entering async mode signal */
 
885
 
 
886
  reping:
 
887
    for (h = hostNamedb; h; h = h->next)
 
888
        h->alive = False;
 
889
    pingTry = 0;
 
890
    goto pingen;
 
891
 
 
892
    for (;;) {
 
893
        to = 0;
 
894
        if (pingTry <= PING_TRIES) {
 
895
            gettimeofday(&tnow, 0);
 
896
            if (nextPing.tv_sec < tnow.tv_sec ||
 
897
                (nextPing.tv_sec == tnow.tv_sec &&
 
898
                 nextPing.tv_usec < tnow.tv_usec))
 
899
            {
 
900
                if (pingTry < PING_TRIES) {
 
901
                  pingen:
 
902
                    pingTry++;
 
903
                    doPingHosts();
 
904
                    gettimeofday(&tnow, 0);
 
905
                    nextPing = tnow;
 
906
                    nextPing.tv_sec++;
 
907
                } else {
 
908
                    for (hp = &hostNamedb; *hp;)
 
909
                        if (!(*hp)->alive) {
 
910
                            h = (*hp)->next;
 
911
                            disposeHostname(*hp);
 
912
                            gSendInt(G_Ch_RemoveHost);
 
913
                            gSendInt((int)(long)*hp); /* just an id */
 
914
                            *hp = h;
 
915
                        } else {
 
916
                            hp = &(*hp)->next;
 
917
                        }
 
918
                    goto noto;
 
919
                }
 
920
            }
 
921
            to = &tnow;
 
922
            tnow.tv_sec = nextPing.tv_sec - tnow.tv_sec;
 
923
            tnow.tv_usec = nextPing.tv_usec - tnow.tv_usec;
 
924
            if (tnow.tv_usec < 0) {
 
925
                tnow.tv_usec += 1000000;
 
926
                tnow.tv_sec--;
 
927
            }
 
928
        }
 
929
      noto:
 
930
        FD_ZERO(&rfds);
 
931
        FD_SET(grtproc.pipe.fd.r, &rfds);
 
932
        FD_SET(socketFD, &rfds);
 
933
#if defined(IPv6) && defined(AF_INET6)
 
934
        if (socket6FD >= 0)
 
935
            FD_SET(socket6FD, &rfds);
 
936
#endif
 
937
        n = grtproc.pipe.fd.r;
 
938
        if (socketFD > n)
 
939
            n = socketFD;
 
940
#if defined(IPv6) && defined(AF_INET6)
 
941
        if (socket6FD > n)
 
942
            n = socket6FD;
 
943
#endif
 
944
        if (select(n + 1, &rfds, 0, 0, to) > 0) {
 
945
            if (FD_ISSET(grtproc.pipe.fd.r, &rfds))
 
946
                switch (cmd = ctrlGreeterWait(False)) {
 
947
                case -1:
 
948
                    break;
 
949
                case G_Ch_Refresh:
 
950
                    goto reping;
 
951
                case G_Ch_RegisterHost:
 
952
                    host = gRecvStr();
 
953
                    if (!registerForPing(host)) {
 
954
                        gSendInt(G_Ch_BadHost);
 
955
                        gSendStr(host);
 
956
                    }
 
957
                    free(host);
 
958
                    goto reping;
 
959
                case G_Ch_DirectChoice:
 
960
                    host = gRecvStr();
 
961
                    directChooseHost(host);
 
962
                    gSendInt(G_Ch_BadHost);
 
963
                    gSendStr(host);
 
964
                    free(host);
 
965
                    break;
 
966
                case G_Ready:
 
967
                    chooseHost(gRecvInt());
 
968
                    /* NOTREACHED */
 
969
                default:
 
970
                    emptyHostnames();
 
971
                    emptyPingHosts();
 
972
                    return cmd;
 
973
                }
 
974
            if (FD_ISSET(socketFD, &rfds))
 
975
                receivePacket(socketFD);
 
976
#if defined(IPv6) && defined(AF_INET6)
 
977
            if (socket6FD >= 0 && FD_ISSET(socket6FD, &rfds))
 
978
                receivePacket(socket6FD);
 
979
#endif
 
980
        }
 
981
    }
 
982
 
 
983
}