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 *
irs_lcl_sv(struct irs_acc * this)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
sv_close(struct irs_sv * this)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 *
sv_byname(struct irs_sv * this,const char * name,const char * proto)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 *
sv_byport(struct irs_sv * this,int port,const char * proto)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
sv_rewind(struct irs_sv * this)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 *
sv_next(struct irs_sv * this)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
sv_minimize(struct irs_sv * this)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 *
irs_lclsv_fnxt(struct lcl_sv * sv)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 *
sv_db_rec(struct lcl_sv * sv,DBT * key,DBT * data)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