xref: /freebsd/lib/libc/net/getservent.c (revision 6780ab54325a71e7e70112b11657973edde8655e)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  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
7  * are met:
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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)getservent.c	8.1 (Berkeley) 6/4/93";
36 #endif /* LIBC_SCCS and not lint */
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #ifdef YP
48 #include <rpc/rpc.h>
49 #include <rpcsvc/yp_prot.h>
50 #include <rpcsvc/ypclnt.h>
51 static int serv_stepping_yp = 0;
52 extern int _yp_check( char ** );
53 #endif
54 
55 
56 #define	MAXALIASES	35
57 
58 static FILE *servf = NULL;
59 static char line[BUFSIZ+1];
60 static struct servent serv;
61 static char *serv_aliases[MAXALIASES];
62 int _serv_stayopen;
63 
64 #ifdef YP
65 char *___getservbyname_yp = NULL;
66 char *___getservbyproto_yp = NULL;
67 int ___getservbyport_yp = 0;
68 static char *yp_domain = NULL;
69 
70 static int
71 _getservbyport_yp(line)
72 	char *line;
73 {
74 	char *result;
75 	int resultlen;
76 	char buf[YPMAXRECORD + 2];
77 	int rv;
78 
79 	snprintf(buf, sizeof(buf), "%d/%s", ntohs(___getservbyport_yp),
80 						___getservbyproto_yp);
81 
82 	___getservbyport_yp = 0;
83 	___getservbyproto_yp = NULL;
84 
85 	if(!yp_domain) {
86 		if(yp_get_default_domain(&yp_domain))
87 			return (0);
88 	}
89 
90 	/*
91 	 * We have to be a little flexible here. Ideally you're supposed
92 	 * to have both a services.byname and a services.byport map, but
93 	 * some systems have only services.byname. FreeBSD cheats a little
94 	 * by putting the services.byport information in the same map as
95 	 * services.byname so that either case will work. We allow for both
96 	 * possibilities here: if there is no services.byport map, we try
97 	 * services.byname instead.
98 	 */
99 	if ((rv = yp_match(yp_domain, "services.byport", buf, strlen(buf),
100 						&result, &resultlen))) {
101 		if (rv == YPERR_MAP) {
102 			if (yp_match(yp_domain, "services.byname", buf,
103 					strlen(buf), &result, &resultlen))
104 			return(0);
105 		} else
106 			return(0);
107 	}
108 
109 	/* getservent() expects lines terminated with \n -- make it happy */
110 	snprintf(line, BUFSIZ, "%.*s\n", resultlen, result);
111 
112 	free(result);
113 	return(1);
114 }
115 
116 static int
117 _getservbyname_yp(line)
118 	char *line;
119 {
120 	char *result;
121 	int resultlen;
122 	char buf[YPMAXRECORD + 2];
123 
124 	if(!yp_domain) {
125 		if(yp_get_default_domain(&yp_domain))
126 			return (0);
127 	}
128 
129 	snprintf(buf, sizeof(buf), "%s/%s", ___getservbyname_yp,
130 						___getservbyproto_yp);
131 
132 	___getservbyname_yp = 0;
133 	___getservbyproto_yp = NULL;
134 
135 	if (yp_match(yp_domain, "services.byname", buf, strlen(buf),
136 						&result, &resultlen)) {
137 		return(0);
138 	}
139 
140 	/* getservent() expects lines terminated with \n -- make it happy */
141 	snprintf(line, BUFSIZ, "%.*s\n", resultlen, result);
142 
143 	free(result);
144 	return(1);
145 }
146 
147 static int
148 _getservent_yp(line)
149 	char *line;
150 {
151 	static char *key = NULL;
152 	static int keylen;
153 	char *lastkey, *result;
154 	int resultlen;
155 	int rv;
156 
157 	if(!yp_domain) {
158 		if(yp_get_default_domain(&yp_domain))
159 			return (0);
160 	}
161 
162 	if (!serv_stepping_yp) {
163 		if (key)
164 			free(key);
165 		if ((rv = yp_first(yp_domain, "services.byname", &key, &keylen,
166 			     &result, &resultlen))) {
167 			serv_stepping_yp = 0;
168 			return(0);
169 		}
170 		serv_stepping_yp = 1;
171 	} else {
172 		lastkey = key;
173 		rv = yp_next(yp_domain, "services.byname", key, keylen, &key,
174 			     &keylen, &result, &resultlen);
175 		free(lastkey);
176 		if (rv) {
177 			serv_stepping_yp = 0;
178 			return (0);
179 		}
180 	}
181 
182 	/* getservent() expects lines terminated with \n -- make it happy */
183 	snprintf(line, BUFSIZ, "%.*s\n", resultlen, result);
184 
185 	free(result);
186 
187 	return(1);
188 }
189 #endif
190 
191 void
192 setservent(f)
193 	int f;
194 {
195 	if (servf == NULL)
196 		servf = fopen(_PATH_SERVICES, "r" );
197 	else
198 		rewind(servf);
199 	_serv_stayopen |= f;
200 }
201 
202 void
203 endservent()
204 {
205 	if (servf) {
206 		fclose(servf);
207 		servf = NULL;
208 	}
209 	_serv_stayopen = 0;
210 }
211 
212 struct servent *
213 getservent()
214 {
215 	char *p;
216 	char *cp, **q;
217 
218 #ifdef YP
219 	if (serv_stepping_yp && _getservent_yp(line)) {
220 		p = (char *)&line;
221 		goto unpack;
222 	}
223 tryagain:
224 #endif
225 	if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL)
226 		return (NULL);
227 again:
228 	if ((p = fgets(line, BUFSIZ, servf)) == NULL)
229 		return (NULL);
230 #ifdef YP
231 	if (*p == '+' && _yp_check(NULL)) {
232 		if (___getservbyname_yp != NULL) {
233 			if (!_getservbyname_yp(line))
234 				goto tryagain;
235 		}
236 		else if (___getservbyport_yp != 0) {
237 			if (!_getservbyport_yp(line))
238 				goto tryagain;
239 		}
240 		else if (!_getservent_yp(line))
241 			goto tryagain;
242 	}
243 unpack:
244 #endif
245 	if (*p == '#')
246 		goto again;
247 	cp = strpbrk(p, "#\n");
248 	if (cp == NULL)
249 		goto again;
250 	*cp = '\0';
251 	serv.s_name = p;
252 	p = strpbrk(p, " \t");
253 	if (p == NULL)
254 		goto again;
255 	*p++ = '\0';
256 	while (*p == ' ' || *p == '\t')
257 		p++;
258 	cp = strpbrk(p, ",/");
259 	if (cp == NULL)
260 		goto again;
261 	*cp++ = '\0';
262 	serv.s_port = htons((u_short)atoi(p));
263 	serv.s_proto = cp;
264 	q = serv.s_aliases = serv_aliases;
265 	cp = strpbrk(cp, " \t");
266 	if (cp != NULL)
267 		*cp++ = '\0';
268 	while (cp && *cp) {
269 		if (*cp == ' ' || *cp == '\t') {
270 			cp++;
271 			continue;
272 		}
273 		if (q < &serv_aliases[MAXALIASES - 1])
274 			*q++ = cp;
275 		cp = strpbrk(cp, " \t");
276 		if (cp != NULL)
277 			*cp++ = '\0';
278 	}
279 	*q = NULL;
280 	return (&serv);
281 }
282