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