1/*	$NetBSD: svc_simple.c,v 1.20 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 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
34 */
35
36/*
37 * svc_simple.c
38 * Simplified front end to rpc.
39 */
40
41/*
42 * This interface creates a virtual listener for all the services
43 * started through rpc_reg(). It listens on the same endpoint for
44 * all the services and then executes the corresponding service
45 * for the given prognum and procnum.
46 */
47
48#include "namespace.h"
49#include "reentrant.h"
50#include <sys/types.h>
51#include <rpc/rpc.h>
52#include <rpc/nettype.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <err.h>
57#include "un-namespace.h"
58
59#include "rpc_com.h"
60#include "mt_misc.h"
61
62static void universal(struct svc_req *, SVCXPRT *);
63
64static struct proglst {
65	char *(*p_progname)(char *);
66	rpcprog_t p_prognum;
67	rpcvers_t p_versnum;
68	rpcproc_t p_procnum;
69	SVCXPRT *p_transp;
70	char *p_netid;
71	char *p_xdrbuf;
72	int p_recvsz;
73	xdrproc_t p_inproc, p_outproc;
74	struct proglst *p_nxt;
75} *proglst;
76
77static const char rpc_reg_err[] = "%s: %s";
78static const char rpc_reg_msg[] = "rpc_reg: ";
79static const char __reg_err1[] = "can't find appropriate transport";
80static const char __reg_err2[] = "can't get protocol info";
81static const char __reg_err3[] = "unsupported transport size";
82static const char __no_mem_str[] = "out of memory";
83
84/*
85 * For simplified, easy to use kind of rpc interfaces.
86 * nettype indicates the type of transport on which the service will be
87 * listening. Used for conservation of the system resource. Only one
88 * handle is created for all the services (actually one of each netid)
89 * and same xdrbuf is used for same netid. The size of the arguments
90 * is also limited by the recvsize for that transport, even if it is
91 * a COTS transport. This may be wrong, but for cases like these, they
92 * should not use the simplified interfaces like this.
93 *
94 * prognum - program number
95 * versnum - version number
96 * procnum - procedure number
97 * progname - Server routine
98 * inproc, outproc - in/out XDR procedures
99 * nettype - nettype
100 */
101int
102rpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
103    char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc,
104    char *nettype)
105{
106	struct netconfig *nconf;
107	int done = FALSE;
108	void *handle;
109
110
111	if (procnum == NULLPROC) {
112		warnx("%s can't reassign procedure number %u", rpc_reg_msg,
113			NULLPROC);
114		return (-1);
115	}
116
117	if (nettype == NULL)
118		nettype = "netpath";		/* The default behavior */
119	if ((handle = __rpc_setconf(nettype)) == NULL) {
120		warnx(rpc_reg_err, rpc_reg_msg, __reg_err1);
121		return (-1);
122	}
123/* VARIABLES PROTECTED BY proglst_lock: proglst */
124	mutex_lock(&proglst_lock);
125	while ((nconf = __rpc_getconf(handle)) != NULL) {
126		struct proglst *pl;
127		SVCXPRT *svcxprt;
128		int madenow;
129		u_int recvsz;
130		char *xdrbuf;
131		char *netid;
132
133		madenow = FALSE;
134		svcxprt = NULL;
135		recvsz = 0;
136		xdrbuf = netid = NULL;
137		for (pl = proglst; pl; pl = pl->p_nxt) {
138			if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
139				svcxprt = pl->p_transp;
140				xdrbuf = pl->p_xdrbuf;
141				recvsz = pl->p_recvsz;
142				netid = pl->p_netid;
143				break;
144			}
145		}
146
147		if (svcxprt == NULL) {
148			struct __rpc_sockinfo si;
149
150			svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
151			if (svcxprt == NULL)
152				continue;
153			if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) {
154				warnx(rpc_reg_err, rpc_reg_msg, __reg_err2);
155				SVC_DESTROY(svcxprt);
156				continue;
157			}
158			recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0);
159			if (recvsz == 0) {
160				warnx(rpc_reg_err, rpc_reg_msg, __reg_err3);
161				SVC_DESTROY(svcxprt);
162				continue;
163			}
164			if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) ||
165				((netid = strdup(nconf->nc_netid)) == NULL)) {
166				warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
167				free(xdrbuf);
168				free(netid);
169				SVC_DESTROY(svcxprt);
170				break;
171			}
172			madenow = TRUE;
173		}
174		/*
175		 * Check if this (program, version, netid) had already been
176		 * registered.  The check may save a few RPC calls to rpcbind
177		 */
178		for (pl = proglst; pl; pl = pl->p_nxt)
179			if ((pl->p_prognum == prognum) &&
180				(pl->p_versnum == versnum) &&
181				(strcmp(pl->p_netid, netid) == 0))
182				break;
183		if (pl == NULL) { /* Not yet */
184			(void) rpcb_unset(prognum, versnum, nconf);
185		} else {
186			/* so that svc_reg does not call rpcb_set() */
187			nconf = NULL;
188		}
189
190		if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
191			warnx("%s couldn't register prog %u vers %u for %s",
192				rpc_reg_msg, (unsigned)prognum,
193				(unsigned)versnum, netid);
194			if (madenow) {
195				SVC_DESTROY(svcxprt);
196				free(xdrbuf);
197				free(netid);
198			}
199			continue;
200		}
201
202		pl = malloc(sizeof (struct proglst));
203		if (pl == NULL) {
204			warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
205			if (madenow) {
206				SVC_DESTROY(svcxprt);
207				free(xdrbuf);
208				free(netid);
209			}
210			break;
211		}
212		pl->p_progname = progname;
213		pl->p_prognum = prognum;
214		pl->p_versnum = versnum;
215		pl->p_procnum = procnum;
216		pl->p_inproc = inproc;
217		pl->p_outproc = outproc;
218		pl->p_transp = svcxprt;
219		pl->p_xdrbuf = xdrbuf;
220		pl->p_recvsz = recvsz;
221		pl->p_netid = netid;
222		pl->p_nxt = proglst;
223		proglst = pl;
224		done = TRUE;
225	}
226	__rpc_endconf(handle);
227	mutex_unlock(&proglst_lock);
228
229	if (done == FALSE) {
230		warnx("%s can't find suitable transport for %s",
231			rpc_reg_msg, nettype);
232		return (-1);
233	}
234	return (0);
235}
236
237/*
238 * The universal handler for the services registered using registerrpc.
239 * It handles both the connectionless and the connection oriented cases.
240 */
241
242static void
243universal(struct svc_req *rqstp, SVCXPRT *transp)
244{
245	rpcprog_t prog;
246	rpcvers_t vers;
247	rpcproc_t proc;
248	char *outdata;
249	char *xdrbuf;
250	struct proglst *pl;
251
252	/*
253	 * enforce "procnum 0 is echo" convention
254	 */
255	if (rqstp->rq_proc == NULLPROC) {
256		if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) ==
257		    FALSE) {
258			warnx("svc_sendreply failed");
259		}
260		return;
261	}
262	prog = rqstp->rq_prog;
263	vers = rqstp->rq_vers;
264	proc = rqstp->rq_proc;
265	mutex_lock(&proglst_lock);
266	for (pl = proglst; pl; pl = pl->p_nxt)
267		if (pl->p_prognum == prog && pl->p_procnum == proc &&
268			pl->p_versnum == vers &&
269			(strcmp(pl->p_netid, transp->xp_netid) == 0)) {
270			/* decode arguments into a CLEAN buffer */
271			xdrbuf = pl->p_xdrbuf;
272			/* Zero the arguments: reqd ! */
273			(void) memset(xdrbuf, 0, (size_t)pl->p_recvsz);
274			/*
275			 * Assuming that sizeof (xdrbuf) would be enough
276			 * for the arguments; if not then the program
277			 * may bomb. BEWARE!
278			 */
279			if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
280				svcerr_decode(transp);
281				mutex_unlock(&proglst_lock);
282				return;
283			}
284			outdata = (*(pl->p_progname))(xdrbuf);
285			if (outdata == NULL &&
286				pl->p_outproc != (xdrproc_t) xdr_void){
287				/* there was an error */
288				mutex_unlock(&proglst_lock);
289				return;
290			}
291			if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
292				warnx(
293			"rpc: rpc_reg trouble replying to prog %u vers %u",
294				(unsigned)prog, (unsigned)vers);
295				mutex_unlock(&proglst_lock);
296				return;
297			}
298			/* free the decoded arguments */
299			(void)svc_freeargs(transp, pl->p_inproc, xdrbuf);
300			mutex_unlock(&proglst_lock);
301			return;
302		}
303	mutex_unlock(&proglst_lock);
304	/* This should never happen */
305	warnx("rpc: rpc_reg: never registered prog %u vers %u",
306		(unsigned)prog, (unsigned)vers);
307	return;
308}
309