4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/conf/transp/transp_sockets.c
44 * Socket specific utilities.
45 * -Erez Zadok <ezk@cs.columbia.edu>
50 #endif /* HAVE_CONFIG_H */
56 * find the IP address that can be used to connect to the local host
59 amu_get_myaddress(struct in_addr
*iap
, const char *preferred_localhost
)
65 #error this code is old and probably not useful any longer.
66 #error Erez, Jan 21, 2004.
67 struct sockaddr_in sin
;
70 * Most modern systems should use 127.0.0.1 as the localhost address over
71 * which you can do NFS mounts. In the past we found that some NFS
72 * clients may not allow mounts from localhost. So we used
73 * get_myaddress() and that seemed to work. Alas, on some other systems,
74 * get_myaddress() may return one of the interface addresses at random,
75 * and thus use a less efficient IP address than 127.0.0.1. The solution
76 * is to hard-code 127.0.0.1, but still check if get_myaddress() returns a
77 * different value and warn about it.
79 memset((char *) &sin
, 0, sizeof(sin
));
81 if (sin
.sin_addr
.s_addr
!= htonl(INADDR_LOOPBACK
))
82 dlog("amu_get_myaddress: myaddress conflict (0x%x vs. 0x%lx)",
83 sin
.sin_addr
.s_addr
, (u_long
) htonl(INADDR_LOOPBACK
));
84 #endif /* DEBUG_off */
86 if (preferred_localhost
== NULL
)
89 /* if specified preferred locahost, then try to use it */
90 hp
= gethostbyname(preferred_localhost
);
92 /* XXX: if hstrerror()/h_errno aren't portable, then need to port the next statement */
93 plog(XLOG_ERROR
, "Unable to resolve localhost_address \"%s\" (%s): using default",
94 preferred_localhost
, hstrerror(h_errno
));
97 if (hp
->h_addr_list
== NULL
) {
98 plog(XLOG_ERROR
, "localhost_address \"%s\" has no IP addresses: using default",
102 if (hp
->h_addr_list
[1] != NULL
) {
103 plog(XLOG_ERROR
, "localhost_address \"%s\" has more than one IP addresses: using first",
104 preferred_localhost
);
107 memmove((voidp
) &iap
->s_addr
, (voidp
) hp
->h_addr_list
[0], sizeof(iap
->s_addr
));
108 plog(XLOG_INFO
, "localhost_address \"%s\" requested, using %s",
109 preferred_localhost
, inet_dquad(dq
, sizeof(dq
), iap
->s_addr
));
113 iap
->s_addr
= htonl(INADDR_LOOPBACK
);
118 * How to bind to reserved ports.
119 * Note: if *pp is non-null and is greater than 0, then *pp will not be modified.
122 bind_resv_port(int so
, u_short
*pp
)
124 struct sockaddr_in sin
;
128 memset((voidp
) &sin
, 0, sizeof(sin
));
129 sin
.sin_family
= AF_INET
;
132 sin
.sin_port
= htons(*pp
);
133 rc
= bind(so
, (struct sockaddr
*) &sin
, sizeof(sin
));
135 port
= IPPORT_RESERVED
;
139 sin
.sin_port
= htons(port
);
140 rc
= bind(so
, (struct sockaddr
*) &sin
, sizeof(sin
));
141 } while (rc
< 0 && (int) port
> IPPORT_RESERVED
/ 2);
152 * close a descriptor, Sockets style
162 * Create an rpc client attached to the mount daemon.
165 get_mount_client(char *unused_host
, struct sockaddr_in
*sin
, struct timeval
*tv
, int *sock
, u_long mnt_version
)
170 * First try a TCP socket
172 if ((*sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) > 0) {
174 * Bind to a privileged port
176 if (bind_resv_port(*sock
, (u_short
*) NULL
) < 0)
177 plog(XLOG_ERROR
, "can't bind privileged port (socket)");
180 * Find mountd port to connect to.
182 * Create a tcp client.
184 if ((sin
->sin_port
= htons(pmap_getport(sin
, MOUNTPROG
, mnt_version
, IPPROTO_TCP
))) != 0) {
185 if (connect(*sock
, (struct sockaddr
*) sin
, sizeof(*sin
)) >= 0
186 && ((client
= clnttcp_create(sin
, MOUNTPROG
, mnt_version
, sock
, 0, 0)) != NULL
))
190 * Failed so close socket
193 } /* tcp socket opened */
194 /* TCP failed so try UDP */
195 if ((*sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
196 plog(XLOG_ERROR
, "Can't create socket to connect to mountd: %m");
201 * Bind to a privileged port
203 if (bind_resv_port(*sock
, (u_short
*) NULL
) < 0)
204 plog(XLOG_ERROR
, "can't bind privileged port");
207 * Zero out the port - make sure we recompute
214 if ((client
= clntudp_create(sin
, MOUNTPROG
, mnt_version
, *tv
, sock
)) == NULL
) {
219 dlog("get_mount_client: Using udp, port %d", sin
->sin_port
);
225 * find the address of the caller of an RPC procedure.
228 amu_svc_getcaller(SVCXPRT
*xprt
)
230 /* glibc 2.2 returns a sockaddr_storage ??? */
231 return (struct sockaddr_in
*) svc_getcaller(xprt
);
236 * Register an RPC server:
237 * return 1 on success, 0 otherwise.
240 amu_svc_register(SVCXPRT
*xprt
, u_long prognum
, u_long versnum
,
241 void (*dispatch
)(struct svc_req
*rqstp
, SVCXPRT
*transp
),
242 u_long protocol
, struct netconfig
*dummy
)
244 /* on Sockets: svc_register returns 1 on success, 0 otherwise */
245 return svc_register(xprt
, prognum
, versnum
, dispatch
, protocol
);
250 * Create the nfs service for amd
253 create_nfs_service(int *soNFSp
, u_short
*nfs_portp
, SVCXPRT
**nfs_xprtp
, void (*dispatch_fxn
)(struct svc_req
*rqstp
, SVCXPRT
*transp
))
256 *soNFSp
= socket(AF_INET
, SOCK_DGRAM
, 0);
258 if (*soNFSp
< 0 || bind_resv_port(*soNFSp
, nfs_portp
) < 0) {
259 plog(XLOG_FATAL
, "Can't create privileged nfs port (socket)");
264 if ((*nfs_xprtp
= svcudp_create(*soNFSp
)) == NULL
) {
265 plog(XLOG_FATAL
, "cannot create rpc/udp service");
269 if ((*nfs_portp
= (*nfs_xprtp
)->xp_port
) >= IPPORT_RESERVED
) {
270 plog(XLOG_FATAL
, "Can't create privileged nfs port");
271 svc_destroy(*nfs_xprtp
);
275 if (!svc_register(*nfs_xprtp
, NFS_PROGRAM
, NFS_VERSION
, dispatch_fxn
, 0)) {
276 plog(XLOG_FATAL
, "unable to register (%ld, %ld, 0)",
277 (u_long
) NFS_PROGRAM
, (u_long
) NFS_VERSION
);
278 svc_destroy(*nfs_xprtp
);
283 return 0; /* all is well */
288 * Create the amq service for amd (both TCP and UDP)
291 create_amq_service(int *udp_soAMQp
,
293 struct netconfig
**dummy1
,
296 struct netconfig
**dummy2
,
297 u_short preferred_amq_port
)
299 /* first create TCP service */
301 *tcp_soAMQp
= socket(AF_INET
, SOCK_STREAM
, 0);
302 if (*tcp_soAMQp
< 0) {
303 plog(XLOG_FATAL
, "cannot create tcp socket for amq service: %m");
307 /* next, bind to a specific (TCP) port if asked for */
308 if (preferred_amq_port
> 0) {
310 * Note: if &preferred_amq_port is non-null and is greater than 0,
311 * then the pointer will not be modified. We don't want it to be
312 * modified because it was passed down to create_amq_service as a
313 * non-pointer (a variable on the stack, not to be modified!)
315 if (bind_resv_port(*tcp_soAMQp
, &preferred_amq_port
) < 0) {
316 plog(XLOG_FATAL
, "can't bind amq service to requested TCP port %d: %m)", preferred_amq_port
);
321 /* now create RPC service handle for amq */
323 (*tcp_amqpp
= svctcp_create(*tcp_soAMQp
, AMQ_SIZE
, AMQ_SIZE
)) == NULL
) {
324 plog(XLOG_FATAL
, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp
);
328 #ifdef SVCSET_CONNMAXREC
330 * This is *BSD at its best.
331 * They just had to do things differently than everyone else
332 * so they fixed a library DoS issue by forcing client-side changes...
334 # ifndef RPC_MAXDATASIZE
335 # define RPC_MAXDATASIZE 9000
336 # endif /* not RPC_MAXDATASIZE */
338 int maxrec
= RPC_MAXDATASIZE
;
339 SVC_CONTROL(*tcp_amqpp
, SVCSET_CONNMAXREC
, &maxrec
);
341 #endif /* not SVCSET_CONNMAXREC */
344 /* next create UDP service */
346 *udp_soAMQp
= socket(AF_INET
, SOCK_DGRAM
, 0);
347 if (*udp_soAMQp
< 0) {
348 plog(XLOG_FATAL
, "cannot create udp socket for amq service: %m");
352 /* next, bind to a specific (UDP) port if asked for */
353 if (preferred_amq_port
> 0) {
355 * Note: see comment about using &preferred_amq_port above in this
358 if (bind_resv_port(*udp_soAMQp
, &preferred_amq_port
) < 0) {
359 plog(XLOG_FATAL
, "can't bind amq service to requested UDP port %d: %m)", preferred_amq_port
);
364 /* now create RPC service handle for amq */
366 (*udp_amqpp
= svcudp_bufcreate(*udp_soAMQp
, AMQ_SIZE
, AMQ_SIZE
)) == NULL
) {
367 plog(XLOG_FATAL
, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp
);
372 return 0; /* all is well */
377 * Check if the portmapper is running and reachable: 0==down, 1==up
379 int check_pmap_up(char *host
, struct sockaddr_in
* sin
)
382 enum clnt_stat clnt_stat
= RPC_TIMEDOUT
; /* assume failure */
383 int socket
= RPC_ANYSOCK
;
384 struct timeval timeout
;
388 sin
->sin_port
= htons(PMAPPORT
);
389 client
= clntudp_create(sin
, PMAPPROG
, PMAPVERS
, timeout
, &socket
);
391 if (client
== (CLIENT
*) NULL
) {
393 "check_pmap_up: cannot create connection to contact portmapper on host \"%s\"%s",
394 host
, clnt_spcreateerror(""));
399 /* Ping the portmapper on a remote system by calling the nullproc */
400 clnt_stat
= clnt_call(client
,
402 (XDRPROC_T_TYPE
) xdr_void
,
404 (XDRPROC_T_TYPE
) xdr_void
,
407 clnt_destroy(client
);
411 if (clnt_stat
== RPC_TIMEDOUT
) {
413 "check_pmap_up: failed to contact portmapper on host \"%s\": %s",
414 host
, clnt_sperrno(clnt_stat
));
422 * Find the best NFS version for a host and protocol.
425 get_nfs_version(char *host
, struct sockaddr_in
*sin
, u_long nfs_version
, const char *proto
)
429 enum clnt_stat clnt_stat
;
435 * If not set or set wrong, then try from NFS_VERS_MAX on down. If
436 * set, then try from nfs_version on down.
438 if (nfs_version
<= 0 || nfs_version
> NFS_VERS_MAX
) {
439 nfs_version
= NFS_VERS_MAX
;
442 tv
.tv_sec
= 2; /* retry every 2 seconds, but also timeout */
447 #endif /* HAVE_FS_NFS3 */
451 if (STREQ(proto
, "tcp"))
452 clnt
= clnttcp_create(sin
, NFS_PROGRAM
, nfs_version
, &sock
, 0, 0);
453 else if (STREQ(proto
, "udp"))
454 clnt
= clntudp_create(sin
, NFS_PROGRAM
, nfs_version
, tv
, &sock
);
459 /* Try three times (6/2=3) to verify the CLIENT handle. */
461 clnt_stat
= clnt_call(clnt
,
463 (XDRPROC_T_TYPE
) xdr_void
,
465 (XDRPROC_T_TYPE
) xdr_void
,
469 if (clnt_stat
!= RPC_SUCCESS
)
470 errstr
= clnt_sperrno(clnt_stat
);
475 #ifdef HAVE_CLNT_SPCREATEERROR
476 errstr
= clnt_spcreateerror("");
477 #else /* not HAVE_CLNT_SPCREATEERROR */
479 #endif /* not HAVE_CLNT_SPCREATEERROR */
483 plog(XLOG_INFO
, "get_nfs_version NFS(%d,%s) failed for %s%s",
484 (int) nfs_version
, proto
, host
, errstr
);
487 if (nfs_version
== NFS_VERSION3
) {
488 nfs_version
= NFS_VERSION
;
490 plog(XLOG_INFO
, "get_nfs_version trying a lower version: NFS(%d,%s)", (int) nfs_version
, proto
);
493 #endif /* HAVE_FS_NFS3 */
498 plog(XLOG_INFO
, "get_nfs_version: returning NFS(%d,%s) on host %s",
499 (int) nfs_version
, proto
, host
);
504 #if defined(HAVE_FS_AUTOFS) && defined(AUTOFS_PROG)
506 * Register the autofs service for amd
509 register_autofs_service(char *autofs_conftype
, void (*autofs_dispatch
)(struct svc_req
*rqstp
, SVCXPRT
*transp
))
512 SVCXPRT
*autofs_xprt
= NULL
;
514 autofs_socket
= socket(AF_INET
, SOCK_DGRAM
, 0);
516 if (autofs_socket
< 0 || bind_resv_port(autofs_socket
, NULL
) < 0) {
517 plog(XLOG_FATAL
, "Can't create privileged autofs port (socket)");
520 if ((autofs_xprt
= svcudp_create(autofs_socket
)) == NULL
) {
521 plog(XLOG_FATAL
, "Can't create autofs rpc/udp service");
524 if (autofs_xprt
->xp_port
>= IPPORT_RESERVED
) {
525 plog(XLOG_FATAL
, "Can't create privileged autofs port");
528 if (!svc_register(autofs_xprt
, AUTOFS_PROG
, AUTOFS_VERS
, autofs_dispatch
, 0)) {
529 plog(XLOG_FATAL
, "unable to register (%ld, %ld, 0)",
530 (u_long
) AUTOFS_PROG
, (u_long
) AUTOFS_VERS
);
534 return 0; /* all is well */
539 unregister_autofs_service(char *autofs_conftype
)
541 svc_unregister(AUTOFS_PROG
, AUTOFS_VERS
);
544 #endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */