xref: /freebsd/lib/libc/rpc/rpc_soc.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
1  /*	$NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $	*/
2  
3  /*-
4   * SPDX-License-Identifier: BSD-3-Clause
5   *
6   * Copyright (c) 2009, Sun Microsystems, Inc.
7   * All rights reserved.
8   *
9   * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions are met:
11   * - Redistributions of source code must retain the above copyright notice,
12   *   this list of conditions and the following disclaimer.
13   * - Redistributions in binary form must reproduce the above copyright notice,
14   *   this list of conditions and the following disclaimer in the documentation
15   *   and/or other materials provided with the distribution.
16   * - Neither the name of Sun Microsystems, Inc. nor the names of its
17   *   contributors may be used to endorse or promote products derived
18   *   from this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   */
32  
33  /*
34   * Copyright (c) 1986-1991 by Sun Microsystems Inc.
35   * In addition, portions of such source code were derived from Berkeley
36   * 4.3 BSD under license from the Regents of the University of
37   * California.
38   */
39  
40  #ifdef PORTMAP
41  /*
42   * rpc_soc.c
43   *
44   * The backward compatibility routines for the earlier implementation
45   * of RPC, where the only transports supported were tcp/ip and udp/ip.
46   * Based on berkeley socket abstraction, now implemented on the top
47   * of TLI/Streams
48   */
49  
50  #include "namespace.h"
51  #include "reentrant.h"
52  #include <sys/types.h>
53  #include <sys/socket.h>
54  #include <stdio.h>
55  #include <rpc/rpc.h>
56  #include <rpc/pmap_clnt.h>
57  #include <rpc/pmap_prot.h>
58  #include <rpc/nettype.h>
59  #include <syslog.h>
60  #include <netinet/in.h>
61  #include <netdb.h>
62  #include <errno.h>
63  #include <syslog.h>
64  #include <stdlib.h>
65  #include <string.h>
66  #include <unistd.h>
67  #include "un-namespace.h"
68  
69  #include "rpc_com.h"
70  #include "mt_misc.h"
71  
72  static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
73      int *, u_int, u_int, char *);
74  static SVCXPRT *svc_com_create(int, u_int, u_int, char *);
75  static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *);
76  
77  /* XXX */
78  #define IN4_LOCALHOST_STRING    "127.0.0.1"
79  #define IN6_LOCALHOST_STRING    "::1"
80  
81  /*
82   * A common clnt create routine
83   */
84  static CLIENT *
clnt_com_create(struct sockaddr_in * raddr,rpcprog_t prog,rpcvers_t vers,int * sockp,u_int sendsz,u_int recvsz,char * tp)85  clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp,
86      u_int sendsz, u_int recvsz, char *tp)
87  {
88  	CLIENT *cl;
89  	int madefd = FALSE;
90  	int fd = *sockp;
91  	struct netconfig *nconf;
92  	struct netbuf bindaddr;
93  
94  	mutex_lock(&rpcsoc_lock);
95  	if ((nconf = __rpc_getconfip(tp)) == NULL) {
96  		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
97  		mutex_unlock(&rpcsoc_lock);
98  		return (NULL);
99  	}
100  	if (fd == RPC_ANYSOCK) {
101  		fd = __rpc_nconf2fd(nconf);
102  		if (fd == -1)
103  			goto syserror;
104  		madefd = TRUE;
105  	}
106  
107  	if (raddr->sin_port == 0) {
108  		u_int proto;
109  		u_short sport;
110  
111  		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
112  		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
113  		sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
114  		    proto);
115  		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
116  		if (sport == 0) {
117  			goto err;
118  		}
119  		raddr->sin_port = htons(sport);
120  	}
121  
122  	/* Transform sockaddr_in to netbuf */
123  	bindaddr.maxlen = bindaddr.len =  sizeof (struct sockaddr_in);
124  	bindaddr.buf = raddr;
125  
126  	bindresvport(fd, NULL);
127  	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
128  				sendsz, recvsz);
129  	if (cl) {
130  		if (madefd == TRUE) {
131  			/*
132  			 * The fd should be closed while destroying the handle.
133  			 */
134  			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
135  			*sockp = fd;
136  		}
137  		(void) freenetconfigent(nconf);
138  		mutex_unlock(&rpcsoc_lock);
139  		return (cl);
140  	}
141  	goto err;
142  
143  syserror:
144  	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
145  	rpc_createerr.cf_error.re_errno = errno;
146  
147  err:	if (madefd == TRUE)
148  		(void)_close(fd);
149  	(void) freenetconfigent(nconf);
150  	mutex_unlock(&rpcsoc_lock);
151  	return (NULL);
152  }
153  
154  CLIENT *
clntudp_bufcreate(struct sockaddr_in * raddr,u_long prog,u_long vers,struct timeval wait,int * sockp,u_int sendsz,u_int recvsz)155  clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers,
156      struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
157  {
158  	CLIENT *cl;
159  
160  	cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
161  	    sendsz, recvsz, "udp");
162  	if (cl == NULL) {
163  		return (NULL);
164  	}
165  	(void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
166  	return (cl);
167  }
168  
169  CLIENT *
clntudp_create(struct sockaddr_in * raddr,u_long program,u_long version,struct timeval wait,int * sockp)170  clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
171      struct timeval wait, int *sockp)
172  {
173  
174  	return clntudp_bufcreate(raddr, program, version, wait, sockp,
175  					UDPMSGSIZE, UDPMSGSIZE);
176  }
177  
178  CLIENT *
clnttcp_create(struct sockaddr_in * raddr,u_long prog,u_long vers,int * sockp,u_int sendsz,u_int recvsz)179  clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
180      u_int sendsz, u_int recvsz)
181  {
182  
183  	return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
184  	    sendsz, recvsz, "tcp");
185  }
186  
187  CLIENT *
clntraw_create(u_long prog,u_long vers)188  clntraw_create(u_long prog, u_long vers)
189  {
190  
191  	return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers);
192  }
193  
194  /*
195   * A common server create routine
196   */
197  static SVCXPRT *
svc_com_create(int fd,u_int sendsize,u_int recvsize,char * netid)198  svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
199  {
200  	struct netconfig *nconf;
201  	SVCXPRT *svc;
202  	int madefd = FALSE;
203  	int port;
204  	struct sockaddr_in sin;
205  
206  	if ((nconf = __rpc_getconfip(netid)) == NULL) {
207  		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
208  		return (NULL);
209  	}
210  	if (fd == RPC_ANYSOCK) {
211  		fd = __rpc_nconf2fd(nconf);
212  		if (fd == -1) {
213  			(void) freenetconfigent(nconf);
214  			(void) syslog(LOG_ERR,
215  			"svc%s_create: could not open connection", netid);
216  			return (NULL);
217  		}
218  		madefd = TRUE;
219  	}
220  
221  	memset(&sin, 0, sizeof sin);
222  	sin.sin_family = AF_INET;
223  	bindresvport(fd, &sin);
224  	_listen(fd, SOMAXCONN);
225  	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
226  	(void) freenetconfigent(nconf);
227  	if (svc == NULL) {
228  		if (madefd)
229  			(void)_close(fd);
230  		return (NULL);
231  	}
232  	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
233  	svc->xp_port = ntohs(port);
234  	return (svc);
235  }
236  
237  SVCXPRT *
svctcp_create(int fd,u_int sendsize,u_int recvsize)238  svctcp_create(int fd, u_int sendsize, u_int recvsize)
239  {
240  
241  	return svc_com_create(fd, sendsize, recvsize, "tcp");
242  }
243  
244  SVCXPRT *
svcudp_bufcreate(int fd,u_int sendsz,u_int recvsz)245  svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz)
246  {
247  
248  	return svc_com_create(fd, sendsz, recvsz, "udp");
249  }
250  
251  SVCXPRT *
svcfd_create(int fd,u_int sendsize,u_int recvsize)252  svcfd_create(int fd, u_int sendsize, u_int recvsize)
253  {
254  
255  	return svc_fd_create(fd, sendsize, recvsize);
256  }
257  
258  
259  SVCXPRT *
svcudp_create(int fd)260  svcudp_create(int fd)
261  {
262  
263  	return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
264  }
265  
266  SVCXPRT *
svcraw_create(void)267  svcraw_create(void)
268  {
269  
270  	return svc_raw_create();
271  }
272  
273  int
get_myaddress(struct sockaddr_in * addr)274  get_myaddress(struct sockaddr_in *addr)
275  {
276  
277  	memset((void *) addr, 0, sizeof(*addr));
278  	addr->sin_family = AF_INET;
279  	addr->sin_port = htons(PMAPPORT);
280  	addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
281  	return (0);
282  }
283  
284  /*
285   * For connectionless "udp" transport. Obsoleted by rpc_call().
286   */
287  int
callrpc(const char * host,int prognum,int versnum,int procnum,xdrproc_t inproc,void * in,xdrproc_t outproc,void * out)288  callrpc(const char *host, int prognum, int versnum, int procnum,
289      xdrproc_t inproc, void *in, xdrproc_t outproc, void *out)
290  {
291  
292  	return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum,
293  	    (rpcproc_t)procnum, inproc, in, outproc, out, "udp");
294  }
295  
296  /*
297   * For connectionless kind of transport. Obsoleted by rpc_reg()
298   */
299  int
registerrpc(int prognum,int versnum,int procnum,char * (* progname)(char[UDPMSGSIZE]),xdrproc_t inproc,xdrproc_t outproc)300  registerrpc(int prognum, int versnum, int procnum,
301      char *(*progname)(char [UDPMSGSIZE]),
302      xdrproc_t inproc, xdrproc_t outproc)
303  {
304  
305  	return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum,
306  	    (rpcproc_t)procnum, progname, inproc, outproc, "udp");
307  }
308  
309  /*
310   * All the following clnt_broadcast stuff is convulated; it supports
311   * the earlier calling style of the callback function
312   */
313  static thread_key_t	clnt_broadcast_key;
314  static resultproc_t	clnt_broadcast_result_main;
315  static once_t		clnt_broadcast_once = ONCE_INITIALIZER;
316  
317  static void
clnt_broadcast_key_init(void)318  clnt_broadcast_key_init(void)
319  {
320  
321  	thr_keycreate(&clnt_broadcast_key, free);
322  }
323  
324  /*
325   * Need to translate the netbuf address into sockaddr_in address.
326   * Dont care about netid here.
327   */
328  /* ARGSUSED */
329  static bool_t
rpc_wrap_bcast(char * resultp,struct netbuf * addr,struct netconfig * nconf)330  rpc_wrap_bcast(char *resultp, struct netbuf *addr, struct netconfig *nconf)
331  /*
332   *	char *resultp;		// results of the call
333   *	struct netbuf *addr;	// address of the guy who responded
334   *	struct netconfig *nconf; // Netconf of the transport
335   */
336  {
337  	resultproc_t clnt_broadcast_result;
338  
339  	if (strcmp(nconf->nc_netid, "udp"))
340  		return (FALSE);
341  	if (thr_main())
342  		clnt_broadcast_result = clnt_broadcast_result_main;
343  	else
344  		clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key);
345  	return (*clnt_broadcast_result)(resultp,
346  				(struct sockaddr_in *)addr->buf);
347  }
348  
349  /*
350   * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
351   */
352  enum clnt_stat
clnt_broadcast(u_long prog,u_long vers,u_long proc,xdrproc_t xargs,void * argsp,xdrproc_t xresults,void * resultsp,resultproc_t eachresult)353  clnt_broadcast(u_long prog, u_long vers, u_long proc, xdrproc_t xargs,
354      void *argsp, xdrproc_t xresults, void *resultsp, resultproc_t eachresult)
355  /*
356   *	u_long		prog;		// program number
357   *	u_long		vers;		// version number
358   *	u_long		proc;		// procedure number
359   *	xdrproc_t	xargs;		// xdr routine for args
360   *	void	       *argsp;		// pointer to args
361   *	xdrproc_t	xresults;	// xdr routine for results
362   *	void	       *resultsp;	// pointer to results
363   *	resultproc_t	eachresult;	// call with each result obtained
364   */
365  {
366  
367  	if (thr_main())
368  		clnt_broadcast_result_main = eachresult;
369  	else {
370  		thr_once(&clnt_broadcast_once, clnt_broadcast_key_init);
371  		thr_setspecific(clnt_broadcast_key, (void *) eachresult);
372  	}
373  	return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
374  	    (rpcproc_t)proc, xargs, argsp, xresults, resultsp,
375  	    (resultproc_t) rpc_wrap_bcast, "udp");
376  }
377  
378  /*
379   * Create the client des authentication object. Obsoleted by
380   * authdes_seccreate().
381   */
382  AUTH *
authdes_create(char * servername,u_int window,struct sockaddr * syncaddr,des_block * ckey)383  authdes_create(char *servername, u_int window, struct sockaddr *syncaddr,
384      des_block *ckey)
385  /*
386   *	char *servername;		// network name of server
387   *	u_int window;			// time to live
388   *	struct sockaddr *syncaddr;	// optional hostaddr to sync with
389   *	des_block *ckey;		// optional conversation key to use
390   */
391  {
392  	AUTH *dummy;
393  	AUTH *nauth;
394  	char hostname[NI_MAXHOST];
395  
396  	if (syncaddr) {
397  		/*
398  		 * Change addr to hostname, because that is the way
399  		 * new interface takes it.
400  		 */
401  		if (getnameinfo(syncaddr, syncaddr->sa_len, hostname,
402  		    sizeof hostname, NULL, 0, 0) != 0)
403  			goto fallback;
404  
405  		nauth = authdes_seccreate(servername, window, hostname, ckey);
406  		return (nauth);
407  	}
408  fallback:
409  	dummy = authdes_seccreate(servername, window, NULL, ckey);
410  	return (dummy);
411  }
412  
413  /*
414   * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
415   */
416  CLIENT *
clntunix_create(struct sockaddr_un * raddr,u_long prog,u_long vers,int * sockp,u_int sendsz,u_int recvsz)417  clntunix_create(struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp,
418      u_int sendsz, u_int recvsz)
419  {
420  	struct netbuf *svcaddr;
421  	CLIENT *cl;
422  	int len;
423  
424  	cl = NULL;
425  	svcaddr = NULL;
426  	if ((raddr->sun_len == 0) ||
427  	   ((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) ||
428  	   ((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) {
429  		free(svcaddr);
430  		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
431  		rpc_createerr.cf_error.re_errno = errno;
432  		return(cl);
433  	}
434  	if (*sockp < 0) {
435  		*sockp = _socket(AF_LOCAL, SOCK_STREAM, 0);
436  		len = raddr->sun_len = SUN_LEN(raddr);
437  		if ((*sockp < 0) || (_connect(*sockp,
438  		    (struct sockaddr *)raddr, len) < 0)) {
439  			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
440  			rpc_createerr.cf_error.re_errno = errno;
441  			if (*sockp != -1)
442  				(void)_close(*sockp);
443  			goto done;
444  		}
445  	}
446  	svcaddr->buf = raddr;
447  	svcaddr->len = raddr->sun_len;
448  	svcaddr->maxlen = sizeof (struct sockaddr_un);
449  	cl = clnt_vc_create(*sockp, svcaddr, prog,
450  	    vers, sendsz, recvsz);
451  done:
452  	free(svcaddr->buf);
453  	free(svcaddr);
454  	return(cl);
455  }
456  
457  /*
458   * Creates, registers, and returns a (rpc) unix based transporter.
459   * Obsoleted by svc_vc_create().
460   */
461  SVCXPRT *
svcunix_create(int sock,u_int sendsize,u_int recvsize,char * path)462  svcunix_create(int sock, u_int sendsize, u_int recvsize, char *path)
463  {
464  	struct netconfig *nconf;
465  	void *localhandle;
466  	struct sockaddr_un sun;
467  	struct sockaddr *sa;
468  	struct t_bind taddr;
469  	SVCXPRT *xprt;
470  	int addrlen;
471  
472  	xprt = (SVCXPRT *)NULL;
473  	localhandle = setnetconfig();
474  	while ((nconf = getnetconfig(localhandle)) != NULL) {
475  		if (nconf->nc_protofmly != NULL &&
476  		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
477  			break;
478  	}
479  	if (nconf == NULL)
480  		goto done;
481  
482  	if ((sock = __rpc_nconf2fd(nconf)) < 0)
483  		goto done;
484  
485  	memset(&sun, 0, sizeof sun);
486  	sun.sun_family = AF_LOCAL;
487  	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
488  	    sizeof(sun.sun_path))
489  		goto done;
490  	sun.sun_len = SUN_LEN(&sun);
491  	addrlen = sizeof (struct sockaddr_un);
492  	sa = (struct sockaddr *)&sun;
493  
494  	if (_bind(sock, sa, addrlen) < 0)
495  		goto done;
496  
497  	taddr.addr.len = taddr.addr.maxlen = addrlen;
498  	taddr.addr.buf = malloc(addrlen);
499  	if (taddr.addr.buf == NULL)
500  		goto done;
501  	memcpy(taddr.addr.buf, sa, addrlen);
502  
503  	if (nconf->nc_semantics != NC_TPI_CLTS) {
504  		if (_listen(sock, SOMAXCONN) < 0) {
505  			free(taddr.addr.buf);
506  			goto done;
507  		}
508  	}
509  
510  	xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);
511  
512  done:
513  	endnetconfig(localhandle);
514  	return(xprt);
515  }
516  
517  /*
518   * Like svunix_create(), except the routine takes any *open* UNIX file
519   * descriptor as its first input. Obsoleted by svc_fd_create();
520   */
521  SVCXPRT *
svcunixfd_create(int fd,u_int sendsize,u_int recvsize)522  svcunixfd_create(int fd, u_int sendsize, u_int recvsize)
523  {
524   	return (svc_fd_create(fd, sendsize, recvsize));
525  }
526  
527  #endif /* PORTMAP */
528