source: rtems-libbsd/freebsd/lib/libc/net/getservent.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

  • Property mode set to 100644
File size: 29.5 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*
4 * Copyright (c) 1983, 1993
5 *      The Regents of the University of California.  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
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#if defined(LIBC_SCCS) && !defined(lint)
33static char sccsid[] = "@(#)getservent.c        8.1 (Berkeley) 6/4/93";
34#endif /* LIBC_SCCS and not lint */
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include <rtems/bsd/sys/param.h>
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <arpa/inet.h>
42#include <db.h>
43#include <errno.h>
44#include <fcntl.h>
45#include <limits.h>
46#include <netdb.h>
47#include <nsswitch.h>
48#include <stdio.h>
49#include <string.h>
50#include <stdlib.h>
51#include <unistd.h>
52#ifdef YP
53#include <rpc/rpc.h>
54#include <rpcsvc/yp_prot.h>
55#include <rpcsvc/ypclnt.h>
56#endif
57#include "namespace.h"
58#include "reentrant.h"
59#include "un-namespace.h"
60#include "netdb_private.h"
61#ifdef NS_CACHING
62#include "nscache.h"
63#endif
64#include "nss_tls.h"
65
66enum constants
67{
68        SETSERVENT              = 1,
69        ENDSERVENT              = 2,
70        SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
71        SERVENT_STORAGE_MAX     = 1 << 20, /* 1 MByte */
72};
73
74struct servent_mdata
75{
76        enum nss_lookup_type how;
77        int compat_mode;
78};
79
80static const ns_src defaultsrc[] = {
81        { NSSRC_COMPAT, NS_SUCCESS },
82        { NULL, 0 }
83};
84
85static int servent_unpack(char *, struct servent *, char **, size_t, int *);
86
87/* files backend declarations */
88struct files_state
89{
90        FILE *fp;
91        int stayopen;
92
93        int compat_mode_active;
94};
95static void files_endstate(void *);
96NSS_TLS_HANDLING(files);
97
98static int files_servent(void *, void *, va_list);
99static int files_setservent(void *, void *, va_list);
100
101/* db backend declarations */
102struct db_state
103{
104        DB *db;
105        int stayopen;
106        int keynum;
107};
108static void db_endstate(void *);
109NSS_TLS_HANDLING(db);
110
111static int db_servent(void *, void *, va_list);
112static int db_setservent(void *, void *, va_list);
113
114#ifdef YP
115/* nis backend declarations */
116static  int     nis_servent(void *, void *, va_list);
117static  int     nis_setservent(void *, void *, va_list);
118
119struct nis_state
120{
121        int yp_stepping;
122        char yp_domain[MAXHOSTNAMELEN];
123        char *yp_key;
124        int yp_keylen;
125};
126static void nis_endstate(void *);
127NSS_TLS_HANDLING(nis);
128
129static int nis_servent(void *, void *, va_list);
130static int nis_setservent(void *, void *, va_list);
131#endif
132
133/* compat backend declarations */
134static int compat_setservent(void *, void *, va_list);
135
136/* get** wrappers for get**_r functions declarations */
137struct servent_state {
138        struct servent serv;
139        char *buffer;
140        size_t bufsize;
141};
142static  void    servent_endstate(void *);
143NSS_TLS_HANDLING(servent);
144
145struct key {
146        const char *proto;
147        union {
148                const char *name;
149                int port;
150        };
151};
152
153static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
154    struct servent **);
155static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
156    struct servent **);
157static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
158    struct servent **);
159static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
160    size_t, struct servent **), struct key);
161
162#ifdef NS_CACHING
163static int serv_id_func(char *, size_t *, va_list, void *);
164static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
165static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
166#endif
167
168static int
169servent_unpack(char *p, struct servent *serv, char **aliases,
170    size_t aliases_size, int *errnop)
171{
172        char *cp, **q, *endp;
173        long l;
174
175        if (*p == '#')
176                return -1;
177
178        memset(serv, 0, sizeof(struct servent));
179
180        cp = strpbrk(p, "#\n");
181        if (cp != NULL)
182                *cp = '\0';
183        serv->s_name = p;
184
185        p = strpbrk(p, " \t");
186        if (p == NULL)
187                return -1;
188        *p++ = '\0';
189        while (*p == ' ' || *p == '\t')
190                p++;
191        cp = strpbrk(p, ",/");
192        if (cp == NULL)
193                return -1;
194
195        *cp++ = '\0';
196        l = strtol(p, &endp, 10);
197        if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
198                return -1;
199        serv->s_port = htons((in_port_t)l);
200        serv->s_proto = cp;
201
202        q = serv->s_aliases = aliases;
203        cp = strpbrk(cp, " \t");
204        if (cp != NULL)
205                *cp++ = '\0';
206        while (cp && *cp) {
207                if (*cp == ' ' || *cp == '\t') {
208                        cp++;
209                        continue;
210                }
211                if (q < &aliases[aliases_size - 1]) {
212                        *q++ = cp;
213                } else {
214                        *q = NULL;
215                        *errnop = ERANGE;
216                        return -1;
217                }
218                cp = strpbrk(cp, " \t");
219                if (cp != NULL)
220                        *cp++ = '\0';
221        }
222        *q = NULL;
223
224        return 0;
225}
226
227static int
228parse_result(struct servent *serv, char *buffer, size_t bufsize,
229    char *resultbuf, size_t resultbuflen, int *errnop)
230{
231        char **aliases;
232        int aliases_size;
233
234        if (bufsize <= resultbuflen + _ALIGNBYTES + sizeof(char *)) {
235                *errnop = ERANGE;
236                return (NS_RETURN);
237        }
238        aliases = (char **)_ALIGN(&buffer[resultbuflen + 1]);
239        aliases_size = (buffer + bufsize - (char *)aliases) / sizeof(char *);
240        if (aliases_size < 1) {
241                *errnop = ERANGE;
242                return (NS_RETURN);
243        }
244
245        memcpy(buffer, resultbuf, resultbuflen);
246        buffer[resultbuflen] = '\0';
247
248        if (servent_unpack(buffer, serv, aliases, aliases_size, errnop) != 0)
249                return ((*errnop == 0) ? NS_NOTFOUND : NS_RETURN);
250        return (NS_SUCCESS);
251}
252
253/* files backend implementation */
254static  void
255files_endstate(void *p)
256{
257        FILE * f;
258
259        if (p == NULL)
260                return;
261
262        f = ((struct files_state *)p)->fp;
263        if (f != NULL)
264                fclose(f);
265
266        free(p);
267}
268
269/*
270 * compat structures. compat and files sources functionalities are almost
271 * equal, so they all are managed by files_servent function
272 */
273static int
274files_servent(void *retval, void *mdata, va_list ap)
275{
276        static const ns_src compat_src[] = {
277#ifdef YP
278                { NSSRC_NIS, NS_SUCCESS },
279#endif
280                { NULL, 0 }
281        };
282        ns_dtab compat_dtab[] = {
283                { NSSRC_DB, db_servent,
284                        (void *)((struct servent_mdata *)mdata)->how },
285#ifdef YP
286                { NSSRC_NIS, nis_servent,
287                        (void *)((struct servent_mdata *)mdata)->how },
288#endif
289                { NULL, NULL, NULL }
290        };
291
292        struct files_state *st;
293        int rv;
294        int stayopen;
295
296        struct servent_mdata *serv_mdata;
297        char *name;
298        char *proto;
299        int port;
300
301        struct servent *serv;
302        char *buffer;
303        size_t bufsize;
304        int *errnop;
305
306        size_t linesize;
307        char *line;
308        char **cp;
309
310        name = NULL;
311        proto = NULL;
312        serv_mdata = (struct servent_mdata *)mdata;
313        switch (serv_mdata->how) {
314        case nss_lt_name:
315                name = va_arg(ap, char *);
316                proto = va_arg(ap, char *);
317                break;
318        case nss_lt_id:
319                port = va_arg(ap, int);
320                proto = va_arg(ap, char *);
321                break;
322        case nss_lt_all:
323                break;
324        default:
325                return NS_NOTFOUND;
326        };
327
328        serv = va_arg(ap, struct servent *);
329        buffer  = va_arg(ap, char *);
330        bufsize = va_arg(ap, size_t);
331        errnop = va_arg(ap,int *);
332
333        *errnop = files_getstate(&st);
334        if (*errnop != 0)
335                return (NS_UNAVAIL);
336
337        if (st->fp == NULL)
338                st->compat_mode_active = 0;
339
340        if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "r")) == NULL) {
341                *errnop = errno;
342                return (NS_UNAVAIL);
343        }
344
345        if (serv_mdata->how == nss_lt_all)
346                stayopen = 1;
347        else {
348                rewind(st->fp);
349                stayopen = st->stayopen;
350        }
351
352        rv = NS_NOTFOUND;
353        do {
354                if (!st->compat_mode_active) {
355                        if ((line = fgetln(st->fp, &linesize)) == NULL) {
356                                *errnop = errno;
357                                rv = NS_RETURN;
358                                break;
359                        }
360
361                        if (*line=='+' && serv_mdata->compat_mode != 0)
362                                st->compat_mode_active = 1;
363                }
364
365                if (st->compat_mode_active != 0) {
366                        switch (serv_mdata->how) {
367                        case nss_lt_name:
368                                rv = nsdispatch(retval, compat_dtab,
369                                    NSDB_SERVICES_COMPAT, "getservbyname_r",
370                                    compat_src, name, proto, serv, buffer,
371                                    bufsize, errnop);
372                                break;
373                        case nss_lt_id:
374                                rv = nsdispatch(retval, compat_dtab,
375                                    NSDB_SERVICES_COMPAT, "getservbyport_r",
376                                    compat_src, port, proto, serv, buffer,
377                                        bufsize, errnop);
378                                break;
379                        case nss_lt_all:
380                                rv = nsdispatch(retval, compat_dtab,
381                                    NSDB_SERVICES_COMPAT, "getservent_r",
382                                    compat_src, serv, buffer, bufsize, errnop);
383                                break;
384                        }
385
386                        if (!(rv & NS_TERMINATE) ||
387                            serv_mdata->how != nss_lt_all)
388                                st->compat_mode_active = 0;
389
390                        continue;
391                }
392
393                rv = parse_result(serv, buffer, bufsize, line, linesize,
394                    errnop);
395                if (rv == NS_NOTFOUND)
396                        continue;
397                if (rv == NS_RETURN)
398                        break;
399
400                rv = NS_NOTFOUND;
401                switch (serv_mdata->how) {
402                case nss_lt_name:
403                        if (strcmp(name, serv->s_name) == 0)
404                                goto gotname;
405                        for (cp = serv->s_aliases; *cp; cp++)
406                                if (strcmp(name, *cp) == 0)
407                                        goto gotname;
408
409                        continue;
410                gotname:
411                        if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
412                                rv = NS_SUCCESS;
413                        break;
414                case nss_lt_id:
415                        if (port != serv->s_port)
416                                continue;
417
418                        if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
419                                rv = NS_SUCCESS;
420                        break;
421                case nss_lt_all:
422                        rv = NS_SUCCESS;
423                        break;
424                }
425
426        } while (!(rv & NS_TERMINATE));
427
428        if (!stayopen && st->fp != NULL) {
429                fclose(st->fp);
430                st->fp = NULL;
431        }
432
433        if ((rv == NS_SUCCESS) && (retval != NULL))
434                *(struct servent **)retval=serv;
435
436        return (rv);
437}
438
439static int
440files_setservent(void *retval, void *mdata, va_list ap)
441{
442        struct files_state *st;
443        int rv;
444        int f;
445
446        rv = files_getstate(&st);
447        if (rv != 0)
448                return (NS_UNAVAIL);
449
450        switch ((enum constants)mdata) {
451        case SETSERVENT:
452                f = va_arg(ap,int);
453                if (st->fp == NULL)
454                        st->fp = fopen(_PATH_SERVICES, "r");
455                else
456                        rewind(st->fp);
457                st->stayopen |= f;
458                break;
459        case ENDSERVENT:
460                if (st->fp != NULL) {
461                        fclose(st->fp);
462                        st->fp = NULL;
463                }
464                st->stayopen = 0;
465                break;
466        default:
467                break;
468        };
469
470        st->compat_mode_active = 0;
471        return (NS_UNAVAIL);
472}
473
474/* db backend implementation */
475static  void
476db_endstate(void *p)
477{
478        DB *db;
479
480        if (p == NULL)
481                return;
482
483        db = ((struct db_state *)p)->db;
484        if (db != NULL)
485                db->close(db);
486
487        free(p);
488}
489
490static int
491db_servent(void *retval, void *mdata, va_list ap)
492{
493        char buf[BUFSIZ];
494        DBT key, data, *result;
495        DB *db;
496
497        struct db_state *st;
498        int rv;
499        int stayopen;
500
501        enum nss_lookup_type how;
502        char *name;
503        char *proto;
504        int port;
505
506        struct servent *serv;
507        char *buffer;
508        size_t bufsize;
509        int *errnop;
510
511        name = NULL;
512        proto = NULL;
513        how = (enum nss_lookup_type)mdata;
514        switch (how) {
515        case nss_lt_name:
516                name = va_arg(ap, char *);
517                proto = va_arg(ap, char *);
518                break;
519        case nss_lt_id:
520                port = va_arg(ap, int);
521                proto = va_arg(ap, char *);
522                break;
523        case nss_lt_all:
524                break;
525        default:
526                return NS_NOTFOUND;
527        };
528
529        serv = va_arg(ap, struct servent *);
530        buffer  = va_arg(ap, char *);
531        bufsize = va_arg(ap, size_t);
532        errnop = va_arg(ap,int *);
533
534        *errnop = db_getstate(&st);
535        if (*errnop != 0)
536                return (NS_UNAVAIL);
537
538        if (how == nss_lt_all && st->keynum < 0)
539                return (NS_NOTFOUND);
540
541        if (st->db == NULL) {
542                st->db = dbopen(_PATH_SERVICES_DB, O_RDONLY, 0, DB_HASH, NULL);
543                if (st->db == NULL) {
544                        *errnop = errno;
545                        return (NS_UNAVAIL);
546                }
547        }
548
549        stayopen = (how == nss_lt_all) ? 1 : st->stayopen;
550        db = st->db;
551
552        do {
553                switch (how) {
554                case nss_lt_name:
555                        key.data = buf;
556                        if (proto == NULL)
557                                key.size = snprintf(buf, sizeof(buf),
558                                    "\376%s", name);
559                        else
560                                key.size = snprintf(buf, sizeof(buf),
561                                    "\376%s/%s", name, proto);
562                        key.size++;
563                        if (db->get(db, &key, &data, 0) != 0 ||
564                            db->get(db, &data, &key, 0) != 0) {
565                                rv = NS_NOTFOUND;
566                                goto db_fin;
567                        }
568                        result = &key;
569                        break;
570                case nss_lt_id:
571                        key.data = buf;
572                        port = htons(port);
573                        if (proto == NULL)
574                                key.size = snprintf(buf, sizeof(buf),
575                                    "\377%d", port);
576                        else
577                                key.size = snprintf(buf, sizeof(buf),
578                                    "\377%d/%s", port, proto);
579                        key.size++;
580                        if (db->get(db, &key, &data, 0) != 0 ||
581                            db->get(db, &data, &key, 0) != 0) {
582                                rv = NS_NOTFOUND;
583                                goto db_fin;
584                        }
585                        result = &key;
586                        break;
587                case nss_lt_all:
588                        key.data = buf;
589                        key.size = snprintf(buf, sizeof(buf), "%d",
590                            st->keynum++);
591                        key.size++;
592                        if (db->get(db, &key, &data, 0) != 0) {
593                                st->keynum = -1;
594                                rv = NS_NOTFOUND;
595                                goto db_fin;
596                        }
597                        result = &data;
598                        break;
599                }
600
601                rv = parse_result(serv, buffer, bufsize, result->data,
602                    result->size - 1, errnop);
603
604        } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
605
606db_fin:
607        if (!stayopen && st->db != NULL) {
608                db->close(db);
609                st->db = NULL;
610        }
611
612        if (rv == NS_SUCCESS && retval != NULL)
613                *(struct servent **)retval = serv;
614
615        return (rv);
616}
617
618static int
619db_setservent(void *retval, void *mdata, va_list ap)
620{
621        DB *db;
622        struct db_state *st;
623        int rv;
624        int f;
625
626        rv = db_getstate(&st);
627        if (rv != 0)
628                return (NS_UNAVAIL);
629
630        switch ((enum constants)mdata) {
631        case SETSERVENT:
632                f = va_arg(ap, int);
633                st->stayopen |= f;
634                st->keynum = 0;
635                break;
636        case ENDSERVENT:
637                db = st->db;
638                if (db != NULL) {
639                        db->close(db);
640                        st->db = NULL;
641                }
642                st->stayopen = 0;
643                break;
644        default:
645                break;
646        };
647
648        return (NS_UNAVAIL);
649}
650
651/* nis backend implementation */
652#ifdef YP
653static  void
654nis_endstate(void *p)
655{
656        if (p == NULL)
657                return;
658
659        free(((struct nis_state *)p)->yp_key);
660        free(p);
661}
662
663static int
664nis_servent(void *retval, void *mdata, va_list ap)
665{
666        char *resultbuf, *lastkey;
667        int resultbuflen;
668        char buf[YPMAXRECORD + 2];
669
670        struct nis_state *st;
671        int rv;
672
673        enum nss_lookup_type how;
674        char *name;
675        char *proto;
676        int port;
677
678        struct servent *serv;
679        char *buffer;
680        size_t bufsize;
681        int *errnop;
682
683        name = NULL;
684        proto = NULL;
685        how = (enum nss_lookup_type)mdata;
686        switch (how) {
687        case nss_lt_name:
688                name = va_arg(ap, char *);
689                proto = va_arg(ap, char *);
690                break;
691        case nss_lt_id:
692                port = va_arg(ap, int);
693                proto = va_arg(ap, char *);
694                break;
695        case nss_lt_all:
696                break;
697        default:
698                return NS_NOTFOUND;
699        };
700
701        serv = va_arg(ap, struct servent *);
702        buffer  = va_arg(ap, char *);
703        bufsize = va_arg(ap, size_t);
704        errnop = va_arg(ap, int *);
705
706        *errnop = nis_getstate(&st);
707        if (*errnop != 0)
708                return (NS_UNAVAIL);
709
710        if (st->yp_domain[0] == '\0') {
711                if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
712                        *errnop = errno;
713                        return (NS_UNAVAIL);
714                }
715        }
716
717        do {
718                switch (how) {
719                case nss_lt_name:
720                        snprintf(buf, sizeof(buf), "%s/%s", name, proto);
721                        if (yp_match(st->yp_domain, "services.byname", buf,
722                            strlen(buf), &resultbuf, &resultbuflen)) {
723                                rv = NS_NOTFOUND;
724                                goto fin;
725                        }
726                        break;
727                case nss_lt_id:
728                        snprintf(buf, sizeof(buf), "%d/%s", ntohs(port),
729                            proto);
730
731                        /*
732                         * We have to be a little flexible
733                         * here. Ideally you're supposed to have both
734                         * a services.byname and a services.byport
735                         * map, but some systems have only
736                         * services.byname. FreeBSD cheats a little by
737                         * putting the services.byport information in
738                         * the same map as services.byname so that
739                         * either case will work. We allow for both
740                         * possibilities here: if there is no
741                         * services.byport map, we try services.byname
742                         * instead.
743                         */
744                        rv = yp_match(st->yp_domain, "services.byport", buf,
745                            strlen(buf), &resultbuf, &resultbuflen);
746                        if (rv) {
747                                if (rv == YPERR_MAP) {
748                                        if (yp_match(st->yp_domain,
749                                            "services.byname", buf,
750                                            strlen(buf), &resultbuf,
751                                            &resultbuflen)) {
752                                                rv = NS_NOTFOUND;
753                                                goto fin;
754                                        }
755                                } else {
756                                        rv = NS_NOTFOUND;
757                                        goto fin;
758                                }
759                        }
760
761                        break;
762                case nss_lt_all:
763                        if (!st->yp_stepping) {
764                                free(st->yp_key);
765                                rv = yp_first(st->yp_domain, "services.byname",
766                                    &st->yp_key, &st->yp_keylen, &resultbuf,
767                                    &resultbuflen);
768                                if (rv) {
769                                        rv = NS_NOTFOUND;
770                                        goto fin;
771                                }
772                                st->yp_stepping = 1;
773                        } else {
774                                lastkey = st->yp_key;
775                                rv = yp_next(st->yp_domain, "services.byname",
776                                    st->yp_key, st->yp_keylen, &st->yp_key,
777                                    &st->yp_keylen, &resultbuf, &resultbuflen);
778                                free(lastkey);
779                                if (rv) {
780                                        st->yp_stepping = 0;
781                                        rv = NS_NOTFOUND;
782                                        goto fin;
783                                }
784                        }
785                        break;
786                };
787
788                rv = parse_result(serv, buffer, bufsize, resultbuf,
789                    resultbuflen, errnop);
790                free(resultbuf);
791
792        } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
793
794fin:
795        if (rv == NS_SUCCESS && retval != NULL)
796                *(struct servent **)retval = serv;
797
798        return (rv);
799}
800
801static int
802nis_setservent(void *result, void *mdata, va_list ap)
803{
804        struct nis_state *st;
805        int rv;
806
807        rv = nis_getstate(&st);
808        if (rv != 0)
809                return (NS_UNAVAIL);
810
811        switch ((enum constants)mdata) {
812        case SETSERVENT:
813        case ENDSERVENT:
814                free(st->yp_key);
815                st->yp_key = NULL;
816                st->yp_stepping = 0;
817                break;
818        default:
819                break;
820        };
821
822        return (NS_UNAVAIL);
823}
824#endif
825
826/* compat backend implementation */
827static int
828compat_setservent(void *retval, void *mdata, va_list ap)
829{
830        static const ns_src compat_src[] = {
831#ifdef YP
832                { NSSRC_NIS, NS_SUCCESS },
833#endif
834                { NULL, 0 }
835        };
836        ns_dtab compat_dtab[] = {
837                { NSSRC_DB, db_setservent, mdata },
838#ifdef YP
839                { NSSRC_NIS, nis_setservent, mdata },
840#endif
841                { NULL, NULL, NULL }
842        };
843        int f;
844
845        (void)files_setservent(retval, mdata, ap);
846
847        switch ((enum constants)mdata) {
848        case SETSERVENT:
849                f = va_arg(ap,int);
850                (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
851                    "setservent", compat_src, f);
852                break;
853        case ENDSERVENT:
854                (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
855                    "endservent", compat_src);
856                break;
857        default:
858                break;
859        }
860
861        return (NS_UNAVAIL);
862}
863
864#ifdef NS_CACHING
865static int
866serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
867{
868        char *name;
869        char *proto;
870        int port;
871
872        size_t desired_size, size, size2;
873        enum nss_lookup_type lookup_type;
874        int res = NS_UNAVAIL;
875
876        lookup_type = (enum nss_lookup_type)cache_mdata;
877        switch (lookup_type) {
878        case nss_lt_name:
879                name = va_arg(ap, char *);
880                proto = va_arg(ap, char *);
881
882                size = strlen(name);
883                desired_size = sizeof(enum nss_lookup_type) + size + 1;
884                if (proto != NULL) {
885                        size2 = strlen(proto);
886                        desired_size += size2 + 1;
887                } else
888                        size2 = 0;
889
890                if (desired_size > *buffer_size) {
891                        res = NS_RETURN;
892                        goto fin;
893                }
894
895                memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
896                memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
897
898                if (proto != NULL)
899                        memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
900                            proto, size2 + 1);
901
902                res = NS_SUCCESS;
903                break;
904        case nss_lt_id:
905                port = va_arg(ap, int);
906                proto = va_arg(ap, char *);
907
908                desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
909                if (proto != NULL) {
910                        size = strlen(proto);
911                        desired_size += size + 1;
912                } else
913                        size = 0;
914
915                if (desired_size > *buffer_size) {
916                        res = NS_RETURN;
917                        goto fin;
918                }
919
920                memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
921                memcpy(buffer + sizeof(enum nss_lookup_type), &port,
922                    sizeof(int));
923
924                if (proto != NULL)
925                        memcpy(buffer + sizeof(enum nss_lookup_type) +
926                            sizeof(int), proto, size + 1);
927
928                res = NS_SUCCESS;
929                break;
930        default:
931                /* should be unreachable */
932                return (NS_UNAVAIL);
933        }
934
935fin:
936        *buffer_size = desired_size;
937        return (res);
938}
939
940int
941serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
942    void *cache_mdata)
943{
944        char *name;
945        char *proto;
946        int port;
947        struct servent *serv;
948        char *orig_buf;
949        size_t orig_buf_size;
950
951        struct servent new_serv;
952        size_t desired_size;
953        char **alias;
954        char *p;
955        size_t size;
956        size_t aliases_size;
957
958        switch ((enum nss_lookup_type)cache_mdata) {
959        case nss_lt_name:
960                name = va_arg(ap, char *);
961                proto = va_arg(ap, char *);
962                break;
963        case nss_lt_id:
964                port = va_arg(ap, int);
965                proto = va_arg(ap, char *);
966                break;
967        case nss_lt_all:
968                break;
969        default:
970                /* should be unreachable */
971                return (NS_UNAVAIL);
972        }
973
974        serv = va_arg(ap, struct servent *);
975        orig_buf = va_arg(ap, char *);
976        orig_buf_size = va_arg(ap, size_t);
977
978        desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
979        if (serv->s_name != NULL)
980                desired_size += strlen(serv->s_name) + 1;
981        if (serv->s_proto != NULL)
982                desired_size += strlen(serv->s_proto) + 1;
983
984        aliases_size = 0;
985        if (serv->s_aliases != NULL) {
986                for (alias = serv->s_aliases; *alias; ++alias) {
987                        desired_size += strlen(*alias) + 1;
988                        ++aliases_size;
989                }
990
991                desired_size += _ALIGNBYTES +
992                    sizeof(char *) * (aliases_size + 1);
993        }
994
995        if (*buffer_size < desired_size) {
996                /* this assignment is here for future use */
997                *buffer_size = desired_size;
998                return (NS_RETURN);
999        }
1000
1001        memcpy(&new_serv, serv, sizeof(struct servent));
1002        memset(buffer, 0, desired_size);
1003
1004        *buffer_size = desired_size;
1005        p = buffer + sizeof(struct servent) + sizeof(char *);
1006        memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
1007        p = (char *)_ALIGN(p);
1008
1009        if (new_serv.s_name != NULL) {
1010                size = strlen(new_serv.s_name);
1011                memcpy(p, new_serv.s_name, size);
1012                new_serv.s_name = p;
1013                p += size + 1;
1014        }
1015
1016        if (new_serv.s_proto != NULL) {
1017                size = strlen(new_serv.s_proto);
1018                memcpy(p, new_serv.s_proto, size);
1019                new_serv.s_proto = p;
1020                p += size + 1;
1021        }
1022
1023        if (new_serv.s_aliases != NULL) {
1024                p = (char *)_ALIGN(p);
1025                memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
1026                new_serv.s_aliases = (char **)p;
1027                p += sizeof(char *) * (aliases_size + 1);
1028
1029                for (alias = new_serv.s_aliases; *alias; ++alias) {
1030                        size = strlen(*alias);
1031                        memcpy(p, *alias, size);
1032                        *alias = p;
1033                        p += size + 1;
1034                }
1035        }
1036
1037        memcpy(buffer, &new_serv, sizeof(struct servent));
1038        return (NS_SUCCESS);
1039}
1040
1041int
1042serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
1043    void *cache_mdata)
1044{
1045        char *name;
1046        char *proto;
1047        int port;
1048        struct servent *serv;
1049        char *orig_buf;
1050        char *p;
1051        char **alias;
1052        size_t orig_buf_size;
1053        int *ret_errno;
1054
1055        switch ((enum nss_lookup_type)cache_mdata) {
1056        case nss_lt_name:
1057                name = va_arg(ap, char *);
1058                proto = va_arg(ap, char *);
1059                break;
1060        case nss_lt_id:
1061                port = va_arg(ap, int);
1062                proto = va_arg(ap, char *);
1063                break;
1064        case nss_lt_all:
1065                break;
1066        default:
1067                /* should be unreachable */
1068                return (NS_UNAVAIL);
1069        }
1070
1071        serv = va_arg(ap, struct servent *);
1072        orig_buf = va_arg(ap, char *);
1073        orig_buf_size = va_arg(ap, size_t);
1074        ret_errno = va_arg(ap, int *);
1075
1076        if (orig_buf_size <
1077            buffer_size - sizeof(struct servent) - sizeof(char *)) {
1078                *ret_errno = ERANGE;
1079                return (NS_RETURN);
1080        }
1081
1082        memcpy(serv, buffer, sizeof(struct servent));
1083        memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
1084
1085        orig_buf = (char *)_ALIGN(orig_buf);
1086        memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
1087            (_ALIGN(p) - (size_t)p),
1088            buffer_size - sizeof(struct servent) - sizeof(char *) -
1089            (_ALIGN(p) - (size_t)p));
1090        p = (char *)_ALIGN(p);
1091
1092        NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
1093        NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
1094        if (serv->s_aliases != NULL) {
1095                NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
1096
1097                for (alias = serv->s_aliases; *alias; ++alias)
1098                        NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
1099        }
1100
1101        if (retval != NULL)
1102                *((struct servent **)retval) = serv;
1103        return (NS_SUCCESS);
1104}
1105
1106NSS_MP_CACHE_HANDLING(services);
1107#endif /* NS_CACHING */
1108
1109/* get**_r functions implementation */
1110int
1111getservbyname_r(const char *name, const char *proto, struct servent *serv,
1112    char *buffer, size_t bufsize, struct servent **result)
1113{
1114        static const struct servent_mdata mdata = { nss_lt_name, 0 };
1115        static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
1116#ifdef NS_CACHING
1117        static const nss_cache_info cache_info =
1118        NS_COMMON_CACHE_INFO_INITIALIZER(
1119                services, (void *)nss_lt_name,
1120                serv_id_func, serv_marshal_func, serv_unmarshal_func);
1121#endif /* NS_CACHING */
1122        static const ns_dtab dtab[] = {
1123                { NSSRC_FILES, files_servent, (void *)&mdata },
1124                { NSSRC_DB, db_servent, (void *)nss_lt_name },
1125#ifdef YP
1126                { NSSRC_NIS, nis_servent, (void *)nss_lt_name },
1127#endif
1128                { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1129#ifdef NS_CACHING
1130                NS_CACHE_CB(&cache_info)
1131#endif
1132                { NULL, NULL, NULL }
1133        };
1134        int     rv, ret_errno;
1135
1136        ret_errno = 0;
1137        *result = NULL;
1138        rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
1139            defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
1140
1141        if (rv == NS_SUCCESS)
1142                return (0);
1143        else
1144                return (ret_errno);
1145}
1146
1147int
1148getservbyport_r(int port, const char *proto, struct servent *serv,
1149    char *buffer, size_t bufsize, struct servent **result)
1150{
1151        static const struct servent_mdata mdata = { nss_lt_id, 0 };
1152        static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
1153#ifdef NS_CACHING
1154        static const nss_cache_info cache_info =
1155        NS_COMMON_CACHE_INFO_INITIALIZER(
1156                services, (void *)nss_lt_id,
1157                serv_id_func, serv_marshal_func, serv_unmarshal_func);
1158#endif
1159        static const ns_dtab dtab[] = {
1160                { NSSRC_FILES, files_servent, (void *)&mdata },
1161                { NSSRC_DB, db_servent, (void *)nss_lt_id },
1162#ifdef YP
1163                { NSSRC_NIS, nis_servent, (void *)nss_lt_id },
1164#endif
1165                { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1166#ifdef NS_CACHING
1167                NS_CACHE_CB(&cache_info)
1168#endif
1169                { NULL, NULL, NULL }
1170        };
1171        int rv, ret_errno;
1172
1173        ret_errno = 0;
1174        *result = NULL;
1175        rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
1176            defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
1177
1178        if (rv == NS_SUCCESS)
1179                return (0);
1180        else
1181                return (ret_errno);
1182}
1183
1184int
1185getservent_r(struct servent *serv, char *buffer, size_t bufsize,
1186    struct servent **result)
1187{
1188        static const struct servent_mdata mdata = { nss_lt_all, 0 };
1189        static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
1190#ifdef NS_CACHING
1191        static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1192                services, (void *)nss_lt_all,
1193                serv_marshal_func, serv_unmarshal_func);
1194#endif
1195        static const ns_dtab dtab[] = {
1196                { NSSRC_FILES, files_servent, (void *)&mdata },
1197                { NSSRC_DB, db_servent, (void *)nss_lt_all },
1198#ifdef YP
1199                { NSSRC_NIS, nis_servent, (void *)nss_lt_all },
1200#endif
1201                { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1202#ifdef NS_CACHING
1203                NS_CACHE_CB(&cache_info)
1204#endif
1205                { NULL, NULL, NULL }
1206        };
1207        int rv, ret_errno;
1208
1209        ret_errno = 0;
1210        *result = NULL;
1211        rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
1212            defaultsrc, serv, buffer, bufsize, &ret_errno);
1213
1214        if (rv == NS_SUCCESS)
1215                return (0);
1216        else
1217                return (ret_errno);
1218}
1219
1220void
1221setservent(int stayopen)
1222{
1223#ifdef NS_CACHING
1224        static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1225                services, (void *)nss_lt_all,
1226                NULL, NULL);
1227#endif
1228        static const ns_dtab dtab[] = {
1229                { NSSRC_FILES, files_setservent, (void *)SETSERVENT },
1230                { NSSRC_DB, db_setservent, (void *)SETSERVENT },
1231#ifdef YP
1232                { NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
1233#endif
1234                { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
1235#ifdef NS_CACHING
1236                NS_CACHE_CB(&cache_info)
1237#endif
1238                { NULL, NULL, NULL }
1239        };
1240
1241        (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
1242            stayopen);
1243}
1244
1245void
1246endservent()
1247{
1248#ifdef NS_CACHING
1249        static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1250                services, (void *)nss_lt_all,
1251                NULL, NULL);
1252#endif
1253        static const ns_dtab dtab[] = {
1254                { NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
1255                { NSSRC_DB, db_setservent, (void *)ENDSERVENT },
1256#ifdef YP
1257                { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
1258#endif
1259                { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
1260#ifdef NS_CACHING
1261                NS_CACHE_CB(&cache_info)
1262#endif
1263                { NULL, NULL, NULL }
1264        };
1265
1266        (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
1267}
1268
1269/* get** wrappers for get**_r functions implementation */
1270static void
1271servent_endstate(void *p)
1272{
1273        if (p == NULL)
1274                return;
1275
1276        free(((struct servent_state *)p)->buffer);
1277        free(p);
1278}
1279
1280static int
1281wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
1282    size_t bufsize, struct servent **res)
1283{
1284        return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
1285            res));
1286}
1287
1288static int
1289wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
1290    size_t bufsize, struct servent **res)
1291{
1292        return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
1293            res));
1294}
1295
1296static  int
1297wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
1298    size_t bufsize, struct servent **res)
1299{
1300        return (getservent_r(serv, buffer, bufsize, res));
1301}
1302
1303static struct servent *
1304getserv(int (*fn)(struct key, struct servent *, char *, size_t,
1305    struct servent **), struct key key)
1306{
1307        int rv;
1308        struct servent *res;
1309        struct servent_state * st;
1310
1311        rv = servent_getstate(&st);
1312        if (rv != 0) {
1313                errno = rv;
1314                return NULL;
1315        }
1316
1317        if (st->buffer == NULL) {
1318                st->buffer = malloc(SERVENT_STORAGE_INITIAL);
1319                if (st->buffer == NULL)
1320                        return (NULL);
1321                st->bufsize = SERVENT_STORAGE_INITIAL;
1322        }
1323        do {
1324                rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
1325                if (res == NULL && rv == ERANGE) {
1326                        free(st->buffer);
1327                        if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
1328                                st->buffer = NULL;
1329                                errno = ERANGE;
1330                                return (NULL);
1331                        }
1332                        st->bufsize <<= 1;
1333                        st->buffer = malloc(st->bufsize);
1334                        if (st->buffer == NULL)
1335                                return (NULL);
1336                }
1337        } while (res == NULL && rv == ERANGE);
1338        if (rv != 0)
1339                errno = rv;
1340
1341        return (res);
1342}
1343
1344struct servent *
1345getservbyname(const char *name, const char *proto)
1346{
1347        struct key key;
1348
1349        key.name = name;
1350        key.proto = proto;
1351
1352        return (getserv(wrap_getservbyname_r, key));
1353}
1354
1355struct servent *
1356getservbyport(int port, const char *proto)
1357{
1358        struct key key;
1359
1360        key.port = port;
1361        key.proto = proto;
1362
1363        return (getserv(wrap_getservbyport_r, key));
1364}
1365
1366struct servent *
1367getservent()
1368{
1369        struct key key;
1370
1371        key.proto = NULL;
1372        key.port = 0;
1373
1374        return (getserv(wrap_getservent_r, key));
1375}
Note: See TracBrowser for help on using the repository browser.