transp_sockets.c revision 42629
1192886Sedwin/*
2192886Sedwin * Copyright (c) 1997-1998 Erez Zadok
32744Swollman * Copyright (c) 1990 Jan-Simon Pendry
458782Sru * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
558782Sru * Copyright (c) 1990 The Regents of the University of California.
658782Sru * All rights reserved.
7273718Sedwin *
843009Swollman * This code is derived from software contributed to Berkeley by
958782Sru * Jan-Simon Pendry at Imperial College, London.
10273718Sedwin *
1143009Swollman * Redistribution and use in source and binary forms, with or without
1219876Swollman * modification, are permitted provided that the following conditions
132744Swollman * are met:
14309583Sglebius * 1. Redistributions of source code must retain the above copyright
15309583Sglebius *    notice, this list of conditions and the following disclaimer.
1658782Sru * 2. Redistributions in binary form must reproduce the above copyright
1758782Sru *    notice, this list of conditions and the following disclaimer in the
18270728Spluknet *    documentation and/or other materials provided with the distribution.
19270728Spluknet * 3. All advertising materials mentioning features or use of this software
20270728Spluknet *    must display the following acknowledgment:
2158782Sru *      This product includes software developed by the University of
22270728Spluknet *      California, Berkeley and its contributors.
2358782Sru * 4. Neither the name of the University nor the names of its contributors
242744Swollman *    may be used to endorse or promote products derived from this software
2519876Swollman *    without specific prior written permission.
2630708Swollman *
2758782Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2858782Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29325324Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30309583Sglebius * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3158782Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3219876Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3319876Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3458782Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3558782Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3658782Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3758782Sru * SUCH DAMAGE.
38199107Sedwin *
39199107Sedwin *      %W% (Berkeley) %G%
40199107Sedwin *
41199107Sedwin * $Id: transp_sockets.c,v 1.2 1998/11/10 16:23:41 ezk Exp $
42199107Sedwin *
43199107Sedwin * Socket specific utilities.
44199107Sedwin *      -Erez Zadok <ezk@cs.columbia.edu>
45199107Sedwin */
46199107Sedwin
47199107Sedwin#ifdef HAVE_CONFIG_H
48199107Sedwin# include <config.h>
49199107Sedwin#endif /* HAVE_CONFIG_H */
50325324Sgordon#include <am_defs.h>
51199107Sedwin#include <amu.h>
52205475Sedwin
53249692Sedwin
54205475Sedwin/*
55205475Sedwin * find the IP address that can be used to connect to the local host
56205475Sedwin */
57205475Sedwinvoid
58205475Sedwinamu_get_myaddress(struct in_addr *iap)
59205475Sedwin{
60205475Sedwin  struct sockaddr_in sin;
61205475Sedwin
62205475Sedwin  memset((char *) &sin, 0, sizeof(sin));
63205475Sedwin  get_myaddress(&sin);
64205475Sedwin  iap->s_addr = sin.sin_addr.s_addr;
65325324Sgordon}
66205475Sedwin
67309583Sglebius
68309583Sglebius/*
69309583Sglebius * How to bind to reserved ports.
70309583Sglebius */
7119876Swollmanint
72309583Sglebiusbind_resv_port(int so, u_short *pp)
73309583Sglebius{
74309583Sglebius  struct sockaddr_in sin;
75309583Sglebius  int rc;
76309583Sglebius  u_short port;
77309583Sglebius
78309583Sglebius  memset((voidp) &sin, 0, sizeof(sin));
79309583Sglebius  sin.sin_family = AF_INET;
80309583Sglebius
81309583Sglebius  port = IPPORT_RESERVED;
82309583Sglebius
83309583Sglebius  do {
84309583Sglebius    --port;
85309583Sglebius    sin.sin_port = htons(port);
86309583Sglebius    rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
87309583Sglebius  } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
88309583Sglebius
89309583Sglebius  if (pp && rc == 0)
9019876Swollman    *pp = port;
9143009Swollman
92273718Sedwin  return rc;
9343009Swollman}
94273718Sedwin
9543009Swollman
96273718Sedwin/*
9714338Swollman * close a descriptor, Sockets style
98270728Spluknet */
99270728Spluknetint
100270728Spluknetamu_close(int fd)
10119876Swollman{
102270728Spluknet  return close(fd);
10314338Swollman}
104270728Spluknet
105270728Spluknet
106270728Spluknet/*
10786218Swollman * Create an rpc client attached to the mount daemon.
10858782Sru */
109270728SpluknetCLIENT *
110270728Spluknetget_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version)
111270728Spluknet{
112149511Swollman  CLIENT *client;
113325324Sgordon
114325324Sgordon  /*
11514338Swollman   * First try a TCP socket
11619876Swollman   */
117149511Swollman  if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0) {
118149511Swollman    /*
11919876Swollman     * Bind to a privileged port
120270728Spluknet     */
12119876Swollman    if (bind_resv_port(*sock, (u_short *) 0) < 0)
122153667Swollman      plog(XLOG_ERROR, "can't bind privileged port");
123273718Sedwin
12430708Swollman    /*
125270728Spluknet     * Find mountd port to connect to.
126270728Spluknet     * Connect to mountd.
12730708Swollman     * Create a tcp client.
12830708Swollman     */
12919876Swollman    if ((sin->sin_port = htons(pmap_getport(sin, MOUNTPROG, mnt_version, IPPROTO_TCP))) != 0) {
13019876Swollman      if (connect(*sock, (struct sockaddr *) sin, sizeof(*sin)) >= 0
131270728Spluknet	  && ((client = clnttcp_create(sin, MOUNTPROG, mnt_version, sock, 0, 0)) != NULL))
132270728Spluknet	return client;
133270728Spluknet    }
134270728Spluknet    /*
135270728Spluknet     * Failed so close socket
136270728Spluknet     */
13758782Sru    (void) close(*sock);
13830708Swollman  }				/* tcp socket opened */
13958782Sru  /* TCP failed so try UDP */
14058782Sru  if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
14130708Swollman    plog(XLOG_ERROR, "Can't create socket to connect to mountd: %m");
14230708Swollman    *sock = RPC_ANYSOCK;
143309583Sglebius    return NULL;
144309583Sglebius  }
14530708Swollman  /*
14630708Swollman   * Bind to a privileged port
147270728Spluknet   */
148325324Sgordon  if (bind_resv_port(*sock, (u_short *) 0) < 0)
14930708Swollman    plog(XLOG_ERROR, "can't bind privileged port");
15030708Swollman
15130708Swollman  /*
15230708Swollman   * Zero out the port - make sure we recompute
15330708Swollman   */
154309583Sglebius  sin->sin_port = 0;
155309583Sglebius
156309583Sglebius  /*
157309583Sglebius   * Make a UDP client
15819876Swollman   */
159270728Spluknet  if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) {
160270728Spluknet    (void) close(*sock);
161270728Spluknet    *sock = RPC_ANYSOCK;
16219876Swollman    return NULL;
163270728Spluknet  }
16419876Swollman#ifdef DEBUG
165270728Spluknet  dlog("get_mount_client: Using udp, port %d", sin->sin_port);
166270728Spluknet#endif /* DEBUG */
167270728Spluknet  return client;
16819876Swollman}
169270728Spluknet
170270728Spluknet
171270728Spluknet/*
17219876Swollman * find the address of the caller of an RPC procedure.
173270728Spluknet */
17458782Srustruct sockaddr_in *
17558782Sruamu_svc_getcaller(SVCXPRT *xprt)
176153667Swollman{
17758782Sru  return svc_getcaller(xprt);
17858782Sru}
17958782Sru
18058782Sru
18158782Sru/*
182309583Sglebius * Bind NFS to a reserved port.
183309583Sglebius */
18458782Srustatic int
18558782Srubindnfs_port(int so, u_short *nfs_portp)
186273718Sedwin{
18719876Swollman  u_short port;
18819876Swollman  int error = bind_resv_port(so, &port);
189270728Spluknet
190149511Swollman  if (error == 0)
19119876Swollman    *nfs_portp = port;
19219876Swollman  return error;
19330708Swollman}
19430708Swollman
19519876Swollman
19619876Swollman/*
197257681Sedwin * Create the nfs service for amd
198257681Sedwin */
19919876Swollmanint
20019876Swollmancreate_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
20130708Swollman{
20219876Swollman
20319876Swollman  *soNFSp = socket(AF_INET, SOCK_DGRAM, 0);
20430708Swollman
205263901Sedwin  if (*soNFSp < 0 || bindnfs_port(*soNFSp, nfs_portp) < 0) {
206263901Sedwin    plog(XLOG_FATAL, "Can't create privileged nfs port");
207263901Sedwin    return 1;
208263901Sedwin  }
209263901Sedwin  if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) {
210263901Sedwin    plog(XLOG_FATAL, "cannot create rpc/udp service");
211263901Sedwin    return 2;
212263901Sedwin  }
213263901Sedwin  if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) {
214263901Sedwin    plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
215263901Sedwin    return 3;
216263901Sedwin  }
217263901Sedwin
218263901Sedwin  return 0;			/* all is well */
219263901Sedwin}
220309583Sglebius
221263901Sedwin
222263901Sedwin/*
223263901Sedwin * Create the amq service for amd (both TCP and UDP)
224263901Sedwin */
225309583Sglebiusint
226309583Sglebiuscreate_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp)
227309583Sglebius{
228309583Sglebius  /* first create TCP service */
229263901Sedwin  if (tcp_soAMQp) {
230309583Sglebius    *tcp_soAMQp = socket(AF_INET, SOCK_STREAM, 0);
231263901Sedwin    if (*tcp_soAMQp < 0) {
232309583Sglebius      plog(XLOG_FATAL, "cannot create tcp socket for amq service: %m");
233273718Sedwin      return 1;
23419876Swollman    }
23519876Swollman
23658782Sru    /* now create RPC service handle for amq */
23719876Swollman    if (tcp_amqpp &&
238270728Spluknet	(*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
239270728Spluknet      plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp);
240270728Spluknet      return 2;
24119876Swollman    }
24258782Sru  }
24358782Sru
244149511Swollman  /* next create UDP service */
245149511Swollman  if (udp_soAMQp) {
24675264Swollman    *udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0);
24775264Swollman    if (*udp_soAMQp < 0) {
24819876Swollman      plog(XLOG_FATAL, "cannot create udp socket for amq service: %m");
24975264Swollman      return 3;
250273718Sedwin    }
251273718Sedwin
25275264Swollman    /* now create RPC service handle for amq */
25375264Swollman    if (udp_amqpp &&
25475264Swollman	(*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
25575264Swollman      plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp);
25675264Swollman      return 4;
25775264Swollman    }
258257681Sedwin  }
25975264Swollman
26075264Swollman  return 0;			/* all is well */
26175264Swollman}
262257681Sedwin
26375264Swollman
26486218Swollman/*
26586218Swollman * Ping the portmapper on a remote system by calling the nullproc
266270728Spluknet */
26786218Swollmanenum clnt_stat
26886218Swollmanpmap_ping(struct sockaddr_in *address)
26986218Swollman{
27086218Swollman  CLIENT *client;
271309583Sglebius  enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
27286218Swollman  int socket = RPC_ANYSOCK;
273309583Sglebius  struct timeval timeout;
274309583Sglebius
27575264Swollman  timeout.tv_sec = 3;
27619876Swollman  timeout.tv_usec = 0;
277149511Swollman  address->sin_port = htons(PMAPPORT);
278270728Spluknet  client = clntudp_create(address, PMAPPROG, PMAPVERS, timeout, &socket);
27919876Swollman  if (client != (CLIENT *) NULL) {
280270728Spluknet    clnt_stat = clnt_call(client,
281270728Spluknet			  PMAPPROC_NULL,
282270728Spluknet			  (XDRPROC_T_TYPE) xdr_void,
283270728Spluknet			  NULL,
28419876Swollman			  (XDRPROC_T_TYPE) xdr_void,
28519876Swollman			  NULL,
28619876Swollman			  timeout);
28730708Swollman    clnt_destroy(client);
28858782Sru  }
28919876Swollman  close(socket);
29019876Swollman  address->sin_port = 0;
29119876Swollman
29258782Sru  return clnt_stat;
29375264Swollman}
29475264Swollman
29575264Swollman
29675264Swollman/*
29775264Swollman * Find the best NFS version for a host and protocol.
29875264Swollman */
29975264Swollmanu_long
30019876Swollmanget_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto)
301114170Swollman{
302114170Swollman  CLIENT *clnt;
303114170Swollman  int again = 0;
304114170Swollman  enum clnt_stat clnt_stat;
305114170Swollman  struct timeval tv;
306309583Sglebius  int sock;
307309583Sglebius
30819876Swollman  /*
30919876Swollman   * If not set or set wrong, then try from NFS_VERS_MAX on down. If
31058782Sru   * set, then try from nfs_version on down.
31119876Swollman   */
31219876Swollman  if (nfs_version <= 0 || nfs_version > NFS_VERS_MAX) {
31319876Swollman    nfs_version = NFS_VERS_MAX;
31420091Swollman    again = 1;
315283042Sedwin  }
31619876Swollman  tv.tv_sec = 3;		/* retry every 3 seconds, but also timeout */
317257681Sedwin  tv.tv_usec = 0;
318257681Sedwin
31919876Swollman  /*
320153667Swollman   * First check if remote portmapper is up (verify if remote host is up).
32119876Swollman   */
32219876Swollman  clnt_stat = pmap_ping(sin);
32319876Swollman  if (clnt_stat == RPC_TIMEDOUT) {
32419876Swollman    plog(XLOG_ERROR, "get_nfs_version: failed to contact portmapper on host \"%s\": %s", host, clnt_sperrno(clnt_stat));
32519876Swollman    return 0;
326270728Spluknet  }
32719876Swollman
32843009Swollman#ifdef HAVE_FS_NFS3
32943009Swollmantry_again:
33043009Swollman#endif /* HAVE_FS_NFS3 */
33143009Swollman
33219876Swollman  sock = RPC_ANYSOCK;
33319876Swollman  if (STREQ(proto, "tcp"))
33419876Swollman    clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0);
33519876Swollman  else if (STREQ(proto, "udp"))
33619876Swollman    clnt = clntudp_create(sin, NFS_PROGRAM, nfs_version, tv, &sock);
33719876Swollman  else
33819876Swollman    clnt = NULL;
33919876Swollman
340257681Sedwin  if (clnt == NULL) {
341#ifdef HAVE_CLNT_SPCREATEERROR
342    plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s :%s",
343	 nfs_version, proto, host, clnt_spcreateerror(""));
344#else /* not HAVE_CLNT_SPCREATEERROR */
345    plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s",
346	 nfs_version, proto, host);
347#endif /* not HAVE_CLNT_SPCREATEERROR */
348    return 0;
349  }
350
351  /* Try a couple times to verify the CLIENT handle. */
352  tv.tv_sec = 6;
353  clnt_stat = clnt_call(clnt,
354			NFSPROC_NULL,
355			(XDRPROC_T_TYPE) xdr_void,
356			0,
357			(XDRPROC_T_TYPE) xdr_void,
358			0,
359			tv);
360  close(sock);
361  clnt_destroy(clnt);
362  if (clnt_stat != RPC_SUCCESS) {
363    if (again) {
364#ifdef HAVE_FS_NFS3
365      if (nfs_version == NFS_VERSION3) {
366	plog(XLOG_INFO, "get_nfs_version trying a lower version");
367	nfs_version = NFS_VERSION;
368	again = 0;
369      }
370      goto try_again;
371#endif /* HAVE_FS_NFS3 */
372    }
373    plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s",
374 	 nfs_version, proto, host);
375    return 0;
376  }
377
378  plog(XLOG_INFO, "get_nfs_version: returning (%d,%s) on host %s",
379       nfs_version, proto, host);
380  return nfs_version;
381}
382
383
384/*
385 * AUTOFS FUNCTIONS FOR SOCKETS:
386 */
387#ifdef HAVE_FS_AUTOFS
388/*
389 * Create the nfs service for amd
390 */
391int
392create_autofs_service(int *soAUTOFSp, u_short *autofs_portp, SVCXPRT **autofs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
393{
394  /* NOT IMPLEMENTED! */
395  return -1;
396}
397#endif /* HAVE_FS_AUTOFS */
398