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