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 */
74 struct 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
82 struct pmaplist *map_head = &pre_init[0];
83 struct 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 */
91 static void
bpmap_addport(rpcprog_t prog,rpcvers_t vers,rpcport_t port)92 bpmap_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 */
117 static void
bpmap_delport(rpcprog_t prog,rpcvers_t vers)118 bpmap_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 */
149 static int
strtoi(char * str,char ** ptr)150 strtoi(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 */
167 static int
uaddr2port(char * addr)168 uaddr2port(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
203 bool_t
xdr_pmap(XDR * xdrs,struct pmap * regs)204 xdr_pmap(XDR *xdrs, struct pmap *regs)
205 {
206 if (xdr_rpcprog(xdrs, ®s->pm_prog) &&
207 xdr_rpcvers(xdrs, ®s->pm_vers) &&
208 xdr_rpcprot(xdrs, ®s->pm_prot))
209 return (xdr_rpcprot(xdrs, ®s->pm_port));
210 return (FALSE);
211 }
212
213 bool_t
xdr_rpcb(XDR * xdrs,RPCB * objp)214 xdr_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 */
233 bool_t
xdr_rmtcall_args(XDR * xdrs,struct rmtcallargs * cap)234 xdr_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 */
262 bool_t
xdr_rmtcallres(XDR * xdrs,struct rmtcallres * crp)263 xdr_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 */
280 bool_t
xdr_rpcb_rmtcallargs(XDR * xdrs,struct rpcb_rmtcallargs * objp)281 xdr_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 */
313 bool_t
xdr_rpcb_rmtcallres(XDR * xdrs,struct rpcb_rmtcallres * objp)314 xdr_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*/
331 enum clnt_stat
bpmap_rmtcall(rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,xdrproc_t in_xdr,caddr_t args,xdrproc_t out_xdr,caddr_t ret,int rexmit,int wait,struct sockaddr_in * to,struct sockaddr_in * from,uint_t auth)332 bpmap_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 */
422 rpcport_t
bpmap_getport(rpcprog_t prog,rpcvers_t vers,enum clnt_stat * rpc_stat,struct sockaddr_in * to,struct sockaddr_in * from)423 bpmap_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 */
517 void
bpmap_memfree(void)518 bpmap_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