1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (c) 1996,1998 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: irp_sv.c,v 1.3 2005/04/27 04:56:29 sra Exp $";
20 #endif /* LIBC_SCCS and not lint */
21 
22 /* extern */
23 
24 #include "port_before.h"
25 
26 #include <syslog.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 
30 #ifdef IRS_LCL_SV_DB
31 #include <db.h>
32 #endif
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <syslog.h>
40 
41 #include <irs.h>
42 #include <irp.h>
43 #include <isc/irpmarshall.h>
44 #include <isc/memcluster.h>
45 
46 #include "irs_p.h"
47 #include "lcl_p.h"
48 #include "irp_p.h"
49 
50 #include "port_after.h"
51 
52 /* Types */
53 
54 struct pvt {
55 	struct irp_p	       *girpdata;
56 	int			warned;
57 	struct servent		service;
58 };
59 
60 /* Forward */
61 
62 static void			sv_close(struct irs_sv*);
63 static struct servent *		sv_next(struct irs_sv *);
64 static struct servent *		sv_byname(struct irs_sv *, const char *,
65 					  const char *);
66 static struct servent *		sv_byport(struct irs_sv *, int, const char *);
67 static void			sv_rewind(struct irs_sv *);
68 static void			sv_minimize(struct irs_sv *);
69 
70 static void			free_service(struct servent *sv);
71 
72 
73 
74 /* Public */
75 
76 /*%
77  * struct irs_sv * irs_irp_sv(struct irs_acc *this)
78  *
79  */
80 
81 struct irs_sv *
82 irs_irp_sv(struct irs_acc *this) {
83 	struct irs_sv *sv;
84 	struct pvt *pvt;
85 
86 	if ((sv = memget(sizeof *sv)) == NULL) {
87 		errno = ENOMEM;
88 		return (NULL);
89 	}
90 	memset(sv, 0x0, sizeof *sv);
91 
92 	if ((pvt = memget(sizeof *pvt)) == NULL) {
93 		memput(sv, sizeof *sv);
94 		errno = ENOMEM;
95 		return (NULL);
96 	}
97 	memset(pvt, 0, sizeof *pvt);
98 	pvt->girpdata = this->private;
99 
100 	sv->private = pvt;
101 	sv->close = sv_close;
102 	sv->next = sv_next;
103 	sv->byname = sv_byname;
104 	sv->byport = sv_byport;
105 	sv->rewind = sv_rewind;
106 	sv->minimize = sv_minimize;
107 
108 	return (sv);
109 }
110 
111 /* Methods */
112 
113 /*%
114  * void sv_close(struct irs_sv *this)
115  *
116  */
117 
118 static void
119 sv_close(struct irs_sv *this) {
120 	struct pvt *pvt = (struct pvt *)this->private;
121 
122 	sv_minimize(this);
123 
124 	free_service(&pvt->service);
125 
126 	memput(pvt, sizeof *pvt);
127 	memput(this, sizeof *this);
128 }
129 
130 /*%
131  *	Fills the cache if necessary and returns the next item from it.
132  *
133  */
134 
135 static struct servent *
136 sv_next(struct irs_sv *this) {
137 	struct pvt *pvt = (struct pvt *)this->private;
138 	struct servent *sv = &pvt->service;
139 	char *body;
140 	size_t bodylen;
141 	int code;
142 	char text[256];
143 
144 	if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
145 		return (NULL);
146 	}
147 
148 	if (irs_irp_send_command(pvt->girpdata, "getservent") != 0) {
149 		return (NULL);
150 	}
151 
152 	if (irs_irp_get_full_response(pvt->girpdata, &code,
153 				      text, sizeof text,
154 				      &body, &bodylen) != 0) {
155 		return (NULL);
156 	}
157 
158 	if (code == IRPD_GETSERVICE_OK) {
159 		free_service(sv);
160 		if (irp_unmarshall_sv(sv, body) != 0) {
161 			sv = NULL;
162 		}
163 	} else {
164 		sv = NULL;
165 	}
166 
167 	if (body != NULL) {
168 		memput(body, bodylen);
169 	}
170 
171 	return (sv);
172 }
173 
174 /*%
175  * struct servent * sv_byname(struct irs_sv *this, const char *name,
176  *				const char *proto)
177  *
178  */
179 
180 static struct servent *
181 sv_byname(struct irs_sv *this, const char *name, const char *proto) {
182 	struct pvt *pvt = (struct pvt *)this->private;
183 	struct servent *sv = &pvt->service;
184 	char *body;
185 	char text[256];
186 	size_t bodylen;
187 	int code;
188 
189 	if (sv->s_name != NULL &&
190 	    strcmp(name, sv->s_name) == 0 &&
191 	    strcasecmp(proto, sv->s_proto) == 0) {
192 		return (sv);
193 	}
194 
195 	if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
196 		return (NULL);
197 	}
198 
199 	if (irs_irp_send_command(pvt->girpdata, "getservbyname %s %s",
200 				 name, proto) != 0)
201 		return (NULL);
202 
203 	if (irs_irp_get_full_response(pvt->girpdata, &code,
204 				      text, sizeof text,
205 				      &body, &bodylen) != 0) {
206 		return (NULL);
207 	}
208 
209 	if (code == IRPD_GETSERVICE_OK) {
210 		free_service(sv);
211 		if (irp_unmarshall_sv(sv, body) != 0) {
212 			sv = NULL;
213 		}
214 	} else {
215 		sv = NULL;
216 	}
217 
218 	if (body != NULL) {
219 		memput(body, bodylen);
220 	}
221 
222 	return (sv);
223 }
224 
225 /*%
226  * struct servent * sv_byport(struct irs_sv *this, int port,
227  *				const char *proto)
228  *
229  */
230 
231 static struct servent *
232 sv_byport(struct irs_sv *this, int port, const char *proto) {
233 	struct pvt *pvt = (struct pvt *)this->private;
234 	struct servent *sv = &pvt->service;
235 	char *body;
236 	size_t bodylen;
237 	char text[256];
238 	int code;
239 
240 	if (sv->s_name != NULL &&
241 	    port == sv->s_port &&
242 	    strcasecmp(proto, sv->s_proto) == 0) {
243 		return (sv);
244 	}
245 
246 	if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
247 		return (NULL);
248 	}
249 
250 	if (irs_irp_send_command(pvt->girpdata, "getservbyport %d %s",
251 				 ntohs((short)port), proto) != 0) {
252 		return (NULL);
253 	}
254 
255 	if (irs_irp_get_full_response(pvt->girpdata, &code,
256 				      text, sizeof text,
257 				      &body, &bodylen) != 0) {
258 		return (NULL);
259 	}
260 
261 	if (code == IRPD_GETSERVICE_OK) {
262 		free_service(sv);
263 		if (irp_unmarshall_sv(sv, body) != 0) {
264 			sv = NULL;
265 		}
266 	} else {
267 		sv = NULL;
268 	}
269 
270 	if (body != NULL) {
271 		memput(body, bodylen);
272 	}
273 
274 	return (sv);
275 }
276 
277 /*%
278  * void sv_rewind(struct irs_sv *this)
279  *
280  */
281 
282 static void
283 sv_rewind(struct irs_sv *this) {
284 	struct pvt *pvt = (struct pvt *)this->private;
285 	char text[256];
286 	int code;
287 
288 	if (irs_irp_connection_setup(pvt->girpdata, &pvt->warned) != 0) {
289 		return;
290 	}
291 
292 	if (irs_irp_send_command(pvt->girpdata, "setservent") != 0) {
293 		return;
294 	}
295 
296 	code = irs_irp_read_response(pvt->girpdata, text, sizeof text);
297 	if (code != IRPD_GETSERVICE_SETOK) {
298 		if (irp_log_errors) {
299 			syslog(LOG_WARNING, "setservent failed: %s", text);
300 		}
301 	}
302 
303 	return;
304 }
305 
306 /*%
307  * void sv_minimize(struct irs_sv *this)
308  *
309  */
310 
311 static void
312 sv_minimize(struct irs_sv *this) {
313 	struct pvt *pvt = (struct pvt *)this->private;
314 
315 	irs_irp_disconnect(pvt->girpdata);
316 }
317 
318 
319 
320 
321 
322 
323 static void
324 free_service(struct servent *sv) {
325 	char **p;
326 
327 	if (sv == NULL) {
328 		return;
329 	}
330 
331 	if (sv->s_name != NULL) {
332 		free(sv->s_name);
333 	}
334 
335 	for (p = sv->s_aliases ; p != NULL && *p != NULL ; p++) {
336 		free(*p);
337 	}
338 
339 	if (sv->s_proto != NULL) {
340 		free(sv->s_proto);
341 	}
342 }
343 
344 
345 
346 /*! \file */
347