xref: /freebsd/usr.sbin/rpcbind/rpcb_svc_4.c (revision 3494f7c0)
1 /*
2  * $NetBSD: rpcb_svc_4.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $
3  */
4 
5 /*-
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Copyright (c) 2009, Sun Microsystems, Inc.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  * - Neither the name of Sun Microsystems, Inc. nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 /*
35  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
36  */
37 
38 /*
39  * rpcb_svc_4.c
40  * The server procedure for the version 4 rpcbind.
41  *
42  */
43 
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <rpc/rpc.h>
47 #include <stdio.h>
48 #include <netconfig.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include "rpcbind.h"
52 
53 static void *rpcbproc_getaddr_4_local(void *, struct svc_req *, SVCXPRT *,
54 				      rpcvers_t);
55 static void *rpcbproc_getversaddr_4_local(void *, struct svc_req *, SVCXPRT *, rpcvers_t);
56 static void *rpcbproc_getaddrlist_4_local
57 	(void *, struct svc_req *, SVCXPRT *, rpcvers_t);
58 static void free_rpcb_entry_list(rpcb_entry_list_ptr *);
59 static void *rpcbproc_dump_4_local(void *, struct svc_req *, SVCXPRT *, rpcvers_t);
60 
61 /*
62  * Called by svc_getreqset. There is a separate server handle for
63  * every transport that it waits on.
64  */
65 void
66 rpcb_service_4(struct svc_req *rqstp, SVCXPRT *transp)
67 {
68 	union {
69 		rpcb rpcbproc_set_4_arg;
70 		rpcb rpcbproc_unset_4_arg;
71 		rpcb rpcbproc_getaddr_4_local_arg;
72 		char *rpcbproc_uaddr2taddr_4_arg;
73 		struct netbuf rpcbproc_taddr2uaddr_4_arg;
74 	} argument;
75 	char *result;
76 	xdrproc_t xdr_argument, xdr_result;
77 	void *(*local)(void *, struct svc_req *, SVCXPRT *, rpcvers_t);
78 
79 	rpcbs_procinfo(RPCBVERS_4_STAT, rqstp->rq_proc);
80 
81 	switch (rqstp->rq_proc) {
82 	case NULLPROC:
83 		/*
84 		 * Null proc call
85 		 */
86 #ifdef RPCBIND_DEBUG
87 		if (debugging)
88 			fprintf(stderr, "RPCBPROC_NULL\n");
89 #endif
90 		check_access(transp, rqstp->rq_proc, NULL, RPCBVERS4);
91 		(void) svc_sendreply(transp, (xdrproc_t) xdr_void,
92 					(char *)NULL);
93 		return;
94 
95 	case RPCBPROC_SET:
96 		/*
97 		 * Check to see whether the message came from
98 		 * loopback transports (for security reasons)
99 		 */
100 		xdr_argument = (xdrproc_t)xdr_rpcb;
101 		xdr_result = (xdrproc_t)xdr_bool;
102 		local = rpcbproc_set_com;
103 		break;
104 
105 	case RPCBPROC_UNSET:
106 		/*
107 		 * Check to see whether the message came from
108 		 * loopback transports (for security reasons)
109 		 */
110 		xdr_argument = (xdrproc_t)xdr_rpcb;
111 		xdr_result = (xdrproc_t)xdr_bool;
112 		local = rpcbproc_unset_com;
113 		break;
114 
115 	case RPCBPROC_GETADDR:
116 		xdr_argument = (xdrproc_t)xdr_rpcb;
117 		xdr_result = (xdrproc_t)xdr_wrapstring;
118 		local = rpcbproc_getaddr_4_local;
119 		break;
120 
121 	case RPCBPROC_GETVERSADDR:
122 #ifdef RPCBIND_DEBUG
123 		if (debugging)
124 			fprintf(stderr, "RPCBPROC_GETVERSADDR\n");
125 #endif
126 		xdr_argument = (xdrproc_t)xdr_rpcb;
127 		xdr_result = (xdrproc_t)xdr_wrapstring;
128 		local = rpcbproc_getversaddr_4_local;
129 		break;
130 
131 	case RPCBPROC_DUMP:
132 #ifdef RPCBIND_DEBUG
133 		if (debugging)
134 			fprintf(stderr, "RPCBPROC_DUMP\n");
135 #endif
136 		xdr_argument = (xdrproc_t)xdr_void;
137 		xdr_result = (xdrproc_t)xdr_rpcblist_ptr;
138 		local = rpcbproc_dump_4_local;
139 		break;
140 
141 	case RPCBPROC_INDIRECT:
142 #ifdef RPCBIND_DEBUG
143 		if (debugging)
144 			fprintf(stderr, "RPCBPROC_INDIRECT\n");
145 #endif
146 		rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
147 		return;
148 
149 /*	case RPCBPROC_CALLIT: */
150 	case RPCBPROC_BCAST:
151 #ifdef RPCBIND_DEBUG
152 		if (debugging)
153 			fprintf(stderr, "RPCBPROC_BCAST\n");
154 #endif
155 		rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
156 		return;
157 
158 	case RPCBPROC_GETTIME:
159 #ifdef RPCBIND_DEBUG
160 		if (debugging)
161 			fprintf(stderr, "RPCBPROC_GETTIME\n");
162 #endif
163 		xdr_argument = (xdrproc_t)xdr_void;
164 		xdr_result = (xdrproc_t)xdr_u_long;
165 		local = rpcbproc_gettime_com;
166 		break;
167 
168 	case RPCBPROC_UADDR2TADDR:
169 #ifdef RPCBIND_DEBUG
170 		if (debugging)
171 			fprintf(stderr, "RPCBPROC_UADDR2TADDR\n");
172 #endif
173 		xdr_argument = (xdrproc_t)xdr_wrapstring;
174 		xdr_result = (xdrproc_t)xdr_netbuf;
175 		local = rpcbproc_uaddr2taddr_com;
176 		break;
177 
178 	case RPCBPROC_TADDR2UADDR:
179 #ifdef RPCBIND_DEBUG
180 		if (debugging)
181 			fprintf(stderr, "RPCBPROC_TADDR2UADDR\n");
182 #endif
183 		xdr_argument = (xdrproc_t)xdr_netbuf;
184 		xdr_result = (xdrproc_t)xdr_wrapstring;
185 		local = rpcbproc_taddr2uaddr_com;
186 		break;
187 
188 	case RPCBPROC_GETADDRLIST:
189 #ifdef RPCBIND_DEBUG
190 		if (debugging)
191 			fprintf(stderr, "RPCBPROC_GETADDRLIST\n");
192 #endif
193 		xdr_argument = (xdrproc_t)xdr_rpcb;
194 		xdr_result = (xdrproc_t)xdr_rpcb_entry_list_ptr;
195 		local = rpcbproc_getaddrlist_4_local;
196 		break;
197 
198 	case RPCBPROC_GETSTAT:
199 #ifdef RPCBIND_DEBUG
200 		if (debugging)
201 			fprintf(stderr, "RPCBPROC_GETSTAT\n");
202 #endif
203 		xdr_argument = (xdrproc_t)xdr_void;
204 		xdr_result = (xdrproc_t)xdr_rpcb_stat_byvers;
205 		local = rpcbproc_getstat;
206 		break;
207 
208 	default:
209 		svcerr_noproc(transp);
210 		return;
211 	}
212 	memset((char *)&argument, 0, sizeof (argument));
213 	if (!svc_getargs(transp, (xdrproc_t) xdr_argument,
214 		(char *)&argument)) {
215 		svcerr_decode(transp);
216 		if (debugging)
217 			(void) fprintf(stderr, "rpcbind: could not decode\n");
218 		return;
219 	}
220 	if (!check_access(transp, rqstp->rq_proc, &argument, RPCBVERS4)) {
221 		svcerr_weakauth(transp);
222 		goto done;
223 	}
224 	result = (*local)(&argument, rqstp, transp, RPCBVERS4);
225 	if (result != NULL && !svc_sendreply(transp, (xdrproc_t) xdr_result,
226 						result)) {
227 		svcerr_systemerr(transp);
228 		if (debugging) {
229 			(void) fprintf(stderr, "rpcbind: svc_sendreply\n");
230 			if (doabort) {
231 				rpcbind_abort();
232 			}
233 		}
234 	}
235 done:
236 	if (!svc_freeargs(transp, (xdrproc_t) xdr_argument,
237 				(char *)&argument)) {
238 		if (debugging) {
239 			(void) fprintf(stderr, "unable to free arguments\n");
240 			if (doabort) {
241 				rpcbind_abort();
242 			}
243 		}
244 	}
245 }
246 
247 /*
248  * Lookup the mapping for a program, version and return its
249  * address. Assuming that the caller wants the address of the
250  * server running on the transport on which the request came.
251  * Even if a service with a different version number is available,
252  * it will return that address.  The client should check with an
253  * clnt_call to verify whether the service is the one that is desired.
254  * We also try to resolve the universal address in terms of
255  * address of the caller.
256  */
257 /* ARGSUSED */
258 static void *
259 rpcbproc_getaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
260 			 rpcvers_t rpcbversnum __unused)
261 {
262 	RPCB *regp = (RPCB *)arg;
263 #ifdef RPCBIND_DEBUG
264 	if (debugging) {
265 		char *uaddr;
266 
267 		uaddr =	taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
268 			    svc_getrpccaller(transp));
269 		fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ",
270 		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
271 		    regp->r_netid, uaddr);
272 		free(uaddr);
273 	}
274 #endif
275 	return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
276 					RPCB_ALLVERS));
277 }
278 
279 /*
280  * Lookup the mapping for a program, version and return its
281  * address. Assuming that the caller wants the address of the
282  * server running on the transport on which the request came.
283  *
284  * We also try to resolve the universal address in terms of
285  * address of the caller.
286  */
287 /* ARGSUSED */
288 static void *
289 rpcbproc_getversaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
290 			     rpcvers_t versnum __unused)
291 {
292 	RPCB *regp = (RPCB *)arg;
293 #ifdef RPCBIND_DEBUG
294 	if (debugging) {
295 		char *uaddr;
296 
297 		uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
298 			    svc_getrpccaller(transp));
299 		fprintf(stderr, "RPCB_GETVERSADDR rqst for (%lu, %lu, %s)"
300 				" from %s : ",
301 		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
302 		    regp->r_netid, uaddr);
303 		free(uaddr);
304 	}
305 #endif
306 	return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
307 					RPCB_ONEVERS));
308 }
309 
310 /*
311  * Lookup the mapping for a program, version and return the
312  * addresses for all transports in the current transport family.
313  * We return a merged address.
314  */
315 /* ARGSUSED */
316 static void *
317 rpcbproc_getaddrlist_4_local(void *arg, struct svc_req *rqstp __unused,
318 			     SVCXPRT *transp, rpcvers_t versnum __unused)
319 {
320 	RPCB *regp = (RPCB *)arg;
321 	static rpcb_entry_list_ptr rlist;
322 	register rpcblist_ptr rbl;
323 	rpcb_entry_list_ptr rp, tail;
324 	rpcprog_t prog;
325 	rpcvers_t vers;
326 	rpcb_entry *a;
327 	struct netconfig *nconf;
328 	struct netconfig *reg_nconf;
329 	char *saddr, *maddr = NULL;
330 
331 	free_rpcb_entry_list(&rlist);
332 	tail = NULL;
333 	prog = regp->r_prog;
334 	vers = regp->r_vers;
335 	reg_nconf = rpcbind_get_conf(transp->xp_netid);
336 	if (reg_nconf == NULL)
337 		return (NULL);
338 	if (*(regp->r_addr) != '\0') {
339 		saddr = regp->r_addr;
340 	} else {
341 		saddr = NULL;
342 	}
343 #ifdef RPCBIND_DEBUG
344 	if (debugging) {
345 		fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n",
346 		    regp->r_addr, regp->r_netid, reg_nconf->nc_protofmly);
347 	}
348 #endif
349 	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
350 	    if ((rbl->rpcb_map.r_prog == prog) &&
351 		(rbl->rpcb_map.r_vers == vers)) {
352 		nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid);
353 		if (nconf == NULL)
354 			goto fail;
355 		if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly)
356 				!= 0) {
357 			continue;	/* not same proto family */
358 		}
359 #ifdef RPCBIND_DEBUG
360 		if (debugging)
361 			fprintf(stderr, "\tmerge with: %s\n",
362 			    rbl->rpcb_map.r_addr);
363 #endif
364 		if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid,
365 				rbl->rpcb_map.r_addr, saddr)) == NULL) {
366 #ifdef RPCBIND_DEBUG
367 		if (debugging)
368 			fprintf(stderr, " FAILED\n");
369 #endif
370 			continue;
371 		} else if (!maddr[0]) {
372 #ifdef RPCBIND_DEBUG
373 	if (debugging)
374 		fprintf(stderr, " SUCCEEDED, but port died -  maddr: nullstring\n");
375 #endif
376 			/* The server died. Unset this combination */
377 			delete_prog(regp->r_prog);
378 			continue;
379 		}
380 #ifdef RPCBIND_DEBUG
381 		if (debugging)
382 			fprintf(stderr, " SUCCEEDED maddr: %s\n", maddr);
383 #endif
384 		/*
385 		 * Add it to rlist.
386 		 */
387 		rp = malloc(sizeof (rpcb_entry_list));
388 		if (rp == NULL)
389 			goto fail;
390 		a = &rp->rpcb_entry_map;
391 		a->r_maddr = maddr;
392 		a->r_nc_netid = nconf->nc_netid;
393 		a->r_nc_semantics = nconf->nc_semantics;
394 		a->r_nc_protofmly = nconf->nc_protofmly;
395 		a->r_nc_proto = nconf->nc_proto;
396 		rp->rpcb_entry_next = NULL;
397 		if (rlist == NULL) {
398 			rlist = rp;
399 			tail = rp;
400 		} else {
401 			tail->rpcb_entry_next = rp;
402 			tail = rp;
403 		}
404 		rp = NULL;
405 	    }
406 	}
407 #ifdef RPCBIND_DEBUG
408 	if (debugging) {
409 		for (rp = rlist; rp; rp = rp->rpcb_entry_next) {
410 			fprintf(stderr, "\t%s %s\n", rp->rpcb_entry_map.r_maddr,
411 				rp->rpcb_entry_map.r_nc_proto);
412 		}
413 	}
414 #endif
415 	/*
416 	 * XXX: getaddrlist info is also being stuffed into getaddr.
417 	 * Perhaps wrong, but better than it not getting counted at all.
418 	 */
419 	rpcbs_getaddr(RPCBVERS4 - 2, prog, vers, transp->xp_netid, maddr);
420 	return (void *)&rlist;
421 
422 fail:	free_rpcb_entry_list(&rlist);
423 	return (NULL);
424 }
425 
426 /*
427  * Free only the allocated structure, rest is all a pointer to some
428  * other data somewhere else.
429  */
430 static void
431 free_rpcb_entry_list(rpcb_entry_list_ptr *rlistp)
432 {
433 	register rpcb_entry_list_ptr rbl, tmp;
434 
435 	for (rbl = *rlistp; rbl != NULL; ) {
436 		tmp = rbl;
437 		rbl = rbl->rpcb_entry_next;
438 		free((char *)tmp->rpcb_entry_map.r_maddr);
439 		free((char *)tmp);
440 	}
441 	*rlistp = NULL;
442 }
443 
444 /* ARGSUSED */
445 static void *
446 rpcbproc_dump_4_local(void *arg __unused, struct svc_req *req __unused,
447     		      SVCXPRT *xprt __unused, rpcvers_t versnum __unused)
448 {
449 	return ((void *)&list_rbl);
450 }
451