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