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