xref: /illumos-gate/usr/src/lib/libresolv2/common/irs/irp.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2001-2002 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /*
7*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996, 1998 by Internet Software Consortium.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
10*7c478bd9Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
11*7c478bd9Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
12*7c478bd9Sstevel@tonic-gate  *
13*7c478bd9Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14*7c478bd9Sstevel@tonic-gate  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15*7c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16*7c478bd9Sstevel@tonic-gate  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17*7c478bd9Sstevel@tonic-gate  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18*7c478bd9Sstevel@tonic-gate  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19*7c478bd9Sstevel@tonic-gate  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*7c478bd9Sstevel@tonic-gate  * SOFTWARE.
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate 
23*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
26*7c478bd9Sstevel@tonic-gate static const char rcsid[] = "$Id: irp.c,v 8.8 2001/09/25 04:50:29 marka Exp $";
27*7c478bd9Sstevel@tonic-gate #endif
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /* Imports */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include "port_before.h"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <syslog.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/un.h>
37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
38*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
39*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate #include <string.h>
42*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
43*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <syslog.h>
45*7c478bd9Sstevel@tonic-gate #include <ctype.h>
46*7c478bd9Sstevel@tonic-gate #include <unistd.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #include <isc/memcluster.h>
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #include <irs.h>
51*7c478bd9Sstevel@tonic-gate #include <irp.h>
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate #include "irs_p.h"
54*7c478bd9Sstevel@tonic-gate #include "irp_p.h"
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #include "port_after.h"
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /* Forward. */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate static void		irp_close(struct irs_acc *);
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #define LINEINCR 128
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #if !defined(SUN_LEN)
65*7c478bd9Sstevel@tonic-gate #define SUN_LEN(su) \
66*7c478bd9Sstevel@tonic-gate 	(sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
67*7c478bd9Sstevel@tonic-gate #endif
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /* Public */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /* send errors to syslog if true. */
74*7c478bd9Sstevel@tonic-gate int irp_log_errors = 1;
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * This module handles the irp module connection to irpd.
78*7c478bd9Sstevel@tonic-gate  *
79*7c478bd9Sstevel@tonic-gate  * The client expects a synchronous interface to functions like
80*7c478bd9Sstevel@tonic-gate  * getpwnam(3), so we can't use the ctl_* i/o library on this end of
81*7c478bd9Sstevel@tonic-gate  * the wire (it's used in the server).
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /*
85*7c478bd9Sstevel@tonic-gate  * irs_acc *irs_irp_acc(const char *options);
86*7c478bd9Sstevel@tonic-gate  *
87*7c478bd9Sstevel@tonic-gate  *	Initialize the irp module.
88*7c478bd9Sstevel@tonic-gate  */
89*7c478bd9Sstevel@tonic-gate struct irs_acc *
90*7c478bd9Sstevel@tonic-gate irs_irp_acc(const char *options) {
91*7c478bd9Sstevel@tonic-gate 	struct irs_acc *acc;
92*7c478bd9Sstevel@tonic-gate 	struct irp_p *irp;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	UNUSED(options);
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if (!(acc = memget(sizeof *acc))) {
97*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
98*7c478bd9Sstevel@tonic-gate 		return (NULL);
99*7c478bd9Sstevel@tonic-gate 	}
100*7c478bd9Sstevel@tonic-gate 	memset(acc, 0x5e, sizeof *acc);
101*7c478bd9Sstevel@tonic-gate 	if (!(irp = memget(sizeof *irp))) {
102*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
103*7c478bd9Sstevel@tonic-gate 		free(acc);
104*7c478bd9Sstevel@tonic-gate 		return (NULL);
105*7c478bd9Sstevel@tonic-gate 	}
106*7c478bd9Sstevel@tonic-gate 	irp->inlast = 0;
107*7c478bd9Sstevel@tonic-gate 	irp->incurr = 0;
108*7c478bd9Sstevel@tonic-gate 	irp->fdCxn = -1;
109*7c478bd9Sstevel@tonic-gate 	acc->private = irp;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #ifdef WANT_IRS_GR
112*7c478bd9Sstevel@tonic-gate 	acc->gr_map = irs_irp_gr;
113*7c478bd9Sstevel@tonic-gate #else
114*7c478bd9Sstevel@tonic-gate 	acc->gr_map = NULL;
115*7c478bd9Sstevel@tonic-gate #endif
116*7c478bd9Sstevel@tonic-gate #ifdef WANT_IRS_PW
117*7c478bd9Sstevel@tonic-gate 	acc->pw_map = irs_irp_pw;
118*7c478bd9Sstevel@tonic-gate #else
119*7c478bd9Sstevel@tonic-gate 	acc->pw_map = NULL;
120*7c478bd9Sstevel@tonic-gate #endif
121*7c478bd9Sstevel@tonic-gate 	acc->sv_map = irs_irp_sv;
122*7c478bd9Sstevel@tonic-gate 	acc->pr_map = irs_irp_pr;
123*7c478bd9Sstevel@tonic-gate 	acc->ho_map = irs_irp_ho;
124*7c478bd9Sstevel@tonic-gate 	acc->nw_map = irs_irp_nw;
125*7c478bd9Sstevel@tonic-gate 	acc->ng_map = irs_irp_ng;
126*7c478bd9Sstevel@tonic-gate 	acc->close = irp_close;
127*7c478bd9Sstevel@tonic-gate 	return (acc);
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate int
132*7c478bd9Sstevel@tonic-gate irs_irp_connection_setup(struct irp_p *cxndata, int *warned) {
133*7c478bd9Sstevel@tonic-gate 	if (irs_irp_is_connected(cxndata)) {
134*7c478bd9Sstevel@tonic-gate 		return (0);
135*7c478bd9Sstevel@tonic-gate 	} else if (irs_irp_connect(cxndata) != 0) {
136*7c478bd9Sstevel@tonic-gate 		if (warned != NULL && !*warned) {
137*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "irpd connection failed: %m\n");
138*7c478bd9Sstevel@tonic-gate 			(*warned)++;
139*7c478bd9Sstevel@tonic-gate 		}
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 		return (-1);
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	return (0);
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate /*
149*7c478bd9Sstevel@tonic-gate  * int irs_irp_connect(void);
150*7c478bd9Sstevel@tonic-gate  *
151*7c478bd9Sstevel@tonic-gate  *	Sets up the connection to the remote irpd server.
152*7c478bd9Sstevel@tonic-gate  *
153*7c478bd9Sstevel@tonic-gate  * Returns:
154*7c478bd9Sstevel@tonic-gate  *
155*7c478bd9Sstevel@tonic-gate  *	0 on success, -1 on failure.
156*7c478bd9Sstevel@tonic-gate  *
157*7c478bd9Sstevel@tonic-gate  */
158*7c478bd9Sstevel@tonic-gate int
159*7c478bd9Sstevel@tonic-gate irs_irp_connect(struct irp_p *pvt) {
160*7c478bd9Sstevel@tonic-gate 	int flags;
161*7c478bd9Sstevel@tonic-gate 	struct sockaddr *addr;
162*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in iaddr;
163*7c478bd9Sstevel@tonic-gate #ifndef NO_SOCKADDR_UN
164*7c478bd9Sstevel@tonic-gate 	struct sockaddr_un uaddr;
165*7c478bd9Sstevel@tonic-gate #endif
166*7c478bd9Sstevel@tonic-gate 	long ipaddr;
167*7c478bd9Sstevel@tonic-gate 	const char *irphost;
168*7c478bd9Sstevel@tonic-gate 	int code;
169*7c478bd9Sstevel@tonic-gate 	char text[256];
170*7c478bd9Sstevel@tonic-gate 	int socklen = 0;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	if (pvt->fdCxn != -1) {
173*7c478bd9Sstevel@tonic-gate 		perror("fd != 1");
174*7c478bd9Sstevel@tonic-gate 		return (-1);
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate #ifndef NO_SOCKADDR_UN
178*7c478bd9Sstevel@tonic-gate 	memset(&uaddr, 0, sizeof uaddr);
179*7c478bd9Sstevel@tonic-gate #endif
180*7c478bd9Sstevel@tonic-gate 	memset(&iaddr, 0, sizeof iaddr);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	irphost = getenv(IRPD_HOST_ENV);
183*7c478bd9Sstevel@tonic-gate 	if (irphost == NULL) {
184*7c478bd9Sstevel@tonic-gate 		irphost = "127.0.0.1";
185*7c478bd9Sstevel@tonic-gate 	}
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate #ifndef NO_SOCKADDR_UN
188*7c478bd9Sstevel@tonic-gate 	if (irphost[0] == '/') {
189*7c478bd9Sstevel@tonic-gate 		addr = (struct sockaddr *)&uaddr;
190*7c478bd9Sstevel@tonic-gate 		strncpy(uaddr.sun_path, irphost, sizeof uaddr.sun_path);
191*7c478bd9Sstevel@tonic-gate 		uaddr.sun_family = AF_UNIX;
192*7c478bd9Sstevel@tonic-gate 		socklen = SUN_LEN(&uaddr);
193*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SA_LEN
194*7c478bd9Sstevel@tonic-gate 		uaddr.sun_len = socklen;
195*7c478bd9Sstevel@tonic-gate #endif
196*7c478bd9Sstevel@tonic-gate 	} else
197*7c478bd9Sstevel@tonic-gate #endif
198*7c478bd9Sstevel@tonic-gate 	{
199*7c478bd9Sstevel@tonic-gate 		if (inet_pton(AF_INET, irphost, &ipaddr) != 1) {
200*7c478bd9Sstevel@tonic-gate 			errno = EADDRNOTAVAIL;
201*7c478bd9Sstevel@tonic-gate 			perror("inet_pton");
202*7c478bd9Sstevel@tonic-gate 			return (-1);
203*7c478bd9Sstevel@tonic-gate 		}
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		addr = (struct sockaddr *)&iaddr;
206*7c478bd9Sstevel@tonic-gate 		socklen = sizeof iaddr;
207*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SA_LEN
208*7c478bd9Sstevel@tonic-gate 		iaddr.sin_len = socklen;
209*7c478bd9Sstevel@tonic-gate #endif
210*7c478bd9Sstevel@tonic-gate 		iaddr.sin_family = AF_INET;
211*7c478bd9Sstevel@tonic-gate 		iaddr.sin_port = htons(IRPD_PORT);
212*7c478bd9Sstevel@tonic-gate 		iaddr.sin_addr.s_addr = ipaddr;
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	pvt->fdCxn = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC);
217*7c478bd9Sstevel@tonic-gate 	if (pvt->fdCxn < 0) {
218*7c478bd9Sstevel@tonic-gate 		perror("socket");
219*7c478bd9Sstevel@tonic-gate 		return (-1);
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	if (connect(pvt->fdCxn, addr, socklen) != 0) {
223*7c478bd9Sstevel@tonic-gate 		perror("connect");
224*7c478bd9Sstevel@tonic-gate 		return (-1);
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	flags = fcntl(pvt->fdCxn, F_GETFL, 0);
228*7c478bd9Sstevel@tonic-gate 	if (flags < 0) {
229*7c478bd9Sstevel@tonic-gate 		close(pvt->fdCxn);
230*7c478bd9Sstevel@tonic-gate 		perror("close");
231*7c478bd9Sstevel@tonic-gate 		return (-1);
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate #if 0
235*7c478bd9Sstevel@tonic-gate 	flags |= O_NONBLOCK;
236*7c478bd9Sstevel@tonic-gate 	if (fcntl(pvt->fdCxn, F_SETFL, flags) < 0) {
237*7c478bd9Sstevel@tonic-gate 		close(pvt->fdCxn);
238*7c478bd9Sstevel@tonic-gate 		perror("fcntl");
239*7c478bd9Sstevel@tonic-gate 		return (-1);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate #endif
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	code = irs_irp_read_response(pvt, text, sizeof text);
244*7c478bd9Sstevel@tonic-gate 	if (code != IRPD_WELCOME_CODE) {
245*7c478bd9Sstevel@tonic-gate 		if (irp_log_errors) {
246*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING, "Connection failed: %s", text);
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 		irs_irp_disconnect(pvt);
249*7c478bd9Sstevel@tonic-gate 		return (-1);
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	return (0);
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate /*
258*7c478bd9Sstevel@tonic-gate  * int	irs_irp_is_connected(struct irp_p *pvt);
259*7c478bd9Sstevel@tonic-gate  *
260*7c478bd9Sstevel@tonic-gate  * Returns:
261*7c478bd9Sstevel@tonic-gate  *
262*7c478bd9Sstevel@tonic-gate  *	Non-zero if streams are setup to remote.
263*7c478bd9Sstevel@tonic-gate  *
264*7c478bd9Sstevel@tonic-gate  */
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate int
267*7c478bd9Sstevel@tonic-gate irs_irp_is_connected(struct irp_p *pvt) {
268*7c478bd9Sstevel@tonic-gate 	return (pvt->fdCxn >= 0);
269*7c478bd9Sstevel@tonic-gate }
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate /*
274*7c478bd9Sstevel@tonic-gate  * void
275*7c478bd9Sstevel@tonic-gate  * irs_irp_disconnect(struct irp_p *pvt);
276*7c478bd9Sstevel@tonic-gate  *
277*7c478bd9Sstevel@tonic-gate  *	Closes streams to remote.
278*7c478bd9Sstevel@tonic-gate  */
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate void
281*7c478bd9Sstevel@tonic-gate irs_irp_disconnect(struct irp_p *pvt) {
282*7c478bd9Sstevel@tonic-gate 	if (pvt->fdCxn != -1) {
283*7c478bd9Sstevel@tonic-gate 		close(pvt->fdCxn);
284*7c478bd9Sstevel@tonic-gate 		pvt->fdCxn = -1;
285*7c478bd9Sstevel@tonic-gate 	}
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate int
291*7c478bd9Sstevel@tonic-gate irs_irp_read_line(struct irp_p *pvt, char *buffer, int len) {
292*7c478bd9Sstevel@tonic-gate 	char *realstart = &pvt->inbuffer[0];
293*7c478bd9Sstevel@tonic-gate 	char *p, *start, *end;
294*7c478bd9Sstevel@tonic-gate 	int spare;
295*7c478bd9Sstevel@tonic-gate 	int i;
296*7c478bd9Sstevel@tonic-gate 	int buffpos = 0;
297*7c478bd9Sstevel@tonic-gate 	int left = len - 1;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	while (left > 0) {
300*7c478bd9Sstevel@tonic-gate 		start = p = &pvt->inbuffer[pvt->incurr];
301*7c478bd9Sstevel@tonic-gate 		end = &pvt->inbuffer[pvt->inlast];
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		while (p != end && *p != '\n')
304*7c478bd9Sstevel@tonic-gate 			p++;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 		if (p == end) {
307*7c478bd9Sstevel@tonic-gate 			/* Found no newline so shift data down if necessary
308*7c478bd9Sstevel@tonic-gate 			 * and append new data to buffer
309*7c478bd9Sstevel@tonic-gate 			 */
310*7c478bd9Sstevel@tonic-gate 			if (start > realstart) {
311*7c478bd9Sstevel@tonic-gate 				memmove(realstart, start, end - start);
312*7c478bd9Sstevel@tonic-gate 				pvt->inlast = end - start;
313*7c478bd9Sstevel@tonic-gate 				start = realstart;
314*7c478bd9Sstevel@tonic-gate 				pvt->incurr = 0;
315*7c478bd9Sstevel@tonic-gate 				end = &pvt->inbuffer[pvt->inlast];
316*7c478bd9Sstevel@tonic-gate 			}
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 			spare = sizeof (pvt->inbuffer) - pvt->inlast;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 			p = end;
321*7c478bd9Sstevel@tonic-gate 			i = read(pvt->fdCxn, end, spare);
322*7c478bd9Sstevel@tonic-gate 			if (i < 0) {
323*7c478bd9Sstevel@tonic-gate 				close(pvt->fdCxn);
324*7c478bd9Sstevel@tonic-gate 				pvt->fdCxn = -1;
325*7c478bd9Sstevel@tonic-gate 				return (buffpos > 0 ? buffpos : -1);
326*7c478bd9Sstevel@tonic-gate 			} else if (i == 0) {
327*7c478bd9Sstevel@tonic-gate 				return (buffpos);
328*7c478bd9Sstevel@tonic-gate 			}
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 			end += i;
331*7c478bd9Sstevel@tonic-gate 			pvt->inlast += i;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 			while (p != end && *p != '\n')
334*7c478bd9Sstevel@tonic-gate 				p++;
335*7c478bd9Sstevel@tonic-gate 		}
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 		if (p == end) {
338*7c478bd9Sstevel@tonic-gate 			/* full buffer and still no newline */
339*7c478bd9Sstevel@tonic-gate 			i = sizeof pvt->inbuffer;
340*7c478bd9Sstevel@tonic-gate 		} else {
341*7c478bd9Sstevel@tonic-gate 			/* include newline */
342*7c478bd9Sstevel@tonic-gate 			i = p - start + 1;
343*7c478bd9Sstevel@tonic-gate 		}
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 		if (i > left)
346*7c478bd9Sstevel@tonic-gate 			i = left;
347*7c478bd9Sstevel@tonic-gate 		memcpy(buffer + buffpos, start, i);
348*7c478bd9Sstevel@tonic-gate 		pvt->incurr += i;
349*7c478bd9Sstevel@tonic-gate 		buffpos += i;
350*7c478bd9Sstevel@tonic-gate 		buffer[buffpos] = '\0';
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 		if (p != end) {
353*7c478bd9Sstevel@tonic-gate 			left = 0;
354*7c478bd9Sstevel@tonic-gate 		} else {
355*7c478bd9Sstevel@tonic-gate 			left -= i;
356*7c478bd9Sstevel@tonic-gate 		}
357*7c478bd9Sstevel@tonic-gate 	}
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate #if 0
360*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "read line: %s\n", buffer);
361*7c478bd9Sstevel@tonic-gate #endif
362*7c478bd9Sstevel@tonic-gate 	return (buffpos);
363*7c478bd9Sstevel@tonic-gate }
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate /*
370*7c478bd9Sstevel@tonic-gate  * int irp_read_response(struct irp_p *pvt);
371*7c478bd9Sstevel@tonic-gate  *
372*7c478bd9Sstevel@tonic-gate  * Returns:
373*7c478bd9Sstevel@tonic-gate  *
374*7c478bd9Sstevel@tonic-gate  *	The number found at the beginning of the line read from
375*7c478bd9Sstevel@tonic-gate  *	FP. 0 on failure(0 is not a legal response code). The
376*7c478bd9Sstevel@tonic-gate  *	rest of the line is discarded.
377*7c478bd9Sstevel@tonic-gate  *
378*7c478bd9Sstevel@tonic-gate  */
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate int
381*7c478bd9Sstevel@tonic-gate irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen) {
382*7c478bd9Sstevel@tonic-gate 	char line[1024];
383*7c478bd9Sstevel@tonic-gate 	int code;
384*7c478bd9Sstevel@tonic-gate 	char *p;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	if (irs_irp_read_line(pvt, line, sizeof line) <= 0) {
387*7c478bd9Sstevel@tonic-gate 		return (0);
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	p = strchr(line, '\n');
391*7c478bd9Sstevel@tonic-gate 	if (p == NULL) {
392*7c478bd9Sstevel@tonic-gate 		return (0);
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	if (sscanf(line, "%d", &code) != 1) {
396*7c478bd9Sstevel@tonic-gate 		code = 0;
397*7c478bd9Sstevel@tonic-gate 	} else if (text != NULL && textlen > 0) {
398*7c478bd9Sstevel@tonic-gate 		p = line;
399*7c478bd9Sstevel@tonic-gate 		while (isspace((unsigned char)*p)) p++;
400*7c478bd9Sstevel@tonic-gate 		while (isdigit((unsigned char)*p)) p++;
401*7c478bd9Sstevel@tonic-gate 		while (isspace((unsigned char)*p)) p++;
402*7c478bd9Sstevel@tonic-gate 		strncpy(text, p, textlen - 1);
403*7c478bd9Sstevel@tonic-gate 		p[textlen - 1] = '\0';
404*7c478bd9Sstevel@tonic-gate 	}
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	return (code);
407*7c478bd9Sstevel@tonic-gate }
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate /*
412*7c478bd9Sstevel@tonic-gate  * char *irp_read_body(struct irp_p *pvt, size_t *size);
413*7c478bd9Sstevel@tonic-gate  *
414*7c478bd9Sstevel@tonic-gate  *	Read in the body of a response. Terminated by a line with
415*7c478bd9Sstevel@tonic-gate  *	just a dot on it. Lines should be terminated with a CR-LF
416*7c478bd9Sstevel@tonic-gate  *	sequence, but we're nt piccky if the CR is missing.
417*7c478bd9Sstevel@tonic-gate  *	No leading dot escaping is done as the protcol doesn't
418*7c478bd9Sstevel@tonic-gate  *	use leading dots anywhere.
419*7c478bd9Sstevel@tonic-gate  *
420*7c478bd9Sstevel@tonic-gate  * Returns:
421*7c478bd9Sstevel@tonic-gate  *
422*7c478bd9Sstevel@tonic-gate  *	Pointer to null-terminated buffer allocated by memget.
423*7c478bd9Sstevel@tonic-gate  *	*SIZE is set to the length of the buffer.
424*7c478bd9Sstevel@tonic-gate  *
425*7c478bd9Sstevel@tonic-gate  */
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate char *
428*7c478bd9Sstevel@tonic-gate irs_irp_read_body(struct irp_p *pvt, size_t *size) {
429*7c478bd9Sstevel@tonic-gate 	char line[1024];
430*7c478bd9Sstevel@tonic-gate 	u_int linelen;
431*7c478bd9Sstevel@tonic-gate 	size_t len = LINEINCR;
432*7c478bd9Sstevel@tonic-gate 	char *buffer = memget(len);
433*7c478bd9Sstevel@tonic-gate 	int idx = 0;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	for (;;) {
436*7c478bd9Sstevel@tonic-gate 		if (irs_irp_read_line(pvt, line, sizeof line) <= 0 ||
437*7c478bd9Sstevel@tonic-gate 		    strchr(line, '\n') == NULL)
438*7c478bd9Sstevel@tonic-gate 			goto death;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 		linelen = strlen(line);
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 		if (line[linelen - 1] != '\n')
443*7c478bd9Sstevel@tonic-gate 			goto death;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		/* We're not strict about missing \r. Should we be??  */
446*7c478bd9Sstevel@tonic-gate 		if (linelen > 2 && line[linelen - 2] == '\r') {
447*7c478bd9Sstevel@tonic-gate 			line[linelen - 2] = '\n';
448*7c478bd9Sstevel@tonic-gate 			line[linelen - 1] = '\0';
449*7c478bd9Sstevel@tonic-gate 			linelen--;
450*7c478bd9Sstevel@tonic-gate 		}
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		if (linelen == 2 && line[0] == '.') {
453*7c478bd9Sstevel@tonic-gate 			*size = len;
454*7c478bd9Sstevel@tonic-gate 			buffer[idx] = '\0';
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 			return (buffer);
457*7c478bd9Sstevel@tonic-gate 		}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 		if (linelen > (len - (idx + 1))) {
460*7c478bd9Sstevel@tonic-gate 			char *p = memget(len + LINEINCR);
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 			if (p == NULL)
463*7c478bd9Sstevel@tonic-gate 				goto death;
464*7c478bd9Sstevel@tonic-gate 			memcpy(p, buffer, len);
465*7c478bd9Sstevel@tonic-gate 			memput(buffer, len);
466*7c478bd9Sstevel@tonic-gate 			buffer = p;
467*7c478bd9Sstevel@tonic-gate 			len += LINEINCR;
468*7c478bd9Sstevel@tonic-gate 		}
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		memcpy(buffer + idx, line, linelen);
471*7c478bd9Sstevel@tonic-gate 		idx += linelen;
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate  death:
474*7c478bd9Sstevel@tonic-gate 	memput(buffer, len);
475*7c478bd9Sstevel@tonic-gate 	return (NULL);
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate /*
480*7c478bd9Sstevel@tonic-gate  * int irs_irp_get_full_response(struct irp_p *pvt, int *code,
481*7c478bd9Sstevel@tonic-gate  *			char **body, size_t *bodylen);
482*7c478bd9Sstevel@tonic-gate  *
483*7c478bd9Sstevel@tonic-gate  *	Gets the response to a command. If the response indicates
484*7c478bd9Sstevel@tonic-gate  *	there's a body to follow(code % 10 == 1), then the
485*7c478bd9Sstevel@tonic-gate  *	body buffer is allcoated with memget and stored in
486*7c478bd9Sstevel@tonic-gate  *	*BODY. The length of the allocated body buffer is stored
487*7c478bd9Sstevel@tonic-gate  *	in *BODY. The caller must give the body buffer back to
488*7c478bd9Sstevel@tonic-gate  *	memput when done. The results code is stored in *CODE.
489*7c478bd9Sstevel@tonic-gate  *
490*7c478bd9Sstevel@tonic-gate  * Returns:
491*7c478bd9Sstevel@tonic-gate  *
492*7c478bd9Sstevel@tonic-gate  *	0 if a result was read. -1 on some sort of failure.
493*7c478bd9Sstevel@tonic-gate  *
494*7c478bd9Sstevel@tonic-gate  */
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate int
497*7c478bd9Sstevel@tonic-gate irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text,
498*7c478bd9Sstevel@tonic-gate 			  size_t textlen, char **body, size_t *bodylen) {
499*7c478bd9Sstevel@tonic-gate 	int result = irs_irp_read_response(pvt, text, textlen);
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	*body = NULL;
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	if (result == 0) {
504*7c478bd9Sstevel@tonic-gate 		return (-1);
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	*code = result;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	/* Code that matches 2xx is a good result code.
510*7c478bd9Sstevel@tonic-gate 	 * Code that matches xx1 means there's a response body coming.
511*7c478bd9Sstevel@tonic-gate 	 */
512*7c478bd9Sstevel@tonic-gate 	if ((result / 100) == 2 && (result % 10) == 1) {
513*7c478bd9Sstevel@tonic-gate 		*body = irs_irp_read_body(pvt, bodylen);
514*7c478bd9Sstevel@tonic-gate 		if (*body == NULL) {
515*7c478bd9Sstevel@tonic-gate 			return (-1);
516*7c478bd9Sstevel@tonic-gate 		}
517*7c478bd9Sstevel@tonic-gate 	}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	return (0);
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate /*
524*7c478bd9Sstevel@tonic-gate  * int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...);
525*7c478bd9Sstevel@tonic-gate  *
526*7c478bd9Sstevel@tonic-gate  *	Sends command to remote connected via the PVT
527*7c478bd9Sstevel@tonic-gate  *	struture. FMT and args after it are fprintf-like
528*7c478bd9Sstevel@tonic-gate  *	arguments for formatting.
529*7c478bd9Sstevel@tonic-gate  *
530*7c478bd9Sstevel@tonic-gate  * Returns:
531*7c478bd9Sstevel@tonic-gate  *
532*7c478bd9Sstevel@tonic-gate  *	0 on success, -1 on failure.
533*7c478bd9Sstevel@tonic-gate  */
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate int
536*7c478bd9Sstevel@tonic-gate irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...) {
537*7c478bd9Sstevel@tonic-gate 	va_list ap;
538*7c478bd9Sstevel@tonic-gate 	char buffer[1024];
539*7c478bd9Sstevel@tonic-gate 	int pos = 0;
540*7c478bd9Sstevel@tonic-gate 	int i, todo;
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	if (pvt->fdCxn < 0) {
544*7c478bd9Sstevel@tonic-gate 		return (-1);
545*7c478bd9Sstevel@tonic-gate 	}
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
548*7c478bd9Sstevel@tonic-gate 	todo = vsprintf(buffer, fmt, ap);
549*7c478bd9Sstevel@tonic-gate 	va_end(ap);
550*7c478bd9Sstevel@tonic-gate 	if (todo > (int)sizeof(buffer) - 3) {
551*7c478bd9Sstevel@tonic-gate 		syslog(LOG_CRIT, "memory overrun in irs_irp_send_command()");
552*7c478bd9Sstevel@tonic-gate 		exit(1);
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 	strcat(buffer, "\r\n");
555*7c478bd9Sstevel@tonic-gate 	todo = strlen(buffer);
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	while (todo > 0) {
558*7c478bd9Sstevel@tonic-gate 		i = write(pvt->fdCxn, buffer + pos, todo);
559*7c478bd9Sstevel@tonic-gate #if 0
560*7c478bd9Sstevel@tonic-gate 		/* XXX brister */
561*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "Wrote: \"");
562*7c478bd9Sstevel@tonic-gate 		fwrite(buffer + pos, sizeof (char), todo, stderr);
563*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\"\n");
564*7c478bd9Sstevel@tonic-gate #endif
565*7c478bd9Sstevel@tonic-gate 		if (i < 0) {
566*7c478bd9Sstevel@tonic-gate 			close(pvt->fdCxn);
567*7c478bd9Sstevel@tonic-gate 			pvt->fdCxn = -1;
568*7c478bd9Sstevel@tonic-gate 			return (-1);
569*7c478bd9Sstevel@tonic-gate 		}
570*7c478bd9Sstevel@tonic-gate 		todo -= i;
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	return (0);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate /* Methods */
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate /*
582*7c478bd9Sstevel@tonic-gate  * void irp_close(struct irs_acc *this)
583*7c478bd9Sstevel@tonic-gate  *
584*7c478bd9Sstevel@tonic-gate  */
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate static void
587*7c478bd9Sstevel@tonic-gate irp_close(struct irs_acc *this) {
588*7c478bd9Sstevel@tonic-gate 	struct irp_p *irp = (struct irp_p *)this->private;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	if (irp != NULL) {
591*7c478bd9Sstevel@tonic-gate 		irs_irp_disconnect(irp);
592*7c478bd9Sstevel@tonic-gate 		memput(irp, sizeof *irp);
593*7c478bd9Sstevel@tonic-gate 	}
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	memput(this, sizeof *this);
596*7c478bd9Sstevel@tonic-gate }
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 
600