static void checkpath(char *name) { /* restrict pathnames to current tree or uucppublic */ if (strstr(name, "../")) { canit(); fprintf(stderr, "\r\nlrz:\tSecurity Violation\r\n"); bibi(-1); } if (name[0] == '.' || strstr(name, "/.")) { canit(); fprintf(stderr, "\r\nlrz:\tSecurity Violation\r\n"); bibi(-1); } }
/* * Nonblocking I/O is a bit different in System V, Release 2 */ int rdchk(int fd) { int lf, savestat; savestat = fcntl(fd, F_GETFL) ; if (savestat == -1) return 0; #ifdef OVERLY_PARANOID if (-1==fcntl(fd, F_SETFL, savestat | O_NDELAY)) return 0; lf = read(fd, &checked, 1) ; if (-1==fcntl(fd, F_SETFL, savestat)) { #ifdef ENABLE_SYSLOG if (enable_syslog) lsyslog(LOG_CRIT,"F_SETFL failed in rdchk(): %s", strerror(errno)); #endif zpfatal("rdchk: F_SETFL failed\n"); /* lose */ /* there is really no way to recover. And we can't tell * the other side what's going on if we can't write to * fd, but we try. */ canit(fd); exit(1); } #else fcntl(fd, F_SETFL, savestat | O_NDELAY); lf = read(fd, &checked, 1) ; fcntl(fd, F_SETFL, savestat); #endif return(lf == -1 && errno==EWOULDBLOCK ? 0 : lf) ; }
/* called by signal interrupt or terminate to clean things up */ void bibi(int n) { canit(0); oflush(); io_mode(io_mode_fd, 0); if (n == SIGQUIT) abort(); exit(128 + n); }
/* called by signal interrupt or terminate to clean things up */ static void bibi(int signum) { if (Zmodem) zmputs(Attn); canit(); mode(0); closeit(); fprintf(stderr, "lrz: caught signal %d; exiting", signum); exit(128 + signum); }
/* called by signal interrupt or terminate to clean things up */ void bibi(n) { if (Zmodem) zmputs(Attn); canit(); mode(0); fprintf(stderr, "rz: caught signal %d; exiting", n); cucheck(); exit(128+n); }
static int wcreceive(int argc, char **argp) { int c; if (Batch || argc == 0) { Crcflg = 1; if (!Quiet) fprintf(stderr, rbmsg, Progname, "sz"); if ((c = tryz())) { if (c == ZCOMPL) return OK; if (c == ERROR) goto fubar; c = rzfiles(); if (c) goto fubar; } else { for (;;) { if (wcrxpn(secbuf) == ERROR) goto fubar; if (secbuf[0] == 0) return OK; if (procheader(secbuf) == ERROR) goto fubar; if (wcrx() == ERROR) goto fubar; } } } else { Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; procheader(""); strcpy(Pathname, *argp); checkpath(Pathname); fprintf(stderr, "\n%s: ready to receive %s\r\n", Progname, Pathname); if ((fout = fopen(Pathname, "w")) == NULL) return ERROR; if (wcrx() == ERROR) goto fubar; timing(1); } return OK; fubar: canit(); if (Topipe && fout) { pclose(fout); return ERROR; } if (fout) closeit(); return ERROR; }
static int wcgetsec(char *rxbuf, int maxtime) { int checksum, wcj, firstch; unsigned short oldcrc; char *p; int sectcurr; for (Lastrx = errors = 0; errors < RETRYMAX; errors++) { if ((firstch = readline(maxtime)) == STX) { Blklen = 1024; goto get2; } if (firstch == SOH) { Blklen = 128; get2: sectcurr = readline(1); if ((sectcurr + (oldcrc = readline(1))) == 0377) { oldcrc = checksum = 0; for (p = rxbuf, wcj = Blklen; --wcj >= 0;) { if ((firstch = readline(1)) < 0) goto bilge; oldcrc = updcrc(firstch, oldcrc); checksum += (*p++ = firstch); } if ((firstch = readline(1)) < 0) goto bilge; if (Crcflg) { oldcrc = updcrc(firstch, oldcrc); if ((firstch = readline(1)) < 0) goto bilge; oldcrc = updcrc(firstch, oldcrc); if (oldcrc & 0xFFFF) zperr("CRC"); else { Firstsec = FALSE; return sectcurr; } } else if (((checksum - firstch) & 0377) == 0) { Firstsec = FALSE; return sectcurr; } else zperr("Checksum"); } else zperr("Sector number garbled"); } /* make sure eot really is eot and not just mixmash */ else if (firstch == EOT && readline(1) == TIMEOUT) return WCEOT; else if (firstch == CAN) { if (Lastrx == CAN) { zperr("Sender CANcelled"); return ERROR; } else { Lastrx = CAN; continue; } } else if (firstch == TIMEOUT) { if (Firstsec) goto humbug; bilge: zperr("TIMEOUT"); } else zperr("Got 0%o sector header", firstch); humbug: Lastrx = 0; while (readline(1) != TIMEOUT); if (Firstsec) { xsendline(Crcflg ? WANTCRC : NAK); Lleft = 0; /* Do read next time ... */ } else { maxtime = 40; xsendline(NAK); Lleft = 0; /* Do read next time ... */ } } /* try to stop the bubble machine. */ canit(); return ERROR; }
int main(int argc, char *argv[]) { char *cp; int npats; char *virgin, **patts = NULL; int exitcode = 0; *pathsname = 0; *tempsname = 0; nodeinf = -1; dszlog = -1; Rxtimeout = 100; setbuf(stderr, NULL); chkinvok(virgin = argv[0]); /* if called as [-]rzCOMMAND set flag */ npats = 0; while (--argc) { cp = *++argv; if (*cp == '-') { while (*++cp) { switch (*cp) { case '\\': cp[1] = toupper(cp[1]); continue; case '+': Lzmanag = ZMAPND; break; case 'a': Rxascii = TRUE; break; case 'b': Rxbinary = TRUE; break; case 'c': Crcflg = TRUE; break; case 'g': if (--argc < 1) { usage(); } iofd = open(*++argv, O_RDWR); break; case 'D': Nflag = TRUE; break; case 'e': Zctlesc = 1; break; case 'h': usage(); break; case 'O': no_timeout = TRUE; break; case 'p': Lzmanag = ZMPROT; break; case 'q': Quiet = TRUE; Verbose = 0; break; case 'r': try_resume = TRUE; break; case 't': if (--argc < 1) { usage(); } Rxtimeout = atoi(*++argv); if (Rxtimeout < 10 || Rxtimeout > 1000) usage(); break; case 'f': if (--argc < 1) { usage(); } strcpy(pathsname, *++argv); break; case 'F': if (--argc < 1) { usage(); } strcpy(tempsname, *++argv); break; case 'n': if (--argc < 1) { usage(); } nodeinf = open(*++argv, O_RDWR); read(nodeinf, &nin, sizeof(struct DayDream_NodeInfo)); nin.ddn_flags |= (1L << 1); break; case 'l': if (--argc < 1) { usage(); } dszlog = open(*++argv, O_WRONLY | O_CREAT, 0755); break; case 'w': if (--argc < 1) { usage(); } Zrwindow = atoi(*++argv); break; case 'u': MakeLCPathname = FALSE; break; case 'v': ++Verbose; break; case 'y': Rxclob = TRUE; break; default: usage(); } } } else if (!npats && argc > 0) { if (argv[0][0]) { npats = argc; patts = argv; } } } if (npats > 1) usage(); if (Batch && npats) usage(); if (Verbose) setbuf(stderr, NULL); if (!Quiet) { if (Verbose == 0) Verbose = 2; } vfile("%s %s\n", Progname, VERSION); mode(1); signal(SIGTERM, bibi); if (wcreceive(npats, patts) == ERROR) { exitcode = 0200; canit(); } mode(0); if (exitcode && !Zmodem) /* bellow again with all thy might. */ canit(); exit(exitcode); return 0; /* compilers would complain */ }
static int wcs(const char *oname, const char *remotename) { #if !defined(S_ISDIR) int c; #endif struct stat f; char *name; struct zm_fileinfo zi; #ifdef HAVE_MMAP int dont_mmap_this = 0; #endif if (Restricted) { /* restrict pathnames to current tree or uucppublic */ if (strstr(oname, "../") #ifdef PUBDIR || (oname[0] == '/' && strncmp(oname, MK_STRING(PUBDIR), strlen(MK_STRING(PUBDIR)))) #endif ) { canit(0); zmodem_error(1, 0, "security violation: not allowed to upload from %s", oname); } } if (0 == strcmp(oname, "-")) { char *p = getenv("ONAME"); name = (char *)malloc(PATH_MAX + 1); if (p) { strcpy(name, p); } else { sprintf(name, "s%lu.lsz", (unsigned long) getpid()); } input_f = stdin; #ifdef HAVE_MMAP dont_mmap_this = 1; #endif } else if ((input_f = fopen(oname, "r")) == NULL) { ++errcnt; return OK; /* pass over it, there may be others */ } else { name = (char *)malloc(PATH_MAX + 1); strcpy(name, oname); } #ifdef HAVE_MMAP if (!use_mmap || dont_mmap_this) #endif { static char *s = NULL; static size_t last_length = 0; struct stat st; if (fstat(fileno(input_f), &st) == -1) st.st_size = 1024 * 1024; if (buffersize == (size_t) - 1 && s) { if ((size_t) st.st_size > last_length) { free(s); s = NULL; last_length = 0; } } if (!s && buffersize) { last_length = 16384; if (buffersize == (size_t) - 1) { if (st.st_size > 0) last_length = st.st_size; } else last_length = buffersize; /* buffer whole pages */ last_length = (last_length + 4095) & 0xfffff000; s = malloc(last_length); if (!s) { exit(1); } } if (s) { #ifdef SETVBUF_REVERSED setvbuf(input_f, _IOFBF, s, last_length); #else setvbuf(input_f, s, _IOFBF, last_length); #endif } } vpos = 0; /* Check for directory or block special files */ fstat(fileno(input_f), &f); #if defined(S_ISDIR) if (S_ISDIR(f.st_mode) || S_ISBLK(f.st_mode)) { #else c = f.st_mode & S_IFMT; if (c == S_IFDIR || c == S_IFBLK) { #endif fclose(input_f); free(name); return OK; } if (remotename) { /* disqualify const */ union { const char *c; char *s; } cheat; cheat.c = remotename; zi.fname = cheat.s; } else zi.fname = name; zi.modtime = f.st_mtime; zi.mode = f.st_mode; #if defined(S_ISFIFO) zi.bytes_total = (S_ISFIFO(f.st_mode)) ? DEFBYTL : f.st_size; #else zi.bytes_total = c == S_IFIFO ? DEFBYTL : f.st_size; #endif zi.bytes_sent = 0; zi.bytes_received = 0; zi.bytes_skipped = 0; zi.eof_seen = 0; ++Filcnt; free(name); switch (wctxpn(&zi)) { case ERROR: return ERROR; case ZSKIP: return OK; } if (!zmodem_requested && wctx(&zi) == ERROR) { return ERROR; } if (Unlinkafter) unlink(oname); return 0; } /* * generate and transmit pathname block consisting of * pathname (null terminated), * file length, mode time and file mode in octal * as provided by the Unix fstat call. * N.B.: modifies the passed name, may extend it! */ static int wctxpn(struct zm_fileinfo *zi) { register char *p, *q; char *name2; struct stat f; name2 = (char *)malloc(PATH_MAX + 1); if (protocol == ZM_XMODEM) { free(name2); return OK; } if (!zmodem_requested) if (getnak()) { free(name2); return ERROR; } q = (char *) 0; #if 0 if (Dottoslash) { /* change . to . */ for (p = zi->fname; *p; ++p) { if (*p == '/') q = p; else if (*p == '.') *(q = p) = '/'; } if (q && strlen(++q) > 8) { /* If name>8 chars */ q += 8; /* make it .ext */ strcpy(name2, q); /* save excess of name */ *q = '.'; strcpy(++q, name2); /* add it back */ } } #endif for (p = zi->fname, q = txbuf; *p;) if ((*q++ = *p++) == '/' && !Fullname) q = txbuf; *q++ = 0; p = q; while (q < (txbuf + MAX_BLOCK)) *q++ = 0; /* note that we may lose some information here in case mode_t is wider than an * int. But i believe sending %lo instead of %o _could_ break compatability */ if (!Ascii && (input_f != stdin) && *zi->fname && fstat(fileno(input_f), &f) != -1) sprintf(p, "%lu %lo %o 0 %d %ld", (long) f.st_size, f.st_mtime, (unsigned int) ((no_unixmode) ? 0 : f.st_mode), Filesleft, Totalleft); Totalleft -= f.st_size; if (--Filesleft <= 0) Totalleft = 0; if (Totalleft < 0) Totalleft = 0; /* force 1k blocks if name won't fit in 128 byte block */ if (txbuf[125]) blklen = 1024; else { /* A little goodie for IMP/KMD */ txbuf[127] = (f.st_size + 127) >> 7; txbuf[126] = (f.st_size + 127) >> 15; } if (zmodem_requested) free(name2); return zsendfile(zi, txbuf, 1 + strlen(p) + (p - txbuf)); /* if (wcputsec(txbuf, 0, 128) == ERROR) { free(name2); return ERROR; } free(name2); return OK; */ } static int getnak(void) { int firstch; int tries = 0; Lastrx = 0; for (;;) { tries++; switch (firstch = READLINE_PF(100)) { case ZPAD: if (getzrxinit()) return ERROR; Ascii = 0; /* Receiver does the conversion */ return FALSE; case TIMEOUT: /* 30 seconds are enough */ if (tries == 3) { return TRUE; } /* don't send a second ZRQINIT _directly_ after the * first one. Never send more then 4 ZRQINIT, because * omen rz stops if it saw 5 of them */ if ((zrqinits_sent > 1 || tries > 1) && zrqinits_sent < 4) { /* if we already sent a ZRQINIT we are using zmodem * protocol and may send further ZRQINITs */ stohdr(0L); zshhdr(ZRQINIT, Txhdr); zrqinits_sent++; } continue; case WANTG: io_mode(io_mode_fd, 2); /* Set cbreak, XON/XOFF, etc. */ Optiong = TRUE; blklen = 1024; case WANTCRC: Crcflg = TRUE; case NAK: return FALSE; case CAN: if ((firstch = READLINE_PF(20)) == CAN && Lastrx == CAN) return TRUE; default: break; } Lastrx = firstch; } }