138494Sobrien/*
2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok
338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry
438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
538494Sobrien * Copyright (c) 1990 The Regents of the University of California.
638494Sobrien * All rights reserved.
738494Sobrien *
838494Sobrien * This code is derived from software contributed to Berkeley by
938494Sobrien * Jan-Simon Pendry at Imperial College, London.
1038494Sobrien *
1138494Sobrien * Redistribution and use in source and binary forms, with or without
1238494Sobrien * modification, are permitted provided that the following conditions
1338494Sobrien * are met:
1438494Sobrien * 1. Redistributions of source code must retain the above copyright
1538494Sobrien *    notice, this list of conditions and the following disclaimer.
1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1738494Sobrien *    notice, this list of conditions and the following disclaimer in the
1838494Sobrien *    documentation and/or other materials provided with the distribution.
1938494Sobrien * 3. All advertising materials mentioning features or use of this software
2042629Sobrien *    must display the following acknowledgment:
2138494Sobrien *      This product includes software developed by the University of
2238494Sobrien *      California, Berkeley and its contributors.
2338494Sobrien * 4. Neither the name of the University nor the names of its contributors
2438494Sobrien *    may be used to endorse or promote products derived from this software
2538494Sobrien *    without specific prior written permission.
2638494Sobrien *
2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3038494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3738494Sobrien * SUCH DAMAGE.
3838494Sobrien *
3938494Sobrien *
40174294Sobrien * File: am-utils/conf/transp/transp_sockets.c
4138494Sobrien *
4238494Sobrien * Socket specific utilities.
4338494Sobrien *      -Erez Zadok <ezk@cs.columbia.edu>
4438494Sobrien */
4538494Sobrien
4638494Sobrien#ifdef HAVE_CONFIG_H
4738494Sobrien# include <config.h>
4838494Sobrien#endif /* HAVE_CONFIG_H */
4938494Sobrien#include <am_defs.h>
5038494Sobrien#include <amu.h>
5138494Sobrien
5238494Sobrien
5338494Sobrien/*
5438494Sobrien * find the IP address that can be used to connect to the local host
5538494Sobrien */
5638494Sobrienvoid
57174294Sobrienamu_get_myaddress(struct in_addr *iap, const char *preferred_localhost)
5838494Sobrien{
59174294Sobrien  struct hostent *hp;
60174294Sobrien  char dq[20];
61174294Sobrien
62174294Sobrien#ifdef DEBUG_off
63174294Sobrien#error this code is old and probably not useful any longer.
64174294Sobrien#error Erez, Jan 21, 2004.
6538494Sobrien  struct sockaddr_in sin;
6638494Sobrien
67174294Sobrien  /*
68174294Sobrien   * Most modern systems should use 127.0.0.1 as the localhost address over
69174294Sobrien   * which you can do NFS mounts.  In the past we found that some NFS
70174294Sobrien   * clients may not allow mounts from localhost.  So we used
71174294Sobrien   * get_myaddress() and that seemed to work.  Alas, on some other systems,
72174294Sobrien   * get_myaddress() may return one of the interface addresses at random,
73174294Sobrien   * and thus use a less efficient IP address than 127.0.0.1.  The solution
74174294Sobrien   * is to hard-code 127.0.0.1, but still check if get_myaddress() returns a
75174294Sobrien   * different value and warn about it.
76174294Sobrien   */
7738494Sobrien  memset((char *) &sin, 0, sizeof(sin));
7838494Sobrien  get_myaddress(&sin);
79174294Sobrien  if (sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
80174294Sobrien    dlog("amu_get_myaddress: myaddress conflict (0x%x vs. 0x%lx)",
81174294Sobrien	 sin.sin_addr.s_addr, (u_long) htonl(INADDR_LOOPBACK));
82174294Sobrien#endif /* DEBUG_off */
83174294Sobrien
84174294Sobrien  if (preferred_localhost == NULL)
85174294Sobrien    goto out;
86174294Sobrien
87174294Sobrien  /* if specified preferred locahost, then try to use it */
88174294Sobrien  hp = gethostbyname(preferred_localhost);
89174294Sobrien  if (hp == NULL) {
90174294Sobrien    /* XXX: if hstrerror()/h_errno aren't portable, then need to port the next statement */
91174294Sobrien    plog(XLOG_ERROR, "Unable to resolve localhost_address \"%s\" (%s): using default",
92174294Sobrien	 preferred_localhost, hstrerror(h_errno));
93174294Sobrien    goto out;
94174294Sobrien  }
95174294Sobrien  if (hp->h_addr_list == NULL) {
96174294Sobrien    plog(XLOG_ERROR, "localhost_address \"%s\" has no IP addresses: using default",
97174294Sobrien	 preferred_localhost);
98174294Sobrien    goto out;
99174294Sobrien  }
100174294Sobrien  if (hp->h_addr_list[1] != NULL) {
101174294Sobrien    plog(XLOG_ERROR, "localhost_address \"%s\" has more than one IP addresses: using first",
102174294Sobrien	 preferred_localhost);
103174294Sobrien    goto out;
104174294Sobrien  }
105174294Sobrien  memmove((voidp) &iap->s_addr, (voidp) hp->h_addr_list[0], sizeof(iap->s_addr));
106174294Sobrien  plog(XLOG_INFO, "localhost_address \"%s\" requested, using %s",
107174294Sobrien       preferred_localhost, inet_dquad(dq, sizeof(dq), iap->s_addr));
108174294Sobrien  return;
109174294Sobrien
110174294Sobrien out:
111174294Sobrien  iap->s_addr = htonl(INADDR_LOOPBACK);
11238494Sobrien}
11338494Sobrien
11438494Sobrien
11538494Sobrien/*
11638494Sobrien * How to bind to reserved ports.
117174294Sobrien * Note: if *pp is non-null and is greater than 0, then *pp will not be modified.
11838494Sobrien */
11938494Sobrienint
12038494Sobrienbind_resv_port(int so, u_short *pp)
12138494Sobrien{
12238494Sobrien  struct sockaddr_in sin;
12338494Sobrien  int rc;
12438494Sobrien  u_short port;
12538494Sobrien
12638494Sobrien  memset((voidp) &sin, 0, sizeof(sin));
12738494Sobrien  sin.sin_family = AF_INET;
12838494Sobrien
129174294Sobrien  if (pp && *pp > 0) {
130174294Sobrien    sin.sin_port = htons(*pp);
13138494Sobrien    rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
132174294Sobrien  } else {
133174294Sobrien    port = IPPORT_RESERVED;
13438494Sobrien
135174294Sobrien    do {
136174294Sobrien      --port;
137174294Sobrien      sin.sin_port = htons(port);
138174294Sobrien      rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
139174294Sobrien    } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
14038494Sobrien
141174294Sobrien    if (pp && rc == 0)
142174294Sobrien      *pp = port;
143174294Sobrien  }
144174294Sobrien
14538494Sobrien  return rc;
14638494Sobrien}
14738494Sobrien
14838494Sobrien
14938494Sobrien/*
15038494Sobrien * close a descriptor, Sockets style
15138494Sobrien */
15238494Sobrienint
15338494Sobrienamu_close(int fd)
15438494Sobrien{
15538494Sobrien  return close(fd);
15638494Sobrien}
15738494Sobrien
15838494Sobrien
15938494Sobrien/*
16038494Sobrien * Create an rpc client attached to the mount daemon.
16138494Sobrien */
16238494SobrienCLIENT *
16338494Sobrienget_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version)
16438494Sobrien{
16538494Sobrien  CLIENT *client;
16638494Sobrien
16738494Sobrien  /*
16838494Sobrien   * First try a TCP socket
16938494Sobrien   */
17038494Sobrien  if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0) {
17138494Sobrien    /*
17238494Sobrien     * Bind to a privileged port
17338494Sobrien     */
17438494Sobrien    if (bind_resv_port(*sock, (u_short *) 0) < 0)
17582794Sobrien      plog(XLOG_ERROR, "can't bind privileged port (socket)");
17638494Sobrien
17738494Sobrien    /*
17838494Sobrien     * Find mountd port to connect to.
17938494Sobrien     * Connect to mountd.
18038494Sobrien     * Create a tcp client.
18138494Sobrien     */
18238494Sobrien    if ((sin->sin_port = htons(pmap_getport(sin, MOUNTPROG, mnt_version, IPPROTO_TCP))) != 0) {
18338494Sobrien      if (connect(*sock, (struct sockaddr *) sin, sizeof(*sin)) >= 0
18438494Sobrien	  && ((client = clnttcp_create(sin, MOUNTPROG, mnt_version, sock, 0, 0)) != NULL))
18538494Sobrien	return client;
18638494Sobrien    }
18738494Sobrien    /*
18838494Sobrien     * Failed so close socket
18938494Sobrien     */
19038494Sobrien    (void) close(*sock);
19138494Sobrien  }				/* tcp socket opened */
19238494Sobrien  /* TCP failed so try UDP */
19338494Sobrien  if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
19438494Sobrien    plog(XLOG_ERROR, "Can't create socket to connect to mountd: %m");
19538494Sobrien    *sock = RPC_ANYSOCK;
19638494Sobrien    return NULL;
19738494Sobrien  }
19838494Sobrien  /*
19938494Sobrien   * Bind to a privileged port
20038494Sobrien   */
20138494Sobrien  if (bind_resv_port(*sock, (u_short *) 0) < 0)
20238494Sobrien    plog(XLOG_ERROR, "can't bind privileged port");
20338494Sobrien
20438494Sobrien  /*
20538494Sobrien   * Zero out the port - make sure we recompute
20638494Sobrien   */
20738494Sobrien  sin->sin_port = 0;
20838494Sobrien
20938494Sobrien  /*
21038494Sobrien   * Make a UDP client
21138494Sobrien   */
21238494Sobrien  if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) {
21338494Sobrien    (void) close(*sock);
21438494Sobrien    *sock = RPC_ANYSOCK;
21538494Sobrien    return NULL;
21638494Sobrien  }
21738494Sobrien  dlog("get_mount_client: Using udp, port %d", sin->sin_port);
21838494Sobrien  return client;
21938494Sobrien}
22038494Sobrien
22138494Sobrien
22238494Sobrien/*
22338494Sobrien * find the address of the caller of an RPC procedure.
22438494Sobrien */
22538494Sobrienstruct sockaddr_in *
22638494Sobrienamu_svc_getcaller(SVCXPRT *xprt)
22738494Sobrien{
22882794Sobrien  /* glibc 2.2 returns a sockaddr_storage ??? */
229174294Sobrien  return (struct sockaddr_in *) svc_getcaller(xprt);
23038494Sobrien}
23138494Sobrien
23238494Sobrien
23338494Sobrien/*
234174294Sobrien * register an RPC server
235174294Sobrien */
236174294Sobrienint
237174294Sobrienamu_svc_register(SVCXPRT *xprt, u_long prognum, u_long versnum,
238174294Sobrien		 void (*dispatch)(struct svc_req *rqstp, SVCXPRT *transp),
239174294Sobrien		 u_long protocol, struct netconfig *dummy)
240174294Sobrien{
241174294Sobrien  return svc_register(xprt, prognum, versnum, dispatch, protocol);
242174294Sobrien}
243174294Sobrien
244174294Sobrien
245174294Sobrien/*
24638494Sobrien * Create the nfs service for amd
24738494Sobrien */
24838494Sobrienint
24938494Sobriencreate_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
25038494Sobrien{
25138494Sobrien
25238494Sobrien  *soNFSp = socket(AF_INET, SOCK_DGRAM, 0);
25338494Sobrien
254174294Sobrien  if (*soNFSp < 0 || bind_resv_port(*soNFSp, nfs_portp) < 0) {
25582794Sobrien    plog(XLOG_FATAL, "Can't create privileged nfs port (socket)");
256174294Sobrien    if (*soNFSp >= 0)
257174294Sobrien      close(*soNFSp);
25838494Sobrien    return 1;
25938494Sobrien  }
26038494Sobrien  if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) {
26138494Sobrien    plog(XLOG_FATAL, "cannot create rpc/udp service");
262174294Sobrien    close(*soNFSp);
26338494Sobrien    return 2;
26438494Sobrien  }
26551292Sobrien  if ((*nfs_portp = (*nfs_xprtp)->xp_port) >= IPPORT_RESERVED) {
26651292Sobrien    plog(XLOG_FATAL, "Can't create privileged nfs port");
267174294Sobrien    svc_destroy(*nfs_xprtp);
268174294Sobrien    close(*soNFSp);
26951292Sobrien    return 1;
27051292Sobrien  }
27138494Sobrien  if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) {
27282794Sobrien    plog(XLOG_FATAL, "unable to register (%ld, %ld, 0)",
27382794Sobrien	 (u_long) NFS_PROGRAM, (u_long) NFS_VERSION);
274174294Sobrien    svc_destroy(*nfs_xprtp);
275174294Sobrien    close(*soNFSp);
27638494Sobrien    return 3;
27738494Sobrien  }
27838494Sobrien
27938494Sobrien  return 0;			/* all is well */
28038494Sobrien}
28138494Sobrien
28238494Sobrien
28338494Sobrien/*
28438494Sobrien * Create the amq service for amd (both TCP and UDP)
28538494Sobrien */
28638494Sobrienint
287174294Sobriencreate_amq_service(int *udp_soAMQp,
288174294Sobrien		   SVCXPRT **udp_amqpp,
289174294Sobrien		   struct netconfig **dummy1,
290174294Sobrien		   int *tcp_soAMQp,
291174294Sobrien		   SVCXPRT **tcp_amqpp,
292174294Sobrien		   struct netconfig **dummy2,
293174294Sobrien		   u_short preferred_amq_port)
29438494Sobrien{
29538494Sobrien  /* first create TCP service */
29638494Sobrien  if (tcp_soAMQp) {
29738494Sobrien    *tcp_soAMQp = socket(AF_INET, SOCK_STREAM, 0);
29838494Sobrien    if (*tcp_soAMQp < 0) {
29938494Sobrien      plog(XLOG_FATAL, "cannot create tcp socket for amq service: %m");
30038494Sobrien      return 1;
30138494Sobrien    }
30238494Sobrien
303174294Sobrien    /* next, bind to a specific (TCP) port if asked for */
304174294Sobrien    if (preferred_amq_port > 0) {
305174294Sobrien      /*
306174294Sobrien       * Note: if &preferred_amq_port is non-null and is greater than 0,
307174294Sobrien       * then the pointer will not be modified.  We don't want it to be
308174294Sobrien       * modified because it was passed down to create_amq_service as a
309174294Sobrien       * non-pointer (a variable on the stack, not to be modified!)
310174294Sobrien       */
311174294Sobrien      if (bind_resv_port(*tcp_soAMQp, &preferred_amq_port) < 0) {
312174294Sobrien	plog(XLOG_FATAL, "can't bind amq service to requested TCP port %d: %m)", preferred_amq_port);
313174294Sobrien	return 1;
314174294Sobrien      }
315174294Sobrien    }
316174294Sobrien
31738494Sobrien    /* now create RPC service handle for amq */
31838494Sobrien    if (tcp_amqpp &&
31938494Sobrien	(*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
32038494Sobrien      plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp);
321174294Sobrien      return 1;
32238494Sobrien    }
323119679Smbr
324119679Smbr#ifdef SVCSET_CONNMAXREC
325119679Smbr    /*
326119679Smbr     * This is *BSD at its best.
327119679Smbr     * They just had to do things differently than everyone else
328119679Smbr     * so they fixed a library DoS issue by forcing client-side changes...
329119679Smbr     */
330119679Smbr# ifndef RPC_MAXDATASIZE
331119679Smbr#  define RPC_MAXDATASIZE 9000
332119679Smbr# endif /* not RPC_MAXDATASIZE */
333174294Sobrien    if (tcp_amqpp) {
334119679Smbr      int maxrec = RPC_MAXDATASIZE;
335119679Smbr      SVC_CONTROL(*tcp_amqpp, SVCSET_CONNMAXREC, &maxrec);
336119679Smbr    }
337119679Smbr#endif /* not SVCSET_CONNMAXREC */
33838494Sobrien  }
33938494Sobrien
34038494Sobrien  /* next create UDP service */
34138494Sobrien  if (udp_soAMQp) {
34238494Sobrien    *udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0);
34338494Sobrien    if (*udp_soAMQp < 0) {
34438494Sobrien      plog(XLOG_FATAL, "cannot create udp socket for amq service: %m");
345174294Sobrien      return 1;
34638494Sobrien    }
34738494Sobrien
348174294Sobrien    /* next, bind to a specific (UDP) port if asked for */
349174294Sobrien    if (preferred_amq_port > 0) {
350174294Sobrien      /*
351174294Sobrien       * Note: see comment about using &preferred_amq_port above in this
352174294Sobrien       * function.
353174294Sobrien       */
354174294Sobrien      if (bind_resv_port(*udp_soAMQp, &preferred_amq_port) < 0) {
355174294Sobrien	plog(XLOG_FATAL, "can't bind amq service to requested UDP port %d: %m)", preferred_amq_port);
356174294Sobrien	return 1;
357174294Sobrien      }
358174294Sobrien    }
359174294Sobrien
36038494Sobrien    /* now create RPC service handle for amq */
36138494Sobrien    if (udp_amqpp &&
36238494Sobrien	(*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
36338494Sobrien      plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp);
364174294Sobrien      return 1;
36538494Sobrien    }
36638494Sobrien  }
36738494Sobrien
36838494Sobrien  return 0;			/* all is well */
36938494Sobrien}
37038494Sobrien
37138494Sobrien
37238494Sobrien/*
373174294Sobrien * Check if the portmapper is running and reachable: 0==down, 1==up
37438494Sobrien */
375174294Sobrienint check_pmap_up(char *host, struct sockaddr_in* sin)
37638494Sobrien{
37738494Sobrien  CLIENT *client;
37838494Sobrien  enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
37938494Sobrien  int socket = RPC_ANYSOCK;
38038494Sobrien  struct timeval timeout;
38138494Sobrien
382174294Sobrien  timeout.tv_sec = 2;
38338494Sobrien  timeout.tv_usec = 0;
384174294Sobrien  sin->sin_port = htons(PMAPPORT);
385174294Sobrien  client = clntudp_create(sin, PMAPPROG, PMAPVERS, timeout, &socket);
386174294Sobrien
387174294Sobrien  if (client == (CLIENT *) NULL) {
388174294Sobrien    plog(XLOG_ERROR,
389174294Sobrien	 "check_pmap_up: cannot create connection to contact portmapper on host \"%s\"%s",
390174294Sobrien	 host, clnt_spcreateerror(""));
391174294Sobrien    return 0;
39238494Sobrien  }
393174294Sobrien
394174294Sobrien  timeout.tv_sec = 6;
395174294Sobrien  /* Ping the portmapper on a remote system by calling the nullproc */
396174294Sobrien  clnt_stat = clnt_call(client,
397174294Sobrien			PMAPPROC_NULL,
398174294Sobrien			(XDRPROC_T_TYPE) xdr_void,
399174294Sobrien			NULL,
400174294Sobrien			(XDRPROC_T_TYPE) xdr_void,
401174294Sobrien			NULL,
402174294Sobrien			timeout);
403174294Sobrien  clnt_destroy(client);
40438494Sobrien  close(socket);
405174294Sobrien  sin->sin_port = 0;
40638494Sobrien
407174294Sobrien  if (clnt_stat == RPC_TIMEDOUT) {
408174294Sobrien    plog(XLOG_ERROR,
409174294Sobrien	 "check_pmap_up: failed to contact portmapper on host \"%s\": %s",
410174294Sobrien	 host, clnt_sperrno(clnt_stat));
411174294Sobrien    return 0;
412174294Sobrien  }
413174294Sobrien  return 1;
41438494Sobrien}
41538494Sobrien
41638494Sobrien
41738494Sobrien/*
41838494Sobrien * Find the best NFS version for a host and protocol.
41938494Sobrien */
42038494Sobrienu_long
42138494Sobrienget_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto)
42238494Sobrien{
42338494Sobrien  CLIENT *clnt;
42438494Sobrien  int again = 0;
42538494Sobrien  enum clnt_stat clnt_stat;
42638494Sobrien  struct timeval tv;
42738494Sobrien  int sock;
428174294Sobrien  char *errstr;
42938494Sobrien
43038494Sobrien  /*
43138494Sobrien   * If not set or set wrong, then try from NFS_VERS_MAX on down. If
43238494Sobrien   * set, then try from nfs_version on down.
43338494Sobrien   */
43438494Sobrien  if (nfs_version <= 0 || nfs_version > NFS_VERS_MAX) {
43538494Sobrien    nfs_version = NFS_VERS_MAX;
43638494Sobrien    again = 1;
43738494Sobrien  }
438174294Sobrien  tv.tv_sec = 2;		/* retry every 2 seconds, but also timeout */
43938494Sobrien  tv.tv_usec = 0;
44038494Sobrien
44138494Sobrien#ifdef HAVE_FS_NFS3
44238494Sobrientry_again:
44338494Sobrien#endif /* HAVE_FS_NFS3 */
44438494Sobrien
44538494Sobrien  sock = RPC_ANYSOCK;
446174294Sobrien  errstr = NULL;
44738494Sobrien  if (STREQ(proto, "tcp"))
44838494Sobrien    clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0);
44938494Sobrien  else if (STREQ(proto, "udp"))
45038494Sobrien    clnt = clntudp_create(sin, NFS_PROGRAM, nfs_version, tv, &sock);
45138494Sobrien  else
45238494Sobrien    clnt = NULL;
45338494Sobrien
454174294Sobrien  if (clnt != NULL) {
455174294Sobrien    /* Try three times (6/2=3) to verify the CLIENT handle. */
456174294Sobrien    tv.tv_sec = 6;
457174294Sobrien    clnt_stat = clnt_call(clnt,
458174294Sobrien			  NFSPROC_NULL,
459174294Sobrien			  (XDRPROC_T_TYPE) xdr_void,
460174294Sobrien			  0,
461174294Sobrien			  (XDRPROC_T_TYPE) xdr_void,
462174294Sobrien			  0,
463174294Sobrien			  tv);
464174294Sobrien
465174294Sobrien    if (clnt_stat != RPC_SUCCESS)
466174294Sobrien      errstr = clnt_sperrno(clnt_stat);
467174294Sobrien
468174294Sobrien    close(sock);
469174294Sobrien    clnt_destroy(clnt);
470174294Sobrien  } else {
47138494Sobrien#ifdef HAVE_CLNT_SPCREATEERROR
472174294Sobrien    errstr = clnt_spcreateerror("");
47338494Sobrien#else /* not HAVE_CLNT_SPCREATEERROR */
474174294Sobrien    errstr = "";
47538494Sobrien#endif /* not HAVE_CLNT_SPCREATEERROR */
47638494Sobrien  }
47738494Sobrien
478174294Sobrien  if (errstr) {
479174294Sobrien    plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s%s",
480174294Sobrien 	 (int) nfs_version, proto, host, errstr);
48138494Sobrien    if (again) {
48238494Sobrien#ifdef HAVE_FS_NFS3
48338494Sobrien      if (nfs_version == NFS_VERSION3) {
48438494Sobrien	nfs_version = NFS_VERSION;
48538494Sobrien	again = 0;
486174294Sobrien	plog(XLOG_INFO, "get_nfs_version trying a lower version: NFS(%d,%s)", (int) nfs_version, proto);
48738494Sobrien      }
48838494Sobrien      goto try_again;
48938494Sobrien#endif /* HAVE_FS_NFS3 */
49038494Sobrien    }
49138494Sobrien    return 0;
49238494Sobrien  }
49338494Sobrien
494174294Sobrien  plog(XLOG_INFO, "get_nfs_version: returning NFS(%d,%s) on host %s",
49551292Sobrien       (int) nfs_version, proto, host);
49638494Sobrien  return nfs_version;
49738494Sobrien}
498174294Sobrien
499174294Sobrien
500174294Sobrien#if defined(HAVE_FS_AUTOFS) && defined(AUTOFS_PROG)
501174294Sobrien/*
502174294Sobrien * Register the autofs service for amd
503174294Sobrien */
504174294Sobrienint
505174294Sobrienregister_autofs_service(char *autofs_conftype, void (*autofs_dispatch)(struct svc_req *rqstp, SVCXPRT *transp))
506174294Sobrien{
507174294Sobrien  int autofs_socket;
508174294Sobrien  SVCXPRT *autofs_xprt = NULL;
509174294Sobrien
510174294Sobrien  autofs_socket = socket(AF_INET, SOCK_DGRAM, 0);
511174294Sobrien
512174294Sobrien  if (autofs_socket < 0 || bind_resv_port(autofs_socket, NULL) < 0) {
513174294Sobrien    plog(XLOG_FATAL, "Can't create privileged autofs port (socket)");
514174294Sobrien    return 1;
515174294Sobrien  }
516174294Sobrien  if ((autofs_xprt = svcudp_create(autofs_socket)) == NULL) {
517174294Sobrien    plog(XLOG_FATAL, "Can't create autofs rpc/udp service");
518174294Sobrien    return 2;
519174294Sobrien  }
520174294Sobrien  if (autofs_xprt->xp_port >= IPPORT_RESERVED) {
521174294Sobrien    plog(XLOG_FATAL, "Can't create privileged autofs port");
522174294Sobrien    return 1;
523174294Sobrien  }
524174294Sobrien  if (!svc_register(autofs_xprt, AUTOFS_PROG, AUTOFS_VERS, autofs_dispatch, 0)) {
525174294Sobrien    plog(XLOG_FATAL, "unable to register (%ld, %ld, 0)",
526174294Sobrien	 (u_long) AUTOFS_PROG, (u_long) AUTOFS_VERS);
527174294Sobrien    return 3;
528174294Sobrien  }
529174294Sobrien
530174294Sobrien  return 0;			/* all is well */
531174294Sobrien}
532174294Sobrien
533174294Sobrien
534174294Sobrienint
535174294Sobrienunregister_autofs_service(char *autofs_conftype)
536174294Sobrien{
537174294Sobrien  svc_unregister(AUTOFS_PROG, AUTOFS_VERS);
538174294Sobrien  return 0;
539174294Sobrien}
540174294Sobrien#endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */
541