Don't use .Xo/.Xc. Fix date format.
[netbsd-mini2440.git] / external / bsd / am-utils / dist / conf / transp / transp_tli.c
blobe5b8d77b36ce70e7c594ae79f53dbfacaf976b59
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_tli.c
44 * TLI 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>
54 struct netconfig *nfsncp;
58 * find the IP address that can be used to connect to the local host
60 void
61 amu_get_myaddress(struct in_addr *iap, const char *preferred_localhost)
63 int ret;
64 voidp handlep;
65 struct netconfig *ncp;
66 struct nd_addrlist *addrs = (struct nd_addrlist *) NULL;
67 struct nd_hostserv service;
69 handlep = setnetconfig();
70 ncp = getnetconfig(handlep);
71 service.h_host = (preferred_localhost ? (char *) preferred_localhost : HOST_SELF_CONNECT);
72 service.h_serv = (char *) NULL;
74 ret = netdir_getbyname(ncp, &service, &addrs);
76 if (ret || !addrs || addrs->n_cnt < 1) {
77 plog(XLOG_FATAL, "cannot get local host address. using 127.0.0.1");
78 iap->s_addr = htonl(INADDR_LOOPBACK);
79 } else {
81 * XXX: there may be more more than one address for this local
82 * host. Maybe something can be done with those.
84 struct sockaddr_in *sinp = (struct sockaddr_in *) addrs->n_addrs[0].buf;
85 char dq[20];
86 if (preferred_localhost)
87 plog(XLOG_INFO, "localhost_address \"%s\" requested, using %s",
88 preferred_localhost, inet_dquad(dq, sizeof(dq), iap->s_addr));
89 iap->s_addr = sinp->sin_addr.s_addr; /* XXX: used to be htonl() */
92 endnetconfig(handlep); /* free's up internal resources too */
93 netdir_free((voidp) addrs, ND_ADDRLIST);
98 * How to bind to reserved ports.
99 * TLI handle (socket) and port version.
102 bind_resv_port(int td, u_short *pp)
104 int rc = -1, port;
105 struct t_bind *treq, *tret;
106 struct sockaddr_in *sin;
108 treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
109 if (!treq) {
110 plog(XLOG_ERROR, "t_alloc req");
111 return -1;
113 tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
114 if (!tret) {
115 t_free((char *) treq, T_BIND);
116 plog(XLOG_ERROR, "t_alloc ret");
117 return -1;
119 memset((char *) treq->addr.buf, 0, treq->addr.len);
120 sin = (struct sockaddr_in *) treq->addr.buf;
121 sin->sin_family = AF_INET;
122 treq->qlen = 64; /* 0 is ok for udp, for tcp you need qlen>0 */
123 treq->addr.len = treq->addr.maxlen;
124 errno = EADDRINUSE;
125 port = IPPORT_RESERVED;
127 do {
128 --port;
129 sin->sin_port = htons(port);
130 rc = t_bind(td, treq, tret);
131 if (rc < 0) {
132 plog(XLOG_ERROR, "t_bind");
133 } else {
134 if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0)
135 break;
136 else
137 t_unbind(td);
139 } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2);
141 if (pp) {
142 if (rc == 0)
143 *pp = port;
144 else
145 plog(XLOG_ERROR, "could not t_bind to any reserved port");
147 t_free((char *) tret, T_BIND);
148 t_free((char *) treq, T_BIND);
149 return rc;
156 * close a descriptor, TLI style
159 amu_close(int fd)
161 return t_close(fd);
166 * Create an rpc client attached to the mount daemon.
168 CLIENT *
169 get_mount_client(char *host, struct sockaddr_in *unused_sin, struct timeval *tv, int *sock, u_long mnt_version)
171 CLIENT *client;
172 struct netbuf nb;
173 struct netconfig *nc = NULL;
174 struct sockaddr_in sin;
176 nb.maxlen = sizeof(sin);
177 nb.buf = (char *) &sin;
180 * First try a TCP handler
184 * Find mountd address on TCP
186 if ((nc = getnetconfigent(NC_TCP)) == NULL) {
187 plog(XLOG_ERROR, "getnetconfig for tcp failed: %s", nc_sperror());
188 goto tryudp;
190 if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) {
192 * don't print error messages here, since mountd might legitimately
193 * serve udp only
195 goto tryudp;
198 * Create privileged TCP socket
200 *sock = t_open(nc->nc_device, O_RDWR, 0);
202 if (*sock < 0) {
203 plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device);
204 goto tryudp;
206 if (bind_resv_port(*sock, (u_short *) NULL) < 0)
207 plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port");
209 if ((client = clnt_vc_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0))
210 == (CLIENT *) NULL) {
211 plog(XLOG_ERROR, "clnt_vc_create failed");
212 t_close(*sock);
213 goto tryudp;
215 /* tcp succeeded */
216 dlog("get_mount_client: using tcp, port %d", sin.sin_port);
217 if (nc)
218 freenetconfigent(nc);
219 return client;
221 tryudp:
222 /* first free possibly previously allocated netconfig entry */
223 if (nc)
224 freenetconfigent(nc);
227 * TCP failed so try UDP
231 * Find mountd address on UDP
233 if ((nc = getnetconfigent(NC_UDP)) == NULL) {
234 plog(XLOG_ERROR, "getnetconfig for udp failed: %s", nc_sperror());
235 goto badout;
237 if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) {
238 plog(XLOG_ERROR, "%s",
239 clnt_spcreateerror("couldn't get mountd address on udp"));
240 goto badout;
243 * Create privileged UDP socket
245 *sock = t_open(nc->nc_device, O_RDWR, 0);
247 if (*sock < 0) {
248 plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device);
249 goto badout; /* neither tcp not udp succeeded */
251 if (bind_resv_port(*sock, (u_short *) NULL) < 0)
252 plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port");
254 if ((client = clnt_dg_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0))
255 == (CLIENT *) NULL) {
256 plog(XLOG_ERROR, "clnt_dg_create failed");
257 t_close(*sock);
258 goto badout; /* neither tcp not udp succeeded */
260 if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) {
261 plog(XLOG_ERROR, "clnt_control CLSET_RETRY_TIMEOUT for udp failed");
262 clnt_destroy(client);
263 goto badout; /* neither tcp not udp succeeded */
265 /* udp succeeded */
266 dlog("get_mount_client: using udp, port %d", sin.sin_port);
267 return client;
269 badout:
270 /* failed */
271 if (nc)
272 freenetconfigent(nc);
273 return NULL;
277 #ifdef NOT_NEEDED_ON_TLI_SYSTEMS
279 * find the address of the caller of an RPC procedure.
281 struct sockaddr_in *
282 amu_svc_getcaller(SVCXPRT *xprt)
285 * On TLI systems we don't use an INET network type, but a "ticlts" (see
286 * /etc/netconfig). This means that packets could only come from the
287 * loopback interface, and we don't need to check them and filter possibly
288 * spoofed packets. Therefore we simply return NULL here, and the caller
289 * will ignore the result.
291 return NULL; /* tell called to ignore check */
293 #endif /* NOT_NEEDED_ON_TLI_SYSTEMS */
297 * Register an RPC server:
298 * return 1 on success, 0 otherwise.
301 amu_svc_register(SVCXPRT *xprt, u_long prognum, u_long versnum,
302 void (*dispatch)(struct svc_req *rqstp, SVCXPRT *xprt),
303 u_long protocol, struct netconfig *ncp)
305 /* on TLI: svc_reg returns 1 on success, 0 otherwise */
306 return svc_reg(xprt, prognum, versnum, dispatch, ncp);
311 * Bind to reserved UDP port, for NFS service only.
312 * Port-only version.
314 static int
315 bind_resv_port_only_udp(u_short *pp)
317 int td, rc = -1, port;
318 struct t_bind *treq, *tret;
319 struct sockaddr_in *sin;
320 extern char *t_errlist[];
321 extern int t_errno;
322 struct netconfig *nc = (struct netconfig *) NULL;
323 voidp nc_handle;
325 if ((nc_handle = setnetconfig()) == (voidp) NULL) {
326 plog(XLOG_ERROR, "Cannot rewind netconfig: %s", nc_sperror());
327 return -1;
330 * Search the netconfig table for INET/UDP.
331 * This loop will terminate if there was an error in the /etc/netconfig
332 * file or if you reached the end of the file without finding the udp
333 * device. Either way your machine has probably far more problems (for
334 * example, you cannot have nfs v2 w/o UDP).
336 while (1) {
337 if ((nc = getnetconfig(nc_handle)) == (struct netconfig *) NULL) {
338 plog(XLOG_ERROR, "Error accessing getnetconfig: %s", nc_sperror());
339 endnetconfig(nc_handle);
340 return -1;
342 if (STREQ(nc->nc_protofmly, NC_INET) &&
343 STREQ(nc->nc_proto, NC_UDP))
344 break;
348 * This is the primary reason for the getnetconfig code above: to get the
349 * correct device name to udp, and t_open a descriptor to be used in
350 * t_bind below.
352 td = t_open(nc->nc_device, O_RDWR, (struct t_info *) NULL);
353 endnetconfig(nc_handle);
355 if (td < 0) {
356 plog(XLOG_ERROR, "t_open failed: %d: %s", t_errno, t_errlist[t_errno]);
357 return -1;
359 treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
360 if (!treq) {
361 plog(XLOG_ERROR, "t_alloc req");
362 return -1;
364 tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
365 if (!tret) {
366 t_free((char *) treq, T_BIND);
367 plog(XLOG_ERROR, "t_alloc ret");
368 return -1;
370 memset((char *) treq->addr.buf, 0, treq->addr.len);
371 sin = (struct sockaddr_in *) treq->addr.buf;
372 sin->sin_family = AF_INET;
373 treq->qlen = 64; /* 0 is ok for udp, for tcp you need qlen>0 */
374 treq->addr.len = treq->addr.maxlen;
375 errno = EADDRINUSE;
377 if (pp && *pp > 0) {
378 sin->sin_port = htons(*pp);
379 rc = t_bind(td, treq, tret);
380 } else {
381 port = IPPORT_RESERVED;
383 do {
384 --port;
385 sin->sin_port = htons(port);
386 rc = t_bind(td, treq, tret);
387 if (rc < 0) {
388 plog(XLOG_ERROR, "t_bind for port %d: %s", port, t_errlist[t_errno]);
389 } else {
390 if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0)
391 break;
392 else
393 t_unbind(td);
395 } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2);
397 if (pp && rc == 0)
398 *pp = port;
401 t_free((char *) tret, T_BIND);
402 t_free((char *) treq, T_BIND);
403 return rc;
408 * Bind NFS to a reserved port.
410 static int
411 bind_nfs_port(int unused_so, u_short *nfs_portp)
413 u_short port = 0;
414 int error = bind_resv_port_only_udp(&port);
416 if (error == 0)
417 *nfs_portp = port;
418 return error;
423 * Create the nfs service for amd
424 * return 0 (TRUE) if OK, 1 (FALSE) if failed.
427 create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
429 char *nettype = "ticlts";
431 nfsncp = getnetconfigent(nettype);
432 if (nfsncp == NULL) {
433 plog(XLOG_ERROR, "cannot getnetconfigent for %s", nettype);
434 /* failed with ticlts, try plain udp (hpux11) */
435 nettype = "udp";
436 nfsncp = getnetconfigent(nettype);
437 if (nfsncp == NULL) {
438 plog(XLOG_ERROR, "cannot getnetconfigent for %s", nettype);
439 return 1;
442 *nfs_xprtp = svc_tli_create(RPC_ANYFD, nfsncp, NULL, 0, 0);
443 if (*nfs_xprtp == NULL) {
444 plog(XLOG_ERROR, "cannot create nfs tli service for amd");
445 return 1;
449 * Get the service file descriptor and check its number to see if
450 * the t_open failed. If it succeeded, then go on to binding to a
451 * reserved nfs port.
453 *soNFSp = (*nfs_xprtp)->xp_fd;
454 if (*soNFSp < 0 || bind_nfs_port(*soNFSp, nfs_portp) < 0) {
455 plog(XLOG_ERROR, "Can't create privileged nfs port (TLI)");
456 svc_destroy(*nfs_xprtp);
457 return 1;
459 if (svc_reg(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, NULL) != 1) {
460 plog(XLOG_ERROR, "could not register amd NFS service");
461 svc_destroy(*nfs_xprtp);
462 return 1;
465 return 0; /* all is well */
470 * Bind to preferred AMQ port.
472 static int
473 bind_preferred_amq_port(u_short pref_port,
474 const struct netconfig *ncp,
475 struct t_bind **tretpp)
477 int td = -1, rc = -1;
478 struct t_bind *treq;
479 struct sockaddr_in *sin, *sin2;
480 extern char *t_errlist[];
481 extern int t_errno;
483 if (!ncp) {
484 plog(XLOG_ERROR, "null ncp");
485 return -1;
488 td = t_open(ncp->nc_device, O_RDWR, (struct t_info *) NULL);
489 if (td < 0) {
490 plog(XLOG_ERROR, "t_open failed: %d: %s", t_errno, t_errlist[t_errno]);
491 return -1;
493 treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
494 if (!treq) {
495 plog(XLOG_ERROR, "t_alloc req");
496 return -1;
498 *tretpp = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
499 if (!*tretpp) {
500 t_free((char *) treq, T_BIND);
501 plog(XLOG_ERROR, "t_alloc tretpp");
502 return -1;
504 memset((char *) treq->addr.buf, 0, treq->addr.len);
505 sin = (struct sockaddr_in *) treq->addr.buf;
506 sin->sin_family = AF_INET;
507 treq->qlen = 64; /* must be greater than 0 to work for TCP connections */
508 treq->addr.len = treq->addr.maxlen;
510 if (pref_port > 0) {
511 sin->sin_port = htons(pref_port);
512 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* XXX: may not be needed */
513 rc = t_bind(td, treq, *tretpp);
514 if (rc < 0) {
515 plog(XLOG_ERROR, "t_bind return err %d", rc);
516 goto out;
518 /* check if we got the port we asked for */
519 sin2 = (struct sockaddr_in *) (*tretpp)->addr.buf;
520 if (sin->sin_port != sin2->sin_port) {
521 plog(XLOG_ERROR, "asked for port %d, got different one (%d)",
522 ntohs(sin->sin_port), ntohs(sin2->sin_port));
523 t_errno = TNOADDR; /* XXX: is this correct? */
524 rc = -1;
525 goto out;
527 if (sin->sin_addr.s_addr != sin2->sin_addr.s_addr) {
528 plog(XLOG_ERROR, "asked for address %x, got different one (%x)",
529 (int) ntohl(sin->sin_addr.s_addr), (int) ntohl(sin2->sin_addr.s_addr));
530 t_errno = TNOADDR; /* XXX: is this correct? */
531 rc = -1;
532 goto out;
535 out:
536 t_free((char *) treq, T_BIND);
537 return (rc < 0 ? rc : td);
542 * Create the amq service for amd (both TCP and UDP)
545 create_amq_service(int *udp_soAMQp,
546 SVCXPRT **udp_amqpp,
547 struct netconfig **udp_amqncpp,
548 int *tcp_soAMQp,
549 SVCXPRT **tcp_amqpp,
550 struct netconfig **tcp_amqncpp,
551 u_short preferred_amq_port)
554 * (partially) create the amq service for amd
555 * to be completed further in by caller.
556 * XXX: is this "partially" still true?! See amd/nfs_start.c. -Erez
559 /* first create the TCP service */
560 if (tcp_amqncpp)
561 if ((*tcp_amqncpp = getnetconfigent(NC_TCP)) == NULL) {
562 plog(XLOG_ERROR, "cannot getnetconfigent for %s", NC_TCP);
563 return 1;
566 if (tcp_amqpp) {
567 if (preferred_amq_port > 0) {
568 struct t_bind *tbp = NULL;
569 int sock;
571 plog(XLOG_INFO, "requesting preferred amq TCP port %d", preferred_amq_port);
572 sock = bind_preferred_amq_port(preferred_amq_port, *tcp_amqncpp, &tbp);
573 if (sock < 0) {
574 plog(XLOG_ERROR, "bind_preferred_amq_port failed for TCP port %d: %s",
575 preferred_amq_port, t_errlist[t_errno]);
576 return 1;
578 *tcp_amqpp = svc_tli_create(sock, *tcp_amqncpp, tbp, 0, 0);
579 if (*tcp_amqpp != NULL)
580 plog(XLOG_INFO, "amq service bound to TCP port %d", preferred_amq_port);
581 t_free((char *) tbp, T_BIND);
582 } else {
583 /* select any port */
584 *tcp_amqpp = svc_tli_create(RPC_ANYFD, *tcp_amqncpp, NULL, 0, 0);
586 if (*tcp_amqpp == NULL) {
587 plog(XLOG_ERROR, "cannot create (tcp) tli service for amq");
588 return 1;
591 if (tcp_soAMQp && tcp_amqpp)
592 *tcp_soAMQp = (*tcp_amqpp)->xp_fd;
594 /* next create the UDP service */
595 if (udp_amqncpp)
596 if ((*udp_amqncpp = getnetconfigent(NC_UDP)) == NULL) {
597 plog(XLOG_ERROR, "cannot getnetconfigent for %s", NC_UDP);
598 return 1;
600 if (udp_amqpp) {
601 if (preferred_amq_port > 0) {
602 struct t_bind *tbp = NULL;
603 int sock;
605 plog(XLOG_INFO, "requesting preferred amq UDP port %d", preferred_amq_port);
606 sock = bind_preferred_amq_port(preferred_amq_port, *udp_amqncpp, &tbp);
607 if (sock < 0) {
608 plog(XLOG_ERROR, "bind_preferred_amq_port failed for UDP port %d: %s",
609 preferred_amq_port, t_errlist[t_errno]);
610 return 1;
612 *udp_amqpp = svc_tli_create(sock, *udp_amqncpp, tbp, 0, 0);
613 if (*udp_amqpp != NULL)
614 plog(XLOG_INFO, "amq service bound to UDP port %d", preferred_amq_port);
615 t_free((char *) tbp, T_BIND);
616 } else {
617 /* select any port */
618 *udp_amqpp = svc_tli_create(RPC_ANYFD, *udp_amqncpp, NULL, 0, 0);
620 if (*udp_amqpp == NULL) {
621 plog(XLOG_ERROR, "cannot create (udp) tli service for amq");
622 return 1;
625 if (udp_soAMQp && udp_amqpp)
626 *udp_soAMQp = (*udp_amqpp)->xp_fd;
628 return 0; /* all is well */
633 * Find netconfig info for TCP/UDP device, and fill in the knetconfig
634 * structure. If in_ncp is not NULL, use that instead of defaulting
635 * to a TCP/UDP service. If in_ncp is NULL, then use the service type
636 * specified in nc_protoname (which may be either "tcp" or "udp"). If
637 * nc_protoname is NULL, default to UDP.
640 get_knetconfig(struct knetconfig **kncpp, struct netconfig *in_ncp, char *nc_protoname)
642 struct netconfig *ncp = NULL;
643 struct stat statbuf;
645 if (in_ncp)
646 ncp = in_ncp;
647 else {
648 if (nc_protoname)
649 ncp = getnetconfigent(nc_protoname);
650 else
651 ncp = getnetconfigent(NC_UDP);
653 if (!ncp)
654 return -2;
656 *kncpp = (struct knetconfig *) xzalloc(sizeof(struct knetconfig));
657 if (*kncpp == (struct knetconfig *) NULL) {
658 if (!in_ncp)
659 freenetconfigent(ncp);
660 return -3;
662 (*kncpp)->knc_semantics = ncp->nc_semantics;
663 (*kncpp)->knc_protofmly = strdup(ncp->nc_protofmly);
664 (*kncpp)->knc_proto = strdup(ncp->nc_proto);
666 if (stat(ncp->nc_device, &statbuf) < 0) {
667 plog(XLOG_ERROR, "could not stat() %s: %m", ncp->nc_device);
668 XFREE(*kncpp);
669 *kncpp = NULL;
670 if (!in_ncp)
671 freenetconfigent(ncp);
672 return -3; /* amd will end (free not needed) */
674 (*kncpp)->knc_rdev = (dev_t) statbuf.st_rdev;
675 if (!in_ncp) { /* free only if argument not passed */
676 freenetconfigent(ncp);
677 ncp = NULL;
679 return 0;
684 * Free a previously allocated knetconfig structure.
686 void
687 free_knetconfig(struct knetconfig *kncp)
689 if (kncp) {
690 if (kncp->knc_protofmly)
691 XFREE(kncp->knc_protofmly);
692 if (kncp->knc_proto)
693 XFREE(kncp->knc_proto);
694 XFREE(kncp);
695 kncp = (struct knetconfig *) NULL;
701 * Check if the portmapper is running and reachable: 0==down, 1==up
703 int check_pmap_up(char *host, struct sockaddr_in* sin)
705 CLIENT *client;
706 enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
707 int socket = RPC_ANYSOCK;
708 struct timeval timeout;
710 timeout.tv_sec = 2;
711 timeout.tv_usec = 0;
712 sin->sin_port = htons(PMAPPORT);
713 client = clntudp_create(sin, PMAPPROG, PMAPVERS, timeout, &socket);
714 if (client == (CLIENT *) NULL) {
715 plog(XLOG_ERROR,
716 "check_pmap_up: cannot create connection to contact portmapper on host \"%s\"%s",
717 host, clnt_spcreateerror(""));
718 return 0;
721 timeout.tv_sec = 6;
722 /* Ping the portmapper on a remote system by calling the nullproc */
723 clnt_stat = clnt_call(client,
724 PMAPPROC_NULL,
725 (XDRPROC_T_TYPE) xdr_void,
726 NULL,
727 (XDRPROC_T_TYPE) xdr_void,
728 NULL,
729 timeout);
730 clnt_destroy(client);
731 close(socket);
732 sin->sin_port = 0;
734 if (clnt_stat == RPC_TIMEDOUT) {
735 plog(XLOG_ERROR,
736 "check_pmap_up: failed to contact portmapper on host \"%s\": %s",
737 host, clnt_sperrno(clnt_stat));
738 return 0;
740 return 1;
745 * Find the best NFS version for a host.
747 u_long
748 get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto)
750 CLIENT *clnt = NULL;
751 rpcvers_t versout;
752 struct timeval tv;
755 * If not set or set wrong, then try from NFS_VERS_MAX on down. If
756 * set, then try from nfs_version on down.
758 if (nfs_version <= 0 || nfs_version > NFS_VERS_MAX) {
759 nfs_version = NFS_VERS_MAX;
762 if (nfs_version == NFS_VERSION) {
763 dlog("get_nfs_version trying NFS(%d,%s) for %s",
764 (int) nfs_version, proto, host);
765 } else {
766 dlog("get_nfs_version trying NFS(%d-%d,%s) for %s",
767 (int) NFS_VERSION, (int) nfs_version, proto, host);
770 /* 3 seconds is more than enough for a LAN */
771 memset(&tv, 0, sizeof(tv));
772 tv.tv_sec = 3;
773 tv.tv_usec = 0;
775 #ifdef HAVE_CLNT_CREATE_VERS_TIMED
776 clnt = clnt_create_vers_timed(host, NFS_PROGRAM, &versout, NFS_VERSION, nfs_version, proto, &tv);
777 #else /* not HAVE_CLNT_CREATE_VERS_TIMED */
778 clnt = clnt_create_vers(host, NFS_PROGRAM, &versout, NFS_VERSION, nfs_version, proto);
779 #endif /* not HAVE_CLNT_CREATE_VERS_TIMED */
781 if (clnt == NULL) {
782 if (nfs_version == NFS_VERSION)
783 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s: %s",
784 (int) nfs_version, proto, host, clnt_spcreateerror(""));
785 else
786 plog(XLOG_INFO, "get_nfs_version NFS(%d-%d,%s) failed for %s: %s",
787 (int) NFS_VERSION, (int) nfs_version, proto, host, clnt_spcreateerror(""));
788 return 0;
790 clnt_destroy(clnt);
792 return versout;
796 #if defined(HAVE_FS_AUTOFS) && defined(AUTOFS_PROG)
798 * find the IP address that can be used to connect autofs service to.
800 static int
801 get_autofs_address(struct netconfig *ncp, struct t_bind *tbp)
803 int ret;
804 struct nd_addrlist *addrs = (struct nd_addrlist *) NULL;
805 struct nd_hostserv service;
807 service.h_host = HOST_SELF_CONNECT;
808 service.h_serv = "autofs";
810 ret = netdir_getbyname(ncp, &service, &addrs);
812 if (ret) {
813 plog(XLOG_FATAL, "get_autofs_address: cannot get local host address: %s", netdir_sperror());
814 goto out;
818 * XXX: there may be more more than one address for this local
819 * host. Maybe something can be done with those.
821 tbp->addr.len = addrs->n_addrs->len;
822 tbp->addr.maxlen = addrs->n_addrs->len;
823 memcpy(tbp->addr.buf, addrs->n_addrs->buf, addrs->n_addrs->len);
825 * qlen should not be zero for TCP connections. It's not clear what it
826 * should be for UDP connections, but setting it to something like 64 seems
827 * to be the safe value that works.
829 tbp->qlen = 64;
831 /* all OK */
832 netdir_free((voidp) addrs, ND_ADDRLIST);
834 out:
835 return ret;
840 * Register the autofs service for amd
843 register_autofs_service(char *autofs_conftype,
844 void (*autofs_dispatch)(struct svc_req *rqstp, SVCXPRT *xprt))
846 struct t_bind *tbp = NULL;
847 struct netconfig *autofs_ncp;
848 SVCXPRT *autofs_xprt = NULL;
849 int fd = -1, err = 1; /* assume failed */
851 plog(XLOG_INFO, "registering autofs service: %s", autofs_conftype);
852 autofs_ncp = getnetconfigent(autofs_conftype);
853 if (autofs_ncp == NULL) {
854 plog(XLOG_ERROR, "register_autofs_service: cannot getnetconfigent for %s", autofs_conftype);
855 goto out;
858 fd = t_open(autofs_ncp->nc_device, O_RDWR, NULL);
859 if (fd < 0) {
860 plog(XLOG_ERROR, "register_autofs_service: t_open failed (%s)",
861 t_errlist[t_errno]);
862 goto out;
865 tbp = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
866 if (!tbp) {
867 plog(XLOG_ERROR, "register_autofs_service: t_alloc failed");
868 goto out;
871 if (get_autofs_address(autofs_ncp, tbp) != 0) {
872 plog(XLOG_ERROR, "register_autofs_service: get_autofs_address failed");
873 goto out;
876 autofs_xprt = svc_tli_create(fd, autofs_ncp, tbp, 0, 0);
877 if (autofs_xprt == NULL) {
878 plog(XLOG_ERROR, "cannot create autofs tli service for amd");
879 goto out;
882 rpcb_unset(AUTOFS_PROG, AUTOFS_VERS, autofs_ncp);
883 if (svc_reg(autofs_xprt, AUTOFS_PROG, AUTOFS_VERS, autofs_dispatch, autofs_ncp) == FALSE) {
884 plog(XLOG_ERROR, "could not register amd AUTOFS service");
885 goto out;
887 err = 0;
888 goto really_out;
890 out:
891 if (autofs_ncp)
892 freenetconfigent(autofs_ncp);
893 if (autofs_xprt)
894 SVC_DESTROY(autofs_xprt);
895 else {
896 if (fd > 0)
897 t_close(fd);
900 really_out:
901 if (tbp)
902 t_free((char *) tbp, T_BIND);
904 dlog("register_autofs_service: returning %d\n", err);
905 return err;
910 unregister_autofs_service(char *autofs_conftype)
912 struct netconfig *autofs_ncp;
913 int err = 1;
915 plog(XLOG_INFO, "unregistering autofs service listener: %s", autofs_conftype);
917 autofs_ncp = getnetconfigent(autofs_conftype);
918 if (autofs_ncp == NULL) {
919 plog(XLOG_ERROR, "destroy_autofs_service: cannot getnetconfigent for %s", autofs_conftype);
920 goto out;
923 out:
924 rpcb_unset(AUTOFS_PROG, AUTOFS_VERS, autofs_ncp);
925 return err;
927 #endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */