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

5-freebsd-12
Last change on this file since c40e45b was c40e45b, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 7, 2016 at 1:10:20 PM

Update to FreeBSD head 2016-08-23

Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.

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