Home | History | Annotate | Line # | Download | only in net
getservent_r.c revision 1.13
      1 /*	$NetBSD: getservent_r.c,v 1.13 2022/03/12 17:31:39 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #if defined(LIBC_SCCS) && !defined(lint)
     34 #if 0
     35 static char sccsid[] = "@(#)getservent.c	8.1 (Berkeley) 6/4/93";
     36 #else
     37 __RCSID("$NetBSD: getservent_r.c,v 1.13 2022/03/12 17:31:39 christos Exp $");
     38 #endif
     39 #endif /* LIBC_SCCS and not lint */
     40 
     41 #include "namespace.h"
     42 #include <cdbr.h>
     43 #include <errno.h>
     44 #include <fcntl.h>
     45 #include <netdb.h>
     46 #include <stdio.h>
     47 #include <stdlib.h>
     48 #include <string.h>
     49 
     50 #include "servent.h"
     51 
     52 #ifdef __weak_alias
     53 __weak_alias(endservent_r,_endservent_r)
     54 __weak_alias(getservent_r,_getservent_r)
     55 __weak_alias(setservent_r,_setservent_r)
     56 #endif
     57 
     58 int
     59 _servent_open(struct servent_data *sd)
     60 {
     61 	if (sd->flags & (_SV_CDB | _SV_PLAINFILE)) {
     62 		sd->flags |= _SV_FIRST;
     63 		return 0;
     64 	}
     65 
     66 	free(sd->line);
     67 	sd->line = NULL;
     68 	free(sd->cdb_buf);
     69 	sd->cdb_buf = NULL;
     70 	sd->cdb_buf_len = 0;
     71 	free(sd->aliases);
     72 	sd->aliases = NULL;
     73 	sd->maxaliases = 0;
     74 	sd->flags |= _SV_FIRST;
     75 
     76 	sd->cdb = cdbr_open(_PATH_SERVICES_CDB, CDBR_DEFAULT);
     77 	if (sd->cdb != NULL) {
     78 		sd->flags |= _SV_CDB;
     79 		return 0;
     80 	}
     81 
     82 	sd->plainfile = fopen(_PATH_SERVICES, "re");
     83 	if (sd->plainfile != NULL) {
     84 		sd->flags |= _SV_PLAINFILE;
     85 		return 0;
     86 	}
     87 	return -1;
     88 }
     89 
     90 void
     91 _servent_close(struct servent_data *sd)
     92 {
     93 	if (sd->flags & _SV_CDB) {
     94 		cdbr_close(sd->cdb);
     95 		sd->cdb = NULL;
     96 		sd->flags &= ~_SV_CDB;
     97 	}
     98 
     99 	if (sd->flags & _SV_PLAINFILE) {
    100 		(void)fclose(sd->plainfile);
    101 		sd->plainfile = NULL;
    102 		sd->flags &= ~_SV_PLAINFILE;
    103 	}
    104 	sd->flags &= ~_SV_STAYOPEN;
    105 }
    106 
    107 
    108 int
    109 _servent_getline(struct servent_data *sd)
    110 {
    111 
    112 	if (sd->flags & _SV_CDB)
    113 		return -1;
    114 
    115 	if ((sd->flags & _SV_PLAINFILE) == 0)
    116 		return -1;
    117 
    118 	free(sd->line);
    119 	sd->line = NULL;
    120 
    121 	if (sd->flags & _SV_FIRST) {
    122 		(void)rewind((FILE *)sd->plainfile);
    123 		sd->flags &= ~_SV_FIRST;
    124 	}
    125 	sd->line = fparseln(sd->plainfile, NULL, NULL, NULL,
    126 	    FPARSELN_UNESCALL);
    127 	return sd->line == NULL ? -1 : 0;
    128 }
    129 
    130 struct servent *
    131 _servent_parseline(struct servent_data *sd, struct servent *sp)
    132 {
    133 	size_t i = 0;
    134 	int oerrno;
    135 	char *p, *cp, **q;
    136 
    137 	if (sd->line == NULL)
    138 		return NULL;
    139 
    140 	sp->s_name = p = sd->line;
    141 	p = strpbrk(p, " \t");
    142 	if (p == NULL)
    143 		return NULL;
    144 	*p++ = '\0';
    145 	while (*p == ' ' || *p == '\t')
    146 		p++;
    147 	cp = strpbrk(p, ",/");
    148 	if (cp == NULL)
    149 		return NULL;
    150 	*cp++ = '\0';
    151 	sp->s_port = htons((u_short)atoi(p));
    152 	sp->s_proto = cp;
    153 	if (sd->aliases == NULL) {
    154 		sd->maxaliases = 10;
    155 		sd->aliases = calloc(sd->maxaliases, sizeof(*sd->aliases));
    156 		if (sd->aliases == NULL) {
    157 			oerrno = errno;
    158 			endservent_r(sd);
    159 			errno = oerrno;
    160 			return NULL;
    161 		}
    162 	}
    163 	sp->s_aliases = sd->aliases;
    164 	cp = strpbrk(cp, " \t");
    165 	if (cp != NULL)
    166 		*cp++ = '\0';
    167 	while (cp && *cp) {
    168 		if (*cp == ' ' || *cp == '\t') {
    169 			cp++;
    170 			continue;
    171 		}
    172 		if (i == sd->maxaliases - 2) {
    173 			sd->maxaliases *= 2;
    174 			q = realloc(sd->aliases, sd->maxaliases * sizeof(*q));
    175 			if (q == NULL) {
    176 				oerrno = errno;
    177 				endservent_r(sd);
    178 				errno = oerrno;
    179 				return NULL;
    180 			}
    181 			sp->s_aliases = sd->aliases = q;
    182 		}
    183 		sp->s_aliases[i++] = cp;
    184 		cp = strpbrk(cp, " \t");
    185 		if (cp != NULL)
    186 			*cp++ = '\0';
    187 	}
    188 	sp->s_aliases[i] = NULL;
    189 	return sp;
    190 }
    191 
    192 void
    193 setservent_r(int f, struct servent_data *sd)
    194 {
    195 	(void)_servent_open(sd);
    196 	sd->flags |= f ? _SV_STAYOPEN : 0;
    197 }
    198 
    199 void
    200 endservent_r(struct servent_data *sd)
    201 {
    202 	_servent_close(sd);
    203 	free(sd->aliases);
    204 	sd->aliases = NULL;
    205 	sd->maxaliases = 0;
    206 	free(sd->line);
    207 	sd->line = NULL;
    208 	free(sd->cdb_buf);
    209 	sd->cdb_buf = NULL;
    210 	sd->cdb_buf_len = 0;
    211 }
    212 
    213 struct servent *
    214 getservent_r(struct servent *sp, struct servent_data *sd)
    215 {
    216 
    217 	if ((sd->flags & (_SV_CDB | _SV_PLAINFILE)) == 0 &&
    218 	    _servent_open(sd) == -1)
    219 		return NULL;
    220 
    221 	if (sd->flags & _SV_CDB) {
    222 		const void *data;
    223 		size_t len;
    224 
    225 		if (sd->flags & _SV_FIRST) {
    226 			sd->cdb_index = 0;
    227 			sd->flags &= ~_SV_FIRST;
    228 		}
    229 
    230 		if (cdbr_get(sd->cdb, sd->cdb_index, &data, &len))
    231 			return NULL;
    232 		++sd->cdb_index;
    233 		return _servent_parsedb(sd, sp, data, len);
    234 	}
    235 	if (sd->flags & _SV_PLAINFILE) {
    236 		for (;;) {
    237 			if (_servent_getline(sd) == -1)
    238 				return NULL;
    239 			if (_servent_parseline(sd, sp) == NULL)
    240 				continue;
    241 			return sp;
    242 		}
    243 	}
    244 	return NULL;
    245 }
    246 
    247 struct servent *
    248 _servent_parsedb(struct servent_data *sd, struct servent *sp,
    249     const uint8_t *data, size_t len)
    250 {
    251 	char **q;
    252 	size_t i;
    253 	int oerrno;
    254 
    255 	if ((sd->flags & _SV_STAYOPEN) == 0) {
    256 		if (len > sd->cdb_buf_len) {
    257 			void *tmp = realloc(sd->cdb_buf, len);
    258 			if (tmp == NULL)
    259 				goto fail;
    260 			sd->cdb_buf = tmp;
    261 			sd->cdb_buf_len = len;
    262 		}
    263 		memcpy(sd->cdb_buf, data, len);
    264 		data = sd->cdb_buf;
    265 	}
    266 
    267 	if (len < 2)
    268 		goto fail;
    269 	sp->s_port = htobe16(be16dec(data));
    270 	data += 2;
    271 	len -= 2;
    272 
    273 	if (len == 0 || len < (size_t)data[0] + 2)
    274 		goto fail;
    275 	sp->s_proto = __UNCONST(data + 1);
    276 
    277 	if (sp->s_proto[data[0]] != '\0')
    278 		goto fail;
    279 
    280 	len -= 2 + data[0];
    281 	data += 2 + data[0];
    282 
    283 	if (len == 0)
    284 		goto fail;
    285 	if (len < (size_t)data[0] + 2)
    286 		goto fail;
    287 
    288 	sp->s_name = __UNCONST(data + 1);
    289 	len -= 2 + data[0];
    290 	data += 2 + data[0];
    291 
    292 	if (sd->aliases == NULL) {
    293 		sd->maxaliases = 10;
    294 		sd->aliases = NULL;
    295 		errno = reallocarr(&sd->aliases,
    296 		    sd->maxaliases, sizeof(*sd->aliases));
    297 		if (errno)
    298 			goto fail;
    299 	}
    300 	sp->s_aliases = sd->aliases;
    301 	i = 0;
    302 	while (len) {
    303 		if (len < (size_t)data[0] + 2)
    304 			goto fail;
    305 		if (i == sd->maxaliases - 2) {
    306 			sd->maxaliases *= 2;
    307 			q = sd->aliases;
    308 			errno = reallocarr(&q, sd->maxaliases, sizeof(*q));
    309 			if (errno)
    310 				goto fail;
    311 			sp->s_aliases = sd->aliases = q;
    312 		}
    313 		sp->s_aliases[i++] = __UNCONST(data + 1);
    314 		len -= 2 + data[0];
    315 		data += 2 + data[0];
    316 	}
    317 	sp->s_aliases[i] = NULL;
    318 	return sp;
    319 
    320 fail:
    321 	oerrno = errno;
    322 	endservent_r(sd);
    323 	errno = oerrno;
    324 	return NULL;
    325 }
    326 
    327