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