]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/rpc/getrpcent.c
MFV r361280:
[FreeBSD/FreeBSD.git] / lib / libc / rpc / getrpcent.c
1 /*      $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $   */
2
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (c) 2009, Sun Microsystems, 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 Sun Microsystems, 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 #if defined(LIBC_SCCS) && !defined(lint)
34 static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";
35 #endif
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40  * Copyright (c) 1984 by Sun Microsystems, Inc.
41  */
42
43 #include <sys/param.h>
44 #include <sys/socket.h>
45 #include <arpa/inet.h>
46 #include <assert.h>
47 #include <errno.h>
48 #include <nsswitch.h>
49 #include <netinet/in.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <stdlib.h>
54 #include <rpc/rpc.h>
55 #ifdef YP
56 #include <rpcsvc/yp_prot.h>
57 #include <rpcsvc/ypclnt.h>
58 #endif
59 #include <unistd.h>
60 #include "namespace.h"
61 #include "reentrant.h"
62 #include "un-namespace.h"
63 #include "libc_private.h"
64 #include "nss_tls.h"
65 #ifdef NS_CACHING
66 #include "nscache.h"
67 #endif
68
69 #define RPCDB   "/etc/rpc"
70
71 /* nsswitch declarations */
72 enum constants
73 {
74         SETRPCENT = 1,
75         ENDRPCENT = 2,
76         RPCENT_STORAGE_INITIAL  = 1 << 10, /* 1 KByte */
77         RPCENT_STORAGE_MAX      = 1 << 20, /* 1 MByte */
78 };
79
80 static const ns_src defaultsrc[] = {
81         { NSSRC_FILES, NS_SUCCESS },
82 #ifdef YP
83         { NSSRC_NIS, NS_SUCCESS },
84 #endif
85         { NULL, 0 }
86 };
87
88 /* files backend declarations */
89 struct files_state {
90         FILE    *fp;
91         int     stayopen;
92 };
93
94 static  int     files_rpcent(void *, void *, va_list);
95 static  int     files_setrpcent(void *, void *, va_list);
96
97 static  void    files_endstate(void *);
98 NSS_TLS_HANDLING(files);
99
100 /* nis backend declarations */
101 #ifdef YP
102 struct nis_state {
103         char    domain[MAXHOSTNAMELEN];
104         char    *current;
105         int     currentlen;
106         int     stepping;
107         int     no_name_map;
108 };
109
110 static  int     nis_rpcent(void *, void *, va_list);
111 static  int     nis_setrpcent(void *, void *, va_list);
112
113 static  void    nis_endstate(void *);
114 NSS_TLS_HANDLING(nis);
115 #endif
116
117 /* get** wrappers for get**_r functions declarations */
118 struct rpcent_state {
119         struct rpcent   rpc;
120         char            *buffer;
121         size_t  bufsize;
122 };
123 static  void    rpcent_endstate(void *);
124 NSS_TLS_HANDLING(rpcent);
125
126 union key {
127         const char      *name;
128         int             number;
129 };
130
131 static int wrap_getrpcbyname_r(union key, struct rpcent *, char *,
132                         size_t, struct rpcent **);
133 static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *,
134                         size_t, struct rpcent **);
135 static int wrap_getrpcent_r(union key, struct rpcent *, char *,
136                         size_t, struct rpcent **);
137 static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *,
138                         size_t, struct rpcent **), union key);
139
140 #ifdef NS_CACHING
141 static int rpc_id_func(char *, size_t *, va_list, void *);
142 static int rpc_marshal_func(char *, size_t *, void *, va_list, void *);
143 static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *);
144 #endif
145
146 static int
147 rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases,
148         size_t aliases_size, int *errnop)
149 {
150         char *cp, **q;
151
152         assert(p != NULL);
153
154         if (*p == '#')
155                 return (-1);
156         cp = strpbrk(p, "#\n");
157         if (cp == NULL)
158                 return (-1);
159         *cp = '\0';
160         cp = strpbrk(p, " \t");
161         if (cp == NULL)
162                 return (-1);
163         *cp++ = '\0';
164         /* THIS STUFF IS INTERNET SPECIFIC */
165         rpc->r_name = p;
166         while (*cp == ' ' || *cp == '\t')
167                 cp++;
168         rpc->r_number = atoi(cp);
169         q = rpc->r_aliases = r_aliases;
170         cp = strpbrk(cp, " \t");
171         if (cp != NULL)
172                 *cp++ = '\0';
173         while (cp && *cp) {
174                 if (*cp == ' ' || *cp == '\t') {
175                         cp++;
176                         continue;
177                 }
178                 if (q < &(r_aliases[aliases_size - 1]))
179                         *q++ = cp;
180                 else {
181                         *errnop = ERANGE;
182                         return -1;
183                 }
184
185                 cp = strpbrk(cp, " \t");
186                 if (cp != NULL)
187                         *cp++ = '\0';
188         }
189         *q = NULL;
190         return 0;
191 }
192
193 /* files backend implementation */
194 static  void
195 files_endstate(void *p)
196 {
197         FILE * f;
198
199         if (p == NULL)
200                 return;
201
202         f = ((struct files_state *)p)->fp;
203         if (f != NULL)
204                 fclose(f);
205
206         free(p);
207 }
208
209 static int
210 files_rpcent(void *retval, void *mdata, va_list ap)
211 {
212         char *name;
213         int number;
214         struct rpcent *rpc;
215         char *buffer;
216         size_t bufsize;
217         int *errnop;
218
219         char *line;
220         size_t linesize;
221         char **aliases;
222         int aliases_size;
223         char **rp;
224
225         struct files_state      *st;
226         int rv;
227         int stayopen;
228         enum nss_lookup_type how;
229
230         how = (enum nss_lookup_type)(uintptr_t)mdata;
231         switch (how)
232         {
233         case nss_lt_name:
234                 name = va_arg(ap, char *);
235                 break;
236         case nss_lt_id:
237                 number = va_arg(ap, int);
238                 break;
239         case nss_lt_all:
240                 break;
241         default:
242                 return (NS_NOTFOUND);
243         }
244
245         rpc = va_arg(ap, struct rpcent *);
246         buffer = va_arg(ap, char *);
247         bufsize = va_arg(ap, size_t);
248         errnop = va_arg(ap, int *);
249
250         *errnop = files_getstate(&st);
251         if (*errnop != 0)
252                 return (NS_UNAVAIL);
253
254         if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) {
255                 *errnop = errno;
256                 return (NS_UNAVAIL);
257         }
258
259         if (how == nss_lt_all)
260                 stayopen = 1;
261         else {
262                 rewind(st->fp);
263                 stayopen = st->stayopen;
264         }
265
266         do {
267                 if ((line = fgetln(st->fp, &linesize)) == NULL) {
268                         *errnop = errno;
269                         rv = NS_RETURN;
270                         break;
271                 }
272
273                 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
274                         *errnop = ERANGE;
275                         rv = NS_RETURN;
276                         break;
277                 }
278
279                 aliases = (char **)_ALIGN(&buffer[linesize+1]);
280                 aliases_size = (buffer + bufsize -
281                         (char *)aliases)/sizeof(char *);
282                 if (aliases_size < 1) {
283                         *errnop = ERANGE;
284                         rv = NS_RETURN;
285                         break;
286                 }
287
288                 memcpy(buffer, line, linesize);
289                 buffer[linesize] = '\0';
290
291                 rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop);
292                 if (rv != 0) {
293                         if (*errnop == 0) {
294                                 rv = NS_NOTFOUND;
295                                 continue;
296                         }
297                         else {
298                                 rv = NS_RETURN;
299                                 break;
300                         }
301                 }
302
303                 switch (how)
304                 {
305                 case nss_lt_name:
306                         if (strcmp(rpc->r_name, name) == 0)
307                                 goto done;
308                         for (rp = rpc->r_aliases; *rp != NULL; rp++) {
309                                 if (strcmp(*rp, name) == 0)
310                                         goto done;
311                         }
312                         rv = NS_NOTFOUND;
313                         continue;
314 done:
315                         rv = NS_SUCCESS;
316                         break;
317                 case nss_lt_id:
318                         rv = (rpc->r_number == number) ? NS_SUCCESS :
319                                 NS_NOTFOUND;
320                         break;
321                 case nss_lt_all:
322                         rv = NS_SUCCESS;
323                         break;
324                 }
325
326         } while (!(rv & NS_TERMINATE));
327
328         if (!stayopen && st->fp!=NULL) {
329                 fclose(st->fp);
330                 st->fp = NULL;
331         }
332
333         if ((rv == NS_SUCCESS) && (retval != NULL))
334                 *((struct rpcent **)retval) = rpc;
335
336         return (rv);
337 }
338
339 static int
340 files_setrpcent(void *retval, void *mdata, va_list ap)
341 {
342         struct files_state      *st;
343         int     rv;
344         int     f;
345
346         rv = files_getstate(&st);
347         if (rv != 0)
348                 return (NS_UNAVAIL);
349
350         switch ((enum constants)(uintptr_t)mdata)
351         {
352         case SETRPCENT:
353                 f = va_arg(ap,int);
354                 if (st->fp == NULL)
355                         st->fp = fopen(RPCDB, "r");
356                 else
357                         rewind(st->fp);
358                 st->stayopen |= f;
359                 break;
360         case ENDRPCENT:
361                 if (st->fp != NULL) {
362                         fclose(st->fp);
363                         st->fp = NULL;
364                 }
365                 st->stayopen = 0;
366                 break;
367         default:
368                 break;
369         }
370
371         return (NS_UNAVAIL);
372 }
373
374 /* nis backend implementation */
375 #ifdef YP
376 static  void
377 nis_endstate(void *p)
378 {
379         if (p == NULL)
380                 return;
381
382         free(((struct nis_state *)p)->current);
383         free(p);
384 }
385
386 static int
387 nis_rpcent(void *retval, void *mdata, va_list ap)
388 {
389         char            *name;
390         int             number;
391         struct rpcent   *rpc;
392         char            *buffer;
393         size_t  bufsize;
394         int             *errnop;
395
396         char            **rp;
397         char            **aliases;
398         int             aliases_size;
399
400         char    *lastkey;
401         char    *resultbuf;
402         int     resultbuflen;
403         char    *buf;
404
405         struct nis_state        *st;
406         int             rv;
407         enum nss_lookup_type    how;
408         int     no_name_active;
409
410         how = (enum nss_lookup_type)(uintptr_t)mdata;
411         switch (how)
412         {
413         case nss_lt_name:
414                 name = va_arg(ap, char *);
415                 break;
416         case nss_lt_id:
417                 number = va_arg(ap, int);
418                 break;
419         case nss_lt_all:
420                 break;
421         default:
422                 return (NS_NOTFOUND);
423         }
424
425         buf = NULL;
426         rpc = va_arg(ap, struct rpcent *);
427         buffer = va_arg(ap, char *);
428         bufsize = va_arg(ap, size_t);
429         errnop = va_arg(ap, int *);
430
431         *errnop = nis_getstate(&st);
432         if (*errnop != 0)
433                 return (NS_UNAVAIL);
434
435         if (st->domain[0] == '\0') {
436                 if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
437                         *errnop = errno;
438                         return (NS_UNAVAIL);
439                 }
440         }
441
442         no_name_active = 0;
443         do {
444                 switch (how)
445                 {
446                 case nss_lt_name:
447                         if (!st->no_name_map)
448                         {
449                                 free(buf);
450                                 asprintf(&buf, "%s", name);
451                                 if (buf == NULL)
452                                         return (NS_TRYAGAIN);
453                                 rv = yp_match(st->domain, "rpc.byname", buf,
454                                         strlen(buf), &resultbuf, &resultbuflen);
455
456                                 switch (rv) {
457                                 case 0:
458                                         break;
459                                 case YPERR_MAP:
460                                         st->stepping = 0;
461                                         no_name_active = 1;
462                                         how = nss_lt_all;
463
464                                         rv = NS_NOTFOUND;
465                                         continue;
466                                 default:
467                                         rv = NS_NOTFOUND;
468                                         goto fin;
469                                 }
470                         } else {
471                                 st->stepping = 0;
472                                 no_name_active = 1;
473                                 how = nss_lt_all;
474
475                                 rv = NS_NOTFOUND;
476                                 continue;
477                         }
478                 break;
479                 case nss_lt_id:
480                         free(buf);
481                         asprintf(&buf, "%d", number);
482                         if (buf == NULL)
483                                 return (NS_TRYAGAIN);
484                         if (yp_match(st->domain, "rpc.bynumber", buf,
485                                 strlen(buf), &resultbuf, &resultbuflen)) {
486                                 rv = NS_NOTFOUND;
487                                 goto fin;
488                         }
489                         break;
490                 case nss_lt_all:
491                                 if (!st->stepping) {
492                                         rv = yp_first(st->domain, "rpc.bynumber",
493                                                 &st->current,
494                                                 &st->currentlen, &resultbuf,
495                                                 &resultbuflen);
496                                         if (rv) {
497                                                 rv = NS_NOTFOUND;
498                                                 goto fin;
499                                         }
500                                         st->stepping = 1;
501                                 } else {
502                                         lastkey = st->current;
503                                         rv = yp_next(st->domain, "rpc.bynumber",
504                                                 st->current,
505                                                 st->currentlen, &st->current,
506                                                 &st->currentlen,
507                                                 &resultbuf,     &resultbuflen);
508                                         free(lastkey);
509                                         if (rv) {
510                                                 st->stepping = 0;
511                                                 rv = NS_NOTFOUND;
512                                                 goto fin;
513                                         }
514                                 }
515                         break;
516                 }
517
518                 /* we need a room for additional \n symbol */
519                 if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
520                     sizeof(char *)) {
521                         *errnop = ERANGE;
522                         rv = NS_RETURN;
523                         free(resultbuf);
524                         break;
525                 }
526
527                 aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
528                 aliases_size = (buffer + bufsize - (char *)aliases) /
529                         sizeof(char *);
530                 if (aliases_size < 1) {
531                         *errnop = ERANGE;
532                         rv = NS_RETURN;
533                         free(resultbuf);
534                         break;
535                 }
536
537                 /*
538                  * rpcent_unpack expects lines terminated with \n -- make it happy
539                  */
540                 memcpy(buffer, resultbuf, resultbuflen);
541                 buffer[resultbuflen] = '\n';
542                 buffer[resultbuflen+1] = '\0';
543                 free(resultbuf);
544
545                 if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
546                     errnop) != 0) {
547                         if (*errnop == 0)
548                                 rv = NS_NOTFOUND;
549                         else
550                                 rv = NS_RETURN;
551                 } else {
552                         if ((how == nss_lt_all) && (no_name_active != 0)) {
553                                 if (strcmp(rpc->r_name, name) == 0)
554                                         goto done;
555                                 for (rp = rpc->r_aliases; *rp != NULL; rp++) {
556                                         if (strcmp(*rp, name) == 0)
557                                                 goto done;
558                                 }
559                                 rv = NS_NOTFOUND;
560                                 continue;
561 done:
562                                 rv = NS_SUCCESS;
563                         } else
564                                 rv = NS_SUCCESS;
565                 }
566
567         } while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
568
569 fin:
570         free(buf);
571         if ((rv == NS_SUCCESS) && (retval != NULL))
572                 *((struct rpcent **)retval) = rpc;
573
574         return (rv);
575 }
576
577 static int
578 nis_setrpcent(void *retval, void *mdata, va_list ap)
579 {
580         struct nis_state        *st;
581         int     rv;
582
583         rv = nis_getstate(&st);
584         if (rv != 0)
585                 return (NS_UNAVAIL);
586
587         switch ((enum constants)(uintptr_t)mdata)
588         {
589         case SETRPCENT:
590         case ENDRPCENT:
591                 free(st->current);
592                 st->current = NULL;
593                 st->stepping = 0;
594                 break;
595         default:
596                 break;
597         }
598
599         return (NS_UNAVAIL);
600 }
601 #endif
602
603 #ifdef NS_CACHING
604 static int
605 rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
606 {
607         char *name;
608         int rpc;
609
610         size_t desired_size, size;
611         enum nss_lookup_type lookup_type;
612         int res = NS_UNAVAIL;
613
614         lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
615         switch (lookup_type) {
616         case nss_lt_name:
617                 name = va_arg(ap, char *);
618
619                 size = strlen(name);
620                 desired_size = sizeof(enum nss_lookup_type) + size + 1;
621                 if (desired_size > *buffer_size) {
622                         res = NS_RETURN;
623                         goto fin;
624                 }
625
626                 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
627                 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
628
629                 res = NS_SUCCESS;
630                 break;
631         case nss_lt_id:
632                 rpc = va_arg(ap, int);
633
634                 desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
635                 if (desired_size > *buffer_size) {
636                         res = NS_RETURN;
637                         goto fin;
638                 }
639
640                 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
641                 memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
642                     sizeof(int));
643
644                 res = NS_SUCCESS;
645                 break;
646         default:
647                 /* should be unreachable */
648                 return (NS_UNAVAIL);
649         }
650
651 fin:
652         *buffer_size = desired_size;
653         return (res);
654 }
655
656 static int
657 rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
658     void *cache_mdata)
659 {
660         char *name;
661         int num;
662         struct rpcent *rpc;
663         char *orig_buf;
664         size_t orig_buf_size;
665
666         struct rpcent new_rpc;
667         size_t desired_size, size, aliases_size;
668         char *p;
669         char **alias;
670
671         switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
672         case nss_lt_name:
673                 name = va_arg(ap, char *);
674                 break;
675         case nss_lt_id:
676                 num = va_arg(ap, int);
677                 break;
678         case nss_lt_all:
679                 break;
680         default:
681                 /* should be unreachable */
682                 return (NS_UNAVAIL);
683         }
684
685         rpc = va_arg(ap, struct rpcent *);
686         orig_buf = va_arg(ap, char *);
687         orig_buf_size = va_arg(ap, size_t);
688
689         desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
690         if (rpc->r_name != NULL)
691                 desired_size += strlen(rpc->r_name) + 1;
692
693         if (rpc->r_aliases != NULL) {
694                 aliases_size = 0;
695                 for (alias = rpc->r_aliases; *alias; ++alias) {
696                         desired_size += strlen(*alias) + 1;
697                         ++aliases_size;
698                 }
699
700                 desired_size += _ALIGNBYTES + (aliases_size + 1) *
701                     sizeof(char *);
702         }
703
704         if (*buffer_size < desired_size) {
705                 /* this assignment is here for future use */
706                 *buffer_size = desired_size;
707                 return (NS_RETURN);
708         }
709
710         new_rpc = *rpc;
711
712         *buffer_size = desired_size;
713         memset(buffer, 0, desired_size);
714         p = buffer + sizeof(struct rpcent) + sizeof(char *);
715         memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
716         p = (char *)_ALIGN(p);
717
718         if (new_rpc.r_name != NULL) {
719                 size = strlen(new_rpc.r_name);
720                 memcpy(p, new_rpc.r_name, size);
721                 new_rpc.r_name = p;
722                 p += size + 1;
723         }
724
725         if (new_rpc.r_aliases != NULL) {
726                 p = (char *)_ALIGN(p);
727                 memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
728                 new_rpc.r_aliases = (char **)p;
729                 p += sizeof(char *) * (aliases_size + 1);
730
731                 for (alias = new_rpc.r_aliases; *alias; ++alias) {
732                         size = strlen(*alias);
733                         memcpy(p, *alias, size);
734                         *alias = p;
735                         p += size + 1;
736                 }
737         }
738
739         memcpy(buffer, &new_rpc, sizeof(struct rpcent));
740         return (NS_SUCCESS);
741 }
742
743 static int
744 rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
745     void *cache_mdata)
746 {
747         char *name;
748         int num;
749         struct rpcent *rpc;
750         char *orig_buf;
751         size_t orig_buf_size;
752         int *ret_errno;
753
754         char *p;
755         char **alias;
756
757         switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
758         case nss_lt_name:
759                 name = va_arg(ap, char *);
760                 break;
761         case nss_lt_id:
762                 num = va_arg(ap, int);
763                 break;
764         case nss_lt_all:
765                 break;
766         default:
767                 /* should be unreachable */
768                 return (NS_UNAVAIL);
769         }
770
771         rpc = va_arg(ap, struct rpcent *);
772         orig_buf = va_arg(ap, char *);
773         orig_buf_size = va_arg(ap, size_t);
774         ret_errno = va_arg(ap, int *);
775
776         if (orig_buf_size <
777             buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
778                 *ret_errno = ERANGE;
779                 return (NS_RETURN);
780         }
781
782         memcpy(rpc, buffer, sizeof(struct rpcent));
783         memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
784
785         orig_buf = (char *)_ALIGN(orig_buf);
786         memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
787             _ALIGN(p) - (size_t)p,
788             buffer_size - sizeof(struct rpcent) - sizeof(char *) -
789             _ALIGN(p) + (size_t)p);
790         p = (char *)_ALIGN(p);
791
792         NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
793         if (rpc->r_aliases != NULL) {
794                 NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
795
796                 for (alias = rpc->r_aliases     ; *alias; ++alias)
797                         NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
798         }
799
800         if (retval != NULL)
801                 *((struct rpcent **)retval) = rpc;
802
803         return (NS_SUCCESS);
804 }
805
806 NSS_MP_CACHE_HANDLING(rpc);
807 #endif /* NS_CACHING */
808
809
810 /* get**_r functions implementation */
811 static int
812 getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
813         size_t bufsize, struct rpcent **result)
814 {
815 #ifdef NS_CACHING
816         static const nss_cache_info cache_info =
817                 NS_COMMON_CACHE_INFO_INITIALIZER(
818                 rpc, (void *)nss_lt_name,
819                 rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
820 #endif
821         static const ns_dtab dtab[] = {
822                 { NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
823 #ifdef YP
824                 { NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
825 #endif
826 #ifdef NS_CACHING
827                 NS_CACHE_CB(&cache_info)
828 #endif
829                 { NULL, NULL, NULL }
830         };
831         int rv, ret_errno;
832
833         ret_errno = 0;
834         *result = NULL;
835         rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
836             name, rpc, buffer, bufsize, &ret_errno);
837
838         if (rv == NS_SUCCESS)
839                 return (0);
840         else
841                 return (ret_errno);
842 }
843
844 static int
845 getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
846         size_t bufsize, struct rpcent **result)
847 {
848 #ifdef NS_CACHING
849         static const nss_cache_info cache_info =
850                 NS_COMMON_CACHE_INFO_INITIALIZER(
851                 rpc, (void *)nss_lt_id,
852                 rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
853 #endif
854         static const ns_dtab dtab[] = {
855                 { NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
856 #ifdef YP
857                 { NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
858 #endif
859 #ifdef NS_CACHING
860                 NS_CACHE_CB(&cache_info)
861 #endif
862                 { NULL, NULL, NULL }
863         };
864         int rv, ret_errno;
865
866         ret_errno = 0;
867         *result = NULL;
868         rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
869             number, rpc, buffer, bufsize, &ret_errno);
870
871         if (rv == NS_SUCCESS)
872                 return (0);
873         else
874                 return (ret_errno);
875 }
876
877 static int
878 getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
879         struct rpcent **result)
880 {
881 #ifdef NS_CACHING
882         static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
883                 rpc, (void *)nss_lt_all,
884                 rpc_marshal_func, rpc_unmarshal_func);
885 #endif
886         static const ns_dtab dtab[] = {
887                 { NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
888 #ifdef YP
889                 { NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
890 #endif
891 #ifdef NS_CACHING
892                 NS_CACHE_CB(&cache_info)
893 #endif
894                 { NULL, NULL, NULL }
895         };
896         int rv, ret_errno;
897
898         ret_errno = 0;
899         *result = NULL;
900         rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
901             rpc, buffer, bufsize, &ret_errno);
902
903         if (rv == NS_SUCCESS)
904                 return (0);
905         else
906                 return (ret_errno);
907 }
908
909 /* get** wrappers for get**_r functions implementation */
910 static  void
911 rpcent_endstate(void *p)
912 {
913         if (p == NULL)
914                 return;
915
916         free(((struct rpcent_state *)p)->buffer);
917         free(p);
918 }
919
920 static  int
921 wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
922     size_t bufsize, struct rpcent **res)
923 {
924         return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
925 }
926
927 static  int
928 wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
929     size_t bufsize, struct rpcent **res)
930 {
931         return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
932 }
933
934 static  int
935 wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
936     size_t bufsize, struct rpcent **res)
937 {
938         return (getrpcent_r(rpc, buffer, bufsize, res));
939 }
940
941 static struct rpcent *
942 getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
943     union key key)
944 {
945         int              rv;
946         struct rpcent   *res;
947         struct rpcent_state * st;
948
949         rv=rpcent_getstate(&st);
950         if (rv != 0) {
951                 errno = rv;
952                 return NULL;
953         }
954
955         if (st->buffer == NULL) {
956                 st->buffer = malloc(RPCENT_STORAGE_INITIAL);
957                 if (st->buffer == NULL)
958                         return (NULL);
959                 st->bufsize = RPCENT_STORAGE_INITIAL;
960         }
961         do {
962                 rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
963                 if (res == NULL && rv == ERANGE) {
964                         free(st->buffer);
965                         if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
966                                 st->buffer = NULL;
967                                 errno = ERANGE;
968                                 return (NULL);
969                         }
970                         st->bufsize <<= 1;
971                         st->buffer = malloc(st->bufsize);
972                         if (st->buffer == NULL)
973                                 return (NULL);
974                 }
975         } while (res == NULL && rv == ERANGE);
976         if (rv != 0)
977                 errno = rv;
978
979         return (res);
980 }
981
982 struct rpcent *
983 getrpcbyname(const char *name)
984 {
985         union key key;
986
987         key.name = name;
988
989         return (getrpc(wrap_getrpcbyname_r, key));
990 }
991
992 struct rpcent *
993 getrpcbynumber(int number)
994 {
995         union key key;
996
997         key.number = number;
998
999         return (getrpc(wrap_getrpcbynumber_r, key));
1000 }
1001
1002 struct rpcent *
1003 getrpcent(void)
1004 {
1005         union key key;
1006
1007         key.number = 0; /* not used */
1008
1009         return (getrpc(wrap_getrpcent_r, key));
1010 }
1011
1012 void
1013 setrpcent(int stayopen)
1014 {
1015 #ifdef NS_CACHING
1016         static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1017                 rpc, (void *)nss_lt_all,
1018                 NULL, NULL);
1019 #endif
1020
1021         static const ns_dtab dtab[] = {
1022                 { NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
1023 #ifdef YP
1024                 { NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
1025 #endif
1026 #ifdef NS_CACHING
1027                 NS_CACHE_CB(&cache_info)
1028 #endif
1029                 { NULL, NULL, NULL }
1030         };
1031
1032         (void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
1033                 stayopen);
1034 }
1035
1036 void
1037 endrpcent(void)
1038 {
1039 #ifdef NS_CACHING
1040         static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1041                 rpc, (void *)nss_lt_all,
1042                 NULL, NULL);
1043 #endif
1044
1045         static const ns_dtab dtab[] = {
1046                 { NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
1047 #ifdef YP
1048                 { NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
1049 #endif
1050 #ifdef NS_CACHING
1051                 NS_CACHE_CB(&cache_info)
1052 #endif
1053                 { NULL, NULL, NULL }
1054         };
1055
1056         (void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc);
1057 }