2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #if defined(LIBC_SCCS) && !defined(lint)
31 static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93";
32 #endif /* LIBC_SCCS and not lint */
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <arpa/inet.h>
50 #include <rpcsvc/yp_prot.h>
51 #include <rpcsvc/ypclnt.h>
53 #include "namespace.h"
54 #include "reentrant.h"
55 #include "un-namespace.h"
56 #include "netdb_private.h"
66 SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
67 SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
72 enum nss_lookup_type how;
76 static const ns_src defaultsrc[] = {
77 { NSSRC_COMPAT, NS_SUCCESS },
81 static int servent_unpack(char *, struct servent *, char **, size_t, int *);
83 /* files backend declarations */
89 int compat_mode_active;
91 static void files_endstate(void *);
92 NSS_TLS_HANDLING(files);
94 static int files_servent(void *, void *, va_list);
95 static int files_setservent(void *, void *, va_list);
98 /* nis backend declarations */
99 static int nis_servent(void *, void *, va_list);
100 static int nis_setservent(void *, void *, va_list);
105 char yp_domain[MAXHOSTNAMELEN];
109 static void nis_endstate(void *);
110 NSS_TLS_HANDLING(nis);
112 static int nis_servent(void *, void *, va_list);
113 static int nis_setservent(void *, void *, va_list);
116 /* compat backend declarations */
117 static int compat_setservent(void *, void *, va_list);
119 /* get** wrappers for get**_r functions declarations */
120 struct servent_state {
125 static void servent_endstate(void *);
126 NSS_TLS_HANDLING(servent);
136 static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
138 static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
140 static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
142 static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
143 size_t, struct servent **), struct key);
146 static int serv_id_func(char *, size_t *, va_list, void *);
147 static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
148 static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
152 servent_unpack(char *p, struct servent *serv, char **aliases,
153 size_t aliases_size, int *errnop)
155 char *cp, **q, *endp;
161 memset(serv, 0, sizeof(struct servent));
163 cp = strpbrk(p, "#\n");
168 p = strpbrk(p, " \t");
172 while (*p == ' ' || *p == '\t')
174 cp = strpbrk(p, ",/");
179 l = strtol(p, &endp, 10);
180 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
182 serv->s_port = htons((in_port_t)l);
185 q = serv->s_aliases = aliases;
186 cp = strpbrk(cp, " \t");
190 if (*cp == ' ' || *cp == '\t') {
194 if (q < &aliases[aliases_size - 1]) {
201 cp = strpbrk(cp, " \t");
210 /* files backend implementation */
212 files_endstate(void *p)
219 f = ((struct files_state *)p)->fp;
227 * compat structures. compat and files sources functionalities are almost
228 * equal, so they all are managed by files_servent function
231 files_servent(void *retval, void *mdata, va_list ap)
233 static const ns_src compat_src[] = {
235 { NSSRC_NIS, NS_SUCCESS },
239 ns_dtab compat_dtab[] = {
241 { NSSRC_NIS, nis_servent,
242 (void *)((struct servent_mdata *)mdata)->how },
247 struct files_state *st;
251 struct servent_mdata *serv_mdata;
256 struct servent *serv;
269 serv_mdata = (struct servent_mdata *)mdata;
270 switch (serv_mdata->how) {
272 name = va_arg(ap, char *);
273 proto = va_arg(ap, char *);
276 port = va_arg(ap, int);
277 proto = va_arg(ap, char *);
285 serv = va_arg(ap, struct servent *);
286 buffer = va_arg(ap, char *);
287 bufsize = va_arg(ap, size_t);
288 errnop = va_arg(ap,int *);
290 *errnop = files_getstate(&st);
295 st->compat_mode_active = 0;
297 if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "r")) == NULL) {
302 if (serv_mdata->how == nss_lt_all)
306 stayopen = st->stayopen;
311 if (!st->compat_mode_active) {
312 if ((line = fgetln(st->fp, &linesize)) == NULL) {
319 if (serv_mdata->compat_mode != 0)
320 st->compat_mode_active = 1;
322 if (bufsize <= linesize + _ALIGNBYTES +
328 aliases = (char **)_ALIGN(&buffer[linesize+1]);
329 aliases_size = (buffer + bufsize -
330 (char *)aliases) / sizeof(char *);
331 if (aliases_size < 1) {
337 memcpy(buffer, line, linesize);
338 buffer[linesize] = '\0';
342 if (st->compat_mode_active != 0) {
343 switch (serv_mdata->how) {
345 rv = nsdispatch(retval, compat_dtab,
346 NSDB_SERVICES_COMPAT, "getservbyname_r",
347 compat_src, name, proto, serv, buffer,
351 rv = nsdispatch(retval, compat_dtab,
352 NSDB_SERVICES_COMPAT, "getservbyport_r",
353 compat_src, port, proto, serv, buffer,
357 rv = nsdispatch(retval, compat_dtab,
358 NSDB_SERVICES_COMPAT, "getservent_r",
359 compat_src, serv, buffer, bufsize, errnop);
363 if (!(rv & NS_TERMINATE) ||
364 serv_mdata->how != nss_lt_all)
365 st->compat_mode_active = 0;
370 rv = servent_unpack(buffer, serv, aliases, aliases_size,
384 switch (serv_mdata->how) {
386 if (strcmp(name, serv->s_name) == 0)
388 for (cp = serv->s_aliases; *cp; cp++)
389 if (strcmp(name, *cp) == 0)
394 if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
398 if (port != serv->s_port)
401 if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
409 } while (!(rv & NS_TERMINATE));
411 if (!stayopen && st->fp != NULL) {
416 if ((rv == NS_SUCCESS) && (retval != NULL))
417 *(struct servent **)retval=serv;
423 files_setservent(void *retval, void *mdata, va_list ap)
425 struct files_state *st;
429 rv = files_getstate(&st);
433 switch ((enum constants)mdata) {
437 st->fp = fopen(_PATH_SERVICES, "r");
443 if (st->fp != NULL) {
453 st->compat_mode_active = 0;
457 /* nis backend implementation */
460 nis_endstate(void *p)
465 free(((struct nis_state *)p)->yp_key);
470 nis_servent(void *retval, void *mdata, va_list ap)
472 char *resultbuf, *lastkey;
474 char buf[YPMAXRECORD + 2];
476 struct nis_state *st;
479 enum nss_lookup_type how;
484 struct servent *serv;
494 how = (enum nss_lookup_type)mdata;
497 name = va_arg(ap, char *);
498 proto = va_arg(ap, char *);
501 port = va_arg(ap, int);
502 proto = va_arg(ap, char *);
510 serv = va_arg(ap, struct servent *);
511 buffer = va_arg(ap, char *);
512 bufsize = va_arg(ap, size_t);
513 errnop = va_arg(ap, int *);
515 *errnop = nis_getstate(&st);
519 if (st->yp_domain[0] == '\0') {
520 if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
529 snprintf(buf, sizeof(buf), "%s/%s", name, proto);
530 if (yp_match(st->yp_domain, "services.byname", buf,
531 strlen(buf), &resultbuf, &resultbuflen)) {
537 snprintf(buf, sizeof(buf), "%d/%s", ntohs(port),
541 * We have to be a little flexible
542 * here. Ideally you're supposed to have both
543 * a services.byname and a services.byport
544 * map, but some systems have only
545 * services.byname. FreeBSD cheats a little by
546 * putting the services.byport information in
547 * the same map as services.byname so that
548 * either case will work. We allow for both
549 * possibilities here: if there is no
550 * services.byport map, we try services.byname
553 rv = yp_match(st->yp_domain, "services.byport", buf,
554 strlen(buf), &resultbuf, &resultbuflen);
556 if (rv == YPERR_MAP) {
557 if (yp_match(st->yp_domain,
558 "services.byname", buf,
559 strlen(buf), &resultbuf,
572 if (!st->yp_stepping) {
574 rv = yp_first(st->yp_domain, "services.byname",
575 &st->yp_key, &st->yp_keylen, &resultbuf,
583 lastkey = st->yp_key;
584 rv = yp_next(st->yp_domain, "services.byname",
585 st->yp_key, st->yp_keylen, &st->yp_key,
586 &st->yp_keylen, &resultbuf, &resultbuflen);
597 /* we need a room for additional \n symbol */
599 resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) {
605 aliases = (char **)_ALIGN(&buffer[resultbuflen + 2]);
607 (buffer + bufsize - (char *)aliases) / sizeof(char *);
608 if (aliases_size < 1) {
615 * servent_unpack expects lines terminated with \n --
618 memcpy(buffer, resultbuf, resultbuflen);
619 buffer[resultbuflen] = '\n';
620 buffer[resultbuflen + 1] = '\0';
622 if (servent_unpack(buffer, serv, aliases, aliases_size,
632 } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
635 if (rv == NS_SUCCESS && retval != NULL)
636 *(struct servent **)retval = serv;
642 nis_setservent(void *result, void *mdata, va_list ap)
644 struct nis_state *st;
647 rv = nis_getstate(&st);
651 switch ((enum constants)mdata) {
666 /* compat backend implementation */
668 compat_setservent(void *retval, void *mdata, va_list ap)
670 static const ns_src compat_src[] = {
672 { NSSRC_NIS, NS_SUCCESS },
676 ns_dtab compat_dtab[] = {
678 { NSSRC_NIS, nis_setservent, mdata },
684 (void)files_setservent(retval, mdata, ap);
686 switch ((enum constants)mdata) {
689 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
690 "setservent", compat_src, f);
693 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
694 "endservent", compat_src);
705 serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
711 size_t desired_size, size, size2;
712 enum nss_lookup_type lookup_type;
713 int res = NS_UNAVAIL;
715 lookup_type = (enum nss_lookup_type)cache_mdata;
716 switch (lookup_type) {
718 name = va_arg(ap, char *);
719 proto = va_arg(ap, char *);
722 desired_size = sizeof(enum nss_lookup_type) + size + 1;
724 size2 = strlen(proto);
725 desired_size += size2 + 1;
729 if (desired_size > *buffer_size) {
734 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
735 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
738 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
744 port = va_arg(ap, int);
745 proto = va_arg(ap, char *);
747 desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
749 size = strlen(proto);
750 desired_size += size + 1;
754 if (desired_size > *buffer_size) {
759 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
760 memcpy(buffer + sizeof(enum nss_lookup_type), &port,
764 memcpy(buffer + sizeof(enum nss_lookup_type) +
765 sizeof(int), proto, size + 1);
770 /* should be unreachable */
775 *buffer_size = desired_size;
780 serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
786 struct servent *serv;
788 size_t orig_buf_size;
790 struct servent new_serv;
797 switch ((enum nss_lookup_type)cache_mdata) {
799 name = va_arg(ap, char *);
800 proto = va_arg(ap, char *);
803 port = va_arg(ap, int);
804 proto = va_arg(ap, char *);
809 /* should be unreachable */
813 serv = va_arg(ap, struct servent *);
814 orig_buf = va_arg(ap, char *);
815 orig_buf_size = va_arg(ap, size_t);
817 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
818 if (serv->s_name != NULL)
819 desired_size += strlen(serv->s_name) + 1;
820 if (serv->s_proto != NULL)
821 desired_size += strlen(serv->s_proto) + 1;
824 if (serv->s_aliases != NULL) {
825 for (alias = serv->s_aliases; *alias; ++alias) {
826 desired_size += strlen(*alias) + 1;
830 desired_size += _ALIGNBYTES +
831 sizeof(char *) * (aliases_size + 1);
834 if (*buffer_size < desired_size) {
835 /* this assignment is here for future use */
836 *buffer_size = desired_size;
840 memcpy(&new_serv, serv, sizeof(struct servent));
841 memset(buffer, 0, desired_size);
843 *buffer_size = desired_size;
844 p = buffer + sizeof(struct servent) + sizeof(char *);
845 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
846 p = (char *)_ALIGN(p);
848 if (new_serv.s_name != NULL) {
849 size = strlen(new_serv.s_name);
850 memcpy(p, new_serv.s_name, size);
855 if (new_serv.s_proto != NULL) {
856 size = strlen(new_serv.s_proto);
857 memcpy(p, new_serv.s_proto, size);
858 new_serv.s_proto = p;
862 if (new_serv.s_aliases != NULL) {
863 p = (char *)_ALIGN(p);
864 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
865 new_serv.s_aliases = (char **)p;
866 p += sizeof(char *) * (aliases_size + 1);
868 for (alias = new_serv.s_aliases; *alias; ++alias) {
869 size = strlen(*alias);
870 memcpy(p, *alias, size);
876 memcpy(buffer, &new_serv, sizeof(struct servent));
881 serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
887 struct servent *serv;
891 size_t orig_buf_size;
894 switch ((enum nss_lookup_type)cache_mdata) {
896 name = va_arg(ap, char *);
897 proto = va_arg(ap, char *);
900 port = va_arg(ap, int);
901 proto = va_arg(ap, char *);
906 /* should be unreachable */
910 serv = va_arg(ap, struct servent *);
911 orig_buf = va_arg(ap, char *);
912 orig_buf_size = va_arg(ap, size_t);
913 ret_errno = va_arg(ap, int *);
916 buffer_size - sizeof(struct servent) - sizeof(char *)) {
921 memcpy(serv, buffer, sizeof(struct servent));
922 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
924 orig_buf = (char *)_ALIGN(orig_buf);
925 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
926 (_ALIGN(p) - (size_t)p),
927 buffer_size - sizeof(struct servent) - sizeof(char *) -
928 (_ALIGN(p) - (size_t)p));
929 p = (char *)_ALIGN(p);
931 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
932 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
933 if (serv->s_aliases != NULL) {
934 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
936 for (alias = serv->s_aliases; *alias; ++alias)
937 NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
941 *((struct servent **)retval) = serv;
945 NSS_MP_CACHE_HANDLING(services);
946 #endif /* NS_CACHING */
948 /* get**_r functions implementation */
950 getservbyname_r(const char *name, const char *proto, struct servent *serv,
951 char *buffer, size_t bufsize, struct servent **result)
953 static const struct servent_mdata mdata = { nss_lt_name, 0 };
954 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
956 static const nss_cache_info cache_info =
957 NS_COMMON_CACHE_INFO_INITIALIZER(
958 services, (void *)nss_lt_name,
959 serv_id_func, serv_marshal_func, serv_unmarshal_func);
960 #endif /* NS_CACHING */
961 static const ns_dtab dtab[] = {
962 { NSSRC_FILES, files_servent, (void *)&mdata },
964 { NSSRC_NIS, nis_servent, (void *)nss_lt_name },
966 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
968 NS_CACHE_CB(&cache_info)
976 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
977 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
979 if (rv == NS_SUCCESS)
986 getservbyport_r(int port, const char *proto, struct servent *serv,
987 char *buffer, size_t bufsize, struct servent **result)
989 static const struct servent_mdata mdata = { nss_lt_id, 0 };
990 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
992 static const nss_cache_info cache_info =
993 NS_COMMON_CACHE_INFO_INITIALIZER(
994 services, (void *)nss_lt_id,
995 serv_id_func, serv_marshal_func, serv_unmarshal_func);
997 static const ns_dtab dtab[] = {
998 { NSSRC_FILES, files_servent, (void *)&mdata },
1000 { NSSRC_NIS, nis_servent, (void *)nss_lt_id },
1002 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1004 NS_CACHE_CB(&cache_info)
1006 { NULL, NULL, NULL }
1012 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
1013 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
1015 if (rv == NS_SUCCESS)
1022 getservent_r(struct servent *serv, char *buffer, size_t bufsize,
1023 struct servent **result)
1025 static const struct servent_mdata mdata = { nss_lt_all, 0 };
1026 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
1028 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1029 services, (void *)nss_lt_all,
1030 serv_marshal_func, serv_unmarshal_func);
1032 static const ns_dtab dtab[] = {
1033 { NSSRC_FILES, files_servent, (void *)&mdata },
1035 { NSSRC_NIS, nis_servent, (void *)nss_lt_all },
1037 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1039 NS_CACHE_CB(&cache_info)
1041 { NULL, NULL, NULL }
1047 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
1048 defaultsrc, serv, buffer, bufsize, &ret_errno);
1050 if (rv == NS_SUCCESS)
1057 setservent(int stayopen)
1060 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1061 services, (void *)nss_lt_all,
1064 static const ns_dtab dtab[] = {
1065 { NSSRC_FILES, files_setservent, (void *)SETSERVENT },
1067 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
1069 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
1071 NS_CACHE_CB(&cache_info)
1073 { NULL, NULL, NULL }
1076 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
1084 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1085 services, (void *)nss_lt_all,
1088 static const ns_dtab dtab[] = {
1089 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
1091 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
1093 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
1095 NS_CACHE_CB(&cache_info)
1097 { NULL, NULL, NULL }
1100 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
1103 /* get** wrappers for get**_r functions implementation */
1105 servent_endstate(void *p)
1110 free(((struct servent_state *)p)->buffer);
1115 wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
1116 size_t bufsize, struct servent **res)
1118 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
1123 wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
1124 size_t bufsize, struct servent **res)
1126 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
1131 wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
1132 size_t bufsize, struct servent **res)
1134 return (getservent_r(serv, buffer, bufsize, res));
1137 static struct servent *
1138 getserv(int (*fn)(struct key, struct servent *, char *, size_t,
1139 struct servent **), struct key key)
1142 struct servent *res;
1143 struct servent_state * st;
1145 rv = servent_getstate(&st);
1151 if (st->buffer == NULL) {
1152 st->buffer = malloc(SERVENT_STORAGE_INITIAL);
1153 if (st->buffer == NULL)
1155 st->bufsize = SERVENT_STORAGE_INITIAL;
1158 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
1159 if (res == NULL && rv == ERANGE) {
1161 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
1167 st->buffer = malloc(st->bufsize);
1168 if (st->buffer == NULL)
1171 } while (res == NULL && rv == ERANGE);
1179 getservbyname(const char *name, const char *proto)
1186 return (getserv(wrap_getservbyname_r, key));
1190 getservbyport(int port, const char *proto)
1197 return (getserv(wrap_getservbyport_r, key));
1208 return (getserv(wrap_getservent_r, key));