source: rtems-libbsd/freebsd/lib/libc/rpc/rpcb_clnt.c @ 338f300

5-freebsd-12
Last change on this file since 338f300 was 338f300, checked in by Christian Mauderer <christian.mauderer@…>, on Apr 25, 2018 at 2:28:00 PM

buildset: Add minimal and everything config.

This adds two new buildset configurations: One that leaves out as much
features as possible and one that enables all features. For the default
configuration WiFi? support is now disabled.

To disable IPv6 for the minimal configuration, all -DINET6 are
eliminated in libbsd.py. They are now replaced by a #ifdef that checks
for RTEMS_BSD_MODULE_NETINET6 instead.

Close #3351.

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