119370Spst/*	$NetBSD: getservent_r.c,v 1.13 2022/03/12 17:31:39 christos Exp $	*/
2130803Smarcel
398944Sobrien/*
419370Spst * Copyright (c) 1983, 1993
519370Spst *	The Regents of the University of California.  All rights reserved.
619370Spst *
798944Sobrien * Redistribution and use in source and binary forms, with or without
819370Spst * modification, are permitted provided that the following conditions
998944Sobrien * are met:
1098944Sobrien * 1. Redistributions of source code must retain the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer.
1298944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1319370Spst *    notice, this list of conditions and the following disclaimer in the
1498944Sobrien *    documentation and/or other materials provided with the distribution.
1598944Sobrien * 3. Neither the name of the University nor the names of its contributors
1698944Sobrien *    may be used to endorse or promote products derived from this software
1798944Sobrien *    without specific prior written permission.
1819370Spst *
1998944Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2098944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2198944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2298944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2319370Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2419370Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2519370Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2619370Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2719370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2819370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2919370Spst * SUCH DAMAGE.
3019370Spst */
3119370Spst
3298944Sobrien#include <sys/cdefs.h>
33130803Smarcel#if defined(LIBC_SCCS) && !defined(lint)
3419370Spst#if 0
3519370Spststatic char sccsid[] = "@(#)getservent.c	8.1 (Berkeley) 6/4/93";
3619370Spst#else
3719370Spst__RCSID("$NetBSD: getservent_r.c,v 1.13 2022/03/12 17:31:39 christos Exp $");
3819370Spst#endif
3919370Spst#endif /* LIBC_SCCS and not lint */
4019370Spst
4119370Spst#include "namespace.h"
4298944Sobrien#include <cdbr.h>
4319370Spst#include <errno.h>
4419370Spst#include <fcntl.h>
4519370Spst#include <netdb.h>
4619370Spst#include <stdio.h>
4719370Spst#include <stdlib.h>
4819370Spst#include <string.h>
4919370Spst
5019370Spst#include "servent.h"
5119370Spst
5246283Sdfr#ifdef __weak_alias
5346283Sdfr__weak_alias(endservent_r,_endservent_r)
5446283Sdfr__weak_alias(getservent_r,_getservent_r)
5598944Sobrien__weak_alias(setservent_r,_setservent_r)
5698944Sobrien#endif
5798944Sobrien
5898944Sobrienint
5946283Sdfr_servent_open(struct servent_data *sd)
6046283Sdfr{
6198944Sobrien	if (sd->flags & (_SV_CDB | _SV_PLAINFILE)) {
6298944Sobrien		sd->flags |= _SV_FIRST;
6398944Sobrien		return 0;
6498944Sobrien	}
6598944Sobrien
6698944Sobrien	free(sd->line);
6746283Sdfr	sd->line = NULL;
6898944Sobrien	free(sd->cdb_buf);
6998944Sobrien	sd->cdb_buf = NULL;
7046283Sdfr	sd->cdb_buf_len = 0;
7146283Sdfr	free(sd->aliases);
7246283Sdfr	sd->aliases = NULL;
7398944Sobrien	sd->maxaliases = 0;
7446283Sdfr	sd->flags |= _SV_FIRST;
7598944Sobrien
7698944Sobrien	sd->cdb = cdbr_open(_PATH_SERVICES_CDB, CDBR_DEFAULT);
7798944Sobrien	if (sd->cdb != NULL) {
7898944Sobrien		sd->flags |= _SV_CDB;
7998944Sobrien		return 0;
8098944Sobrien	}
8198944Sobrien
8298944Sobrien	sd->plainfile = fopen(_PATH_SERVICES, "re");
8398944Sobrien	if (sd->plainfile != NULL) {
8498944Sobrien		sd->flags |= _SV_PLAINFILE;
8598944Sobrien		return 0;
8698944Sobrien	}
8746283Sdfr	return -1;
8846283Sdfr}
8998944Sobrien
9098944Sobrienvoid
9198944Sobrien_servent_close(struct servent_data *sd)
9298944Sobrien{
9398944Sobrien	if (sd->flags & _SV_CDB) {
9498944Sobrien		cdbr_close(sd->cdb);
9546283Sdfr		sd->cdb = NULL;
9619370Spst		sd->flags &= ~_SV_CDB;
9719370Spst	}
9819370Spst
9919370Spst	if (sd->flags & _SV_PLAINFILE) {
10019370Spst		(void)fclose(sd->plainfile);
10119370Spst		sd->plainfile = NULL;
10219370Spst		sd->flags &= ~_SV_PLAINFILE;
103130803Smarcel	}
10419370Spst	sd->flags &= ~_SV_STAYOPEN;
10519370Spst}
10698944Sobrien
10719370Spst
10819370Spstint
10919370Spst_servent_getline(struct servent_data *sd)
11019370Spst{
11119370Spst
11219370Spst	if (sd->flags & _SV_CDB)
11319370Spst		return -1;
11419370Spst
11519370Spst	if ((sd->flags & _SV_PLAINFILE) == 0)
11619370Spst		return -1;
11719370Spst
11819370Spst	free(sd->line);
11919370Spst	sd->line = NULL;
12019370Spst
12119370Spst	if (sd->flags & _SV_FIRST) {
12219370Spst		(void)rewind((FILE *)sd->plainfile);
12319370Spst		sd->flags &= ~_SV_FIRST;
12419370Spst	}
12519370Spst	sd->line = fparseln(sd->plainfile, NULL, NULL, NULL,
12619370Spst	    FPARSELN_UNESCALL);
12719370Spst	return sd->line == NULL ? -1 : 0;
12819370Spst}
12919370Spst
13019370Spststruct servent *
13119370Spst_servent_parseline(struct servent_data *sd, struct servent *sp)
13219370Spst{
13319370Spst	size_t i = 0;
13419370Spst	int oerrno;
13519370Spst	char *p, *cp, **q;
13619370Spst
13719370Spst	if (sd->line == NULL)
13819370Spst		return NULL;
13919370Spst
14019370Spst	sp->s_name = p = sd->line;
14119370Spst	p = strpbrk(p, " \t");
14219370Spst	if (p == NULL)
14319370Spst		return NULL;
14419370Spst	*p++ = '\0';
14519370Spst	while (*p == ' ' || *p == '\t')
14619370Spst		p++;
14719370Spst	cp = strpbrk(p, ",/");
14819370Spst	if (cp == NULL)
14998944Sobrien		return NULL;
15019370Spst	*cp++ = '\0';
15119370Spst	sp->s_port = htons((u_short)atoi(p));
15246283Sdfr	sp->s_proto = cp;
15319370Spst	if (sd->aliases == NULL) {
15419370Spst		sd->maxaliases = 10;
15519370Spst		sd->aliases = calloc(sd->maxaliases, sizeof(*sd->aliases));
15619370Spst		if (sd->aliases == NULL) {
15719370Spst			oerrno = errno;
15819370Spst			endservent_r(sd);
15919370Spst			errno = oerrno;
16019370Spst			return NULL;
16119370Spst		}
16219370Spst	}
16319370Spst	sp->s_aliases = sd->aliases;
16498944Sobrien	cp = strpbrk(cp, " \t");
16598944Sobrien	if (cp != NULL)
16619370Spst		*cp++ = '\0';
167130803Smarcel	while (cp && *cp) {
16819370Spst		if (*cp == ' ' || *cp == '\t') {
16919370Spst			cp++;
17019370Spst			continue;
17198944Sobrien		}
17219370Spst		if (i == sd->maxaliases - 2) {
17319370Spst			sd->maxaliases *= 2;
17446283Sdfr			q = realloc(sd->aliases, sd->maxaliases * sizeof(*q));
17519370Spst			if (q == NULL) {
17619370Spst				oerrno = errno;
17798944Sobrien				endservent_r(sd);
17819370Spst				errno = oerrno;
17919370Spst				return NULL;
18019370Spst			}
18198944Sobrien			sp->s_aliases = sd->aliases = q;
18219370Spst		}
18319370Spst		sp->s_aliases[i++] = cp;
18419370Spst		cp = strpbrk(cp, " \t");
18598944Sobrien		if (cp != NULL)
18619370Spst			*cp++ = '\0';
18798944Sobrien	}
18819370Spst	sp->s_aliases[i] = NULL;
18919370Spst	return sp;
19019370Spst}
19119370Spst
19219370Spstvoid
19398944Sobriensetservent_r(int f, struct servent_data *sd)
19419370Spst{
19519370Spst	(void)_servent_open(sd);
19619370Spst	sd->flags |= f ? _SV_STAYOPEN : 0;
19719370Spst}
19819370Spst
19919370Spstvoid
20019370Spstendservent_r(struct servent_data *sd)
20198944Sobrien{
20219370Spst	_servent_close(sd);
20319370Spst	free(sd->aliases);
20419370Spst	sd->aliases = NULL;
20519370Spst	sd->maxaliases = 0;
20619370Spst	free(sd->line);
20719370Spst	sd->line = NULL;
20819370Spst	free(sd->cdb_buf);
20919370Spst	sd->cdb_buf = NULL;
21019370Spst	sd->cdb_buf_len = 0;
21119370Spst}
21219370Spst
21319370Spststruct servent *
21419370Spstgetservent_r(struct servent *sp, struct servent_data *sd)
21519370Spst{
21619370Spst
21719370Spst	if ((sd->flags & (_SV_CDB | _SV_PLAINFILE)) == 0 &&
21819370Spst	    _servent_open(sd) == -1)
21919370Spst		return NULL;
22019370Spst
22119370Spst	if (sd->flags & _SV_CDB) {
22219370Spst		const void *data;
22319370Spst		size_t len;
22419370Spst
22519370Spst		if (sd->flags & _SV_FIRST) {
22619370Spst			sd->cdb_index = 0;
22719370Spst			sd->flags &= ~_SV_FIRST;
22846283Sdfr		}
22919370Spst
23019370Spst		if (cdbr_get(sd->cdb, sd->cdb_index, &data, &len))
23119370Spst			return NULL;
23298944Sobrien		++sd->cdb_index;
23319370Spst		return _servent_parsedb(sd, sp, data, len);
23419370Spst	}
23519370Spst	if (sd->flags & _SV_PLAINFILE) {
23619370Spst		for (;;) {
23719370Spst			if (_servent_getline(sd) == -1)
23819370Spst				return NULL;
23919370Spst			if (_servent_parseline(sd, sp) == NULL)
24019370Spst				continue;
24198944Sobrien			return sp;
24219370Spst		}
24319370Spst	}
24419370Spst	return NULL;
24519370Spst}
24619370Spst
24719370Spststruct servent *
24819370Spst_servent_parsedb(struct servent_data *sd, struct servent *sp,
24919370Spst    const uint8_t *data, size_t len)
25019370Spst{
25198944Sobrien	char **q;
25219370Spst	size_t i;
253130803Smarcel	int oerrno;
25498944Sobrien
25519370Spst	if ((sd->flags & _SV_STAYOPEN) == 0) {
25619370Spst		if (len > sd->cdb_buf_len) {
25719370Spst			void *tmp = realloc(sd->cdb_buf, len);
25819370Spst			if (tmp == NULL)
25919370Spst				goto fail;
26019370Spst			sd->cdb_buf = tmp;
26119370Spst			sd->cdb_buf_len = len;
26219370Spst		}
26319370Spst		memcpy(sd->cdb_buf, data, len);
26419370Spst		data = sd->cdb_buf;
26519370Spst	}
26619370Spst
26719370Spst	if (len < 2)
26819370Spst		goto fail;
26919370Spst	sp->s_port = htobe16(be16dec(data));
27019370Spst	data += 2;
27119370Spst	len -= 2;
27219370Spst
27319370Spst	if (len == 0 || len < (size_t)data[0] + 2)
27419370Spst		goto fail;
27519370Spst	sp->s_proto = __UNCONST(data + 1);
27619370Spst
27719370Spst	if (sp->s_proto[data[0]] != '\0')
27819370Spst		goto fail;
27919370Spst
28019370Spst	len -= 2 + data[0];
28119370Spst	data += 2 + data[0];
28219370Spst
28319370Spst	if (len == 0)
28419370Spst		goto fail;
28519370Spst	if (len < (size_t)data[0] + 2)
28619370Spst		goto fail;
28719370Spst
28819370Spst	sp->s_name = __UNCONST(data + 1);
28919370Spst	len -= 2 + data[0];
29019370Spst	data += 2 + data[0];
29119370Spst
29219370Spst	if (sd->aliases == NULL) {
29319370Spst		sd->maxaliases = 10;
29419370Spst		sd->aliases = NULL;
29519370Spst		errno = reallocarr(&sd->aliases,
29619370Spst		    sd->maxaliases, sizeof(*sd->aliases));
29719370Spst		if (errno)
29819370Spst			goto fail;
29919370Spst	}
30019370Spst	sp->s_aliases = sd->aliases;
30119370Spst	i = 0;
30219370Spst	while (len) {
30319370Spst		if (len < (size_t)data[0] + 2)
30419370Spst			goto fail;
30519370Spst		if (i == sd->maxaliases - 2) {
30619370Spst			sd->maxaliases *= 2;
30719370Spst			q = sd->aliases;
30819370Spst			errno = reallocarr(&q, sd->maxaliases, sizeof(*q));
30919370Spst			if (errno)
31098944Sobrien				goto fail;
31119370Spst			sp->s_aliases = sd->aliases = q;
31219370Spst		}
31398944Sobrien		sp->s_aliases[i++] = __UNCONST(data + 1);
31419370Spst		len -= 2 + data[0];
31519370Spst		data += 2 + data[0];
31619370Spst	}
31719370Spst	sp->s_aliases[i] = NULL;
31819370Spst	return sp;
31919370Spst
32019370Spstfail:
32119370Spst	oerrno = errno;
32219370Spst	endservent_r(sd);
32319370Spst	errno = oerrno;
32419370Spst	return NULL;
32519370Spst}
32619370Spst
32719370Spst