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 /*
24 * Copyright (c) 2014 Gary Mills
25 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31 /*
32 * Portions of this source code were derived from Berkeley
33 * 4.3 BSD under license from the Regents of the University of
34 * California.
35 */
36
37 /*
38 * interface to rpcbind rpc service.
39 */
40
41 #include "mt.h"
42 #include "rpc_mt.h"
43 #include <assert.h>
44 #include <rpc/rpc.h>
45 #include <rpc/rpcb_prot.h>
46 #include <netconfig.h>
47 #include <netdir.h>
48 #include <rpc/nettype.h>
49 #include <syslog.h>
50 #ifdef PORTMAP
51 #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
52 #include <rpc/pmap_prot.h>
53 #endif
54 #ifdef ND_DEBUG
55 #include <stdio.h>
56 #endif
57 #include <sys/utsname.h>
58 #include <errno.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62
63 static struct timeval tottimeout = { 60, 0 };
64 static const struct timeval rmttimeout = { 3, 0 };
65 static struct timeval rpcbrmttime = { 15, 0 };
66
67 extern bool_t xdr_wrapstring(XDR *, char **);
68
69 static const char nullstring[] = "\000";
70
71 extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *,
72 struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t,
73 const struct timeval *);
74
75 static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **,
76 struct timeval *);
77
78
79 /*
80 * The life time of a cached entry should not exceed 5 minutes
81 * since automountd attempts an unmount every 5 minutes.
82 * It is arbitrarily set a little lower (3 min = 180 sec)
83 * to reduce the time during which an entry is stale.
84 */
85 #define CACHE_TTL 180
86 #define CACHESIZE 6
87
88 struct address_cache {
89 char *ac_host;
90 char *ac_netid;
91 char *ac_uaddr;
92 struct netbuf *ac_taddr;
93 struct address_cache *ac_next;
94 time_t ac_maxtime;
95 };
96
97 static struct address_cache *front;
98 static int cachesize;
99
100 extern int lowvers;
101 extern int authdes_cachesz;
102 /*
103 * This routine adjusts the timeout used for calls to the remote rpcbind.
104 * Also, this routine can be used to set the use of portmapper version 2
105 * only when doing rpc_broadcasts
106 * These are private routines that may not be provided in future releases.
107 */
108 bool_t
109 __rpc_control(int request, void *info)
110 {
111 switch (request) {
112 case CLCR_GET_RPCB_TIMEOUT:
113 *(struct timeval *)info = tottimeout;
114 break;
115 case CLCR_SET_RPCB_TIMEOUT:
116 tottimeout = *(struct timeval *)info;
117 break;
118 case CLCR_GET_LOWVERS:
119 *(int *)info = lowvers;
120 break;
121 case CLCR_SET_LOWVERS:
122 lowvers = *(int *)info;
123 break;
124 case CLCR_GET_RPCB_RMTTIME:
125 *(struct timeval *)info = rpcbrmttime;
126 break;
127 case CLCR_SET_RPCB_RMTTIME:
128 rpcbrmttime = *(struct timeval *)info;
129 break;
130 case CLCR_GET_CRED_CACHE_SZ:
131 *(int *)info = authdes_cachesz;
132 break;
133 case CLCR_SET_CRED_CACHE_SZ:
134 authdes_cachesz = *(int *)info;
135 break;
136 default:
137 return (FALSE);
138 }
139 return (TRUE);
140 }
141
142 /*
143 * It might seem that a reader/writer lock would be more reasonable here.
144 * However because getclnthandle(), the only user of the cache functions,
145 * may do a delete_cache() operation if a check_cache() fails to return an
146 * address useful to clnt_tli_create(), we may as well use a mutex.
147 */
148 /*
149 * As it turns out, if the cache lock is *not* a reader/writer lock, we will
150 * block all clnt_create's if we are trying to connect to a host that's down,
151 * since the lock will be held all during that time.
152 */
153 extern rwlock_t rpcbaddr_cache_lock;
154
155 /*
156 * The routines check_cache(), add_cache(), delete_cache() manage the
157 * cache of rpcbind addresses for (host, netid).
158 */
159
160 static struct address_cache *
161 check_cache(char *host, char *netid)
162 {
163 struct address_cache *cptr;
164
165 /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
166
167 assert(RW_READ_HELD(&rpcbaddr_cache_lock));
168 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
169 if ((strcmp(cptr->ac_host, host) == 0) &&
170 (strcmp(cptr->ac_netid, netid) == 0) &&
171 (time(NULL) <= cptr->ac_maxtime)) {
172 #ifdef ND_DEBUG
173 fprintf(stderr, "Found cache entry for %s: %s\n",
174 host, netid);
175 #endif
176 return (cptr);
177 }
178 }
179 return (NULL);
180 }
181
182 static void
183 delete_cache(struct netbuf *addr)
184 {
185 struct address_cache *cptr, *prevptr = NULL;
186
187 /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
188 assert(RW_WRITE_HELD(&rpcbaddr_cache_lock));
189 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
190 if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
191 free(cptr->ac_host);
192 free(cptr->ac_netid);
193 free(cptr->ac_taddr->buf);
194 free(cptr->ac_taddr);
195 if (cptr->ac_uaddr)
196 free(cptr->ac_uaddr);
197 if (prevptr)
198 prevptr->ac_next = cptr->ac_next;
199 else
200 front = cptr->ac_next;
201 free(cptr);
202 cachesize--;
203 break;
204 }
205 prevptr = cptr;
206 }
207 }
208
209 static void
210 add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr)
211 {
212 struct address_cache *ad_cache, *cptr, *prevptr;
213
214 ad_cache = malloc(sizeof (struct address_cache));
215 if (!ad_cache) {
216 goto memerr;
217 }
218 ad_cache->ac_maxtime = time(NULL) + CACHE_TTL;
219 ad_cache->ac_host = strdup(host);
220 ad_cache->ac_netid = strdup(netid);
221 ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
222 ad_cache->ac_taddr = malloc(sizeof (struct netbuf));
223 if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
224 (uaddr && !ad_cache->ac_uaddr)) {
225 goto memerr1;
226 }
227
228 ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
229 ad_cache->ac_taddr->buf = malloc(taddr->len);
230 if (ad_cache->ac_taddr->buf == NULL) {
231 goto memerr1;
232 }
233
234 (void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
235 #ifdef ND_DEBUG
236 (void) fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
237 #endif
238
239 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
240
241 (void) rw_wrlock(&rpcbaddr_cache_lock);
242 if (cachesize < CACHESIZE) {
243 ad_cache->ac_next = front;
244 front = ad_cache;
245 cachesize++;
246 } else {
247 /* Free the last entry */
248 cptr = front;
249 prevptr = NULL;
250 while (cptr->ac_next) {
251 prevptr = cptr;
252 cptr = cptr->ac_next;
253 }
254
255 #ifdef ND_DEBUG
256 fprintf(stderr, "Deleted from cache: %s : %s\n",
257 cptr->ac_host, cptr->ac_netid);
258 #endif
259 free(cptr->ac_host);
260 free(cptr->ac_netid);
261 free(cptr->ac_taddr->buf);
262 free(cptr->ac_taddr);
263 if (cptr->ac_uaddr)
264 free(cptr->ac_uaddr);
265
266 if (prevptr) {
267 prevptr->ac_next = NULL;
268 ad_cache->ac_next = front;
269 front = ad_cache;
270 } else {
271 front = ad_cache;
272 ad_cache->ac_next = NULL;
273 }
274 free(cptr);
275 }
276 (void) rw_unlock(&rpcbaddr_cache_lock);
277 return;
278 memerr1:
279 if (ad_cache->ac_host)
280 free(ad_cache->ac_host);
281 if (ad_cache->ac_netid)
282 free(ad_cache->ac_netid);
283 if (ad_cache->ac_uaddr)
284 free(ad_cache->ac_uaddr);
285 if (ad_cache->ac_taddr)
286 free(ad_cache->ac_taddr);
287 free(ad_cache);
288 memerr:
289 syslog(LOG_ERR, "add_cache : out of memory.");
290 }
291
292 /*
293 * This routine will return a client handle that is connected to the
294 * rpcbind. Returns NULL on error and free's everything.
295 */
296 static CLIENT *
297 getclnthandle(char *host, struct netconfig *nconf, char **targaddr)
298 {
299 return (_getclnthandle_timed(host, nconf, targaddr, NULL));
300 }
301
302 /*
303 * Same as getclnthandle() except it takes an extra timeout argument.
304 * This is for bug 4049792: clnt_create_timed does not timeout.
305 *
306 * If tp is NULL, use default timeout to get a client handle.
307 */
308 static CLIENT *
309 _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr,
310 struct timeval *tp)
311 {
312 CLIENT *client = NULL;
313 struct netbuf *addr;
314 struct netbuf addr_to_delete;
315 struct nd_addrlist *nas;
316 struct nd_hostserv rpcbind_hs;
317 struct address_cache *ad_cache;
318 char *tmpaddr;
319 int neterr;
320 int j;
321
322 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
323
324 /* Get the address of the rpcbind. Check cache first */
325 addr_to_delete.len = 0;
326 (void) rw_rdlock(&rpcbaddr_cache_lock);
327 ad_cache = check_cache(host, nconf->nc_netid);
328 if (ad_cache != NULL) {
329 addr = ad_cache->ac_taddr;
330 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr,
331 RPCBPROG, RPCBVERS4, 0, 0, tp);
332 if (client != NULL) {
333 if (targaddr) {
334 /*
335 * case where a client handle is created
336 * without a targaddr and the handle is
337 * requested with a targaddr
338 */
339 if (ad_cache->ac_uaddr != NULL) {
340 *targaddr = strdup(ad_cache->ac_uaddr);
341 if (*targaddr == NULL) {
342 syslog(LOG_ERR,
343 "_getclnthandle_timed: strdup "
344 "failed.");
345 rpc_createerr.cf_stat =
346 RPC_SYSTEMERROR;
347 (void) rw_unlock(
348 &rpcbaddr_cache_lock);
349 return (NULL);
350 }
351 } else {
352 *targaddr = NULL;
353 }
354 }
355 (void) rw_unlock(&rpcbaddr_cache_lock);
356 return (client);
357 }
358 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
359 (void) rw_unlock(&rpcbaddr_cache_lock);
360 return (NULL);
361 }
362 addr_to_delete.len = addr->len;
363 addr_to_delete.buf = malloc(addr->len);
364 if (addr_to_delete.buf == NULL) {
365 addr_to_delete.len = 0;
366 } else {
367 (void) memcpy(addr_to_delete.buf, addr->buf, addr->len);
368 }
369 }
370 (void) rw_unlock(&rpcbaddr_cache_lock);
371 if (addr_to_delete.len != 0) {
372 /*
373 * Assume this may be due to cache data being
374 * outdated
375 */
376 (void) rw_wrlock(&rpcbaddr_cache_lock);
377 delete_cache(&addr_to_delete);
378 (void) rw_unlock(&rpcbaddr_cache_lock);
379 free(addr_to_delete.buf);
380 }
381 rpcbind_hs.h_host = host;
382 rpcbind_hs.h_serv = "rpcbind";
383 #ifdef ND_DEBUG
384 fprintf(stderr, "rpcbind client routines: diagnostics :\n");
385 fprintf(stderr, "\tGetting address for (%s, %s, %s) ... \n",
386 rpcbind_hs.h_host, rpcbind_hs.h_serv, nconf->nc_netid);
387 #endif
388
389 if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
390 if (neterr == ND_NOHOST)
391 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
392 else
393 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
394 return (NULL);
395 }
396 /* XXX nas should perhaps be cached for better performance */
397
398 for (j = 0; j < nas->n_cnt; j++) {
399 addr = &(nas->n_addrs[j]);
400 #ifdef ND_DEBUG
401 {
402 int i;
403 char *ua;
404
405 ua = taddr2uaddr(nconf, &(nas->n_addrs[j]));
406 fprintf(stderr, "Got it [%s]\n", ua);
407 free(ua);
408
409 fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
410 addr->len, addr->maxlen);
411 fprintf(stderr, "\tAddress is ");
412 for (i = 0; i < addr->len; i++)
413 fprintf(stderr, "%u.", addr->buf[i]);
414 fprintf(stderr, "\n");
415 }
416 #endif
417 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
418 RPCBVERS4, 0, 0, tp);
419 if (client)
420 break;
421 }
422 #ifdef ND_DEBUG
423 if (!client) {
424 clnt_pcreateerror("rpcbind clnt interface");
425 }
426 #endif
427
428 if (client) {
429 tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
430 add_cache(host, nconf->nc_netid, addr, tmpaddr);
431 if (targaddr) {
432 *targaddr = tmpaddr;
433 }
434 }
435 netdir_free((char *)nas, ND_ADDRLIST);
436 return (client);
437 }
438
439 /*
440 * This routine will return a client handle that is connected to the local
441 * rpcbind. Returns NULL on error and free's everything.
442 */
443 static CLIENT *
444 local_rpcb(void)
445 {
446 static struct netconfig *loopnconf;
447 static char *hostname;
448 extern mutex_t loopnconf_lock;
449
450 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
451 (void) mutex_lock(&loopnconf_lock);
452 if (loopnconf == NULL) {
453 struct utsname utsname;
454 struct netconfig *nconf, *tmpnconf = NULL;
455 void *nc_handle;
456
457 if (hostname == NULL) {
458 #if defined(__i386) && !defined(__amd64)
459 if ((_nuname(&utsname) == -1) ||
460 ((hostname = strdup(utsname.nodename)) == NULL)) {
461 #else
462 if ((uname(&utsname) == -1) ||
463 ((hostname = strdup(utsname.nodename)) == NULL)) {
464 #endif
465 syslog(LOG_ERR, "local_rpcb : strdup failed.");
466 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
467 (void) mutex_unlock(&loopnconf_lock);
468 return (NULL);
469 }
470 }
471 nc_handle = setnetconfig();
472 if (nc_handle == NULL) {
473 /* fails to open netconfig file */
474 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
475 (void) mutex_unlock(&loopnconf_lock);
476 return (NULL);
477 }
478 while (nconf = getnetconfig(nc_handle)) {
479 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
480 tmpnconf = nconf;
481 if (nconf->nc_semantics == NC_TPI_CLTS)
482 break;
483 }
484 }
485 if (tmpnconf == NULL) {
486 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
487 (void) mutex_unlock(&loopnconf_lock);
488 return (NULL);
489 }
490 loopnconf = getnetconfigent(tmpnconf->nc_netid);
491 /* loopnconf is never freed */
492 (void) endnetconfig(nc_handle);
493 }
494 (void) mutex_unlock(&loopnconf_lock);
495 return (getclnthandle(hostname, loopnconf, NULL));
496 }
497
498 /*
499 * Set a mapping between program, version and address.
500 * Calls the rpcbind service to do the mapping.
501 */
502 bool_t
503 rpcb_set(const rpcprog_t program, const rpcvers_t version,
504 const struct netconfig *nconf, const struct netbuf *address)
505 {
506 CLIENT *client;
507 bool_t rslt = FALSE;
508 RPCB parms;
509 char uidbuf[32];
510
511 /* parameter checking */
512 if (nconf == NULL) {
513 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
514 return (FALSE);
515 }
516 if (address == NULL) {
517 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
518 return (FALSE);
519 }
520 client = local_rpcb();
521 if (!client)
522 return (FALSE);
523
524 parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
525 (struct netbuf *)address); /* convert to universal */
526 if (!parms.r_addr) {
527 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
528 return (FALSE); /* no universal address */
529 }
530 parms.r_prog = program;
531 parms.r_vers = version;
532 parms.r_netid = nconf->nc_netid;
533 /*
534 * Though uid is not being used directly, we still send it for
535 * completeness. For non-unix platforms, perhaps some other
536 * string or an empty string can be sent.
537 */
538 (void) sprintf(uidbuf, "%d", (int)geteuid());
539 parms.r_owner = uidbuf;
540
541 CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
542 (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
543
544 CLNT_DESTROY(client);
545 free(parms.r_addr);
546 return (rslt);
547 }
548
549 /*
550 * Remove the mapping between program, version and netbuf address.
551 * Calls the rpcbind service to do the un-mapping.
552 * If netbuf is NULL, unset for all the transports, otherwise unset
553 * only for the given transport.
554 */
555 bool_t
556 rpcb_unset(const rpcprog_t program, const rpcvers_t version,
557 const struct netconfig *nconf)
558 {
559 CLIENT *client;
560 bool_t rslt = FALSE;
561 RPCB parms;
562 char uidbuf[32];
563
564 client = local_rpcb();
565 if (!client)
566 return (FALSE);
567
568 parms.r_prog = program;
569 parms.r_vers = version;
570 if (nconf)
571 parms.r_netid = nconf->nc_netid;
572 else
573 parms.r_netid = (char *)&nullstring[0]; /* unsets all */
574 parms.r_addr = (char *)&nullstring[0];
575 (void) sprintf(uidbuf, "%d", (int)geteuid());
576 parms.r_owner = uidbuf;
577
578 CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
579 (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
580
581 CLNT_DESTROY(client);
582 return (rslt);
583 }
584
585 /*
586 * From the merged list, find the appropriate entry
587 */
588 static struct netbuf *
589 got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf)
590 {
591 struct netbuf *na = NULL;
592 rpcb_entry_list_ptr sp;
593 rpcb_entry *rmap;
594
595 for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
596 rmap = &sp->rpcb_entry_map;
597 if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
598 (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
599 (nconf->nc_semantics == rmap->r_nc_semantics) &&
600 (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
601 na = uaddr2taddr(nconf, rmap->r_maddr);
602 #ifdef ND_DEBUG
603 fprintf(stderr, "\tRemote address is [%s].\n",
604 rmap->r_maddr);
605 if (!na)
606 fprintf(stderr,
607 "\tCouldn't resolve remote address!\n");
608 #endif
609 break;
610 }
611 }
612 return (na);
613 }
614
615 /*
616 * Quick check to see if rpcbind is up. Tries to connect over
617 * local transport.
618 */
619 bool_t
620 __rpcbind_is_up(void)
621 {
622 struct utsname name;
623 char uaddr[SYS_NMLN];
624 struct netbuf *addr;
625 int fd;
626 struct t_call *sndcall;
627 struct netconfig *netconf;
628 bool_t res;
629
630 #if defined(__i386) && !defined(__amd64)
631 if (_nuname(&name) == -1)
632 #else
633 if (uname(&name) == -1)
634 #endif
635 return (TRUE);
636
637 if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
638 return (TRUE);
639
640 if (t_bind(fd, NULL, NULL) == -1) {
641 (void) t_close(fd);
642 return (TRUE);
643 }
644
645 /* LINTED pointer cast */
646 if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) {
647 (void) t_close(fd);
648 return (TRUE);
649 }
650
651 uaddr[0] = '\0';
652 (void) strcpy(uaddr, name.nodename);
653 (void) strcat(uaddr, ".rpc");
654 if ((netconf = getnetconfigent("ticotsord")) == NULL) {
655 (void) t_free((char *)sndcall, T_CALL);
656 (void) t_close(fd);
657 return (FALSE);
658 }
659 addr = uaddr2taddr(netconf, uaddr);
660 freenetconfigent(netconf);
661 if (addr == NULL || addr->buf == NULL) {
662 if (addr)
663 free(addr);
664 (void) t_free((char *)sndcall, T_CALL);
665 (void) t_close(fd);
666 return (FALSE);
667 }
668 sndcall->addr.maxlen = addr->maxlen;
669 sndcall->addr.len = addr->len;
670 sndcall->addr.buf = addr->buf;
671
672 if (t_connect(fd, sndcall, NULL) == -1)
673 res = FALSE;
674 else
675 res = TRUE;
676
677 sndcall->addr.maxlen = sndcall->addr.len = 0;
678 sndcall->addr.buf = NULL;
679 (void) t_free((char *)sndcall, T_CALL);
680 free(addr->buf);
681 free(addr);
682 (void) t_close(fd);
683
684 return (res);
685 }
686
687
688 /*
689 * An internal function which optimizes rpcb_getaddr function. It returns
690 * the universal address of the remote service or NULL. It also optionally
691 * returns the client handle that it uses to contact the remote rpcbind.
692 *
693 * The algorithm used: First try version 4. Then try version 3 (svr4).
694 * Finally, if the transport is TCP or UDP, try version 2 (portmap).
695 * We assume that version 4 is now available on many machines on the network.
696 * With this algorithm, we get performance as well as a plan for
697 * obsoleting version 2.
698 *
699 * XXX: Due to some problems with t_connect(), we do not reuse the same client
700 * handle for COTS cases and hence in these cases we do not return the
701 * client handle. This code will change if t_connect() ever
702 * starts working properly. Also look under clnt_vc.c.
703 */
704 struct netbuf *
705 __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
706 struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp)
707 {
708 static bool_t check_rpcbind = TRUE;
709 CLIENT *client = NULL;
710 RPCB parms;
711 enum clnt_stat clnt_st;
712 char *ua = NULL;
713 uint_t vers;
714 struct netbuf *address = NULL;
715 void *handle;
716 rpcb_entry_list_ptr relp = NULL;
717 bool_t tmp_client = FALSE;
718
719 /* parameter checking */
720 if (nconf == NULL) {
721 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
722 return (NULL);
723 }
724
725 parms.r_addr = NULL;
726
727 /*
728 * Use default total timeout if no timeout is specified.
729 */
730 if (tp == NULL)
731 tp = &tottimeout;
732
733 /*
734 * Check if rpcbind is up. This prevents needless delays when
735 * accessing applications such as the keyserver while booting
736 * disklessly.
737 */
738 if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
739 if (!__rpcbind_is_up()) {
740 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
741 rpc_createerr.cf_error.re_errno = 0;
742 rpc_createerr.cf_error.re_terrno = 0;
743 goto error;
744 }
745 check_rpcbind = FALSE;
746 }
747
748 /*
749 * First try version 4.
750 */
751 parms.r_prog = program;
752 parms.r_vers = version;
753 parms.r_owner = (char *)&nullstring[0]; /* not needed; */
754 /* just for xdring */
755 parms.r_netid = nconf->nc_netid; /* not really needed */
756
757 /*
758 * If a COTS transport is being used, try getting address via CLTS
759 * transport. This works only with version 4.
760 */
761 if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
762 nconf->nc_semantics == NC_TPI_COTS) {
763 handle = __rpc_setconf("datagram_v");
764 } else {
765 handle = __rpc_setconf(nconf->nc_proto);
766 }
767
768 if (handle != NULL) {
769 struct netconfig *nconf_clts;
770
771 while ((nconf_clts = __rpc_getconf(handle))
772 != NULL) {
773 if (strcmp(nconf_clts->nc_protofmly,
774 nconf->nc_protofmly) != 0) {
775 continue;
776 }
777 client = _getclnthandle_timed(host,
778 nconf_clts, &parms.r_addr,
779 tp);
780 break;
781 }
782 __rpc_endconf(handle);
783 }
784 if (client != NULL) {
785
786 if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
787 nconf->nc_semantics == NC_TPI_COTS)
788 tmp_client = TRUE;
789
790 /* Set rpcbind version 4 */
791 vers = RPCBVERS4;
792 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
793
794 /*
795 * We also send the remote system the address we used to
796 * contact it in case it can help it connect back with us
797 */
798 if (parms.r_addr == NULL) {
799 parms.r_addr = strdup(""); /* for XDRing */
800 if (parms.r_addr == NULL) {
801 syslog(LOG_ERR, "__rpcb_findaddr_timed: "
802 "strdup failed.");
803 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
804 address = NULL;
805 goto error;
806 }
807 }
808
809 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
810 (char *)&rpcbrmttime);
811
812 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
813 (xdrproc_t)xdr_rpcb, (char *)&parms,
814 (xdrproc_t)xdr_rpcb_entry_list_ptr,
815 (char *)&relp, *tp);
816 switch (clnt_st) {
817 case RPC_SUCCESS:
818 if (address = got_entry(relp, nconf)) {
819 xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
820 (char *)&relp);
821 goto done;
822 }
823 /* Entry not found for this transport */
824 xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
825 (char *)&relp);
826 /*
827 * XXX: should have perhaps returned with error but
828 * since the remote machine might not always be able
829 * to send the address on all transports, we try the
830 * regular way with version 3, then 2
831 */
832 /* Try the next version */
833 break;
834 case RPC_PROGVERSMISMATCH:
835 case RPC_PROGUNAVAIL:
836 /* Try the next version */
837 break;
838 default:
839 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
840 clnt_geterr(client, &rpc_createerr.cf_error);
841 goto error;
842 break;
843 }
844 } /* End of version 4 */
845
846 /*
847 * Try version 3
848 */
849
850 /* Now the same transport is to be used to get the address */
851 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
852 (nconf->nc_semantics == NC_TPI_COTS))) {
853 /* A CLTS type of client - destroy it */
854 CLNT_DESTROY(client);
855 client = NULL;
856 free(parms.r_addr);
857 parms.r_addr = NULL;
858 }
859
860 if (client == NULL) {
861 client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
862 }
863 if (client != NULL) {
864 tmp_client = FALSE;
865 if (parms.r_addr == NULL) {
866 parms.r_addr = strdup(""); /* for XDRing */
867 if (parms.r_addr == NULL) {
868 syslog(LOG_ERR, "__rpcb_findaddr_timed: "
869 "strdup failed.");
870 address = NULL;
871 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
872 goto error;
873 }
874 }
875
876 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
877 (char *)&rpcbrmttime);
878 vers = RPCBVERS; /* Set the version */
879 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
880 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
881 (xdrproc_t)xdr_rpcb, (char *)&parms,
882 (xdrproc_t)xdr_wrapstring,
883 (char *)&ua, *tp);
884 switch (clnt_st) {
885 case RPC_SUCCESS:
886 if ((ua != NULL) && (ua[0] != '\0')) {
887 address = uaddr2taddr(nconf, ua);
888 #ifdef ND_DEBUG
889 fprintf(stderr, "\tRemote address is [%s]\n",
890 ua);
891 #endif
892 xdr_free((xdrproc_t)xdr_wrapstring,
893 (char *)&ua);
894 } else if (ua != NULL) {
895 xdr_free(xdr_wrapstring, (char *)&ua);
896 }
897
898 if (ua != NULL && address != NULL) {
899 goto done;
900 } else if (address == NULL) {
901 /* We don't know about your universal addr */
902 #ifdef ND_DEBUG
903 fprintf(stderr,
904 "\tCouldn't resolve remote address!\n");
905 #endif
906 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
907 goto error;
908 }
909 /* Try the next version */
910 break;
911 case RPC_PROGVERSMISMATCH:
912 clnt_geterr(client, &rpc_createerr.cf_error);
913 if (rpc_createerr.cf_error.re_vers.low > RPCBVERS4)
914 goto error; /* a new version, can't handle */
915 /* Try the next version */
916 break;
917 case RPC_PROGUNAVAIL:
918 /* Try the next version */
919 break;
920 default:
921 clnt_geterr(client, &rpc_createerr.cf_error);
922 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
923 goto error;
924 break;
925 }
926 } else {
927 address = NULL;
928 } /* End of version 3 */
929
930 /*
931 * Try version 2
932 */
933
934 #ifdef PORTMAP
935 /* Try version 2 for TCP or UDP */
936 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
937 ushort_t port = 0;
938 struct netbuf remote;
939 uint_t pmapvers = 2;
940 struct pmap pmapparms;
941
942 /*
943 * Try UDP only - there are some portmappers out
944 * there that use UDP only.
945 */
946 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
947 struct netconfig *newnconf;
948
949 if (client) {
950 CLNT_DESTROY(client);
951 client = NULL;
952 free(parms.r_addr);
953 parms.r_addr = NULL;
954 }
955 if ((handle = __rpc_setconf("udp")) == NULL) {
956 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
957 return (NULL);
958 }
959
960 /*
961 * The following to reinforce that you can
962 * only request for remote address through
963 * the same transport you are requesting.
964 * ie. requesting unversial address
965 * of IPv4 has to be carried through IPv4.
966 * Can't use IPv6 to send out the request.
967 * The mergeaddr in rpcbind can't handle
968 * this.
969 */
970 for (;;) {
971 if ((newnconf = __rpc_getconf(handle))
972 == NULL) {
973 __rpc_endconf(handle);
974 rpc_createerr.cf_stat =
975 RPC_UNKNOWNPROTO;
976 return (NULL);
977 }
978 /*
979 * here check the protocol family to
980 * be consistent with the request one
981 */
982 if (strcmp(newnconf->nc_protofmly,
983 nconf->nc_protofmly) == NULL)
984 break;
985 }
986
987 client = _getclnthandle_timed(host, newnconf,
988 &parms.r_addr, tp);
989 __rpc_endconf(handle);
990 }
991 if (client == NULL)
992 return (NULL);
993
994 if (strcmp(nconf->nc_proto, NC_TCP) == 0)
995 tmp_client = TRUE;
996
997 /*
998 * Set version and retry timeout.
999 */
1000 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
1001 CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
1002
1003 pmapparms.pm_prog = program;
1004 pmapparms.pm_vers = version;
1005 pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
1006 IPPROTO_UDP : IPPROTO_TCP;
1007 pmapparms.pm_port = 0; /* not needed */
1008 clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
1009 (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
1010 (xdrproc_t)xdr_u_short, (caddr_t)&port,
1011 *tp);
1012 if (clnt_st != RPC_SUCCESS) {
1013 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
1014 clnt_geterr(client, &rpc_createerr.cf_error);
1015 goto error;
1016 } else if (port == 0) {
1017 address = NULL;
1018 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1019 goto error;
1020 }
1021 port = htons(port);
1022 CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
1023 if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
1024 ((address->buf = malloc(remote.len)) == NULL)) {
1025 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1026 clnt_geterr(client, &rpc_createerr.cf_error);
1027 if (address) {
1028 free(address);
1029 address = NULL;
1030 }
1031 goto error;
1032 }
1033 (void) memcpy(address->buf, remote.buf, remote.len);
1034 (void) memcpy(&address->buf[sizeof (short)], &port,
1035 sizeof (short));
1036 address->len = address->maxlen = remote.len;
1037 goto done;
1038 }
1039 #endif
1040
1041 error:
1042 /* Return NULL address and NULL client */
1043 if (client) {
1044 CLNT_DESTROY(client);
1045 client = NULL;
1046 }
1047
1048 done:
1049 /* Return an address and optional client */
1050 if (tmp_client) {
1051 /* This client is the temporary one */
1052 if (client) {
1053 CLNT_DESTROY(client);
1054 client = NULL;
1055 }
1056 }
1057 if (clpp) {
1058 *clpp = client;
1059 } else if (client) {
1060 CLNT_DESTROY(client);
1061 }
1062 if (parms.r_addr)
1063 free(parms.r_addr);
1064 return (address);
1065 }
1066
1067
1068 /*
1069 * Find the mapped address for program, version.
1070 * Calls the rpcbind service remotely to do the lookup.
1071 * Uses the transport specified in nconf.
1072 * Returns FALSE (0) if no map exists, else returns 1.
1073 *
1074 * Assuming that the address is all properly allocated
1075 */
1076 int
1077 rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
1078 const struct netconfig *nconf, struct netbuf *address, const char *host)
1079 {
1080 struct netbuf *na;
1081
1082 if ((na = __rpcb_findaddr_timed(program, version,
1083 (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL)
1084 return (FALSE);
1085
1086 if (na->len > address->maxlen) {
1087 /* Too long address */
1088 netdir_free((char *)na, ND_ADDR);
1089 rpc_createerr.cf_stat = RPC_FAILED;
1090 return (FALSE);
1091 }
1092 (void) memcpy(address->buf, na->buf, (int)na->len);
1093 address->len = na->len;
1094 netdir_free((char *)na, ND_ADDR);
1095 return (TRUE);
1096 }
1097
1098 /*
1099 * Get a copy of the current maps.
1100 * Calls the rpcbind service remotely to get the maps.
1101 *
1102 * It returns only a list of the services
1103 * It returns NULL on failure.
1104 */
1105 rpcblist *
1106 rpcb_getmaps(const struct netconfig *nconf, const char *host)
1107 {
1108 rpcblist_ptr head = NULL;
1109 CLIENT *client;
1110 enum clnt_stat clnt_st;
1111 int vers = 0;
1112
1113 client = getclnthandle((char *)host,
1114 (struct netconfig *)nconf, NULL);
1115 if (client == NULL)
1116 return (NULL);
1117
1118 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
1119 (xdrproc_t)xdr_void, NULL,
1120 (xdrproc_t)xdr_rpcblist_ptr,
1121 (char *)&head, tottimeout);
1122 if (clnt_st == RPC_SUCCESS)
1123 goto done;
1124
1125 if ((clnt_st != RPC_PROGVERSMISMATCH) &&
1126 (clnt_st != RPC_PROGUNAVAIL)) {
1127 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1128 clnt_geterr(client, &rpc_createerr.cf_error);
1129 goto done;
1130 }
1131
1132 /* fall back to earlier version */
1133 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1134 if (vers == RPCBVERS4) {
1135 vers = RPCBVERS;
1136 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1137 if (CLNT_CALL(client, RPCBPROC_DUMP,
1138 (xdrproc_t)xdr_void,
1139 NULL, (xdrproc_t)xdr_rpcblist_ptr,
1140 (char *)&head, tottimeout) == RPC_SUCCESS)
1141 goto done;
1142 }
1143 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1144 clnt_geterr(client, &rpc_createerr.cf_error);
1145
1146 done:
1147 CLNT_DESTROY(client);
1148 return (head);
1149 }
1150
1151 /*
1152 * rpcbinder remote-call-service interface.
1153 * This routine is used to call the rpcbind remote call service
1154 * which will look up a service program in the address maps, and then
1155 * remotely call that routine with the given parameters. This allows
1156 * programs to do a lookup and call in one step.
1157 */
1158 enum clnt_stat
1159 rpcb_rmtcall(const struct netconfig *nconf, const char *host,
1160 const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc,
1161 const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres,
1162 const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr)
1163 {
1164 CLIENT *client;
1165 enum clnt_stat stat;
1166 struct r_rpcb_rmtcallargs a;
1167 struct r_rpcb_rmtcallres r;
1168 int rpcb_vers;
1169
1170 client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL);
1171 if (client == NULL)
1172 return (RPC_FAILED);
1173 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout);
1174 a.prog = prog;
1175 a.vers = vers;
1176 a.proc = proc;
1177 a.args.args_val = argsp;
1178 a.xdr_args = xdrargs;
1179 r.addr = NULL;
1180 r.results.results_val = resp;
1181 r.xdr_res = xdrres;
1182
1183 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
1184 CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers);
1185 stat = CLNT_CALL(client, RPCBPROC_CALLIT,
1186 (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
1187 (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
1188 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
1189 struct netbuf *na;
1190
1191 na = uaddr2taddr((struct netconfig *)nconf, r.addr);
1192 if (!na) {
1193 stat = RPC_N2AXLATEFAILURE;
1194 ((struct netbuf *)addr_ptr)->len = 0;
1195 goto error;
1196 }
1197 if (na->len > addr_ptr->maxlen) {
1198 /* Too long address */
1199 stat = RPC_FAILED; /* XXX A better error no */
1200 netdir_free((char *)na, ND_ADDR);
1201 ((struct netbuf *)addr_ptr)->len = 0;
1202 goto error;
1203 }
1204 (void) memcpy(addr_ptr->buf, na->buf, (int)na->len);
1205 ((struct netbuf *)addr_ptr)->len = na->len;
1206 netdir_free((char *)na, ND_ADDR);
1207 break;
1208 }
1209 if ((stat != RPC_PROGVERSMISMATCH) &&
1210 (stat != RPC_PROGUNAVAIL))
1211 goto error;
1212 }
1213 error:
1214 CLNT_DESTROY(client);
1215 if (r.addr)
1216 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr);
1217 return (stat);
1218 }
1219
1220 /*
1221 * Gets the time on the remote host.
1222 * Returns 1 if succeeds else 0.
1223 */
1224 bool_t
1225 rpcb_gettime(const char *host, time_t *timep)
1226 {
1227 CLIENT *client = NULL;
1228 void *handle;
1229 struct netconfig *nconf;
1230 int vers;
1231 enum clnt_stat st;
1232
1233 if ((host == NULL) || (host[0] == NULL)) {
1234 (void) time(timep);
1235 return (TRUE);
1236 }
1237
1238 if ((handle = __rpc_setconf("netpath")) == NULL) {
1239 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1240 return (FALSE);
1241 }
1242 rpc_createerr.cf_stat = RPC_SUCCESS;
1243 while (client == NULL) {
1244 if ((nconf = __rpc_getconf(handle)) == NULL) {
1245 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1246 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1247 break;
1248 }
1249 client = getclnthandle((char *)host, nconf, NULL);
1250 if (client)
1251 break;
1252 }
1253 __rpc_endconf(handle);
1254 if (client == NULL)
1255 return (FALSE);
1256
1257 st = CLNT_CALL(client, RPCBPROC_GETTIME,
1258 (xdrproc_t)xdr_void, NULL,
1259 (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
1260
1261 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
1262 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1263 if (vers == RPCBVERS4) {
1264 /* fall back to earlier version */
1265 vers = RPCBVERS;
1266 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1267 st = CLNT_CALL(client, RPCBPROC_GETTIME,
1268 (xdrproc_t)xdr_void, NULL,
1269 (xdrproc_t)xdr_time_t, (char *)timep,
1270 tottimeout);
1271 }
1272 }
1273 CLNT_DESTROY(client);
1274 return (st == RPC_SUCCESS? TRUE : FALSE);
1275 }
1276
1277 /*
1278 * Converts taddr to universal address. This routine should never
1279 * really be called because local n2a libraries are always provided.
1280 */
1281 char *
1282 rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
1283 {
1284 CLIENT *client;
1285 char *uaddr = NULL;
1286
1287 /* parameter checking */
1288 if (nconf == NULL) {
1289 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1290 return (NULL);
1291 }
1292 if (taddr == NULL) {
1293 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1294 return (NULL);
1295 }
1296 client = local_rpcb();
1297 if (!client)
1298 return (NULL);
1299
1300 CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf,
1301 (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
1302 tottimeout);
1303 CLNT_DESTROY(client);
1304 return (uaddr);
1305 }
1306
1307 /*
1308 * Converts universal address to netbuf. This routine should never
1309 * really be called because local n2a libraries are always provided.
1310 */
1311 struct netbuf *
1312 rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
1313 {
1314 CLIENT *client;
1315 struct netbuf *taddr;
1316
1317 /* parameter checking */
1318 if (nconf == NULL) {
1319 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1320 return (NULL);
1321 }
1322 if (uaddr == NULL) {
1323 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1324 return (NULL);
1325 }
1326 client = local_rpcb();
1327 if (!client)
1328 return (NULL);
1329
1330 taddr = calloc(1, sizeof (struct netbuf));
1331 if (taddr == NULL) {
1332 CLNT_DESTROY(client);
1333 return (NULL);
1334 }
1335
1336 if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring,
1337 (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
1338 tottimeout) != RPC_SUCCESS) {
1339 free(taddr);
1340 taddr = NULL;
1341 }
1342 CLNT_DESTROY(client);
1343 return (taddr);
1344 }