/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ #define USE_REMOTE /* @(#)scsi-remote.c 1.18 06/01/12 Copyright 1990,2000-2003 J. Schilling */ /* * Remote SCSI user level command transport routines * * Warning: you may change this source, but if you do that * you need to change the _usal_version and _usal_auth* string below. * You may not return "schily" for an SCG_AUTHOR request anymore. * Choose your name instead of "schily" and make clear that the version * string is related to a modified source. * * Copyright (c) 1990,2000-2003 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2) #undef USE_RCMD_RSH #endif /* * We may work without getservbyname() if we restructure the code not to * use the port number if we only use _rcmdrsh(). */ #if !defined(HAVE_GETSERVBYNAME) #undef USE_REMOTE /* Cannot get rcmd() port # */ #endif #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH) #undef USE_REMOTE /* There is no rcmd() */ #endif #ifdef USE_REMOTE #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #include #include #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_PWD_H #include #endif #include #include #include #include #include #include #include #if defined(SIGDEFER) || defined(SVR4) #define signal sigset #endif /* * On Cygwin, there are no privilleged ports. * On UNIX, rcmd() uses privilleged port that only work for root. */ #ifdef IS_CYGWIN #define privport_ok() (1) #else #ifdef HAVE_GETPPRIV #define privport_ok() ppriv_ok() #else #define privport_ok() (geteuid() == 0) #endif #endif #define CMD_SIZE 80 #define MAX_SCG 16 /* Max # of SCSI controllers */ #define MAX_TGT 16 #define MAX_LUN 8 /*extern BOOL debug;*/ LOCAL BOOL debug = 1; LOCAL char _usal_trans_version[] = "remote-1.18"; /* The version for remote SCSI */ LOCAL char _usal_auth_cdrkit[] = "cdrkit-team"; /* The author for this module */ LOCAL int usalo_rsend __PR((SCSI *usalp)); LOCAL char * usalo_rversion __PR((SCSI *usalp, int what)); LOCAL int usalo_rhelp __PR((SCSI *usalp, FILE *f)); LOCAL int usalo_ropen __PR((SCSI *usalp, char *device)); LOCAL int usalo_rclose __PR((SCSI *usalp)); LOCAL long usalo_rmaxdma __PR((SCSI *usalp, long amt)); LOCAL void * usalo_rgetbuf __PR((SCSI *usalp, long amt)); LOCAL void usalo_rfreebuf __PR((SCSI *usalp)); LOCAL BOOL usalo_rhavebus __PR((SCSI *usalp, int busno)); LOCAL int usalo_rfileno __PR((SCSI *usalp, int busno, int tgt, int tlun)); LOCAL int usalo_rinitiator_id __PR((SCSI *usalp)); LOCAL int usalo_risatapi __PR((SCSI *usalp)); LOCAL int usalo_rreset __PR((SCSI *usalp, int what)); /* * XXX We should rethink the fd parameter now that we introduced * XXX the rscsirchar() function and most access of remfd is done * XXX via usallocal(usalp)->remfd. */ LOCAL void rscsiabrt __PR((int sig)); LOCAL int rscsigetconn __PR((SCSI *usalp, char *host)); LOCAL char *rscsiversion __PR((SCSI *usalp, int fd, int what)); LOCAL int rscsiopen __PR((SCSI *usalp, int fd, char *fname)); LOCAL int rscsiclose __PR((SCSI *usalp, int fd)); LOCAL int rscsimaxdma __PR((SCSI *usalp, int fd, long amt)); LOCAL int rscsigetbuf __PR((SCSI *usalp, int fd, long amt)); LOCAL int rscsifreebuf __PR((SCSI *usalp, int fd)); LOCAL int rscsihavebus __PR((SCSI *usalp, int fd, int bus)); LOCAL int rscsifileno __PR((SCSI *usalp, int fd, int busno, int tgt, int tlun)); LOCAL int rscsiinitiator_id __PR((SCSI *usalp, int fd)); LOCAL int rscsiisatapi __PR((SCSI *usalp, int fd)); LOCAL int rscsireset __PR((SCSI *usalp, int fd, int what)); LOCAL int rscsiscmd __PR((SCSI *usalp, int fd, struct usal_cmd *sp)); LOCAL int rscsifillrbuf __PR((SCSI *usalp)); LOCAL int rscsirchar __PR((SCSI *usalp, char *cp)); LOCAL int rscsireadbuf __PR((SCSI *usalp, int fd, char *buf, int count)); LOCAL void rscsivoidarg __PR((SCSI *usalp, int fd, int count)); LOCAL int rscsicmd __PR((SCSI *usalp, int fd, char *name, char *cbuf)); LOCAL void rscsisendcmd __PR((SCSI *usalp, int fd, char *name, char *cbuf)); LOCAL int rscsigetline __PR((SCSI *usalp, int fd, char *line, int count)); LOCAL int rscsireadnum __PR((SCSI *usalp, int fd)); LOCAL int rscsigetstatus __PR((SCSI *usalp, int fd, char *name)); LOCAL int rscsiaborted __PR((SCSI *usalp, int fd)); #ifdef USE_RCMD_RSH LOCAL int _rcmdrsh __PR((char **ahost, int inport, const char *locuser, const char *remuser, const char *cmd, const char *rsh)); #ifdef HAVE_GETPPRIV LOCAL BOOL ppriv_ok __PR((void)); #endif #endif /*--------------------------------------------------------------------------*/ #define READBUF_SIZE 128 struct usal_local { int remfd; char readbuf[READBUF_SIZE]; char *readbptr; int readbcnt; BOOL isopen; int rsize; int wsize; char *v_version; char *v_author; char *v_sccs_id; }; #define usallocal(p) ((struct usal_local *)((p)->local)) usal_ops_t remote_ops = { usalo_rsend, /* "S" end */ usalo_rversion, /* "V" ersion */ usalo_rhelp, /* help */ usalo_ropen, /* "O" pen */ usalo_rclose, /* "C" lose */ usalo_rmaxdma, /* "D" MA */ usalo_rgetbuf, /* "M" alloc */ usalo_rfreebuf, /* "F" free */ usalo_rhavebus, /* "B" us */ usalo_rfileno, /* "T" arget */ usalo_rinitiator_id, /* "I" nitiator */ usalo_risatapi, /* "A" tapi */ usalo_rreset, /* "R" eset */ }; /* * Return our ops ptr. */ usal_ops_t * usal_remote() { return (&remote_ops); } /* * Return version information for the low level SCSI transport code. * This has been introduced to make it easier to trace down problems * in applications. */ LOCAL char * usalo_rversion(usalp, what) SCSI *usalp; int what; { int f; if (usalp->local == NULL) return ((char *)0); f = usallocal(usalp)->remfd; if (usalp != (SCSI *)0) { switch (what) { case SCG_VERSION: return (_usal_trans_version); /* * If you changed this source, you are not allowed to * return "schily" for the SCG_AUTHOR request. */ case SCG_AUTHOR: return (_usal_auth_cdrkit); case SCG_SCCS_ID: return (__sccsid); case SCG_RVERSION: if (usallocal(usalp)->v_version == NULL) usallocal(usalp)->v_version = rscsiversion(usalp, f, SCG_VERSION); return (usallocal(usalp)->v_version); /* * If you changed this source, you are not allowed to * return "schily" for the SCG_AUTHOR request. */ case SCG_RAUTHOR: if (usallocal(usalp)->v_author == NULL) usallocal(usalp)->v_author = rscsiversion(usalp, f, SCG_AUTHOR); return (usallocal(usalp)->v_author); case SCG_RSCCS_ID: if (usallocal(usalp)->v_sccs_id == NULL) usallocal(usalp)->v_sccs_id = rscsiversion(usalp, f, SCG_SCCS_ID); return (usallocal(usalp)->v_sccs_id); } } return ((char *)0); } LOCAL int usalo_rhelp(usalp, f) SCSI *usalp; FILE *f; { __usal_help(f, "RSCSI", "Remote SCSI", "REMOTE:", "rscsi@host:bus,target,lun", "REMOTE:rscsi@host:1,2,0", TRUE, FALSE); return (0); } LOCAL int usalo_ropen(usalp, device) SCSI *usalp; char *device; { int busno = usal_scsibus(usalp); int tgt = usal_target(usalp); int tlun = usal_lun(usalp); register int f; register int nopen = 0; char devname[128]; char *p; if (usalp->overbose) fprintf(stderr, "Warning: Using remote SCSI interface.\n"); if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) { errno = EINVAL; if (usalp->errstr) snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "Illegal value for busno, target or lun '%d,%d,%d'", busno, tgt, tlun); return (-1); } if (usalp->local == NULL) { usalp->local = malloc(sizeof (struct usal_local)); if (usalp->local == NULL) return (0); usallocal(usalp)->remfd = -1; usallocal(usalp)->readbptr = usallocal(usalp)->readbuf; usallocal(usalp)->readbcnt = 0; usallocal(usalp)->isopen = FALSE; usallocal(usalp)->rsize = 0; usallocal(usalp)->wsize = 0; usallocal(usalp)->v_version = NULL; usallocal(usalp)->v_author = NULL; usallocal(usalp)->v_sccs_id = NULL; } if (device == NULL || (strncmp(device, "REMOTE", 6) != 0) || (device = strchr(device, ':')) == NULL) { if (usalp->errstr) snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "Illegal remote device syntax"); return (-1); } device++; /* * Save non user@host:device */ snprintf(devname, sizeof (devname), "%s", device); if ((p = strchr(devname, ':')) != NULL) *p++ = '\0'; f = rscsigetconn(usalp, devname); if (f < 0) { if (usalp->errstr) snprintf(usalp->errstr, SCSI_ERRSTR_SIZE, "Cannot get connection to remote host"); return (-1); } usallocal(usalp)->remfd = f; debug = usalp->debug; if (rscsiopen(usalp, f, p) >= 0) { nopen++; usallocal(usalp)->isopen = TRUE; } return (nopen); } LOCAL int usalo_rclose(usalp) SCSI *usalp; { register int f; int ret; if (usalp->local == NULL) return (-1); if (usallocal(usalp)->v_version != NULL) { free(usallocal(usalp)->v_version); usallocal(usalp)->v_version = NULL; } if (usallocal(usalp)->v_author != NULL) { free(usallocal(usalp)->v_author); usallocal(usalp)->v_author = NULL; } if (usallocal(usalp)->v_sccs_id != NULL) { free(usallocal(usalp)->v_sccs_id); usallocal(usalp)->v_sccs_id = NULL; } f = usallocal(usalp)->remfd; if (f < 0 || !usallocal(usalp)->isopen) return (0); ret = rscsiclose(usalp, f); usallocal(usalp)->isopen = FALSE; close(f); usallocal(usalp)->remfd = -1; return (ret); } LOCAL long usalo_rmaxdma(usalp, amt) SCSI *usalp; long amt; { if (usalp->local == NULL) return (-1L); return (rscsimaxdma(usalp, usallocal(usalp)->remfd, amt)); } LOCAL void * usalo_rgetbuf(usalp, amt) SCSI *usalp; long amt; { int ret; if (usalp->local == NULL) return ((void *)0); ret = rscsigetbuf(usalp, usallocal(usalp)->remfd, amt); if (ret < 0) return ((void *)0); #ifdef HAVE_VALLOC usalp->bufbase = (void *)valloc((size_t)amt); #else usalp->bufbase = (void *)malloc((size_t)amt); #endif if (usalp->bufbase == NULL) { usalo_rfreebuf(usalp); return ((void *)0); } return (usalp->bufbase); } LOCAL void usalo_rfreebuf(usalp) SCSI *usalp; { int f; if (usalp->bufbase) free(usalp->bufbase); usalp->bufbase = NULL; if (usalp->local == NULL) return; f = usallocal(usalp)->remfd; if (f < 0 || !usallocal(usalp)->isopen) return; rscsifreebuf(usalp, f); } LOCAL BOOL usalo_rhavebus(usalp, busno) SCSI *usalp; int busno; { if (usalp->local == NULL || busno < 0 || busno >= MAX_SCG) return (FALSE); return (rscsihavebus(usalp, usallocal(usalp)->remfd, busno)); } LOCAL int usalo_rfileno(usalp, busno, tgt, tlun) SCSI *usalp; int busno; int tgt; int tlun; { int f; if (usalp->local == NULL || busno < 0 || busno >= MAX_SCG || tgt < 0 || tgt >= MAX_TGT || tlun < 0 || tlun >= MAX_LUN) return (-1); f = usallocal(usalp)->remfd; if (f < 0 || !usallocal(usalp)->isopen) return (-1); return (rscsifileno(usalp, f, busno, tgt, tlun)); } LOCAL int usalo_rinitiator_id(usalp) SCSI *usalp; { if (usalp->local == NULL) return (-1); return (rscsiinitiator_id(usalp, usallocal(usalp)->remfd)); } LOCAL int usalo_risatapi(usalp) SCSI *usalp; { if (usalp->local == NULL) return (-1); return (rscsiisatapi(usalp, usallocal(usalp)->remfd)); } LOCAL int usalo_rreset(usalp, what) SCSI *usalp; int what; { if (usalp->local == NULL) return (-1); return (rscsireset(usalp, usallocal(usalp)->remfd, what)); } LOCAL int usalo_rsend(usalp) SCSI *usalp; { struct usal_cmd *sp = usalp->scmd; int ret; if (usalp->local == NULL) return (-1); if (usalp->fd < 0) { sp->error = SCG_FATAL; return (0); } ret = rscsiscmd(usalp, usallocal(usalp)->remfd, usalp->scmd); return (ret); } /*--------------------------------------------------------------------------*/ LOCAL void rscsiabrt(sig) int sig; { rscsiaborted((SCSI *)0, -1); } LOCAL int rscsigetconn(usalp, host) SCSI *usalp; char *host; { static struct servent *sp = 0; static struct passwd *pw = 0; char *name = "root"; char *p; char *rscsi; char *rsh; int rscsisock; char *rscsipeer; char rscsiuser[128]; signal(SIGPIPE, rscsiabrt); if (sp == 0) { sp = getservbyname("shell", "tcp"); if (sp == 0) { comerrno(EX_BAD, "shell/tcp: unknown service\n"); /* NOTREACHED */ } pw = getpwuid(getuid()); if (pw == 0) { comerrno(EX_BAD, "who are you? No passwd entry found.\n"); /* NOTREACHED */ } } if ((p = strchr(host, '@')) != NULL) { size_t d = p - host; if (d > sizeof (rscsiuser)) d = sizeof (rscsiuser); snprintf(rscsiuser, sizeof (rscsiuser), "%.*s", (int)d, host); name = rscsiuser; host = &p[1]; } else { name = pw->pw_name; } if (usalp->debug > 0) errmsgno(EX_BAD, "locuser: '%s' rscsiuser: '%s' host: '%s'\n", pw->pw_name, name, host); rscsipeer = host; if ((rscsi = getenv("RSCSI")) == NULL) rscsi = "/usr/sbin/netscsid"; rsh = getenv("RSH"); #ifdef USE_RCMD_RSH if (!privport_ok() || rsh != NULL) rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port, pw->pw_name, name, rscsi, rsh); else #endif #ifdef HAVE_RCMD rscsisock = rcmd(&rscsipeer, (unsigned short)sp->s_port, pw->pw_name, name, rscsi, 0); #else rscsisock = _rcmdrsh(&rscsipeer, (unsigned short)sp->s_port, pw->pw_name, name, rscsi, rsh); #endif return (rscsisock); } LOCAL char * rscsiversion(usalp, fd, what) SCSI *usalp; int fd; int what; { char cbuf[CMD_SIZE]; char *p; int ret; snprintf(cbuf, sizeof (cbuf), "V%d\n", what); ret = rscsicmd(usalp, fd, "version", cbuf); p = malloc(ret); if (p == NULL) return (p); rscsireadbuf(usalp, fd, p, ret); return (p); } LOCAL int rscsiopen(usalp, fd, fname) SCSI *usalp; int fd; char *fname; { char cbuf[CMD_SIZE]; int ret; int bus; int chan; int tgt; int lun; snprintf(cbuf, sizeof (cbuf), "O%s\n", fname?fname:""); ret = rscsicmd(usalp, fd, "open", cbuf); if (ret < 0) return (ret); bus = rscsireadnum(usalp, fd); chan = rscsireadnum(usalp, fd); tgt = rscsireadnum(usalp, fd); lun = rscsireadnum(usalp, fd); usal_settarget(usalp, bus, tgt, lun); return (ret); } LOCAL int rscsiclose(usalp, fd) SCSI *usalp; int fd; { return (rscsicmd(usalp, fd, "close", "C\n")); } LOCAL int rscsimaxdma(usalp, fd, amt) SCSI *usalp; int fd; long amt; { char cbuf[CMD_SIZE]; snprintf(cbuf, sizeof (cbuf), "D%ld\n", amt); return (rscsicmd(usalp, fd, "maxdma", cbuf)); } LOCAL int rscsigetbuf(usalp, fd, amt) SCSI *usalp; int fd; long amt; { char cbuf[CMD_SIZE]; int size; int ret; snprintf(cbuf, sizeof (cbuf), "M%ld\n", amt); ret = rscsicmd(usalp, fd, "getbuf", cbuf); if (ret < 0) return (ret); size = ret + 1024; /* Add protocol overhead */ #ifdef SO_SNDBUF if (size > usallocal(usalp)->wsize) while (size > 512 && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof (size)) < 0) { size -= 512; } if (size > usallocal(usalp)->wsize) { usallocal(usalp)->wsize = size; if (usalp->debug > 0) errmsgno(EX_BAD, "sndsize: %d\n", size); } #endif #ifdef SO_RCVBUF if (size > usallocal(usalp)->rsize) while (size > 512 && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof (size)) < 0) { size -= 512; } if (size > usallocal(usalp)->rsize) { usallocal(usalp)->rsize = size; if (usalp->debug > 0) errmsgno(EX_BAD, "rcvsize: %d\n", size); } #endif return (ret); } LOCAL int rscsifreebuf(usalp, fd) SCSI *usalp; int fd; { return (rscsicmd(usalp, fd, "freebuf", "F\n")); } LOCAL int rscsihavebus(usalp, fd, busno) SCSI *usalp; int fd; int busno; { char cbuf[2*CMD_SIZE]; snprintf(cbuf, sizeof (cbuf), "B%d\n%d\n", busno, 0); return (rscsicmd(usalp, fd, "havebus", cbuf)); } LOCAL int rscsifileno(usalp, fd, busno, tgt, tlun) SCSI *usalp; int fd; int busno; int tgt; int tlun; { char cbuf[3*CMD_SIZE]; snprintf(cbuf, sizeof (cbuf), "T%d\n%d\n%d\n%d\n", busno, 0, tgt, tlun); return (rscsicmd(usalp, fd, "fileno", cbuf)); } LOCAL int rscsiinitiator_id(usalp, fd) SCSI *usalp; int fd; { return (rscsicmd(usalp, fd, "initiator id", "I\n")); } LOCAL int rscsiisatapi(usalp, fd) SCSI *usalp; int fd; { return (rscsicmd(usalp, fd, "isatapi", "A\n")); } LOCAL int rscsireset(usalp, fd, what) SCSI *usalp; int fd; int what; { char cbuf[CMD_SIZE]; snprintf(cbuf, sizeof (cbuf), "R%d\n", what); return (rscsicmd(usalp, fd, "reset", cbuf)); } LOCAL int rscsiscmd(usalp, fd, sp) SCSI *usalp; int fd; struct usal_cmd *sp; { char cbuf[1600]; int ret; int amt = 0; int voidsize = 0; ret = snprintf(cbuf, sizeof (cbuf), "S%d\n%d\n%d\n%d\n%d\n", sp->size, sp->flags, sp->cdb_len, sp->sense_len, sp->timeout); movebytes(sp->cdb.cmd_cdb, &cbuf[ret], sp->cdb_len); ret += sp->cdb_len; if ((sp->flags & SCG_RECV_DATA) == 0 && sp->size > 0) { amt = sp->size; if ((ret + amt) <= sizeof (cbuf)) { movebytes(sp->addr, &cbuf[ret], amt); ret += amt; amt = 0; } } errno = 0; if (_nixwrite(fd, cbuf, ret) != ret) rscsiaborted(usalp, fd); if (amt > 0) { if (_nixwrite(fd, sp->addr, amt) != amt) rscsiaborted(usalp, fd); } ret = rscsigetstatus(usalp, fd, "sendcmd"); if (ret < 0) return (ret); sp->resid = sp->size - ret; sp->error = rscsireadnum(usalp, fd); sp->ux_errno = rscsireadnum(usalp, fd); *(Uchar *)&sp->scb = rscsireadnum(usalp, fd); sp->sense_count = rscsireadnum(usalp, fd); if (sp->sense_count > SCG_MAX_SENSE) { voidsize = sp->sense_count - SCG_MAX_SENSE; sp->sense_count = SCG_MAX_SENSE; } if (sp->sense_count > 0) { rscsireadbuf(usalp, fd, (char *)sp->u_sense.cmd_sense, sp->sense_count); rscsivoidarg(usalp, fd, voidsize); } if ((sp->flags & SCG_RECV_DATA) != 0 && ret > 0) rscsireadbuf(usalp, fd, sp->addr, ret); return (0); } LOCAL int rscsifillrbuf(usalp) SCSI *usalp; { usallocal(usalp)->readbptr = usallocal(usalp)->readbuf; return (usallocal(usalp)->readbcnt = _niread(usallocal(usalp)->remfd, usallocal(usalp)->readbuf, READBUF_SIZE)); } LOCAL int rscsirchar(usalp, cp) SCSI *usalp; char *cp; { if (--(usallocal(usalp)->readbcnt) < 0) { if (rscsifillrbuf(usalp) <= 0) return (usallocal(usalp)->readbcnt); --(usallocal(usalp)->readbcnt); } *cp = *(usallocal(usalp)->readbptr)++; return (1); } LOCAL int rscsireadbuf(usalp, fd, buf, count) SCSI *usalp; int fd; char *buf; int count; { register int n = count; register int amt = 0; register int cnt; if (usallocal(usalp)->readbcnt > 0) { cnt = usallocal(usalp)->readbcnt; if (cnt > n) cnt = n; movebytes(usallocal(usalp)->readbptr, buf, cnt); usallocal(usalp)->readbptr += cnt; usallocal(usalp)->readbcnt -= cnt; amt += cnt; } while (amt < n) { if ((cnt = _niread(fd, &buf[amt], n - amt)) <= 0) { return (rscsiaborted(usalp, fd)); } amt += cnt; } return (amt); } LOCAL void rscsivoidarg(usalp, fd, n) SCSI *usalp; int fd; register int n; { register int i; register int amt; char buf[512]; for (i = 0; i < n; i += amt) { amt = sizeof (buf); if ((n - i) < amt) amt = n - i; rscsireadbuf(usalp, fd, buf, amt); } } LOCAL int rscsicmd(usalp, fd, name, cbuf) SCSI *usalp; int fd; char *name; char *cbuf; { rscsisendcmd(usalp, fd, name, cbuf); return (rscsigetstatus(usalp, fd, name)); } LOCAL void rscsisendcmd(usalp, fd, name, cbuf) SCSI *usalp; int fd; char *name; char *cbuf; { int buflen = strlen(cbuf); errno = 0; if (_nixwrite(fd, cbuf, buflen) != buflen) rscsiaborted(usalp, fd); } LOCAL int rscsigetline(usalp, fd, line, count) SCSI *usalp; int fd; char *line; int count; { register char *cp; for (cp = line; cp < &line[count]; cp++) { if (rscsirchar(usalp, cp) != 1) return (rscsiaborted(usalp, fd)); if (*cp == '\n') { *cp = '\0'; return (cp - line); } } return (rscsiaborted(usalp, fd)); } LOCAL int rscsireadnum(usalp, fd) SCSI *usalp; int fd; { char cbuf[CMD_SIZE]; rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); return (atoi(cbuf)); } LOCAL int rscsigetstatus(usalp, fd, name) SCSI *usalp; int fd; char *name; { char cbuf[CMD_SIZE]; char code; int number; int count; int voidsize = 0; rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); code = cbuf[0]; number = atoi(&cbuf[1]); if (code == 'E' || code == 'F') { rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); if (code == 'F') /* should close file ??? */ rscsiaborted(usalp, fd); rscsigetline(usalp, fd, cbuf, sizeof (cbuf)); count = atoi(cbuf); if (count > 0) { if (usalp->errstr == NULL) { voidsize = count; count = 0; } else if (count > SCSI_ERRSTR_SIZE) { voidsize = count - SCSI_ERRSTR_SIZE; count = SCSI_ERRSTR_SIZE; } rscsireadbuf(usalp, fd, usalp->errstr, count); rscsivoidarg(usalp, fd, voidsize); } if (usalp->debug > 0) errmsgno(number, "Remote status(%s): %d '%s'.\n", name, number, cbuf); errno = number; return (-1); } if (code != 'A') { /* XXX Hier kommt evt Command not found ... */ if (usalp->debug > 0) errmsgno(EX_BAD, "Protocol error (got %s).\n", cbuf); return (rscsiaborted(usalp, fd)); } return (number); } LOCAL int rscsiaborted(usalp, fd) SCSI *usalp; int fd; { if ((usalp && usalp->debug > 0) || debug) errmsgno(EX_BAD, "Lost connection to remote host ??\n"); /* if fd >= 0 */ /* close file */ if (errno == 0) errno = EIO; return (-1); } /*--------------------------------------------------------------------------*/ #ifdef USE_RCMD_RSH /* * If we make a separate file for libschily, we would need these include files: * * socketpair(): sys/types.h + sys/socket.h * dup2(): unixstd.h (hat auch sys/types.h) * strrchr(): strdefs.h * * and make sure that we use sigset() instead of signal() if possible. */ #include LOCAL int _rcmdrsh(ahost, inport, locuser, remuser, cmd, rsh) char **ahost; int inport; /* port is ignored */ const char *locuser; const char *remuser; const char *cmd; const char *rsh; { struct passwd *pw; int pp[2]; int pid; if (rsh == 0) rsh = "rsh"; /* * Verify that 'locuser' is present on local host. */ if ((pw = getpwnam(locuser)) == NULL) { errmsgno(EX_BAD, "Unknown user: %s\n", locuser); return (-1); } /* XXX Check the existence for 'ahost' here? */ /* * rcmd(3) creates a single socket to be used for communication. * We need a bi-directional pipe to implement the same interface. * On newer OS that implement bi-directional we could use pipe(2) * but it makes no sense unless we find an OS that implements a * bi-directional pipe(2) but no socketpair(). */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pp) == -1) { errmsg("Cannot create socketpair.\n"); return (-1); } pid = fork(); if (pid < 0) { return (-1); } else if (pid == 0) { const char *p; const char *av0; int xpid; (void) close(pp[0]); if (dup2(pp[1], 0) == -1 || /* Pipe becomes 'stdin' */ dup2(0, 1) == -1) { /* Pipe becomes 'stdout' */ errmsg("dup2 failed.\n"); _exit(EX_BAD); /* NOTREACHED */ } (void) close(pp[1]); /* We don't need this anymore*/ /* * Become 'locuser' to tell the rsh program the local user id. */ if (getuid() != pw->pw_uid && setuid(pw->pw_uid) == -1) { errmsg("setuid(%lld) failed.\n", (Llong)pw->pw_uid); _exit(EX_BAD); /* NOTREACHED */ } if (getuid() != geteuid() && #ifdef HAVE_SETREUID setreuid(-1, pw->pw_uid) == -1) { #else #ifdef HAVE_SETEUID seteuid(pw->pw_uid) == -1) { #else setuid(pw->pw_uid) == -1) { #endif #endif errmsg("seteuid(%lld) failed.\n", (Llong)pw->pw_uid); _exit(EX_BAD); /* NOTREACHED */ } if (getuid() != geteuid() && seteuid(pw->pw_uid) == -1) { errmsg("seteuid(%lld) failed.\n", (Llong)pw->pw_uid); _exit(EX_BAD); /* NOTREACHED */ } /* * Fork again to completely detach from parent * and avoid the need to wait(2). */ if ((xpid = fork()) == -1) { errmsg("rcmdsh: fork to lose parent failed.\n"); _exit(EX_BAD); /* NOTREACHED */ } if (xpid > 0) { _exit(0); /* NOTREACHED */ } /* * Always use remote shell programm (even for localhost). * The client command may call getpeername() for security * reasons and this would fail on a simple pipe. */ /* * By default, 'rsh' handles terminal created signals * but this is not what we like. * For this reason, we tell 'rsh' to ignore these signals. * Ignoring these signals is important to allow 'star' / 'sdd' * to e.g. implement SIGQUIT as signal to trigger intermediate * status printing. * * For now (late 2002), we know that the following programs * are broken and do not implement signal handling correctly: * * rsh on SunOS-5.0...SunOS-5.9 * ssh from ssh.com * ssh from openssh.org * * Sun already did accept a bug report for 'rsh'. For the ssh * commands we need to send out bug reports. Meanwhile it could * help to call setsid() if we are running under X so the ssh * X pop up for passwd reading will work. */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); #ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); /* We would not be able to continue*/ #endif av0 = rsh; if ((p = strrchr(rsh, '/')) != NULL) av0 = ++p; execlp(rsh, av0, *ahost, "-l", remuser, cmd, (char *)NULL); errmsg("execlp '%s' failed.\n", rsh); _exit(EX_BAD); /* NOTREACHED */ } else { (void) close(pp[1]); /* * Wait for the intermediate child. * The real 'rsh' program is completely detached from us. */ wait(0); return (pp[0]); } return (-1); /* keep gcc happy */ } #ifdef HAVE_GETPPRIV #include LOCAL BOOL ppriv_ok() { priv_set_t *privset; BOOL net_privaddr = FALSE; if ((privset = priv_allocset()) == NULL) { return (FALSE); } if (getppriv(PRIV_EFFECTIVE, privset) == -1) { priv_freeset(privset); return (FALSE); } if (priv_ismember(privset, PRIV_NET_PRIVADDR)) { net_privaddr = TRUE; } priv_freeset(privset); return (net_privaddr); } #endif /* HAVE_GETPPRIV */ #endif /* USE_RCMD_RSH */ #endif /* USE_REMOTE */