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 35static 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 58int 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 90void 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 108int 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 130struct 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 192void 193setservent_r(int f, struct servent_data *sd) 194{ 195 (void)_servent_open(sd); 196 sd->flags |= f ? _SV_STAYOPEN : 0; 197} 198 199void 200endservent_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 213struct servent * 214getservent_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 247struct 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 320fail: 321 oerrno = errno; 322 endservent_r(sd); 323 errno = oerrno; 324 return NULL; 325} 326 327