pflag= 1;
}
+ /* Initialize current Time */
+ time(&now);
+
if (cflag) {
int fd1, fd2;
job->rtime= NEVER;
return;
}
+ tmptm= *localtime(&job->rtime);
if (tmptm.tm_hour != nexttm.tm_hour ||
tmptm.tm_min != nexttm.tm_min)
{
job->rtime= NEVER;
return;
}
+ tmptm= *localtime(&job->rtime);
if (tmptm.tm_hour != nexttm.tm_hour ||
tmptm.tm_min != nexttm.tm_min)
{
--- /dev/null
+# Makefile for ftpd
+#
+# 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
+# 2005-02-25 version 2.00
+
+CFLAGS= -O -D_MINIX -D_POSIX_SOURCE -m
+LDFLAGS=-i
+BINDIR= /usr/bin
+PROG= in.ftpd
+MANDIR= /usr/man/man8
+MANPAGE=ftpd.8
+
+OBJS= ftpd.o access.o file.o net.o
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS)
+ install -S 8kw $@
+
+clean:
+ rm -f $(PROG) $(OBJS)
+
+install: $(BINDIR)/$(PROG) $(BINDIR)/setup.anonftp $(BINDIR)/ftpdsh
+
+$(BINDIR)/$(PROG): $(PROG)
+ install -cs -o bin $? $@
+
+$(BINDIR)/setup.anonftp: setup.anonftp
+ install -c -o bin $? $@
+
+$(BINDIR)/ftpdsh: ftpdsh
+ install -c -o bin $? $@
+
+ftpd.o: ftpd.c ftpd.h access.h file.h net.h
+access.o: access.c ftpd.h access.h
+file.o: file.c ftpd.h access.h file.h net.h
+net.o: net.c ftpd.h net.h
+
+installman: $(MANDIR)/$(MANPAGE)
+ cp $(MANPAGE) $(MANDIR)
+ echo "You may need to run makewhatis to update man page index"
--- /dev/null
+ftpd200 --- FTP server program for Minix 2.0
+written by Michael Temari <Michael@TemWare.Com> release 2.00 2005-02-25
+
+Full download: <a href="/pub/contrib/ftpd200.tar.Z">ftpd200.tar.Z</a>
+
+Ftpd is the File Transfer Protocol (FTP) server.
+
+Important: Release 2.00 incorporates an improved mechanism to restrict
+execution of commands on the server. This is done through use of a
+shell script, ftpdsh. Any earlier ftpd version in use on a system
+accessible from the Internet should be upgraded at least to version 1.01,
+version 2.00 is preferable.
+
+Installation: unpack the tarball in /usr/local/src or another directory
+of your choice:
+zcat < ftpd200.tar.Z | tar xvfp -
+
+The ftpd200 directory will be created. Read the Makefile to see how
+the program is compiled and installed:
+
+make (or make ftpd) -- compiles the binary
+make install -- installs /usr/bin/in.ftpd, and ftpdsh. Also installs
+ setup.anonftp script.
+make installman -- installs new ftpd.8 man page in /usr/local/man/man8
+
+The shell script setup.anonftp sets up and verifies configuration for
+anonymous ftp. If you provide anonymous ftp you are letting anyone in
+the whole wide world execute a program on your computer. You want to
+make sure it's set up correctly so outsiders can't mess with things
+they shouldn't.
+
+This file is included as README in the source directory. For more
+notes on compiling and installing, also please see the file README2.
+
+notes updated by asw 2005-02-25
--- /dev/null
+README2: additional notes on compiling and installing ftpd.
+
+Note that the Makefile install options will replace files in /usr/bin
+and /usr/man that were installed with the Minix distribution. If you
+are not sure you want to do this you can either rename the original
+in.ftpd binary, the anonftp.* scripts, and the ftpd.8 man page to
+prevent them from being replaced, or you can edit the Makefile to
+change the directory values:
+ BINDIR= /usr/local/bin
+ MANDIR= /usr/local/man/man8
+ASW's practice is to rename binaries with a suffix that indicates the
+original distribution from which they were obtained, i.e., in.ftpd.203
+for the version distributed with Minix 2.0.3, or with a date code or a
+version number.
+
+If you are sure you want to replace the original ftpd provided with your
+distribution you may want to copy the contents of the unpacked tarball
+to the main directory tree, in this case /usr/src/commands/ftpd, so that
+a new version will be compiled if you do a general recompilation of all
+commands using "make all" or "make compile" in /usr/src. ASW's practice
+is generally to make a directory in /usr/local/src for new versions of
+major programs.
+Also note that if you create a new man page where one did not exist
+previously you will need to run makewhatis to rebuild the whatis
+database, i.e.:
+ makewhatis /usr/man
+or
+ makewhatis /usr/local/man
+
+Important: the scripts for setting up and maintaining an anonymous ftp
+installation haven't been checked for a long time, I would appreciate
+comments.
+
+ASW 2005-02-06
--- /dev/null
+/* access.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftpd.
+ *
+ * This file handles:
+ *
+ * USER PASS QUIT
+ *
+ *
+ * 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+
+#include "ftpd.h"
+#include "access.h"
+
+_PROTOTYPE(static int AreWeIn, (char *name, struct passwd *pwd));
+
+static char *msg530 = "530 Not logged in.\r\n";
+
+/* Returns -1 = not logged in, 0 = loggedin */
+int ChkLoggedIn()
+{
+ if(!loggedin) {
+ printf(msg530);
+ return(-1);
+ } else
+ return(0);
+}
+
+/* what a USER! */
+int doUSER(buff)
+char *buff;
+{
+ loggedin = 0;
+ gotuser = 0;
+ strncpy(username, buff, sizeof(username));
+ username[sizeof(username)-1] = '\0';
+
+ if(*username == '\0') {
+ printf("501 Bad user name.\r\n");
+ return(GOOD);
+ }
+
+ gotuser = 1;
+
+ printf("331 Password required for %s.\r\n", username);
+
+ return(GOOD);
+}
+
+/* secret, secret, secret */
+int doPASS(buff)
+char *buff;
+{
+char *name;
+struct passwd *pwd;
+int bad=0;
+
+ name = username;
+
+ if(!strcmp(name, "anonymous"))
+ name = "ftp";
+
+ if(!gotuser || ((pwd = getpwnam(name)) == (struct passwd *)0))
+ bad = 1;
+ else
+ if(strcmp(name, "ftp")) {
+ if(!strcmp(pwd->pw_passwd, crypt("", pwd->pw_passwd)))
+ bad = 1;
+ if(strcmp(pwd->pw_passwd, crypt(buff, pwd->pw_passwd)))
+ bad = 1;
+ } else {
+ strncpy(anonpass, buff, sizeof(anonpass));
+ anonpass[sizeof(anonpass)-1] = '\0';
+ }
+
+ if(bad) {
+ logit("LOGIN", "FAIL");
+ printf(msg530);
+ return(GOOD);
+ }
+
+ return(AreWeIn(name, pwd));
+}
+
+/* bye, bye don't let the door hit you in the butt on the way out */
+int doQUIT(buff)
+char *buff;
+{
+ printf("221 Service closing, don't be a stranger.\r\n");
+
+ return(BAD);
+}
+
+/* see if this user is okay */
+static int AreWeIn(name, pwd)
+char *name;
+struct passwd *pwd;
+{
+ if(!strcmp(name, "ftp")) {
+ if(chroot(pwd->pw_dir)) {
+ logit("LOGIN", "FAIL");
+ printf("530 Not logged in, could not chroot.\r\n");
+ return(GOOD);
+ }
+ strncpy(newroot, pwd->pw_dir, sizeof(newroot));
+ newroot[sizeof(newroot)-1] = '\0';
+ anonymous = 1;
+ strcpy(pwd->pw_dir, "/");
+ }
+
+ if(setgid(pwd->pw_gid) || setuid(pwd->pw_uid) || chdir(pwd->pw_dir)) {
+ logit("LOGIN", "FAIL");
+ printf(msg530);
+ anonymous = 0;
+ } else {
+ logit("LOGIN", "PASS");
+ showmsg("230", (char *)NULL);
+ printf("230 User %s logged in, directory %s.\r\n",
+ username, pwd->pw_dir);
+ loggedin = 1;
+ }
+
+ return(GOOD);
+}
--- /dev/null
+/* ftpd.h
+ *
+ * This file is part of ftpd.
+ *
+ *
+ * 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(int ChkLoggedIn, (void));
+_PROTOTYPE(int doUSER, (char *buff));
+_PROTOTYPE(int doPASS, (char *buff));
+_PROTOTYPE(int doQUIT, (char *buff));
--- /dev/null
+/* file.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftpd.
+ *
+ * This file handles:
+ *
+ * ALLO APPE CDUP CWD DELE LIST MDTM MODE MKD NLST PWD REST RETR
+ * RMD RNFR RNTO SITE SIZE STAT STOR STOU STRU SYST TYPE
+ *
+ * 01/25/96 Initial Release Michael Temari
+ * 03/09/00 Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <net/hton.h>
+#include <net/gen/in.h>
+#include <net/gen/inet.h>
+#include <net/gen/tcp.h>
+
+#include "ftpd.h"
+#include "access.h"
+#include "file.h"
+#include "net.h"
+
+_PROTOTYPE(static int fdxcmd, (int cmd, char *arg));
+_PROTOTYPE(static int endfdxcmd, (int fd));
+_PROTOTYPE(static int asciisize, (char *filename, unsigned long *filesize));
+_PROTOTYPE(static int cnvtfile, (char *name, char **name2));
+_PROTOTYPE(static int procfile, (char *name));
+_PROTOTYPE(static unsigned long fsize, (char *fname));
+_PROTOTYPE(static int sendfile, (char *name, int xmode));
+_PROTOTYPE(static int recvfile, (char *name, int xmode));
+_PROTOTYPE(static char *uniqname, (void));
+_PROTOTYPE(static int docrc, (char *buff, int xmode));
+_PROTOTYPE(static int dofdet, (char *buff));
+_PROTOTYPE(static char *path, (char *fname));
+
+#define SEND_FILE 0
+#define SEND_NLST 1
+#define SEND_LIST 2
+
+#define RECV_FILE 0
+#define RECV_APND 1
+#define RECV_UNIQ 2
+
+#define CNVT_ERROR 0
+#define CNVT_NONE 1
+#define CNVT_TAR 2
+#define CNVT_TAR_Z 3
+#define CNVT_COMP 4
+#define CNVT_TAR_GZ 5
+#define CNVT_GZIP 6
+#define CNVT_UNCOMP 7
+
+
+#define PROG_FTPDSH "ftpdsh"
+#define CMD_NLST 1
+#define CMD_LIST 2
+#define CMD_CRC 3
+
+static char *msg550 = "550 %s %s.\r\n";
+
+static unsigned long file_restart = 0;
+
+static char rnfr[256];
+static char buffer[8192];
+static char bufout[8192];
+
+static cmdpid = -1;
+
+/* allocate, we don't need no stink'n allocate */
+int doALLO(buff)
+char *buff;
+{
+ printf("202 ALLO command not needed at this site.\r\n");
+
+ return(GOOD);
+}
+
+/* append to a file if it exists */
+int doAPPE(buff)
+char *buff;
+{
+ return(recvfile(buff, RECV_APND));
+}
+
+/* change to parent directory */
+int doCDUP(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ return(doCWD(".."));
+}
+
+/* change directory */
+int doCWD(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(chdir(buff))
+ printf(msg550, buff, strerror(errno));
+ else {
+ showmsg("250", ".ftpd_msg");
+ printf("250 %s command okay.\r\n", line);
+ }
+
+ return(GOOD);
+}
+
+/* remove a file */
+int doDELE(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(anonymous) {
+ printf("550 Command not allowed for anonymous user\r\n");
+ return(GOOD);
+ }
+
+ if(unlink(buff))
+ printf(msg550, buff, strerror(errno));
+ else {
+ printf("250 File \"%s\" deleted.\r\n", buff);
+ logit("DELE", path(buff));
+ }
+
+ return(GOOD);
+}
+
+/* directory listing */
+int doLIST(buff)
+char *buff;
+{
+ file_restart = 0;
+
+ return(sendfile(buff, SEND_LIST));
+}
+
+/* file modification time, btw when will this be put into an RFC */
+int doMDTM(buff)
+char *buff;
+{
+struct stat st;
+struct tm *t;
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(stat(buff, &st)) {
+ printf(msg550, buff, strerror(errno));
+ return(GOOD);
+ }
+
+ if((st.st_mode & S_IFMT) != S_IFREG) {
+ printf("550 Not a regular file.\r\n");
+ return(GOOD);
+ }
+
+ t = gmtime(&st.st_mtime);
+
+ printf("215 %04d%02d%02d%02d%02d%02d\r\n",
+ t->tm_year+1900, t->tm_mon+1, t->tm_mday,
+ t->tm_hour, t->tm_min, t->tm_sec);
+
+ return(GOOD);
+}
+
+/* mode */
+int doMODE(buff)
+char *buff;
+{
+ switch(*buff) {
+ case 'b':
+ case 'B':
+ printf("200 Mode set to %c.\r\n", *buff);
+ mode = MODE_B;
+ break;
+ case 's':
+ case 'S':
+ printf("200 Mode set to %c.\r\n", *buff);
+ mode = MODE_S;
+ break;
+ default:
+ printf("501 Unknown mode %c.\r\n", *buff);
+ }
+
+ return(GOOD);
+}
+
+/* make a directory */
+int doMKD(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(anonymous) {
+ printf("550 Command not allowed for anonymous user\r\n");
+ return(GOOD);
+ }
+
+ if(mkdir(buff, 0777))
+ printf(msg550, buff, strerror(errno));
+ else {
+ printf("257 \"%s\" directory created.\r\n", buff);
+ logit("MKD ", path(buff));
+ }
+
+ return(GOOD);
+}
+
+/* name listing */
+int doNLST(buff)
+char *buff;
+{
+ file_restart = 0;
+
+ return(sendfile(buff, SEND_NLST));
+}
+
+/* where are we */
+int doPWD(buff)
+char *buff;
+{
+char dir[128];
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(getcwd(dir, sizeof(dir)) == (char *)NULL)
+ printf(msg550, buff, strerror(errno));
+ else
+ printf("257 \"%s\" is current directory.\r\n", dir);
+
+ return(GOOD);
+}
+
+/* restart command */
+int doREST(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ file_restart = atol(buff);
+
+ printf("350 Next file transfer will restart at %lu.\r\n", file_restart);
+
+ return(GOOD);
+}
+
+/* they want a file */
+int doRETR(buff)
+char *buff;
+{
+ return(sendfile(buff, SEND_FILE));
+}
+
+/* remove a directory */
+int doRMD(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(anonymous) {
+ printf("550 Command not allowed for anonymous user\r\n");
+ return(GOOD);
+ }
+
+ if(rmdir(buff))
+ printf(msg550, buff, strerror(errno));
+ else {
+ printf("250 Directory \"%s\" deleted.\r\n", buff);
+ logit("RMD ", path(buff));
+ }
+
+ return(GOOD);
+}
+
+/* rename from */
+int doRNFR(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(anonymous) {
+ printf("550 Command not allowed for anonymous user\r\n");
+ return(GOOD);
+ }
+
+ strncpy(rnfr, buff, sizeof(rnfr));
+ rnfr[sizeof(rnfr)-1] = '\0';
+
+ printf("350 Got RNFR waiting for RNTO.\r\n");
+
+ return(GOOD);
+}
+
+/* rename to */
+int doRNTO(buff)
+char *buff;
+{
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(anonymous) {
+ printf("550 Command not allowed for anonymous user\r\n");
+ return(GOOD);
+ }
+
+ if(rnfr[0] == '\0') {
+ printf("550 Rename failed.\r\n");
+ return(GOOD);
+ }
+
+ if(rename(rnfr, buff) < 0)
+ printf("550 Rename failed. Error %s\r\n", strerror(errno));
+ else {
+ printf("250 Renamed %s to %s.\r\n", rnfr, buff);
+ logit("RNFR", path(rnfr));
+ logit("RNTO", path(buff));
+ }
+
+ rnfr[0] = '\0';
+
+ return(GOOD);
+}
+
+/* xmode = 0 for multiline crc, xmode <> 0 for single file single line crc */
+static int docrc(buff, xmode)
+char *buff;
+int xmode;
+{
+unsigned short cs;
+long fs;
+int fd;
+int s;
+char *p;
+
+ if((fd = fdxcmd(CMD_CRC, buff)) < 0) {
+ printf("501 Could not obtain CRC.\r\n");
+ return(GOOD);
+ }
+
+ if(xmode == 0)
+ printf("202-SITE CRC \"%s\"\r\n", buff);
+
+ while(1) {
+ p = buffer;
+ while(1) {
+ if((s = read(fd, p, 1)) != 1) {
+ if(xmode == 0)
+ printf("202 SITE CRC DONE.\r\n");
+ else
+ printf("501 Could not obtain CRC.\r\n");
+ endfdxcmd(fd);
+ return(GOOD);
+ }
+ if(*p == '\n') {
+ *p++ = '\r';
+ *p++ = '\n';
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+ if(xmode != 0)
+ break;
+ printf(" %s", buffer);
+ }
+
+ cs = atoi(buffer);
+
+ fs = atol(buffer+6);
+
+ printf("202 CRC %05u %ld.\r\n", cs, fs);
+
+ endfdxcmd(fd);
+
+ return(GOOD);
+}
+
+/* site specific */
+int doSITE(buff)
+char *buff;
+{
+char *args;
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+
+ strncpy(line, buff, sizeof(line));
+ line[sizeof(line)-1] = '\0';
+
+ cvtline(&args);
+
+ if(!strcmp(line, "CRC") || !strcmp(line, "CCRC"))
+ return(docrc(args, strcmp(line, "CRC")));
+
+ if(!strcmp(line, "FDET"))
+ return(dofdet(args));
+
+ printf("501 Unknown SITE command %s.\r\n", line);
+
+ return(GOOD);
+}
+
+static unsigned long fsize(fname)
+char *fname;
+{
+struct stat st;
+unsigned long fs = 0L;
+
+ if(stat(fname, &st))
+ return(fs);
+
+ if((st.st_mode & S_IFMT) != S_IFREG)
+ return(fs);
+
+ if(type == TYPE_A)
+ return(fs);
+
+ fs = st.st_size;
+
+ return(fs);
+}
+
+/* file size, btw when will this be put into an RFC */
+int doSIZE(buff)
+char *buff;
+{
+struct stat st;
+unsigned long filesize;
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(stat(buff, &st)) {
+ printf(msg550, buff, strerror(errno));
+ return(GOOD);
+ }
+
+ if((st.st_mode & S_IFMT) != S_IFREG) {
+ printf("550 Not a regular file.\r\n");
+ return(GOOD);
+ }
+
+ filesize = st.st_size;
+
+ if(type == TYPE_A)
+ if(asciisize(buff, &filesize))
+ return(GOOD);
+
+ printf("215 %lu\r\n", filesize);
+
+ return(GOOD);
+}
+
+/* server status, or file status */
+int doSTAT(buff)
+char *buff;
+{
+time_t now;
+struct tm *tm;
+int fd;
+int s;
+
+ if(!*buff) {
+ (void) time(&now);
+ tm = localtime(&now);
+ printf("211-%s(%s:%u) FTP server status:\r\n",
+ myhostname, inet_ntoa(myipaddr), ntohs(myport));
+ printf(" Version %s ", FtpdVersion);
+ printf("%s, %02d %s %d %02d:%02d:%02d %s\r\n", days[tm->tm_wday],
+ tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, tzname[tm->tm_isdst]);
+ printf(" Connected to %s:%u\r\n", inet_ntoa(rmtipaddr), ntohs(rmtport));
+ if(!loggedin)
+ printf(" Not logged in\r\n");
+ else
+ printf(" Logged in %s\r\n", username);
+ printf(" MODE: %s\r\n",(mode == MODE_B) ? "Block" : "Stream");
+ printf(" TYPE: %s\r\n",(type == TYPE_A) ? "Ascii" : "Binary");
+ printf("211 End of status\r\n");
+ return(GOOD);
+ }
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ printf("211-Status of %s:\r\n", buff);
+
+ if((fd = fdxcmd(CMD_LIST, buff)) < 0)
+ printf(" Could not retrieve status");
+ else {
+ while((s = read(fd, buffer, 1)) == 1) {
+ if(*buffer == '\n')
+ printf("\r\n");
+ else
+ printf("%c", *buffer);
+ }
+ endfdxcmd(fd);
+ }
+
+ printf("211 End of status\r\n");
+
+ return(GOOD);
+}
+
+/* hey look, we're getting a file */
+int doSTOR(buff)
+char *buff;
+{
+ return(recvfile(buff, RECV_FILE));
+}
+
+/* hey, get a file unique */
+int doSTOU(buff)
+char *buff;
+{
+ return(recvfile(buff, RECV_UNIQ));
+}
+
+/* structure */
+int doSTRU(buff)
+char *buff;
+{
+ switch(*buff) {
+ case 'f':
+ case 'F':
+ printf("200 Structure set to %c.\r\n", *buff);
+ break;
+ default:
+ printf("501 Unknown structure %c.\r\n", *buff);
+ }
+
+ return(GOOD);
+}
+
+/* we're UNIX and proud of it! */
+int doSYST(buff)
+char *buff;
+{
+ printf("215 UNIX Type: L8\r\n");
+
+ return(GOOD);
+}
+
+/* change transfer type */
+int doTYPE(buff)
+char *buff;
+{
+ if(*(buff+1) != '\0') {
+ printf("501 Syntax error in parameters.\r\n");
+ return(GOOD);
+ }
+
+ switch(*buff) {
+ case 'A':
+ case 'a':
+ type = TYPE_A;
+ printf("200 Type set to A.\r\n");
+ break;
+ case 'I':
+ case 'i':
+ type = TYPE_I;
+ printf("200 Type set to I.\r\n");
+ break;
+ default:
+ printf("501 Invalid type %c.\r\n", *buff);
+ }
+
+ return(GOOD);
+}
+
+static int fdxcmd(cmd, arg)
+int cmd;
+char *arg;
+{
+char xcmd[3];
+char *argv[5];
+int fds[2];
+char *smallenv[] = { "PATH=/bin:/usr/bin:/usr/local/bin", NULL, NULL };
+
+ if((smallenv[1] = getenv("TZ")) != NULL) smallenv[1] -= 3; /* ouch... */
+
+ sprintf(xcmd, "%d", cmd);
+
+ argv[0] = PROG_FTPDSH;
+ argv[1] = xcmd;
+ argv[2] = arg;
+ argv[3] = (char *)NULL;
+
+ if(pipe(fds) < 0)
+ return(-1);
+
+ if((cmdpid = fork()) < 0) {
+ close(fds[0]);
+ close(fds[1]);
+ return(-1);
+ }
+
+ if(cmdpid == 0) { /* Child */
+ close(fds[0]);
+ close(0);
+ open("/dev/null", O_RDONLY);
+ dup2(fds[1], 1);
+ dup2(fds[1], 2);
+ close(fds[1]);
+ sprintf(argv[0], "/bin/%s", PROG_FTPDSH);
+ execve(argv[0], argv, smallenv);
+ sprintf(argv[0], "/usr/bin/%s", PROG_FTPDSH);
+ execve(argv[0], argv, smallenv);
+ sprintf(argv[0], "/usr/local/bin/%s", PROG_FTPDSH);
+ execve(argv[0], argv, smallenv);
+ exit(0);
+ }
+
+ close(fds[1]);
+
+ return(fds[0]);
+}
+
+/* Same as close if not cmd child started */
+static int endfdxcmd(fd)
+int fd;
+{
+int s;
+int cs;
+
+ close(fd);
+
+ if(cmdpid == -1)
+ return(0);
+
+ s = waitpid(cmdpid, &cs, 0);
+
+ cmdpid = -1;
+
+ return(0);
+}
+
+/* returns -1 = size could not be determined, */
+/* 0 = size determined and in filesize */
+static int asciisize(filename, filesize)
+char *filename;
+unsigned long *filesize;
+{
+unsigned long count;
+int fd;
+char *p, *pp;
+int cnt;
+
+ if((fd = open(filename, O_RDONLY)) < 0) {
+ printf(msg550, filename, strerror(errno));
+ return(-1);
+ }
+
+ count = 0;
+
+ while((cnt = read(fd, buffer, sizeof(buffer))) > 0) {
+ count += cnt;
+ p = buffer;
+ while(cnt > 0)
+ if((pp = memchr(p, '\n', cnt)) != (char *)NULL) {
+ count++;
+ cnt = cnt - 1 - (pp - p);
+ p = pp + 1;
+ } else
+ break;
+ }
+
+ if(cnt == 0) {
+ *filesize = count;
+ close(fd);
+ return(0);
+ }
+
+ printf(msg550, filename, strerror(errno));
+
+ close(fd);
+
+ return(-1);
+}
+
+/* see if we need to run a command to convert the file */
+static int cnvtfile(name, name2)
+char *name;
+char **name2;
+{
+struct stat st;
+static char fname[256];
+char *p;
+int cmode;
+
+ if(!stat(name, &st)) /* file exists can't be a conversion */
+ if((st.st_mode & S_IFMT) != S_IFREG) { /* must be regular file */
+ printf("550 Not a regular file.\r\n");
+ return(CNVT_ERROR);
+ } else
+ return(CNVT_NONE);
+
+ if(errno != ENOENT) { /* doesn't exist is okay, others are not */
+ printf(msg550, name, strerror(errno));
+ return(CNVT_ERROR);
+ }
+
+ /* find out what kind of conversion */
+ strncpy(fname, name, sizeof(fname));
+ fname[sizeof(fname)-1] = '\0';
+
+ p = fname + strlen(fname);
+ cmode = CNVT_ERROR;
+ while(p > fname && cmode == CNVT_ERROR) {
+ if(*p == '.') {
+ if(!strcmp(p, ".tar"))
+ cmode = CNVT_TAR;
+ else
+ if(!strcmp(p, ".tar.Z"))
+ cmode = CNVT_TAR_Z;
+ else
+ if(!strcmp(p, ".Z"))
+ cmode = CNVT_COMP;
+ else
+ if(!strcmp(p, ".tar.gz"))
+ cmode = CNVT_TAR_GZ;
+ else
+ if(!strcmp(p, ".gz"))
+ cmode = CNVT_GZIP;
+
+ if (cmode != CNVT_ERROR) {
+ /* is there a file to convert? */
+ *p = '\0';
+ if (!stat(fname, &st)) break;
+ *p = '.';
+ cmode = CNVT_ERROR;
+ }
+ }
+ p--;
+ }
+
+ if(cmode == CNVT_ERROR) {
+ printf(msg550, fname, strerror(errno));
+ return(CNVT_ERROR);
+ }
+
+ if(cmode == CNVT_COMP || cmode == CNVT_GZIP || cmode == CNVT_UNCOMP)
+ if((st.st_mode & S_IFMT) != S_IFREG) {
+ printf("550 Not a regular file.\r\n");
+ return(CNVT_ERROR);
+ }
+
+ *name2 = fname;
+
+ return(cmode);
+}
+
+static int procfile(name)
+char *name;
+{
+int cmd;
+int fd;
+char *name2;
+
+ cmd = cnvtfile(name, &name2);
+
+ switch(cmd) {
+ case CNVT_TAR:
+ fd = fdxcmd(cmd + 10, name2);
+ break;
+ case CNVT_TAR_Z:
+ fd = fdxcmd(cmd + 10, name2);
+ break;
+ case CNVT_COMP:
+ fd = fdxcmd(cmd + 10, name2);
+ break;
+ case CNVT_TAR_GZ:
+ fd = fdxcmd(cmd + 10, name2);
+ break;
+ case CNVT_GZIP:
+ fd = fdxcmd(cmd + 10, name2);
+ break;
+ case CNVT_UNCOMP:
+ fd = fdxcmd(cmd + 10, name2);
+ break;
+ case CNVT_NONE:
+ fd = open(name, O_RDONLY);
+ break;
+ case CNVT_ERROR:
+ default:
+ return(-1);
+ }
+
+ if(fd < 0)
+ printf(msg550, name, strerror(errno));
+
+ return(fd);
+}
+
+/* oh no, they're taking a file */
+static int sendfile(name, xmode)
+char *name;
+int xmode;
+{
+char *fname;
+int fd, s;
+time_t datastart, dataend;
+unsigned long datacount;
+long kbs;
+char c;
+char *p;
+char *op, *ope;
+off_t sp;
+int doascii;
+unsigned long fs;
+char block[3];
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ switch(xmode) {
+ case SEND_NLST:
+ fname = "NLST";
+ fd = fdxcmd(CMD_NLST, name);
+ if(fd < 0)
+ printf(msg550, name, strerror(errno));
+ break;
+ case SEND_LIST:
+ fname = "LIST";
+ fd = fdxcmd(CMD_LIST, name);
+ if(fd < 0)
+ printf(msg550, name, strerror(errno));
+ break;
+ default:
+ fname = name;
+ fd = procfile(name);
+ if(fd < 0)
+ logit("FAIL", path(fname));
+ else
+ logit("SEND", path(fname));
+ }
+
+ if(fd < 0)
+ return(GOOD);
+
+ /* set file position at approriate spot */
+ if(file_restart) {
+ if(type == TYPE_A) {
+ sp = 0;
+ while(sp < file_restart) {
+ sp++;
+ s = read(fd, buffer, 1);
+ if(s < 0) {
+ printf(msg550, fname, strerror(errno));
+ endfdxcmd(fd);
+ file_restart = 0;
+ return(GOOD);
+ }
+ if(s == 0) break;
+ if(*buffer == '\n')
+ sp++;
+ }
+ } else {
+ sp = lseek(fd, file_restart, SEEK_SET);
+ if(sp == -1) {
+ printf(msg550, fname, strerror(errno));
+ endfdxcmd(fd);
+ file_restart = 0;
+ return(GOOD);
+ }
+ }
+ if(sp != file_restart) {
+ printf("550 File restart point error. %lu not %lu\r\n", sp, file_restart);
+ endfdxcmd(fd);
+ file_restart = 0;
+ return(GOOD);
+ }
+ }
+ file_restart = 0;
+
+ fs = fsize(fname);
+ if(fs == 0L)
+ printf("%03d File %s okay. Opening data connection.\r\n",
+ ftpdata_fd >= 0 ? 125 : 150, fname);
+ else
+ printf("%03d Opening %s mode data connection for %s (%ld bytes).\r\n",
+ ftpdata_fd >= 0 ? 125 : 150,
+ type == TYPE_A ? "ASCII" : "BINARY",
+ fname, fs);
+ fflush(stdout);
+
+#ifdef DEBUG
+ fprintf(logfile, "After 125/150 b4 DataConnect\n");
+ fflush(logfile);
+#endif
+
+ if(DataConnect()) {
+ endfdxcmd(fd);
+ return(GOOD);
+ }
+
+#ifdef DEBUG
+ fprintf(logfile, "After DataConnect\n");
+ fflush(logfile);
+ fprintf(logfile, "ftpd: parent %d start sendfile \n", getpid());
+ fflush(logfile);
+#endif
+
+ /* start transfer */
+ doascii = (type == TYPE_A) ||
+ ((xmode == SEND_LIST) || (xmode == SEND_NLST)); /* per RFC1123 4.1.2.7 */
+ datacount = 0;
+ time(&datastart);
+ op = bufout; ope = bufout + sizeof(bufout) - 3;
+ while((s = read(fd, buffer, sizeof(buffer))) > 0) {
+#ifdef DEBUG
+ fprintf(logfile, "sendfile read %d\n", s); fflush(logfile);
+#endif
+ datacount += s;
+ if(doascii) {
+ p = buffer;
+ while(s-- > 0) {
+ c = *p++;
+ if(c == '\n') {
+ *op++ = '\r';
+ datacount++;
+ }
+ *op++ = c;
+ if(op >= ope) {
+ if(mode == MODE_B) {
+ block[0] = '\0';
+ *(u16_t *)&block[1] = htons(op - bufout);
+ write(ftpdata_fd, block, sizeof(block));
+ }
+ write(ftpdata_fd, bufout, op - bufout);
+ op = bufout;
+ }
+ }
+ } else {
+ if(mode == MODE_B) {
+ block[0] = '\0';
+ *(u16_t *)&block[1] = htons(s);
+ write(ftpdata_fd, block, sizeof(block));
+ }
+ s = write(ftpdata_fd, buffer, s);
+ }
+ }
+ if(op > bufout) {
+ if(mode == MODE_B) {
+ block[0] = MODE_B_EOF;
+ *(u16_t *)&block[1] = htons(op - bufout);
+ write(ftpdata_fd, block, sizeof(block));
+ }
+ write(ftpdata_fd, bufout, op - bufout);
+ } else
+ if(mode == MODE_B) {
+ block[0] = MODE_B_EOF;
+ *(u16_t *)&block[1] = htons(0);
+ write(ftpdata_fd, block, sizeof(block));
+ }
+ time(&dataend);
+
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d end sendfile \n", getpid());
+ fflush(logfile);
+#endif
+
+ endfdxcmd(fd);
+ if(mode != MODE_B) {
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ }
+
+ if(dataend == datastart) dataend++;
+ kbs = (datacount * 100 / (dataend - datastart)) / 1024;
+
+ if(s < 0)
+ printf("451 Transfer aborted.\r\n");
+ else
+ printf("%03d Transfer finished successfully. %ld.%02d KB/s\r\n",
+ mode == MODE_B ? 250 : 226,
+ (long)(kbs / 100), (int)(kbs % 100));
+
+ return(GOOD);
+}
+
+static int recvfile(name, xmode)
+char *name;
+int xmode;
+{
+char *fname;
+time_t datastart, dataend;
+unsigned long datacount;
+long kbs;
+char c;
+char *p;
+char *op, *ope;
+int fd, oflag;
+int s;
+int gotcr;
+off_t sp;
+char block[3];
+unsigned short cnt;
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ fname = name;
+
+ switch(xmode) {
+ case RECV_APND:
+ oflag = O_WRONLY | O_APPEND;
+ break;
+ case RECV_UNIQ:
+ fname = uniqname();
+ oflag = O_WRONLY | O_CREAT;
+ break;
+ default:
+ oflag = O_WRONLY | O_CREAT | O_TRUNC;
+ }
+
+ if(file_restart)
+ oflag = O_RDWR;
+
+ fd = open(fname, oflag, (anonymous ? 0000:0600));
+
+ if(fd < 0) {
+ printf(msg550, fname, strerror(errno));
+ return(GOOD);
+ }
+
+ /* log the received file */
+ logit("RECV", path(fname));
+
+ /* set file position at approriate spot */
+ if(file_restart) {
+ if(type == TYPE_A) {
+ sp = 0;
+ while(sp < file_restart) {
+ sp++;
+ s = read(fd, buffer, 1);
+ if(s < 0) {
+ printf(msg550, fname, strerror(errno));
+ close(fd);
+ file_restart = 0;
+ return(GOOD);
+ }
+ if(s == 0) break;
+ if(*buffer == '\n')
+ sp++;
+ }
+ } else {
+ sp = lseek(fd, file_restart, SEEK_SET);
+ if(sp == -1) {
+ printf(msg550, fname, strerror(errno));
+ close(fd);
+ file_restart = 0;
+ return(GOOD);
+ }
+ }
+ if(sp != file_restart) {
+ printf("550 File restart point error. %lu not %lu\r\n", sp, file_restart);
+ close(fd);
+ file_restart = 0;
+ return(GOOD);
+ }
+ }
+ file_restart = 0;
+
+ if(xmode == RECV_UNIQ)
+ printf("%03d FILE: %s\r\n",
+ ftpdata_fd >= 0 ? 125 : 150, fname); /* per RFC1123 4.1.2.9 */
+ else
+ printf("%03d File %s okay. Opening data connection.\r\n",
+ ftpdata_fd >= 0 ? 125 : 150, fname);
+ fflush(stdout);
+
+ if(DataConnect()) {
+ close(fd);
+ return(GOOD);
+ }
+
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d start recvfile \n", getpid());
+ fflush(logfile);
+#endif
+
+ /* start receiving file */
+ datacount = 0;
+ gotcr = 0;
+ op = bufout; ope = bufout + sizeof(bufout) - 3;
+ cnt = 0;
+ time(&datastart);
+ while(1) {
+ if(mode != MODE_B)
+ cnt = sizeof(buffer);
+ else
+ if(cnt == 0) {
+ s = read(ftpdata_fd, block, sizeof(block));
+ cnt = ntohs(*(u16_t *)&block[1]);
+ s = 0;
+ if(cnt == 0 && block[0] & MODE_B_EOF)
+ break;
+ }
+ s = read(ftpdata_fd, buffer, cnt > sizeof(buffer) ? sizeof(buffer) : cnt);
+ if(s <= 0) break;
+ cnt -= s;
+ datacount += (long)s;
+ if(type == TYPE_A) {
+ 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;
+ }
+ }
+ } else
+ write(fd, buffer, s);
+ 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);
+ time(&dataend);
+
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d end recvfile \n", getpid());
+ fflush(logfile);
+#endif
+
+ close(fd);
+ if(mode != MODE_B) {
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ }
+
+ if(dataend == datastart) dataend++;
+ kbs = (datacount * 100 / (dataend - datastart)) / 1024;
+
+ if((mode == MODE_B && cnt != 0) || s != 0)
+ printf("451 Transfer aborted.\r\n");
+ else {
+ printf("%03d Transfer finished successfully. ",
+ mode == MODE_B ? 250 : 226);
+ if(xmode == RECV_UNIQ)
+ printf("Unique file %s. ", fname);
+ printf("%ld.%02d KB/s\r\n", (long)(kbs / 100), (int)(kbs % 100));
+ }
+
+ return(GOOD);
+}
+
+static char *uniqname()
+{
+static char uniq[32];
+int i;
+struct stat st;
+
+ for(i = 0; i < 1000; i++) {
+ sprintf(uniq, "ftpd%d%d", getpid(), i);
+ if(stat(uniq, &st) == -1)
+ return(uniq);
+ }
+ return(uniq);
+}
+
+static char *spath[256];
+static char *path(fname)
+char *fname;
+{
+char dir[128];
+
+ if(getcwd(dir, sizeof(dir)) == (char *)NULL)
+ sprintf(dir, "???");
+
+ if(fname[0] == '/')
+ sprintf((char *)spath, "%s%s", newroot, fname);
+ else
+ if(dir[1] == '\0')
+ sprintf((char *)spath, "%s%s%s", newroot, dir, fname);
+ else
+ sprintf((char *)spath, "%s%s/%s", newroot, dir, fname);
+
+ return((char *)spath);
+}
+
+/* do file detail */
+static int dofdet(buff)
+char *buff;
+{
+struct stat st;
+char ft;
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ if(stat(buff, &st)) {
+ printf("501 Could not obtain file detail.\r\n");
+ return(GOOD);
+ }
+ switch(st.st_mode & S_IFMT) {
+ case S_IFIFO: ft = 'p'; break;
+ case S_IFCHR: ft = 'c'; break;
+ case S_IFDIR: ft = 'd'; break;
+ case S_IFBLK: ft = 'b'; break;
+ case S_IFREG: ft = 'f'; break;
+ default: ft = '?'; break;
+ }
+ printf("202 %c %u %u %u %u %u %lu %lu\r\n",
+ ft, /* file type */
+ st.st_rdev >> 8, /* Major */
+ st.st_rdev & 0xff, /* Minor */
+ st.st_uid, /* UID */
+ st.st_gid, /* GID */
+ st.st_mode, /* File Modes */
+ st.st_size, /* SIZE */
+ st.st_mtime); /* Mod Time */
+
+ return(GOOD);
+}
--- /dev/null
+/* file.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftpd.
+ *
+ *
+ * 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(int doALLO, (char *buff));
+_PROTOTYPE(int doAPPE, (char *buff));
+_PROTOTYPE(int doCDUP, (char *buff));
+_PROTOTYPE(int doCWD, (char *buff));
+_PROTOTYPE(int doDELE, (char *buff));
+_PROTOTYPE(int doLIST, (char *buff));
+_PROTOTYPE(int doMDTM, (char *buff));
+_PROTOTYPE(int doMODE, (char *buff));
+_PROTOTYPE(int doMKD, (char *buff));
+_PROTOTYPE(int doNLST, (char *buff));
+_PROTOTYPE(int doPWD, (char *buff));
+_PROTOTYPE(int doREST, (char *buff));
+_PROTOTYPE(int doRETR, (char *buff));
+_PROTOTYPE(int doRMD, (char *buff));
+_PROTOTYPE(int doRNFR, (char *buff));
+_PROTOTYPE(int doRNTO, (char *buff));
+_PROTOTYPE(int doSITE, (char *buff));
+_PROTOTYPE(int doSIZE, (char *buff));
+_PROTOTYPE(int doSTAT, (char *buff));
+_PROTOTYPE(int doSTOR, (char *buff));
+_PROTOTYPE(int doSTOU, (char *buff));
+_PROTOTYPE(int doSTRU, (char *buff));
+_PROTOTYPE(int doSYST, (char *buff));
+_PROTOTYPE(int doTYPE, (char *buff));
--- /dev/null
+.\" Copyright (c) 1985 Regents of the University of California.
+.\" All rights reserved. The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\" @(#)ftpd.8c 6.4 (Berkeley) 5/28/86
+.\"
+.TH FTPD 8
+.SH NAME
+ftpd, in.ftpd, ftpdsh, setup.anonftp \- DARPA Internet File Transfer Protocol server
+.SH SYNOPSIS
+.B "ftp stream tcp nowait root /usr/bin/in.ftpd in.ftpd"
+.br
+.B "tcpd ftp /usr/bin/in.ftpd"
+.SH DESCRIPTION
+.B Ftpd
+is the DARPA Internet File Transfer Prototocol
+server process. The server uses the TCP protocol
+and listens at the port specified in the ``ftp''
+service specification; see
+.BR services (5).
+.PP
+The ftp server currently supports the following ftp
+requests; case is not distinguished.
+.PP
+.nf
+.ta \w'Request 'u
+\fBRequest Description\fP
+ABOR abort previous command
+ACCT specify account (ignored)
+ALLO allocate storage (vacuously)
+APPE append to a file
+CDUP change to parent of current working directory
+CWD change working directory
+DELE delete a file
+HELP give help information
+LIST give list files in a directory (``ls -lA'')
+MKD make a directory
+MODE specify data transfer \fImode\fP
+NLST give name list of files in directory (``ls'')
+NOOP do nothing
+PASS specify password
+PASV prepare for server-to-server transfer
+PORT specify data connection port
+PWD print the current working directory
+QUIT terminate session
+RETR retrieve a file
+RMD remove a directory
+RNFR specify rename-from file name
+RNTO specify rename-to file name
+STOR store a file
+STOU store a file with a unique name
+STRU specify data transfer \fIstructure\fP
+TYPE specify data transfer \fItype\fP
+USER specify user name
+XCUP change to parent of current working directory
+XCWD change working directory
+XMKD make a directory
+XPWD print the current working directory
+XRMD remove a directory
+.fi
+.PP
+The remaining ftp requests specified in Internet RFC 959 are
+recognized, but not implemented.
+.PP
+The ftp server will abort an active file transfer only when the
+ABOR command is preceded by a Telnet "Interrupt Process" (IP)
+signal and a Telnet "Synch" signal in the command Telnet stream,
+as described in Internet RFC 959.
+.PP
+.B Ftpd
+interprets file names according to the ``globbing''
+conventions used by
+.BR csh (1).
+This allows users to utilize the metacharacters ``*?[]{}~''.
+.PP
+.B Ftpd
+authenticates users according to two rules.
+.IP 1)
+The user name must be in the password data base,
+.BR /etc/passwd ,
+and not have a null password. In this case a password
+must be provided by the client before any file operations
+may be performed.
+.IP 2)
+If the user name is ``anonymous'' or ``ftp'', an
+anonymous ftp account must be present in the password
+file (user ``ftp''). In this case the user is allowed
+to log in by specifying any password (by convention this
+is given as the client host's name).
+.PP
+In the last case,
+.B ftpd
+takes special measures to restrict the client's access privileges.
+The server performs a
+.BR chroot (2)
+command to the home directory of the ``ftp'' user.
+In order that system security is not breached, it is recommended
+that the ``ftp'' subtree be constructed with care; the following
+rules are recommended.
+.IP ~ftp)
+Make the home directory owned by ``ftp'' and unwritable by anyone.
+.IP ~ftp/bin)
+Make this directory owned by the super-user and unwritable by
+anyone. The program
+.BR ls (1)
+must be present to support the list commands.
+Also,
+.BR crc (1)
+must be present to support generating crcs using the site command,
+.BR tar (1)
+and
+.BR compress (1)
+must be present to support on-the-fly generation of .tar and .tar.Z archives,
+.BR gzip (1)
+must be present to support gzip compression, and
+.BR sh (1)
+must be present to support
+.BR ftpdsh (8)
+which also must be present.
+.BR ftpdsh controls which binaries can be used.
+These programs should all have mode 111.
+.IP ~ftp/etc)
+Make this directory owned by the super-user and unwritable by
+anyone. The files
+.BR passwd (5)
+and
+.BR group (5)
+must be present for the
+.B ls
+command to work properly. These files should be mode 444. They can (and
+should) be stripped down versions so as not to reveal names of users who
+are not owners of files in the ~ftp/pub directory tree.
+.IP ~ftp/pub)
+Make this directory mode 755 and owned by the super-user. Create
+directories in it owned by users if those users want to manage an
+anonymous ftp directory.
+.IP ~ftp/pub/incoming)
+Optionally create this directory for anonymous uploads. Make it mode
+777. The FTP daemon will create files with mode 266, so remote users
+can write a file, but only local users can do something with it.
+.PP
+The script
+.B setup.anonftp
+can be used to create or check an anonymous FTP tree.
+.SH "SEE ALSO"
+.BR ftp (1).
+.SH BUGS
+The anonymous account is inherently dangerous and should
+avoided when possible.
+.ig \" Minix doesn't have privileged port numbers (yet?)
+.PP
+The server must run as the super-user
+to create sockets with privileged port numbers. It maintains
+an effective user id of the logged in user, reverting to
+the super-user only when binding addresses to sockets. The
+possible security holes have been extensively
+scrutinized, but are possibly incomplete.
+..
+.\" man page updated by Al Woodhull 2005-02-25
+
+
--- /dev/null
+/* ftpd.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * ftpd An FTP server program for use with Minix.
+ *
+ * Usage: Minix usage: tcpd ftp ftpd
+ *
+ * 06/14/92 Tnet Release Michael Temari
+ * 01/15/96 0.30 Michael Temari
+ * 01/25/96 0.90 Michael Temari
+ * 03/17/96 0.91 Michael Temari
+ * 06/27/96 0.92 Michael Temari
+ * 07/02/96 0.93 Michael Temari
+ * 07/15/96 0.94 Michael Temari
+ * 08/27/96 0.95 Michael Temari
+ * 02/09/97 0.96 Michael Temari
+ * 02/10/97 0.97 Michael Temari
+ * 09/25/97 0.98 Michael Temari
+ * 03/10/00 0.99 Michael Temari, <Michael@TemWare.Com>
+ * 12/12/03 1.00 Michael Temari, <Michael@TemWare.Com>
+ * 02/06/05 1.01 Michael Temari, <Michael@TemWare.Com>
+ * 02/12/05 2.00 Michael Temari, <Michael@TemWare.Com>
+ */
+
+char *FtpdVersion = "2.00";
+
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <net/gen/in.h>
+#include <net/gen/tcp.h>
+
+#include "ftpd.h"
+#include "access.h"
+#include "file.h"
+#include "net.h"
+
+_PROTOTYPE(static void init, (void));
+_PROTOTYPE(static int doHELP, (char *buff));
+_PROTOTYPE(static int doNOOP, (char *buff));
+_PROTOTYPE(static int doUNIMP, (char *buff));
+_PROTOTYPE(static int getline, (char *line, int len));
+
+FILE *msgfile = (FILE *)NULL;
+
+/* The following defines the inactivity timeout in seconds */
+#define INACTIVITY_TIMEOUT 60*5
+
+char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+char line[512];
+
+int type, format, mode, structure;
+int ftpdata_fd = -1;
+int loggedin, gotuser, anonymous;
+char username[80];
+char anonpass[128];
+char newroot[128];
+
+ipaddr_t myipaddr, rmtipaddr, dataaddr;
+tcpport_t myport, rmtport, dataport;
+
+char myhostname[256], rmthostname[256];
+
+#define FTPD_LOG "/usr/adm/ftpd.log"
+#define FTPD_MSG "/etc/ftpd_msg"
+
+FILE *logfile;
+
+int timeout = 0;
+
+_PROTOTYPE(static int doHELP, (char *buff));
+_PROTOTYPE(int readline, (char **args));
+_PROTOTYPE(void Timeout, (int sig));
+_PROTOTYPE(int main, (int argc, char *argv[]));
+
+struct commands {
+ char *name;
+ _PROTOTYPE(int (*func), (char *buff));
+};
+
+struct commands commands[] = {
+ "ABOR", doUNIMP,
+ "ACCT", doUNIMP,
+ "ALLO", doALLO,
+ "APPE", doAPPE,
+ "CDUP", doCDUP,
+ "CWD", doCWD,
+ "DELE", doDELE,
+ "HELP", doHELP,
+ "LIST", doLIST,
+ "MDTM", doMDTM,
+ "MKD", doMKD,
+ "MODE", doMODE,
+ "NLST", doNLST,
+ "NOOP", doNOOP,
+ "PASS", doPASS,
+ "PASV", doPASV,
+ "PORT", doPORT,
+ "PWD", doPWD,
+ "QUIT", doQUIT,
+ "REIN", doUNIMP,
+ "REST", doREST,
+ "RETR", doRETR,
+ "RMD", doRMD,
+ "RNFR", doRNFR,
+ "RNTO", doRNTO,
+ "SITE", doSITE,
+ "SIZE", doSIZE,
+ "SMNT", doUNIMP,
+ "STAT", doSTAT,
+ "STOR", doSTOR,
+ "STOU", doSTOU,
+ "STRU", doSTRU,
+ "SYST", doSYST,
+ "TYPE", doTYPE,
+ "USER", doUSER,
+ "XCUP", doCDUP,
+ "XCWD", doCWD,
+ "XMKD", doMKD,
+ "XPWD", doPWD,
+ "XRMD", doRMD,
+ "", (int (*)())0
+};
+
+static void init()
+{
+ loggedin = 0;
+ gotuser = 0;
+ anonymous = 0;
+ newroot[0] = '\0';
+ type = TYPE_A;
+ format = 0;
+ mode = MODE_S;
+ structure = 0;
+ ftpdata_fd = -1;
+ username[0] = '\0';
+ anonpass[0] = '\0';
+}
+
+/* nothing, nada, zilch... */
+static int doNOOP(buff)
+char *buff;
+{
+ printf("200 NOOP to you too!\r\n");
+
+ return(GOOD);
+}
+
+/* giv'em help, what a USER! */
+static int doHELP(buff)
+char *buff;
+{
+struct commands *cmd;
+char star;
+int i;
+char *space = " ";
+
+ printf("214-Here is a list of available ftp commands\r\n");
+ printf(" Those with '*' are not yet implemented.\r\n");
+
+ i = 0;
+ for(cmd = commands; *cmd->name != '\0'; cmd++) {
+ if(cmd->func == doUNIMP)
+ star = '*';
+ else
+ star = ' ';
+ printf(" %s%c%s", cmd->name, star, space + strlen(cmd->name));
+ if(++i == 6) {
+ printf("\r\n");
+ i = 0;
+ }
+ }
+
+ if(i)
+ printf("\r\n");
+
+ printf("214 That's all the help you get.\r\n");
+
+ return(GOOD);
+}
+
+/* not implemented */
+static int doUNIMP(buff)
+char *buff;
+{
+ printf("502 Command \"%s\" not implemented!\r\n", line);
+
+ return(GOOD);
+}
+
+/* convert line for use */
+void cvtline(args)
+char **args;
+{
+char *p;
+
+ p = line + strlen(line);
+ while(--p >= line)
+ if(*p == '\r' || *p == '\n' || isspace(*p))
+ *p = '\0';
+ else
+ break;
+
+ p = line;
+
+#ifdef DEBUG
+ logit("COMMAND", line);
+#endif
+
+ while(*p && !isspace(*p)) {
+ *p = toupper(*p);
+ p++;
+ }
+
+ if(*p) {
+ *p = '\0';
+ p++;
+ while(*p && isspace(*p))
+ p++;
+ }
+
+ *args = p;
+
+ return;
+}
+
+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(0, line, 1);
+ if(s != 1)
+ return(-1);
+ if(*line == '\n')
+ break;
+ gotcr = (*line == '\r');
+ line++;
+ }
+ if(gotcr)
+ --line;
+
+ *line = '\0';
+
+ return(0);
+}
+
+int readline(args)
+char **args;
+{
+ if(getline(line, sizeof(line)))
+ return(BAD);
+
+ cvtline(args);
+
+ return(GOOD);
+}
+
+/* signal handler for inactivity timeout */
+void Timeout(sig)
+int sig;
+{
+ timeout = 1;
+
+ printf("421 Inactivity timer expired.\r\n");
+}
+
+/* logit */
+void logit(type, parm)
+char *type;
+char *parm;
+{
+time_t now;
+struct tm *tm;
+
+ if(logfile == (FILE *)NULL)
+ return;
+
+ time(&now);
+ tm = localtime(&now);
+ fprintf(logfile, "%4d%02d%02d%02d%02d%02d ",
+ 1900+tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ fprintf(logfile, "%s %s %s %s %s\n",
+ rmthostname, username, anonymous ? anonpass : username, type, parm);
+ fflush(logfile);
+}
+
+void showmsg(reply, filename)
+char *reply;
+char *filename;
+{
+FILE *mfp;
+char *pe;
+static char mline[256];
+
+ if(filename == (char *)NULL)
+ mfp = msgfile;
+ else
+ mfp = fopen(filename, "r");
+
+ if(mfp == (FILE *)NULL)
+ return;
+
+ while(fgets(mline, sizeof(mline), mfp) != (char *)NULL) {
+ pe = mline + strlen(mline);
+ while(--pe >= mline)
+ if(*pe == '\r' || *pe == '\n')
+ *pe = '\0';
+ else
+ break;
+ printf("%s- %s\r\n", reply, mline);
+ }
+
+ if(filename != (char *)NULL)
+ fclose(mfp);
+}
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+struct commands *cmd;
+char *args;
+int status;
+time_t now;
+struct tm *tm;
+int s;
+
+ GetNetInfo();
+
+ /* open transfer log file if it exists */
+ if((logfile = fopen(FTPD_LOG, "r")) != (FILE *)NULL) {
+ fclose(logfile);
+ logfile = fopen(FTPD_LOG, "a");
+ }
+
+ /* open login msg file */
+ msgfile = fopen(FTPD_MSG, "r");
+
+ /* Let's initialize some stuff */
+ init();
+
+ /* Log the connection */
+ logit("CONNECT", "");
+
+ /* Tell 'em we are ready */
+ time(&now);
+ tm = localtime(&now);
+ printf("220 FTP service (Ftpd %s) ready on %s at ",
+ FtpdVersion, myhostname);
+ printf("%s, %02d %s %d %02d:%02d:%02d %s\r\n", days[tm->tm_wday],
+ tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ tzname[tm->tm_isdst]);
+ fflush(stdout);
+
+ /* Loop here getting commands */
+ while(1) {
+ signal(SIGALRM, Timeout);
+ alarm(INACTIVITY_TIMEOUT);
+ if(readline(&args) != GOOD) {
+ if(!timeout)
+ printf("221 Control connection closing (EOF).\r\n");
+ break;
+ }
+ alarm(0);
+ for(cmd = commands; *cmd->name != '\0'; cmd++)
+ if(!strcmp(line, cmd->name))
+ break;
+ if(*cmd->name != '\0')
+ status = (*cmd->func)(args);
+ else {
+ printf("500 Command \"%s\" not recognized.\r\n", line);
+ status = GOOD;
+ }
+ fflush(stdout);
+ if(status != GOOD)
+ break;
+ }
+
+ CleanUpPasv();
+
+ return(-1);
+}
--- /dev/null
+/* ftpd.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftpd.
+ *
+ *
+ * 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
+ */
+
+#define GOOD 0
+#define BAD 1
+
+#define TYPE_A 0
+#define TYPE_I 1
+
+#define MODE_S 0
+#define MODE_B 1
+
+#define MODE_B_EOF 64
+
+extern char *FtpdVersion;
+extern int type, format, mode, structure;
+extern ipaddr_t myipaddr, rmtipaddr, dataaddr;
+extern tcpport_t myport, rmtport, dataport;
+extern int ftpdata_fd;
+extern int loggedin, gotuser, anonymous;
+extern char newroot[128];
+extern char *days[], *months[];
+extern char username[80];
+extern char anonpass[128];
+extern char myhostname[256], rmthostname[256];
+extern char line[512];
+
+extern FILE *logfile;
+
+_PROTOTYPE(void cvtline, (char **args));
+_PROTOTYPE(void logit, (char *type, char *parm));
+_PROTOTYPE(void showmsg, (char *reply, char *filename));
--- /dev/null
+#!/bin/sh
+
+case $1 in
+ 1) ls -A $2 ;;
+ 2) ls -la $2 ;;
+ 3) crc $2 ;;
+ 12) tar cf - $2 ;;
+ 13) tar cf - $2 | compress -q ;;
+ 14) compress -cq $2 ;;
+ 15) tar cf - $2 | gzip ;;
+ 16) tar -c $2 ;;
+ 17) compress -dcq $2 ;;
+esac
+exit
--- /dev/null
+/* net.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftpd.
+ *
+ * This file handles:
+ *
+ * PASV PORT
+ *
+ *
+ * 01/25/1995 Initial Release Michael Temari, <Michael@TemWare.Com>
+ * 02/09/2005 Initial Release Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <time.h>
+#include <net/netlib.h>
+#include <net/hton.h>
+#include <net/gen/in.h>
+#include <net/gen/inet.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/gen/socket.h>
+#include <net/gen/netdb.h>
+
+#include "ftpd.h"
+#include "access.h"
+#include "net.h"
+
+_PROTOTYPE(static void timeout, (int sig));
+
+static char *msg425 = "425-Could not open data connection.\r\n";
+static char *msg501 = "501 Syntax error in parameters.\r\n";
+
+static int gottimeout = 0;
+static int lpid = -1;
+static int didpassive = 0;
+
+/* they must be behind a firewall or using a web browser */
+int doPASV(buff)
+char *buff;
+{
+nwio_tcpconf_t tcpconf;
+nwio_tcpcl_t tcplopt;
+char *tcp_device;
+ipaddr_t ipaddr;
+tcpport_t lport;
+int s;
+time_t starttime;
+int retry;
+
+ if(ChkLoggedIn())
+ return(GOOD);
+
+ CleanUpPasv();
+
+ /* here we set up a connection to listen on */
+ if((tcp_device = getenv("TCP_DEVICE")) == NULL)
+ tcp_device = TCP_DEVICE;
+
+ if(ftpdata_fd >= 0) {
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ }
+
+ if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
+ printf(msg425);
+ printf("425 Could not open tcp_device. Error %s\r\n", strerror(errno));
+ return(GOOD);
+ }
+
+ tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_UNSET_RP;
+
+ tcpconf.nwtc_remaddr = rmtipaddr;
+ tcpconf.nwtc_remport = htons(0);
+ tcpconf.nwtc_locport = htons(0);
+
+ s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Could not ioctl NWIOSTCPCONF. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(GOOD);
+ }
+
+ s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Could not NWIOGTCPCONF. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(GOOD);
+ }
+ ipaddr = tcpconf.nwtc_locaddr;
+ lport = tcpconf.nwtc_locport;
+
+ /* Now lets fork a child to do the listening :-( */
+
+ tcplopt.nwtcl_flags = 0;
+
+ lpid = fork();
+ if(lpid < 0) {
+ printf(msg425);
+ printf("425 Could not fork listener. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(GOOD);
+ } else if(lpid == 0) {
+ retry = 0;
+ while(1) {
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: child %d parent %d listen try %d\n", getpid(), getppid(), retry);
+ fflush(logfile);
+#endif
+ s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
+ if(!(s == -1 && errno == EAGAIN)) break;
+ if(retry++ > 10) break;
+ sleep(1);
+ }
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: child %d s %d errno %d\n", getpid(), s, errno);
+ fflush(logfile);
+#endif
+ if(s < 0)
+ exit(errno); /* tells parent listen failed */
+ else
+ exit(0); /* tells parent listen okay */
+ }
+
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d wait for %d\n", getpid(), lpid);
+ fflush(logfile);
+#endif
+
+ /* wait for child to be listening, no more than serveral seconds */
+ (void) time(&starttime);
+ while(1) {
+ if(time((time_t *)NULL) > (starttime + 15)) break;
+ signal(SIGALRM, timeout);
+ alarm(1);
+ s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d s %d errno %d start %ld now %ld\n",
+ getpid(), lpid, s, errno, starttime, time((time_t *)NULL));
+ fflush(logfile);
+#endif
+ alarm(0);
+ if(s == -1) break;
+ sleep(1);
+ }
+
+#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)
+
+ printf("227 Entering Passive Mode (%u,%u,%u,%u,%u,%u).\r\n",
+ hibyte(hiword(htonl(ipaddr))), lobyte(hiword(htonl(ipaddr))),
+ hibyte(loword(htonl(ipaddr))), lobyte(loword(htonl(ipaddr))),
+ hibyte(htons(lport)), lobyte(htons(lport)));
+
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d send 227\n", getpid(), lpid);
+ fflush(logfile);
+#endif
+
+ didpassive = -1;
+
+ return(GOOD);
+}
+
+/* they want us to connect here */
+int doPORT(buff)
+char *buff;
+{
+u32_t ipaddr;
+u16_t port;
+int i;
+
+ if(ftpdata_fd >= 0) {
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ }
+
+ ipaddr = (u32_t)0;
+ for(i = 0; i < 4; i++) {
+ ipaddr = (ipaddr << 8) + (u32_t)atoi(buff);
+ if((buff = strchr(buff, ',')) == (char *)0) {
+ printf(msg501);
+ return(GOOD);
+ }
+ buff++;
+ }
+ port = (u16_t)atoi(buff);
+ if((buff = strchr(buff, ',')) == (char *)0) {
+ printf(msg501);
+ return(0);
+ }
+ buff++;
+ port = (port << 8) + (u16_t)atoi(buff);
+
+ dataaddr = htonl(ipaddr);
+ dataport = htons(port);
+ if(dataaddr != rmtipaddr) {
+ printf(msg501);
+ return(GOOD);
+ }
+
+ printf("200 Port command okay.\r\n");
+
+ return(GOOD);
+}
+
+/* connect, huh? */
+int DataConnect()
+{
+nwio_tcpconf_t tcpconf;
+nwio_tcpcl_t tcpcopt;
+nwio_tcpcl_t tcplopt;
+char *tcp_device;
+int s, cs;
+int retry;
+
+ if(didpassive && ftpdata_fd >= 0) {
+ didpassive = 0;
+ gottimeout = 0;
+ signal(SIGALRM, timeout);
+ alarm(10);
+ while(!gottimeout) {
+ s = waitpid(lpid, &cs, 0);
+ if((s == lpid) || (s < 0 && errno == ECHILD)) break;
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d waitpid s %d cs %04x errno %d\n", getpid(), lpid, s, cs, errno);
+ fflush(logfile);
+#endif
+ }
+ alarm(0);
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d waitpid s %d cs %04x errno %d\n", getpid(), lpid, s, cs, errno);
+ fflush(logfile);
+#endif
+ if(gottimeout) {
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d got timeout\n", getpid(), lpid);
+ fflush(logfile);
+#endif
+ kill(lpid, SIGKILL);
+ s = waitpid(lpid, &cs, 0);
+ }
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d continuing\n", getpid(), lpid);
+ fflush(logfile);
+#endif
+ lpid = -1;
+ if(gottimeout) {
+ printf(msg425);
+ printf("425 Child listener timeout.\r\n");
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Child listener vanished.\r\n");
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+ if((cs & 0x00ff)) {
+ printf(msg425);
+ printf("425 Child listener failed %04x\r\n", cs);
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+ cs = (cs >> 8) & 0x00ff;
+ if(cs) {
+ printf(msg425);
+ printf("425 Child listener error %s\r\n", strerror(cs));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+#ifdef DEBUG
+ fprintf(logfile, "ftpd: parent %d child %d pasv done\n", getpid(), lpid);
+ fflush(logfile);
+#endif
+ return(GOOD);
+ }
+
+ if(ftpdata_fd >= 0)
+ return(GOOD);
+
+ if((tcp_device = getenv("TCP_DEVICE")) == NULL)
+ tcp_device = TCP_DEVICE;
+
+ if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
+ printf(msg425);
+ printf("425 Could not open tcp_device. Error %s\r\n", strerror(errno));
+ return(BAD);
+ }
+
+ tcpconf.nwtc_flags = NWTC_LP_SET | NWTC_SET_RA | NWTC_SET_RP;
+ tcpconf.nwtc_remaddr = dataaddr;
+ tcpconf.nwtc_remport = dataport;
+ tcpconf.nwtc_locport = htons(20);
+
+ s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Could not ioctl NWIOSTCPCONF. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+
+ s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Could not ioctl NWIOGTCPCONF. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+
+ tcpcopt.nwtcl_flags = 0;
+
+ retry = 0;
+ do {
+#ifdef DEBUG
+ fprintf(logfile, "try connect\n"); fflush(logfile);
+ fflush(logfile);
+#endif
+ sleep(2);
+ s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
+#ifdef DEBUG
+ fprintf(logfile, "after connect %d %d\n", s, errno);
+ fflush(logfile);
+#endif
+ if(!(s == -1 && errno == EAGAIN)) break;
+ if(retry++ > 10) break;
+ sleep(1);
+ } while(1);
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Could not ioctl NWIOTCPCONN. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+
+ s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+ if(s < 0) {
+ printf(msg425);
+ printf("425 Could not ioctl NWIOGTCPCONF. Error %s\r\n", strerror(errno));
+ close(ftpdata_fd);
+ ftpdata_fd = -1;
+ return(BAD);
+ }
+
+ return(GOOD);
+}
+
+/* Clean up stuff we did to get a Pasv connection going */
+int CleanUpPasv()
+{
+int s, cs;
+
+ if(lpid >= 0) {
+ kill(lpid, SIGKILL);
+ while(1) {
+ s = waitpid(lpid, &cs, 0);
+ if(s == lpid || (s == -1 && errno == ECHILD))
+ break;
+ }
+ }
+
+ lpid = -1;
+
+ didpassive = 0;
+
+ return(GOOD);
+}
+
+void GetNetInfo()
+{
+nwio_tcpconf_t tcpconf;
+int s;
+struct hostent *hostent;
+
+ /* Ask the system what our hostname is. */
+ if(gethostname(myhostname, sizeof(myhostname)) < 0)
+ strcpy(myhostname, "unknown");
+
+ /* lets get our ip address and the clients ip address */
+ s = ioctl(0, NWIOGTCPCONF, &tcpconf);
+ if(s < 0) {
+ printf("421 FTP service unable to get remote ip address. Closing.\r\n");
+ fflush(stdout);
+ exit(1);
+ }
+
+ myipaddr = tcpconf.nwtc_locaddr;
+ myport = tcpconf.nwtc_locport;
+ rmtipaddr = tcpconf.nwtc_remaddr;
+ rmtport = tcpconf.nwtc_remport;
+
+ /* Look up the host name of the remote host. */
+ hostent = gethostbyaddr((char *) &rmtipaddr, sizeof(rmtipaddr), AF_INET);
+ if(!hostent)
+ strcpy(rmthostname, inet_ntoa(rmtipaddr));
+ else {
+ strncpy(rmthostname, hostent->h_name, sizeof(rmthostname)-1);
+ rmthostname[sizeof(rmthostname)-1] = '\0';
+ }
+}
+
+static void timeout(sig)
+int sig;
+{
+ gottimeout = 1;
+}
--- /dev/null
+/* net.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftpd.
+ *
+ *
+ * 01/25/96 Initial Release Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(int doPASV, (char *buff));
+_PROTOTYPE(int doPORT, (char *buff));
+_PROTOTYPE(int DataConnect, (void));
+_PROTOTYPE(int CleanUpPasv, (void));
+_PROTOTYPE(void GetNetInfo, (void));
--- /dev/null
+#!/bin/sh
+# setup.anonftp - Anonymous FTP setup and maintenance.
+#
+# 01/22/96 Initial Release Al Woodhul, <asw@hampshire.edu>
+# 01/25/96 Michael Temari, <temari@ix.netcom.com>
+#
+
+# What is needed for anon ftp
+
+# ref: Hunt TCP/IP Net Admin pp. 338++
+# ref: Nemeth et al UNIX System Admin Handbook p. 295
+# ref: mail from M. Temari 18.01.96
+
+# programs possibly used by ftpd
+PROGS="sh ls crc tar compress gzip"
+
+echo Checking /etc/passwd
+if grep '^ftp:[^:]*:[1-9][0-9]*:[1-9][0-9]*:[^:]*:/[^:]*:[^:]*$' \
+ /etc/passwd >/dev/null
+then
+ echo -n "OK, ftp entry found: "
+ grep '^ftp:' /etc/passwd
+else
+ echo "Found no entry for ftp in /etc/passwd, please add one with the"
+ echo "home directory pointing to the anonymous FTP directory"
+ exit 1
+fi
+
+# ftp directory
+FTPDIR="`sed '/^ftp:/!d; s/^.*:\\([^:]*\\):[^:]*/\\1/' /etc/passwd`"
+
+if [ `whoami` != root ]
+then
+ echo You must be root to do this
+ exit 1
+fi
+
+echo Setting up for anonymous ftp
+
+echo Making $FTPDIR and subdirectories
+install -d -m 755 -o root -g operator $FTPDIR
+install -d -m 751 -o root -g operator $FTPDIR/bin
+install -d -m 751 -o root -g operator $FTPDIR/dev
+install -d -m 751 -o root -g operator $FTPDIR/etc
+install -d -m 755 -o root -g operator $FTPDIR/pub
+incoming=
+if [ -d $FTPDIR/pub/incoming ]
+then
+ incoming=t
+elif [ -t 0 ]
+then
+ echo -n "Create \"incoming\" directory? [n] "; read yn
+ case "$yn" in
+ [yY]*|ok|sure) incoming=t
+ esac
+fi
+test "$incoming" && install -d -m 777 -o root -g operator $FTPDIR/pub/incoming
+
+echo Copying files
+for PROG in $PROGS
+do
+ test -f /usr/bin/$PROG && install -lcs /usr/bin/$PROG $FTPDIR/bin
+done
+cp -rp /dev/tcp $FTPDIR/dev/tcp
+install -lcs ftpdsh $FTPDIR/bin
+
+echo Copying a minimum of the password and group files
+sed 's/^\([^:]*\):[^:]*:\([^:]*:[^:]*\):.*$/\1:*:\2:::/' \
+ /etc/passwd >$FTPDIR/etc/passwd
+sed 's/^\([^:]*\):[^:]*:\([^:]*\):.*$/\1:*:\2:/' \
+ /etc/group >$FTPDIR/etc/group
+chown root:operator $FTPDIR/etc/*
+chmod 444 $FTPDIR/etc/*
+
+echo "Anonymous ftp setup complete"
* If you want to compile this for non-IBM PC architectures, the header files
* require that you have your CHIP, MACHINE etc. defined.
* Full syntax:
- * ps [-][alx]
+ * ps [-][aeflx]
* Option `a' gives all processes, `l' for detailed info, `x' includes even
* processes without a terminal.
+ * The `f' and `e' options were added by Kees Bot for the convenience of
+ * Solaris users accustomed to these options. The `e' option is equivalent to
+ * `a' and `f' is equivalent to -l. These do not appear in the usage message.
*
* VERY IMPORTANT NOTE:
* To compile ps, the kernel/, fs/ and pm/ source directories must be in
void usage(pname)
char *pname;
{
- fprintf(stderr, "Usage: %s [-][alx]\n", pname);
+ fprintf(stderr, "Usage: %s [-][aeflx]\n", pname);
exit(1);
}
{ 0x100B, 0xD001, "Nat. Semi. 87410" },
{ 0x1013, 0x00B8, "Cirrus Logic GD 5446" },
{ 0x1013, 0x6003, "Cirrus Logic CS4614/22/24 CrystalClear" },
+ { 0x1022, 0x2000, "AMD Lance/PCI" },
{ 0x1022, 0x700C, "AMD-762 CPU to PCI Bridge (SMP chipset)" },
{ 0x1022, 0x700D, "AMD-762 CPU to PCI Bridge (AGP 4x)" },
{ 0x1022, 0x7410, "AMD-766 PCI to ISA/LPC Bridge" },
{ 0x5333, 0x88d0, "S3 Vision 964 vers 0" },
{ 0x5333, 0x8a01, "S3 Virge/DX or /GX" },
{ 0x8086, 0x1004, "Intel 82543GC Gigabit Ethernet Controller" },
- { 0x8086, 0x1229, "Intel 82557" },
+ { 0x8086, 0x1029, "Intel EtherExpressPro100 ID1029" },
+ { 0x8086, 0x1030, "Intel Corporation 82559 InBusiness 10/100" },
+ { 0x8086, 0x1209, "Intel EtherExpressPro100 82559ER" },
+ { 0x8086, 0x1229, "Intel EtherExpressPro100 82557/8/9" },
{ 0x8086, 0x122D, "Intel 82437FX" },
{ 0x8086, 0x122E, "Intel 82371FB (PIIX)" },
{ 0x8086, 0x1230, "Intel 82371FB (IDE)" },
{ 0x8086, 0x1237, "Intel 82441FX (440FX)" },
{ 0x8086, 0x1250, "Intel 82439HX" },
+ { 0x8086, 0x2449, "Intel EtherExpressPro100 82562EM" },
{ 0x8086, 0x7000, "Intel 82371SB" },
{ 0x8086, 0x7010, "Intel 82371SB (IDE)" },
{ 0x8086, 0x7020, "Intel 82371SB (USB)" },
+ { 0x8086, 0x7030, "Intel 82437VX" }, /* asw 2005-03-02 */
+ { 0x8086, 0x7100, "Intel 82371AB" }, /* asw 2004-07-31 */
{ 0x8086, 0x7100, "Intel 82371AB" },
{ 0x8086, 0x7110, "Intel 82371AB (PIIX4)" },
{ 0x8086, 0x7111, "Intel 82371AB (IDE)" },
{ 0x8086, 0x7112, "Intel 82371AB (USB)" },
{ 0x8086, 0x7113, "Intel 82371AB (Power)" },
+ { 0x8086, 0x7124, "Intel 82801AA" }, /* asw 2004-11-09 */
{ 0x8086, 0x7190, "Intel 82443BX" },
{ 0x8086, 0x7191, "Intel 82443BX (AGP bridge)" },
{ 0x9004, 0x8178, "Adaptec AHA-2940U/2940UW Ultra/Ultra-Wide SCSI Ctrlr" },
{ 0x8086, 0x122D, }, /* Intel 82437FX */
{ 0x8086, 0x1237, }, /* Intel 82441FX */
{ 0x8086, 0x1250, }, /* Intel 82439HX */
- { 0x8086, 0x7100, }, /* Intel 82371AB */
+ { 0x8086, 0x7030, }, /* Intel 82437VX (asw 2005-03-02) */
+ { 0x8086, 0x7100, }, /* Intel 82371AB (asw 2004-07-31) */
+ { 0x8086, 0x7124, }, /* Intel 82801AA (asw 2004-11-09) */
{ 0x8086, 0x7190, }, /* Intel 82443BX */
{ 0x0000, 0x0000, },
};
{ 0x1106, 0x3227, 1, PCI_IB_VIA, }, /* VIA */
{ 0x8086, 0x122E, 1, PCI_IB_PIIX, }, /* Intel 82371FB */
{ 0x8086, 0x7000, 1, PCI_IB_PIIX, }, /* Intel 82371SB */
- { 0x8086, 0x7100, 1, PCI_IB_PIIX, }, /* Intel 82371AB */
- { 0x8086, 0x7110, 1, PCI_IB_PIIX, }, /* Intel PIIX4 */
+ { 0x8086, 0x7030, 1, PCI_IB_PIIX, }, /* Intel 82437VX (asw 2005-03-02) */
+ { 0x8086, 0x7100, 1, PCI_IB_PIIX, }, /* Intel 82371AB (asw 2004-07-31) */
+ { 0x8086, 0x7110, 1, PCI_IB_PIIX, }, /* Intel PIIX4 */
+ { 0x8086, 0x7124, 1, PCI_IB_PIIX, }, /* Intel 82801AA (asw 2004-11-09) */
{ 0x0000, 0x0000, 0, 0, },
};
&& rdy_head[PPRI_USER] != NIL_PROC))
{
m.NOTIFY_TYPE = HARD_INT;
- int_notify(CLOCK, &m);
+ lock_notify(CLOCK, &m);
}
else if (--sched_ticks <= 0) {
sched_ticks = SCHED_RATE; /* reset the quantum */
*
* As well as several entry points used from the interrupt and task level:
*
- * lock_notify: send a notification to inform a process of a system event
- * int_notify: same as above, but from an interrupt handler (no locking)
+ * lock_notify: notify a process of a system event
* lock_send: send a message to a process
- * lock_ready: put a process on one of the ready queues so it can be run
+ * lock_ready: put a process on one of the ready queues
* lock_unready: remove a process from the ready queues
* lock_sched: a process has run too long; schedule another one
*
int dst; /* to whom is message being sent? */
message *m_ptr; /* pointer to message buffer */
{
-/* Safe gateway to mini_notify() for tasks. Don't use this function from the
- * interrupt level, as it will reenable interrupts (because of the unlock()
- * call). For interrupt handlers, int_notify() is available.
+/* Safe gateway to mini_notify() for tasks and interrupt handlers. MINIX
+ * kernel is not reentrant, which means to interrupts are disabled after
+ * the first kernel entry (hardware interrupt, trap, or exception). Locking
+ * work is done by temporarily disabling interrupts.
*/
int result;
- register struct proc *caller_ptr;
- lock(0, "notify");
- caller_ptr = (k_reenter >= 0) ? proc_addr(HARDWARE) : proc_ptr;
- result = mini_notify(caller_ptr, dst, m_ptr);
- unlock(0);
- return(result);
-}
+ /* Exception or interrupt occurred, thus already locked. */
+ if (k_reenter >= 0) {
+ result = mini_notify(proc_addr(HARDWARE), dst, m_ptr);
+ }
-/*==========================================================================*
- * int_notify *
- *==========================================================================*/
-PUBLIC int int_notify(dst, m_ptr)
-int dst; /* to whom is message being sent? */
-message *m_ptr; /* pointer to message buffer */
-{
-/* Gateway to mini_notify() for interrupt handlers. This function doesn't
- * use lock() and unlock() because interrupts are already disabled.
- */
- int result;
- register struct proc *caller_ptr = proc_addr(HARDWARE);
- result = mini_notify(caller_ptr, dst, m_ptr);
+ /* Call from task level, locking is required. */
+ else {
+ lock(0, "notify");
+ result = mini_notify(proc_ptr, dst, m_ptr);
+ unlock(0);
+ }
return(result);
}
+
/*===========================================================================*
* pick_proc *
*===========================================================================*/
/* proc.c */
_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr) );
_PROTOTYPE( int lock_notify, (int dst, message *m_ptr) );
-_PROTOTYPE( int int_notify, (int dst, message *m_ptr) );
_PROTOTYPE( int lock_send, (int dst, message *m_ptr) );
_PROTOTYPE( void lock_ready, (struct proc *rp) );
_PROTOTYPE( void lock_sched, (int queue) );
/* Build notification message and return. */
m.NOTIFY_TYPE = HARD_INT;
m.NOTIFY_ARG = hook->irq;
- int_notify(hook->proc_nr, &m);
+ lock_notify(hook->proc_nr, &m);
return(hook->policy & IRQ_REENABLE);
}
tmpday = day;
day += (dst->ds_date[2] - firstday + 7) % 7
+ 7 * (dst->ds_date[1] - 1);
- if (day >= tmpday + _ytab[leap][month]) day -= 7;
+ if (day >= tmpday + _ytab[leap][month-1]) day -= 7;
return day;
}
not to the global variable named
.BR x .
.PP
-The only special parameter than can be made local is ``\fB-\fR''.
+The only special parameter that can be made local is ``\fB-\fR''.
Making ``\fB-\fR'' local any shell options that are changed via the
.I set
command inside the function to be restored to their original values
.SH BUGS
When command substitution occurs inside a here document, the commands inside
the here document are run with their standard input closed. For example,
-the following will not word because the standard input of the
+the following will not work because the standard input of the
.I line
command will be closed when the command is run:
.d
What this means is that if you mistype the terminator line, the shell
will silently swallow up the rest of your shell script and stick it
in the here document.
+.\" several minor typos corrected -- ASW 2005-01-15
instead.
.SH "SEE ALSO"
.BR mt (1),
-.BR hd (4),
-.BR sd (4).
+.BR disk (4),
+.BR tape (4).
.SH AUTHOR
Kees J. Bot (kjb@cs.vu.nl)
+
+.\" hd, sd changed to disk, tape -- ASW 2004-12-13
+
+
+
+
.SH "SEE ALSO"
.BR ctags (1),
.BR ref (1),
-.BR virec (1),
+.BR elvrec (1),
.BR elvis (9).
.PP
\fIElvis - A Clone of Vi/Ex\fP, the complete \fBelvis\fP documentation.
Many other people have worked to port \fBelvis\fP to various operating systems.
To see who deserves credit, run the \fB:version\fP command from within \fBelvis\fP,
or look in the system-specific section of the complete documentation.
+.\" ref to virec chnaged to elvrec -- ASW 2004-12-13
library with which to link the scanners.
.SH "SEE ALSO"
.LP
-flexdoc(1), lex(1), yacc(1), sed(1), awk(1).
+flexdoc(1), lex(1), yacc(1), sed(1), awk(9).
.LP
M. E. Lesk and E. Schmidt,
.I LEX - Lexical Analyzer Generator
The
.I flex
internal algorithms need documentation.
+.\" ref. to awk(9) man page corrected -- ASW 2005-01-15
See flex(1).
.SH "SEE ALSO"
.LP
-flex(1), lex(1), yacc(1), sed(1), awk(1).
+flex(1), lex(1), yacc(1), sed(1), awk(9).
.LP
M. E. Lesk and E. Schmidt,
.I LEX - Lexical Analyzer Generator
decvax!cornell!vern
.fi
+.\" ref. to awk(9) man page corrected -- ASW 2005-01-15
.FL "\-r" "Prompt user for repairs if inconsistencies are found
.FL "\-s" "List the superblock of the file system"
.SH EXAMPLES
-.EX "fsck /dev/hd4" "Check file system on \fI/dev/hd4\fR"
+.EX "fsck /dev/c0d0p3" "Check file system on \fI/dev/c0d0p3\fR"
.EX "fsck \-a /dev/at0" "Automatically fix errors on \fI/dev/at0\fR"
.EX "fsck \-l /dev/fd0" "List the contents of \fI/dev/fd0\fR"
-.EX "fsck \-c 2 3 /dev/hd3" "Check and list \fI/dev/hd3\fR i-nodes 2 & 3"
+.EX "fsck \-c 2 3 /dev/c0d0p2" "Check and list \fI/dev/c0d0p2\fR i-nodes 2 & 3"
.SH DESCRIPTION
.PP
\fIFsck\fR performs consistency checks on the file systems which reside
.SH "SEE ALSO"
.BR mkfs (1),
.BR mount (1).
+.\" disk name refs corrected, i.e., old hd1 now c0d0p0 -- ASW 2005-01-15
.SH "SEE ALSO"
.BR sort (1),
.BR comm (1),
-.BR awk (1).
+.BR awk (9).
.SH BUGS
With default field separation,
the collating sequence is that of
.BR uniq ,
.BR look
and
-.BR awk (1)
+.BR awk (9)
are wildly incongruous.
+.\" ref. to awk(9) man page corrected -- ASW 2005-01-15
.BR whatis (1)
to give one line descriptions. See
.BR whatis (5)
-for a desciption of what a whatis database should look like and the
+for a description of what a whatis database should look like and the
restrictions that are placed on the NAME sections so that
.B makewhatis
can make whatis lines out of the manual pages.
enough.
.SH AUTHOR
Kees J. Bot (kjb@cs.vu.nl)
+.\" minor correction -- ASW 2005-01-15
.SH NAME
ps \- process status
.SH SYNOPSIS
-\fBps \fR[\fB\-alxU\fR] [\fBkernel mm fs\fR]\fR
+\fBps \fR[\fR[\fB\-\fR]\fBalx\fR]
.br
.de FL
.TP
.FL "\-l" "Give long listing"
.FL "\-x" "Include processes without a terminal"
.SH EXAMPLES
+.EX "ps " "Show user's own processes in short format"
.EX "ps \-axl" "Print all processes and tasks in long format"
+.EX "ps \axl" "Same -- the '\-' is optional"
.SH DESCRIPTION
.PP
\fIPs\fR prints the status of active processes. Normally only the caller's own
line arguments from. Terminal names in \fI/dev\fR are used to generate the
mnemonic names in the TTY column, so \fIps\fR is independent of terminal naming
conventions.
+.SH NOTES
+The '\-' option prefix is not required.
+For marginal compatibility with System V usage, the hidden option
+.B \-e
+means the same as
+.BR \-ax ,
+and
+.B \-f
+is the same as
+.BR \-l .
+
+.\" edited by ASW 2004-12-14
+
.SH EXAMPLES
.EX "tar c /dev/fd1 ." "Back up current directory to \fI/dev/fd1\fR"
.EX "tar xv /dev/fd1 file1 file2" "Extract two files from the archive"
-.EX "tar cf \- | (cd dest; tar xf \-)" "Copy current directory to \fIdest\fR"
+.EX "tar cf \- . | (cd dest; tar xf \-)" "Copy current directory to \fIdest\fR"
.SH DESCRIPTION
.PP
\fITar\fR is a POSIX-compatible archiver, except that it does not use tape.
.SH "SEE ALSO"
.BR compress (1),
.BR vol (1).
+.\" minor correction ASW 2005-01-15
.TH TOUCH 1
.SH NAME
-touch \- update a file's time of last modification
+touch \- change file access and modification times
.SH SYNOPSIS
-\fBtouch\fR [\fB\-c\fR] \fIfile\fR ...\fR
+\fBtouch\fR [\fB\-c\fR] [\fB\-a\fR] [\fB\-m\fR] [\fB\-r\fR file] [\fB\-t\fR [CC[YY]]MMDDhhmm[.ss]] [MMDDhhmm[YY]] \fIfile\fR ...\fR
.br
.de FL
.TP
# \\$2
..
.SH OPTIONS
-.FL "\-c" "Do not create the file"
+.FL "\-c" "Do not create the file if it doesn't already exist"
+.FL "\-a" "Change access time"
+.FL "\-m" "Change modification time"
+.FL "\-r file" "Apply time of specified file"
+.FL "\-t [CC[YY]]MMDDhhmm[.ss]]" "Apply time specified"
+.FL "\-t [MMDDhhmm[YY]]" "Apply time specified (alternate form)"
.SH EXAMPLES
.EX "touch *.h" "Make the \fI.h\fP files look recent"
+.EX "touch -t 199610010000 *" "Change date and time of all files in current directory to midnight Oct 1, 1996"
.SH DESCRIPTION
-############ NEXT ENTRY HAS NOT BEEN CHECKED #############
.PP
-The time of last modification is set to the current time.
+With no options specified, the times of last modification and last access
+are set to the current time.
This command is mostly used to trick
.I make
into thinking that a file is more recent than it really is.
If the file being touched does not exist, it is created, unless the \fB\-c\fR
flag is present.
+.PP
+The \fB\-a\fR or \fB\-m\fR flag may be used to change only the access or
+modification time. The \fB\-r\fR or \fB\-t\fR flag may be used to change
+the times to match the times of another file or to a specified time.
.SH "SEE ALSO"
.BR utime (2).
+.SH "AUTHOR"
+.PP
+Original author unknown. Rewritten for POSIX by Peter Holzer
+(hp@vmars.tuwien.ac.at).
+.\" man page updated by A. S. Woodhull 2005-01-15
+
+
+