source: rtems-libbsd/freebsd/lib/libc/rpc/rpcb_clnt.c @ 60b1d40

5-freebsd-12freebsd-9.3
Last change on this file since 60b1d40 was 60b1d40, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 9, 2016 at 8:23:57 AM

RPC(3): Import from FreeBSD

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