Don't use .Xo/.Xc. Fix date format.
[netbsd-mini2440.git] / external / bsd / am-utils / dist / conf / transp / transp_sockets.c
blobf0d0639910f221cc223bac7b55dcd0060de5d54c
1 /* $NetBSD$ */
3 /*
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.
8 * All rights reserved.
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
15 * are met:
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
39 * SUCH DAMAGE.
42 * File: am-utils/conf/transp/transp_sockets.c
44 * Socket specific utilities.
45 * -Erez Zadok <ezk@cs.columbia.edu>
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <amu.h>
56 * find the IP address that can be used to connect to the local host
58 void
59 amu_get_myaddress(struct in_addr *iap, const char *preferred_localhost)
61 struct hostent *hp;
62 char dq[20];
64 #ifdef DEBUG_off
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));
80 get_myaddress(&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)
87 goto out;
89 /* if specified preferred locahost, then try to use it */
90 hp = gethostbyname(preferred_localhost);
91 if (hp == NULL) {
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));
95 goto out;
97 if (hp->h_addr_list == NULL) {
98 plog(XLOG_ERROR, "localhost_address \"%s\" has no IP addresses: using default",
99 preferred_localhost);
100 goto out;
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);
105 goto out;
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));
110 return;
112 out:
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;
125 int rc;
126 u_short port;
128 memset((voidp) &sin, 0, sizeof(sin));
129 sin.sin_family = AF_INET;
131 if (pp && *pp > 0) {
132 sin.sin_port = htons(*pp);
133 rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
134 } else {
135 port = IPPORT_RESERVED;
137 do {
138 --port;
139 sin.sin_port = htons(port);
140 rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
141 } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
143 if (pp && rc == 0)
144 *pp = port;
147 return rc;
152 * close a descriptor, Sockets style
155 amu_close(int fd)
157 return close(fd);
162 * Create an rpc client attached to the mount daemon.
164 CLIENT *
165 get_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version)
167 CLIENT *client;
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.
181 * Connect to mountd.
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))
187 return client;
190 * Failed so close socket
192 (void) close(*sock);
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");
197 *sock = RPC_ANYSOCK;
198 return NULL;
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
209 sin->sin_port = 0;
212 * Make a UDP client
214 if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) {
215 (void) close(*sock);
216 *sock = RPC_ANYSOCK;
217 return NULL;
219 dlog("get_mount_client: Using udp, port %d", sin->sin_port);
220 return client;
225 * find the address of the caller of an RPC procedure.
227 struct sockaddr_in *
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)");
260 if (*soNFSp >= 0)
261 close(*soNFSp);
262 return 1;
264 if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) {
265 plog(XLOG_FATAL, "cannot create rpc/udp service");
266 close(*soNFSp);
267 return 2;
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);
272 close(*soNFSp);
273 return 1;
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);
279 close(*soNFSp);
280 return 3;
283 return 0; /* all is well */
288 * Create the amq service for amd (both TCP and UDP)
291 create_amq_service(int *udp_soAMQp,
292 SVCXPRT **udp_amqpp,
293 struct netconfig **dummy1,
294 int *tcp_soAMQp,
295 SVCXPRT **tcp_amqpp,
296 struct netconfig **dummy2,
297 u_short preferred_amq_port)
299 /* first create TCP service */
300 if (tcp_soAMQp) {
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");
304 return 1;
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);
317 return 1;
321 /* now create RPC service handle for amq */
322 if (tcp_amqpp &&
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);
325 return 1;
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 */
337 if (tcp_amqpp) {
338 int maxrec = RPC_MAXDATASIZE;
339 SVC_CONTROL(*tcp_amqpp, SVCSET_CONNMAXREC, &maxrec);
341 #endif /* not SVCSET_CONNMAXREC */
344 /* next create UDP service */
345 if (udp_soAMQp) {
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");
349 return 1;
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
356 * function.
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);
360 return 1;
364 /* now create RPC service handle for amq */
365 if (udp_amqpp &&
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);
368 return 1;
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)
381 CLIENT *client;
382 enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
383 int socket = RPC_ANYSOCK;
384 struct timeval timeout;
386 timeout.tv_sec = 2;
387 timeout.tv_usec = 0;
388 sin->sin_port = htons(PMAPPORT);
389 client = clntudp_create(sin, PMAPPROG, PMAPVERS, timeout, &socket);
391 if (client == (CLIENT *) NULL) {
392 plog(XLOG_ERROR,
393 "check_pmap_up: cannot create connection to contact portmapper on host \"%s\"%s",
394 host, clnt_spcreateerror(""));
395 return 0;
398 timeout.tv_sec = 6;
399 /* Ping the portmapper on a remote system by calling the nullproc */
400 clnt_stat = clnt_call(client,
401 PMAPPROC_NULL,
402 (XDRPROC_T_TYPE) xdr_void,
403 NULL,
404 (XDRPROC_T_TYPE) xdr_void,
405 NULL,
406 timeout);
407 clnt_destroy(client);
408 close(socket);
409 sin->sin_port = 0;
411 if (clnt_stat == RPC_TIMEDOUT) {
412 plog(XLOG_ERROR,
413 "check_pmap_up: failed to contact portmapper on host \"%s\": %s",
414 host, clnt_sperrno(clnt_stat));
415 return 0;
417 return 1;
422 * Find the best NFS version for a host and protocol.
424 u_long
425 get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto)
427 CLIENT *clnt;
428 int again = 0;
429 enum clnt_stat clnt_stat;
430 struct timeval tv;
431 int sock;
432 char *errstr;
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;
440 again = 1;
442 tv.tv_sec = 2; /* retry every 2 seconds, but also timeout */
443 tv.tv_usec = 0;
445 #ifdef HAVE_FS_NFS3
446 try_again:
447 #endif /* HAVE_FS_NFS3 */
449 sock = RPC_ANYSOCK;
450 errstr = NULL;
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);
455 else
456 clnt = NULL;
458 if (clnt != NULL) {
459 /* Try three times (6/2=3) to verify the CLIENT handle. */
460 tv.tv_sec = 6;
461 clnt_stat = clnt_call(clnt,
462 NFSPROC_NULL,
463 (XDRPROC_T_TYPE) xdr_void,
465 (XDRPROC_T_TYPE) xdr_void,
467 tv);
469 if (clnt_stat != RPC_SUCCESS)
470 errstr = clnt_sperrno(clnt_stat);
472 close(sock);
473 clnt_destroy(clnt);
474 } else {
475 #ifdef HAVE_CLNT_SPCREATEERROR
476 errstr = clnt_spcreateerror("");
477 #else /* not HAVE_CLNT_SPCREATEERROR */
478 errstr = "";
479 #endif /* not HAVE_CLNT_SPCREATEERROR */
482 if (errstr) {
483 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s%s",
484 (int) nfs_version, proto, host, errstr);
485 if (again) {
486 #ifdef HAVE_FS_NFS3
487 if (nfs_version == NFS_VERSION3) {
488 nfs_version = NFS_VERSION;
489 again = 0;
490 plog(XLOG_INFO, "get_nfs_version trying a lower version: NFS(%d,%s)", (int) nfs_version, proto);
492 goto try_again;
493 #endif /* HAVE_FS_NFS3 */
495 return 0;
498 plog(XLOG_INFO, "get_nfs_version: returning NFS(%d,%s) on host %s",
499 (int) nfs_version, proto, host);
500 return nfs_version;
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))
511 int autofs_socket;
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)");
518 return 1;
520 if ((autofs_xprt = svcudp_create(autofs_socket)) == NULL) {
521 plog(XLOG_FATAL, "Can't create autofs rpc/udp service");
522 return 2;
524 if (autofs_xprt->xp_port >= IPPORT_RESERVED) {
525 plog(XLOG_FATAL, "Can't create privileged autofs port");
526 return 1;
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);
531 return 3;
534 return 0; /* all is well */
539 unregister_autofs_service(char *autofs_conftype)
541 svc_unregister(AUTOFS_PROG, AUTOFS_VERS);
542 return 0;
544 #endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */