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