1 /* $NetBSD: getservent_r.c,v 1.10 2010/04/25 00:54:46 joerg 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.10 2010/04/25 00:54:46 joerg 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, "r"); 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 = malloc(sd->maxaliases * sizeof(char *)); 295 if (sd->aliases == NULL) 296 goto fail; 297 } 298 sp->s_aliases = sd->aliases; 299 i = 0; 300 while (len) { 301 if (len < (size_t)data[0] + 2) 302 goto fail; 303 if (i == sd->maxaliases - 2) { 304 sd->maxaliases *= 2; 305 q = realloc(sd->aliases, sd->maxaliases * sizeof(*q)); 306 if (q == NULL) 307 goto fail; 308 sp->s_aliases = sd->aliases = q; 309 } 310 sp->s_aliases[i++] = __UNCONST(data + 1); 311 len -= 2 + data[0]; 312 data += 2 + data[0]; 313 } 314 sp->s_aliases[i] = NULL; 315 return sp; 316 317 fail: 318 oerrno = errno; 319 endservent_r(sd); 320 errno = oerrno; 321 return NULL; 322 } 323 324