1 /* 2 * Copyright (c) 1989, 1993, 1995 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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 36 * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 37 * 38 * Permission to use, copy, modify, and distribute this software for any 39 * purpose with or without fee is hereby granted, provided that the above 40 * copyright notice and this permission notice appear in all copies. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 43 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 44 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 45 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 47 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 48 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 */ 50 51 #if defined(LIBC_SCCS) && !defined(lint) 52 static const char rcsid[] = "$Id: lcl_sv.c,v 1.4 2005/04/27 04:56:31 sra Exp $"; 53 #endif /* LIBC_SCCS and not lint */ 54 55 /* extern */ 56 57 #include "port_before.h" 58 59 #include <sys/types.h> 60 #include <sys/socket.h> 61 #include <netinet/in.h> 62 #include <arpa/nameser.h> 63 #include <resolv.h> 64 65 #ifdef IRS_LCL_SV_DB 66 #include <db.h> 67 #endif 68 #include <errno.h> 69 #include <fcntl.h> 70 #include <limits.h> 71 #include <stdio.h> 72 #include <string.h> 73 #include <stdlib.h> 74 75 #include <irs.h> 76 #include <isc/memcluster.h> 77 78 #include "port_after.h" 79 80 #include "irs_p.h" 81 #include "lcl_p.h" 82 83 #ifdef SPRINTF_CHAR 84 # define SPRINTF(x) strlen(sprintf/**/x) 85 #else 86 # define SPRINTF(x) ((size_t)sprintf x) 87 #endif 88 89 /* Types */ 90 91 struct pvt { 92 #ifdef IRS_LCL_SV_DB 93 DB * dbh; 94 int dbf; 95 #endif 96 struct lcl_sv sv; 97 }; 98 99 /* Forward */ 100 101 static void sv_close(struct irs_sv*); 102 static struct servent * sv_next(struct irs_sv *); 103 static struct servent * sv_byname(struct irs_sv *, const char *, 104 const char *); 105 static struct servent * sv_byport(struct irs_sv *, int, const char *); 106 static void sv_rewind(struct irs_sv *); 107 static void sv_minimize(struct irs_sv *); 108 /*global*/ struct servent * irs_lclsv_fnxt(struct lcl_sv *); 109 #ifdef IRS_LCL_SV_DB 110 static struct servent * sv_db_rec(struct lcl_sv *, DBT *, DBT *); 111 #endif 112 113 /* Portability */ 114 115 #ifndef SEEK_SET 116 # define SEEK_SET 0 117 #endif 118 119 /* Public */ 120 121 struct irs_sv * 122 irs_lcl_sv(struct irs_acc *this) { 123 struct irs_sv *sv; 124 struct pvt *pvt; 125 126 UNUSED(this); 127 128 if ((sv = memget(sizeof *sv)) == NULL) { 129 errno = ENOMEM; 130 return (NULL); 131 } 132 memset(sv, 0x5e, sizeof *sv); 133 if ((pvt = memget(sizeof *pvt)) == NULL) { 134 memput(sv, sizeof *sv); 135 errno = ENOMEM; 136 return (NULL); 137 } 138 memset(pvt, 0, sizeof *pvt); 139 sv->private = pvt; 140 sv->close = sv_close; 141 sv->next = sv_next; 142 sv->byname = sv_byname; 143 sv->byport = sv_byport; 144 sv->rewind = sv_rewind; 145 sv->minimize = sv_minimize; 146 sv->res_get = NULL; 147 sv->res_set = NULL; 148 #ifdef IRS_LCL_SV_DB 149 pvt->dbf = R_FIRST; 150 #endif 151 return (sv); 152 } 153 154 /* Methods */ 155 156 static void 157 sv_close(struct irs_sv *this) { 158 struct pvt *pvt = (struct pvt *)this->private; 159 160 #ifdef IRS_LCL_SV_DB 161 if (pvt->dbh != NULL) 162 (*pvt->dbh->close)(pvt->dbh); 163 #endif 164 if (pvt->sv.fp) 165 fclose(pvt->sv.fp); 166 memput(pvt, sizeof *pvt); 167 memput(this, sizeof *this); 168 } 169 170 static struct servent * 171 sv_byname(struct irs_sv *this, const char *name, const char *proto) { 172 #ifdef IRS_LCL_SV_DB 173 struct pvt *pvt = (struct pvt *)this->private; 174 #endif 175 struct servent *p; 176 char **cp; 177 178 sv_rewind(this); 179 #ifdef IRS_LCL_SV_DB 180 if (pvt->dbh != NULL) { 181 DBT key, data; 182 183 /* Note that (sizeof "/") == 2. */ 184 if ((strlen(name) + sizeof "/" + proto ? strlen(proto) : 0) 185 > sizeof pvt->sv.line) 186 goto try_local; 187 key.data = pvt->sv.line; 188 key.size = SPRINTF((pvt->sv.line, "%s/%s", name, 189 proto ? proto : "")) + 1; 190 if (proto != NULL) { 191 if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0) 192 return (NULL); 193 } else if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR) 194 != 0) 195 return (NULL); 196 return (sv_db_rec(&pvt->sv, &key, &data)); 197 } 198 try_local: 199 #endif 200 201 while ((p = sv_next(this))) { 202 if (strcmp(name, p->s_name) == 0) 203 goto gotname; 204 for (cp = p->s_aliases; *cp; cp++) 205 if (strcmp(name, *cp) == 0) 206 goto gotname; 207 continue; 208 gotname: 209 if (proto == NULL || strcmp(p->s_proto, proto) == 0) 210 break; 211 } 212 return (p); 213 } 214 215 static struct servent * 216 sv_byport(struct irs_sv *this, int port, const char *proto) { 217 #ifdef IRS_LCL_SV_DB 218 struct pvt *pvt = (struct pvt *)this->private; 219 #endif 220 struct servent *p; 221 222 sv_rewind(this); 223 #ifdef IRS_LCL_SV_DB 224 if (pvt->dbh != NULL) { 225 DBT key, data; 226 u_short *ports; 227 228 ports = (u_short *)pvt->sv.line; 229 ports[0] = 0; 230 ports[1] = port; 231 key.data = ports; 232 key.size = sizeof(u_short) * 2; 233 if (proto && *proto) { 234 strncpy((char *)ports + key.size, proto, 235 BUFSIZ - key.size); 236 key.size += strlen((char *)ports + key.size) + 1; 237 if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0) 238 return (NULL); 239 } else { 240 if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR) 241 != 0) 242 return (NULL); 243 } 244 return (sv_db_rec(&pvt->sv, &key, &data)); 245 } 246 #endif 247 while ((p = sv_next(this))) { 248 if (p->s_port != port) 249 continue; 250 if (proto == NULL || strcmp(p->s_proto, proto) == 0) 251 break; 252 } 253 return (p); 254 } 255 256 static void 257 sv_rewind(struct irs_sv *this) { 258 struct pvt *pvt = (struct pvt *)this->private; 259 260 if (pvt->sv.fp) { 261 if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0) 262 return; 263 (void)fclose(pvt->sv.fp); 264 pvt->sv.fp = NULL; 265 } 266 #ifdef IRS_LCL_SV_DB 267 pvt->dbf = R_FIRST; 268 if (pvt->dbh != NULL) 269 return; 270 pvt->dbh = dbopen(_PATH_SERVICES_DB, O_RDONLY,O_RDONLY,DB_BTREE, NULL); 271 if (pvt->dbh != NULL) { 272 if (fcntl((*pvt->dbh->fd)(pvt->dbh), F_SETFD, 1) < 0) { 273 (*pvt->dbh->close)(pvt->dbh); 274 pvt->dbh = NULL; 275 } 276 return; 277 } 278 #endif 279 if ((pvt->sv.fp = fopen(_PATH_SERVICES, "r")) == NULL) 280 return; 281 if (fcntl(fileno(pvt->sv.fp), F_SETFD, 1) < 0) { 282 (void)fclose(pvt->sv.fp); 283 pvt->sv.fp = NULL; 284 } 285 } 286 287 static struct servent * 288 sv_next(struct irs_sv *this) { 289 struct pvt *pvt = (struct pvt *)this->private; 290 291 #ifdef IRS_LCL_SV_DB 292 if (pvt->dbh == NULL && pvt->sv.fp == NULL) 293 #else 294 if (pvt->sv.fp == NULL) 295 #endif 296 sv_rewind(this); 297 298 #ifdef IRS_LCL_SV_DB 299 if (pvt->dbh != NULL) { 300 DBT key, data; 301 302 while ((*pvt->dbh->seq)(pvt->dbh, &key, &data, pvt->dbf) == 0){ 303 pvt->dbf = R_NEXT; 304 if (((char *)key.data)[0]) 305 continue; 306 return (sv_db_rec(&pvt->sv, &key, &data)); 307 } 308 } 309 #endif 310 311 if (pvt->sv.fp == NULL) 312 return (NULL); 313 return (irs_lclsv_fnxt(&pvt->sv)); 314 } 315 316 static void 317 sv_minimize(struct irs_sv *this) { 318 struct pvt *pvt = (struct pvt *)this->private; 319 320 #ifdef IRS_LCL_SV_DB 321 if (pvt->dbh != NULL) { 322 (*pvt->dbh->close)(pvt->dbh); 323 pvt->dbh = NULL; 324 } 325 #endif 326 if (pvt->sv.fp != NULL) { 327 (void)fclose(pvt->sv.fp); 328 pvt->sv.fp = NULL; 329 } 330 } 331 332 /* Quasipublic. */ 333 334 struct servent * 335 irs_lclsv_fnxt(struct lcl_sv *sv) { 336 char *p, *cp, **q; 337 338 again: 339 if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL) 340 return (NULL); 341 if (*p == '#') 342 goto again; 343 sv->serv.s_name = p; 344 while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#') 345 ++p; 346 if (*p == '\0' || *p == '#' || *p == '\n') 347 goto again; 348 *p++ = '\0'; 349 while (*p == ' ' || *p == '\t') 350 p++; 351 if (*p == '\0' || *p == '#' || *p == '\n') 352 goto again; 353 sv->serv.s_port = htons((u_short)strtol(p, &cp, 10)); 354 if (cp == p || (*cp != '/' && *cp != ',')) 355 goto again; 356 p = cp + 1; 357 sv->serv.s_proto = p; 358 359 q = sv->serv.s_aliases = sv->serv_aliases; 360 361 while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#') 362 ++p; 363 364 while (*p == ' ' || *p == '\t') { 365 *p++ = '\0'; 366 while (*p == ' ' || *p == '\t') 367 ++p; 368 if (*p == '\0' || *p == '#' || *p == '\n') 369 break; 370 if (q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) 371 *q++ = p; 372 while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#') 373 ++p; 374 } 375 376 *p = '\0'; 377 *q = NULL; 378 return (&sv->serv); 379 } 380 381 /* Private. */ 382 383 #ifdef IRS_LCL_SV_DB 384 static struct servent * 385 sv_db_rec(struct lcl_sv *sv, DBT *key, DBT *data) { 386 char *p, **q; 387 int n; 388 389 p = data->data; 390 p[data->size - 1] = '\0'; /*%< should be, but we depend on it */ 391 if (((char *)key->data)[0] == '\0') { 392 if (key->size < sizeof(u_short)*2 || data->size < 2) 393 return (NULL); 394 sv->serv.s_port = ((u_short *)key->data)[1]; 395 n = strlen(p) + 1; 396 if ((size_t)n > sizeof(sv->line)) { 397 n = sizeof(sv->line); 398 } 399 memcpy(sv->line, p, n); 400 sv->serv.s_name = sv->line; 401 if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL) 402 *(sv->serv.s_proto)++ = '\0'; 403 p += n; 404 data->size -= n; 405 } else { 406 if (data->size < sizeof(u_short) + 1) 407 return (NULL); 408 if (key->size > sizeof(sv->line)) 409 key->size = sizeof(sv->line); 410 ((char *)key->data)[key->size - 1] = '\0'; 411 memcpy(sv->line, key->data, key->size); 412 sv->serv.s_name = sv->line; 413 if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL) 414 *(sv->serv.s_proto)++ = '\0'; 415 sv->serv.s_port = *(u_short *)data->data; 416 p += sizeof(u_short); 417 data->size -= sizeof(u_short); 418 } 419 q = sv->serv.s_aliases = sv->serv_aliases; 420 while (data->size > 0 && q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) { 421 422 *q++ = p; 423 n = strlen(p) + 1; 424 data->size -= n; 425 p += n; 426 } 427 *q = NULL; 428 return (&sv->serv); 429 } 430 #endif 431 432 /*! \file */ 433