1/* $NetBSD: scm.c,v 1.28 2009/10/17 22:26:13 christos Exp $ */ 2 3/* 4 * Copyright (c) 1992 Carnegie Mellon University 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify and distribute this software and its 8 * documentation is hereby granted, provided that both the copyright 9 * notice and this permission notice appear in all copies of the 10 * software, derivative works or modified versions, and any portions 11 * thereof, and that both notices appear in supporting documentation. 12 * 13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 16 * 17 * Carnegie Mellon requests users of this software to return to 18 * 19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 20 * School of Computer Science 21 * Carnegie Mellon University 22 * Pittsburgh PA 15213-3890 23 * 24 * any improvements or extensions that they make and grant Carnegie Mellon 25 * the rights to redistribute these changes. 26 */ 27/* 28 * SUP Communication Module for 4.3 BSD 29 * 30 * SUP COMMUNICATION MODULE SPECIFICATIONS: 31 * 32 * IN THIS MODULE: 33 * 34 * CONNECTION ROUTINES 35 * 36 * FOR SERVER 37 * servicesetup (port) establish TCP port connection 38 * char *port; name of service 39 * service () accept TCP port connection 40 * servicekill () close TCP port in use by another process 41 * serviceprep () close temp ports used to make connection 42 * serviceend () close TCP port 43 * 44 * FOR CLIENT 45 * request (port,hostname,retry) establish TCP port connection 46 * char *port,*hostname; name of service and host 47 * int retry; true if retries should be used 48 * requestend () close TCP port 49 * 50 * HOST NAME CHECKING 51 * p = remotehost () remote host name (if known) 52 * char *p; 53 * i = samehost () whether remote host is also this host 54 * int i; 55 * i = matchhost (name) whether remote host is same as name 56 * int i; 57 * char *name; 58 * 59 * RETURN CODES 60 * All procedures return values as indicated above. Other routines 61 * normally return SCMOK on success, SCMERR on error. 62 * 63 * COMMUNICATION PROTOCOL 64 * 65 * Described in scmio.c. 66 * 67 ********************************************************************** 68 * HISTORY 69 * 2-Oct-92 Mary Thompson (mrt) at Carnegie-Mellon University 70 * Added conditional declarations of INADDR_NONE and INADDR_LOOPBACK 71 * since Tahoe version of <netinet/in.h> does not define them. 72 * 73 * Revision 1.13 92/08/11 12:05:35 mrt 74 * Added changes from stump: 75 * Allow for multiple interfaces, and for numeric addresses. 76 * Changed to use builtin port for the "supfiledbg" 77 * service when getservbyname() cannot find it. 78 * Added forward static declatations, delinted. 79 * Updated variable argument usage. 80 * [92/08/08 mrt] 81 * 82 * Revision 1.12 92/02/08 19:01:11 mja 83 * Add (struct sockaddr *) casts for HC 2.1. 84 * [92/02/08 18:59:09 mja] 85 * 86 * Revision 1.11 89/08/03 19:49:03 mja 87 * Updated to use v*printf() in place of _doprnt(). 88 * [89/04/19 mja] 89 * 90 * 11-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University 91 * Moved sleep into computeBackoff, renamed to dobackoff. 92 * 93 * 10-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University 94 * Added timeout to backoff. 95 * 96 * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University 97 * Removed nameserver support. 98 * 99 * 09-Sep-87 Glenn Marcy (gm0w) at Carnegie-Mellon University 100 * Fixed to depend less upon having name of remote host. 101 * 102 * 25-May-87 Doug Philips (dwp) at Carnegie-Mellon Universtiy 103 * Extracted backoff/sleeptime computation from "request" and 104 * created "computeBackoff" so that I could use it in sup.c when 105 * trying to get to nameservers as a group. 106 * 107 * 21-May-87 Chriss Stephens (chriss) at Carnegie Mellon University 108 * Merged divergent CS and EE versions. 109 * 110 * 02-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University 111 * Added some bullet-proofing code around hostname calls. 112 * 113 * 31-Mar-87 Dan Nydick (dan) at Carnegie-Mellon University 114 * Fixed for 4.3. 115 * 116 * 30-May-86 Glenn Marcy (gm0w) at Carnegie-Mellon University 117 * Added code to use known values for well-known ports if they are 118 * not found in the host table. 119 * 120 * 19-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University 121 * Changed setsockopt SO_REUSEADDR to be non-fatal. Added fourth 122 * parameter as described in 4.3 manual entry. 123 * 124 * 15-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University 125 * Added call of readflush() to requestend() routine. 126 * 127 * 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 128 * Major rewrite for protocol version 4. All read/write and crypt 129 * routines are now in scmio.c. 130 * 131 * 14-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 132 * Added setsockopt SO_REUSEADDR call. 133 * 134 * 01-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 135 * Removed code to "gracefully" handle unexpected messages. This 136 * seems reasonable since it didn't work anyway, and should be 137 * handled at a higher level anyway by adhering to protocol version 138 * number conventions. 139 * 140 * 26-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 141 * Fixed scm.c to free space for remote host name when connection 142 * is closed. 143 * 144 * 07-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 145 * Fixed 4.2 retry code to reload sin values before retry. 146 * 147 * 22-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 148 * Added code to retry initial connection open request. 149 * 150 * 22-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 151 * Merged 4.1 and 4.2 versions together. 152 * 153 * 21-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University 154 * Add close() calls after pipe() call. 155 * 156 * 12-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University 157 * Converted for 4.2 sockets; added serviceprep() routine. 158 * 159 * 04-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University 160 * Created for 4.2 BSD. 161 * 162 ********************************************************************** 163 */ 164 165#include "libc.h" 166#include <errno.h> 167#include <sys/param.h> 168#include <sys/types.h> 169#include <sys/time.h> 170#include <sys/socket.h> 171#include <netinet/in.h> 172#include <arpa/inet.h> 173#include <net/if.h> 174#include <netdb.h> 175#include <stdarg.h> 176#if !defined(__linux__) 177#if !defined(__CYGWIN__) 178#include <ifaddrs.h> 179#else 180#include "ifaddrs.h" 181#endif 182#else 183#include <sys/ioctl.h> 184#endif 185#ifdef __CYGWIN__ 186#include "getaddrinfo.h" 187#endif 188#include "supcdefs.h" 189#include "supextern.h" 190 191#ifndef INADDR_NONE 192#define INADDR_NONE 0xffffffff /* -1 return */ 193#endif 194#ifndef INADDR_LOOPBACK 195#define INADDR_LOOPBACK (u_long)0x7f000001 /* 127.0.0.1 */ 196#endif 197 198char scmversion[] = "4.3 BSD"; 199extern int silent; 200 201/************************* 202 *** M A C R O S *** 203 *************************/ 204 205/* networking parameters */ 206#define NCONNECTS 5 207 208/********************************************* 209 *** G L O B A L V A R I A B L E S *** 210 *********************************************/ 211 212extern char program[]; /* name of program we are running */ 213extern int progpid; /* process id to display */ 214 215int netfile = -1; /* network file descriptor */ 216 217static int sock = -1; /* socket used to make connection */ 218static struct sockaddr_storage remoteaddr; /* remote host address */ 219static char *remotename = NULL; /* remote host name */ 220static int swapmode; /* byte-swapping needed on server? */ 221 222 223static char *myhost(void); 224 225/*************************************************** 226 *** C O N N E C T I O N R O U T I N E S *** 227 *** F O R S E R V E R *** 228 ***************************************************/ 229 230int 231servicesetup(char *server, int af) 232{ /* listen for clients */ 233 struct addrinfo hints, *res0, *res; 234 char port[NI_MAXSERV]; 235 int error; 236 const char *cause = "unknown"; 237 int one = 1; 238 239 memset(&hints, 0, sizeof(hints)); 240 hints.ai_family = af; 241 hints.ai_socktype = SOCK_STREAM; 242 hints.ai_flags = AI_PASSIVE; 243 error = getaddrinfo(NULL, server, &hints, &res0); 244 if (error) { 245 /* retry with precompiled knowledge */ 246 if (strcmp(server, FILEPORT) == 0) 247 snprintf(port, sizeof(port), "%u", FILEPORTNUM); 248 else if (strcmp(server, DEBUGFPORT) == 0) 249 snprintf(port, sizeof(port), "%u", DEBUGFPORTNUM); 250 else 251 port[0] = '\0'; 252 if (port[0]) 253 error = getaddrinfo(NULL, port, &hints, &res0); 254 if (error) 255 return (scmerr(-1, "%s: %s", server, 256 gai_strerror(error))); 257 } 258 for (res = res0; res; res = res->ai_next) { 259 sock = socket(res->ai_family, res->ai_socktype, 260 res->ai_protocol); 261 if (sock < 0) { 262 cause = "socket"; 263 continue; 264 } 265 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 266 &one, sizeof(int)) < 0) { 267 cause = "setsockopt(SO_REUSEADDR)"; 268 close(sock); 269 continue; 270 } 271 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 272 cause = "bind"; 273 close(sock); 274 continue; 275 } 276 if (listen(sock, NCONNECTS) < 0) { 277 cause = "listen"; 278 close(sock); 279 continue; 280 } 281 freeaddrinfo(res0); 282 return SCMOK; 283 } 284 285 freeaddrinfo(res0); 286 return (scmerr(errno, "%s", cause)); 287} 288 289int 290service(void) 291{ 292 struct sockaddr_storage from; 293 int x; 294 socklen_t len; 295 296 remotename = NULL; 297 len = sizeof(from); 298 do { 299 netfile = accept(sock, (struct sockaddr *)(void *)&from, &len); 300 } while (netfile < 0 && errno == EINTR); 301 if (netfile < 0) 302 return (scmerr(errno, "Can't accept connections")); 303 if (len > sizeof(remoteaddr)) { 304 close(netfile); 305 return (scmerr(errno, "Can't accept connections")); 306 } 307 memcpy(&remoteaddr, &from, len); 308 if (read(netfile, &x, sizeof(int)) != sizeof(int)) 309 return (scmerr(errno, "Can't transmit data on connection")); 310 if (x == 0x01020304) 311 swapmode = 0; 312 else if (x == 0x04030201) 313 swapmode = 1; 314 else 315 return (scmerr(-1, "Unexpected byteswap mode %x", x)); 316 setproctitle("Serving %s", remotehost()); 317 return (SCMOK); 318} 319 320int 321serviceprep(void) 322{ /* kill temp socket in daemon */ 323 if (sock >= 0) { 324 (void) close(sock); 325 sock = -1; 326 } 327 return (SCMOK); 328} 329 330int 331servicekill(void) 332{ /* kill net file in daemon's parent */ 333 if (netfile >= 0) { 334 (void) close(netfile); 335 netfile = -1; 336 } 337 if (remotename) { 338 free(remotename); 339 remotename = NULL; 340 } 341 return (SCMOK); 342} 343 344int 345serviceend(void) 346{ /* kill net file after use in daemon */ 347 if (netfile >= 0) { 348 (void) close(netfile); 349 netfile = -1; 350 } 351 if (remotename) { 352 free(remotename); 353 remotename = NULL; 354 } 355 return (SCMOK); 356} 357/*************************************************** 358 *** C O N N E C T I O N R O U T I N E S *** 359 *** F O R C L I E N T *** 360 ***************************************************/ 361 362int 363dobackoff(int *t, int *b) 364{ 365 struct timeval tt; 366 unsigned s; 367 368 if (*t == 0) 369 return (0); 370 s = *b * 30; 371 if (gettimeofday(&tt, NULL) >= 0) 372 s += ((uint32_t)tt.tv_usec >> 8) % s; 373 if (*b < 32) 374 *b <<= 1; 375 if (*t != -1) { 376 if (s > (unsigned) *t) 377 s = *t; 378 *t -= s; 379 } 380 if (!silent) 381 (void) scmerr(-1, "Will retry in %d seconds", s); 382 sleep(s); 383 return (1); 384} 385 386int 387request(char *server, char *hostname, int *retry) 388{ /* connect to server */ 389 struct addrinfo hints, *res, *res0; 390 int error; 391 char port[NI_MAXSERV]; 392 int backoff; 393 int x; 394 395 memset(&hints, 0, sizeof(hints)); 396 hints.ai_family = PF_UNSPEC; 397 hints.ai_socktype = SOCK_STREAM; 398 error = getaddrinfo(hostname, server, &hints, &res0); 399 if (error) { 400 /* retry with precompiled knowledge */ 401 if (strcmp(server, FILEPORT) == 0) 402 snprintf(port, sizeof(port), "%u", FILEPORTNUM); 403 else if (strcmp(server, DEBUGFPORT) == 0) 404 snprintf(port, sizeof(port), "%u", DEBUGFPORTNUM); 405 else 406 port[0] = '\0'; 407 if (port[0]) 408 error = getaddrinfo(hostname, port, &hints, &res0); 409 if (error) 410 return (scmerr(-1, "%s: %s", server, 411 gai_strerror(error))); 412 } 413 backoff = 1; 414 for (;;) { 415 netfile = -1; 416 for (res = res0; res; res = res->ai_next) { 417 if (res->ai_addrlen > sizeof(remoteaddr)) 418 continue; 419 netfile = socket(res->ai_family, res->ai_socktype, 420 res->ai_protocol); 421 if (netfile < 0) 422 continue; 423 if (connect(netfile, res->ai_addr, res->ai_addrlen) < 0) { 424 close(netfile); 425 netfile = -1; 426 continue; 427 } 428 break; 429 } 430 431 if (netfile < 0) { 432 if (!dobackoff(retry, &backoff)) { 433 freeaddrinfo(res0); 434 return (SCMERR); 435 } 436 continue; 437 } else 438 break; 439 } 440 441 if (res == NULL) { 442 freeaddrinfo(res0); 443 return (SCMERR); 444 } 445 memcpy(&remoteaddr, res->ai_addr, res->ai_addrlen); 446 remotename = estrdup(hostname); 447 x = 0x01020304; 448 (void) write(netfile, &x, sizeof(int)); 449 swapmode = 0; /* swap only on server, not client */ 450 freeaddrinfo(res0); 451 return (SCMOK); 452} 453 454int 455requestend(void) 456{ /* end connection to server */ 457 (void) readflush(); 458 if (netfile >= 0) { 459 (void) close(netfile); 460 netfile = -1; 461 } 462 if (remotename) { 463 free(remotename); 464 remotename = NULL; 465 } 466 return (SCMOK); 467} 468/************************************************* 469 *** H O S T N A M E C H E C K I N G *** 470 *************************************************/ 471 472static char * 473myhost(void) 474{ /* find my host name */ 475 struct hostent *h; 476 static char name[MAXHOSTNAMELEN + 1]; 477 478 if (name[0] == '\0') { 479 if (gethostname(name, sizeof name) < 0) 480 return (NULL); 481 name[sizeof(name) - 1] = '\0'; 482 if ((h = gethostbyname(name)) == NULL) 483 return (NULL); 484 (void) strcpy(name, h->h_name); 485 } 486 return (name); 487} 488 489const char * 490remotehost(void) 491{ /* remote host name (if known) */ 492 char h1[NI_MAXHOST]; 493 494 if (remotename == NULL) { 495 if (getnameinfo((struct sockaddr *)(void *)&remoteaddr, 496#ifdef BSD4_4 497 (socklen_t)remoteaddr.ss_len, 498#else 499 sizeof(struct sockaddr), 500#endif 501 h1, sizeof(h1), NULL, 0, 0)) 502 return ("UNKNOWN"); 503 remotename = estrdup(h1); 504 if (remotename == NULL) 505 return ("UNKNOWN"); 506 } 507 return (remotename); 508} 509 510int 511thishost(char *host) 512{ 513 struct hostent *h; 514 char *name; 515 516 if ((name = myhost()) == NULL) 517 logquit(1, "Can't find my host entry '%s'", myhost()); 518 h = gethostbyname(host); 519 if (h == NULL) 520 return (0); 521 return (strcasecmp(name, h->h_name) == 0); 522} 523 524#ifdef __linux__ 525/* Nice and sleazy does it... */ 526struct ifaddrs { 527 struct ifaddrs *ifa_next; 528 struct sockaddr *ifa_addr; 529 struct sockaddr ifa_addrspace; 530}; 531 532static int 533getifaddrs(struct ifaddrs **ifap) 534{ 535 struct ifaddrs *ifa; 536 int nint; 537 int n; 538 char buf[10 * 1024]; 539 struct ifconf ifc; 540 struct ifreq *ifr; 541 int s; 542 543 if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) 544 return -1; 545 546 ifc.ifc_len = sizeof(buf); 547 ifc.ifc_buf = buf; 548 549 if (ioctl(s, SIOCGIFCONF, &ifc) == -1) { 550 (void)close(s); 551 return -1; 552 } 553 554 (void)close(s); 555 556 if ((nint = ifc.ifc_len / sizeof(struct ifreq)) <= 0) 557 return 0; 558 559 if ((ifa = malloc((unsigned)nint * sizeof(struct ifaddrs))) == NULL) 560 return -1; 561 562 for (ifr = ifc.ifc_req, n = 0; n < nint; n++, ifr++) { 563 ifa[n].ifa_next = &ifa[n + 1]; 564 ifa[n].ifa_addr = &ifa[n].ifa_addrspace; 565 (void)memcpy(ifa[n].ifa_addr, &ifr->ifr_addr, 566 sizeof(*ifa[n].ifa_addr)); 567 } 568 569 ifa[nint - 1].ifa_next = NULL; 570 *ifap = ifa; 571 return nint; 572} 573 574static void 575freeifaddrs(struct ifaddrs *ifa) 576{ 577 free(ifa); 578} 579 580#endif 581 582int 583samehost(void) 584{ /* is remote host same as local host? */ 585 struct ifaddrs *ifap, *ifa; 586 char h1[NI_MAXHOST], h2[NI_MAXHOST]; 587 const int niflags = NI_NUMERICHOST; 588 589 if (getnameinfo((struct sockaddr *)(void *)&remoteaddr, 590#ifdef BSD4_4 591 (socklen_t)remoteaddr.ss_len, 592#else 593 sizeof(struct sockaddr), 594#endif 595 h1, sizeof(h1), NULL, 0, niflags)) 596 return (0); 597 if (getifaddrs(&ifap) < 0) 598 return (0); 599 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 600 if (remoteaddr.ss_family != ifa->ifa_addr->sa_family) 601 continue; 602 if (getnameinfo(ifa->ifa_addr, 603#ifdef BSD4_4 604 (socklen_t)ifa->ifa_addr->sa_len, 605#else 606 sizeof(struct sockaddr), 607#endif 608 h2, sizeof(h2), NULL, 0, niflags)) 609 continue; 610 if (strcmp(h1, h2) == 0) { 611 freeifaddrs(ifap); 612 return (1); 613 } 614 } 615 freeifaddrs(ifap); 616 return (0); 617} 618 619int 620matchhost(char *name) 621{ /* is this name of remote host? */ 622 char h1[NI_MAXHOST], h2[NI_MAXHOST]; 623 const int niflags = NI_NUMERICHOST; 624 struct addrinfo hints, *res0, *res; 625 626 if (getnameinfo((struct sockaddr *)(void *)&remoteaddr, 627#ifdef BSD4_4 628 (socklen_t)remoteaddr.ss_len, 629#else 630 sizeof(struct sockaddr), 631#endif 632 h1, sizeof(h1), NULL, 0, niflags)) 633 return (0); 634 memset(&hints, 0, sizeof(hints)); 635 hints.ai_family = PF_UNSPEC; 636 hints.ai_socktype = SOCK_DGRAM; /* dummy */ 637 if (getaddrinfo(name, "0", &hints, &res0) != 0) 638 return (0); 639 for (res = res0; res; res = res->ai_next) { 640 if (remoteaddr.ss_family != res->ai_family) 641 continue; 642 if (getnameinfo(res->ai_addr, res->ai_addrlen, 643 h2, sizeof(h2), NULL, 0, niflags)) 644 continue; 645 if (strcmp(h1, h2) == 0) { 646 freeaddrinfo(res0); 647 return (1); 648 } 649 } 650 freeaddrinfo(res0); 651 return (0); 652} 653 654int 655scmerr(int error, const char *fmt, ...) 656{ 657 va_list ap; 658 659 va_start(ap, fmt); 660 661 (void) fflush(stdout); 662 if (progpid > 0) 663 fprintf(stderr, "%s %d: ", program, progpid); 664 else 665 fprintf(stderr, "%s: ", program); 666 667 vfprintf(stderr, fmt, ap); 668 va_end(ap); 669 if (error >= 0) 670 fprintf(stderr, " (%s)\n", strerror(error)); 671 else 672 fprintf(stderr, "\n"); 673 (void) fflush(stderr); 674 return (SCMERR); 675} 676/******************************************************* 677 *** I N T E G E R B Y T E - S W A P P I N G *** 678 *******************************************************/ 679 680union intchar { 681 int ui; 682 char uc[sizeof(int)]; 683}; 684 685int 686byteswap(int in) 687{ 688 union intchar x, y; 689 int ix, iy; 690 691 if (swapmode == 0) 692 return (in); 693 x.ui = in; 694 iy = sizeof(int); 695 for (ix = 0; ix < (int) sizeof(int); ix++) { 696 --iy; 697 y.uc[iy] = x.uc[ix]; 698 } 699 return (y.ui); 700} 701