xref: /freebsd/lib/libc/net/getprotoent.c (revision d3ac2b30d40b8257bbf8680487708e05e3de8ea7)
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[] = "@(#)getprotoent.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/param.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <errno.h>
44 #include <limits.h>
45 #include <netdb.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "namespace.h"
50 #include "reentrant.h"
51 #include "un-namespace.h"
52 #include "netdb_private.h"
53 
54 NETDB_THREAD_ALLOC(protoent_data)
55 NETDB_THREAD_ALLOC(protodata)
56 
57 static void
58 protoent_data_clear(struct protoent_data *ped)
59 {
60 	if (ped->fp) {
61 		fclose(ped->fp);
62 		ped->fp = NULL;
63 	}
64 }
65 
66 static void
67 protoent_data_free(void *ptr)
68 {
69 	struct protoent_data *ped = ptr;
70 
71 	protoent_data_clear(ped);
72 	free(ped);
73 }
74 
75 static void
76 protodata_free(void *ptr)
77 {
78 	free(ptr);
79 }
80 
81 int
82 __copy_protoent(struct protoent *pe, struct protoent *pptr, char *buf,
83     size_t buflen)
84 {
85 	char *cp;
86 	int i, n;
87 	int numptr, len;
88 
89 	/* Find out the amount of space required to store the answer. */
90 	numptr = 1; /* NULL ptr */
91 	len = (char *)ALIGN(buf) - buf;
92 	for (i = 0; pe->p_aliases[i]; i++, numptr++) {
93 		len += strlen(pe->p_aliases[i]) + 1;
94 	}
95 	len += strlen(pe->p_name) + 1;
96 	len += numptr * sizeof(char*);
97 
98 	if (len > (int)buflen) {
99 		errno = ERANGE;
100 		return (-1);
101 	}
102 
103 	/* copy protocol value*/
104 	pptr->p_proto = pe->p_proto;
105 
106 	cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
107 
108 	/* copy official name */
109 	n = strlen(pe->p_name) + 1;
110 	strcpy(cp, pe->p_name);
111 	pptr->p_name = cp;
112 	cp += n;
113 
114 	/* copy aliases */
115 	pptr->p_aliases = (char **)ALIGN(buf);
116 	for (i = 0 ; pe->p_aliases[i]; i++) {
117 		n = strlen(pe->p_aliases[i]) + 1;
118 		strcpy(cp, pe->p_aliases[i]);
119 		pptr->p_aliases[i] = cp;
120 		cp += n;
121 	}
122 	pptr->p_aliases[i] = NULL;
123 
124 	return (0);
125 }
126 
127 void
128 __setprotoent_p(int f, struct protoent_data *ped)
129 {
130 	if (ped->fp == NULL)
131 		ped->fp = fopen(_PATH_PROTOCOLS, "r");
132 	else
133 		rewind(ped->fp);
134 	ped->stayopen |= f;
135 }
136 
137 void
138 __endprotoent_p(struct protoent_data *ped)
139 {
140 	if (ped->fp) {
141 		fclose(ped->fp);
142 		ped->fp = NULL;
143 	}
144 	ped->stayopen = 0;
145 }
146 
147 int
148 __getprotoent_p(struct protoent *pe, struct protoent_data *ped)
149 {
150 	char *p;
151 	char *cp, **q, *endp;
152 	long l;
153 
154 	if (ped->fp == NULL && (ped->fp = fopen(_PATH_PROTOCOLS, "r")) == NULL)
155 		return (-1);
156 again:
157 	if ((p = fgets(ped->line, sizeof ped->line, ped->fp)) == NULL)
158 		return (-1);
159 	if (*p == '#')
160 		goto again;
161 	cp = strpbrk(p, "#\n");
162 	if (cp != NULL)
163 		*cp = '\0';
164 	pe->p_name = p;
165 	cp = strpbrk(p, " \t");
166 	if (cp == NULL)
167 		goto again;
168 	*cp++ = '\0';
169 	while (*cp == ' ' || *cp == '\t')
170 		cp++;
171 	p = strpbrk(cp, " \t");
172 	if (p != NULL)
173 		*p++ = '\0';
174 	l = strtol(cp, &endp, 10);
175 	if (endp == cp || *endp != '\0' || l < 0 || l > USHRT_MAX)
176 		goto again;
177 	pe->p_proto = l;
178 	q = pe->p_aliases = ped->aliases;
179 	if (p != NULL) {
180 		cp = p;
181 		while (cp && *cp) {
182 			if (*cp == ' ' || *cp == '\t') {
183 				cp++;
184 				continue;
185 			}
186 			if (q < &ped->aliases[_MAXALIASES - 1])
187 				*q++ = cp;
188 			cp = strpbrk(cp, " \t");
189 			if (cp != NULL)
190 				*cp++ = '\0';
191 		}
192 	}
193 	*q = NULL;
194 	return (0);
195 }
196 
197 int
198 getprotoent_r(struct protoent *pptr, char *buffer, size_t buflen,
199     struct protoent **result)
200 {
201 	struct protoent pe;
202 	struct protoent_data *ped;
203 
204 	if ((ped = __protoent_data_init()) == NULL)
205 		return (-1);
206 
207 	if (__getprotoent_p(&pe, ped) != 0)
208 		return (-1);
209 	if (__copy_protoent(&pe, pptr, buffer, buflen) != 0)
210 		return (-1);
211 	*result = pptr;
212 	return (0);
213 }
214 
215 void
216 setprotoent(int f)
217 {
218 	struct protoent_data *ped;
219 
220 	if ((ped = __protoent_data_init()) == NULL)
221 		return;
222 	__setprotoent_p(f, ped);
223 }
224 
225 void
226 endprotoent(void)
227 {
228 	struct protoent_data *ped;
229 
230 	if ((ped = __protoent_data_init()) == NULL)
231 		return;
232 	__endprotoent_p(ped);
233 }
234 
235 struct protoent *
236 getprotoent(void)
237 {
238 	struct protodata *pd;
239 	struct protoent *rval;
240 
241 	if ((pd = __protodata_init()) == NULL)
242 		return (NULL);
243 	if (getprotoent_r(&pd->proto, pd->data, sizeof(pd->data), &rval) != 0)
244 		return (NULL);
245 	return (rval);
246 }
247