Importing usr.bin/ftp

This commit is contained in:
Thomas Cort 2013-04-05 19:02:06 +00:00
parent 2db46bcfa1
commit 04203a83a6
37 changed files with 15092 additions and 2982 deletions

View file

@ -10,7 +10,7 @@ SUBDIR= add_route arp ash at backup basename btrace \
dhrystone diff dirname diskctl dumpcore \
eject env expand factor fbdctl \
find finger fingerd fix fold format fortune fsck.mfs \
ftp101 gcore gcov-pull getty grep hexdump host \
gcore gcov-pull getty grep hexdump host \
hostaddr id ifconfig ifdef \
intr ipcrm ipcs irdpd isoread last \
less loadkeys loadramdisk logger look lp \

View file

@ -1,11 +0,0 @@
# Makefile for ftp
#
# 01/25/96 Initial Release Michael Temari
# 03/08/00 Michael Temari, <Michael@TemWare.Com>
# 02/07/05 v. 1.01 Michael Temari, <Michael@TemWare.Com>
PROG= ftp
SRCS= ftp.c local.c file.c xfer.c other.c net.c crc.c
CPPFLAGS+= -DCRC_ONLY
.include <bsd.prog.mk>

View file

@ -1,39 +0,0 @@
ftp101 --- An FTP client program for Minix 2.0
written by Michael Temari <Michael@TemWare.Com> release 1.01a 2006-06-07
Full download: <a href="/pub/contrib/ftp101.tar.Z">ftp101.tar.Z</a>
FTP is the File Transfer Protocol client that allows you to connect to
a remote FTP server.
This version should work equally well with Minix 2 and Minix 3.
Release 1.01a 2006-06-07: minor documentation edits
Release 1.01 2005-02-07: minor bug fix
Release 1.00 2003-12-14: added "ver" command to display current version
and an ftp(1) man page.
Installation: unpack the tarball, it will create an ftp101 directory. Although
this is a replacement for the ftp client provided in the Minix 2.0.0 and later
distributions, it is suggested you unpack and compile in the /usr/local/src
directory.
zcat < ftp101.tar.Z | tar xvfp -
Invoking make -n will show you what the Makefile will do.
make (or make ftp) compiles a new ftp binary, leaving it in the source
directory.
make install compiles the binary and installs it in /usr/bin.
make installman installs the man page in /usr/local/man/man1. The
directory must exist.
Note: there is a bug in the version of the ftp client distributed with
Minix 2.0.2 and 2.0.3 that causes a \r (0xd) character to be appended
to file names in the destination directory when files are downloaded in
binary mode using the mget command. The bug was corrected in a release
prior to 1.00.
Notes by ASW revised 2006-06-07

View file

@ -1,132 +0,0 @@
/* Compute checksum Author: Johan W. Stevenson */
/* Copyright 1988 by Johan W. Stevenson */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if !CRC_ONLY
int errs;
#if __STDC__
int main(int argc, char **argv);
void crc(char *fname);
#else
void crc();
#endif
int main(argc, argv)
int argc;
char **argv;
{
char line[256];
if (argc <= 1)
crc((char *) 0);
else if (argc == 2 && strcmp(argv[1], "-") == 0)
while (fgets(line, sizeof line, stdin) != NULL) {
if (line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = '\0';
crc(line);
}
else
do {
crc(argv[1]);
argv++;
argc--;
} while (argc > 1);
return(errs != 0);
}
#endif
/* Crctab calculated by Mark G. Mendel, Network Systems Corporation */
static unsigned short crctab[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
/* Updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
* NOTE: First argument must be in range 0 to 255.
* Second argument is referenced twice.
*
* Programmers may incorporate any or all code into their programs,
* giving proper credit within the source. Publication of the
* source routines is permitted so long as proper credit is given
* to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
* Omen Technology.
*/
#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
#if CRC_ONLY
unsigned short crc(char *fname)
#else
void crc(fname)
char *fname;
#endif
{
register int c;
register long len = 0;
register unsigned short crc = 0;
register FILE *fp;
#if CRC_ONLY
if((fp = fopen(fname, "r")) == NULL)
return 0;
#else
if (fname == NULL)
fp = stdin;
else if ((fp = fopen(fname, "r")) == NULL) {
fprintf(stderr, "crc: cannot open %s\n", fname);
errs++;
return;
}
#endif
while ((c = getc(fp)) != EOF) {
len++;
crc = updcrc(c, crc);
}
#if CRC_ONLY
fclose(fp);
return crc;
#else
printf("%05u %6ld", crc, len);
if (fname) {
printf(" %s", fname);
fclose(fp);
}
printf("\n");
#endif
}

View file

@ -1,935 +0,0 @@
/* file.c Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#include <net/hton.h>
#include "ftp.h"
#include "file.h"
#include "net.h"
static char *dir(char *path, int full);
static int asciisize(int fd, off_t *filesize);
static off_t asciisetsize(int fd, off_t filesize);
static int cloneit(char *file, int mode);
#if (__WORD_SIZE == 4)
static char buffer[8192];
#else
static char buffer[2048];
#endif
static char line2[512];
static char *dir(path, full)
char *path;
int full;
{
char cmd[128];
static char name[32];
tmpnam(name);
if(full)
sprintf(cmd, "ls -l %s > %s", path, name);
else
sprintf(cmd, "ls -dA %s > %s", path, name);
system(cmd);
return(name);
}
int DOascii()
{
int s;
if(DOcmdcheck())
return(0);
s = DOcommand("TYPE", "A");
type = TYPE_A;
return(s);
}
int DObinary()
{
int s;
if(DOcmdcheck())
return(0);
s = DOcommand("TYPE", "I");
type = TYPE_I;
return(s);
}
int DOblock()
{
int s;
if(DOcmdcheck())
return(0);
s = DOcommand("MODE", "B");
mode = MODE_B;
return(s);
}
int DOstream()
{
int s;
if(DOcmdcheck())
return(0);
s = DOcommand("MODE", "S");
mode = MODE_S;
return(s);
}
int DOpwd()
{
int s;
if(DOcmdcheck())
return(0);
s = DOcommand("PWD", "");
if(s == 500 || s == 502)
s = DOcommand("XPWD", "");
return(s);
}
int DOcd()
{
char *path;
int s;
if(DOcmdcheck())
return(0);
path = cmdargv[1];
if(cmdargc < 2) {
if(readline("Path: ", line2, sizeof(line2)) < 0)
return(-1);
path = line2;
}
if(!strcmp(path, ".."))
s = DOcommand("CDUP", "");
else
s = DOcommand("CWD", path);
if(s == 500 || s == 502) {
if(!strcmp(path, ".."))
s = DOcommand("XCUP", "");
else
s = DOcommand("XCWD", path);
}
return(s);
}
int DOmkdir()
{
char *path;
int s;
if(DOcmdcheck())
return(0);
path = cmdargv[1];
if(cmdargc < 2) {
if(readline("Directory: ", line2, sizeof(line2)) < 0)
return(-1);
path = line2;
}
s = DOcommand("MKD", path);
if(s == 500 || s == 502)
s = DOcommand("XMKD", path);
return(s);
}
int DOrmdir()
{
char *path;
int s;
if(DOcmdcheck())
return(0);
path = cmdargv[1];
if(cmdargc < 2) {
if(readline("Directory: ", line2, sizeof(line2)) < 0)
return(-1);
path = line2;
}
s = DOcommand("RMD", path);
if(s == 500 || s == 502)
s = DOcommand("XRMD", path);
return(s);
}
int DOdelete()
{
char *file;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
return(DOcommand("DELE", file));
}
int DOmdtm()
{
char *file;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
return(DOcommand("MDTM", file));
}
int DOsize()
{
char *file;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
return(DOcommand("SIZE", file));
}
int DOstat()
{
char *file;
if(cmdargc < 2) {
if(!linkopen) {
printf("You must \"OPEN\" a connection first.\n");
return(0);
} else {
return(DOcommand("STAT", ""));
}
}
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
return(DOcommand("STAT", file));
}
int DOlist()
{
char *path;
char *local;
int fd;
int s;
if(DOcmdcheck())
return(0);
path = cmdargv[1];
if(cmdargc < 2)
path = "";
if(cmdargc < 3)
local = "";
else
local = cmdargv[2];
if(*local == '\0')
fd = 1;
else
fd = open(local, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", local, strerror(errno));
return(0);
}
s = DOdata("LIST", path, RETR, fd);
if(fd > 2)
close(fd);
return(s);
}
int DOnlst()
{
char *path;
char *local;
int fd;
int s;
if(DOcmdcheck())
return(0);
path = cmdargv[1];
if(cmdargc < 2)
path = "";
if(cmdargc < 3)
local = "";
else
local = cmdargv[2];
if(*local == '\0')
fd = 1;
else
fd = open(local, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", local, strerror(errno));
return(0);
}
s = DOdata("NLST", path, RETR, fd);
if(fd > 2)
close(fd);
return(s);
}
int DOretr()
{
char *file, *localfile;
int fd;
int s;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("Remote File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
if(cmdargc < 3)
localfile = file;
else
localfile = cmdargv[2];
fd = open(localfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", localfile, strerror(errno));
return(0);
}
s = DOdata("RETR", file, RETR, fd);
close(fd);
return(s);
}
int DOrretr()
{
char *file, *localfile;
int fd;
int s;
off_t filesize;
char restart[16];
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("Remote File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
if(cmdargc < 3)
localfile = file;
else
localfile = cmdargv[2];
fd = open(localfile, O_RDWR);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", localfile, strerror(errno));
return(0);
}
if(type == TYPE_A) {
if(asciisize(fd, &filesize)) {
printf("Could not determine ascii file size of %s\n", localfile);
close(fd);
return(0);
}
} else
filesize = lseek(fd, 0, SEEK_END);
sprintf(restart, "%u", filesize);
s = DOcommand("REST", restart);
if(s != 350) {
close(fd);
return(s);
}
s = DOdata("RETR", file, RETR, fd);
close(fd);
return(s);
}
char *ttime(time_t t)
{
struct tm *tm;
static char tbuf[16];
tm = localtime(&t);
sprintf(tbuf, "%04d%02d%02d%02d%02d.%02d",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return(tbuf);
}
static int cloneit(file, mode)
char *file;
int mode;
{
int opr;
int s;
int ss;
struct stat st;
static unsigned short lcrc;
static unsigned short ccrc;
static unsigned long csize;
static char ft;
static unsigned long maj;
static unsigned long min;
static unsigned long uid;
static unsigned long gid;
static unsigned long fmode;
static unsigned long size;
static unsigned long mtime;
struct utimbuf ut;
unsigned short crc(char *fname);
if(mode == 1) {
/* see if file exists locally */
ss = stat(file, &st);
opr = printreply;
printreply = 0;
s = DOcommand("SITE FDET", file);
printreply = opr;
if((s / 100) != 2)
return(-1);
sscanf(reply, "%*d %c%lu%lu%lu%lu%lu%lu%lu",
&ft, &maj, &min, &uid, &gid, &fmode, &size, &mtime);
if(ft == 'f') {
opr = printreply;
printreply = 0;
s = DOcommand("SITE CCRC", file);
printreply = opr;
if((s / 100) != 2)
return(-1);
sscanf(reply, "%*hu %*s%u%lu", &ccrc, &csize);
if(ss < 0) return(-1);
lcrc = crc(file);
if(size != csize || size != st.st_size || ccrc != lcrc)
return(-1);
} else
if(ss < 0 && ft == 'd') {
s = mkdir(file, fmode);
printf("mkdir %s\n", file);
} else
if((ss < 0) && (ft == 'b' || ft == 'c' || ft == 'p')) {
s = mknod(file, fmode, maj << 8 | min);
printf("mknod %s %lu %lu\n", file, maj, min);
} else
return(0);
}
ss = stat(file, &st);
if(ss < 0)
return(-1);
if(st.st_uid != uid || st.st_gid != gid) {
s = chown(file, uid, gid);
printf("chown %lu:%lu %s\n", uid, gid, file);
}
if(st.st_mode != fmode) {
s = chmod(file, fmode);
printf("chmod %04lo %s\n", fmode, file);
}
if(st.st_mtime != mtime) {
ut.actime = mtime;
ut.modtime = mtime;
s = utime(file, &ut);
printf("touch -m -t %s %s\n", ttime(mtime), file);
}
return(0);
}
int DOMretr()
{
char *files;
int fd, s;
char *p;
FILE *fp;
char name[32];
if(DOcmdcheck())
return(0);
files = cmdargv[1];
if(cmdargc < 2) {
if(readline("Files: ", line2, sizeof(line2)) < 0)
return(-1);
files = line2;
}
tmpnam(name);
fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", name, strerror(errno));
return(0);
}
s = DOdata("NLST", files, RETR, fd);
close(fd);
if(s == 226 || s == 250) {
fp = fopen(name, "r");
unlink(name);
if(fp == (FILE *)NULL) {
printf("Unable to open file listing.\n");
return(0);
}
while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
p = line2 + strlen(line2) - 1;
if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
printf("Retrieving file: %s\n", line2); fflush(stdout);
fd = open(line2, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0)
printf("Unable to open local file %s\n", line2);
else {
s = DOdata("RETR", line2, RETR, fd);
close(fd);
if(s < 0) break;
}
}
fclose(fp);
} else
unlink(name);
return(s);
}
int DOappe()
{
char *file, *remotefile;
int fd;
int s;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("Local File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
if(cmdargc < 3)
remotefile = file;
else
remotefile = cmdargv[2];
fd = open(file, O_RDONLY);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", file, strerror(errno));
return(0);
}
s = DOdata("APPE", remotefile, STOR, fd);
close(fd);
return(s);
}
int DOstor()
{
char *file, *remotefile;
int fd;
int s;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("Local File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
if(cmdargc < 3)
remotefile = file;
else
remotefile = cmdargv[2];
fd = open(file, O_RDONLY);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", file, strerror(errno));
return(0);
}
s = DOdata("STOR", remotefile, STOR, fd);
close(fd);
return(s);
}
int DOrstor()
{
char *file, *remotefile;
int fd;
int s;
off_t filesize, rmtsize;
char restart[16];
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("Local File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
if(cmdargc < 3)
remotefile = file;
else
remotefile = cmdargv[2];
s = DOcommand("SIZE", remotefile);
if(s != 215)
return(s);
rmtsize = atol(reply+4);
fd = open(file, O_RDONLY);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", file, strerror(errno));
return(0);
}
if(type == TYPE_A)
filesize = asciisetsize(fd, rmtsize);
else
filesize = lseek(fd, rmtsize, SEEK_SET);
if(filesize != rmtsize) {
printf("Could not set file start of %s\n", file);
close(fd);
return(0);
}
sprintf(restart, "%u", rmtsize);
s = DOcommand("REST", restart);
if(s != 350) {
close(fd);
return(s);
}
s = DOdata("STOR", remotefile, STOR, fd);
close(fd);
return(s);
}
int DOstou()
{
char *file, *remotefile;
int fd;
int s;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
if(readline("Local File: ", line2, sizeof(line2)) < 0)
return(-1);
file = line2;
}
if(cmdargc < 3)
remotefile = file;
else
remotefile = cmdargv[2];
fd = open(file, O_RDONLY);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", file, strerror(errno));
return(0);
}
s = DOdata("STOU", remotefile, STOR, fd);
close(fd);
return(s);
}
int DOMstor()
{
char *files;
char *name;
char *p;
int fd, s;
FILE *fp;
if(DOcmdcheck())
return(0);
files = cmdargv[1];
if(cmdargc < 2) {
if(readline("Files: ", line2, sizeof(line2)) < 0)
return(-1);
files = line2;
}
name = dir(files, 0);
fp = fopen(name, "r");
if(fp == (FILE *)NULL) {
printf("Unable to open listing file.\n");
return(0);
}
while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
p = line2 + strlen(line2) - 1;
if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
printf("Sending file: %s\n", line2); fflush(stdout);
fd = open(line2, O_RDONLY);
if(fd < 0)
printf("Unable to open local file %s\n", line2);
else {
s = DOdata("STOR", line2, STOR, fd);
close(fd);
if(s < 0) break;
}
}
fclose(fp);
unlink(name);
return(s);
}
static int asciisize(fd, filesize)
int fd;
off_t *filesize;
{
unsigned long count;
char *p, *pp;
int cnt;
count = 0;
while((cnt = read(fd, buffer, sizeof(buffer))) > 0) {
p = buffer; pp = buffer + cnt;
count += cnt;
while(p < pp)
if(*p++ == '\n')
count++;
}
if(cnt == 0) {
*filesize = count;
return(0);
}
return(-1);
}
static off_t asciisetsize(fd, filesize)
int fd;
off_t filesize;
{
off_t sp;
int s;
sp = 0;
while(sp < filesize) {
s = read(fd, buffer, 1);
if(s < 0)
return(-1);
if(s == 0) break;
sp++;
if(*buffer == '\n')
sp++;
}
return(sp);
}
int DOclone()
{
char *files;
int fd, s;
char *p;
FILE *fp;
char name[32];
if(DOcmdcheck())
return(0);
files = cmdargv[1];
tmpnam(name);
fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0) {
printf("Could not open local file %s. Error %s\n", name, strerror(errno));
return(0);
}
s = DOdata("NLST", files, RETR, fd);
close(fd);
if(s == 226 || s == 250) {
fp = fopen(name, "r");
unlink(name);
if(fp == (FILE *)NULL) {
printf("Unable to open file listing.\n");
return(0);
}
while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
p = line2 + strlen(line2) - 1;
if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
cmdargv[1] = line2;
if(cloneit(line2, 1)) {
printf("Retrieving file: %s\n", line2); fflush(stdout);
fd = open(line2, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(fd < 0)
printf("Unable to open local file %s\n", line2);
else {
s = DOdata("RETR", line2, RETR, fd);
close(fd);
if(s < 0) break;
}
s = cloneit(line2, 2);
}
}
fclose(fp);
} else
unlink(name);
return(s);
}

View file

@ -1,33 +0,0 @@
/* file.h Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
int recvfile(int fd, int fdin);
int sendfile(int fd, int fdout);
int DOascii(void);
int DObinary(void);
int DOblock(void);
int DOstream(void);
int DOpwd(void);
int DOcd(void);
int DOmkdir(void);
int DOrmdir(void);
int DOdelete(void);
int DOmdtm(void);
int DOsize(void);
int DOstat(void);
int DOlist(void);
int DOnlst(void);
int DOretr(void);
int DOrretr(void);
int DOMretr(void);
int DOappe(void);
int DOstor(void);
int DOrstor(void);
int DOstou(void);
int DOMstor(void);
int DOclone(void);

View file

@ -1,148 +0,0 @@
.TH FTP 1
.SH NAME
ftp \- a File Transfer Protocol client for Minix
.SH SYNOPSIS
.B ftp
.RI [ server_name ]
.SH DESCRIPTION
.B Ftp
is a File Transfer Protocol client for Minix written by Michael Temari.
.P
There are no command line options for
.B ftp
except for the optional server name, which may be either a numeric IP address
or a domain name resolvable by DNS.
.P
If a server name is specified a connection attempt will be made, and you
will be prompted for a user name and password by the remote system.
Following the login (or immediately, if no server name was specified), the
.br
.B ftp>
.br
prompt is displayed. The following commands are accepted at the prompt:
.P
Command: Description
.br
! Escape to a shell
.br
append Append a file to remote host
.br
ascii Set file transfer type to ascii
.br
binary Set file transfer type to binary
.br
block Set file transfer mode to block
.br
bye Close connection and exit
.br
cd Change directory on remote host
.br
close Close connection
.br
clone Clone a file
.br
del Remove file on remote host
.br
dir Display long form remote host directory listing
.br
exit Close connection and exit
.br
get Retrieve a file from remote host
.br
help Display this text
.br
lcd Change directory on local host
.br
ldir Display long form local host directory listing
.br
lls Display local host directory listing
.br
lmkdir Create directory on local host
.br
lpwd Display current directory on local host
.br
lrmdir Remove directory on local host
.br
ls Display remote host directory listing
.br
mget Retrieve multiple files from remote host
.br
mkdir Create directory on remote host
.br
mod Get file modification time
.br
mput Send multiple files to remote host
.br
noop Send the ftp NOOP command
.br
open Open connection to remote host
.br
pass Enter remote user password
.br
passive Toggle passive mode
.br
put Send a file to remote host
.br
putu Send a file to remote host(unique)
.br
pwd Display current directory on remote host
.br
quit Close connection and exit
.br
quote Send raw ftp command to remote host
.br
reget Restart a partial file retrieve from remote host
.br
remotehelp Display ftp commands implemented on remote host
.br
reput Restart a partial file send to remote host
.br
rm Remove file on remote host
.br
rmdir Remove directory on remote host
.br
site Send a site specific command
.br
size Get file size information
.br
status Get connection/file status information
.br
stream Set file transfer mode to stream
.br
system Get remote system type information
.br
user Enter remote user information
.br
ver Display client version information
.SH "SEE ALSO"
.BR ftpd (8),
.BR ftpget (1).
.SH NOTES
The FTP protocol passes unencrypted usernames and passwords to clients,
so they are potentially exposed to evildoers with network sniffers. So be
wary of using this to exchange files between your own accounts. Obviously
if you have a root account on another system and the remote system will
accept a login as root this is extremely dangerous. (Many ftp servers will
not allow a connection by root).
.P
Text-mode (ASCII) transfers are the default mode, be sure to enter the
"binary" command if you are downloading a program file or a compressed
archive, in fact anything other than a text file from a machine with a
different text-file format than Minix uses.
.P
If you are behind a firewall you probably need to use passive mode to
successfully transfer files.
.SH BUGS
None are known, but there may be some unknown ones. Version 1.00 corrects
a bug in previous versions that would append a \\r (0xd) character to file
names on the destination when an mget transfer was used in binary mode.
.SH AUTHOR
The Minix httpd server was created by and is maintained by Michael Temari
<Michael@TemWare.Com>. The earliest version was released in 1992, for use
with Michael's TNet networking extensions for Minix 1.5.
.P
Man page compiled by Al Woodhull <asw@woodhull.com>
.\" updated 2006-06-18

View file

@ -1,407 +0,0 @@
/* ftp.c Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* ftp An ftp client program for use with TNET.
*
* Usage: ftp [host]
*
* Version: 0.10 06/21/92 (pre-release not yet completed)
* 0.20 07/01/92
* 0.30 01/15/96 (Minix 1.7.1 initial release)
* 0.40 08/27/96
* 0.50 03/08/00
* 1.00 12/12/03 (added ver command)
* 1.01 02/07/05
*
* Author: Michael Temari, <Michael@TemWare.Com>
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include "ftp.h"
#include "local.h"
#include "file.h"
#include "other.h"
#include "net.h"
char *FtpVersion = "1.01 02/07/05";
int linkopen;
int loggedin;
int type;
int format;
int mode;
int structure;
int passive;
int atty;
int cmdargc;
char *cmdargv[NUMARGS];
int printreply = 1;
char reply[1024];
/* Already declared in stdio.h */
#define getline ftp_getline
static void makeargs(char *buff);
int DOver(void);
int DOhelp(void);
static int getline(char *line, int len);
int main(int argc, char *argv[]);
static void makeargs(buff)
char *buff;
{
int i;
char *p;
for(i = 0; i < NUMARGS; i++)
cmdargv[i] = (char *)0;
p = buff + strlen(buff) - 1;
while(p >= buff)
if(*p == '\r' || *p == '\n' || isspace(*p))
*p-- = '\0';
else
break;
p = buff;
cmdargc = 0;
while(cmdargc < NUMARGS) {
while(*p && isspace(*p))
p++;
if(*p == '\0')
break;
cmdargv[cmdargc++] = p;
while(*p && !isspace(*p)) {
if(cmdargc == 1)
*p = tolower(*p);
p++;
}
if(*p == '\0')
break;
*p = '\0';
p++;
}
}
int readline(prompt, buff, len)
char *prompt;
char *buff;
int len;
{
char *p;
printf(prompt); fflush(stdout);
if(fgets(buff, len, stdin) == (char *)NULL) {
printf("\nEnd of file on input!\n");
return(-1);
}
p = buff + strlen(buff) - 1;
while(p >= buff)
if(*p == '\r' || *p == '\n' || isspace(*p))
*p-- = '\0';
else
break;
if(!atty) {
printf("%s\n", buff);
fflush(stdout);
}
return(0);
}
static int getline(line, len)
char *line;
int len;
{
int s;
int gotcr;
/* leave room for at end for null */
len--;
/* got to be able to put in at least 1 character */
if(len < 1)
return(-1);
gotcr = 0;
while(len-- > 0) {
s = read(ftpcomm_fd, line, 1);
if(s != 1)
return(-1);
if(*line == '\n')
break;
gotcr = (*line == '\r');
line++;
}
if(gotcr)
--line;
*line = '\0';
return(0);
}
int DOgetreply()
{
int firsttime;
int s;
char code[4];
do {
firsttime = 1;
do {
if((s = getline(reply, sizeof(reply))) < 0)
return(s);
if(printreply) {
printf("%s\n", reply);
fflush(stdout);
}
if(firsttime) {
firsttime = 0;
strncpy(code, reply, 3);
code[3] = '\0';
}
} while(strncmp(reply, code, 3) || reply[3] == '-');
s = atoi(code);
} while(s < 200 && s != 125 && s != 150);
return(s);
}
int DOcmdcheck()
{
if(!linkopen) {
printf("You must \"OPEN\" a connection first.\n");
return(1);
}
if(!loggedin) {
printf("You must login first.\n");
return(1);
}
return(0);
}
int DOcommand(ftpcommand, ftparg)
char *ftpcommand;
char *ftparg;
{
int s;
#if 1
static char ss[64];
if(*ftparg)
sprintf(ss, "%s %s\r\n", ftpcommand, ftparg);
else
sprintf(ss, "%s\r\n", ftpcommand);
s = write(ftpcomm_fd, ss, strlen(ss));
if(s != strlen(ss))
return(-1);
#else
s = write(ftpcomm_fd, ftpcommand, strlen(ftpcommand));
if(s != strlen(ftpcommand))
return(-1);
if(*ftparg) {
s = write(ftpcomm_fd, " ", 1);
if(s != 1)
return(-1);
s = write(ftpcomm_fd, ftparg, strlen(ftparg));
if(s != strlen(ftparg))
return(-1);
}
s = write(ftpcomm_fd, "\r\n", 2);
if(s != 2)
return(-1);
#endif
return(DOgetreply());
}
int DOver()
{
printf("FTP Version %s\n", FtpVersion);
return(0);
}
int DOhelp()
{
char junk[10];
printf("Command: Description\n");
printf("! Escape to a shell\n");
printf("append Append a file to remote host\n");
printf("ascii Set file transfer type to ascii\n");
printf("binary Set file transfer type to binary\n");
printf("block Set file transfer mode to block\n");
printf("bye Close connection and exit\n");
printf("cd Change directory on remote host\n");
printf("close Close connection\n");
printf("clone Clone a file\n");
printf("del Remove file on remote host\n");
printf("dir Display long form remote host directory listing\n");
printf("exit Close connection and exit\n");
printf("get Retrieve a file from remote host\n");
printf("help Display this text\n");
if(readline("Press ENTER to continue... ", junk, sizeof(junk)))
return(-1);
printf("lcd Change directory on local host\n");
printf("ldir Display long form local host directory listing\n");
printf("lls Display local host directory listing\n");
printf("lmkdir Create directory on local host\n");
printf("lpwd Display current directory on local host\n");
printf("lrmdir Remove directory on local host\n");
printf("ls Display remote host directory listing\n");
printf("mget Retrieve multiple files from remote host\n");
printf("mkdir Create directory on remote host\n");
printf("mod Get file modification time\n");
printf("mput Send multiple files to remote host\n");
printf("noop Send the ftp NOOP command\n");
if(readline("Press ENTER to continue... ", junk, sizeof(junk)))
return(-1);
printf("open Open connection to remote host\n");
printf("pass Enter remote user password\n");
printf("passive Toggle passive mode\n");
printf("put Send a file to remote host\n");
printf("putu Send a file to remote host(unique)\n");
printf("pwd Display current directory on remote host\n");
printf("quit Close connection and exit\n");
printf("quote Send raw ftp command to remote host\n");
printf("reget Restart a partial file retrieve from remote host\n");
printf("remotehelp Display ftp commands implemented on remote host\n");
printf("reput Restart a partial file send to remote host\n");
printf("rm Remove file on remote host\n");
printf("rmdir Remove directory on remote host\n");
if(readline("Press ENTER to continue... ", junk, sizeof(junk)))
return(-1);
printf("site Send a site specific command\n");
printf("size Get file size information\n");
printf("status Get connection/file status information\n");
printf("stream Set file transfer mode to stream\n");
printf("system Get remote system type information\n");
printf("user Enter remote user information\n");
printf("ver Display client version information\n");
return(0);
}
struct commands {
char *name;
int(*func) (void);
};
static struct commands commands[] = {
"!", DOlshell,
"append", DOappe,
"ascii", DOascii,
"binary", DObinary,
"block", DOblock,
"bye", DOquit,
"cd", DOcd,
"close", DOclose,
"clone", DOclone,
"del", DOdelete,
"dir", DOlist,
"exit", DOquit,
"get", DOretr,
"help", DOhelp,
"lcd", DOlcd,
"ldir", DOllist,
"lls", DOlnlst,
"lmkdir", DOlmkdir,
"lpwd", DOlpwd,
"lrmdir", DOlrmdir,
"ls", DOnlst,
"mget", DOMretr,
"mkdir", DOmkdir,
"mod", DOmdtm,
"mput", DOMstor,
"noop", DOnoop,
"open", DOopen,
"pass", DOpass,
"passive", DOpassive,
"put", DOstor,
"putu", DOstou,
"pwd", DOpwd,
"quit", DOquit,
"quote", DOquote,
"reget", DOrretr,
"remotehelp", DOremotehelp,
"reput", DOrstor,
"rm", DOdelete,
"rmdir", DOrmdir,
"site", DOsite,
"size", DOsize,
"status", DOstat,
"stream", DOstream,
"system", DOsyst,
"user", DOuser,
"ver", DOver,
"", (int (*)())0
};
int main(argc, argv)
int argc;
char *argv[];
{
int s;
struct commands *cmd;
static char buffer[128];
if(NETinit())
return(-1);
FTPinit();
s = 0;
if(argc > 1) {
sprintf(buffer, "open %s ", argv[1]);
makeargs(buffer);
s = DOopen();
if(atty && s > 0) {
sprintf(buffer, "user");
makeargs(buffer);
s = DOuser();
}
}
while(s >= 0) {
s = readline("ftp>", buffer, sizeof(buffer));
if(s < 0) break;
makeargs(buffer);
if(cmdargc == 0) continue;
for(cmd = commands; *cmd->name != '\0'; cmd++)
if(!strcmp(cmdargv[0], cmd->name))
break;
if(*cmd->name != '\0')
s = (*cmd->func)();
else {
s = 0;
printf("Command \"%s\" not recognized.\n", cmdargv[0]);
}
}
return(s);
}

View file

@ -1,39 +0,0 @@
/* ftp.h Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
extern int linkopen;
extern int loggedin;
extern int type;
extern int format;
extern int mode;
extern int structure;
extern int passive;
extern int atty;
#define NUMARGS 10
extern int cmdargc;
extern char *cmdargv[NUMARGS];
extern int printreply;
extern char reply[1024];
#define RETR 0
#define STOR 1
#define TYPE_A 0
#define TYPE_I 1
#define MODE_S 0
#define MODE_B 1
#define MODE_B_EOF 64
int readline(char *prompt, char *buff, int len);
int DOgetreply(void);
int DOcmdcheck(void);
int DOcommand(char *ftpcommand, char *ftparg);

View file

@ -1,134 +0,0 @@
/* local.c Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "ftp.h"
#include "local.h"
static char line2[512];
static void dodir(char *path, int full);
int DOlpwd()
{
if(getcwd(line2, sizeof(line2)) == (char *)NULL)
printf("Could not determine local directory. %s\n", strerror(errno));
else
printf("Current local directory: %s\n", line2);
return(0);
}
int DOlcd()
{
char *path;
path = cmdargv[1];
if(cmdargc < 2) {
if(readline("Path: ", line2, sizeof(line2)) < 0)
return(-1);
path = line2;
}
if(chdir(path))
printf("Could not change local directory. %s\n", strerror(errno));
else
return(DOlpwd());
return(0);
}
int DOlmkdir()
{
char *path;
path = cmdargv[1];
if(cmdargc < 2) {
if(readline("Path: ", line2, sizeof(line2)) < 0)
return(-1);
path = line2;
}
if(mkdir(path, 0777))
printf("Could not make directory %s. %s\n", path, strerror(errno));
else
printf("Directory created.\n");
return(0);
}
int DOlrmdir()
{
char *path;
path = cmdargv[1];
if(cmdargc < 2) {
if(readline("Path: ", line2, sizeof(line2)) < 0)
return(-1);
path = line2;
}
if(rmdir(path))
printf("Could not remove directory %s. %s\n", path, strerror(errno));
else
printf("Directory removed.\n");
return(0);
}
int DOllist(void)
{
dodir(".", 1);
return(0);
}
int DOlnlst(void)
{
dodir(".", 0);
return(0);
}
int DOlshell(void)
{
(void) system("$SHELL");
return(0);
}
static void dodir(path, full)
char *path;
int full;
{
static char cmd[128];
static char name[32];
(void) tmpnam(name);
if(full)
sprintf(cmd, "ls -l %s > %s", path, name);
else
sprintf(cmd, "ls %s > %s", path, name);
(void) system(cmd);
sprintf(cmd, "more %s", name);
(void) system(cmd);
sprintf(cmd, "rm %s", name);
(void) system(cmd);
}

View file

@ -1,15 +0,0 @@
/* local.h Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
int DOlpwd(void);
int DOlcd(void);
int DOlmkdir(void);
int DOlrmdir(void);
int DOllist(void);
int DOlnlst(void);
int DOlshell(void);

View file

@ -1,569 +0,0 @@
/* net.c Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <net/netlib.h>
#include <net/hton.h>
#include <net/gen/netdb.h>
#include <net/gen/in.h>
#include <net/gen/inet.h>
#include <net/gen/tcp.h>
#include <net/gen/tcp_io.h>
#include "ftp.h"
#include "xfer.h"
#include "net.h"
void donothing(int sig);
int ftpcomm_fd;
static ipaddr_t myip;
static ipaddr_t hostip;
static char host[256];
static int lpid;
int NETinit()
{
int s;
char *tcp_device;
int tcp_fd;
nwio_tcpconf_t nwio_tcpconf;
/* All this just to get our ip address */
if((tcp_device = getenv("TCP_DEVICE")) == (char *)NULL)
tcp_device = TCP_DEVICE;
tcp_fd = open(tcp_device, O_RDWR);
if(tcp_fd < 0) {
perror("ftp: Could not open tcp_device");
return(-1);
}
s = ioctl(tcp_fd, NWIOGTCPCONF, &nwio_tcpconf);
if(s < 0) {
perror("ftp: Could not get tcp configuration");
return(-1);
}
myip = nwio_tcpconf.nwtc_locaddr;
close(tcp_fd);
return(0);
}
int DOopen()
{
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t tcpcopt;
char *tcp_device;
tcpport_t port;
int s;
struct hostent *hp;
struct servent *servent;
if(linkopen) {
printf("Use \"CLOSE\" to close the connection first.\n");
return(0);
}
if(cmdargc < 2) {
if(readline("Host: ", host, sizeof(host)) < 0)
return(-1);
} else
strncpy(host, cmdargv[1], sizeof(host));
if((servent = getservbyname("ftp", "tcp")) == (struct servent *)NULL) {
fprintf(stderr, "ftp: Could not find ftp tcp service\n");
port = htons(21);
} else
port = (tcpport_t)servent->s_port;
hp = gethostbyname(host);
if(hp == (struct hostent *)NULL) {
hostip = (ipaddr_t)0;
printf("Unresolved host %s\n", host);
return(0);
} else
memcpy((char *) &hostip, (char *) hp->h_addr, hp->h_length);
/* This HACK allows the server to establish data connections correctly */
/* when using the loopback device to talk to ourselves */
if((hostip & ntohl(0xFF000000)) == inet_addr("127.0.0.0"))
hostip = myip;
if((tcp_device = getenv("TCP_DEVICE")) == NULL)
tcp_device = "/dev/tcp";
if((ftpcomm_fd = open(tcp_device, O_RDWR)) < 0) {
perror("ftp: open error on tcp device");
return(-1);
}
tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
tcpconf.nwtc_remaddr = hostip;
tcpconf.nwtc_remport = port;
s = ioctl(ftpcomm_fd, NWIOSTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOSTCPCONF");
close(ftpcomm_fd);
return(-1);
}
tcpcopt.nwtcl_flags = 0;
s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
if(s < 0) {
perror("ftp: ioctl error on NWIOTCPCONN");
close(ftpcomm_fd);
return(-1);
}
s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOGTCPCONF");
close(ftpcomm_fd);
return(-1);
}
s = DOgetreply();
if(s < 0) {
close(ftpcomm_fd);
return(s);
}
if(s != 220) {
close(ftpcomm_fd);
return(0);
}
linkopen = 1;
return(s);
}
int DOclose()
{
if(!linkopen) {
printf("You can't close a connection that isn't open.\n");
return(0);
}
close(ftpcomm_fd);
linkopen = 0;
loggedin = 0;
return(0);
}
int DOquit()
{
int s;
if(linkopen) {
s = DOcommand("QUIT", "");
s = DOclose();
}
printf("FTP done.\n");
exit(0);
}
void donothing(sig)
int sig;
{
}
int DOdata(datacom, file, direction, fd)
char *datacom;
char *file;
int direction; /* RETR or STOR */
int fd;
{
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t tcplopt, tcpcopt;
char *tcp_device;
static int ftpdata_fd = -1;
char *buff;
ipaddr_t ripaddr;
tcpport_t rport;
static tcpport_t lport;
int s;
int i;
int wpid;
int cs;
int pfd[2];
char dummy;
char port[32];
int wasopen;
lport = htons(0xF000);
#ifdef DEBUG
printf("DOdata %s %s %d %d\n", datacom, file, direction, fd);
#endif
ripaddr = hostip;
rport = htons(2);
/* here we set up a connection to listen on if not passive mode */
/* otherwise we use this to connect for passive mode */
if((tcp_device = getenv("TCP_DEVICE")) == NULL)
tcp_device = "/dev/tcp";
if(ftpdata_fd >= 0 && mode != MODE_B) {
close(ftpdata_fd);
ftpdata_fd = -1;
}
wasopen = (ftpdata_fd >= 0);
#ifdef DEBUG
printf("wasopen = %d\n", wasopen);
#endif
if(wasopen)
goto WASOPEN;
#ifdef DEBUG
printf("b4 open = %d\n", ftpdata_fd);
#endif
if(ftpdata_fd == -1)
if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
perror("ftp: open error on tcp device");
return(0);
}
#ifdef DEBUG
printf("at open = %d\n", ftpdata_fd);
#endif
if(passive) {
#ifdef DEBUG
printf("b4 PASV command\n");
#endif
s = DOcommand("PASV", "");
#ifdef DEBUG
printf("PASV command returned %d\n", s);
#endif
if(s != 227) {
close(ftpdata_fd);
ftpdata_fd = -1;
return(s);
}
/* decode host and port */
buff = reply;
while(*buff && (*buff != '(')) buff++;
buff++;
ripaddr = (ipaddr_t)0;
for(i = 0; i < 4; i++) {
ripaddr = (ripaddr << 8) + (ipaddr_t)atoi(buff);
if((buff = strchr(buff, ',')) == (char *)0) {
printf("Could not parse PASV reply\n");
return(0);
}
buff++;
}
rport = (tcpport_t)atoi(buff);
if((buff = strchr(buff, ',')) == (char *)0) {
printf("Could not parse PASV reply\n");
return(0);
}
buff++;
rport = (rport << 8) + (tcpport_t)atoi(buff);
ripaddr = ntohl(ripaddr);
rport = ntohs(rport);
#ifdef DEBUG
printf("PASV %08x %04x\n", ripaddr, rport);
#endif
}
while(1) {
tcpconf.nwtc_flags = NWTC_SET_RA | NWTC_SET_RP;
if(passive || ntohs(lport) >= 0xF000) {
tcpconf.nwtc_flags |= NWTC_LP_SEL;
} else {
/* For no good reason Sun hosts don't like it if they have to
* connect to the same port twice in a short time...
*/
lport = htons(ntohs(lport) + 1);
tcpconf.nwtc_flags |= NWTC_LP_SET;
tcpconf.nwtc_locport = lport;
}
tcpconf.nwtc_remaddr = ripaddr;
tcpconf.nwtc_remport = rport;
#ifdef DEBUG
printf("b4 STCPCONF locport = %d\n", lport);
#endif
s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
#ifdef DEBUG
printf("at STCPCONF %d %d\n", s, errno);
#endif
if(s < 0) {
if(errno == EADDRINUSE) continue;
perror("ftp: ioctl error on NWIOSTCPCONF");
close(ftpdata_fd);
ftpdata_fd = -1;
return(0);
}
break;
}
#ifdef DEBUG
printf("b4 GTCPCONF\n");
#endif
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
#ifdef DEBUG
printf("at GTCPCONF %d %d\n", s, errno);
#endif
if(s < 0) {
perror("ftp: ioctl error on NWIOGTCPCONF");
close(ftpdata_fd);
ftpdata_fd = -1;
return(0);
}
lport = tcpconf.nwtc_locport;
#ifdef DEBUG
printf("lport = %04x\n", lport);
#endif
if(passive) {
/* passive mode we connect to them */
tcpcopt.nwtcl_flags = 0;
#ifdef DEBUG
printf("Doing TCPCONN\n");
#endif
s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
#ifdef DEBUG
printf("TCPCONN %d %d\n", s, errno);
#endif
if(s < 0) {
perror("ftp: error on ioctl NWIOTCPCONN");
close(ftpdata_fd);
ftpdata_fd = -1;
return(0);
}
#ifdef DEBUG
printf("GTCPCONF\n");
#endif
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
#ifdef DEBUG
printf("GTCPCONF %d %d\n", s, errno);
#endif
if(s < 0) {
perror("ftp: error on ioctl NWIOGTCPCONF");
close(ftpdata_fd);
ftpdata_fd = -1;
return(0);
}
} else {
/* we listen for them */
tcplopt.nwtcl_flags = 0;
#ifdef DEBUG
printf("Listen\n");
#endif
if (pipe(pfd) < 0) {
perror("ftp: could not create a pipe");
close(ftpdata_fd);
ftpdata_fd = -1;
return(0);
}
lpid = fork();
if(lpid < 0) {
perror("ftp: could not fork listener");
close(ftpdata_fd);
ftpdata_fd = -1;
close(pfd[0]);
close(pfd[1]);
return(0);
} else if(lpid == 0) {
#ifdef DEBUG
printf("Child here\n");
#endif
close(pfd[0]);
signal(SIGALRM, donothing);
alarm(15);
close(pfd[1]);
#ifdef DEBUG
printf("child TCPLISTEN\n");
#endif
s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
alarm(0);
#ifdef DEBUG
printf("listen %d %d\n", s, errno);
#endif
if(s < 0)
exit(errno); /* error */
else
exit(0); /* connection made */
}
#ifdef DEBUG
printf("Fork = %d\n", lpid);
#endif
/* Wait for the pipe to close, then the listener is ready (almost). */
close(pfd[1]);
(void) read(pfd[0], &dummy, 1);
close(pfd[0]);
while(1) {
wpid = waitpid(lpid, &cs, WNOHANG);
#ifdef DEBUG
printf("waitpid %d %d\n", wpid, cs);
printf("GTCPCONF loop\n");
#endif
if(wpid != 0) break;
signal(SIGALRM, donothing);
alarm(1);
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
alarm(0);
#ifdef DEBUG
printf("GTCPCONF loop %d %d\n", s, errno);
#endif
if(s == -1) break;
sleep(1);
}
#ifdef DEBUG
printf("GTCPCONF = %d\n", s);
#endif
}
#define hiword(x) ((u16_t)((x) >> 16))
#define loword(x) ((u16_t)(x & 0xffff))
#define hibyte(x) (((x) >> 8) & 0xff)
#define lobyte(x) ((x) & 0xff)
if(!passive) {
if(wpid != 0) {
close(ftpdata_fd);
ftpdata_fd = -1;
cs = (cs >> 8) & 0x00ff;
printf("Child listener error %s\n", strerror(cs));
return(0);
}
sprintf(port, "%u,%u,%u,%u,%u,%u",
hibyte(hiword(ntohl(myip))), lobyte(hiword(ntohl(myip))),
hibyte(loword(ntohl(myip))), lobyte(loword(ntohl(myip))),
hibyte(ntohs(lport)), lobyte(ntohs(lport)));
#ifdef DEBUG
printf("sending port command %s\n", port);
#endif
s = DOcommand("PORT", port);
#ifdef DEBUG
printf("port command = %d\n", s);
#endif
if(s != 200) {
close(ftpdata_fd);
ftpdata_fd = -1;
kill(lpid, SIGKILL);
(void) wait(&cs);
return(s);
}
}
WASOPEN:
#ifdef DEBUG
printf("doing data command %s %s\n", datacom, file);
#endif
s = DOcommand(datacom, file);
#ifdef DEBUG
printf("do command reply %d\n", s);
#endif
if(s == 125 || s == 150) {
if(!passive && !wasopen) {
while(1) {
#ifdef DEBUG
printf("Waiting for child %d\n", lpid);
#endif
s = wait(&cs);
#ifdef DEBUG
printf("Wait returned %d cs=%d errno=%d\n", s, cs, errno);
#endif
if(s < 0 || s == lpid)
break;
}
if(s < 0) {
perror("wait error:");
close(ftpdata_fd);
ftpdata_fd = -1;
kill(lpid, SIGKILL);
(void) wait(&cs);
return(s);
}
if((cs & 0x00ff)) {
printf("Child listener failed %04x\n", cs);
close(ftpdata_fd);
ftpdata_fd = -1;
return(-1);
}
cs = (cs >> 8) & 0x00ff;
if(cs) {
printf("Child listener error %s\n", strerror(cs));
close(ftpdata_fd);
ftpdata_fd = -1;
return(DOgetreply());
}
}
#ifdef DEBUG
printf("Before recvfile/sendfile call\n");
#endif
switch(direction) {
case RETR:
s = recvfile(fd, ftpdata_fd);
break;
case STOR:
s = sendfile(fd, ftpdata_fd);
break;
}
#ifdef DEBUG
printf("send/recieve %d\n", s);
#endif
if(mode != MODE_B) {
close(ftpdata_fd);
ftpdata_fd = -1;
}
s = DOgetreply();
#ifdef DEBUG
printf("send/recieve reply %d\n", s);
#endif
if(mode == MODE_B && s == 226) {
close(ftpdata_fd);
ftpdata_fd = -1;
}
} else {
if(!passive) {
kill(lpid, SIGKILL);
(void) wait(&cs);
}
close(ftpdata_fd);
ftpdata_fd = -1;
}
return(s);
}

View file

@ -1,15 +0,0 @@
/* net.h Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
int NETinit(void);
int DOopen(void);
int DOclose(void);
int DOquit(void);
int DOdata(char *datacom, char *file, int direction, int fd);
extern int ftpcomm_fd;

View file

@ -1,173 +0,0 @@
/* other.c Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* ftp An ftp client program for use with TNET.
*
* Author: Michael Temari, <Michael@TemWare.Com>
*/
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include "ftp.h"
#include "other.h"
static int docmdargs(char *cmd, int fa);
void FTPinit()
{
linkopen = 0;
loggedin = 0;
type = TYPE_A;
format = 0;
mode = MODE_S;
structure = 0;
passive = 0;
atty = isatty(0);
}
int DOpass()
{
int s;
struct termios oldtty, newtty;
char *pass;
char password[64];
if(!linkopen) {
printf("You must \"OPEN\" a connection first.\n");
return(0);
}
pass = cmdargv[1];
s = 0;
if(cmdargc < 2) {
if(atty) {
tcgetattr(fileno(stdout), &oldtty);
newtty = oldtty;
newtty.c_lflag &= ~ECHO;
tcsetattr(fileno(stdout), TCSANOW, &newtty);
}
s = readline("Password: ", password, sizeof(password));
if(atty) {
tcsetattr(fileno(stdout), TCSANOW, &oldtty);
printf("\n");
}
pass = password;
}
if(s < 0)
return(-1);
s = DOcommand("PASS", pass);
if(s == 230)
loggedin = 1;
return(s);
}
int DOuser()
{
char *user;
int s;
char username[32];
if(!linkopen) {
printf("You must \"OPEN\" a connection first.\n");
return(0);
}
loggedin = 0;
user = cmdargv[1];
s = 0;
if(cmdargc < 2) {
if(readline("Username: ", username, sizeof(username)) < 0)
return(-1);
user = username;
}
s = DOcommand("USER", user);
if(atty && s == 331) {
cmdargv[0] = "password";
cmdargc = 1;
return(DOpass());
}
if(s == 230)
loggedin = 1;
return(s);
}
int DOnoop()
{
if(DOcmdcheck())
return(0);
return(DOcommand("NOOP", ""));
}
int DOpassive()
{
passive = 1 - passive;
printf("Passive mode is now %s\n", (passive ? "ON" : "OFF"));
return(0);
}
int DOsyst()
{
if(DOcmdcheck())
return(0);
return(DOcommand("SYST", ""));
}
int DOremotehelp()
{
if(!linkopen) {
printf("You must \"OPEN\" a connection first.\n");
return(0);
}
return(DOcommand("HELP", ""));
}
static int docmdargs(cmd, fa)
char *cmd;
int fa;
{
int i;
static char args[512];
args[0] = '\0';
for(i = fa; i < cmdargc; i++) {
if(i != fa)
strcat(args, " ");
strcat(args, cmdargv[i]);
}
return(DOcommand(cmd, args));
}
int DOquote()
{
return(docmdargs(cmdargv[1], 2));
}
int DOsite()
{
return(docmdargs("SITE", 1));
}

View file

@ -1,17 +0,0 @@
/* other.h Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
*/
void FTPinit(void);
int DOpass(void);
int DOuser(void);
int DOnoop(void);
int DOpassive(void);
int DOsyst(void);
int DOremotehelp(void);
int DOquote(void);
int DOsite(void);

View file

@ -1,305 +0,0 @@
/* xfer.c Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*
* 03/14/00 Initial Release Michael Temari, <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#include <net/hton.h>
#include "ftp.h"
#include "xfer.h"
static int asciisend(int fd, int fdout);
static int binarysend(int fd, int fdout);
static int asciirecv(int fd, int fdin);
static int binaryrecv(int fd, int fdin);
#if (__WORD_SIZE == 4)
static char buffer[8192];
static char bufout[8192];
#else
static char buffer[2048];
static char bufout[2048];
#endif
static int asciisend(fd, fdout)
int fd;
int fdout;
{
int s;
char c;
char *p;
char *op, *ope;
unsigned long total=0L;
char block[3];
if(atty) {
printf("Sent ");
fflush(stdout);
}
op = bufout;
ope = bufout + sizeof(bufout) - 3;
while((s = read(fd, buffer, sizeof(buffer))) > 0) {
total += (long)s;
p = buffer;
while(s-- > 0) {
c = *p++;
if(c == '\n') {
*op++ = '\r';
total++;
}
*op++ = c;
if(op >= ope) {
if(mode == MODE_B) {
block[0] = '\0';
*(u16_t *)&block[1] = htons(op - bufout);
write(fdout, block, sizeof(block));
}
write(fdout, bufout, op - bufout);
op = bufout;
}
}
if(atty) {
printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
}
if(op > bufout) {
if(mode == MODE_B) {
block[0] = MODE_B_EOF;
*(u16_t *)&block[1] = htons(op - bufout);
write(fdout, block, sizeof(block));
}
write(fdout, bufout, op - bufout);
} else if(mode == MODE_B) {
block[0] = MODE_B_EOF;
*(u16_t *)&block[1] = htons(0);
write(fdout, block, sizeof(block));
s = 0;
}
if(atty) {
printf("\n");
fflush(stdout);
}
return(s);
}
static int binarysend(fd, fdout)
int fd;
int fdout;
{
int s;
unsigned long total=0L;
char block[3];
if(atty) {
printf("Sent ");
fflush(stdout);
}
while((s = read(fd, buffer, sizeof(buffer))) > 0) {
if(mode == MODE_B) {
block[0] = MODE_B_EOF;
*(u16_t *)&block[1] = htons(s);
write(fdout, block, sizeof(block));
}
write(fdout, buffer, s);
total += (long)s;
if(atty) {
printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
}
if(mode == MODE_B) {
block[0] = MODE_B_EOF;
*(u16_t *)&block[1] = htons(0);
write(fdout, block, sizeof(block));
s = 0;
}
if(atty) {
printf("\n");
fflush(stdout);
}
return(s);
}
int sendfile(fd, fdout)
int fd;
int fdout;
{
int s;
switch(type) {
case TYPE_A:
s = asciisend(fd, fdout);
break;
default:
s = binarysend(fd, fdout);
}
if(s < 0)
return(-1);
else
return(0);
}
static int asciirecv(fd, fdin)
int fd;
int fdin;
{
int s;
int gotcr;
char c;
char *p;
char *op, *ope;
unsigned long total=0L;
char block[3];
unsigned short cnt;
if(isatty && fd > 2) {
printf("Received ");
fflush(stdout);
}
gotcr = 0;
op = bufout; ope = bufout + sizeof(bufout) - 3;
cnt = 0;
while(1) {
if(mode != MODE_B)
cnt = sizeof(buffer);
else
if(cnt == 0) {
s = read(fdin, block, sizeof(block));
cnt = ntohs(*(u16_t *)&block[1]);
s = 0;
if(cnt == 0 && block[0] & MODE_B_EOF)
break;
}
s = read(fdin, buffer, cnt > sizeof(buffer) ? sizeof(buffer) : cnt);
if(s <= 0) break;
cnt -= s;
total += (long)s;
p = buffer;
while(s-- > 0) {
c = *p++;
if(gotcr) {
gotcr = 0;
if(c != '\n')
*op++ = '\r';
}
if(c == '\r')
gotcr = 1;
else
*op++ = c;
if(op >= ope) {
write(fd, bufout, op - bufout);
op = bufout;
}
}
if(atty && fd > 2) {
printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
if(cnt == 0 && mode == MODE_B && block[0] & MODE_B_EOF) {
s = 0;
break;
}
}
if(gotcr)
*op++ = '\r';
if(op > bufout)
write(fd, bufout, op - bufout);
if(atty && fd > 2) {
printf("\n");
fflush(stdout);
}
if((mode == MODE_B && cnt != 0) || s != 0)
return(-1);
else
return(0);
}
static int binaryrecv(fd, fdin)
int fd;
int fdin;
{
int s;
unsigned long total=0L;
char block[3];
unsigned short cnt;
if(atty && fd > 2) {
printf("Received ");
fflush(stdout);
}
cnt = 0;
while(1) {
if(mode != MODE_B)
cnt = sizeof(buffer);
else
if(cnt == 0) {
s = read(fdin, block, sizeof(block));
cnt = ntohs(*(u16_t *)&block[1]);
s = 0;
if(cnt == 0 && block[0] & MODE_B_EOF)
break;
}
s = read(fdin, buffer, cnt > sizeof(buffer) ? sizeof(buffer) : cnt);
if(s <= 0) break;
cnt -= s;
total += (long)s;
write(fd, buffer, s);
if(atty && fd > 2) {
printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
if(cnt == 0 && mode == MODE_B && block[0] & MODE_B_EOF) {
s = 0;
break;
}
}
if(atty && fd > 2) {
printf("\n");
fflush(stdout);
}
if((mode == MODE_B && cnt != 0) || s != 0)
return(-1);
else
return(0);
}
int recvfile(fd, fdin)
int fd;
int fdin;
{
int s;
switch(type) {
case TYPE_A:
s = asciirecv(fd, fdin);
break;
default:
s = binaryrecv(fd, fdin);
}
if(s < 0)
return(-1);
else
return(0);
}

View file

@ -1,8 +0,0 @@
/* xfer.h Copyright 1992-2000 by Michael Temari All Rights Reserved
*
* This file is part of ftp.
*
*/
int recvfile(int fd, int fdin);
int sendfile(int fd, int fdout);

View file

@ -131,6 +131,7 @@
2012/10/17 12:00:00,usr.bin/ctags
2011/09/01 13:37:33,usr.bin/du
2013/03/22 12:00:00,usr.bin/from
2013/04/05 12:00:00,usr.bin/ftp
2013/03/18 12:00:00,usr.bin/head
2012/10/17 12:00:00,usr.bin/genassym
2013/03/09 12:00:00,usr.bin/getopt

View file

@ -10,7 +10,7 @@ SUBDIR= \
col ctags \
du \
\
from \
from ftp \
genassym getopt head \
indent infocmp join \
ldd \

40
usr.bin/ftp/Makefile Normal file
View file

@ -0,0 +1,40 @@
# $NetBSD: Makefile,v 1.36 2012/12/21 18:07:36 christos Exp $
# from: @(#)Makefile 8.2 (Berkeley) 4/3/94
.include <bsd.own.mk>
USE_FORT?= yes # network client
PROG= ftp
SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c \
progressbar.c ruserpass.c util.c
# Uncomment the following to provide defaults for gate-ftp operation
#
#CPPFLAGS+=-DGATE_SERVER=\"ftp-gw.host\" # -DGATE_PORT=21
.if defined(__MINIX)
CPPFLAGS+= -DDIRENT_MISSING_D_NAMLEN
.endif # defined (__MINIX)
.if defined(SMALLPROG)
CPPFLAGS+=-DNO_EDITCOMPLETE -DNO_ABOUT -DNO_AUTH -DNO_HELP -DNO_STATUS -DNO_DEBUG -DNO_USAGE
.else
LDADD+= -ledit -lterminfo
DPADD+= ${LIBEDIT} ${LIBTERMINFO}
.if (${MKCRYPTO} != "no")
CPPFLAGS+= -DWITH_SSL
SRCS+=ssl.c
LDADD+= -lssl -lcrypto
DPADD+= ${LIBSSL} ${LIBCRYPTO}
.endif
.endif
.if (!defined(SMALLPROG) || defined(SMALLPROG_INET6)) && (${USE_INET6} != "no")
CPPFLAGS+= -DINET6
.endif
cmds.o fetch.o: version.h
main.o: ftp_var.h
.include <bsd.prog.mk>

2795
usr.bin/ftp/cmds.c Normal file

File diff suppressed because it is too large Load diff

307
usr.bin/ftp/cmdtab.c Normal file
View file

@ -0,0 +1,307 @@
/* $NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cmdtab.c 8.4 (Berkeley) 10/9/94";
#else
__RCSID("$NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp $");
#endif
#endif /* not lint */
#include <stdio.h>
#include "ftp_var.h"
/*
* User FTP -- Command Tables.
*/
#define HSTR static const char
#ifndef NO_HELP
HSTR accounthelp[] = "send account command to remote server";
HSTR appendhelp[] = "append to a file";
HSTR asciihelp[] = "set ascii transfer type";
HSTR beephelp[] = "beep when command completed";
HSTR binaryhelp[] = "set binary transfer type";
HSTR casehelp[] = "toggle mget upper/lower case id mapping";
HSTR cdhelp[] = "change remote working directory";
HSTR cduphelp[] = "change remote working directory to parent directory";
HSTR chmodhelp[] = "change file permissions of remote file";
HSTR connecthelp[] = "connect to remote ftp server";
HSTR crhelp[] = "toggle carriage return stripping on ascii gets";
HSTR debughelp[] = "toggle/set debugging mode";
HSTR deletehelp[] = "delete remote file";
HSTR disconhelp[] = "terminate ftp session";
HSTR domachelp[] = "execute macro";
HSTR edithelp[] = "toggle command line editing";
HSTR epsvhelp[] = "toggle use of EPSV/EPRT on both IPv4 and IPV6 ftp";
HSTR epsv4help[] = "toggle use of EPSV/EPRT on IPv4 ftp";
HSTR epsv6help[] = "toggle use of EPSV/EPRT on IPv6 ftp";
HSTR feathelp[] = "show FEATures supported by remote system";
HSTR formhelp[] = "set file transfer format";
HSTR gatehelp[] = "toggle gate-ftp; specify host[:port] to change proxy";
HSTR globhelp[] = "toggle metacharacter expansion of local file names";
HSTR hashhelp[] = "toggle printing `#' marks; specify number to set size";
HSTR helphelp[] = "print local help information";
HSTR idlehelp[] = "get (set) idle timer on remote side";
HSTR lcdhelp[] = "change local working directory";
HSTR lpagehelp[] = "view a local file through your pager";
HSTR lpwdhelp[] = "print local working directory";
HSTR lshelp[] = "list contents of remote path";
HSTR macdefhelp[] = "define a macro";
HSTR mdeletehelp[] = "delete multiple files";
HSTR mgethelp[] = "get multiple files";
HSTR mregethelp[] = "get multiple files restarting at end of local file";
HSTR fgethelp[] = "get files using a localfile as a source of names";
HSTR mkdirhelp[] = "make directory on the remote machine";
HSTR mlshelp[] = "list contents of multiple remote directories";
HSTR mlsdhelp[] = "list contents of remote directory in a machine "
"parsable form";
HSTR mlsthelp[] = "list remote path in a machine parsable form";
HSTR modehelp[] = "set file transfer mode";
HSTR modtimehelp[] = "show last modification time of remote file";
HSTR mputhelp[] = "send multiple files";
HSTR newerhelp[] = "get file if remote file is newer than local file ";
HSTR nmaphelp[] = "set templates for default file name mapping";
HSTR ntranshelp[] = "set translation table for default file name mapping";
HSTR optshelp[] = "show or set options for remote commands";
HSTR pagehelp[] = "view a remote file through your pager";
HSTR passivehelp[] = "toggle use of passive transfer mode";
HSTR plshelp[] = "list contents of remote path through your pager";
HSTR pmlsdhelp[] = "list contents of remote directory in a machine "
"parsable form through your pager";
HSTR porthelp[] = "toggle use of PORT/LPRT cmd for each data connection";
HSTR preservehelp[] ="toggle preservation of modification time of "
"retrieved files";
HSTR progresshelp[] ="toggle transfer progress meter";
HSTR prompthelp[] = "force interactive prompting on multiple commands";
HSTR proxyhelp[] = "issue command on alternate connection";
HSTR pwdhelp[] = "print working directory on remote machine";
HSTR quithelp[] = "terminate ftp session and exit";
HSTR quotehelp[] = "send arbitrary ftp command";
HSTR ratehelp[] = "set transfer rate limit (in bytes/second)";
HSTR receivehelp[] = "receive file";
HSTR regethelp[] = "get file restarting at end of local file";
HSTR remotehelp[] = "get help from remote server";
HSTR renamehelp[] = "rename file";
HSTR resethelp[] = "clear queued command replies";
HSTR restarthelp[]= "restart file transfer at bytecount";
HSTR rmdirhelp[] = "remove directory on the remote machine";
HSTR rmtstatushelp[]="show status of remote machine";
HSTR runiquehelp[] = "toggle store unique for local files";
HSTR sendhelp[] = "send one file";
HSTR sethelp[] = "set or display options";
HSTR shellhelp[] = "escape to the shell";
HSTR sitehelp[] = "send site specific command to remote server\n"
"\t\tTry \"rhelp site\" or \"site help\" "
"for more information";
HSTR sizecmdhelp[] = "show size of remote file";
HSTR statushelp[] = "show current status";
HSTR structhelp[] = "set file transfer structure";
HSTR suniquehelp[] = "toggle store unique on remote machine";
HSTR systemhelp[] = "show remote system type";
HSTR tenexhelp[] = "set tenex file transfer type";
HSTR tracehelp[] = "toggle packet tracing";
HSTR typehelp[] = "set file transfer type";
HSTR umaskhelp[] = "get (set) umask on remote side";
HSTR unsethelp[] = "unset an option";
HSTR usagehelp[] = "show command usage";
HSTR userhelp[] = "send new user information";
HSTR verbosehelp[] = "toggle verbose mode";
HSTR xferbufhelp[] = "set socket send/receive buffer size";
#endif
HSTR empty[] = "";
#ifdef NO_HELP
#define H(x) empty
#else
#define H(x) x
#endif
#ifdef NO_EDITCOMPLETE
#define CMPL(x)
#define CMPL0
#else /* !NO_EDITCOMPLETE */
#define CMPL(x) #x,
#define CMPL0 empty,
#endif /* !NO_EDITCOMPLETE */
struct cmd cmdtab[] = {
{ "!", H(shellhelp), 0, 0, 0, CMPL0 shell },
{ "$", H(domachelp), 1, 0, 0, CMPL0 domacro },
{ "account", H(accounthelp), 0, 1, 1, CMPL0 account},
{ "append", H(appendhelp), 1, 1, 1, CMPL(lr) put },
{ "ascii", H(asciihelp), 0, 1, 1, CMPL0 setascii },
{ "bell", H(beephelp), 0, 0, 0, CMPL0 setbell },
{ "binary", H(binaryhelp), 0, 1, 1, CMPL0 setbinary },
{ "bye", H(quithelp), 0, 0, 0, CMPL0 quit },
{ "case", H(casehelp), 0, 0, 1, CMPL0 setcase },
{ "cd", H(cdhelp), 0, 1, 1, CMPL(r) cd },
{ "cdup", H(cduphelp), 0, 1, 1, CMPL0 cdup },
{ "chmod", H(chmodhelp), 0, 1, 1, CMPL(nr) do_chmod },
{ "close", H(disconhelp), 0, 1, 1, CMPL0 disconnect },
{ "cr", H(crhelp), 0, 0, 0, CMPL0 setcr },
{ "debug", H(debughelp), 0, 0, 0, CMPL0 setdebug },
{ "delete", H(deletehelp), 0, 1, 1, CMPL(r) delete },
{ "dir", H(lshelp), 1, 1, 1, CMPL(rl) ls },
{ "disconnect", H(disconhelp), 0, 1, 1, CMPL0 disconnect },
{ "edit", H(edithelp), 0, 0, 0, CMPL0 setedit },
{ "epsv", H(epsvhelp), 0, 0, 0, CMPL0 setepsv },
{ "epsv4", H(epsv4help), 0, 0, 0, CMPL0 setepsv4 },
{ "epsv6", H(epsv6help), 0, 0, 0, CMPL0 setepsv6 },
{ "exit", H(quithelp), 0, 0, 0, CMPL0 quit },
{ "features", H(feathelp), 0, 1, 1, CMPL0 feat },
{ "fget", H(fgethelp), 1, 1, 1, CMPL(l) fget },
{ "form", H(formhelp), 0, 1, 1, CMPL0 setform },
{ "ftp", H(connecthelp), 0, 0, 1, CMPL0 setpeer },
{ "gate", H(gatehelp), 0, 0, 0, CMPL0 setgate },
{ "get", H(receivehelp), 1, 1, 1, CMPL(rl) get },
{ "glob", H(globhelp), 0, 0, 0, CMPL0 setglob },
{ "hash", H(hashhelp), 0, 0, 0, CMPL0 sethash },
{ "help", H(helphelp), 0, 0, 1, CMPL(C) help },
{ "idle", H(idlehelp), 0, 1, 1, CMPL0 idlecmd },
{ "image", H(binaryhelp), 0, 1, 1, CMPL0 setbinary },
{ "lcd", H(lcdhelp), 0, 0, 0, CMPL(l) lcd },
{ "less", H(pagehelp), 1, 1, 1, CMPL(r) page },
{ "lpage", H(lpagehelp), 0, 0, 0, CMPL(l) lpage },
{ "lpwd", H(lpwdhelp), 0, 0, 0, CMPL0 lpwd },
{ "ls", H(lshelp), 1, 1, 1, CMPL(rl) ls },
{ "macdef", H(macdefhelp), 0, 0, 0, CMPL0 macdef },
{ "mdelete", H(mdeletehelp), 1, 1, 1, CMPL(R) mdelete },
{ "mdir", H(mlshelp), 1, 1, 1, CMPL(R) mls },
{ "mget", H(mgethelp), 1, 1, 1, CMPL(R) mget },
{ "mkdir", H(mkdirhelp), 0, 1, 1, CMPL(r) makedir },
{ "mls", H(mlshelp), 1, 1, 1, CMPL(R) mls },
{ "mlsd", H(mlsdhelp), 1, 1, 1, CMPL(r) ls },
{ "mlst", H(mlsthelp), 1, 1, 1, CMPL(r) mlst },
{ "mode", H(modehelp), 0, 1, 1, CMPL0 setftmode },
{ "modtime", H(modtimehelp), 0, 1, 1, CMPL(r) modtime },
{ "more", H(pagehelp), 1, 1, 1, CMPL(r) page },
{ "mput", H(mputhelp), 1, 1, 1, CMPL(L) mput },
{ "mreget", H(mregethelp), 1, 1, 1, CMPL(R) mget },
{ "msend", H(mputhelp), 1, 1, 1, CMPL(L) mput },
{ "newer", H(newerhelp), 1, 1, 1, CMPL(r) newer },
{ "nlist", H(lshelp), 1, 1, 1, CMPL(rl) ls },
{ "nmap", H(nmaphelp), 0, 0, 1, CMPL0 setnmap },
{ "ntrans", H(ntranshelp), 0, 0, 1, CMPL0 setntrans },
{ "open", H(connecthelp), 0, 0, 1, CMPL0 setpeer },
{ "page", H(pagehelp), 1, 1, 1, CMPL(r) page },
{ "passive", H(passivehelp), 0, 0, 0, CMPL0 setpassive },
{ "pdir", H(plshelp), 1, 1, 1, CMPL(r) ls },
{ "pls", H(plshelp), 1, 1, 1, CMPL(r) ls },
{ "pmlsd", H(pmlsdhelp), 1, 1, 1, CMPL(r) ls },
{ "preserve", H(preservehelp),0, 0, 0, CMPL0 setpreserve },
{ "progress", H(progresshelp),0, 0, 0, CMPL0 setprogress },
{ "prompt", H(prompthelp), 0, 0, 0, CMPL0 setprompt },
{ "proxy", H(proxyhelp), 0, 0, 1, CMPL(c) doproxy },
{ "put", H(sendhelp), 1, 1, 1, CMPL(lr) put },
{ "pwd", H(pwdhelp), 0, 1, 1, CMPL0 pwd },
{ "quit", H(quithelp), 0, 0, 0, CMPL0 quit },
{ "quote", H(quotehelp), 1, 1, 1, CMPL0 quote },
{ "rate", H(ratehelp), 0, 0, 0, CMPL0 setrate },
{ "rcvbuf", H(xferbufhelp), 0, 0, 0, CMPL0 setxferbuf },
{ "recv", H(receivehelp), 1, 1, 1, CMPL(rl) get },
{ "reget", H(regethelp), 1, 1, 1, CMPL(rl) reget },
{ "remopts", H(optshelp), 0, 1, 1, CMPL0 opts },
{ "rename", H(renamehelp), 0, 1, 1, CMPL(rr) renamefile },
{ "reset", H(resethelp), 0, 1, 1, CMPL0 reset },
{ "restart", H(restarthelp), 1, 1, 1, CMPL0 restart },
{ "rhelp", H(remotehelp), 0, 1, 1, CMPL0 rmthelp },
{ "rmdir", H(rmdirhelp), 0, 1, 1, CMPL(r) removedir },
{ "rstatus", H(rmtstatushelp),0, 1, 1, CMPL(r) rmtstatus },
{ "runique", H(runiquehelp), 0, 0, 1, CMPL0 setrunique },
{ "send", H(sendhelp), 1, 1, 1, CMPL(lr) put },
{ "sendport", H(porthelp), 0, 0, 0, CMPL0 setport },
{ "set", H(sethelp), 0, 0, 0, CMPL(o) setoption },
{ "site", H(sitehelp), 0, 1, 1, CMPL0 site },
{ "size", H(sizecmdhelp), 1, 1, 1, CMPL(r) sizecmd },
{ "sndbuf", H(xferbufhelp), 0, 0, 0, CMPL0 setxferbuf },
{ "status", H(statushelp), 0, 0, 1, CMPL0 status },
{ "struct", H(structhelp), 0, 1, 1, CMPL0 setstruct },
{ "sunique", H(suniquehelp), 0, 0, 1, CMPL0 setsunique },
{ "system", H(systemhelp), 0, 1, 1, CMPL0 syst },
{ "tenex", H(tenexhelp), 0, 1, 1, CMPL0 settenex },
{ "throttle", H(ratehelp), 0, 0, 0, CMPL0 setrate },
{ "trace", H(tracehelp), 0, 0, 0, CMPL0 settrace },
{ "type", H(typehelp), 0, 1, 1, CMPL0 settype },
{ "umask", H(umaskhelp), 0, 1, 1, CMPL0 do_umask },
{ "unset", H(unsethelp), 0, 0, 0, CMPL(o) unsetoption },
{ "usage", H(usagehelp), 0, 0, 1, CMPL(C) help },
{ "user", H(userhelp), 0, 1, 1, CMPL0 user },
{ "verbose", H(verbosehelp), 0, 0, 0, CMPL0 setverbose },
{ "xferbuf", H(xferbufhelp), 0, 0, 0, CMPL0 setxferbuf },
{ "?", H(helphelp), 0, 0, 1, CMPL(C) help },
{ NULL, NULL, 0, 0, 0, CMPL0 NULL },
};
struct option optiontab[] = {
{ "anonpass", NULL },
{ "ftp_proxy", NULL },
{ "http_proxy", NULL },
{ "https_proxy",NULL },
{ "no_proxy", NULL },
{ "pager", NULL },
{ "prompt", NULL },
{ "rprompt", NULL },
{ NULL, NULL },
};

432
usr.bin/ftp/complete.c Normal file
View file

@ -0,0 +1,432 @@
/* $NetBSD: complete.c,v 1.46 2009/04/12 10:18:52 lukem Exp $ */
/*-
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: complete.c,v 1.46 2009/04/12 10:18:52 lukem Exp $");
#endif /* not lint */
/*
* FTP user program - command and file completion routines
*/
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ftp_var.h"
#ifndef NO_EDITCOMPLETE
static int comparstr (const void *, const void *);
static unsigned char complete_ambiguous (char *, int, StringList *);
static unsigned char complete_command (char *, int);
static unsigned char complete_local (char *, int);
static unsigned char complete_option (char *, int);
static unsigned char complete_remote (char *, int);
static int
comparstr(const void *a, const void *b)
{
return (strcmp(*(const char * const *)a, *(const char * const *)b));
}
/*
* Determine if complete is ambiguous. If unique, insert.
* If no choices, error. If unambiguous prefix, insert that.
* Otherwise, list choices. words is assumed to be filtered
* to only contain possible choices.
* Args:
* word word which started the match
* list list by default
* words stringlist containing possible matches
* Returns a result as per el_set(EL_ADDFN, ...)
*/
static unsigned char
complete_ambiguous(char *word, int list, StringList *words)
{
char insertstr[MAXPATHLEN];
char *lastmatch, *p;
size_t i, j;
size_t matchlen, wordlen;
wordlen = strlen(word);
if (words->sl_cur == 0)
return (CC_ERROR); /* no choices available */
if (words->sl_cur == 1) { /* only once choice available */
p = words->sl_str[0] + wordlen;
if (*p == '\0') /* at end of word? */
return (CC_REFRESH);
ftpvis(insertstr, sizeof(insertstr), p, strlen(p));
if (el_insertstr(el, insertstr) == -1)
return (CC_ERROR);
else
return (CC_REFRESH);
}
if (!list) {
matchlen = 0;
lastmatch = words->sl_str[0];
matchlen = strlen(lastmatch);
for (i = 1 ; i < words->sl_cur ; i++) {
for (j = wordlen ; j < strlen(words->sl_str[i]); j++)
if (lastmatch[j] != words->sl_str[i][j])
break;
if (j < matchlen)
matchlen = j;
}
if (matchlen > wordlen) {
ftpvis(insertstr, sizeof(insertstr),
lastmatch + wordlen, matchlen - wordlen);
if (el_insertstr(el, insertstr) == -1)
return (CC_ERROR);
else
return (CC_REFRESH_BEEP);
}
}
putc('\n', ttyout);
qsort(words->sl_str, words->sl_cur, sizeof(char *), comparstr);
list_vertical(words);
return (CC_REDISPLAY);
}
/*
* Complete a command
*/
static unsigned char
complete_command(char *word, int list)
{
struct cmd *c;
StringList *words;
size_t wordlen;
unsigned char rv;
words = ftp_sl_init();
wordlen = strlen(word);
for (c = cmdtab; c->c_name != NULL; c++) {
if (wordlen > strlen(c->c_name))
continue;
if (strncmp(word, c->c_name, wordlen) == 0)
ftp_sl_add(words, ftp_strdup(c->c_name));
}
rv = complete_ambiguous(word, list, words);
if (rv == CC_REFRESH) {
if (el_insertstr(el, " ") == -1)
rv = CC_ERROR;
}
sl_free(words, 1);
return (rv);
}
/*
* Complete a local file
*/
static unsigned char
complete_local(char *word, int list)
{
StringList *words;
char dir[MAXPATHLEN];
char *file;
DIR *dd;
struct dirent *dp;
unsigned char rv;
size_t len;
if ((file = strrchr(word, '/')) == NULL) {
dir[0] = '.';
dir[1] = '\0';
file = word;
} else {
if (file == word) {
dir[0] = '/';
dir[1] = '\0';
} else
(void)strlcpy(dir, word, file - word + 1);
file++;
}
if (dir[0] == '~') {
char *p;
if ((p = globulize(dir)) == NULL)
return (CC_ERROR);
(void)strlcpy(dir, p, sizeof(dir));
free(p);
}
if ((dd = opendir(dir)) == NULL)
return (CC_ERROR);
words = ftp_sl_init();
len = strlen(file);
for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
#if defined(DIRENT_MISSING_D_NAMLEN)
if (len > strlen(dp->d_name))
continue;
#else
if (len > dp->d_namlen)
continue;
#endif
if (strncmp(file, dp->d_name, len) == 0) {
char *tcp;
tcp = ftp_strdup(dp->d_name);
ftp_sl_add(words, tcp);
}
}
closedir(dd);
rv = complete_ambiguous(file, list, words);
if (rv == CC_REFRESH) {
struct stat sb;
char path[MAXPATHLEN];
(void)strlcpy(path, dir, sizeof(path));
(void)strlcat(path, "/", sizeof(path));
(void)strlcat(path, words->sl_str[0], sizeof(path));
if (stat(path, &sb) >= 0) {
char suffix[2] = " ";
if (S_ISDIR(sb.st_mode))
suffix[0] = '/';
if (el_insertstr(el, suffix) == -1)
rv = CC_ERROR;
}
}
sl_free(words, 1);
return (rv);
}
/*
* Complete an option
*/
static unsigned char
complete_option(char *word, int list)
{
struct option *o;
StringList *words;
size_t wordlen;
unsigned char rv;
words = ftp_sl_init();
wordlen = strlen(word);
for (o = optiontab; o->name != NULL; o++) {
if (wordlen > strlen(o->name))
continue;
if (strncmp(word, o->name, wordlen) == 0)
ftp_sl_add(words, ftp_strdup(o->name));
}
rv = complete_ambiguous(word, list, words);
if (rv == CC_REFRESH) {
if (el_insertstr(el, " ") == -1)
rv = CC_ERROR;
}
sl_free(words, 1);
return (rv);
}
/*
* Complete a remote file
*/
static unsigned char
complete_remote(char *word, int list)
{
static StringList *dirlist;
static char lastdir[MAXPATHLEN];
StringList *words;
char dir[MAXPATHLEN];
char *file, *cp;
size_t i;
unsigned char rv;
char cmdbuf[MAX_C_NAME];
char *dummyargv[3] = { NULL, NULL, NULL };
(void)strlcpy(cmdbuf, "complete", sizeof(cmdbuf));
dummyargv[0] = cmdbuf;
dummyargv[1] = dir;
if ((file = strrchr(word, '/')) == NULL) {
dir[0] = '\0';
file = word;
} else {
cp = file;
while (*cp == '/' && cp > word)
cp--;
(void)strlcpy(dir, word, cp - word + 2);
file++;
}
if (dirchange || dirlist == NULL ||
strcmp(dir, lastdir) != 0) { /* dir not cached */
const char *emesg;
if (dirlist != NULL)
sl_free(dirlist, 1);
dirlist = ftp_sl_init();
mflag = 1;
emesg = NULL;
while ((cp = remglob(dummyargv, 0, &emesg)) != NULL) {
char *tcp;
if (!mflag)
continue;
if (*cp == '\0') {
mflag = 0;
continue;
}
tcp = strrchr(cp, '/');
if (tcp)
tcp++;
else
tcp = cp;
tcp = ftp_strdup(tcp);
ftp_sl_add(dirlist, tcp);
}
if (emesg != NULL) {
fprintf(ttyout, "\n%s\n", emesg);
return (CC_REDISPLAY);
}
(void)strlcpy(lastdir, dir, sizeof(lastdir));
dirchange = 0;
}
words = ftp_sl_init();
for (i = 0; i < dirlist->sl_cur; i++) {
cp = dirlist->sl_str[i];
if (strlen(file) > strlen(cp))
continue;
if (strncmp(file, cp, strlen(file)) == 0)
ftp_sl_add(words, cp);
}
rv = complete_ambiguous(file, list, words);
sl_free(words, 0);
return (rv);
}
/*
* Generic complete routine
*/
unsigned char
complete(EditLine *cel, int ch)
{
static char word[FTPBUFLEN];
static size_t lastc_argc, lastc_argo;
struct cmd *c;
const LineInfo *lf;
int dolist, cmpltype;
size_t celems, len;
lf = el_line(cel);
len = lf->lastchar - lf->buffer;
if (len >= sizeof(line))
return (CC_ERROR);
(void)strlcpy(line, lf->buffer, len + 1);
cursor_pos = line + (lf->cursor - lf->buffer);
lastc_argc = cursor_argc; /* remember last cursor pos */
lastc_argo = cursor_argo;
makeargv(); /* build argc/argv of current line */
if (cursor_argo >= sizeof(word))
return (CC_ERROR);
dolist = 0;
/* if cursor and word is same, list alternatives */
if (lastc_argc == cursor_argc && lastc_argo == cursor_argo
&& strncmp(word, margv[cursor_argc] ? margv[cursor_argc] : "",
cursor_argo) == 0)
dolist = 1;
else if (cursor_argc < (size_t)margc)
(void)strlcpy(word, margv[cursor_argc], cursor_argo + 1);
word[cursor_argo] = '\0';
if (cursor_argc == 0)
return (complete_command(word, dolist));
c = getcmd(margv[0]);
if (c == (struct cmd *)-1 || c == 0)
return (CC_ERROR);
celems = strlen(c->c_complete);
/* check for 'continuation' completes (which are uppercase) */
if ((cursor_argc > celems) && (celems > 0)
&& isupper((unsigned char) c->c_complete[celems-1]))
cursor_argc = celems;
if (cursor_argc > celems)
return (CC_ERROR);
cmpltype = c->c_complete[cursor_argc - 1];
switch (cmpltype) {
case 'c': /* command complete */
case 'C':
return (complete_command(word, dolist));
case 'l': /* local complete */
case 'L':
return (complete_local(word, dolist));
case 'n': /* no complete */
case 'N': /* no complete */
return (CC_ERROR);
case 'o': /* local complete */
case 'O':
return (complete_option(word, dolist));
case 'r': /* remote complete */
case 'R':
if (connected != -1) {
fputs("\nMust be logged in to complete.\n",
ttyout);
return (CC_REDISPLAY);
}
return (complete_remote(word, dolist));
default:
errx(1, "complete: unknown complete type `%c'",
cmpltype);
return (CC_ERROR);
}
/* NOTREACHED */
}
#endif /* !NO_EDITCOMPLETE */

145
usr.bin/ftp/domacro.c Normal file
View file

@ -0,0 +1,145 @@
/* $NetBSD: domacro.c,v 1.22 2009/04/12 10:18:52 lukem Exp $ */
/*
* Copyright (c) 1985, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)domacro.c 8.3 (Berkeley) 4/2/94";
#else
__RCSID("$NetBSD: domacro.c,v 1.22 2009/04/12 10:18:52 lukem Exp $");
#endif
#endif /* not lint */
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "ftp_var.h"
void
domacro(int argc, char *argv[])
{
int i, j, count = 2, loopflg = 0;
char *cp1, *cp2, line2[FTPBUFLEN];
struct cmd *c;
char cmdbuf[MAX_C_NAME];
if ((argc == 0 && argv != NULL) ||
(argc < 2 && !another(&argc, &argv, "macro name"))) {
UPRINTF("usage: %s macro_name [args]\n", argv[0]);
code = -1;
return;
}
for (i = 0; i < macnum; ++i) {
if (!strncmp(argv[1], macros[i].mac_name, 9))
break;
}
if (i == macnum) {
fprintf(ttyout, "'%s' macro not found.\n", argv[1]);
code = -1;
return;
}
(void)strlcpy(line2, line, sizeof(line2));
TOP:
cp1 = macros[i].mac_start;
while (cp1 != macros[i].mac_end) {
while (isspace((unsigned char)*cp1))
cp1++;
cp2 = line;
while (*cp1 != '\0') {
switch(*cp1) {
case '\\':
*cp2++ = *++cp1;
break;
case '$':
if (isdigit((unsigned char)*(cp1+1))) {
j = 0;
while (isdigit((unsigned char)*++cp1))
j = 10*j + *cp1 - '0';
cp1--;
if (argc - 2 >= j) {
(void)strlcpy(cp2, argv[j+1],
sizeof(line) - (cp2 - line));
cp2 += strlen(argv[j+1]);
}
break;
}
if (*(cp1+1) == 'i') {
loopflg = 1;
cp1++;
if (count < argc) {
(void)strlcpy(cp2, argv[count],
sizeof(line) - (cp2 - line));
cp2 += strlen(argv[count]);
}
break;
}
/* intentional drop through */
default:
*cp2++ = *cp1;
break;
}
if (*cp1 != '\0')
cp1++;
}
*cp2 = '\0';
makeargv();
c = getcmd(margv[0]);
if (c == (struct cmd *)-1) {
fputs("?Ambiguous command.\n", ttyout);
code = -1;
} else if (c == 0) {
fputs("?Invalid command.\n", ttyout);
code = -1;
} else if (c->c_conn && !connected) {
fputs("Not connected.\n", ttyout);
code = -1;
} else {
if (verbose) {
fputs(line, ttyout);
putc('\n', ttyout);
}
(void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
margv[0] = cmdbuf;
(*c->c_handler)(margc, margv);
if (bell && c->c_bell)
(void)putc('\007', ttyout);
(void)strlcpy(line, line2, sizeof(line));
makeargv();
argc = margc;
argv = margv;
}
if (cp1 != macros[i].mac_end)
cp1++;
}
if (loopflg && ++count < argc)
goto TOP;
}

248
usr.bin/ftp/extern.h Normal file
View file

@ -0,0 +1,248 @@
/* $NetBSD: extern.h,v 1.80 2012/07/04 06:09:37 is Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 1994 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.3 (Berkeley) 10/9/94
*/
/*
* Copyright (C) 1997 and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
struct sockaddr;
struct tm;
struct addrinfo;
void abort_remote(FILE *);
void account(int, char **);
void ai_unmapped(struct addrinfo *);
int another(int *, char ***, const char *);
int auto_fetch(int, char **);
int auto_put(int, char **, const char *);
void blkfree(char **);
void cd(int, char **);
void cdup(int, char **);
void changetype(int, int);
void cleanuppeer(void);
void cmdabort(int);
void cmdtimeout(int);
void cmdscanner(void);
int command(const char *, ...)
__attribute__((__format__(__printf__, 1, 2)));
#ifndef NO_EDITCOMPLETE
unsigned char complete(EditLine *, int);
void controlediting(void);
#endif /* !NO_EDITCOMPLETE */
void crankrate(int);
FILE *dataconn(const char *);
void delete(int, char **);
void disconnect(int, char **);
void do_chmod(int, char **);
void do_umask(int, char **);
void domacro(int, char **);
void doproxy(int, char **);
void feat(int, char **);
void fget(int, char **);
int fileindir(const char *, const char *);
int foregroundproc(void);
void formatbuf(char *, size_t, const char *);
void ftpvis(char *, size_t, const char *, size_t);
int ftp_login(const char *, const char *, const char *);
void get(int, char **);
struct cmd *getcmd(const char *);
int getit(int, char **, int, const char *);
int get_line(FILE *, char *, size_t, const char **);
struct option *getoption(const char *);
char *getoptionvalue(const char *);
void getremoteinfo(void);
int getreply(int);
char *globulize(const char *);
char *gunique(const char *);
void help(int, char **);
char *hookup(const char *, const char *);
void idlecmd(int, char **);
int initconn(void);
__dead void intr(int);
int isipv6addr(const char *);
void list_vertical(StringList *);
void lcd(int, char **);
void lostpeer(int);
void lpage(int, char **);
void lpwd(int, char **);
void ls(int, char **);
void macdef(int, char **);
void makeargv(void);
void makedir(int, char **);
void mdelete(int, char **);
void mget(int, char **);
void mls(int, char **);
void mlst(int, char **);
void modtime(int, char **);
void mput(int, char **);
const char *onoff(int);
void opts(int, char **);
void newer(int, char **);
void page(int, char **);
const char *parse_rfc2616time(struct tm *, const char *);
int parserate(int, char **, int);
char *prompt(void);
__dead void proxabort(int);
void proxtrans(const char *, const char *, const char *);
void psabort(int);
void pswitch(int);
void put(int, char **);
void pwd(int, char **);
void quit(int, char **);
void quote(int, char **);
void quote1(const char *, int, char **);
void recvrequest(const char *, const char *, const char *,
const char *, int, int);
void reget(int, char **);
char *remglob(char **, int, const char **);
time_t remotemodtime(const char *, int);
off_t remotesize(const char *, int);
void removedir(int, char **);
void renamefile(int, char **);
void reset(int, char **);
void restart(int, char **);
const char *rfc2822time(const struct tm *);
void rmthelp(int, char **);
void rmtstatus(int, char **);
char *rprompt(void);
int ruserpass(const char *, char **, char **, char **);
void sendrequest(const char *, const char *, const char *, int);
void setascii(int, char **);
void setbell(int, char **);
void setbinary(int, char **);
void setcase(int, char **);
void setcr(int, char **);
void setdebug(int, char **);
void setedit(int, char **);
void setepsv4(int, char **);
void setepsv6(int, char **);
void setepsv(int, char **);
void setform(int, char **);
void setftmode(int, char **);
void setgate(int, char **);
void setglob(int, char **);
void sethash(int, char **);
void setnmap(int, char **);
void setntrans(int, char **);
void setoption(int, char **);
void setpassive(int, char **);
void setpeer(int, char **);
void setport(int, char **);
void setpreserve(int, char **);
void setprogress(int, char **);
void setprompt(int, char **);
void setrate(int, char **);
void setrunique(int, char **);
void setstruct(int, char **);
void setsunique(int, char **);
void settenex(int, char **);
void settrace(int, char **);
void setttywidth(int);
void settype(int, char **);
void setupsockbufsize(int);
void setverbose(int, char **);
void setxferbuf(int, char **);
void set_option(const char *, const char *, int);
void shell(int, char **);
void site(int, char **);
void sizecmd(int, char **);
char *slurpstring(void);
void status(int, char **);
int strsuftoi(const char *);
void syst(int, char **);
int togglevar(int, char **, int *, const char *);
void unsetoption(int, char **);
void updatelocalcwd(void);
void updateremotecwd(void);
void user(int, char **);
int ftp_connect(int, const struct sockaddr *, socklen_t, int);
int ftp_listen(int, int);
int ftp_poll(struct pollfd *, int, int);
void *ftp_malloc(size_t);
StringList *ftp_sl_init(void);
void ftp_sl_add(StringList *, char *);
char *ftp_strdup(const char *);

1979
usr.bin/ftp/fetch.c Normal file

File diff suppressed because it is too large Load diff

2421
usr.bin/ftp/ftp.1 Normal file

File diff suppressed because it is too large Load diff

2178
usr.bin/ftp/ftp.c Normal file

File diff suppressed because it is too large Load diff

354
usr.bin/ftp/ftp_var.h Normal file
View file

@ -0,0 +1,354 @@
/* $NetBSD: ftp_var.h,v 1.82 2012/12/21 18:07:36 christos Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1985, 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ftp_var.h 8.4 (Berkeley) 10/9/94
*/
/*
* Copyright (C) 1997 and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* FTP global variables.
*/
#ifdef SMALL
#undef NO_EDITCOMPLETE
#define NO_EDITCOMPLETE
#undef NO_PROGRESS
#define NO_PROGRESS
#endif
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <setjmp.h>
#include <stringlist.h>
#ifndef NO_EDITCOMPLETE
#include <histedit.h>
#endif /* !NO_EDITCOMPLETE */
#include "extern.h"
#include "progressbar.h"
/*
* Format of command table.
*/
struct cmd {
const char *c_name; /* name of command */
const char *c_help; /* help string */
char c_bell; /* give bell when command completes */
char c_conn; /* must be connected to use command */
char c_proxy; /* proxy server may execute */
#ifndef NO_EDITCOMPLETE
const char *c_complete; /* context sensitive completion list */
#endif /* !NO_EDITCOMPLETE */
void (*c_handler)(int, char **); /* function to call */
};
#define MAX_C_NAME 12 /* maximum length of cmd.c_name */
/*
* Format of macro table
*/
struct macel {
char mac_name[9]; /* macro name */
char *mac_start; /* start of macro in macbuf */
char *mac_end; /* end of macro in macbuf */
};
/*
* Format of option table
*/
struct option {
const char *name;
char *value;
};
/*
* Indices to features[]; an array containing status of remote server
* features; -1 not known (FEAT failed), 0 absent, 1 present.
*/
enum {
FEAT_FEAT = 0, /* FEAT, OPTS */
FEAT_MDTM, /* MDTM */
FEAT_MLST, /* MLSD, MLST */
FEAT_REST_STREAM, /* RESTart STREAM */
FEAT_SIZE, /* SIZE */
FEAT_TVFS, /* TVFS (not used) */
FEAT_max
};
/*
* Global defines
*/
#define FTPBUFLEN MAXPATHLEN + 200
#define MAX_IN_PORT_T 0xffffU
#define HASHBYTES 1024 /* default mark for `hash' command */
#define DEFAULTINCR 1024 /* default increment for `rate' command */
#define FTP_PORT 21 /* default if ! getservbyname("ftp/tcp") */
#define HTTP_PORT 80 /* default if ! getservbyname("http/tcp") */
#define HTTPS_PORT 443 /* default if ! getservbyname("https/tcp") */
#ifndef GATE_PORT
#define GATE_PORT 21 /* default if ! getservbyname("ftpgate/tcp") */
#endif
#ifndef GATE_SERVER
#define GATE_SERVER "" /* default server */
#endif
#define DEFAULTPAGER "more" /* default pager if $PAGER isn't set */
#define DEFAULTPROMPT "ftp> " /* default prompt if `set prompt' is empty */
#define DEFAULTRPROMPT "" /* default rprompt if `set rprompt' is empty */
#define TMPFILE "ftpXXXXXXXXXX"
#ifndef GLOBAL
#define GLOBAL extern
#endif
/*
* Options and other state info.
*/
GLOBAL int trace; /* trace packets exchanged */
GLOBAL int hash; /* print # for each buffer transferred */
GLOBAL int mark; /* number of bytes between hashes */
GLOBAL int sendport; /* use PORT/LPRT cmd for each data connection */
GLOBAL int connected; /* 1 = connected to server, -1 = logged in */
GLOBAL int interactive; /* interactively prompt on m* cmds */
GLOBAL int confirmrest; /* confirm rest of current m* cmd */
GLOBAL int ftp_debug; /* debugging level */
GLOBAL int bell; /* ring bell on cmd completion */
GLOBAL int doglob; /* glob local file names */
GLOBAL int autologin; /* establish user account on connection */
GLOBAL int proxy; /* proxy server connection active */
GLOBAL int proxflag; /* proxy connection exists */
GLOBAL int gatemode; /* use gate-ftp */
GLOBAL const char *gateserver; /* server to use for gate-ftp */
GLOBAL int sunique; /* store files on server with unique name */
GLOBAL int runique; /* store local files with unique name */
GLOBAL int mcase; /* map upper to lower case for mget names */
GLOBAL int ntflag; /* use ntin ntout tables for name translation */
GLOBAL int mapflag; /* use mapin mapout templates on file names */
GLOBAL int preserve; /* preserve modification time on files */
GLOBAL int code; /* return/reply code for ftp command */
GLOBAL int crflag; /* if 1, strip car. rets. on ascii gets */
GLOBAL int passivemode; /* passive mode enabled */
GLOBAL int activefallback; /* fall back to active mode if passive fails */
GLOBAL char *altarg; /* argv[1] with no shell-like preprocessing */
GLOBAL char ntin[17]; /* input translation table */
GLOBAL char ntout[17]; /* output translation table */
GLOBAL char mapin[MAXPATHLEN]; /* input map template */
GLOBAL char mapout[MAXPATHLEN]; /* output map template */
GLOBAL char typename[32]; /* name of file transfer type */
GLOBAL int type; /* requested file transfer type */
GLOBAL int curtype; /* current file transfer type */
GLOBAL char structname[32]; /* name of file transfer structure */
GLOBAL int stru; /* file transfer structure */
GLOBAL char formname[32]; /* name of file transfer format */
GLOBAL int form; /* file transfer format */
GLOBAL char modename[32]; /* name of file transfer mode */
GLOBAL int mode; /* file transfer mode */
GLOBAL char bytename[32]; /* local byte size in ascii */
GLOBAL int bytesize; /* local byte size in binary */
GLOBAL int anonftp; /* automatic anonymous login */
GLOBAL int dirchange; /* remote directory changed by cd command */
GLOBAL int flushcache; /* set HTTP cache flush headers with request */
GLOBAL int rate_get; /* maximum get xfer rate */
GLOBAL int rate_get_incr; /* increment for get xfer rate */
GLOBAL int rate_put; /* maximum put xfer rate */
GLOBAL int rate_put_incr; /* increment for put xfer rate */
GLOBAL int retry_connect; /* seconds between retrying connection */
GLOBAL const char *tmpdir; /* temporary directory */
GLOBAL int epsv4; /* use EPSV/EPRT on IPv4 connections */
GLOBAL int epsv4bad; /* EPSV doesn't work on the current server */
GLOBAL int epsv6; /* use EPSV/EPRT on IPv6 connections */
GLOBAL int epsv6bad; /* EPSV doesn't work on the current server */
GLOBAL int editing; /* command line editing enabled */
GLOBAL int features[FEAT_max]; /* remote FEATures supported */
#ifndef NO_EDITCOMPLETE
GLOBAL EditLine *el; /* editline(3) status structure */
GLOBAL History *hist; /* editline(3) history structure */
GLOBAL char *cursor_pos; /* cursor position we're looking for */
GLOBAL size_t cursor_argc; /* location of cursor in margv */
GLOBAL size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */
#endif /* !NO_EDITCOMPLETE */
GLOBAL char *hostname; /* name of host connected to */
GLOBAL int unix_server; /* server is unix, can use binary for ascii */
GLOBAL int unix_proxy; /* proxy is unix, can use binary for ascii */
GLOBAL char localcwd[MAXPATHLEN]; /* local dir */
GLOBAL char remotecwd[MAXPATHLEN]; /* remote dir */
GLOBAL char *username; /* name of user logged in as. (dynamic) */
GLOBAL sa_family_t family; /* address family to use for connections */
GLOBAL const char *ftpport; /* port number to use for FTP connections */
GLOBAL const char *httpport; /* port number to use for HTTP connections */
#ifdef WITH_SSL
GLOBAL const char *httpsport; /* port number to use for HTTPS connections */
#endif
GLOBAL const char *gateport; /* port number to use for gateftp connections */
GLOBAL struct addrinfo *bindai; /* local address to bind as */
GLOBAL char *outfile; /* filename to output URLs to */
GLOBAL int restartautofetch; /* restart auto-fetch */
GLOBAL char line[FTPBUFLEN]; /* input line buffer */
GLOBAL char *stringbase; /* current scan point in line buffer */
GLOBAL char argbuf[FTPBUFLEN]; /* argument storage buffer */
GLOBAL char *argbase; /* current storage point in arg buffer */
GLOBAL StringList *marg_sl; /* stringlist containing margv */
GLOBAL int margc; /* count of arguments on input line */
#define margv (marg_sl->sl_str) /* args parsed from input line */
GLOBAL int cpend; /* flag: if != 0, then pending server reply */
GLOBAL int mflag; /* flag: if != 0, then active multi command */
GLOBAL int options; /* used during socket creation */
GLOBAL int sndbuf_size; /* socket send buffer size */
GLOBAL int rcvbuf_size; /* socket receive buffer size */
GLOBAL int macnum; /* number of defined macros */
GLOBAL struct macel macros[16];
GLOBAL char macbuf[4096];
GLOBAL char *localhome; /* local home directory */
GLOBAL char *localname; /* local user name */
GLOBAL char netrc[MAXPATHLEN]; /* path to .netrc file */
GLOBAL char reply_string[BUFSIZ]; /* first line of previous reply */
GLOBAL void (*reply_callback)(const char *);
/*
* function to call for each line in
* the server's reply except for the
* first (`xxx-') and last (`xxx ')
*/
GLOBAL volatile sig_atomic_t sigint_raised;
GLOBAL FILE *cin;
GLOBAL FILE *cout;
GLOBAL int data;
extern struct cmd cmdtab[];
extern struct option optiontab[];
#define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0'))
#define FREEPTR(x) if ((x) != NULL) { free(x); (x) = NULL; }
#ifdef BSD4_4
# define HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1
#endif
#ifdef NO_LONG_LONG
# define STRTOLL(x,y,z) strtol(x,y,z)
#else
# define STRTOLL(x,y,z) strtoll(x,y,z)
#endif
#ifdef NO_DEBUG
#define DPRINTF(...)
#define DWARN(...)
#else
#define DPRINTF(...) if (ftp_debug) (void)fprintf(ttyout, __VA_ARGS__)
#define DWARN(...) if (ftp_debug) warn(__VA_ARGS__)
#endif
#define STRorNULL(s) ((s) ? (s) : "<null>")
#ifdef NO_USAGE
void xusage(void);
#define UPRINTF(...) xusage()
#else
#define UPRINTF(...) (void)fprintf(ttyout, __VA_ARGS__)
#endif

1057
usr.bin/ftp/main.c Normal file

File diff suppressed because it is too large Load diff

472
usr.bin/ftp/progressbar.c Normal file
View file

@ -0,0 +1,472 @@
/* $NetBSD: progressbar.c,v 1.22 2012/06/27 22:07:36 riastradh Exp $ */
/*-
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: progressbar.c,v 1.22 2012/06/27 22:07:36 riastradh Exp $");
#endif /* not lint */
/*
* FTP User Program -- Misc support routines
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#include "progressbar.h"
#if !defined(NO_PROGRESS)
/*
* return non-zero if we're the current foreground process
*/
int
foregroundproc(void)
{
static pid_t pgrp = -1;
if (pgrp == -1)
pgrp = getpgrp();
return (tcgetpgrp(fileno(ttyout)) == pgrp);
}
#endif /* !defined(NO_PROGRESS) */
static void updateprogressmeter(int);
/*
* SIGALRM handler to update the progress meter
*/
static void
updateprogressmeter(int dummy)
{
int oerrno = errno;
progressmeter(0);
errno = oerrno;
}
/*
* List of order of magnitude suffixes, per IEC 60027-2.
*/
static const char * const suffixes[] = {
"", /* 2^0 (byte) */
"KiB", /* 2^10 Kibibyte */
"MiB", /* 2^20 Mebibyte */
"GiB", /* 2^30 Gibibyte */
"TiB", /* 2^40 Tebibyte */
"PiB", /* 2^50 Pebibyte */
"EiB", /* 2^60 Exbibyte */
#if 0
/* The following are not necessary for signed 64-bit off_t */
"ZiB", /* 2^70 Zebibyte */
"YiB", /* 2^80 Yobibyte */
#endif
};
#define NSUFFIXES (int)(sizeof(suffixes) / sizeof(suffixes[0]))
/*
* Display a transfer progress bar if progress is non-zero.
* SIGALRM is hijacked for use by this function.
* - Before the transfer, set filesize to size of file (or -1 if unknown),
* and call with flag = -1. This starts the once per second timer,
* and a call to updateprogressmeter() upon SIGALRM.
* - During the transfer, updateprogressmeter will call progressmeter
* with flag = 0
* - After the transfer, call with flag = 1
*/
static struct timeval start;
static struct timeval lastupdate;
#define BUFLEFT (sizeof(buf) - len)
void
progressmeter(int flag)
{
static off_t lastsize;
off_t cursize;
struct timeval now, wait;
#ifndef NO_PROGRESS
struct timeval td;
off_t abbrevsize, bytespersec;
double elapsed;
int ratio, i, remaining, barlength;
/*
* Work variables for progress bar.
*
* XXX: if the format of the progress bar changes
* (especially the number of characters in the
* `static' portion of it), be sure to update
* these appropriately.
*/
#endif
size_t len;
char buf[256]; /* workspace for progress bar */
#ifndef NO_PROGRESS
#define BAROVERHEAD 45 /* non `*' portion of progress bar */
/*
* stars should contain at least
* sizeof(buf) - BAROVERHEAD entries
*/
static const char stars[] =
"*****************************************************************************"
"*****************************************************************************"
"*****************************************************************************";
#endif
if (flag == -1) {
(void)gettimeofday(&start, NULL);
lastupdate = start;
lastsize = restart_point;
}
(void)gettimeofday(&now, NULL);
cursize = bytes + restart_point;
timersub(&now, &lastupdate, &wait);
if (cursize > lastsize) {
lastupdate = now;
lastsize = cursize;
wait.tv_sec = 0;
} else {
#ifndef STANDALONE_PROGRESS
if (quit_time > 0 && wait.tv_sec > quit_time) {
len = snprintf(buf, sizeof(buf), "\r\n%s: "
"transfer aborted because stalled for %lu sec.\r\n",
getprogname(), (unsigned long)wait.tv_sec);
(void)write(fileno(ttyout), buf, len);
alarmtimer(0);
(void)xsignal(SIGALRM, SIG_DFL);
siglongjmp(toplevel, 1);
}
#endif /* !STANDALONE_PROGRESS */
}
/*
* Always set the handler even if we are not the foreground process.
*/
#ifdef STANDALONE_PROGRESS
if (progress) {
#else
if (quit_time > 0 || progress) {
#endif /* !STANDALONE_PROGRESS */
if (flag == -1) {
(void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
alarmtimer(1); /* set alarm timer for 1 Hz */
} else if (flag == 1) {
alarmtimer(0);
(void)xsignal(SIGALRM, SIG_DFL);
}
}
#ifndef NO_PROGRESS
if (!progress)
return;
len = 0;
/*
* print progress bar only if we are foreground process.
*/
if (! foregroundproc())
return;
len += snprintf(buf + len, BUFLEFT, "\r");
if (prefix)
len += snprintf(buf + len, BUFLEFT, "%s", prefix);
if (filesize > 0) {
ratio = (int)((double)cursize * 100.0 / (double)filesize);
ratio = MAX(ratio, 0);
ratio = MIN(ratio, 100);
len += snprintf(buf + len, BUFLEFT, "%3d%% ", ratio);
/*
* calculate the length of the `*' bar, ensuring that
* the number of stars won't exceed the buffer size
*/
barlength = MIN((int)(sizeof(buf) - 1), ttywidth) - BAROVERHEAD;
if (prefix)
barlength -= (int)strlen(prefix);
if (barlength > 0) {
i = barlength * ratio / 100;
len += snprintf(buf + len, BUFLEFT,
"|%.*s%*s|", i, stars, (int)(barlength - i), "");
}
}
abbrevsize = cursize;
for (i = 0; abbrevsize >= 100000 && i < NSUFFIXES; i++)
abbrevsize >>= 10;
if (i == NSUFFIXES)
i--;
len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %-3s ",
(LLT)abbrevsize,
suffixes[i]);
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
bytespersec = 0;
if (bytes > 0) {
bytespersec = bytes;
if (elapsed > 0.0)
bytespersec /= elapsed;
}
for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
bytespersec >>= 10;
len += snprintf(buf + len, BUFLEFT,
" " LLFP("3") ".%02d %.2sB/s ",
(LLT)(bytespersec / 1024),
(int)((bytespersec % 1024) * 100 / 1024),
suffixes[i]);
if (filesize > 0) {
if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) {
len += snprintf(buf + len, BUFLEFT, " --:-- ETA");
} else if (wait.tv_sec >= STALLTIME) {
len += snprintf(buf + len, BUFLEFT, " - stalled -");
} else {
remaining = (int)
((filesize - restart_point) / (bytes / elapsed) -
elapsed);
if (remaining >= 100 * SECSPERHOUR)
len += snprintf(buf + len, BUFLEFT,
" --:-- ETA");
else {
i = remaining / SECSPERHOUR;
if (i)
len += snprintf(buf + len, BUFLEFT,
"%2d:", i);
else
len += snprintf(buf + len, BUFLEFT,
" ");
i = remaining % SECSPERHOUR;
len += snprintf(buf + len, BUFLEFT,
"%02d:%02d ETA", i / 60, i % 60);
}
}
}
if (flag == 1)
len += snprintf(buf + len, BUFLEFT, "\n");
(void)write(fileno(ttyout), buf, len);
#endif /* !NO_PROGRESS */
}
#ifndef STANDALONE_PROGRESS
/*
* Display transfer statistics.
* Requires start to be initialised by progressmeter(-1),
* direction to be defined by xfer routines, and filesize and bytes
* to be updated by xfer routines
* If siginfo is nonzero, an ETA is displayed, and the output goes to stderr
* instead of ttyout.
*/
void
ptransfer(int siginfo)
{
struct timeval now, td, wait;
double elapsed;
off_t bytespersec;
int remaining, hh, i;
size_t len;
char buf[256]; /* Work variable for transfer status. */
if (!verbose && !progress && !siginfo)
return;
(void)gettimeofday(&now, NULL);
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
bytespersec = 0;
if (bytes > 0) {
bytespersec = bytes;
if (elapsed > 0.0)
bytespersec /= elapsed;
}
len = 0;
len += snprintf(buf + len, BUFLEFT, LLF " byte%s %s in ",
(LLT)bytes, bytes == 1 ? "" : "s", direction);
remaining = (int)elapsed;
if (remaining > SECSPERDAY) {
int days;
days = remaining / SECSPERDAY;
remaining %= SECSPERDAY;
len += snprintf(buf + len, BUFLEFT,
"%d day%s ", days, days == 1 ? "" : "s");
}
hh = remaining / SECSPERHOUR;
remaining %= SECSPERHOUR;
if (hh)
len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
len += snprintf(buf + len, BUFLEFT,
"%02d:%02d ", remaining / 60, remaining % 60);
for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
bytespersec >>= 10;
if (i == NSUFFIXES)
i--;
len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %.2sB/s)",
(LLT)(bytespersec / 1024),
(int)((bytespersec % 1024) * 100 / 1024),
suffixes[i]);
if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0
&& bytes + restart_point <= filesize) {
remaining = (int)((filesize - restart_point) /
(bytes / elapsed) - elapsed);
hh = remaining / SECSPERHOUR;
remaining %= SECSPERHOUR;
len += snprintf(buf + len, BUFLEFT, " ETA: ");
if (hh)
len += snprintf(buf + len, BUFLEFT, "%2d:", hh);
len += snprintf(buf + len, BUFLEFT, "%02d:%02d",
remaining / 60, remaining % 60);
timersub(&now, &lastupdate, &wait);
if (wait.tv_sec >= STALLTIME)
len += snprintf(buf + len, BUFLEFT, " (stalled)");
}
len += snprintf(buf + len, BUFLEFT, "\n");
(void)write(siginfo ? STDERR_FILENO : fileno(ttyout), buf, len);
}
/*
* SIG{INFO,QUIT} handler to print transfer stats if a transfer is in progress
*/
void
psummary(int notused)
{
int oerrno = errno;
if (bytes > 0) {
if (fromatty)
write(fileno(ttyout), "\n", 1);
ptransfer(1);
}
errno = oerrno;
}
#endif /* !STANDALONE_PROGRESS */
/*
* Set the SIGALRM interval timer for wait seconds, 0 to disable.
*/
void
alarmtimer(int wait)
{
struct itimerval itv;
itv.it_value.tv_sec = wait;
itv.it_value.tv_usec = 0;
itv.it_interval = itv.it_value;
setitimer(ITIMER_REAL, &itv, NULL);
}
/*
* Install a POSIX signal handler, allowing the invoker to set whether
* the signal should be restartable or not
*/
sigfunc
xsignal_restart(int sig, sigfunc func, int restartable)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
#if defined(SA_RESTART) /* 4.4BSD, Posix(?), SVR4 */
act.sa_flags = restartable ? SA_RESTART : 0;
#elif defined(SA_INTERRUPT) /* SunOS 4.x */
act.sa_flags = restartable ? 0 : SA_INTERRUPT;
#else
#error "system must have SA_RESTART or SA_INTERRUPT"
#endif
if (sigaction(sig, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
/*
* Install a signal handler with the `restartable' flag set dependent upon
* which signal is being set. (This is a wrapper to xsignal_restart())
*/
sigfunc
xsignal(int sig, sigfunc func)
{
int restartable;
/*
* Some signals print output or change the state of the process.
* There should be restartable, so that reads and writes are
* not affected. Some signals should cause program flow to change;
* these signals should not be restartable, so that the system call
* will return with EINTR, and the program will go do something
* different. If the signal handler calls longjmp() or siglongjmp(),
* it doesn't matter if it's restartable.
*/
switch(sig) {
#ifdef SIGINFO
case SIGINFO:
#endif
case SIGQUIT:
case SIGUSR1:
case SIGUSR2:
case SIGWINCH:
restartable = 1;
break;
case SIGALRM:
case SIGINT:
case SIGPIPE:
restartable = 0;
break;
default:
/*
* This is unpleasant, but I don't know what would be better.
* Right now, this "can't happen"
*/
errx(1, "xsignal_restart: called with signal %d", sig);
}
return(xsignal_restart(sig, func, restartable));
}

92
usr.bin/ftp/progressbar.h Normal file
View file

@ -0,0 +1,92 @@
/* $NetBSD: progressbar.h,v 1.8 2009/04/12 10:18:52 lukem Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef STANDALONE_PROGRESS
#include <setjmp.h>
#endif /* !STANDALONE_PROGRESS */
#ifndef GLOBAL
#define GLOBAL extern
#endif
#define STALLTIME 5 /* # of seconds of no xfer before "stalling" */
typedef void (*sigfunc)(int);
GLOBAL FILE *ttyout; /* stdout, or stderr if retrieving to stdout */
GLOBAL int progress; /* display transfer progress bar */
GLOBAL int ttywidth; /* width of tty */
GLOBAL off_t bytes; /* current # of bytes read */
GLOBAL off_t filesize; /* size of file being transferred */
GLOBAL off_t restart_point; /* offset to restart transfer */
GLOBAL char *prefix; /* Text written left of progress bar */
#ifndef STANDALONE_PROGRESS
GLOBAL int fromatty; /* input is from a terminal */
GLOBAL int verbose; /* print messages coming back from server */
GLOBAL int quit_time; /* maximum time to wait if stalled */
GLOBAL const char *direction; /* direction transfer is occurring */
GLOBAL sigjmp_buf toplevel; /* non-local goto stuff for cmd scanner */
#endif /* !STANDALONE_PROGRESS */
int foregroundproc(void);
void alarmtimer(int);
void progressmeter(int);
sigfunc xsignal(int, sigfunc);
sigfunc xsignal_restart(int, sigfunc, int);
#ifndef STANDALONE_PROGRESS
void psummary(int);
void ptransfer(int);
#endif /* !STANDALONE_PROGRESS */
#ifdef NO_LONG_LONG
# define LLF "%ld"
# define LLFP(x) "%" x "ld"
# define LLT long
# define ULLF "%lu"
# define ULLFP(x) "%" x "lu"
# define ULLT unsigned long
#else
# define LLF "%lld"
# define LLFP(x) "%" x "lld"
# define LLT long long
# define ULLF "%llu"
# define ULLFP(x) "%" x "llu"
# define ULLT unsigned long long
#endif

318
usr.bin/ftp/ruserpass.c Normal file
View file

@ -0,0 +1,318 @@
/* $NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp $ */
/*
* Copyright (c) 1985, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95";
#else
__RCSID("$NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ftp_var.h"
static int token(void);
static FILE *cfile;
#define DEFAULT 1
#define LOGIN 2
#define PASSWD 3
#define ACCOUNT 4
#define MACDEF 5
#define ID 10
#define MACH 11
static char tokval[100];
static struct toktab {
const char *tokstr;
int tval;
} toktab[] = {
{ "default", DEFAULT },
{ "login", LOGIN },
{ "password", PASSWD },
{ "passwd", PASSWD },
{ "account", ACCOUNT },
{ "machine", MACH },
{ "macdef", MACDEF },
{ NULL, 0 }
};
int
ruserpass(const char *host, char **aname, char **apass, char **aacct)
{
char *tmp;
const char *mydomain;
char myname[MAXHOSTNAMELEN + 1];
int t, i, c, usedefault = 0;
struct stat stb;
if (netrc[0] == '\0')
return (0);
cfile = fopen(netrc, "r");
if (cfile == NULL) {
if (errno != ENOENT)
warn("Can't read `%s'", netrc);
return (0);
}
if (gethostname(myname, sizeof(myname)) < 0)
myname[0] = '\0';
myname[sizeof(myname) - 1] = '\0';
if ((mydomain = strchr(myname, '.')) == NULL)
mydomain = "";
next:
while ((t = token()) > 0) switch(t) {
case DEFAULT:
usedefault = 1;
/* FALL THROUGH */
case MACH:
if (!usedefault) {
if ((t = token()) == -1)
goto bad;
if (t != ID)
continue;
/*
* Allow match either for user's input host name
* or official hostname. Also allow match of
* incompletely-specified host in local domain.
*/
if (strcasecmp(host, tokval) == 0)
goto match;
if (strcasecmp(hostname, tokval) == 0)
goto match;
if ((tmp = strchr(hostname, '.')) != NULL &&
strcasecmp(tmp, mydomain) == 0 &&
strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
tokval[tmp - hostname] == '\0')
goto match;
if ((tmp = strchr(host, '.')) != NULL &&
strcasecmp(tmp, mydomain) == 0 &&
strncasecmp(host, tokval, tmp - host) == 0 &&
tokval[tmp - host] == '\0')
goto match;
continue;
}
match:
while ((t = token()) > 0 &&
t != MACH && t != DEFAULT) switch(t) {
case LOGIN:
if ((t = token()) == -1)
goto bad;
if (t) {
if (*aname == NULL)
*aname = ftp_strdup(tokval);
else {
if (strcmp(*aname, tokval))
goto next;
}
}
break;
case PASSWD:
if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
fstat(fileno(cfile), &stb) >= 0 &&
(stb.st_mode & 077) != 0) {
warnx("Error: .netrc file is readable by others");
warnx("Remove password or make file unreadable by others");
goto bad;
}
if ((t = token()) == -1)
goto bad;
if (t && *apass == NULL)
*apass = ftp_strdup(tokval);
break;
case ACCOUNT:
if (fstat(fileno(cfile), &stb) >= 0
&& (stb.st_mode & 077) != 0) {
warnx("Error: .netrc file is readable by others");
warnx("Remove account or make file unreadable by others");
goto bad;
}
if ((t = token()) == -1)
goto bad;
if (t && *aacct == NULL)
*aacct = ftp_strdup(tokval);
break;
case MACDEF:
if (proxy) {
(void)fclose(cfile);
return (0);
}
while ((c = getc(cfile)) != EOF)
if (c != ' ' && c != '\t')
break;
if (c == EOF || c == '\n') {
fputs("Missing macdef name argument.\n",
ttyout);
goto bad;
}
if (macnum == 16) {
fputs(
"Limit of 16 macros have already been defined.\n",
ttyout);
goto bad;
}
tmp = macros[macnum].mac_name;
*tmp++ = c;
for (i = 0; i < 8 && (c = getc(cfile)) != EOF &&
!isspace(c); ++i) {
*tmp++ = c;
}
if (c == EOF) {
fputs(
"Macro definition missing null line terminator.\n",
ttyout);
goto bad;
}
*tmp = '\0';
if (c != '\n') {
while ((c = getc(cfile)) != EOF && c != '\n');
}
if (c == EOF) {
fputs(
"Macro definition missing null line terminator.\n",
ttyout);
goto bad;
}
if (macnum == 0) {
macros[macnum].mac_start = macbuf;
}
else {
macros[macnum].mac_start =
macros[macnum-1].mac_end + 1;
}
tmp = macros[macnum].mac_start;
while (tmp != macbuf + 4096) {
if ((c = getc(cfile)) == EOF) {
fputs(
"Macro definition missing null line terminator.\n",
ttyout);
goto bad;
}
*tmp = c;
if (*tmp == '\n') {
if (tmp == macros[macnum].mac_start) {
macros[macnum++].mac_end = tmp;
break;
} else if (*(tmp - 1) == '\0') {
macros[macnum++].mac_end =
tmp - 1;
break;
}
*tmp = '\0';
}
tmp++;
}
if (tmp == macbuf + 4096) {
fputs("4K macro buffer exceeded.\n",
ttyout);
goto bad;
}
break;
default:
warnx("Unknown .netrc keyword `%s'", tokval);
break;
}
goto done;
}
done:
if (t == -1)
goto bad;
(void)fclose(cfile);
return (0);
bad:
(void)fclose(cfile);
return (-1);
}
static int
token(void)
{
char *cp;
int c;
struct toktab *t;
if (feof(cfile) || ferror(cfile))
return (0);
while ((c = getc(cfile)) != EOF &&
(c == '\n' || c == '\t' || c == ' ' || c == ','))
continue;
if (c == EOF)
return (0);
cp = tokval;
if (c == '"') {
while ((c = getc(cfile)) != EOF && c != '"') {
if (c == '\\')
if ((c = getc(cfile)) == EOF)
break;
*cp++ = c;
if (cp == tokval + sizeof(tokval)) {
warnx("Token in .netrc too long");
return (-1);
}
}
} else {
*cp++ = c;
while ((c = getc(cfile)) != EOF
&& c != '\n' && c != '\t' && c != ' ' && c != ',') {
if (c == '\\')
if ((c = getc(cfile)) == EOF)
break;
*cp++ = c;
if (cp == tokval + sizeof(tokval)) {
warnx("Token in .netrc too long");
return (-1);
}
}
}
*cp = 0;
if (tokval[0] == 0)
return (0);
for (t = toktab; t->tokstr; t++)
if (!strcmp(t->tokstr, tokval))
return (t->tval);
return (ID);
}

608
usr.bin/ftp/ssl.c Normal file
View file

@ -0,0 +1,608 @@
/* $NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
* Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $");
#endif
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/uio.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "ssl.h"
extern int quit_time, verbose, ftp_debug;
extern FILE *ttyout;
struct fetch_connect {
int sd; /* file/socket descriptor */
char *buf; /* buffer */
size_t bufsize; /* buffer size */
size_t bufpos; /* position of buffer */
size_t buflen; /* length of buffer contents */
struct { /* data cached after an
interrupted read */
char *buf;
size_t size;
size_t pos;
size_t len;
} cache;
int issock;
int iserr;
int iseof;
SSL *ssl; /* SSL handle */
};
/*
* Write a vector to a connection w/ timeout
* Note: can modify the iovec.
*/
static ssize_t
fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
{
struct timeval now, timeout, delta;
fd_set writefds;
ssize_t len, total;
int r;
if (quit_time > 0) {
FD_ZERO(&writefds);
gettimeofday(&timeout, NULL);
timeout.tv_sec += quit_time;
}
total = 0;
while (iovcnt > 0) {
while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) {
FD_SET(conn->sd, &writefds);
gettimeofday(&now, NULL);
delta.tv_sec = timeout.tv_sec - now.tv_sec;
delta.tv_usec = timeout.tv_usec - now.tv_usec;
if (delta.tv_usec < 0) {
delta.tv_usec += 1000000;
delta.tv_sec--;
}
if (delta.tv_sec < 0) {
errno = ETIMEDOUT;
return -1;
}
errno = 0;
r = select(conn->sd + 1, NULL, &writefds, NULL, &delta);
if (r == -1) {
if (errno == EINTR)
continue;
return -1;
}
}
errno = 0;
if (conn->ssl != NULL)
len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
else
len = writev(conn->sd, iov, iovcnt);
if (len == 0) {
/* we consider a short write a failure */
/* XXX perhaps we shouldn't in the SSL case */
errno = EPIPE;
return -1;
}
if (len < 0) {
if (errno == EINTR)
continue;
return -1;
}
total += len;
while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) {
len -= iov->iov_len;
iov++;
iovcnt--;
}
if (iovcnt > 0) {
iov->iov_len -= len;
iov->iov_base = (char *)iov->iov_base + len;
}
}
return total;
}
/*
* Write to a connection w/ timeout
*/
static int
fetch_write(struct fetch_connect *conn, const char *str, size_t len)
{
struct iovec iov[1];
iov[0].iov_base = (char *)__UNCONST(str);
iov[0].iov_len = len;
return fetch_writev(conn, iov, 1);
}
/*
* Send a formatted line; optionally echo to terminal
*/
int
fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
{
va_list ap;
size_t len;
char *msg;
int r;
va_start(ap, fmt);
len = vasprintf(&msg, fmt, ap);
va_end(ap);
if (msg == NULL) {
errno = ENOMEM;
return -1;
}
r = fetch_write(conn, msg, len);
free(msg);
return r;
}
int
fetch_fileno(struct fetch_connect *conn)
{
return conn->sd;
}
int
fetch_error(struct fetch_connect *conn)
{
return conn->iserr;
}
static void
fetch_clearerr(struct fetch_connect *conn)
{
conn->iserr = 0;
}
int
fetch_flush(struct fetch_connect *conn)
{
int v;
if (conn->issock) {
#ifdef TCP_NOPUSH
v = 0;
setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
#endif
v = 1;
setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
}
return 0;
}
/*ARGSUSED*/
struct fetch_connect *
fetch_open(const char *fname, const char *fmode)
{
struct fetch_connect *conn;
int fd;
fd = open(fname, O_RDONLY); /* XXX: fmode */
if (fd < 0)
return NULL;
if ((conn = calloc(1, sizeof(*conn))) == NULL) {
close(fd);
return NULL;
}
conn->sd = fd;
conn->issock = 0;
return conn;
}
/*ARGSUSED*/
struct fetch_connect *
fetch_fdopen(int sd, const char *fmode)
{
struct fetch_connect *conn;
#if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH)
int opt = 1;
#endif
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return NULL;
conn->sd = sd;
conn->issock = 1;
fcntl(sd, F_SETFD, FD_CLOEXEC);
#ifdef SO_NOSIGPIPE
setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
#endif
#ifdef TCP_NOPUSH
setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
#endif
return conn;
}
int
fetch_close(struct fetch_connect *conn)
{
int rv = 0;
if (conn != NULL) {
fetch_flush(conn);
SSL_free(conn->ssl);
rv = close(conn->sd);
if (rv < 0) {
errno = rv;
rv = EOF;
}
free(conn->cache.buf);
free(conn->buf);
free(conn);
}
return rv;
}
#define FETCH_READ_WAIT -2
#define FETCH_READ_ERROR -1
static ssize_t
fetch_ssl_read(SSL *ssl, void *buf, size_t len)
{
ssize_t rlen;
int ssl_err;
rlen = SSL_read(ssl, buf, len);
if (rlen < 0) {
ssl_err = SSL_get_error(ssl, rlen);
if (ssl_err == SSL_ERROR_WANT_READ ||
ssl_err == SSL_ERROR_WANT_WRITE) {
return FETCH_READ_WAIT;
}
ERR_print_errors_fp(ttyout);
return FETCH_READ_ERROR;
}
return rlen;
}
static ssize_t
fetch_nonssl_read(int sd, void *buf, size_t len)
{
ssize_t rlen;
rlen = read(sd, buf, len);
if (rlen < 0) {
if (errno == EAGAIN || errno == EINTR)
return FETCH_READ_WAIT;
return FETCH_READ_ERROR;
}
return rlen;
}
/*
* Cache some data that was read from a socket but cannot be immediately
* returned because of an interrupted system call.
*/
static int
fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
{
if (conn->cache.size < nbytes) {
char *tmp = realloc(conn->cache.buf, nbytes);
if (tmp == NULL)
return -1;
conn->cache.buf = tmp;
conn->cache.size = nbytes;
}
memcpy(conn->cache.buf, src, nbytes);
conn->cache.len = nbytes;
conn->cache.pos = 0;
return 0;
}
ssize_t
fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
{
struct timeval now, timeout, delta;
fd_set readfds;
ssize_t rlen, total;
size_t len;
char *start, *buf;
if (quit_time > 0) {
gettimeofday(&timeout, NULL);
timeout.tv_sec += quit_time;
}
total = 0;
start = buf = ptr;
len = size * nmemb;
if (conn->cache.len > 0) {
/*
* The last invocation of fetch_read was interrupted by a
* signal after some data had been read from the socket. Copy
* the cached data into the supplied buffer before trying to
* read from the socket again.
*/
total = (conn->cache.len < len) ? conn->cache.len : len;
memcpy(buf, conn->cache.buf, total);
conn->cache.len -= total;
conn->cache.pos += total;
len -= total;
buf += total;
}
while (len > 0) {
/*
* The socket is non-blocking. Instead of the canonical
* select() -> read(), we do the following:
*
* 1) call read() or SSL_read().
* 2) if an error occurred, return -1.
* 3) if we received data but we still expect more,
* update our counters and loop.
* 4) if read() or SSL_read() signaled EOF, return.
* 5) if we did not receive any data but we're not at EOF,
* call select().
*
* In the SSL case, this is necessary because if we
* receive a close notification, we have to call
* SSL_read() one additional time after we've read
* everything we received.
*
* In the non-SSL case, it may improve performance (very
* slightly) when reading small amounts of data.
*/
if (conn->ssl != NULL)
rlen = fetch_ssl_read(conn->ssl, buf, len);
else
rlen = fetch_nonssl_read(conn->sd, buf, len);
if (rlen == 0) {
break;
} else if (rlen > 0) {
len -= rlen;
buf += rlen;
total += rlen;
continue;
} else if (rlen == FETCH_READ_ERROR) {
if (errno == EINTR)
fetch_cache_data(conn, start, total);
return -1;
}
FD_ZERO(&readfds);
while (!FD_ISSET(conn->sd, &readfds)) {
FD_SET(conn->sd, &readfds);
if (quit_time > 0) {
gettimeofday(&now, NULL);
if (!timercmp(&timeout, &now, >)) {
errno = ETIMEDOUT;
return -1;
}
timersub(&timeout, &now, &delta);
}
errno = 0;
if (select(conn->sd + 1, &readfds, NULL, NULL,
quit_time > 0 ? &delta : NULL) < 0) {
if (errno == EINTR)
continue;
return -1;
}
}
}
return total;
}
#define MIN_BUF_SIZE 1024
/*
* Read a line of text from a connection w/ timeout
*/
char *
fetch_getln(char *str, int size, struct fetch_connect *conn)
{
size_t tmpsize;
ssize_t len;
char c;
if (conn->buf == NULL) {
if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
errno = ENOMEM;
conn->iserr = 1;
return NULL;
}
conn->bufsize = MIN_BUF_SIZE;
}
if (conn->iserr || conn->iseof)
return NULL;
if (conn->buflen - conn->bufpos > 0)
goto done;
conn->buf[0] = '\0';
conn->bufpos = 0;
conn->buflen = 0;
do {
len = fetch_read(&c, sizeof(c), 1, conn);
if (len == -1) {
conn->iserr = 1;
return NULL;
}
if (len == 0) {
conn->iseof = 1;
break;
}
conn->buf[conn->buflen++] = c;
if (conn->buflen == conn->bufsize) {
char *tmp = conn->buf;
tmpsize = conn->bufsize * 2 + 1;
if ((tmp = realloc(tmp, tmpsize)) == NULL) {
errno = ENOMEM;
conn->iserr = 1;
return NULL;
}
conn->buf = tmp;
conn->bufsize = tmpsize;
}
} while (c != '\n');
if (conn->buflen == 0)
return NULL;
done:
tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos));
memcpy(str, conn->buf + conn->bufpos, tmpsize);
str[tmpsize] = '\0';
conn->bufpos += tmpsize;
return str;
}
int
fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
const char **errormsg)
{
size_t len;
int rv;
if (fetch_getln(buf, buflen, conn) == NULL) {
if (conn->iseof) { /* EOF */
rv = -2;
if (errormsg)
*errormsg = "\nEOF received";
} else { /* error */
rv = -1;
if (errormsg)
*errormsg = "Error encountered";
}
fetch_clearerr(conn);
return rv;
}
len = strlen(buf);
if (buf[len - 1] == '\n') { /* clear any trailing newline */
buf[--len] = '\0';
} else if (len == buflen - 1) { /* line too long */
while (1) {
char c;
ssize_t rlen = fetch_read(&c, sizeof(c), 1, conn);
if (rlen <= 0 || c == '\n')
break;
}
if (errormsg)
*errormsg = "Input line is too long";
fetch_clearerr(conn);
return -3;
}
if (errormsg)
*errormsg = NULL;
return len;
}
void *
fetch_start_ssl(int sock)
{
SSL *ssl;
SSL_CTX *ctx;
int ret, ssl_err;
/* Init the SSL library and context */
if (!SSL_library_init()){
fprintf(ttyout, "SSL library init failed\n");
return NULL;
}
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
ssl = SSL_new(ctx);
if (ssl == NULL){
fprintf(ttyout, "SSL context creation failed\n");
SSL_CTX_free(ctx);
return NULL;
}
SSL_set_fd(ssl, sock);
while ((ret = SSL_connect(ssl)) == -1) {
ssl_err = SSL_get_error(ssl, ret);
if (ssl_err != SSL_ERROR_WANT_READ &&
ssl_err != SSL_ERROR_WANT_WRITE) {
ERR_print_errors_fp(ttyout);
SSL_free(ssl);
return NULL;
}
}
if (ftp_debug && verbose) {
X509 *cert;
X509_NAME *name;
char *str;
fprintf(ttyout, "SSL connection established using %s\n",
SSL_get_cipher(ssl));
cert = SSL_get_peer_certificate(ssl);
name = X509_get_subject_name(cert);
str = X509_NAME_oneline(name, 0, 0);
fprintf(ttyout, "Certificate subject: %s\n", str);
free(str);
name = X509_get_issuer_name(cert);
str = X509_NAME_oneline(name, 0, 0);
fprintf(ttyout, "Certificate issuer: %s\n", str);
free(str);
}
return ssl;
}
void
fetch_set_ssl(struct fetch_connect *conn, void *ssl)
{
conn->ssl = ssl;
}

62
usr.bin/ftp/ssl.h Normal file
View file

@ -0,0 +1,62 @@
/* $NetBSD: ssl.h,v 1.1 2012/12/21 18:07:36 christos Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WITH_SSL
#define FETCH struct fetch_connect
struct fetch_connect;
int fetch_printf(struct fetch_connect *, const char *fmt, ...);
int fetch_fileno(struct fetch_connect *);
int fetch_error(struct fetch_connect *);
int fetch_flush(struct fetch_connect *);
struct fetch_connect *fetch_open(const char *, const char *);
struct fetch_connect *fetch_fdopen(int, const char *);
int fetch_close(struct fetch_connect *);
ssize_t fetch_read(void *, size_t, size_t, struct fetch_connect *);
char *fetch_getln(char *, int, struct fetch_connect *);
int fetch_getline(struct fetch_connect *, char *, size_t, const char **);
void fetch_set_ssl(struct fetch_connect *, void *);
void *fetch_start_ssl(int);
#else /* !WITH_SSL */
#define FETCH FILE
#define fetch_printf fprintf
#define fetch_fileno fileno
#define fetch_error ferror
#define fetch_flush fflush
#define fetch_open fopen
#define fetch_fdopen fdopen
#define fetch_close fclose
#define fetch_read fread
#define fetch_getln fgets
#define fetch_getline get_line
#define fetch_set_ssl(a, b)
#endif /* !WITH_SSL */

1543
usr.bin/ftp/util.c Normal file

File diff suppressed because it is too large Load diff

38
usr.bin/ftp/version.h Normal file
View file

@ -0,0 +1,38 @@
/* $NetBSD: version.h,v 1.83 2013/02/06 16:37:20 christos Exp $ */
/*-
* Copyright (c) 1999-2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FTP_PRODUCT
#define FTP_PRODUCT "NetBSD-ftp"
#endif
#ifndef FTP_VERSION
#define FTP_VERSION "20121224"
#endif