1/* 2 * 3Copyright 1990, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in 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 57static int 58FormatBytes ( 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 78static int 79FormatARRAY8 ( 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 */ 91static int 92ARRAY8ToDottedDecimal ( 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 108typedef struct _IndirectUsers { 109 struct _IndirectUsers *next; 110 ARRAY8 client; 111 CARD16 connectionType; 112} IndirectUsersRec, *IndirectUsersPtr; 113 114static IndirectUsersPtr indirectUsers; 115 116int 117RememberIndirectClient ( 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 144void 145ForgetIndirectClient ( 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 169int 170IsIndirectClient ( 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 183static int 184FormatChooserArgument (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 237typedef struct _Choices { 238 struct _Choices *next; 239 ARRAY8 client; 240 CARD16 connectionType; 241 ARRAY8 choice; 242 Time_t time; 243} ChoiceRec, *ChoicePtr; 244 245static ChoicePtr choices; 246 247ARRAY8Ptr 248IndirectChoice ( 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 285static int 286RegisterIndirectChoice ( 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 335static 336RemoveIndirectChoice (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*/ 363static void 364AddChooserHost ( 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 391void 392ProcessChooserSocket (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 445void 446RunChooser (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