1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * This file contains the routines that maintain a linked list of known
31 * program to udp port mappings. There are three static members initialized
32 * by default, one for the portmapper itself (of course), one for rpcbind,
33 * and one for nfs. If a program number is not in the list, then routines
34 * in this file contact the portmapper on the server, and dynamically add
35 * new members to this list.
36 *
37 * This file also contains bpmap_rmtcall() - which lets one get the port
38 * number AND run the rpc call in one step. Only the server that successfully
39 * completes the rpc call will return a result.
40 *
41 * NOTE: Because we will end up caching the port entries we need
42 * before the kernel begins running, we can use dynamic allocation here.
43 * boot_memfree() calls bpmap_memfree() to free up any dynamically
44 * allocated entries when the boot program has finished its job.
45 */
46
47#include <sys/types.h>
48#include <rpc/types.h>
49#include <sys/errno.h>
50#include <sys/time.h>
51#include <sys/socket.h>
52#include <net/if.h>
53#include <netinet/in.h>
54#include <netinet/if_ether.h>
55#include <rpc/xdr.h>
56#include <rpc/auth.h>
57#include <sys/t_lock.h>
58#include "clnt.h"
59#include <rpc/pmap_prot.h>
60#include <rpc/pmap_rmt.h>
61#include <rpc/rpc.h>
62#include "brpc.h"
63#include "pmap.h"
64#include "nfs_inet.h"
65#include <rpcsvc/nfs_prot.h>
66#include <rpc/rpcb_prot.h>
67#include <sys/salib.h>
68#include "socket_inet.h"
69#include <sys/promif.h>
70#include <sys/bootdebug.h>
71
72/* portmap structure */
73#define	PMAP_STATIC	(3)	/* last statically allocated list entry */
74struct pmaplist pre_init[PMAP_STATIC + 1] = {
75	{ {PMAPPROG,	PMAPVERS,	IPPROTO_UDP, PMAPPORT}, &pre_init[1] },
76	/* SVR4 rpcbind listens to old portmapper port */
77	{ {RPCBPROG,	RPCBVERS,	IPPROTO_UDP, PMAPPORT}, &pre_init[2] },
78	{ {NFS_PROGRAM, NFS_VERSION,	IPPROTO_UDP, NFS_PORT}, &pre_init[3] },
79	{ {NFS_PROGRAM, NFS_V3,		IPPROTO_UDP, NFS_PORT}, NULL }
80};
81
82struct pmaplist *map_head = &pre_init[0];
83struct pmaplist *map_tail = &pre_init[PMAP_STATIC];
84
85#define	dprintf	if (boothowto & RB_DEBUG) printf
86
87/*
88 * bpmap_addport: adds a new entry on to the end of the pmap cache.
89 * Items are kept in host order.
90 */
91static void
92bpmap_addport(rpcprog_t prog, rpcvers_t vers, rpcport_t port)
93{
94	struct pmaplist *newp;
95
96	/* allocate new pmaplist */
97	newp = (struct pmaplist *)bkmem_alloc(sizeof (struct pmaplist));
98
99	if (newp == NULL)
100		return; /* not fatal here, we'll just throw out the entry */
101
102	newp->pml_map.pm_prog = prog;
103	newp->pml_map.pm_vers = vers;
104	newp->pml_map.pm_prot = (rpcprot_t)IPPROTO_UDP;
105	newp->pml_map.pm_port = port;
106
107	map_tail->pml_next = newp;
108	newp->pml_next = NULL;
109	map_tail = newp;
110}
111
112/*
113 * bpmap_delport: deletes an existing entry from the list. Caution - don't
114 * call this function to delete statically allocated entries. Why would
115 * you want to, anyway? Only IPPROTO_UDP is supported, of course.
116 */
117static void
118bpmap_delport(rpcprog_t prog, rpcvers_t vers)
119{
120	struct pmaplist *tmp, *prev;
121
122	prev = map_head;
123	for (tmp = map_head; tmp != NULL; tmp = tmp->pml_next) {
124		if ((tmp->pml_map.pm_prog == prog) &&
125		    (tmp->pml_map.pm_vers == vers)) {
126			if (tmp == map_head)
127				map_head = tmp->pml_next; /* new head */
128			else if (tmp == map_tail) {
129				map_tail = prev;	/* new tail */
130				map_tail->pml_next = NULL;
131			} else {
132				/* internal delete */
133				prev->pml_next = tmp->pml_next;
134			}
135#ifdef	DEBUG
136			printf("bpmap_delport: prog: %x, vers: %x\n", prog,
137			    vers);
138#endif	/* DEBUG */
139			bkmem_free((caddr_t)tmp, sizeof (struct pmaplist));
140			break;
141		} else
142			prev = tmp;
143	}
144}
145
146/*
147 * Modified strtol(3).
148 */
149static int
150strtoi(char *str, char **ptr)
151{
152	int c, val;
153
154	for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
155		val *= 10;
156		val += c - '0';
157	}
158	*ptr = str;
159	return (val);
160}
161
162/*
163 * (from dlboot_inet.c) (kernel)
164 * Convert a port number from a sockaddr_in expressed
165 * in universal address format.
166 */
167static int
168uaddr2port(char	*addr)
169{
170	int	p1, p2;
171	char	*next;
172
173	/*
174	 * A struct sockaddr_in expressed in universal address
175	 * format looks like:
176	 *
177	 *	"IP.IP.IP.IP.PORT[top byte].PORT[bot. byte]"
178	 *
179	 * Where each component expresses as a charactor,
180	 * the corresponding part of the IP address
181	 * and port number.
182	 * Thus 127.0.0.1, port 2345 looks like:
183	 *
184	 *	49 50 55 46 48 46 48 46 49 46 57 46 52 49
185	 *	1  2  7  .  0  .  0  .  1  .  9  .  4  1
186	 *
187	 * 2345 = 929base16 = 9.32+9 = 9.41
188	 */
189	(void) strtoi(addr, &next);
190	(void) strtoi(next, &next);
191	(void) strtoi(next, &next);
192	(void) strtoi(next, &next);
193	p1 = strtoi(next, &next);
194	p2 = strtoi(next, &next);
195
196	return ((p1 << 8) + p2);
197}
198
199/*
200 * Xdr routines used for calling portmapper/rpcbind.
201 */
202
203bool_t
204xdr_pmap(XDR *xdrs, struct pmap *regs)
205{
206	if (xdr_rpcprog(xdrs, &regs->pm_prog) &&
207		xdr_rpcvers(xdrs, &regs->pm_vers) &&
208		xdr_rpcprot(xdrs, &regs->pm_prot))
209		return (xdr_rpcprot(xdrs, &regs->pm_port));
210	return (FALSE);
211}
212
213bool_t
214xdr_rpcb(XDR *xdrs, RPCB *objp)
215{
216	if (!xdr_rpcprog(xdrs, &objp->r_prog))
217		return (FALSE);
218	if (!xdr_rpcvers(xdrs, &objp->r_vers))
219		return (FALSE);
220	if (!xdr_string(xdrs, &objp->r_netid, ~0))
221		return (FALSE);
222	if (!xdr_string(xdrs, &objp->r_addr, ~0))
223		return (FALSE);
224	if (!xdr_string(xdrs, &objp->r_owner, ~0))
225		return (FALSE);
226	return (TRUE);
227}
228
229/*
230 * XDR remote call arguments
231 * written for XDR_ENCODE direction only
232 */
233bool_t
234xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
235{
236	uint_t	lenposition, argposition, position;
237
238	if (xdr_rpcprog(xdrs, &(cap->prog)) &&
239	    xdr_rpcvers(xdrs, &(cap->vers)) &&
240	    xdr_rpcproc(xdrs, &(cap->proc))) {
241		lenposition = XDR_GETPOS(xdrs);
242		if (!xdr_u_int(xdrs, &(cap->arglen)))
243			return (FALSE);
244		argposition = XDR_GETPOS(xdrs);
245		if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
246			return (FALSE);
247		position = XDR_GETPOS(xdrs);
248		cap->arglen = position - argposition;
249		XDR_SETPOS(xdrs, lenposition);
250		if (!xdr_u_int(xdrs, &(cap->arglen)))
251			return (FALSE);
252		XDR_SETPOS(xdrs, position);
253		return (TRUE);
254	}
255	return (FALSE);
256}
257
258/*
259 * XDR remote call results
260 * written for XDR_DECODE direction only
261 */
262bool_t
263xdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
264{
265	caddr_t	port_ptr;
266
267	port_ptr = (caddr_t)crp->port_ptr;
268	if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
269	    xdr_u_int(xdrs, &crp->resultslen)) {
270		crp->port_ptr = (rpcport_t *)port_ptr;
271		return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
272	}
273	return (FALSE);
274}
275
276/*
277 * XDR remote call arguments
278 * written for XDR_ENCODE direction only
279 */
280bool_t
281xdr_rpcb_rmtcallargs(XDR *xdrs, struct rpcb_rmtcallargs *objp)
282{
283	uint_t lenposition, argposition, position;
284
285	if (!xdr_rpcprog(xdrs, &objp->prog))
286		return (FALSE);
287	if (!xdr_rpcvers(xdrs, &objp->vers))
288		return (FALSE);
289	if (!xdr_rpcproc(xdrs, &objp->proc))
290		return (FALSE);
291	/*
292	 * All the jugglery for just getting the size of the arguments
293	 */
294	lenposition = XDR_GETPOS(xdrs);
295	if (!xdr_u_int(xdrs, &(objp->arglen)))
296		return (FALSE);
297	argposition = XDR_GETPOS(xdrs);
298	if (!(*(objp->xdr_args))(xdrs, objp->args_ptr))
299		return (FALSE);
300	position = XDR_GETPOS(xdrs);
301	objp->arglen = position - argposition;
302	XDR_SETPOS(xdrs, lenposition);
303	if (!xdr_u_int(xdrs, &(objp->arglen)))
304		return (FALSE);
305	XDR_SETPOS(xdrs, position);
306	return (TRUE);
307}
308
309/*
310 * XDR remote call results
311 * written for XDR_DECODE direction only
312 */
313bool_t
314xdr_rpcb_rmtcallres(XDR *xdrs, struct rpcb_rmtcallres *objp)
315{
316	if (!xdr_string(xdrs, &objp->addr_ptr, ~0))
317		return (FALSE);
318	if (!xdr_u_int(xdrs, &objp->resultslen))
319		return (FALSE);
320	return ((*(objp->xdr_results))(xdrs, objp->results_ptr));
321}
322
323/*
324 * bpmap_rmtcall: does PMAPPROC_CALLIT broadcasts w/ rpc_call requests.
325 * Lets one do a PMAPGETPORT/RPC PROC call in one easy step. sockaddr_in args
326 * are taken as network order.
327 *
328 * Code adapted from bpmap_rmtcall() in dlboot_inet.c (kernel)
329 */
330/*ARGSUSED*/
331enum clnt_stat
332bpmap_rmtcall(
333	rpcprog_t		prog,	/* rpc program number to call. */
334	rpcvers_t		vers,	/* rpc program version */
335	rpcproc_t		proc,	/* rpc procedure to call */
336	xdrproc_t		in_xdr,	/* routine to serialize arguments */
337	caddr_t			args,	/* arg vector for remote call */
338	xdrproc_t		out_xdr, /* routine to deserialize results */
339	caddr_t			ret,	/* addr of buf to place results in */
340	int			rexmit,	/* retransmission interval (secs) */
341	int			wait,	/* how long (secs) to wait for a resp */
342	struct sockaddr_in 	*to,	/* destination */
343	struct sockaddr_in	*from,	/* filled in w/ responder's port/addr */
344	uint_t			auth)	/* type of authentication wanted. */
345{
346	enum clnt_stat		status;		/* rpc_call status */
347	rpcport_t		port = 0;	/* returned port # */
348	struct rmtcallargs	pmap_a;		/* args for pmap call */
349	struct rmtcallres	pmap_r;		/* results from pmap call */
350	struct rpcb_rmtcallargs	rpcb_a;		/* args for rpcb call */
351	struct rpcb_rmtcallres	rpcb_r;		/* results from rpcb call */
352	char			ua[UA_SIZE];	/* universal addr buffer */
353
354	/* initialize pmap */
355	pmap_a.prog = prog;
356	pmap_a.vers = vers;
357	pmap_a.proc = proc;
358	pmap_a.args_ptr = args;
359	pmap_a.xdr_args = in_xdr;
360	pmap_r.port_ptr = &port;
361	pmap_r.results_ptr = ret;
362	pmap_r.xdr_results = out_xdr;
363
364	status = brpc_call((rpcprog_t)PMAPPROG, (rpcvers_t)PMAPVERS,
365	    (rpcproc_t)PMAPPROC_CALLIT, xdr_rmtcall_args, (caddr_t)&pmap_a,
366	    xdr_rmtcallres, (caddr_t)&pmap_r, rexmit, wait, to, from,
367	    AUTH_NONE);
368	if (status != RPC_PROGUNAVAIL) {
369		if (status == RPC_SUCCESS) {
370			/* delete old port mapping, if it exists */
371			bpmap_delport(prog, vers);
372
373			/* save the new port mapping */
374			bpmap_addport(prog, vers, port);
375		}
376		return (status);
377	}
378
379	/*
380	 * PMAP is unavailable. Maybe there's a SVR4 machine, with rpcbind.
381	 */
382	bzero(ua, sizeof (ua));
383
384	/* initialize rpcb */
385	rpcb_a.prog = prog;
386	rpcb_a.vers = vers;
387	rpcb_a.proc = proc;
388	rpcb_a.args_ptr = args;
389	rpcb_a.xdr_args = in_xdr;
390	rpcb_r.addr_ptr = ua;
391	rpcb_r.results_ptr = ret;
392	rpcb_r.xdr_results = out_xdr;
393
394	status = brpc_call((rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS,
395	    (rpcproc_t)RPCBPROC_CALLIT, xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_a,
396	    xdr_rpcb_rmtcallres, (caddr_t)&rpcb_r, rexmit, wait, to, from,
397	    AUTH_NONE);
398	if (status == RPC_SUCCESS) {
399		/* delete old port mapping, if it exists */
400		bpmap_delport(prog, vers);
401
402		/* save the new port mapping */
403		port = ntohs(uaddr2port(ua));
404		bpmap_addport(prog, vers, port);
405	}
406	return (status);
407}
408
409/*
410 * bpmap_getport: Queries current list of cached pmap_list entries,
411 * returns the port number of the entry found. If the port number
412 * is not cached, then getport makes a rpc call first to the portmapper,
413 * and then to rpcbind (SVR4) if the portmapper does not respond. The
414 * returned port is then added to the cache, and the port number is
415 * returned. If both portmapper and rpc bind fail to give us the necessary
416 * port, we return 0 to signal we hit an error, and set rpc_stat to
417 * the appropriate RPC error code. Only IPPROTO_UDP protocol is supported.
418 *
419 * Port and sockaddr_in arguments taken in network order. rpcport_t is returned
420 * in host order.
421 */
422rpcport_t
423bpmap_getport(rpcprog_t prog, rpcvers_t vers, enum clnt_stat *rpc_stat,
424    struct sockaddr_in *to, struct sockaddr_in *from)
425{
426	struct pmaplist	*walk;
427	struct pmap	pmap_send;	/* portmap */
428	in_port_t	pmap_port;
429	rpcport_t	dport;
430
431#ifdef DEBUG
432	printf("bpmap_getport: called with: prog: %d, vers: %d\n", prog, vers);
433#endif /* DEBUG */
434	for (walk = map_head; walk != 0; walk = walk->pml_next) {
435		if ((walk->pml_map.pm_prog == prog) &&
436		    (walk->pml_map.pm_vers == vers) &&
437		    (walk->pml_map.pm_prot == (rpcprot_t)IPPROTO_UDP)) {
438#ifdef DEBUG
439			printf("bpmap_getport: Found in cache. returning: %d\n",
440			    walk->pml_map.pm_port);
441#endif /* DEBUG */
442			return (walk->pml_map.pm_port);
443		}
444	}
445
446	/*
447	 * Not in the cache. First try the portmapper (SunOS server?) and
448	 * if that fails, try rpcbind (SVR4 server).
449	 */
450	pmap_send.pm_prog = prog;
451	pmap_send.pm_vers = vers;
452	pmap_send.pm_prot = (rpcprot_t)IPPROTO_UDP;
453	pmap_send.pm_port = 0;	/* what we're after */
454
455	*rpc_stat = brpc_call(PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
456	    xdr_pmap, (caddr_t)&pmap_send, xdr_u_short,
457	    (caddr_t)&pmap_port, 0, 0, to, from, AUTH_NONE);
458
459	if (*rpc_stat == RPC_PROGUNAVAIL) {
460		/*
461		 * The portmapper isn't available. Try rpcbind.
462		 * Maybe the server is a SVR4 server.
463		 */
464		char	*ua;			/* universal address */
465		char	ua_buf[UA_SIZE];	/* and its buffer */
466		RPCB	rpcb_send;
467
468		rpcb_send.r_prog = prog;
469		rpcb_send.r_vers = vers;
470		rpcb_send.r_netid = NULL;
471		rpcb_send.r_addr = NULL;
472		rpcb_send.r_owner = NULL;
473
474		bzero(ua_buf, UA_SIZE);
475		ua = ua_buf;
476
477		/*
478		 * Again, default # of retries. xdr_wrapstring()
479		 * wants a char **.
480		 */
481		*rpc_stat = brpc_call(RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
482		    xdr_rpcb, (caddr_t)&rpcb_send, xdr_wrapstring,
483		    (char *)&ua, 0, 0, to, from, AUTH_NONE);
484
485		if (*rpc_stat == RPC_SUCCESS) {
486			if (ua[0] != '\0')
487				dport = ntohs(uaddr2port(ua));
488			else
489				return (0); /* Address unknown */
490		}
491	} else {
492		/*
493		 * Why are rpcport_t's uint32_t? port numbers are uint16_t
494		 * for ipv4 AND ipv6.... XXXX
495		 */
496		dport = (rpcport_t)pmap_port;
497	}
498
499	if (*rpc_stat != RPC_SUCCESS)  {
500		dprintf("pmap_getport: Failed getting port.\n");
501		return (0);	/* we failed. */
502	}
503
504#ifdef DEBUG
505	printf("bpmap_getport: prog: %d, vers: %d; returning port: %d.\n",
506	    prog, vers, dport);
507#endif /* DEBUG */
508
509	bpmap_addport(prog, vers, dport);
510
511	return (dport);
512}
513
514/*
515 * bpmap_memfree: frees up any dynamically allocated entries.
516 */
517void
518bpmap_memfree(void)
519{
520	struct pmaplist *current, *tmp;
521
522	if (map_tail == &pre_init[PMAP_STATIC])
523		return; /* no dynamic entries */
524
525	/* free from head of the list to the tail. */
526	current = pre_init[PMAP_STATIC].pml_next;
527	while (current != NULL) {
528		tmp = current->pml_next;
529		bkmem_free((caddr_t)current, sizeof (struct pmaplist));
530		current = tmp;
531	}
532}
533