2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)rscsi.c 1.29 05/05/16 Copyright 1994,2000-2002 J. Schilling*/
17 * Copyright (c) 1994,2000-2002 J. Schilling
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License version 2
22 * as published by the Free Software Foundation.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License along with
30 * this program; see the file COPYING. If not, write to the Free Software
31 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 /*#define FORCE_DEBUG*/
40 #include <unixstd.h> /* includes <sys/types.h> */
45 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h> /* BSD-4.2 & Linux need this for MAXHOSTNAMELEN */
60 #include <usal/usalcmd.h>
61 #include <usal/scsitransp.h>
63 #include <netinet/in.h>
64 #ifdef HAVE_ARPA_INET_H
65 #include <arpa/inet.h> /* BeOS does not have <arpa/inet.h> */
66 #endif /* but inet_ntaoa() is in <netdb.h> */
72 static void checkuser(void);
73 static char *getpeer(void);
74 static BOOL checktarget(void);
75 static void dorscsi(void);
76 static void scsiversion(void);
77 static void openscsi(void);
78 static void closescsi(void);
79 static void maxdma(void);
80 static void getbuf(void);
81 static void freebuf(void);
82 static void havebus(void);
83 static void scsifileno(void);
84 static void initiator_id(void);
85 static void isatapi(void);
86 static void scsireset(void);
87 static void sendcmd(void);
89 static int fillrdbuf(void);
90 static int readchar(char *cp);
92 static void readbuf(char *buf, int n);
93 static void voidarg(int n);
94 static void readarg(char *buf, int n);
95 static char *preparebuffer(int size);
96 static int checkscsi(char *decive);
97 static void rscsirespond(int ret, int err);
98 static void rscsireply(int ret);
99 static void rscsierror(int err, char *str, char *xstr);
103 static SCSI *scsi_ptr = NULL;
105 static long Sbufsize;
107 static char *username;
108 static char *peername;
110 static char *debug_name;
111 static FILE *debug_file;
113 #define DEBUG(fmt) if (debug_file) fprintf(debug_file, fmt)
114 #define DEBUG1(fmt,a) if (debug_file) fprintf(debug_file, fmt, a)
115 #define DEBUG2(fmt,a1,a2) if (debug_file) fprintf(debug_file, fmt, a1, a2)
116 #define DEBUG3(fmt,a1,a2,a3) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3)
117 #define DEBUG4(fmt,a1,a2,a3,a4) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4)
118 #define DEBUG5(fmt,a1,a2,a3,a4,a5) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4, a5)
119 #define DEBUG6(fmt,a1,a2,a3,a4,a5,a6) if (debug_file) fprintf(debug_file, fmt, a1, a2, a3, a4, a5, a6)
120 #endif /* USE_REMOTE */
123 main(int argc, char *argv[])
125 save_args(argc, argv);
127 comerrno(EX_BAD, "No remote SCSI support on this platform.\n");
130 if (argc > 0 && strcmp(*argv, "-c") == 0) {
132 * Skip params in case we have been installed as shell.
138 * WARNING you are only allowed to change the defaults configuration
139 * filename if you also change the documentation and add a statement
140 * that makes clear where the official location of the file is, why you
141 * did choose a nonstandard location and that the nonstandard location
142 * only refers to inofficial rscsi versions.
144 * I was forced to add this because some people change cdrecord without
145 * rational reason and then publish the result. As those people
146 * don't contribute work and don't give support, they are causing extra
147 * work for me and this way slow down the development.
149 if (cfg_open("/etc/netscsid.conf") < 0) {
150 rscsierror(geterrno(), errmsgstr(geterrno()),
151 "Remote configuration error: Cannot open /etc/netscsid.conf");
152 /* rscsirespond(-1, geterrno());*/
155 debug_name=cfg_get("DEBUG");
157 if (debug_name == NULL && argc <= 0)
158 debug_name = "/tmp/RSCSI";
162 * Should we allow root to shoot himself into the foot?
163 * Allowing to write arbitrary files may be a security risk.
165 if (argc > 0 && getuid() == 0)
170 * XXX If someone sets up debugging and allows the debug file to be
171 * XXX replaced by a symlink to e.g. /etc/passwd this would be a
172 * XXX security risk. But /etc/rscsi.conf is only writable by root
173 * XXX and for this reason a possible security risk would have been
174 * XXX introduced by the administrator.
176 if (debug_name != NULL) {
177 /* Try to be careful when opening debug files, might be
178 * created in an unsafe location
180 int fd = open(debug_name, O_CREAT | O_EXCL | O_TRUNC | O_RDWR, 0600);
182 debug_file = fdopen(fd, "w");
184 rscsirespond(-1, geterrno());
190 if (debug_file == 0) {
191 rscsirespond(-1, geterrno());
194 (void) setbuf(debug_file, (char *)0);
196 checkuser(); /* Check if we are called by a bad guy */
197 peername = getpeer(); /* Get host name of caller */
199 #endif /* USE_REMOTE */
207 uid_t uid = getuid();
213 DEBUG("rscsid: user id 0, name root\n");
220 username = pw->pw_name;
221 DEBUG2("rscsid: user id %ld, name %s\n", (long)uid, username);
224 while ((uname = cfg_get_next("USER")) != NULL) {
225 if (0==strcmp(username, uname))
229 DEBUG2("rscsid: Illegal user '%s' id %ld for RSCSI server\n",
230 username, (long)uid);
231 rscsierror(0, "Illegal user id for RSCSI server", NULL);
236 #ifdef MAXHOSTNAMELEN /* XXX remove this and sys/param.h */
237 #define NI_MAXHOST MAXHOSTNAMELEN
239 #define NI_MAXHOST 64
246 #ifdef HAVE_GETNAMEINFO
247 #ifdef HAVE_SOCKADDR_STORAGE
248 struct sockaddr_storage sa;
256 struct sockaddr *sap;
257 struct sockaddr_in *s;
258 socklen_t sasize = sizeof (sa);
259 static char buffer[NI_MAXHOST];
261 sap = (struct sockaddr *)&sa;
262 if (getpeername(STDIN_FILENO, sap, &sasize) < 0) {
263 int errsav = geterrno();
266 if (fstat(STDIN_FILENO, &sb) >= 0) {
267 if (S_ISFIFO(sb.st_mode)) {
268 DEBUG("rmt: stdin is a PIPE\n");
271 DEBUG1("rscsid: stdin st_mode %0llo\n", (Llong)sb.st_mode);
274 DEBUG1("rscsid: peername %s\n", errmsgstr(errsav));
275 return ("ILLEGAL_SOCKET");
277 s = (struct sockaddr_in *)&sa;
279 if (s->sin_family != AF_INET && s->sin_family != AF_INET6) {
281 if (s->sin_family != AF_INET) {
285 * AF_UNIX is not defined on BeOS
287 if (s->sin_family == AF_UNIX) {
288 DEBUG("rmt: stdin is a PIPE (UNIX domain socket)\n");
292 DEBUG1("rmt: stdin NOT_IP socket (sin_family: %d)\n",
297 #ifdef HAVE_GETNAMEINFO
300 getnameinfo(sap, sasize, buffer, sizeof (buffer), NULL, 0,
301 NI_NUMERICHOST) == 0) {
302 DEBUG1("rmt: peername %s\n", buffer);
305 if (getnameinfo(sap, sasize, buffer, sizeof (buffer), NULL, 0,
307 DEBUG1("rmt: peername %s\n", buffer);
310 return ("CANNOT_MAP_ADDRESS");
311 #else /* HAVE_GETNAMEINFO */
312 #ifdef HAVE_INET_NTOA
313 (void) snprintf(buffer, sizeof(buffer), "%s", inet_ntoa(s->sin_addr));
315 (void) snprintf(buffer, sizeof(buffer), "%x", s->sin_addr.s_addr);
317 DEBUG1("rscsid: peername %s\n", buffer);
318 he = gethostbyaddr((char *)&s->sin_addr.s_addr, 4, AF_INET);
319 DEBUG1("rscsid: peername %s\n", he!=NULL?he->h_name:buffer);
323 #endif /* HAVE_GETNAMEINFO */
339 if (peername == NULL)
342 while ((target = cfg_get_next("ACCESS")) != NULL) {
347 if ((p = strchr(p, '\t')) != NULL)
351 if (0!=strcmp(username, user))
357 if ((p = strchr(p, '\t')) != NULL)
361 if (0!=strcmp(peername, host))
375 if (*p != '\t' && *p != '\n' && *p != '\r' && *p != '\0')
377 DEBUG6("ACCESS %s %s %d.%d,%d,%d\n", user, host, bus, chan, tgt, lun);
379 if (bus != -1 && bus != usal_scsibus(scsi_ptr))
381 if (tgt != -1 && tgt != usal_target(scsi_ptr))
383 if (lun != -1 && lun != usal_lun(scsi_ptr))
395 while (readchar(&c) == 1) {
400 case 'V': /* "V" ersion */
403 case 'O': /* "O" pen */
406 case 'C': /* "C" lose */
409 case 'D': /* "D" MA */
412 case 'M': /* "M" alloc */
415 case 'F': /* "F" free */
418 case 'B': /* "B" us */
421 case 'T': /* "T" arget */
424 case 'I': /* "I" nitiator */
427 case 'A': /* "A" tapi */
430 case 'R': /* "R" eset */
433 case 'S': /* "S" end */
438 DEBUG1("rscsid: garbage command '%c'\n", c);
439 rscsierror(0, "Garbage command", NULL);
453 readarg(what, sizeof(what));
454 DEBUG1("rscsid: V %s\n", what);
455 if (scsi_ptr == NULL) {
456 rscsirespond(-1, EBADF);
459 str = usal_version(scsi_ptr, atoi(what));
461 ret++; /* Include null char */
462 rscsirespond(ret, geterrno());
463 _nixwrite(STDOUT_FILENO, str, ret);
469 char device[CMD_SIZE];
476 if (scsi_ptr != NULL)
477 (void) usal_close(scsi_ptr);
479 readarg(device, sizeof(device));
480 DEBUG1("rscsid: O %s\n", device);
481 if (strncmp(device, "REMOTE", 6) == 0) {
484 } else if (!checkscsi(device)) {
488 scsi_ptr = usal_open(device, errstr, sizeof(errstr), debug, lverbose);
489 if (scsi_ptr == NULL) {
492 scsi_ptr->silent = 1;
493 scsi_ptr->verbose = 0;
495 scsi_ptr->kdebug = 0;
500 * XXX This is currently the only place where we use the
501 * XXX extended error string.
503 rscsierror(geterrno(), errmsgstr(geterrno()), errstr);
504 /* rscsirespond(ret, geterrno());*/
507 DEBUG4("rscsid:>A 0 %d.%d,%d,%d\n",
508 usal_scsibus(scsi_ptr),
510 usal_target(scsi_ptr),
513 ret = snprintf(rbuf, sizeof(rbuf), "A0\n%d\n%d\n%d\n%d\n",
514 usal_scsibus(scsi_ptr),
516 usal_target(scsi_ptr),
518 (void) _nixwrite(STDOUT_FILENO, rbuf, ret);
525 char device[CMD_SIZE];
527 readarg(device, sizeof(device));
528 DEBUG1("rscsid: C %s\n", device);
529 ret = usal_close(scsi_ptr);
530 rscsirespond(ret, geterrno());
540 readarg(amt, sizeof(amt));
541 DEBUG1("rscsid: D %s\n", amt);
542 if (scsi_ptr == NULL) {
543 rscsirespond(-1, EBADF);
546 ret = usal_bufsize(scsi_ptr, atol(amt));
547 rscsirespond(ret, geterrno());
556 readarg(amt, sizeof(amt));
557 DEBUG1("rscsid: M %s\n", amt);
558 if (scsi_ptr == NULL) {
559 rscsirespond(-1, EBADF);
562 ret = usal_bufsize(scsi_ptr, atol(amt));
563 if (preparebuffer(ret) == NULL)
565 rscsirespond(ret, geterrno());
572 char dummy[CMD_SIZE];
574 readarg(dummy, sizeof(dummy));
575 DEBUG1("rscsid: F %s\n", dummy);
576 if (scsi_ptr == NULL) {
577 rscsirespond(-1, EBADF);
580 usal_freebuf(scsi_ptr);
582 rscsirespond(ret, geterrno());
592 readarg(bus, sizeof(bus));
593 readarg(chan, sizeof(chan));
594 DEBUG2("rscsid: B %s.%s\n", bus, chan);
595 if (scsi_ptr == NULL) {
596 rscsirespond(-1, EBADF);
599 ret = usal_havebus(scsi_ptr, atol(bus));
600 rscsirespond(ret, geterrno());
612 readarg(bus, sizeof(bus));
613 readarg(chan, sizeof(chan));
614 readarg(tgt, sizeof(tgt));
615 readarg(lun, sizeof(lun));
616 DEBUG4("rscsid: T %s.%s,%s,%s\n", bus, chan, tgt, lun);
617 if (scsi_ptr == NULL) {
618 rscsirespond(-1, EBADF);
622 ret = usal_settarget(scsi_ptr, atoi(bus), atoi(tgt), atoi(lun));
623 if (!checktarget()) {
624 usal_settarget(scsi_ptr, -1, -1, -1);
628 rscsirespond(ret, geterrno());
637 char dummy[CMD_SIZE];
639 readarg(dummy, sizeof(dummy));
640 DEBUG1("rscsid: I %s\n", dummy);
641 if (scsi_ptr == NULL) {
642 rscsirespond(-1, EBADF);
646 ret = usal_initiator_id(scsi_ptr);
648 rscsirespond(ret, geterrno());
657 char dummy[CMD_SIZE];
659 readarg(dummy, sizeof(dummy));
660 DEBUG1("rscsid: A %s\n", dummy);
661 if (scsi_ptr == NULL) {
662 rscsirespond(-1, EBADF);
666 ret = usal_isatapi(scsi_ptr);
668 rscsirespond(ret, geterrno());
679 readarg(what, sizeof(what));
680 DEBUG1("rscsid: R %s\n", what);
681 if (scsi_ptr == NULL) {
682 rscsirespond(-1, EBADF);
685 ret = usal_reset(scsi_ptr, atoi(what));
686 rscsirespond(ret, geterrno());
692 register struct usal_cmd *scmd;
695 char count[CMD_SIZE];
696 char flags[CMD_SIZE];
697 char cdb_len[CMD_SIZE];
698 char sense_len[CMD_SIZE];
699 char timeout[CMD_SIZE];
713 * <data if available>
717 * - sss.uuu (e.g. 10.23)
719 readarg(count, sizeof(count));
720 readarg(flags, sizeof(flags));
721 readarg(cdb_len, sizeof(cdb_len));
722 readarg(sense_len, sizeof(sense_len));
723 readarg(timeout, sizeof(timeout));
724 DEBUG5("rscsid: S %s %s %s %s %s", count, flags, cdb_len, sense_len, timeout);
726 cflags = atoi(flags);
727 clen = atoi(cdb_len);
729 p = strchr(timeout, '.');
732 ctimeout = atoi(timeout);
734 if (scsi_ptr == NULL || clen > SCG_MAX_CMD || csize > Sbufsize) {
737 if ((cflags & SCG_RECV_DATA) == 0 && csize > 0)
739 rscsirespond(-1, scsi_ptr==NULL ? EBADF : EINVAL);
743 scmd = scsi_ptr->scmd;
744 fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
745 scmd->addr = (caddr_t)Sbuf;
747 scmd->flags = cflags;
748 scmd->cdb_len = clen;
749 scmd->sense_len = atoi(sense_len);
750 scmd->timeout = ctimeout;
751 readbuf((char *)scmd->cdb.cmd_cdb, clen);
752 DEBUG6(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
753 scmd->cdb.cmd_cdb[0],
754 scmd->cdb.cmd_cdb[1],
755 scmd->cdb.cmd_cdb[2],
756 scmd->cdb.cmd_cdb[3],
757 scmd->cdb.cmd_cdb[4],
758 scmd->cdb.cmd_cdb[5]);
760 if ((cflags & SCG_RECV_DATA) == 0 && csize > 0)
761 readbuf(Sbuf, scmd->size);
763 scsi_ptr->cmdname = "";
765 ret = usal_cmd(scsi_ptr);
768 if ((csize - scmd->resid) > 0)
769 n = csize - scmd->resid;
777 * <data if available>
779 DEBUG5("rscsid:>A %d %d %d %d %d\n",
783 *(Uchar *)&scmd->scb,
786 ret = snprintf(rbuf, sizeof(rbuf), "A%d\n%d\n%d\n%d\n%d\n",
790 *(Uchar *)&scmd->scb,
793 if (scmd->sense_count > 0) {
794 movebytes(scmd->u_sense.cmd_sense, &rbuf[ret], scmd->sense_count);
795 ret += scmd->sense_count;
797 if ((cflags & SCG_RECV_DATA) == 0)
799 if (n > 0 && ((ret + n) <= sizeof(rbuf))) {
800 movebytes(Sbuf, &rbuf[ret], n);
804 (void) _nixwrite(STDOUT_FILENO, rbuf, ret);
807 (void) _nixwrite(STDOUT_FILENO, Sbuf, n);
810 #define READB_SIZE 128
811 static char readb[READB_SIZE];
812 static char *readbptr;
820 return (readbcnt = _niread(STDIN_FILENO, readb, READB_SIZE));
826 if (--readbcnt < 0) {
827 if (fillrdbuf() <= 0)
836 readbuf(register char *buf, register int n)
845 movebytes(readbptr, buf, amt);
851 for (; i < n; i += amt) {
852 amt = _niread(STDIN_FILENO, &buf[i], n - i);
854 DEBUG("rscsid: premature eof\n");
855 rscsierror(0, "Premature eof", NULL);
862 voidarg(register int n)
868 for (i = 0; i < n; i += amt) {
877 readarg(char *buf, int n)
881 for (i = 0; i < n; i++) {
882 if (readchar(&buf[i]) != 1)
891 preparebuffer(int size)
894 if ((Sbuf = usal_getbuf(scsi_ptr, Sbufsize)) == NULL) {
898 size = Sbufsize + 1024; /* Add protocol overhead */
902 setsockopt(STDOUT_FILENO, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof (size)) < 0)
904 DEBUG1("rscsid: sndsize: %d\n", size);
908 setsockopt(STDIN_FILENO, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof (size)) < 0)
910 DEBUG1("rscsid: rcvsize: %d\n", size);
916 checkscsi(char *device)
919 if (strncmp(device, "/dev/rst", 8) == 0 ||
920 strncmp(device, "/dev/nrst", 9) == 0 ||
921 strcmp(device, "/dev/zero") == 0 ||
922 strcmp(device, "/dev/null") == 0)
931 rscsirespond(int ret, int err)
934 rscsierror(err, errmsgstr(err), NULL);
945 DEBUG1("rscsid:>A %d\n", ret);
946 (void) snprintf(rbuf, sizeof(rbuf), "A%d\n", ret);
947 (void) _nixwrite(STDOUT_FILENO, rbuf, strlen(rbuf));
951 rscsierror(int err, char *str, char *xstr)
958 xlen = strlen(xstr) + 1;
960 DEBUG3("rscsid:>E %d (%s) [%s]\n", err, str, xstr?xstr:"");
961 n = snprintf(rbuf, sizeof(rbuf), "E%d\n%s\n%d\n", err, str, xlen);
963 if (xlen > 0 && ((xlen + n) <= sizeof(rbuf))) {
964 movebytes(xstr, &rbuf[n], xlen);
968 (void) _nixwrite(STDOUT_FILENO, rbuf, n);
970 (void) _nixwrite(STDOUT_FILENO, xstr, xlen);
972 #endif /* USE_REMOTE */