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