1 /* $NetBSD: lcl_sv.c,v 1.1.1.1 2009/04/12 15:33:37 christos Exp $ */ 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) 54 static 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 93 struct 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 103 static void sv_close(struct irs_sv*); 104 static struct servent * sv_next(struct irs_sv *); 105 static struct servent * sv_byname(struct irs_sv *, const char *, 106 const char *); 107 static struct servent * sv_byport(struct irs_sv *, int, const char *); 108 static void sv_rewind(struct irs_sv *); 109 static void sv_minimize(struct irs_sv *); 110 /*global*/ struct servent * irs_lclsv_fnxt(struct lcl_sv *); 111 #ifdef IRS_LCL_SV_DB 112 static 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 123 struct irs_sv * 124 irs_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 158 static void 159 sv_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 172 static struct servent * 173 sv_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 217 static struct servent * 218 sv_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 258 static void 259 sv_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 289 static struct servent * 290 sv_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 318 static void 319 sv_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 336 struct servent * 337 irs_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 386 static struct servent * 387 sv_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