1 /* $NetBSD: scm.c,v 1.27 2009/10/16 12:41:37 christos Exp $ */
4 * Copyright (c) 1992 Carnegie Mellon University
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:
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
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
51 * p = remotehost () remote host name (if known)
53 * i = samehost () whether remote host is also this host
55 * i = matchhost (name) whether remote host is same as name
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 **********************************************************************
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.
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().
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
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
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 **********************************************************************
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>
176 #if !defined(__linux__)
177 #if !defined(__CYGWIN__)
183 #include <sys/ioctl.h>
186 #include "getaddrinfo.h"
188 #include "supcdefs.h"
189 #include "supextern.h"
192 #define INADDR_NONE 0xffffffff /* -1 return */
194 #ifndef INADDR_LOOPBACK
195 #define INADDR_LOOPBACK (u_long)0x7f000001 /* 127.0.0.1 */
198 char scmversion
[] = "4.3 BSD";
201 /*************************
203 *************************/
205 /* networking parameters */
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
];
236 const char *cause
= "unknown";
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
);
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
);
253 error
= getaddrinfo(NULL
, port
, &hints
, &res0
);
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
,
265 if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
,
266 &one
, sizeof(int)) < 0) {
267 cause
= "setsockopt(SO_REUSEADDR)";
271 if (bind(sock
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
276 if (listen(sock
, NCONNECTS
) < 0) {
286 return (scmerr(errno
, "%s", cause
));
292 struct sockaddr_storage from
;
299 netfile
= accept(sock
, (struct sockaddr
*)(void *)&from
, &len
);
300 } while (netfile
< 0 && errno
== EINTR
);
302 return (scmerr(errno
, "Can't accept connections"));
303 if (len
> sizeof(remoteaddr
)) {
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"));
312 else if (x
== 0x04030201)
315 return (scmerr(-1, "Unexpected byteswap mode %x", x
));
316 setproctitle("Serving %s", remotehost());
322 { /* kill temp socket in daemon */
332 { /* kill net file in daemon's parent */
334 (void) close(netfile
);
346 { /* kill net file after use in daemon */
348 (void) close(netfile
);
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 ***************************************************/
363 dobackoff(int *t
, int *b
)
371 if (gettimeofday(&tt
, (struct timezone
*) NULL
) >= 0)
372 s
+= ((uint32_t)tt
.tv_usec
>> 8) % s
;
376 if (s
> (unsigned) *t
)
381 (void) scmerr(-1, "Will retry in %d seconds", s
);
387 request(char *server
, char *hostname
, int *retry
)
388 { /* connect to server */
389 struct addrinfo hints
, *res
, *res0
;
391 char port
[NI_MAXSERV
];
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
);
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
);
408 error
= getaddrinfo(hostname
, port
, &hints
, &res0
);
410 return (scmerr(-1, "%s: %s", server
,
411 gai_strerror(error
)));
416 for (res
= res0
; res
; res
= res
->ai_next
) {
417 if (res
->ai_addrlen
> sizeof(remoteaddr
))
419 netfile
= socket(res
->ai_family
, res
->ai_socktype
,
423 if (connect(netfile
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
432 if (!dobackoff(retry
, &backoff
)) {
445 memcpy(&remoteaddr
, res
->ai_addr
, res
->ai_addrlen
);
446 remotename
= estrdup(hostname
);
448 (void) write(netfile
, &x
, sizeof(int));
449 swapmode
= 0; /* swap only on server, not client */
456 { /* end connection to server */
459 (void) close(netfile
);
468 /*************************************************
469 *** H O S T N A M E C H E C K I N G ***
470 *************************************************/
474 { /* find my host name */
476 static char name
[MAXHOSTNAMELEN
+ 1];
478 if (name
[0] == '\0') {
479 if (gethostname(name
, sizeof name
) < 0)
481 name
[sizeof(name
) - 1] = '\0';
482 if ((h
= gethostbyname(name
)) == NULL
)
484 (void) strcpy(name
, h
->h_name
);
491 { /* remote host name (if known) */
494 if (remotename
== NULL
) {
495 if (getnameinfo((struct sockaddr
*)(void *)&remoteaddr
,
497 (socklen_t
)remoteaddr
.ss_len
,
499 sizeof(struct sockaddr
),
501 h1
, sizeof(h1
), NULL
, 0, 0))
503 remotename
= estrdup(h1
);
504 if (remotename
== NULL
)
516 if ((name
= myhost()) == NULL
)
517 logquit(1, "Can't find my host entry '%s'", myhost());
518 h
= gethostbyname(host
);
521 return (strcasecmp(name
, h
->h_name
) == 0);
525 /* Nice and sleazy does it... */
527 struct ifaddrs
*ifa_next
;
528 struct sockaddr
*ifa_addr
;
529 struct sockaddr ifa_addrspace
;
533 getifaddrs(struct ifaddrs
**ifap
)
543 if ((s
= socket (AF_INET
, SOCK_DGRAM
, 0)) == -1)
546 ifc
.ifc_len
= sizeof(buf
);
549 if (ioctl(s
, SIOCGIFCONF
, &ifc
) == -1) {
556 if ((nint
= ifc
.ifc_len
/ sizeof(struct ifreq
)) <= 0)
559 if ((ifa
= malloc((unsigned)nint
* sizeof(struct ifaddrs
))) == NULL
)
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
;
575 freeifaddrs(struct ifaddrs
*ifa
)
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
,
591 (socklen_t
)remoteaddr
.ss_len
,
593 sizeof(struct sockaddr
),
595 h1
, sizeof(h1
), NULL
, 0, niflags
))
597 if (getifaddrs(&ifap
) < 0)
599 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
600 if (remoteaddr
.ss_family
!= ifa
->ifa_addr
->sa_family
)
602 if (getnameinfo(ifa
->ifa_addr
,
604 (socklen_t
)ifa
->ifa_addr
->sa_len
,
606 sizeof(struct sockaddr
),
608 h2
, sizeof(h2
), NULL
, 0, niflags
))
610 if (strcmp(h1
, h2
) == 0) {
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
,
628 (socklen_t
)remoteaddr
.ss_len
,
630 sizeof(struct sockaddr
),
632 h1
, sizeof(h1
), NULL
, 0, niflags
))
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)
639 for (res
= res0
; res
; res
= res
->ai_next
) {
640 if (remoteaddr
.ss_family
!= res
->ai_family
)
642 if (getnameinfo(res
->ai_addr
, res
->ai_addrlen
,
643 h2
, sizeof(h2
), NULL
, 0, niflags
))
645 if (strcmp(h1
, h2
) == 0) {
655 scmerr(int error
, const char *fmt
, ...)
661 (void) fflush(stdout
);
663 fprintf(stderr
, "%s %d: ", program
, progpid
);
665 fprintf(stderr
, "%s: ", program
);
667 vfprintf(stderr
, fmt
, ap
);
670 fprintf(stderr
, " (%s)\n", strerror(error
));
672 fprintf(stderr
, "\n");
673 (void) fflush(stderr
);
676 /*******************************************************
677 *** I N T E G E R B Y T E - S W A P P I N G ***
678 *******************************************************/
682 char uc
[sizeof(int)];
695 for (ix
= 0; ix
< (int) sizeof(int); ix
++) {