Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / scm.c
blob7d936d80d5f365296a57b7b931dde560bffa612e
1 /* $NetBSD: scm.c,v 1.27 2009/10/16 12:41:37 christos Exp $ */
3 /*
4 * Copyright (c) 1992 Carnegie Mellon University
5 * All Rights Reserved.
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.
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.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie Mellon
25 * the rights to redistribute these changes.
28 * SUP Communication Module for 4.3 BSD
30 * SUP COMMUNICATION MODULE SPECIFICATIONS:
32 * IN THIS MODULE:
34 * CONNECTION ROUTINES
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
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
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;
59 * RETURN CODES
60 * All procedures return values as indicated above. Other routines
61 * normally return SCMOK on success, SCMERR on error.
63 * COMMUNICATION PROTOCOL
65 * Described in scmio.c.
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.
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]
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]
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]
90 * 11-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
91 * Moved sleep into computeBackoff, renamed to dobackoff.
93 * 10-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
94 * Added timeout to backoff.
96 * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
97 * Removed nameserver support.
99 * 09-Sep-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
100 * Fixed to depend less upon having name of remote host.
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.
107 * 21-May-87 Chriss Stephens (chriss) at Carnegie Mellon University
108 * Merged divergent CS and EE versions.
110 * 02-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
111 * Added some bullet-proofing code around hostname calls.
113 * 31-Mar-87 Dan Nydick (dan) at Carnegie-Mellon University
114 * Fixed for 4.3.
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.
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.
124 * 15-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
125 * Added call of readflush() to requestend() routine.
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.
131 * 14-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
132 * Added setsockopt SO_REUSEADDR call.
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.
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.
144 * 07-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
145 * Fixed 4.2 retry code to reload sin values before retry.
147 * 22-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
148 * Added code to retry initial connection open request.
150 * 22-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
151 * Merged 4.1 and 4.2 versions together.
153 * 21-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
154 * Add close() calls after pipe() call.
156 * 12-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University
157 * Converted for 4.2 sockets; added serviceprep() routine.
159 * 04-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University
160 * Created for 4.2 BSD.
162 **********************************************************************
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"
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
198 char scmversion[] = "4.3 BSD";
199 extern int silent;
201 /*************************
202 *** M A C R O S ***
203 *************************/
205 /* networking parameters */
206 #define NCONNECTS 5
208 /*********************************************
209 *** G L O B A L V A R I A B L E S ***
210 *********************************************/
212 extern char program[]; /* name of program we are running */
213 extern int progpid; /* process id to display */
215 int netfile = -1; /* network file descriptor */
217 static int sock = -1; /* socket used to make connection */
218 static struct sockaddr_storage remoteaddr; /* remote host address */
219 static char *remotename = NULL; /* remote host name */
220 static int swapmode; /* byte-swapping needed on server? */
223 static char *myhost(void);
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 ***************************************************/
231 servicesetup(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;
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)));
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;
265 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
266 &one, sizeof(int)) < 0) {
267 cause = "setsockopt(SO_REUSEADDR)";
268 close(sock);
269 continue;
271 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
272 cause = "bind";
273 close(sock);
274 continue;
276 if (listen(sock, NCONNECTS) < 0) {
277 cause = "listen";
278 close(sock);
279 continue;
281 freeaddrinfo(res0);
282 return SCMOK;
285 freeaddrinfo(res0);
286 return (scmerr(errno, "%s", cause));
290 service(void)
292 struct sockaddr_storage from;
293 int x;
294 socklen_t len;
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"));
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);
321 serviceprep(void)
322 { /* kill temp socket in daemon */
323 if (sock >= 0) {
324 (void) close(sock);
325 sock = -1;
327 return (SCMOK);
331 servicekill(void)
332 { /* kill net file in daemon's parent */
333 if (netfile >= 0) {
334 (void) close(netfile);
335 netfile = -1;
337 if (remotename) {
338 free(remotename);
339 remotename = NULL;
341 return (SCMOK);
345 serviceend(void)
346 { /* kill net file after use in daemon */
347 if (netfile >= 0) {
348 (void) close(netfile);
349 netfile = -1;
351 if (remotename) {
352 free(remotename);
353 remotename = NULL;
355 return (SCMOK);
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 ***************************************************/
362 int
363 dobackoff(int *t, int *b)
365 struct timeval tt;
366 unsigned s;
368 if (*t == 0)
369 return (0);
370 s = *b * 30;
371 if (gettimeofday(&tt, (struct timezone *) 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;
380 if (!silent)
381 (void) scmerr(-1, "Will retry in %d seconds", s);
382 sleep(s);
383 return (1);
387 request(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;
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)));
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;
428 break;
431 if (netfile < 0) {
432 if (!dobackoff(retry, &backoff)) {
433 freeaddrinfo(res0);
434 return (SCMERR);
436 continue;
437 } else
438 break;
441 if (res == NULL) {
442 freeaddrinfo(res0);
443 return (SCMERR);
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);
455 requestend(void)
456 { /* end connection to server */
457 (void) readflush();
458 if (netfile >= 0) {
459 (void) close(netfile);
460 netfile = -1;
462 if (remotename) {
463 free(remotename);
464 remotename = NULL;
466 return (SCMOK);
468 /*************************************************
469 *** H O S T N A M E C H E C K I N G ***
470 *************************************************/
472 static char *
473 myhost(void)
474 { /* find my host name */
475 struct hostent *h;
476 static char name[MAXHOSTNAMELEN + 1];
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);
486 return (name);
489 const char *
490 remotehost(void)
491 { /* remote host name (if known) */
492 char h1[NI_MAXHOST];
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");
507 return (remotename);
510 int
511 thishost(char *host)
513 struct hostent *h;
514 char *name;
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);
524 #ifdef __linux__
525 /* Nice and sleazy does it... */
526 struct ifaddrs {
527 struct ifaddrs *ifa_next;
528 struct sockaddr *ifa_addr;
529 struct sockaddr ifa_addrspace;
532 static int
533 getifaddrs(struct ifaddrs **ifap)
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;
543 if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
544 return -1;
546 ifc.ifc_len = sizeof(buf);
547 ifc.ifc_buf = buf;
549 if (ioctl(s, SIOCGIFCONF, &ifc) == -1) {
550 (void)close(s);
551 return -1;
554 (void)close(s);
556 if ((nint = ifc.ifc_len / sizeof(struct ifreq)) <= 0)
557 return 0;
559 if ((ifa = malloc((unsigned)nint * sizeof(struct ifaddrs))) == NULL)
560 return -1;
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));
569 ifa[nint - 1].ifa_next = NULL;
570 *ifap = ifa;
571 return nint;
574 static void
575 freeifaddrs(struct ifaddrs *ifa)
577 free(ifa);
580 #endif
582 int
583 samehost(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;
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);
615 freeifaddrs(ifap);
616 return (0);
619 int
620 matchhost(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;
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);
650 freeaddrinfo(res0);
651 return (0);
654 int
655 scmerr(int error, const char *fmt, ...)
657 va_list ap;
659 va_start(ap, fmt);
661 (void) fflush(stdout);
662 if (progpid > 0)
663 fprintf(stderr, "%s %d: ", program, progpid);
664 else
665 fprintf(stderr, "%s: ", program);
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);
676 /*******************************************************
677 *** I N T E G E R B Y T E - S W A P P I N G ***
678 *******************************************************/
680 union intchar {
681 int ui;
682 char uc[sizeof(int)];
685 int
686 byteswap(int in)
688 union intchar x, y;
689 int ix, iy;
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];
699 return (y.ui);