xref: /dragonfly/lib/libc/net/getprotoent.c (revision e97a1dae)
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. 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.
16  *
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
27  * SUCH DAMAGE.
28  *
29  * @(#)getprotoent.c	8.1 (Berkeley) 6/4/93
30  * $FreeBSD: src/lib/libc/net/getprotoent.c,v 1.9 2007/01/09 00:28:02 imp Exp $
31  */
32 
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <nsswitch.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "namespace.h"
44 #include "reentrant.h"
45 #include "un-namespace.h"
46 #include "netdb_private.h"
47 #ifdef NS_CACHING
48 #include "nscache.h"
49 #endif
50 #include "nss_tls.h"
51 
52 static const ns_src defaultsrc[] = {
53 	{ NSSRC_FILES, NS_SUCCESS },
54 	{ NULL, 0 }
55 };
56 
57 NETDB_THREAD_ALLOC(protoent_data)
58 NETDB_THREAD_ALLOC(protodata)
59 
60 static void
61 protoent_data_clear(struct protoent_data *ped)
62 {
63 	if (ped->fp) {
64 		fclose(ped->fp);
65 		ped->fp = NULL;
66 	}
67 }
68 
69 static void
70 protoent_data_free(void *ptr)
71 {
72 	struct protoent_data *ped = ptr;
73 
74 	protoent_data_clear(ped);
75 	free(ped);
76 }
77 
78 static void
79 protodata_free(void *ptr)
80 {
81 	free(ptr);
82 }
83 
84 #ifdef NS_CACHING
85 int
86 __proto_id_func(char *buffer, size_t *buffer_size, va_list ap,
87     void *cache_mdata)
88 {
89 	char *name;
90 	int proto;
91 
92 	size_t desired_size, size;
93 	enum nss_lookup_type lookup_type;
94 	int res = NS_UNAVAIL;
95 
96 	lookup_type = (enum nss_lookup_type)cache_mdata;
97 	switch (lookup_type) {
98 	case nss_lt_name:
99 		name = va_arg(ap, char *);
100 
101 		size = strlen(name);
102 		desired_size = sizeof(enum nss_lookup_type) + size + 1;
103 		if (desired_size > *buffer_size) {
104 			res = NS_RETURN;
105 			goto fin;
106 		}
107 
108 		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
109 		memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
110 
111 		res = NS_SUCCESS;
112 		break;
113 	case nss_lt_id:
114 		proto = va_arg(ap, int);
115 
116 		desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
117 		if (desired_size > *buffer_size) {
118 			res = NS_RETURN;
119 			goto fin;
120 		}
121 
122 		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
123 		memcpy(buffer + sizeof(enum nss_lookup_type), &proto,
124 			sizeof(int));
125 
126 		res = NS_SUCCESS;
127 		break;
128 	default:
129 		/* should be unreachable */
130 		return (NS_UNAVAIL);
131 	}
132 
133 fin:
134 	*buffer_size = desired_size;
135 	return (res);
136 }
137 
138 
139 int
140 __proto_marshal_func(char *buffer, size_t *buffer_size, void *retval __unused,
141     va_list ap, void *cache_mdata)
142 {
143 	char *name __unused;
144 	int num __unused;
145 	struct protoent *proto;
146 	char *orig_buf __unused;
147 	size_t orig_buf_size __unused;
148 
149 	struct protoent new_proto;
150 	size_t desired_size, size, aliases_size;
151 	char *p;
152 	char **alias;
153 
154 	switch ((enum nss_lookup_type)cache_mdata) {
155 	case nss_lt_name:
156 		name = va_arg(ap, char *);
157 		break;
158 	case nss_lt_id:
159 		num = va_arg(ap, int);
160 		break;
161 	case nss_lt_all:
162 		break;
163 	default:
164 		/* should be unreachable */
165 		return (NS_UNAVAIL);
166 	}
167 
168 	proto = va_arg(ap, struct protoent *);
169 	orig_buf = va_arg(ap, char *);
170 	orig_buf_size = va_arg(ap, size_t);
171 
172 	desired_size = _ALIGNBYTES + sizeof(struct protoent) + sizeof(char *);
173 	if (proto->p_name != NULL)
174 		desired_size += strlen(proto->p_name) + 1;
175 
176 	if (proto->p_aliases != NULL) {
177 		aliases_size = 0;
178 		for (alias = proto->p_aliases; *alias; ++alias) {
179 			desired_size += strlen(*alias) + 1;
180 			++aliases_size;
181 		}
182 
183 		desired_size += _ALIGNBYTES + (aliases_size + 1) *
184 		    sizeof(char *);
185 	}
186 
187 	if (*buffer_size < desired_size) {
188 		/* this assignment is here for future use */
189 		*buffer_size = desired_size;
190 		return (NS_RETURN);
191 	}
192 
193 	memcpy(&new_proto, proto, sizeof(struct protoent));
194 
195 	*buffer_size = desired_size;
196 	memset(buffer, 0, desired_size);
197 	p = buffer + sizeof(struct protoent) + sizeof(char *);
198 	memcpy(buffer + sizeof(struct protoent), &p, sizeof(char *));
199 	p = (char *)_ALIGN(p);
200 
201 	if (new_proto.p_name != NULL) {
202 		size = strlen(new_proto.p_name);
203 		memcpy(p, new_proto.p_name, size);
204 		new_proto.p_name = p;
205 		p += size + 1;
206 	}
207 
208 	if (new_proto.p_aliases != NULL) {
209 		p = (char *)_ALIGN(p);
210 		memcpy(p, new_proto.p_aliases, sizeof(char *) * aliases_size);
211 		new_proto.p_aliases = (char **)p;
212 		p += sizeof(char *) * (aliases_size + 1);
213 
214 		for (alias = new_proto.p_aliases; *alias; ++alias) {
215 			size = strlen(*alias);
216 			memcpy(p, *alias, size);
217 			*alias = p;
218 			p += size + 1;
219 		}
220 	}
221 
222 	memcpy(buffer, &new_proto, sizeof(struct protoent));
223 	return (NS_SUCCESS);
224 }
225 
226 int
227 __proto_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
228     va_list ap, void *cache_mdata)
229 {
230 	char *name __unused;
231 	int num __unused;
232 	struct protoent *proto;
233 	char *orig_buf;
234 	size_t orig_buf_size;
235 	int *ret_errno;
236 
237 	char *p;
238 	char **alias;
239 
240 	switch ((enum nss_lookup_type)cache_mdata) {
241 	case nss_lt_name:
242 		name = va_arg(ap, char *);
243 		break;
244 	case nss_lt_id:
245 		num = va_arg(ap, int);
246 		break;
247 	case nss_lt_all:
248 		break;
249 	default:
250 		/* should be unreachable */
251 		return (NS_UNAVAIL);
252 	}
253 
254 	proto = va_arg(ap, struct protoent *);
255 	orig_buf = va_arg(ap, char *);
256 	orig_buf_size = va_arg(ap, size_t);
257 	ret_errno = va_arg(ap, int *);
258 
259 	if (orig_buf_size <
260 	    buffer_size - sizeof(struct protoent) - sizeof(char *)) {
261 		*ret_errno = ERANGE;
262 		return (NS_RETURN);
263 	}
264 
265 	memcpy(proto, buffer, sizeof(struct protoent));
266 	memcpy(&p, buffer + sizeof(struct protoent), sizeof(char *));
267 
268 	orig_buf = (char *)_ALIGN(orig_buf);
269 	memcpy(orig_buf, buffer + sizeof(struct protoent) + sizeof(char *) +
270 	    _ALIGN(p) - (size_t)p,
271 	    buffer_size - sizeof(struct protoent) - sizeof(char *) -
272 	    _ALIGN(p) + (size_t)p);
273 	p = (char *)_ALIGN(p);
274 
275 	NS_APPLY_OFFSET(proto->p_name, orig_buf, p, char *);
276 	if (proto->p_aliases != NULL) {
277 		NS_APPLY_OFFSET(proto->p_aliases, orig_buf, p, char **);
278 
279 		for (alias = proto->p_aliases; *alias; ++alias)
280 			NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
281 	}
282 
283 	if (retval != NULL)
284 		*((struct protoent **)retval) = proto;
285 
286 	return (NS_SUCCESS);
287 }
288 
289 NSS_MP_CACHE_HANDLING(protocols);
290 #endif /* NS_CACHING */
291 
292 int
293 __copy_protoent(struct protoent *pe, struct protoent *pptr, char *buf,
294     size_t buflen)
295 {
296 	char *cp;
297 	int i, n;
298 	int numptr, len;
299 
300 	/* Find out the amount of space required to store the answer. */
301 	numptr = 1; /* NULL ptr */
302 	len = (char *)ALIGN(buf) - buf;
303 	for (i = 0; pe->p_aliases[i]; i++, numptr++) {
304 		len += strlen(pe->p_aliases[i]) + 1;
305 	}
306 	len += strlen(pe->p_name) + 1;
307 	len += numptr * sizeof(char*);
308 
309 	if (len > (int)buflen) {
310 		errno = ERANGE;
311 		return (-1);
312 	}
313 
314 	/* copy protocol value*/
315 	pptr->p_proto = pe->p_proto;
316 
317 	cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
318 
319 	/* copy official name */
320 	n = strlen(pe->p_name) + 1;
321 	strcpy(cp, pe->p_name);
322 	pptr->p_name = cp;
323 	cp += n;
324 
325 	/* copy aliases */
326 	pptr->p_aliases = (char **)ALIGN(buf);
327 	for (i = 0 ; pe->p_aliases[i]; i++) {
328 		n = strlen(pe->p_aliases[i]) + 1;
329 		strcpy(cp, pe->p_aliases[i]);
330 		pptr->p_aliases[i] = cp;
331 		cp += n;
332 	}
333 	pptr->p_aliases[i] = NULL;
334 
335 	return (0);
336 }
337 
338 void
339 __setprotoent_p(int f, struct protoent_data *ped)
340 {
341 	if (ped->fp == NULL)
342 		ped->fp = fopen(_PATH_PROTOCOLS, "r");
343 	else
344 		rewind(ped->fp);
345 	ped->stayopen |= f;
346 }
347 
348 void
349 __endprotoent_p(struct protoent_data *ped)
350 {
351 	if (ped->fp) {
352 		fclose(ped->fp);
353 		ped->fp = NULL;
354 	}
355 	ped->stayopen = 0;
356 }
357 
358 int
359 __getprotoent_p(struct protoent *pe, struct protoent_data *ped)
360 {
361 	char *p;
362 	char *cp, **q, *endp;
363 	long l;
364 
365 	if (ped->fp == NULL && (ped->fp = fopen(_PATH_PROTOCOLS, "r")) == NULL)
366 		return (-1);
367 again:
368 	if ((p = fgets(ped->line, sizeof ped->line, ped->fp)) == NULL)
369 		return (-1);
370 	if (*p == '#')
371 		goto again;
372 	cp = strpbrk(p, "#\n");
373 	if (cp != NULL)
374 		*cp = '\0';
375 	pe->p_name = p;
376 	cp = strpbrk(p, " \t");
377 	if (cp == NULL)
378 		goto again;
379 	*cp++ = '\0';
380 	while (*cp == ' ' || *cp == '\t')
381 		cp++;
382 	p = strpbrk(cp, " \t");
383 	if (p != NULL)
384 		*p++ = '\0';
385 	l = strtol(cp, &endp, 10);
386 	if (endp == cp || *endp != '\0' || l < 0 || l > USHRT_MAX)
387 		goto again;
388 	pe->p_proto = l;
389 	q = pe->p_aliases = ped->aliases;
390 	if (p != NULL) {
391 		cp = p;
392 		while (cp && *cp) {
393 			if (*cp == ' ' || *cp == '\t') {
394 				cp++;
395 				continue;
396 			}
397 			if (q < &ped->aliases[_MAXALIASES - 1])
398 				*q++ = cp;
399 			cp = strpbrk(cp, " \t");
400 			if (cp != NULL)
401 				*cp++ = '\0';
402 		}
403 	}
404 	*q = NULL;
405 	return (0);
406 }
407 
408 static int
409 files_getprotoent_r(void *retval, void *mdata __unused, va_list ap)
410 {
411 	struct protoent pe;
412 	struct protoent_data *ped;
413 
414 	struct protoent	*pptr;
415 	char *buffer;
416 	size_t buflen;
417 	int *errnop;
418 
419 	pptr = va_arg(ap, struct protoent *);
420 	buffer = va_arg(ap, char *);
421 	buflen = va_arg(ap, size_t);
422 	errnop = va_arg(ap, int *);
423 
424 	if ((ped = __protoent_data_init()) == NULL)
425 		return (-1);
426 
427 	if (__getprotoent_p(&pe, ped) != 0) {
428 		*errnop = errno;
429 		return (NS_NOTFOUND);
430 	}
431 
432 	if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
433 		*errnop = errno;
434 		return (NS_NOTFOUND);
435 	}
436 
437 	*((struct protoent **)retval) = pptr;
438 	return (NS_SUCCESS);
439 }
440 
441 static int
442 files_setprotoent(void *retval __unused, void *mdata __unused, va_list ap)
443 {
444 	struct protoent_data *ped;
445 	int f;
446 
447 	f = va_arg(ap, int);
448 	if ((ped = __protoent_data_init()) == NULL)
449 		return (NS_UNAVAIL);
450 
451 	__setprotoent_p(f, ped);
452 	return (NS_UNAVAIL);
453 }
454 
455 static int
456 files_endprotoent(void *retval __unused, void *mdata __unused,
457     va_list ap __unused)
458 {
459 	struct protoent_data *ped;
460 
461 	if ((ped = __protoent_data_init()) == NULL)
462 		return (NS_UNAVAIL);
463 
464 	__endprotoent_p(ped);
465 	return (NS_UNAVAIL);
466 }
467 
468 int
469 getprotoent_r(struct protoent *pptr, char *buffer, size_t buflen,
470     struct protoent **result)
471 {
472 #ifdef NS_CACHING
473 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
474 		protocols, (void *)nss_lt_all,
475 		__proto_marshal_func, __proto_unmarshal_func);
476 #endif
477 	static const ns_dtab dtab[] = {
478 		{ NSSRC_FILES, files_getprotoent_r, (void *)nss_lt_all },
479 #ifdef NS_CACHING
480 		NS_CACHE_CB(&cache_info)
481 #endif
482 		{ NULL, NULL, NULL }
483 	};
484 	int rv, ret_errno;
485 
486 	ret_errno = 0;
487 	*result = NULL;
488 	rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotoent_r",
489 	    defaultsrc, pptr, buffer, buflen, &ret_errno);
490 
491 	if (rv == NS_SUCCESS)
492 		return (0);
493 	else
494 		return (ret_errno);
495 }
496 
497 void
498 setprotoent(int stayopen)
499 {
500 #ifdef NS_CACHING
501 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
502 		protocols, (void *)nss_lt_all,
503 		NULL, NULL);
504 #endif
505 
506 	static const ns_dtab dtab[] = {
507 		{ NSSRC_FILES, files_setprotoent, NULL },
508 #ifdef NS_CACHING
509 		NS_CACHE_CB(&cache_info)
510 #endif
511 		{ NULL, NULL, NULL }
512 	};
513 
514 	nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "setprotoent", defaultsrc,
515 		stayopen);
516 }
517 
518 void
519 endprotoent(void)
520 {
521 #ifdef NS_CACHING
522 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
523 		protocols, (void *)nss_lt_all,
524 		NULL, NULL);
525 #endif
526 
527 	static const ns_dtab dtab[] = {
528 		{ NSSRC_FILES, files_endprotoent, NULL },
529 #ifdef NS_CACHING
530 		NS_CACHE_CB(&cache_info)
531 #endif
532 		{ NULL, NULL, NULL }
533 	};
534 
535 	nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "endprotoent", defaultsrc);
536 }
537 
538 struct protoent *
539 getprotoent(void)
540 {
541 	struct protodata *pd;
542 	struct protoent *rval;
543 
544 	if ((pd = __protodata_init()) == NULL)
545 		return (NULL);
546 	if (getprotoent_r(&pd->proto, pd->data, sizeof(pd->data), &rval) != 0)
547 		return (NULL);
548 	return (rval);
549 }
550