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