1/*	$NetBSD: rpc_soc.c,v 1.24 2024/01/23 17:24:38 christos Exp $	*/
2
3/*
4 * Copyright (c) 2010, Oracle America, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above
13 *       copyright notice, this list of conditions and the following
14 *       disclaimer in the documentation and/or other materials
15 *       provided with the distribution.
16 *     * Neither the name of the "Oracle America, 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
21 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/* #ident	"@(#)rpc_soc.c	1.17	94/04/24 SMI" */
35
36/*
37 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
38 * In addition, portions of such source code were derived from Berkeley
39 * 4.3 BSD under license from the Regents of the University of
40 * California.
41 */
42
43#include <sys/cdefs.h>
44#if defined(LIBC_SCCS) && !defined(lint)
45#if 0
46static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro";
47#else
48__RCSID("$NetBSD: rpc_soc.c,v 1.24 2024/01/23 17:24:38 christos Exp $");
49#endif
50#endif
51
52#ifdef PORTMAP
53/*
54 * rpc_soc.c
55 *
56 * The backward compatibility routines for the earlier implementation
57 * of RPC, where the only transports supported were tcp/ip and udp/ip.
58 * Based on berkeley socket abstraction, now implemented on the top
59 * of TLI/Streams
60 */
61
62#include "namespace.h"
63#include "reentrant.h"
64#include <sys/types.h>
65#include <sys/socket.h>
66#include <stdio.h>
67#include <rpc/rpc.h>
68#include <rpc/pmap_clnt.h>
69#include <rpc/pmap_prot.h>
70#include <rpc/nettype.h>
71#include <netinet/in.h>
72#include <assert.h>
73#include <errno.h>
74#include <netdb.h>
75#include <stdlib.h>
76#include <string.h>
77#include <syslog.h>
78#include <unistd.h>
79
80#include "svc_fdset.h"
81#include "rpc_internal.h"
82
83#ifdef __weak_alias
84__weak_alias(clntudp_bufcreate,_clntudp_bufcreate)
85__weak_alias(clntudp_create,_clntudp_create)
86__weak_alias(clnttcp_create,_clnttcp_create)
87__weak_alias(clntraw_create,_clntraw_create)
88__weak_alias(get_myaddress,_get_myaddress)
89__weak_alias(svcfd_create,_svcfd_create)
90__weak_alias(svcudp_bufcreate,_svcudp_bufcreate)
91__weak_alias(svcudp_create,_svcudp_create)
92__weak_alias(svctcp_create,_svctcp_create)
93__weak_alias(svcraw_create,_svcraw_create)
94__weak_alias(callrpc,_callrpc)
95__weak_alias(registerrpc,_registerrpc)
96__weak_alias(clnt_broadcast,_clnt_broadcast)
97#endif
98
99static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
100				    int *, u_int, u_int, const char *);
101static SVCXPRT *svc_com_create(int, u_int, u_int, const char *);
102static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *);
103
104/*
105 * A common clnt create routine
106 */
107static CLIENT *
108clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
109	int *sockp, u_int sendsz, u_int recvsz, const char *tp)
110{
111	CLIENT *cl;
112	int madefd = FALSE;
113	int fd;
114	struct netconfig *nconf;
115	struct netbuf bindaddr;
116
117	_DIAGASSERT(raddr != NULL);
118	_DIAGASSERT(sockp != NULL);
119	_DIAGASSERT(tp != NULL);
120
121	fd = *sockp;
122
123	mutex_lock(&rpcsoc_lock);
124	if ((nconf = __rpc_getconfip(tp)) == NULL) {
125		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
126		mutex_unlock(&rpcsoc_lock);
127		return (NULL);
128	}
129	if (fd == RPC_ANYSOCK) {
130		fd = __rpc_nconf2fd(nconf);
131		if (fd == -1)
132			goto syserror;
133		madefd = TRUE;
134	}
135
136	if (raddr->sin_port == 0) {
137		u_int proto;
138		u_short sport;
139
140		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
141		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
142		sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
143		    proto);
144		if (sport == 0) {
145			goto err;
146		}
147		raddr->sin_port = htons(sport);
148		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
149	}
150
151	/* Transform sockaddr_in to netbuf */
152	bindaddr.maxlen = bindaddr.len =  sizeof (struct sockaddr_in);
153	bindaddr.buf = raddr;
154
155	(void)bindresvport(fd, NULL);
156	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
157				sendsz, recvsz);
158	if (cl) {
159		if (madefd == TRUE) {
160			/*
161			 * The fd should be closed while destroying the handle.
162			 */
163			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
164			*sockp = fd;
165		}
166		(void) freenetconfigent(nconf);
167		mutex_unlock(&rpcsoc_lock);
168		return (cl);
169	}
170	goto err;
171
172syserror:
173	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
174	rpc_createerr.cf_error.re_errno = errno;
175
176err:	if (madefd == TRUE)
177		(void) close(fd);
178	(void) freenetconfigent(nconf);
179	mutex_unlock(&rpcsoc_lock);
180	return (NULL);
181}
182
183CLIENT *
184clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
185{
186	CLIENT *cl;
187
188	_DIAGASSERT(raddr != NULL);
189	_DIAGASSERT(sockp != NULL);
190
191	cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
192	    sendsz, recvsz, "udp");
193	if (cl == NULL) {
194		return (NULL);
195	}
196	(void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)(void *)&wait);
197	return (cl);
198}
199
200CLIENT *
201clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
202    struct timeval wait, int *sockp)
203{
204	return clntudp_bufcreate(raddr, program, version, wait, sockp,
205					UDPMSGSIZE, UDPMSGSIZE);
206}
207
208CLIENT *
209clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
210    u_int sendsz, u_int recvsz)
211{
212	return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
213	    sendsz, recvsz, "tcp");
214}
215
216CLIENT *
217clntraw_create(u_long prog, u_long vers)
218{
219	return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers);
220}
221
222/*
223 * A common server create routine
224 */
225static SVCXPRT *
226svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid)
227{
228	struct netconfig *nconf;
229	SVCXPRT *svc;
230	int madefd = FALSE;
231	int port;
232	struct sockaddr_in sccsin;
233
234	_DIAGASSERT(netid != NULL);
235
236	if ((nconf = __rpc_getconfip(netid)) == NULL) {
237		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
238		return (NULL);
239	}
240	if (fd == RPC_ANYSOCK) {
241		fd = __rpc_nconf2fd(nconf);
242		if (fd == -1) {
243			(void) freenetconfigent(nconf);
244			(void) syslog(LOG_ERR,
245			"svc%s_create: could not open connection", netid);
246			return (NULL);
247		}
248		madefd = TRUE;
249	}
250
251	memset(&sccsin, 0, sizeof sccsin);
252	sccsin.sin_family = AF_INET;
253	(void)bindresvport(fd, &sccsin);
254
255	switch (nconf->nc_semantics) {
256	case NC_TPI_COTS:
257	case NC_TPI_COTS_ORD:
258		if (listen(fd, SOMAXCONN) == -1) {
259			(void) syslog(LOG_ERR,
260			    "svc%s_create: listen(2) failed: %s",
261			    netid, strerror(errno));
262			(void) freenetconfigent(nconf);
263			goto out;
264		}
265		break;
266	default:
267		break;
268	}
269
270	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
271	(void) freenetconfigent(nconf);
272	if (svc == NULL)
273		goto out;
274	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
275	svc->xp_port = ntohs(port);
276	return svc;
277out:
278	if (madefd)
279		(void) close(fd);
280	return NULL;
281}
282
283SVCXPRT *
284svctcp_create(int fd, u_int sendsize, u_int recvsize)
285{
286	return svc_com_create(fd, sendsize, recvsize, "tcp");
287}
288
289SVCXPRT *
290svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz)
291{
292	return svc_com_create(fd, sendsz, recvsz, "udp");
293}
294
295SVCXPRT *
296svcfd_create(int fd, u_int sendsize, u_int recvsize)
297{
298	return svc_fd_create(fd, sendsize, recvsize);
299}
300
301
302SVCXPRT *
303svcudp_create(int fd)
304{
305	return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
306}
307
308SVCXPRT *
309svcraw_create(void)
310{
311	return svc_raw_create();
312}
313
314int
315get_myaddress(struct sockaddr_in *addr)
316{
317
318	_DIAGASSERT(addr != NULL);
319
320	memset((void *) addr, 0, sizeof(*addr));
321	addr->sin_family = AF_INET;
322	addr->sin_port = htons(PMAPPORT);
323	addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
324	return (0);
325}
326
327/*
328 * For connectionless "udp" transport. Obsoleted by rpc_call().
329 */
330int
331callrpc(char *host, int prognum, int versnum, int procnum,
332	xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
333{
334	return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum,
335	    (rpcproc_t)procnum, inproc, in, outproc, out, "udp");
336}
337
338/*
339 * For connectionless kind of transport. Obsoleted by rpc_reg()
340 */
341int
342registerrpc(int prognum, int versnum, int procnum,
343	char *(*progname)(char [UDPMSGSIZE]),
344	xdrproc_t inproc, xdrproc_t outproc)
345{
346	return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum,
347	    (rpcproc_t)procnum, progname, inproc, outproc, __UNCONST("udp"));
348}
349
350/*
351 * All the following clnt_broadcast stuff is convulated; it supports
352 * the earlier calling style of the callback function
353 */
354#ifdef _REENTRANT
355static thread_key_t	clnt_broadcast_key;
356#endif
357static resultproc_t	clnt_broadcast_result_main;
358
359/*
360 * Need to translate the netbuf address into sockaddr_in address.
361 * Dont care about netid here.
362 */
363/* ARGSUSED */
364static bool_t
365rpc_wrap_bcast(
366	char *resultp,		/* results of the call */
367	struct netbuf *addr,	/* address of the guy who responded */
368	struct netconfig *nconf) /* Netconf of the transport */
369{
370	resultproc_t clnt_broadcast_result;
371
372	_DIAGASSERT(resultp != NULL);
373	_DIAGASSERT(addr != NULL);
374	_DIAGASSERT(nconf != NULL);
375
376	if (strcmp(nconf->nc_netid, "udp"))
377		return (FALSE);
378#ifdef _REENTRANT
379	if (__isthreaded == 0)
380		clnt_broadcast_result = clnt_broadcast_result_main;
381	else
382		clnt_broadcast_result = thr_getspecific(clnt_broadcast_key);
383#else
384	clnt_broadcast_result = clnt_broadcast_result_main;
385#endif
386	return (*clnt_broadcast_result)(resultp,
387				(struct sockaddr_in *)addr->buf);
388}
389
390#ifdef _REENTRANT
391static once_t clnt_broadcast_once = ONCE_INITIALIZER;
392
393static void
394clnt_broadcast_setup(void)
395{
396
397	thr_keycreate(&clnt_broadcast_key, free);
398}
399#endif
400
401/*
402 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
403 */
404enum clnt_stat
405clnt_broadcast(
406	u_long		prog,		/* program number */
407	u_long		vers,		/* version number */
408	u_long		proc,		/* procedure number */
409	xdrproc_t	xargs,		/* xdr routine for args */
410	caddr_t		argsp,		/* pointer to args */
411	xdrproc_t	xresults,	/* xdr routine for results */
412	caddr_t		resultsp,	/* pointer to results */
413	resultproc_t	eachresult)	/* call with each result obtained */
414{
415#ifdef _REENTRANT
416	if (__isthreaded == 0)
417		clnt_broadcast_result_main = eachresult;
418	else {
419		thr_once(&clnt_broadcast_once, clnt_broadcast_setup);
420		thr_setspecific(clnt_broadcast_key, (void *) eachresult);
421	}
422#else
423	clnt_broadcast_result_main = eachresult;
424#endif
425	return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
426	    (rpcproc_t)proc, xargs, argsp, xresults, resultsp,
427	    (resultproc_t) rpc_wrap_bcast, "udp");
428}
429
430#endif /* PORTMAP */
431