netkit-ftp-0.17/ 40700 144 144 0 7141142001 12711 5ustar dhollandpeoplenetkit-ftp-0.17/ftp/ 40700 144 144 0 7141142002 13503 5ustar dhollandpeoplenetkit-ftp-0.17/ftp/.cvsignore100644 144 144 4 6751156314 15545 0ustar dhollandpeopleftp netkit-ftp-0.17/ftp/Makefile100644 144 144 1240 6750761154 15273 0ustar dhollandpeopleall: ftp include ../MCONFIG include ../MRULES ifeq ($(USE_READLINE),1) CFLAGS += -D__USE_READLINE__ LIBS += -lreadline $(LIBTERMCAP) endif ftp: cmds.o cmdtab.o domacro.o ftp.o glob.o main.o ruserpass.o $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ domacro.o ftp.o glob.o main.o ruserpass.o: ftp_var.h pathnames.h cmds.o cmdtab.o: ftp_var.h pathnames.h cmds.h cmds.o glob.o: glob.h install: ftp install -s -m$(BINMODE) ftp $(INSTALLROOT)$(BINDIR) ln -sf ftp $(INSTALLROOT)$(BINDIR)/pftp install -m$(MANMODE) ftp.1 $(INSTALLROOT)$(MANDIR)/man1 ln -sf ftp.1 $(INSTALLROOT)$(MANDIR)/man1/pftp.1 install -m$(MANMODE) netrc.5 $(INSTALLROOT)$(MANDIR)/man5 clean: rm -f *.o ftp netkit-ftp-0.17/ftp/cmds.c100644 144 144 132752 7136446073 15001 0ustar dhollandpeople/* * Copyright (c) 1985, 1989 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ /* * from: @(#)cmds.c 5.26 (Berkeley) 3/5/91 */ char cmds_rcsid[] = "$Id: cmds.c,v 1.33 2000/07/23 01:36:59 dholland Exp $"; /* * FTP User Program -- Command Routines. */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* for PATH_MAX */ #include #include #include #ifdef __USE_READLINE__ #include #include #endif #include "ftp_var.h" #include "pathnames.h" #include "cmds.h" #include "glob.h" void intr(int); extern FILE *cout; extern int data; extern const char *home; extern off_t restart_point; extern char reply_string[]; static char *mname; static sigjmp_buf jabort; static sigjmp_buf abortprox; static char *remglob(char *argv[], int doswitch); static int checkglob(int fd, const char *pattern); static char *dotrans(char *name); static char *domap(char *name); static char *globulize(char *str); static int confirm(const char *cmd, const char *file); static int getit(int argc, char *argv[], int restartit, const char *modestr); static void quote1(const char *initial, int argc, char **argv); /* * pipeprotect: protect against "special" local filenames by prepending * "./". Special local filenames are "-" and "|..." AND "/...". */ static char *pipeprotect(char *name) { char *nu; if (strcmp(name, "-") && *name!='|' && *name!='/') { return name; } /* We're going to leak this memory. XXX. */ nu = malloc(strlen(name)+3); if (nu==NULL) { perror("malloc"); code = -1; return NULL; } strcpy(nu, "."); if (*name != '/') strcat(nu, "/"); strcat(nu, name); return nu; } /* * Look for embedded ".." in a pathname and change it to "!!", printing * a warning. */ static char *pathprotect(char *name) { int gotdots=0, i, len; /* Convert null terminator to trailing / to catch a trailing ".." */ len = strlen(name)+1; name[len-1] = '/'; /* * State machine loop. gotdots is < 0 if not looking at dots, * 0 if we just saw a / and thus might start getting dots, * and the count of dots seen so far if we have seen some. */ for (i=0; i=0) gotdots++; else if (name[i]=='/' && gotdots<0) gotdots=0; else if (name[i]=='/' && gotdots==2) { printf("Warning: embedded .. in %.*s (changing to !!)\n", len-1, name); name[i-1] = '!'; name[i-2] = '!'; gotdots = 0; } else if (name[i]=='/') gotdots = 0; else gotdots = -1; } name[len-1] = 0; return name; } /* * `Another' gets another argument, and stores the new argc and argv. * It reverts to the top level (via main.c's intr()) on EOF/error. * * Returns false if no new arguments have been added. */ int another(int *pargc, char ***pargv, const char *prompt) { int margc; char **margv; unsigned len = strlen(line); int ret; if (len >= sizeof(line) - 3) { printf("sorry, arguments too long\n"); intr(0); } printf("(%s) ", prompt); line[len++] = ' '; if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) intr(0); len += strlen(&line[len]); if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0'; margv = makeargv(&margc, NULL); ret = margc > *pargc; *pargc = margc; *pargv = margv; return ret; } /* * Connect to peer server and * auto-login, if possible. */ void setpeer(int argc, char *argv[]) { char *host; unsigned short port; if (connected) { printf("Already connected to %s, use close first.\n", hostname); code = -1; return; } if (argc < 2) (void) another(&argc, &argv, "to"); if (argc < 2 || argc > 3) { printf("usage: %s host-name [port]\n", argv[0]); code = -1; return; } port = ftp_port; if (argc > 2) { port = atoi(argv[2]); if (port < 1) { printf("%s: bad port number-- %s\n", argv[1], argv[2]); printf ("usage: %s host-name [port]\n", argv[0]); code = -1; return; } port = htons(port); } host = hookup(argv[1], port); if (host) { int overbose; connected = 1; /* * Set up defaults for FTP. */ (void) strcpy(typename, "ascii"), type = TYPE_A; curtype = TYPE_A; (void) strcpy(formname, "non-print"), form = FORM_N; (void) strcpy(modename, "stream"), mode = MODE_S; (void) strcpy(structname, "file"), stru = STRU_F; (void) strcpy(bytename, "8"), bytesize = 8; if (autologin) (void) dologin(argv[1]); #if defined(__unix__) && CHAR_BIT == 8 /* * this ifdef is to keep someone form "porting" this to an incompatible * system and not checking this out. This way they have to think about it. */ overbose = verbose; if (debug == 0) verbose = -1; if (command("SYST") == COMPLETE && overbose) { register char *cp, c = 0; cp = index(reply_string+4, ' '); if (cp == NULL) cp = index(reply_string+4, '\r'); if (cp) { if (cp[-1] == '.') cp--; c = *cp; *cp = '\0'; } printf("Remote system type is %s.\n", reply_string+4); if (cp) *cp = c; } if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { if (proxy) unix_proxy = 1; else unix_server = 1; /* * Set type to 0 (not specified by user), * meaning binary by default, but don't bother * telling server. We can use binary * for text files unless changed by the user. */ type = 0; (void) strcpy(typename, "binary"); if (overbose) printf("Using %s mode to transfer files.\n", typename); } else { if (proxy) unix_proxy = 0; else unix_server = 0; if (overbose && !strncmp(reply_string, "215 TOPS20", 10)) printf( "Remember to set tenex mode when transfering binary files from this machine.\n"); } verbose = overbose; #else #warning "Unix auto-mode code skipped" #endif /* unix */ } } struct types { const char *t_name; const char *t_mode; int t_type; const char *t_arg; } types[] = { { "ascii", "A", TYPE_A, NULL }, { "binary", "I", TYPE_I, NULL }, { "image", "I", TYPE_I, NULL }, { "ebcdic", "E", TYPE_E, NULL }, { "tenex", "L", TYPE_L, bytename }, { NULL, NULL, 0, NULL } }; /* * Set transfer type. */ static void do_settype(const char *thetype) { struct types *p; int comret; for (p = types; p->t_name; p++) if (strcmp(thetype, p->t_name) == 0) break; if (p->t_name == 0) { printf("%s: unknown mode\n", thetype); code = -1; return; } if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) comret = command("TYPE %s %s", p->t_mode, p->t_arg); else comret = command("TYPE %s", p->t_mode); if (comret == COMPLETE) { (void) strcpy(typename, p->t_name); curtype = type = p->t_type; } } void settype(int argc, char *argv[]) { struct types *p; if (argc > 2) { const char *sep; printf("usage: %s [", argv[0]); sep = " "; for (p = types; p->t_name; p++) { printf("%s%s", sep, p->t_name); sep = " | "; } printf(" ]\n"); code = -1; return; } if (argc < 2) { printf("Using %s mode to transfer files.\n", typename); code = 0; return; } do_settype(argv[1]); } /* * Internal form of settype; changes current type in use with server * without changing our notion of the type for data transfers. * Used to change to and from ascii for listings. */ void changetype(int newtype, int show) { register struct types *p; int comret, oldverbose = verbose; int oldtick = tick; if (newtype == 0) newtype = TYPE_I; if (newtype == curtype) return; if (debug == 0 && show == 0) verbose = 0; tick = 0; for (p = types; p->t_name; p++) if (newtype == p->t_type) break; if (p->t_name == 0) { printf("ftp: internal error: unknown type %d\n", newtype); return; } if (newtype == TYPE_L && bytename[0] != '\0') comret = command("TYPE %s %s", p->t_mode, bytename); else comret = command("TYPE %s", p->t_mode); if (comret == COMPLETE) curtype = newtype; verbose = oldverbose; tick = oldtick; } /* * Set binary transfer type. */ /*VARARGS*/ void setbinary(void) { do_settype("binary"); } /* * Set ascii transfer type. */ /*VARARGS*/ void setascii(void) { do_settype("ascii"); } /* * Set tenex transfer type. */ /*VARARGS*/ void settenex(void) { do_settype("tenex"); } /* * Set file transfer mode. */ /*ARGSUSED*/ void setmode(void) { printf("We only support %s mode, sorry.\n", modename); code = -1; } /* * Set file transfer format. */ /*ARGSUSED*/ void setform(void) { printf("We only support %s format, sorry.\n", formname); code = -1; } /* * Set file transfer structure. */ void setstruct(void) { printf("We only support %s structure, sorry.\n", structname); code = -1; } /* * Send a single file. */ void put(int argc, char *argv[]) { const char *cmd; int loc = 0; char *oldargv1, *oldargv2; if (argc == 2) { argc++; argv[2] = argv[1]; loc++; } if (argc < 2 && !another(&argc, &argv, "local-file")) goto usage; if (argc < 3 && !another(&argc, &argv, "remote-file")) { usage: printf("usage: %s local-file remote-file\n", argv[0]); code = -1; return; } oldargv1 = argv[1]; oldargv2 = argv[2]; argv[1] = globulize(argv[1]); if (!argv[1]) { code = -1; return; } /* * If "globulize" modifies argv[1], and argv[2] is a copy of * the old argv[1], make it a copy of the new argv[1]. */ if (argv[1] != oldargv1 && argv[2] == oldargv1) { argv[2] = argv[1]; } cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); if (loc && ntflag) { argv[2] = dotrans(argv[2]); } if (loc && mapflag) { argv[2] = domap(argv[2]); } sendrequest(cmd, argv[1], argv[2], argv[1] != oldargv1 || argv[2] != oldargv2); } void mabort(int); /* * Send multiple files. */ void mput(int argc, char *argv[]) { register int i; void (*oldintr)(int); int ointer; char *tp; if (argc < 2 && !another(&argc, &argv, "local-files")) { printf("usage: %s local-files\n", argv[0]); code = -1; return; } mname = argv[0]; mflag = 1; oldintr = signal(SIGINT, mabort); (void) sigsetjmp(jabort, 1); if (proxy) { char *cp, *tp2, tmpbuf[PATH_MAX]; while ((cp = remglob(argv,0)) != NULL) { if (*cp == 0) { mflag = 0; continue; } if (mflag && confirm(argv[0], cp)) { tp = cp; if (mcase) { while (*tp && !islower(*tp)) { tp++; } if (!*tp) { tp = cp; tp2 = tmpbuf; while ((*tp2 = *tp) != '\0') { if (isupper(*tp2)) { *tp2 = 'a' + *tp2 - 'A'; } tp++; tp2++; } } tp = tmpbuf; } if (ntflag) { tp = dotrans(tp); } if (mapflag) { tp = domap(tp); } sendrequest((sunique) ? "STOU" : "STOR", cp, tp, cp != tp || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mput")) { mflag++; } interactive = ointer; } } } (void) signal(SIGINT, oldintr); mflag = 0; return; } for (i = 1; i < argc; i++) { register char **cpp, **gargs; if (!doglob) { if (mflag && confirm(argv[0], argv[i])) { tp = (ntflag) ? dotrans(argv[i]) : argv[i]; tp = (mapflag) ? domap(tp) : tp; sendrequest((sunique) ? "STOU" : "STOR", argv[i], tp, tp != argv[i] || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mput")) { mflag++; } interactive = ointer; } } continue; } gargs = ftpglob(argv[i]); if (globerr != NULL) { printf("%s\n", globerr); if (gargs) { blkfree(gargs); free((char *)gargs); } continue; } for (cpp = gargs; cpp && *cpp != NULL; cpp++) { if (mflag && confirm(argv[0], *cpp)) { tp = (ntflag) ? dotrans(*cpp) : *cpp; tp = (mapflag) ? domap(tp) : tp; sendrequest((sunique) ? "STOU" : "STOR", *cpp, tp, *cpp != tp || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mput")) { mflag++; } interactive = ointer; } } } if (gargs != NULL) { blkfree(gargs); free((char *)gargs); } } (void) signal(SIGINT, oldintr); mflag = 0; } void reget(int argc, char *argv[]) { (void) getit(argc, argv, 1, "r+w"); } void get(int argc, char *argv[]) { (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" ); } /* * Receive one file. */ static int getit(int argc, char *argv[], int restartit, const char *modestr) { int loc = 0; char *oldargv1, *oldargv2; if (argc == 2) { argc++; /* * Protect the user from accidentally retrieving special * local names. */ argv[2] = pipeprotect(argv[1]); if (!argv[2]) { code = -1; return 0; } loc++; } if (argc < 2 && !another(&argc, &argv, "remote-file")) goto usage; if (argc < 3 && !another(&argc, &argv, "local-file")) { usage: printf("usage: %s remote-file [ local-file ]\n", argv[0]); code = -1; return (0); } oldargv1 = argv[1]; oldargv2 = argv[2]; argv[2] = globulize(argv[2]); if (!argv[2]) { code = -1; return (0); } if (loc && mcase) { char *tp = argv[1], *tp2, tmpbuf[PATH_MAX]; while (*tp && !islower(*tp)) { tp++; } if (!*tp) { tp = argv[2]; tp2 = tmpbuf; while ((*tp2 = *tp) != '\0') { if (isupper(*tp2)) { *tp2 = 'a' + *tp2 - 'A'; } tp++; tp2++; } argv[2] = tmpbuf; } } if (loc && ntflag) argv[2] = dotrans(argv[2]); if (loc && mapflag) argv[2] = domap(argv[2]); if (restartit) { struct stat stbuf; int ret; ret = stat(argv[2], &stbuf); if (restartit == 1) { if (ret < 0) { fprintf(stderr, "local: %s: %s\n", argv[2], strerror(errno)); return (0); } restart_point = stbuf.st_size; } else { if (ret == 0) { int overbose; overbose = verbose; if (debug == 0) verbose = -1; if (command("MDTM %s", argv[1]) == COMPLETE) { int yy, mo, day, hour, min, sec; struct tm *tm; verbose = overbose; sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, &day, &hour, &min, &sec); tm = gmtime(&stbuf.st_mtime); tm->tm_mon++; /* Indentation is misleading, but changes keep small. */ /* * I think the indentation and braces are now correct. Whoever put this * in the way it was originally should be prohibited by law. */ if (tm->tm_year+1900 > yy) return (1); if (tm->tm_year+1900 == yy) { if (tm->tm_mon > mo) return (1); if (tm->tm_mon == mo) { if (tm->tm_mday > day) return (1); if (tm->tm_mday == day) { if (tm->tm_hour > hour) return (1); if (tm->tm_hour == hour) { if (tm->tm_min > min) return (1); if (tm->tm_min == min) { if (tm->tm_sec > sec) return (1); } } } } } } else { printf("%s\n", reply_string); verbose = overbose; return (0); } } } } recvrequest("RETR", argv[2], argv[1], modestr, argv[1] != oldargv1 || argv[2] != oldargv2); restart_point = 0; return (0); } void mabort(int ignore) { int ointer; (void)ignore; printf("\n"); (void) fflush(stdout); if (mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with", mname)) { interactive = ointer; siglongjmp(jabort,0); } interactive = ointer; } mflag = 0; siglongjmp(jabort,0); } /* * Get multiple files. */ void mget(int argc, char **argv) { void (*oldintr)(int); int ointer; char *cp, *tp, *tp2, tmpbuf[PATH_MAX]; if (argc < 2 && !another(&argc, &argv, "remote-files")) { printf("usage: %s remote-files\n", argv[0]); code = -1; return; } mname = argv[0]; mflag = 1; oldintr = signal(SIGINT,mabort); (void) sigsetjmp(jabort, 1); while ((cp = remglob(argv,proxy)) != NULL) { if (*cp == '\0') { mflag = 0; continue; } if (mflag && confirm(argv[0], cp)) { tp = cp; if (mcase) { while (*tp && !islower(*tp)) { tp++; } if (!*tp) { tp = cp; tp2 = tmpbuf; while ((*tp2 = *tp) != '\0') { if (isupper(*tp2)) { *tp2 = 'a' + *tp2 - 'A'; } tp++; tp2++; } } tp = tmpbuf; } if (ntflag) { tp = dotrans(tp); } if (mapflag) { tp = domap(tp); } /* Reject embedded ".." */ tp = pathprotect(tp); /* Prepend ./ to "-" or "!*" or leading "/" */ tp = pipeprotect(tp); if (tp == NULL) { /* hmm... how best to handle this? */ mflag = 0; } else { recvrequest("RETR", tp, cp, "w", tp != cp || !interactive); } if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with","mget")) { mflag++; } interactive = ointer; } } } (void) signal(SIGINT,oldintr); mflag = 0; } char * remglob(char *argv[], int doswitch) { char temp[16]; static char buf[PATH_MAX]; static FILE *ftemp = NULL; static char **args; int oldverbose, oldhash, badglob = 0; char *cp; if (!mflag) { if (!doglob) { args = NULL; } else { if (ftemp) { (void) fclose(ftemp); ftemp = NULL; } } return(NULL); } if (!doglob) { if (args == NULL) args = argv; if ((cp = *++args) == NULL) args = NULL; return (cp); } if (ftemp == NULL) { int oldumask, fd; (void) strcpy(temp, _PATH_TMP); /* libc 5.2.18 creates with mode 0666, which is dumb */ oldumask = umask(077); fd = mkstemp(temp); umask(oldumask); if (fd<0) { printf("Error creating temporary file, oops\n"); return NULL; } oldverbose = verbose, verbose = 0; oldhash = hash, hash = 0; if (doswitch) { pswitch(!proxy); } while (*++argv != NULL) { int dupfd = dup(fd); recvrequest ("NLST", temp, *argv, "a", 0); if (!checkglob(dupfd, *argv)) { badglob = 1; break; } } unlink(temp); if (doswitch) { pswitch(!proxy); } verbose = oldverbose; hash = oldhash; if (badglob) { printf("Refusing to handle insecure file list\n"); close(fd); return NULL; } ftemp = fdopen(fd, "r"); if (ftemp == NULL) { printf("fdopen failed, oops\n"); return NULL; } rewind(ftemp); } if (fgets(buf, sizeof (buf), ftemp) == NULL) { (void) fclose(ftemp), ftemp = NULL; return (NULL); } if ((cp = index(buf, '\n')) != NULL) *cp = '\0'; return (buf); } /* * Check whether given pattern matches `..' * We assume only a glob pattern starting with a dot will match * dot entries on the server. */ static int isdotdotglob(const char *pattern) { int havedot = 0; char c; if (*pattern++ != '.') return 0; while ((c = *pattern++) != '\0' && c != '/') { if (c == '*' || c == '?') continue; if (c == '.' && havedot++) return 0; } return 1; } /* * This function makes sure the list of globbed files returned from * the server doesn't contain anything dangerous such as * /home//.forward, or ../.forward, * or |mail foe@doe = MAXPATHLEN) { printf("Incredible pattern: %s\n", pattern); return 0; } dotdot[nrslash++] = isdotdotglob(sp); } fp = fdopen(fd, "r"); while (okay && fgets(buffer, sizeof(buffer), fp) != NULL) { char *sp; if ((sp = strchr(buffer, '\n')) != 0) { *sp = '\0'; } else { printf("Extremely long filename from server: %s", buffer); okay = 0; break; } if (buffer[0] == '|' || (buffer[0] != '/' && initial) || (buffer[0] == '/' && !initial)) okay = 0; for (sp = buffer, nr = 0; sp; sp = strchr(sp, '/'), nr++) { while (*sp == '/') sp++; if (sp[0] == '.' && !strncmp(sp, "../", 3) && (nr >= nrslash || !dotdot[nr])) okay = 0; } } if (!okay) printf("Filename provided by server " "doesn't match pattern `%s': %s\n", pattern, buffer); fclose(fp); return okay; } static const char * onoff(int bool) { return (bool ? "on" : "off"); } /* * Show status. */ void status(void) { int i; if (connected) printf("Connected to %s.\n", hostname); else printf("Not connected.\n"); if (!proxy) { pswitch(1); if (connected) { printf("Connected for proxy commands to %s.\n", hostname); } else { printf("No proxy connection.\n"); } pswitch(0); } printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", modename, typename, formname, structname); printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), onoff(runique)); printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); if (ntflag) { printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); } else { printf("Ntrans: off\n"); } if (mapflag) { printf("Nmap: (in) %s (out) %s\n", mapin, mapout); } else { printf("Nmap: off\n"); } printf("Hash mark printing: %s; Use of PORT cmds: %s\n", onoff(hash), onoff(sendport)); printf("Tick counter printing: %s\n", onoff(tick)); if (macnum > 0) { printf("Macros:\n"); for (i=0; i 1) { val = atoi(argv[1]); if (val < 0) { printf("%s: bad debugging value.\n", argv[1]); code = -1; return; } } else val = !debug; debug = val; if (debug) options |= SO_DEBUG; else options &= ~SO_DEBUG; printf("Debugging %s (debug=%d).\n", onoff(debug), debug); code = debug > 0; } /* * Set current working directory * on remote machine. */ void cd(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "remote-directory")) { printf("usage: %s remote-directory\n", argv[0]); code = -1; return; } if (command("CWD %s", argv[1]) == ERROR && code == 500) { if (verbose) printf("CWD command not recognized, trying XCWD\n"); (void) command("XCWD %s", argv[1]); } } /* * Set current working directory * on local machine. */ void lcd(int argc, char *argv[]) { char buf[PATH_MAX]; const char *dir = NULL; if (argc == 1) { /*dir = home;*/ dir = "."; } else if (argc != 2) { printf("usage: %s local-directory\n", argv[0]); code = -1; return; } else { dir = globulize(argv[1]); } if (!dir) { code = -1; return; } if (chdir(dir) < 0) { fprintf(stderr, "local: %s: %s\n", dir, strerror(errno)); code = -1; return; } if (!getcwd(buf, sizeof(buf))) { if (errno==ERANGE) strcpy(buf, ""); else strcpy(buf, "???"); } printf("Local directory now %s\n", buf); code = 0; } /* * Delete a single file. */ void delete_cmd(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "remote-file")) { printf("usage: %s remote-file\n", argv[0]); code = -1; return; } (void) command("DELE %s", argv[1]); } /* * Delete multiple files. */ void mdelete(int argc, char *argv[]) { void (*oldintr)(int); int ointer; char *cp; if (argc < 2 && !another(&argc, &argv, "remote-files")) { printf("usage: %s remote-files\n", argv[0]); code = -1; return; } mname = argv[0]; mflag = 1; oldintr = signal(SIGINT, mabort); (void) sigsetjmp(jabort, 1); while ((cp = remglob(argv,0)) != NULL) { if (*cp == '\0') { mflag = 0; continue; } if (mflag && confirm(argv[0], cp)) { (void) command("DELE %s", cp); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with", "mdelete")) { mflag++; } interactive = ointer; } } } (void) signal(SIGINT, oldintr); mflag = 0; } /* * Rename a remote file. */ void renamefile(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "from-name")) goto usage; if (argc < 3 && !another(&argc, &argv, "to-name")) { usage: printf("%s from-name to-name\n", argv[0]); code = -1; return; } if (command("RNFR %s", argv[1]) == CONTINUE) (void) command("RNTO %s", argv[2]); } /* * Get a directory listing * of remote files. */ void ls(int argc, char *argv[]) { static char foo[2] = "-"; const char *cmd; if (argc < 2) { argc++, argv[1] = NULL; } if (argc < 3) { argc++, argv[2] = foo; } if (argc > 3) { printf("usage: %s remote-directory local-file\n", argv[0]); code = -1; return; } cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; if (strcmp(argv[2], "-") && (argv[2] = globulize(argv[2]))==NULL) { code = -1; return; } if (strcmp(argv[2], "-") && *argv[2] != '|') if ((argv[2] = globulize(argv[2]))==NULL || !confirm("output to local-file:", argv[2])) { code = -1; return; } recvrequest(cmd, argv[2], argv[1], "w", 0); } /* * Get a directory listing * of multiple remote files. */ void mls(int argc, char *argv[]) { void (*oldintr)(int); int ointer, i; const char *volatile cmd; char *volatile dest; const char *modestr; if (argc < 2 && !another(&argc, &argv, "remote-files")) goto usage; if (argc < 3 && !another(&argc, &argv, "local-file")) { usage: printf("usage: %s remote-files local-file\n", argv[0]); code = -1; return; } dest = argv[argc - 1]; argv[argc - 1] = NULL; if (strcmp(dest, "-") && *dest != '|') if ((dest = globulize(dest))==NULL || !confirm("output to local-file:", dest)) { code = -1; return; } cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; mname = argv[0]; mflag = 1; oldintr = signal(SIGINT, mabort); /* * This just plain seems wrong. */ (void) sigsetjmp(jabort, 1); for (i = 1; mflag && i < argc-1; ++i) { modestr = (i == 1) ? "w" : "a"; recvrequest(cmd, dest, argv[i], modestr, 0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; if (confirm("Continue with", argv[0])) { mflag ++; } interactive = ointer; } } (void) signal(SIGINT, oldintr); mflag = 0; } /* * Do a shell escape */ void shell(const char *arg) { int pid; void (*old1)(int); void (*old2)(int); char shellnam[40]; const char *theshell, *namep; old1 = signal (SIGINT, SIG_IGN); old2 = signal (SIGQUIT, SIG_IGN); if ((pid = fork()) == 0) { for (pid = 3; pid < 20; pid++) (void) close(pid); (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); theshell = getenv("SHELL"); if (theshell == NULL) theshell = _PATH_BSHELL; namep = strrchr(theshell, '/'); if (namep == NULL) namep = theshell; else namep++; (void) strcpy(shellnam,"-"); (void) strcat(shellnam, namep); if (strcmp(namep, "sh") != 0) shellnam[0] = '+'; if (debug) { printf("%s\n", theshell); (void) fflush (stdout); } if (arg) { execl(theshell, shellnam, "-c", arg, NULL); } else { execl(theshell, shellnam, NULL); } perror(theshell); code = -1; exit(1); } if (pid > 0) while (wait(NULL) != pid); (void) signal(SIGINT, old1); (void) signal(SIGQUIT, old2); if (pid == -1) { perror("Try again later"); code = -1; } else { code = 0; } } /* * Send new user information (re-login) */ void user(int argc, char *argv[]) { char theacct[80]; int n, aflag = 0; if (argc < 2) (void) another(&argc, &argv, "username"); if (argc < 2 || argc > 4) { printf("usage: %s username [password] [account]\n", argv[0]); code = -1; return; } n = command("USER %s", argv[1]); if (n == CONTINUE) { if (argc < 3 ) argv[2] = getpass("Password: "), argc++; n = command("PASS %s", argv[2]); } if (n == CONTINUE) { if (argc < 4) { printf("Account: "); (void) fflush(stdout); fgets(theacct, sizeof(theacct), stdin); argv[3] = theacct; argc++; } n = command("ACCT %s", argv[3]); aflag++; } if (n != COMPLETE) { fprintf(stdout, "Login failed.\n"); return; } if (!aflag && argc == 4) { (void) command("ACCT %s", argv[3]); } } /* * Print working directory. */ void pwd(void) { int oldverbose = verbose; /* * If we aren't verbose, this doesn't do anything! */ verbose = 1; if (command("PWD") == ERROR && code == 500) { printf("PWD command not recognized, trying XPWD\n"); (void) command("XPWD"); } verbose = oldverbose; } /* * Make a directory. */ void makedir(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "directory-name")) { printf("usage: %s directory-name\n", argv[0]); code = -1; return; } if (command("MKD %s", argv[1]) == ERROR && code == 500) { if (verbose) printf("MKD command not recognized, trying XMKD\n"); (void) command("XMKD %s", argv[1]); } } /* * Remove a directory. */ void removedir(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "directory-name")) { printf("usage: %s directory-name\n", argv[0]); code = -1; return; } if (command("RMD %s", argv[1]) == ERROR && code == 500) { if (verbose) printf("RMD command not recognized, trying XRMD\n"); (void) command("XRMD %s", argv[1]); } } /* * Send a line, verbatim, to the remote machine. */ void quote(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "command line to send")) { printf("usage: %s line-to-send\n", argv[0]); code = -1; return; } quote1("", argc, argv); } /* * Send a SITE command to the remote machine. The line * is sent verbatim to the remote machine, except that the * word "SITE" is added at the front. */ void site(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { printf("usage: %s line-to-send\n", argv[0]); code = -1; return; } quote1("SITE ", argc, argv); } /* * Turn argv[1..argc) into a space-separated string, then prepend initial text. * Send the result as a one-line command and get response. */ static void quote1(const char *initial, int argc, char **argv) { register int i, len; char buf[BUFSIZ]; /* must be >= sizeof(line) */ (void) strcpy(buf, initial); if (argc > 1) { len = strlen(buf); len += strlen(strcpy(&buf[len], argv[1])); for (i = 2; i < argc; i++) { buf[len++] = ' '; len += strlen(strcpy(&buf[len], argv[i])); } } if (command("%s", buf) == PRELIM) { while (getreply(0) == PRELIM); } } void do_chmod(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "mode")) goto usage; if (argc < 3 && !another(&argc, &argv, "file-name")) { usage: printf("usage: %s mode file-name\n", argv[0]); code = -1; return; } (void) command("SITE CHMOD %s %s", argv[1], argv[2]); } void do_umask(int argc, char *argv[]) { int oldverbose = verbose; verbose = 1; (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); verbose = oldverbose; } void idle_cmd(int argc, char *argv[]) { int oldverbose = verbose; verbose = 1; (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); verbose = oldverbose; } /* * Ask the other side for help. */ void rmthelp(int argc, char *argv[]) { int oldverbose = verbose; verbose = 1; (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); verbose = oldverbose; } /* * Terminate session and exit. */ void quit(void) { if (connected) disconnect(); pswitch(1); if (connected) { disconnect(); } exit(0); } /* * Terminate session, but don't exit. */ void disconnect(void) { if (!connected) return; (void) command("QUIT"); if (cout) { (void) fclose(cout); } cout = NULL; connected = 0; data = -1; if (!proxy) { macnum = 0; } } static int confirm(const char *cmd, const char *file) { char lyne[BUFSIZ]; if (!interactive) return (1); #ifdef __USE_READLINE__ if (fromatty && !rl_inhibit) { char *lineread; snprintf(lyne, BUFSIZ, "%s %s? ", cmd, file); lineread = readline(lyne); if (!lineread) return 0; strcpy(lyne, lineread); free(lineread); } else { #endif printf("%s %s? ", cmd, file); fflush(stdout); if (fgets(lyne, sizeof(lyne), stdin) == NULL) { return 0; } #ifdef __USE_READLINE__ } #endif return (*lyne != 'n' && *lyne != 'N'); } void fatal(const char *msg) { fprintf(stderr, "ftp: %s\n", msg); exit(1); } /* * Glob a local file name specification with * the expectation of a single return value. * Can't control multiple values being expanded * from the expression, we return only the first. */ static char * globulize(char *cpp) { char **globbed; char *rv = cpp; if (!doglob) return cpp; globbed = ftpglob(cpp); if (globerr != NULL) { printf("%s: %s\n", cpp, globerr); if (globbed) { blkfree(globbed); free(globbed); } return NULL; } if (globbed) { rv = globbed[0]; /* don't waste too much memory */ if (globbed[0]) { blkfree(globbed+1); } free(globbed); } return rv; } void account(int argc, char *argv[]) { char buf[128], *ap; if (argc > 1) { *buf = 0; while (argc > 1) { --argc; ++argv; strncat(buf, *argv, sizeof(buf)-strlen(buf)); buf[sizeof(buf)-1] = 0; } ap = buf; } else { ap = getpass("Account:"); } command("ACCT %s", ap); } static void proxabort(int ignore) { (void)ignore; if (!proxy) { pswitch(1); } if (connected) { proxflag = 1; } else { proxflag = 0; } pswitch(0); siglongjmp(abortprox,1); } void doproxy(int argc, char *argv[]) { register struct cmd *c; void (*oldintr)(int); if (argc < 2 && !another(&argc, &argv, "command")) { printf("usage: %s command\n", argv[0]); code = -1; return; } c = getcmd(argv[1]); if (c == (struct cmd *) -1) { printf("?Ambiguous command\n"); (void) fflush(stdout); code = -1; return; } if (c == 0) { printf("?Invalid command\n"); (void) fflush(stdout); code = -1; return; } if (!c->c_proxy) { printf("?Invalid proxy command\n"); (void) fflush(stdout); code = -1; return; } if (sigsetjmp(abortprox, 1)) { code = -1; return; } oldintr = signal(SIGINT, proxabort); pswitch(1); if (c->c_conn && !connected) { printf("Not connected\n"); (void) fflush(stdout); pswitch(0); (void) signal(SIGINT, oldintr); code = -1; return; } if (c->c_handler_v) c->c_handler_v(argc-1, argv+1); else if (c->c_handler_0) c->c_handler_0(); else c->c_handler_1(NULL); /* should not reach this */ if (connected) { proxflag = 1; } else { proxflag = 0; } pswitch(0); (void) signal(SIGINT, oldintr); } void setcase(void) { mcase = !mcase; printf("Case mapping %s.\n", onoff(mcase)); code = mcase; } void setcr(void) { crflag = !crflag; printf("Carriage Return stripping %s.\n", onoff(crflag)); code = crflag; } void setntrans(int argc, char *argv[]) { if (argc == 1) { ntflag = 0; printf("Ntrans off.\n"); code = ntflag; return; } ntflag++; code = ntflag; (void) strncpy(ntin, argv[1], 16); ntin[16] = '\0'; if (argc == 2) { ntout[0] = '\0'; return; } (void) strncpy(ntout, argv[2], 16); ntout[16] = '\0'; } static char * dotrans(char *name) { static char new[PATH_MAX]; char *cp1, *cp2 = new; register int i, ostop, found; for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++); for (cp1 = name; *cp1; cp1++) { found = 0; for (i = 0; *(ntin + i) && i < 16; i++) { if (*cp1 == *(ntin + i)) { found++; if (i < ostop) { *cp2++ = *(ntout + i); } break; } } if (!found) { *cp2++ = *cp1; } } *cp2 = '\0'; return(new); } void setnmap(int argc, char *argv[]) { char *cp; if (argc == 1) { mapflag = 0; printf("Nmap off.\n"); code = mapflag; return; } if (argc < 3 && !another(&argc, &argv, "mapout")) { printf("Usage: %s [mapin mapout]\n",argv[0]); code = -1; return; } mapflag = 1; code = 1; cp = index(altarg, ' '); if (proxy) { while(*++cp == ' '); altarg = cp; cp = index(altarg, ' '); } *cp = '\0'; (void) strncpy(mapin, altarg, PATH_MAX - 1); mapin[PATH_MAX-1] = 0; while (*++cp == ' '); (void) strncpy(mapout, cp, PATH_MAX - 1); mapout[PATH_MAX-1] = 0; } static char * domap(char *name) { static char new[PATH_MAX]; register char *cp1 = name, *cp2 = mapin; char *tp[9], *te[9]; int i, toks[9], toknum = 0, match = 1; for (i=0; i < 9; ++i) { toks[i] = 0; } while (match && *cp1 && *cp2) { switch (*cp2) { case '\\': if (*++cp2 != *cp1) { match = 0; } break; case '$': if (*(cp2+1) >= '1' && *(cp2+1) <= '9') { if (*cp1 != *(++cp2+1)) { toknum = *cp2 - '1'; toks[toknum]++; tp[toknum] = cp1; while (*++cp1 && *(cp2+1) != *cp1); te[toknum] = cp1; } cp2++; break; } /* FALLTHROUGH */ default: if (*cp2 != *cp1) { match = 0; } break; } if (match && *cp1) { cp1++; } if (match && *cp2) { cp2++; } } if (!match && *cp1) /* last token mismatch */ { toks[toknum] = 0; } cp1 = new; *cp1 = '\0'; cp2 = mapout; while (*cp2) { match = 0; switch (*cp2) { case '\\': if (*(cp2 + 1)) { *cp1++ = *++cp2; } break; case '[': LOOP: if (*++cp2 == '$' && isdigit(*(cp2+1))) { if (*++cp2 == '0') { char *cp3 = name; while (*cp3) { *cp1++ = *cp3++; } match = 1; } else if (toks[toknum = *cp2 - '1']) { char *cp3 = tp[toknum]; while (cp3 != te[toknum]) { *cp1++ = *cp3++; } match = 1; } } else { while (*cp2 && *cp2 != ',' && *cp2 != ']') { if (*cp2 == '\\') { cp2++; } else if (*cp2 == '$' && isdigit(*(cp2+1))) { if (*++cp2 == '0') { char *cp3 = name; while (*cp3) { *cp1++ = *cp3++; } } else if (toks[toknum = *cp2 - '1']) { char *cp3=tp[toknum]; while (cp3 != te[toknum]) { *cp1++ = *cp3++; } } } else if (*cp2) { *cp1++ = *cp2++; } } if (!*cp2) { printf("nmap: unbalanced brackets\n"); return(name); } match = 1; cp2--; } if (match) { while (*++cp2 && *cp2 != ']') { if (*cp2 == '\\' && *(cp2 + 1)) { cp2++; } } if (!*cp2) { printf("nmap: unbalanced brackets\n"); return(name); } break; } switch (*++cp2) { case ',': goto LOOP; case ']': break; default: cp2--; goto LOOP; } break; case '$': if (isdigit(*(cp2 + 1))) { if (*++cp2 == '0') { char *cp3 = name; while (*cp3) { *cp1++ = *cp3++; } } else if (toks[toknum = *cp2 - '1']) { char *cp3 = tp[toknum]; while (cp3 != te[toknum]) { *cp1++ = *cp3++; } } break; } /* intentional drop through */ default: *cp1++ = *cp2; break; } cp2++; } *cp1 = '\0'; if (!*new) { return(name); } return(new); } void setsunique(void) { sunique = !sunique; printf("Store unique %s.\n", onoff(sunique)); code = sunique; } void setrunique(void) { runique = !runique; printf("Receive unique %s.\n", onoff(runique)); code = runique; } /* change directory to parent directory */ void cdup(void) { if (command("CDUP") == ERROR && code == 500) { if (verbose) printf("CDUP command not recognized, trying XCUP\n"); (void) command("XCUP"); } } /* restart transfer at specific point */ void restart(int argc, char *argv[]) { if (argc != 2) printf("restart: offset not specified\n"); else { restart_point = atol(argv[1]); printf("restarting at %ld. %s\n", restart_point, "execute get, put or append to initiate transfer"); } } /* show remote system type */ void syst(void) { command("SYST"); } void macdef(int argc, char *argv[]) { char *tmp; int c; if (macnum == 16) { printf("Limit of 16 macros have already been defined\n"); code = -1; return; } if (argc < 2 && !another(&argc, &argv, "macro name")) { printf("Usage: %s macro_name\n",argv[0]); code = -1; return; } if (interactive) { printf("Enter macro line by line, terminating it with a null line\n"); } (void) strncpy(macros[macnum].mac_name, argv[1], 8); macros[macnum].mac_name[8] = 0; if (macnum == 0) { macros[macnum].mac_start = macbuf; } else { macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; } tmp = macros[macnum].mac_start; /* stepping over the end of the array, remember to take away 1! */ while (tmp != macbuf+MACBUF_SIZE) { if ((c = getchar()) == EOF) { printf("macdef:end of file encountered\n"); code = -1; return; } if ((*tmp = c) == '\n') { if (tmp == macros[macnum].mac_start) { macros[macnum++].mac_end = tmp; code = 0; return; } if (*(tmp-1) == '\0') { macros[macnum++].mac_end = tmp - 1; code = 0; return; } *tmp = '\0'; } tmp++; } while (1) { while ((c = getchar()) != '\n' && c != EOF) /* LOOP */; if (c == EOF || getchar() == '\n') { printf("Macro not defined - 4k buffer exceeded\n"); code = -1; return; } } } /* * Start up passive mode interaction */ void setpassive(void) { passivemode = !passivemode; printf("Passive mode %s.\n", onoff(passivemode)); code = passivemode; } /* * get size of file on remote machine */ void sizecmd(int argc, char *argv[]) { if (argc < 2 && !another(&argc, &argv, "filename")) { printf("usage: %s filename\n", argv[0]); code = -1; return; } (void) command("SIZE %s", argv[1]); } /* * get last modification time of file on remote machine */ void modtime(int argc, char *argv[]) { int overbose; if (argc < 2 && !another(&argc, &argv, "filename")) { printf("usage: %s filename\n", argv[0]); code = -1; return; } overbose = verbose; if (debug == 0) verbose = -1; if (command("MDTM %s", argv[1]) == COMPLETE) { int yy, mo, day, hour, min, sec; sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, &day, &hour, &min, &sec); /* might want to print this in local time */ printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], mo, day, yy, hour, min, sec); } else printf("%s\n", reply_string); verbose = overbose; } /* * show status on remote machine */ void rmtstatus(int argc, char *argv[]) { (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); } /* * get file if modtime is more recent than current file */ void newer(int argc, char *argv[]) { if (getit(argc, argv, -1, "w")) { /* This should be controlled by some verbose flag */ printf("Local file \"%s\" is newer than remote file \"%s\"\n", argv[2], argv[1]); } } netkit-ftp-0.17/ftp/cmds.h100644 144 144 3454 6204460340 14726 0ustar dhollandpeoplevoid settick(void); void disconnect(void); void setascii(void); void setbell(void); void setbinary(void); void setdebug(int argc, char *argv[]); void setform(void); void setglob(void); void sethash(void); void setmode(void); void setport(void); void setprompt(void); void setstruct(void); void settenex(void); void settrace(void); void settype(int argc, char *argv[]); void setverbose(void); void restart(int argc, char *argv[]); void reget(int argc, char *argv[]); void syst(void); void cd(int argc, char *argv[]); void lcd(int argc, char *argv[]); void delete_cmd(int argc, char *argv[]); void mdelete(int argc, char *argv[]); void user(int argc, char *argv[]); void ls(int argc, char *argv[]); void mls(int argc, char *argv[]); void get(int argc, char *argv[]); void mget(int argc, char *argv[]); void help(int argc, char *argv[]); void append(int argc, char *argv[]); void put(int argc, char *argv[]); void mput(int argc, char *argv[]); void renamefile(int argc, char *argv[]); void status(void); void quote(int argc, char *argv[]); void rmthelp(int argc, char *argv[]); void shell(const char *arg); void site(int argc, char *argv[]); void pwd(void); void makedir(int argc, char *argv[]); void removedir(int argc, char *argv[]); void setcr(void); void account(int argc, char *argv[]); void doproxy(int argc, char *argv[]); void reset(void); void setcase(void); void setntrans(int argc, char *argv[]); void setnmap(int argc, char *argv[]); void setsunique(void); void setrunique(void); void cdup(void); void macdef(int argc, char *argv[]); void sizecmd(int argc, char *argv[]); void modtime(int argc, char *argv[]); void newer(int argc, char *argv[]); void rmtstatus(int argc, char *argv[]); void do_chmod(int argc, char *argv[]); void do_umask(int argc, char *argv[]); void idle_cmd(int argc, char *argv[]); void setpassive(void); netkit-ftp-0.17/ftp/cmdtab.c100644 144 144 24210 6774160145 15252 0ustar dhollandpeople/* * Copyright (c) 1985, 1989 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ /* * from: @(#)cmdtab.c 5.10 (Berkeley) 6/1/90 */ char cmdtab_rcsid[] = "$Id: cmdtab.c,v 1.8 1999/09/28 15:36:05 dholland Exp $"; #include /* for NULL */ #include "ftp_var.h" #include "cmds.h" /* * User FTP -- Command Tables. */ const char accounthelp[] = "send account command to remote server"; const char appendhelp[] = "append to a file"; const char asciihelp[] = "set ascii transfer type"; const char beephelp[] = "beep when command completed"; const char binaryhelp[] = "set binary transfer type"; const char casehelp[] = "toggle mget upper/lower case id mapping"; const char cdhelp[] = "change remote working directory"; const char cduphelp[] = "change remote working directory to parent directory"; const char chmodhelp[] = "change file permissions of remote file"; const char connecthelp[] = "connect to remote ftp"; const char crhelp[] = "toggle carriage return stripping on ascii gets"; const char deletehelp[] = "delete remote file"; const char debughelp[] = "toggle/set debugging mode"; const char dirhelp[] = "list contents of remote directory"; const char disconhelp[] = "terminate ftp session"; const char domachelp[] = "execute macro"; const char formhelp[] = "set file transfer format"; const char globhelp[] = "toggle metacharacter expansion of local file names"; const char hashhelp[] = "toggle printing `#' for each buffer transferred"; const char helphelp[] = "print local help information"; const char idlehelp[] = "get (set) idle timer on remote side"; const char lcdhelp[] = "change local working directory"; const char lshelp[] = "list contents of remote directory"; const char macdefhelp[] = "define a macro"; const char mdeletehelp[] = "delete multiple files"; const char mdirhelp[] = "list contents of multiple remote directories"; const char mgethelp[] = "get multiple files"; const char mkdirhelp[] = "make directory on the remote machine"; const char mlshelp[] = "list contents of multiple remote directories"; const char modtimehelp[] = "show last modification time of remote file"; const char modehelp[] = "set file transfer mode"; const char mputhelp[] = "send multiple files"; const char newerhelp[] = "get file if remote file is newer than local file "; const char nlisthelp[] = "nlist contents of remote directory"; const char nmaphelp[] = "set templates for default file name mapping"; const char ntranshelp[] ="set translation table for default file name mapping"; const char passivehelp[] = "enter passive transfer mode"; const char porthelp[] = "toggle use of PORT cmd for each data connection"; const char prompthelp[] = "force interactive prompting on multiple commands"; const char proxyhelp[] = "issue command on alternate connection"; const char pwdhelp[] = "print working directory on remote machine"; const char quithelp[] = "terminate ftp session and exit"; const char quotehelp[] = "send arbitrary ftp command"; const char receivehelp[] = "receive file"; const char regethelp[] = "get file restarting at end of local file"; const char remotehelp[] = "get help from remote server"; const char renamehelp[] = "rename file"; const char restarthelp[] = "restart file transfer at bytecount"; const char rmdirhelp[] = "remove directory on the remote machine"; const char rmtstatushelp[]="show status of remote machine"; const char runiquehelp[] = "toggle store unique for local files"; const char resethelp[] = "clear queued command replies"; const char sendhelp[] = "send one file"; const char sitehelp[] = "send site specific command to remote server\n" "\t\tTry \"rhelp site\" or \"site help\" for more information"; const char shellhelp[] = "escape to the shell"; const char sizecmdhelp[] = "show size of remote file"; const char statushelp[] = "show current status"; const char structhelp[] = "set file transfer structure"; const char suniquehelp[] = "toggle store unique on remote machine"; const char systemhelp[] = "show remote system type"; const char tenexhelp[] = "set tenex file transfer type"; const char tickhelp[] = "toggle printing byte counter during transfers"; const char tracehelp[] = "toggle packet tracing"; const char typehelp[] = "set file transfer type"; const char umaskhelp[] = "get (set) umask on remote side"; const char userhelp[] = "send new user information"; const char verbosehelp[] = "toggle verbose mode"; struct cmd cmdtab[] = { { "!", shellhelp, 0, 0, 0, NULL, NULL, shell }, { "$", domachelp, 1, 0, 0, domacro, NULL, NULL }, { "account", accounthelp, 0, 1, 1, account, NULL, NULL }, { "append", appendhelp, 1, 1, 1, put, NULL, NULL }, { "ascii", asciihelp, 0, 1, 1, NULL, setascii, NULL }, { "bell", beephelp, 0, 0, 0, NULL, setbell, NULL }, { "binary", binaryhelp, 0, 1, 1, NULL, setbinary, NULL }, { "bye", quithelp, 0, 0, 0, NULL, quit, NULL }, { "case", casehelp, 0, 0, 1, NULL, setcase, NULL }, { "cd", cdhelp, 0, 1, 1, cd, NULL, NULL }, { "cdup", cduphelp, 0, 1, 1, NULL, cdup, NULL }, { "chmod", chmodhelp, 0, 1, 1, do_chmod, NULL, NULL }, { "close", disconhelp, 0, 1, 1, NULL, disconnect, NULL }, { "cr", crhelp, 0, 0, 0, NULL, setcr, NULL }, { "delete", deletehelp, 0, 1, 1, delete_cmd, NULL, NULL }, { "debug", debughelp, 0, 0, 0, setdebug, NULL, NULL }, { "dir", dirhelp, 1, 1, 1, ls, NULL, NULL }, { "disconnect", disconhelp, 0, 1, 1, NULL, disconnect, NULL }, { "exit", quithelp, 0, 0, 0, NULL, quit, NULL }, { "form", formhelp, 0, 1, 1, NULL, setform, NULL }, { "get", receivehelp, 1, 1, 1, get, NULL, NULL }, { "glob", globhelp, 0, 0, 0, NULL, setglob, NULL }, { "hash", hashhelp, 0, 0, 0, NULL, sethash, NULL }, { "help", helphelp, 0, 0, 1, help, NULL, NULL }, { "idle", idlehelp, 0, 1, 1, idle_cmd, NULL, NULL }, { "image", binaryhelp, 0, 1, 1, NULL, setbinary, NULL }, { "lcd", lcdhelp, 0, 0, 0, lcd, NULL, NULL }, { "ls", lshelp, 1, 1, 1, ls, NULL, NULL }, { "macdef", macdefhelp, 0, 0, 0, macdef, NULL, NULL }, { "mdelete", mdeletehelp, 1, 1, 1, mdelete, NULL, NULL }, { "mdir", mdirhelp, 1, 1, 1, mls, NULL, NULL }, { "mget", mgethelp, 1, 1, 1, mget, NULL, NULL }, { "mkdir", mkdirhelp, 0, 1, 1, makedir, NULL, NULL }, { "mls", mlshelp, 1, 1, 1, mls, NULL, NULL }, { "mode", modehelp, 0, 1, 1, NULL, setmode, NULL }, { "modtime", modtimehelp, 0, 1, 1, modtime, NULL, NULL }, { "mput", mputhelp, 1, 1, 1, mput, NULL, NULL }, { "newer", newerhelp, 1, 1, 1, newer, NULL, NULL }, { "nmap", nmaphelp, 0, 0, 1, setnmap, NULL, NULL }, { "nlist", nlisthelp, 1, 1, 1, ls, NULL, NULL }, { "ntrans", ntranshelp, 0, 0, 1, setntrans, NULL, NULL }, { "open", connecthelp, 0, 0, 1, setpeer, NULL, NULL }, { "prompt", prompthelp, 0, 0, 0, NULL, setprompt, NULL }, { "passive", passivehelp, 0, 0, 0, NULL, setpassive, NULL }, { "proxy", proxyhelp, 0, 0, 1, doproxy, NULL, NULL }, { "sendport", porthelp, 0, 0, 0, NULL, setport, NULL }, { "put", sendhelp, 1, 1, 1, put, NULL, NULL }, { "pwd", pwdhelp, 0, 1, 1, NULL, pwd, NULL }, { "quit", quithelp, 0, 0, 0, NULL, quit, NULL }, { "quote", quotehelp, 1, 1, 1, quote, NULL, NULL }, { "recv", receivehelp, 1, 1, 1, get, NULL, NULL }, { "reget", regethelp, 1, 1, 1, reget, NULL, NULL }, { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus, NULL, NULL }, { "rhelp", remotehelp, 0, 1, 1, rmthelp, NULL, NULL }, { "rename", renamehelp, 0, 1, 1, renamefile, NULL, NULL }, { "reset", resethelp, 0, 1, 1, NULL, reset, NULL }, { "restart", restarthelp, 1, 1, 1, restart, NULL, NULL }, { "rmdir", rmdirhelp, 0, 1, 1, removedir, NULL, NULL }, { "runique", runiquehelp, 0, 0, 1, NULL, setrunique, NULL }, { "send", sendhelp, 1, 1, 1, put, NULL, NULL }, { "site", sitehelp, 0, 1, 1, site, NULL, NULL }, { "size", sizecmdhelp, 1, 1, 1, sizecmd, NULL, NULL }, { "status", statushelp, 0, 0, 1, NULL, status, NULL }, { "struct", structhelp, 0, 1, 1, NULL, setstruct, NULL }, { "system", systemhelp, 0, 1, 1, NULL, syst, NULL }, { "sunique", suniquehelp, 0, 0, 1, NULL, setsunique, NULL }, { "tenex", tenexhelp, 0, 1, 1, NULL, settenex, NULL }, { "tick", tickhelp, 0, 0, 0, NULL, settick, NULL }, { "trace", tracehelp, 0, 0, 0, NULL, settrace, NULL }, { "type", typehelp, 0, 1, 1, settype, NULL, NULL }, { "user", userhelp, 0, 1, 1, user, NULL, NULL }, { "umask", umaskhelp, 0, 1, 1, do_umask, NULL, NULL }, { "verbose", verbosehelp, 0, 0, 0, NULL, setverbose, NULL }, { "?", helphelp, 0, 0, 1, help, NULL, NULL }, { 0, 0, 0, 0, 0, 0, 0, 0 }, }; int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1; netkit-ftp-0.17/ftp/domacro.c100644 144 144 10161 6204460340 15430 0ustar dhollandpeople/* * Copyright (c) 1985 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ /* * from: @(#)domacro.c 1.8 (Berkeley) 9/28/90 */ char domacro_rcsid[] = "$Id: domacro.c,v 1.4 1996/08/14 23:27:28 dholland Exp $"; #include #include #include #include #include "ftp_var.h" void domacro(int argc, char *argv[]) { int margc; char *marg; char **margv; register int i, j; register char *cp1, *cp2; int count = 2, loopflg = 0; char line2[200]; struct cmd *c; if (argc < 2 && !another(&argc, &argv, "macro name")) { printf("Usage: %s macro_name.\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) { printf("'%s' macro not found.\n", argv[1]); code = -1; return; } (void) strcpy(line2, line); TOP: cp1 = macros[i].mac_start; while (cp1 != macros[i].mac_end) { while (isspace(*cp1)) { cp1++; } cp2 = line; while (*cp1 != '\0') { switch(*cp1) { case '\\': *cp2++ = *++cp1; break; case '$': if (isdigit(*(cp1+1))) { j = 0; while (isdigit(*++cp1)) { j = 10*j + *cp1 - '0'; } cp1--; if (argc - 2 >= j) { (void) strcpy(cp2, argv[j+1]); cp2 += strlen(argv[j+1]); } break; } if (*(cp1+1) == 'i') { loopflg = 1; cp1++; if (count < argc) { (void) strcpy(cp2, argv[count]); cp2 += strlen(argv[count]); } break; } /* intentional drop through */ default: *cp2++ = *cp1; break; } if (*cp1 != '\0') { cp1++; } } *cp2 = '\0'; margv = makeargv(&margc, &marg); c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); code = -1; } else if (c == NULL) { printf("?Invalid command\n"); code = -1; } else if (c->c_conn && !connected) { printf("Not connected.\n"); code = -1; } else { if (verbose) { printf("%s\n",line); } if (c->c_handler_v) c->c_handler_v(margc, margv); else if (c->c_handler_0) c->c_handler_0(); else c->c_handler_1(marg); if (bell && c->c_bell) { (void) putchar('\007'); } (void) strcpy(line, line2); margv = makeargv(&margc, &marg); argc = margc; argv = margv; } if (cp1 != macros[i].mac_end) { cp1++; } } if (loopflg && ++count < argc) { goto TOP; } } netkit-ftp-0.17/ftp/ftp.1100644 144 144 65207 7141140313 14522 0ustar dhollandpeople.\" Copyright (c) 1985, 1989, 1990 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. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. 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. .\" .\" from: @(#)ftp.1 6.18 (Berkeley) 7/30/91 .\" $Id: ftp.1,v 1.14 2000/07/30 23:56:59 dholland Exp $ .\" .Dd August 15, 1999 .Dt FTP 1 .Os "Linux NetKit (0.17)" .Sh NAME .Nm ftp .Nd .Tn Internet file transfer program .Sh SYNOPSIS .Nm ftp .Op Fl pinegvd .Op Ar host .Nm pftp .Op Fl inegvd .Op Ar host .Sh DESCRIPTION .Nm Ftp is the user interface to the .Tn Internet standard File Transfer Protocol. The program allows a user to transfer files to and from a remote network site. .Pp Options may be specified at the command line, or to the command interpreter. .Bl -tag -width flag .It Fl p Use passive mode for data transfers. Allows use of ftp in environments where a firewall prevents connections from the outside world back to the client machine. Requires that the ftp server support the PASV command. This is the default if invoked as .Nm pftp. .It Fl i Turns off interactive prompting during multiple file transfers. .It Fl n Restrains .Nm ftp from attempting \*(Lqauto-login\*(Rq upon initial connection. If auto-login is enabled, .Nm ftp will check the .Pa .netrc (see .Xr netrc 5) file in the user's home directory for an entry describing an account on the remote machine. If no entry exists, .Nm ftp will prompt for the remote machine login name (default is the user identity on the local machine), and, if necessary, prompt for a password and an account with which to login. .It Fl e Disables command editing and history support, if it was compiled into the .Nm ftp executable. Otherwise, does nothing. .It Fl g Disables file name globbing. .It Fl v Verbose option forces .Nm ftp to show all responses from the remote server, as well as report on data transfer statistics. .It Fl d Enables debugging. .El .Pp The client host with which .Nm ftp is to communicate may be specified on the command line. If this is done, .Nm ftp will immediately attempt to establish a connection to an .Tn FTP server on that host; otherwise, .Nm ftp will enter its command interpreter and await instructions from the user. When .Nm ftp is awaiting commands from the user the prompt .Ql ftp> is provided to the user. The following commands are recognized by .Nm ftp : .Bl -tag -width Fl .It Ic \&! Op Ar command Op Ar args Invoke an interactive shell on the local machine. If there are arguments, the first is taken to be a command to execute directly, with the rest of the arguments as its arguments. .It Ic \&$ Ar macro-name Op Ar args Execute the macro .Ar macro-name that was defined with the .Ic macdef command. Arguments are passed to the macro unglobbed. .It Ic account Op Ar passwd Supply a supplemental password required by a remote system for access to resources once a login has been successfully completed. If no argument is included, the user will be prompted for an account password in a non-echoing input mode. .It Ic append Ar local-file Op Ar remote-file Append a local file to a file on the remote machine. If .Ar remote-file is left unspecified, the local file name is used in naming the remote file after being altered by any .Ic ntrans or .Ic nmap setting. File transfer uses the current settings for .Ic type , .Ic format , .Ic mode , and .Ic structure . .It Ic ascii Set the file transfer .Ic type to network .Tn ASCII . This is the default type. .It Ic bell Arrange that a bell be sounded after each file transfer command is completed. .It Ic binary Set the file transfer .Ic type to support binary image transfer. .It Ic bye Terminate the .Tn FTP session with the remote server and exit .Nm ftp . An end of file will also terminate the session and exit. .It Ic case Toggle remote computer file name case mapping during .Ic mget commands. When .Ic case is on (default is off), remote computer file names with all letters in upper case are written in the local directory with the letters mapped to lower case. .It Ic \&cd Ar remote-directory Change the working directory on the remote machine to .Ar remote-directory . .It Ic cdup Change the remote machine working directory to the parent of the current remote machine working directory. .It Ic chmod Ar mode file-name Change the permission modes of the file .Ar file-name on the remote sytem to .Ar mode . .It Ic close Terminate the .Tn FTP session with the remote server, and return to the command interpreter. Any defined macros are erased. .It Ic \&cr Toggle carriage return stripping during ascii type file retrieval. Records are denoted by a carriage return/linefeed sequence during ascii type file transfer. When .Ic \&cr is on (the default), carriage returns are stripped from this sequence to conform with the .Ux single linefeed record delimiter. Records on .Pf non\- Ns Ux remote systems may contain single linefeeds; when an ascii type transfer is made, these linefeeds may be distinguished from a record delimiter only when .Ic \&cr is off. .It Ic delete Ar remote-file Delete the file .Ar remote-file on the remote machine. .It Ic debug Op Ar debug-value Toggle debugging mode. If an optional .Ar debug-value is specified it is used to set the debugging level. When debugging is on, .Nm ftp prints each command sent to the remote machine, preceded by the string .Ql \-\-> .It Xo .Ic dir .Op Ar remote-directory .Op Ar local-file .Xc Print a listing of the directory contents in the directory, .Ar remote-directory , and, optionally, placing the output in .Ar local-file . If interactive prompting is on, .Nm ftp will prompt the user to verify that the last argument is indeed the target local file for receiving .Ic dir output. If no directory is specified, the current working directory on the remote machine is used. If no local file is specified, or .Ar local-file is .Fl , output comes to the terminal. .It Ic disconnect A synonym for .Ar close . .It Ic form Ar format Set the file transfer .Ic form to .Ar format . The default format is \*(Lqfile\*(Rq. .It Ic get Ar remote-file Op Ar local-file Retrieve the .Ar remote-file and store it on the local machine. If the local file name is not specified, it is given the same name it has on the remote machine, subject to alteration by the current .Ic case , .Ic ntrans , and .Ic nmap settings. The current settings for .Ic type , .Ic form , .Ic mode , and .Ic structure are used while transferring the file. .It Ic glob Toggle filename expansion for .Ic mdelete , .Ic mget and .Ic mput . If globbing is turned off with .Ic glob , the file name arguments are taken literally and not expanded. Globbing for .Ic mput is done as in .Xr csh 1 . For .Ic mdelete and .Ic mget , each remote file name is expanded separately on the remote machine and the lists are not merged. Expansion of a directory name is likely to be different from expansion of the name of an ordinary file: the exact result depends on the foreign operating system and ftp server, and can be previewed by doing .Ql mls remote-files \- Note: .Ic mget and .Ic mput are not meant to transfer entire directory subtrees of files. That can be done by transferring a .Xr tar 1 archive of the subtree (in binary mode). .It Ic hash Toggle hash-sign (``#'') printing for each data block transferred. The size of a data block is 1024 bytes. .It Ic help Op Ar command Print an informative message about the meaning of .Ar command . If no argument is given, .Nm ftp prints a list of the known commands. .It Ic idle Op Ar seconds Set the inactivity timer on the remote server to .Ar seconds seconds. If .Ar seconds is ommitted, the current inactivity timer is printed. .It Ic lcd Op Ar directory Change the working directory on the local machine. If no .Ar directory is specified, the user's home directory is used. .It Xo .Ic \&ls .Op Ar remote-directory .Op Ar local-file .Xc Print a listing of the contents of a directory on the remote machine. The listing includes any system-dependent information that the server chooses to include; for example, most .Ux systems will produce output from the command .Ql ls \-l . (See also .Ic nlist . ) If .Ar remote-directory is left unspecified, the current working directory is used. If interactive prompting is on, .Nm ftp will prompt the user to verify that the last argument is indeed the target local file for receiving .Ic \&ls output. If no local file is specified, or if .Ar local-file is .Sq Fl , the output is sent to the terminal. .It Ic macdef Ar macro-name Define a macro. Subsequent lines are stored as the macro .Ar macro-name ; a null line (consecutive newline characters in a file or carriage returns from the terminal) terminates macro input mode. There is a limit of 16 macros and 4096 total characters in all defined macros. Macros remain defined until a .Ic close command is executed. The macro processor interprets `$' and `\e' as special characters. A `$' followed by a number (or numbers) is replaced by the corresponding argument on the macro invocation command line. A `$' followed by an `i' signals that macro processor that the executing macro is to be looped. On the first pass `$i' is replaced by the first argument on the macro invocation command line, on the second pass it is replaced by the second argument, and so on. A `\e' followed by any character is replaced by that character. Use the `\e' to prevent special treatment of the `$'. .It Ic mdelete Op Ar remote-files Delete the .Ar remote-files on the remote machine. .It Ic mdir Ar remote-files local-file Like .Ic dir , except multiple remote files may be specified. If interactive prompting is on, .Nm ftp will prompt the user to verify that the last argument is indeed the target local file for receiving .Ic mdir output. .It Ic mget Ar remote-files Expand the .Ar remote-files on the remote machine and do a .Ic get for each file name thus produced. See .Ic glob for details on the filename expansion. Resulting file names will then be processed according to .Ic case , .Ic ntrans , and .Ic nmap settings. Files are transferred into the local working directory, which can be changed with .Ql lcd directory ; new local directories can be created with .Ql "\&! mkdir directory" . .It Ic mkdir Ar directory-name Make a directory on the remote machine. .It Ic mls Ar remote-files local-file Like .Ic nlist , except multiple remote files may be specified, and the .Ar local-file must be specified. If interactive prompting is on, .Nm ftp will prompt the user to verify that the last argument is indeed the target local file for receiving .Ic mls output. .It Ic mode Op Ar mode-name Set the file transfer .Ic mode to .Ar mode-name . The default mode is \*(Lqstream\*(Rq mode. .It Ic modtime Ar file-name Show the last modification time of the file on the remote machine. .It Ic mput Ar local-files Expand wild cards in the list of local files given as arguments and do a .Ic put for each file in the resulting list. See .Ic glob for details of filename expansion. Resulting file names will then be processed according to .Ic ntrans and .Ic nmap settings. .It Ic newer Ar file-name Op Ar local-file Get the file only if the modification time of the remote file is more recent that the file on the current system. If the file does not exist on the current system, the remote file is considered .Ic newer . Otherwise, this command is identical to .Ar get . .It Xo .Ic nlist .Op Ar remote-directory .Op Ar local-file .Xc Print a list of the files in a directory on the remote machine. If .Ar remote-directory is left unspecified, the current working directory is used. If interactive prompting is on, .Nm ftp will prompt the user to verify that the last argument is indeed the target local file for receiving .Ic nlist output. If no local file is specified, or if .Ar local-file is .Fl , the output is sent to the terminal. .It Ic nmap Op Ar inpattern outpattern Set or unset the filename mapping mechanism. If no arguments are specified, the filename mapping mechanism is unset. If arguments are specified, remote filenames are mapped during .Ic mput commands and .Ic put commands issued without a specified remote target filename. If arguments are specified, local filenames are mapped during .Ic mget commands and .Ic get commands issued without a specified local target filename. This command is useful when connecting to a .No non\- Ns Ux remote computer with different file naming conventions or practices. The mapping follows the pattern set by .Ar inpattern and .Ar outpattern . .Op Ar Inpattern is a template for incoming filenames (which may have already been processed according to the .Ic ntrans and .Ic case settings). Variable templating is accomplished by including the sequences `$1', `$2', ..., `$9' in .Ar inpattern . Use `\\' to prevent this special treatment of the `$' character. All other characters are treated literally, and are used to determine the .Ic nmap .Op Ar inpattern variable values. For example, given .Ar inpattern $1.$2 and the remote file name "mydata.data", $1 would have the value "mydata", and $2 would have the value "data". The .Ar outpattern determines the resulting mapped filename. The sequences `$1', `$2', ...., `$9' are replaced by any value resulting from the .Ar inpattern template. The sequence `$0' is replace by the original filename. Additionally, the sequence .Ql Op Ar seq1 , Ar seq2 is replaced by .Op Ar seq1 if .Ar seq1 is not a null string; otherwise it is replaced by .Ar seq2 . For example, the command .Pp .Bd -literal -offset indent -compact nmap $1.$2.$3 [$1,$2].[$2,file] .Ed .Pp would yield the output filename "myfile.data" for input filenames "myfile.data" and "myfile.data.old", "myfile.file" for the input filename "myfile", and "myfile.myfile" for the input filename ".myfile". Spaces may be included in .Ar outpattern , as in the example: `nmap $1 sed "s/ *$//" > $1' . Use the `\e' character to prevent special treatment of the `$','[','[', and `,' characters. .It Ic ntrans Op Ar inchars Op Ar outchars Set or unset the filename character translation mechanism. If no arguments are specified, the filename character translation mechanism is unset. If arguments are specified, characters in remote filenames are translated during .Ic mput commands and .Ic put commands issued without a specified remote target filename. If arguments are specified, characters in local filenames are translated during .Ic mget commands and .Ic get commands issued without a specified local target filename. This command is useful when connecting to a .No non\- Ns Ux remote computer with different file naming conventions or practices. Characters in a filename matching a character in .Ar inchars are replaced with the corresponding character in .Ar outchars . If the character's position in .Ar inchars is longer than the length of .Ar outchars , the character is deleted from the file name. .It Ic open Ar host Op Ar port Establish a connection to the specified .Ar host .Tn FTP server. An optional port number may be supplied, in which case, .Nm ftp will attempt to contact an .Tn FTP server at that port. If the .Ic auto-login option is on (default), .Nm ftp will also attempt to automatically log the user in to the .Tn FTP server (see below). .It Ic prompt Toggle interactive prompting. Interactive prompting occurs during multiple file transfers to allow the user to selectively retrieve or store files. If prompting is turned off (default is on), any .Ic mget or .Ic mput will transfer all files, and any .Ic mdelete will delete all files. .It Ic proxy Ar ftp-command Execute an ftp command on a secondary control connection. This command allows simultaneous connection to two remote ftp servers for transferring files between the two servers. The first .Ic proxy command should be an .Ic open , to establish the secondary control connection. Enter the command "proxy ?" to see other ftp commands executable on the secondary connection. The following commands behave differently when prefaced by .Ic proxy : .Ic open will not define new macros during the auto-login process, .Ic close will not erase existing macro definitions, .Ic get and .Ic mget transfer files from the host on the primary control connection to the host on the secondary control connection, and .Ic put , .Ic mput , and .Ic append transfer files from the host on the secondary control connection to the host on the primary control connection. Third party file transfers depend upon support of the ftp protocol .Dv PASV command by the server on the secondary control connection. .It Ic put Ar local-file Op Ar remote-file Store a local file on the remote machine. If .Ar remote-file is left unspecified, the local file name is used after processing according to any .Ic ntrans or .Ic nmap settings in naming the remote file. File transfer uses the current settings for .Ic type , .Ic format , .Ic mode , and .Ic structure . .It Ic pwd Print the name of the current working directory on the remote machine. .It Ic quit A synonym for .Ic bye . .It Ic quote Ar arg1 arg2 ... The arguments specified are sent, verbatim, to the remote .Tn FTP server. .It Ic recv Ar remote-file Op Ar local-file A synonym for get. .It Ic reget Ar remote-file Op Ar local-file Reget acts like get, except that if .Ar local-file exists and is smaller than .Ar remote-file , .Ar local-file is presumed to be a partially transferred copy of .Ar remote-file and the transfer is continued from the apparent point of failure. This command is useful when transferring very large files over networks that are prone to dropping connections. .It Ic remotehelp Op Ar command-name Request help from the remote .Tn FTP server. If a .Ar command-name is specified it is supplied to the server as well. .It Ic remotestatus Op Ar file-name With no arguments, show status of remote machine. If .Ar file-name is specified, show status of .Ar file-name on remote machine. .It Xo .Ic rename .Op Ar from .Op Ar to .Xc Rename the file .Ar from on the remote machine, to the file .Ar to . .It Ic reset Clear reply queue. This command re-synchronizes command/reply sequencing with the remote ftp server. Resynchronization may be necessary following a violation of the ftp protocol by the remote server. .It Ic restart Ar marker Restart the immediately following .Ic get or .Ic put at the indicated .Ar marker . On .Ux systems, marker is usually a byte offset into the file. .It Ic rmdir Ar directory-name Delete a directory on the remote machine. .It Ic runique Toggle storing of files on the local system with unique filenames. If a file already exists with a name equal to the target local filename for a .Ic get or .Ic mget command, a ".1" is appended to the name. If the resulting name matches another existing file, a ".2" is appended to the original name. If this process continues up to ".99", an error message is printed, and the transfer does not take place. The generated unique filename will be reported. Note that .Ic runique will not affect local files generated from a shell command (see below). The default value is off. .It Ic send Ar local-file Op Ar remote-file A synonym for put. .It Ic sendport Toggle the use of .Dv PORT commands. By default, .Nm ftp will attempt to use a .Dv PORT command when establishing a connection for each data transfer. The use of .Dv PORT commands can prevent delays when performing multiple file transfers. If the .Dv PORT command fails, .Nm ftp will use the default data port. When the use of .Dv PORT commands is disabled, no attempt will be made to use .Dv PORT commands for each data transfer. This is useful for certain .Tn FTP implementations which do ignore .Dv PORT commands but, incorrectly, indicate they've been accepted. .It Ic site Ar arg1 arg2 ... The arguments specified are sent, verbatim, to the remote .Tn FTP server as a .Dv SITE command. .It Ic size Ar file-name Return size of .Ar file-name on remote machine. .It Ic status Show the current status of .Nm ftp . .It Ic struct Op Ar struct-name Set the file transfer .Ar structure to .Ar struct-name . By default \*(Lqstream\*(Rq structure is used. .It Ic sunique Toggle storing of files on remote machine under unique file names. Remote ftp server must support ftp protocol .Dv STOU command for successful completion. The remote server will report unique name. Default value is off. .It Ic system Show the type of operating system running on the remote machine. .It Ic tenex Set the file transfer type to that needed to talk to .Tn TENEX machines. .It Ic trace Toggle packet tracing. .It Ic type Op Ar type-name Set the file transfer .Ic type to .Ar type-name . If no type is specified, the current type is printed. The default type is network .Tn ASCII . .It Ic umask Op Ar newmask Set the default umask on the remote server to .Ar newmask . If .Ar newmask is ommitted, the current umask is printed. .It Xo .Ic user Ar user-name .Op Ar password .Op Ar account .Xc Identify yourself to the remote .Tn FTP server. If the .Ar password is not specified and the server requires it, .Nm ftp will prompt the user for it (after disabling local echo). If an .Ar account field is not specified, and the .Tn FTP server requires it, the user will be prompted for it. If an .Ar account field is specified, an account command will be relayed to the remote server after the login sequence is completed if the remote server did not require it for logging in. Unless .Nm ftp is invoked with \*(Lqauto-login\*(Rq disabled, this process is done automatically on initial connection to the .Tn FTP server. .It Ic verbose Toggle verbose mode. In verbose mode, all responses from the .Tn FTP server are displayed to the user. In addition, if verbose is on, when a file transfer completes, statistics regarding the efficiency of the transfer are reported. By default, verbose is on. .It Ic ? Op Ar command A synonym for help. .El .Pp Command arguments which have embedded spaces may be quoted with quote `"' marks. .Sh ABORTING A FILE TRANSFER To abort a file transfer, use the terminal interrupt key (usually Ctrl-C). Sending transfers will be immediately halted. Receiving transfers will be halted by sending a ftp protocol .Dv ABOR command to the remote server, and discarding any further data received. The speed at which this is accomplished depends upon the remote server's support for .Dv ABOR processing. If the remote server does not support the .Dv ABOR command, an .Ql ftp> prompt will not appear until the remote server has completed sending the requested file. .Pp The terminal interrupt key sequence will be ignored when .Nm ftp has completed any local processing and is awaiting a reply from the remote server. A long delay in this mode may result from the ABOR processing described above, or from unexpected behavior by the remote server, including violations of the ftp protocol. If the delay results from unexpected remote server behavior, the local .Nm ftp program must be killed by hand. .Sh FILE NAMING CONVENTIONS Files specified as arguments to .Nm ftp commands are processed according to the following rules. .Bl -enum .It If the file name .Sq Fl is specified, the .Ar stdin (for reading) or .Ar stdout (for writing) is used. .It If the first character of the file name is .Sq \&| , the remainder of the argument is interpreted as a shell command. .Nm Ftp then forks a shell, using .Xr popen 3 with the argument supplied, and reads (writes) from the stdout (stdin). If the shell command includes spaces, the argument must be quoted; e.g. \*(Lq" ls -lt"\*(Rq. A particularly useful example of this mechanism is: \*(Lqdir more\*(Rq. .It Failing the above checks, if ``globbing'' is enabled, local file names are expanded according to the rules used in the .Xr csh 1 ; c.f. the .Ic glob command. If the .Nm ftp command expects a single local file (.e.g. .Ic put ) , only the first filename generated by the "globbing" operation is used. .It For .Ic mget commands and .Ic get commands with unspecified local file names, the local filename is the remote filename, which may be altered by a .Ic case , .Ic ntrans , or .Ic nmap setting. The resulting filename may then be altered if .Ic runique is on. .It For .Ic mput commands and .Ic put commands with unspecified remote file names, the remote filename is the local filename, which may be altered by a .Ic ntrans or .Ic nmap setting. The resulting filename may then be altered by the remote server if .Ic sunique is on. .El .Sh FILE TRANSFER PARAMETERS The FTP specification specifies many parameters which may affect a file transfer. The .Ic type may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary), \*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for .Tn PDP Ns -10's and .Tn PDP Ns -20's mostly). .Nm Ftp supports the ascii and image types of file transfer, plus local byte size 8 for .Ic tenex mode transfers. .Pp .Nm Ftp supports only the default values for the remaining file transfer parameters: .Ic mode , .Ic form , and .Ic struct . .Sh ENVIRONMENT .Nm Ftp utilizes the following environment variables. .Bl -tag -width Fl .It Ev HOME For default location of a .Pa .netrc file, if one exists. .It Ev SHELL For default shell. .El .Sh SEE ALSO .Xr ftpd 8 , RFC 959 .Sh HISTORY The .Nm ftp command appeared in .Bx 4.2 . .Sh BUGS Correct execution of many commands depends upon proper behavior by the remote server. .Pp An error in the treatment of carriage returns in the .Bx 4.2 ascii-mode transfer code has been corrected. This correction may result in incorrect transfers of binary files to and from .Bx 4.2 servers using the ascii type. Avoid this problem by using the binary image type. netkit-ftp-0.17/ftp/ftp.c100644 144 144 105531 7025254020 14621 0ustar dhollandpeople/* * Copyright (c) 1985, 1989 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ /* * From: @(#)ftp.c 5.38 (Berkeley) 4/22/91 */ char ftp_rcsid[] = "$Id: ftp.c,v 1.25 1999/12/13 20:33:20 dholland Exp $"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ftp_var.h" #include "cmds.h" #include "../version.h" int data = -1; off_t restart_point = 0; static struct sockaddr_in hisctladdr; static struct sockaddr_in data_addr; static struct sockaddr_in myctladdr; static int ptflag = 0; static sigjmp_buf recvabort; static sigjmp_buf sendabort; static sigjmp_buf ptabort; static int ptabflg = 0; static int abrtflag = 0; void lostpeer(int); extern int connected; static char *gunique(char *); static void proxtrans(const char *cmd, char *local, char *remote); static int initconn(void); static void ptransfer(const char *direction, long bytes, const struct timeval *t0, const struct timeval *t1); static void tvsub(struct timeval *tdiff, const struct timeval *t1, const struct timeval *t0); static void abort_remote(FILE *din); FILE *cin, *cout; static FILE *dataconn(const char *); char * hookup(char *host, int port) { register struct hostent *hp = 0; int s, tos; socklen_t len; static char hostnamebuf[256]; memset(&hisctladdr, 0, sizeof(hisctladdr)); if (inet_aton(host, &hisctladdr.sin_addr)) { hisctladdr.sin_family = AF_INET; strncpy(hostnamebuf, host, sizeof(hostnamebuf)); hostnamebuf[sizeof(hostnamebuf)-1]=0; } else { hp = gethostbyname(host); if (hp == NULL) { fprintf(stderr, "ftp: %s: ", host); herror((char *)NULL); code = -1; return((char *) 0); } hisctladdr.sin_family = hp->h_addrtype; if (hp->h_length > (int)sizeof(hisctladdr.sin_addr)) { hp->h_length = sizeof(hisctladdr.sin_addr); } memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0], hp->h_length); (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); hostnamebuf[sizeof(hostnamebuf)-1] = 0; } hostname = hostnamebuf; s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); if (s < 0) { perror("ftp: socket"); code = -1; return (0); } hisctladdr.sin_port = port; while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { if (hp && hp->h_addr_list[1]) { int oerrno = errno; fprintf(stderr, "ftp: connect to address %s: ", inet_ntoa(hisctladdr.sin_addr)); errno = oerrno; perror((char *) 0); hp->h_addr_list++; memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0], hp->h_length); fprintf(stdout, "Trying %s...\n", inet_ntoa(hisctladdr.sin_addr)); (void) close(s); s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); if (s < 0) { perror("ftp: socket"); code = -1; return (0); } continue; } perror("ftp: connect"); code = -1; goto bad; } len = sizeof (myctladdr); if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { perror("ftp: getsockname"); code = -1; goto bad; } #ifdef IP_TOS tos = IPTOS_LOWDELAY; if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif cin = fdopen(s, "r"); cout = fdopen(s, "w"); if (cin == NULL || cout == NULL) { fprintf(stderr, "ftp: fdopen failed.\n"); if (cin) (void) fclose(cin); if (cout) (void) fclose(cout); code = -1; goto bad; } if (verbose) printf("Connected to %s.\n", hostname); if (getreply(0) > 2) { /* read startup message from server */ if (cin) (void) fclose(cin); if (cout) (void) fclose(cout); code = -1; goto bad; } #ifdef SO_OOBINLINE { int on = 1; if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0 && debug) { perror("ftp: setsockopt"); } } #endif /* SO_OOBINLINE */ return (hostname); bad: (void) close(s); return ((char *)0); } int dologin(const char *host) { char tmp[80]; char *luser, *pass, *zacct; int n, aflag = 0; luser = pass = zacct = 0; if (xruserpass(host, &luser, &pass, &zacct) < 0) { code = -1; return(0); } while (luser == NULL) { char *myname = getlogin(); if (myname == NULL) { struct passwd *pp = getpwuid(getuid()); if (pp != NULL) myname = pp->pw_name; } if (myname) printf("Name (%s:%s): ", host, myname); else printf("Name (%s): ", host); if (fgets(tmp, sizeof(tmp) - 1, stdin)==NULL) { fprintf(stderr, "\nLogin failed.\n"); return 0; } tmp[strlen(tmp) - 1] = '\0'; if (*tmp == '\0') luser = myname; else luser = tmp; } n = command("USER %s", luser); if (n == CONTINUE) { if (pass == NULL) { /* fflush(stdout); */ pass = getpass("Password:"); } n = command("PASS %s", pass); } if (n == CONTINUE) { aflag++; /* fflush(stdout); */ zacct = getpass("Account:"); n = command("ACCT %s", zacct); } if (n != COMPLETE) { fprintf(stderr, "Login failed.\n"); return (0); } if (!aflag && zacct != NULL) (void) command("ACCT %s", zacct); if (proxy) return(1); for (n = 0; n < macnum; ++n) { if (!strcmp("init", macros[n].mac_name)) { int margc; char **margv; strcpy(line, "$init"); margv = makeargv(&margc, NULL); domacro(margc, margv); break; } } return (1); } static void cmdabort(int ignore) { (void)ignore; printf("\n"); fflush(stdout); abrtflag++; if (ptflag) siglongjmp(ptabort,1); } int command(const char *fmt, ...) { va_list ap; int r; void (*oldintr)(int); abrtflag = 0; if (debug) { printf("---> "); va_start(ap, fmt); if (strncmp("PASS ", fmt, 5) == 0) printf("PASS XXXX"); else vfprintf(stdout, fmt, ap); va_end(ap); printf("\n"); (void) fflush(stdout); } if (cout == NULL) { perror ("No control connection for command"); code = -1; return (0); } oldintr = signal(SIGINT, cmdabort); va_start(ap, fmt); vfprintf(cout, fmt, ap); va_end(ap); fprintf(cout, "\r\n"); (void) fflush(cout); cpend = 1; r = getreply(!strcmp(fmt, "QUIT")); if (abrtflag && oldintr != SIG_IGN) (*oldintr)(SIGINT); (void) signal(SIGINT, oldintr); return(r); } char reply_string[BUFSIZ]; /* last line of previous reply */ #include int getreply(int expecteof) { register int c, n; register int dig; register char *cp; int originalcode = 0, continuation = 0; void (*oldintr)(int); int pflag = 0; size_t px = 0; size_t psize = sizeof(pasv); oldintr = signal(SIGINT, cmdabort); for (;;) { dig = n = code = 0; cp = reply_string; while ((c = getc(cin)) != '\n') { if (c == IAC) { /* handle telnet commands */ switch (c = getc(cin)) { case WILL: case WONT: c = getc(cin); fprintf(cout, "%c%c%c", IAC, DONT, c); (void) fflush(cout); break; case DO: case DONT: c = getc(cin); fprintf(cout, "%c%c%c", IAC, WONT, c); (void) fflush(cout); break; default: break; } continue; } dig++; if (c == EOF) { if (expecteof) { (void) signal(SIGINT,oldintr); code = 221; return (0); } lostpeer(0); if (verbose) { printf("421 Service not available, remote server has closed connection\n"); (void) fflush(stdout); } code = 421; return(4); } if (c != '\r' && (verbose > 0 || (verbose > -1 && n == '5' && dig > 4))) { if (proxflag && (dig == 1 || (dig == 5 && verbose == 0))) printf("%s:",hostname); (void) putchar(c); } if (dig < 4 && isdigit(c)) code = code * 10 + (c - '0'); if (!pflag && code == 227) pflag = 1; if (dig > 4 && pflag == 1 && isdigit(c)) pflag = 2; if (pflag == 2) { if (c != '\r' && c != ')') { if (px < psize-1) pasv[px++] = c; } else { pasv[px] = '\0'; pflag = 3; } } if (dig == 4 && c == '-') { if (continuation) code = 0; continuation++; } if (n == 0) n = c; if (cp < &reply_string[sizeof(reply_string) - 1]) *cp++ = c; } if (verbose > 0 || (verbose > -1 && n == '5')) { (void) putchar(c); (void) fflush (stdout); } if (continuation && code != originalcode) { if (originalcode == 0) originalcode = code; continue; } *cp = '\0'; if (n != '1') cpend = 0; (void) signal(SIGINT,oldintr); if (code == 421 || originalcode == 421) lostpeer(0); if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) (*oldintr)(SIGINT); return (n - '0'); } } static int empty(fd_set *mask, int hifd, int sec) { struct timeval t; t.tv_sec = (long) sec; t.tv_usec = 0; return(select(hifd+1, mask, (fd_set *) 0, (fd_set *) 0, &t)); } static void abortsend(int ignore) { (void)ignore; mflag = 0; abrtflag = 0; printf("\nsend aborted\nwaiting for remote to finish abort\n"); (void) fflush(stdout); siglongjmp(sendabort, 1); } #define HASHBYTES 1024 void sendrequest(const char *cmd, char *local, char *remote, int printnames) { struct stat st; struct timeval start, stop; register int c, d; FILE *volatile fin, *volatile dout = 0; int (*volatile closefunc)(FILE *); void (*volatile oldintr)(int); void (*volatile oldintp)(int); volatile long bytes = 0, hashbytes = HASHBYTES; char buf[BUFSIZ], *bufp; const char *volatile lmode; if (verbose && printnames) { if (local && *local != '-') printf("local: %s ", local); if (remote) printf("remote: %s\n", remote); } if (proxy) { proxtrans(cmd, local, remote); return; } if (curtype != type) changetype(type, 0); closefunc = NULL; oldintr = NULL; oldintp = NULL; lmode = "w"; if (sigsetjmp(sendabort, 1)) { while (cpend) { (void) getreply(0); } if (data >= 0) { (void) close(data); data = -1; } if (oldintr) (void) signal(SIGINT,oldintr); if (oldintp) (void) signal(SIGPIPE,oldintp); code = -1; return; } oldintr = signal(SIGINT, abortsend); if (strcmp(local, "-") == 0) fin = stdin; else if (*local == '|') { oldintp = signal(SIGPIPE,SIG_IGN); fin = popen(local + 1, "r"); if (fin == NULL) { perror(local + 1); (void) signal(SIGINT, oldintr); (void) signal(SIGPIPE, oldintp); code = -1; return; } closefunc = pclose; } else { fin = fopen(local, "r"); if (fin == NULL) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); (void) signal(SIGINT, oldintr); code = -1; return; } closefunc = fclose; if (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG) { fprintf(stdout, "%s: not a plain file.\n", local); (void) signal(SIGINT, oldintr); fclose(fin); code = -1; return; } } if (initconn()) { (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); code = -1; if (closefunc != NULL) (*closefunc)(fin); return; } if (sigsetjmp(sendabort, 1)) goto abort; if (restart_point && (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { if (fseek(fin, (long) restart_point, 0) < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); restart_point = 0; if (closefunc != NULL) (*closefunc)(fin); return; } if (command("REST %ld", (long) restart_point) != CONTINUE) { restart_point = 0; if (closefunc != NULL) (*closefunc)(fin); return; } restart_point = 0; lmode = "r+w"; } if (remote) { if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); if (closefunc != NULL) (*closefunc)(fin); return; } } else if (command("%s", cmd) != PRELIM) { (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); if (closefunc != NULL) (*closefunc)(fin); return; } dout = dataconn(lmode); if (dout == NULL) goto abort; (void) gettimeofday(&start, (struct timezone *)0); oldintp = signal(SIGPIPE, SIG_IGN); switch (curtype) { case TYPE_I: case TYPE_L: errno = d = 0; while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { bytes += c; for (bufp = buf; c > 0; c -= d, bufp += d) if ((d = write(fileno(dout), bufp, c)) <= 0) break; if (hash) { while (bytes >= hashbytes) { (void) putchar('#'); hashbytes += HASHBYTES; } (void) fflush(stdout); } if (tick && (bytes >= hashbytes)) { printf("\rBytes transferred: %ld", bytes); (void) fflush(stdout); while (bytes >= hashbytes) hashbytes += TICKBYTES; } } if (hash && (bytes > 0)) { if (bytes < HASHBYTES) (void) putchar('#'); (void) putchar('\n'); (void) fflush(stdout); } if (tick) { (void) printf("\rBytes transferred: %ld\n", bytes); (void) fflush(stdout); } if (c < 0) fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); if (d < 0) { if (errno != EPIPE) perror("netout"); bytes = -1; } break; case TYPE_A: while ((c = getc(fin)) != EOF) { if (c == '\n') { while (hash && (bytes >= hashbytes)) { (void) putchar('#'); (void) fflush(stdout); hashbytes += HASHBYTES; } if (tick && (bytes >= hashbytes)) { (void) printf("\rBytes transferred: %ld", bytes); (void) fflush(stdout); while (bytes >= hashbytes) hashbytes += TICKBYTES; } if (ferror(dout)) break; (void) putc('\r', dout); bytes++; } (void) putc(c, dout); bytes++; /* if (c == '\r') { */ /* (void) putc('\0', dout); (* this violates rfc */ /* bytes++; */ /* } */ } if (hash) { if (bytes < hashbytes) (void) putchar('#'); (void) putchar('\n'); (void) fflush(stdout); } if (tick) { (void) printf("\rBytes transferred: %ld\n", bytes); (void) fflush(stdout); } if (ferror(fin)) fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); if (ferror(dout)) { if (errno != EPIPE) perror("netout"); bytes = -1; } break; } (void) gettimeofday(&stop, (struct timezone *)0); if (closefunc != NULL) (*closefunc)(fin); (void) fclose(dout); /* closes data as well, so discard it */ data = -1; (void) getreply(0); (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); if (bytes > 0) ptransfer("sent", bytes, &start, &stop); return; abort: (void) gettimeofday(&stop, (struct timezone *)0); (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); if (!cpend) { code = -1; return; } if (dout) { (void) fclose(dout); } if (data >= 0) { /* if it just got closed with dout, again won't hurt */ (void) close(data); data = -1; } (void) getreply(0); code = -1; if (closefunc != NULL && fin != NULL) (*closefunc)(fin); if (bytes > 0) ptransfer("sent", bytes, &start, &stop); } static void abortrecv(int ignore) { (void)ignore; mflag = 0; abrtflag = 0; printf("\nreceive aborted\nwaiting for remote to finish abort\n"); (void) fflush(stdout); siglongjmp(recvabort, 1); } void recvrequest(const char *cmd, char *volatile local, char *remote, const char *lmode, int printnames) { FILE *volatile fout, *volatile din = 0; int (*volatile closefunc)(FILE *); void (*volatile oldintp)(int); void (*volatile oldintr)(int); volatile int is_retr, tcrflag, bare_lfs = 0; static unsigned bufsize; static char *buf; volatile long bytes = 0, hashbytes = HASHBYTES; register int c, d; struct timeval start, stop; struct stat st; is_retr = strcmp(cmd, "RETR") == 0; if (is_retr && verbose && printnames) { if (local && *local != '-') printf("local: %s ", local); if (remote) printf("remote: %s\n", remote); } if (proxy && is_retr) { proxtrans(cmd, local, remote); return; } closefunc = NULL; oldintr = NULL; oldintp = NULL; tcrflag = !crflag && is_retr; if (sigsetjmp(recvabort, 1)) { while (cpend) { (void) getreply(0); } if (data >= 0) { (void) close(data); data = -1; } if (oldintr) (void) signal(SIGINT, oldintr); code = -1; return; } oldintr = signal(SIGINT, abortrecv); if (strcmp(local, "-") && *local != '|') { if (access(local, W_OK) < 0) { char *dir = rindex(local, '/'); if (errno != ENOENT && errno != EACCES) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); (void) signal(SIGINT, oldintr); code = -1; return; } if (dir != NULL) *dir = 0; d = access(dir ? local : ".", W_OK); if (dir != NULL) *dir = '/'; if (d < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); (void) signal(SIGINT, oldintr); code = -1; return; } if (!runique && errno == EACCES && chmod(local, 0600) < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); /* * Believe it or not, this was actually * repeated in the original source. */ (void) signal(SIGINT, oldintr); /*(void) signal(SIGINT, oldintr);*/ code = -1; return; } if (runique && errno == EACCES && (local = gunique(local)) == NULL) { (void) signal(SIGINT, oldintr); code = -1; return; } } else if (runique && (local = gunique(local)) == NULL) { (void) signal(SIGINT, oldintr); code = -1; return; } } if (!is_retr) { if (curtype != TYPE_A) changetype(TYPE_A, 0); } else if (curtype != type) { changetype(type, 0); } if (initconn()) { (void) signal(SIGINT, oldintr); code = -1; return; } if (sigsetjmp(recvabort, 1)) goto abort; if (is_retr && restart_point && command("REST %ld", (long) restart_point) != CONTINUE) return; if (remote) { if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); return; } } else { if (command("%s", cmd) != PRELIM) { (void) signal(SIGINT, oldintr); return; } } din = dataconn("r"); if (din == NULL) goto abort; if (strcmp(local, "-") == 0) fout = stdout; else if (*local == '|') { oldintp = signal(SIGPIPE, SIG_IGN); fout = popen(local + 1, "w"); if (fout == NULL) { perror(local+1); goto abort; } closefunc = pclose; } else { fout = fopen(local, lmode); if (fout == NULL) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); goto abort; } closefunc = fclose; } if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) st.st_blksize = BUFSIZ; if (st.st_blksize > bufsize) { if (buf) (void) free(buf); buf = malloc((unsigned)st.st_blksize); if (buf == NULL) { perror("malloc"); bufsize = 0; goto abort; } bufsize = st.st_blksize; } (void) gettimeofday(&start, (struct timezone *)0); switch (curtype) { case TYPE_I: case TYPE_L: if (restart_point && lseek(fileno(fout), (long) restart_point, L_SET) < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); if (closefunc != NULL) (*closefunc)(fout); return; } errno = d = 0; while ((c = read(fileno(din), buf, bufsize)) > 0) { if ((d = write(fileno(fout), buf, c)) != c) break; bytes += c; if (hash && is_retr) { while (bytes >= hashbytes) { (void) putchar('#'); hashbytes += HASHBYTES; } (void) fflush(stdout); } if (tick && (bytes >= hashbytes) && is_retr) { (void) printf("\rBytes transferred: %ld", bytes); (void) fflush(stdout); while (bytes >= hashbytes) hashbytes += TICKBYTES; } } if (hash && bytes > 0) { if (bytes < HASHBYTES) (void) putchar('#'); (void) putchar('\n'); (void) fflush(stdout); } if (tick && is_retr) { (void) printf("\rBytes transferred: %ld\n", bytes); (void) fflush(stdout); } if (c < 0) { if (errno != EPIPE) perror("netin"); bytes = -1; } if (d < c) { if (d < 0) fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); else fprintf(stderr, "%s: short write\n", local); } break; case TYPE_A: if (restart_point) { register int i, n, ch; if (fseek(fout, 0L, L_SET) < 0) goto done; n = restart_point; for (i = 0; i++ < n;) { if ((ch = getc(fout)) == EOF) goto done; if (ch == '\n') i++; } if (fseek(fout, 0L, L_INCR) < 0) { done: fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); if (closefunc != NULL) (*closefunc)(fout); return; } } while ((c = getc(din)) != EOF) { if (c == '\n') bare_lfs++; while (c == '\r') { while (hash && (bytes >= hashbytes) && is_retr) { (void) putchar('#'); (void) fflush(stdout); hashbytes += HASHBYTES; } if (tick && (bytes >= hashbytes) && is_retr) { printf("\rBytes transferred: %ld", bytes); fflush(stdout); while (bytes >= hashbytes) hashbytes += TICKBYTES; } bytes++; if ((c = getc(din)) != '\n' || tcrflag) { if (ferror(fout)) goto break2; (void) putc('\r', fout); if (c == '\0') { bytes++; goto contin2; } if (c == EOF) goto contin2; } } (void) putc(c, fout); bytes++; contin2: ; } break2: if (hash && is_retr) { if (bytes < hashbytes) (void) putchar('#'); (void) putchar('\n'); (void) fflush(stdout); } if (tick && is_retr) { (void) printf("\rBytes transferred: %ld\n", bytes); (void) fflush(stdout); } if (bare_lfs) { printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); printf("File may not have transferred correctly.\n"); } if (ferror(din)) { if (errno != EPIPE) perror("netin"); bytes = -1; } if (ferror(fout)) fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); break; } if (closefunc != NULL) (*closefunc)(fout); (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); (void) gettimeofday(&stop, (struct timezone *)0); (void) fclose(din); /* closes data as well, so discard it */ data = -1; (void) getreply(0); if (bytes > 0 && is_retr) ptransfer("received", bytes, &start, &stop); return; abort: /* abort using RFC959 recommended IP,SYNC sequence */ (void) gettimeofday(&stop, (struct timezone *)0); if (oldintp) (void) signal(SIGPIPE, oldintp); (void) signal(SIGINT, SIG_IGN); if (!cpend) { code = -1; (void) signal(SIGINT, oldintr); return; } abort_remote(din); code = -1; if (closefunc != NULL && fout != NULL) (*closefunc)(fout); if (din) { (void) fclose(din); } if (data >= 0) { /* if it just got closed with din, again won't hurt */ (void) close(data); data = -1; } if (bytes > 0) ptransfer("received", bytes, &start, &stop); (void) signal(SIGINT, oldintr); } /* * Need to start a listen on the data channel before we send the command, * otherwise the server's connect may fail. */ static int initconn(void) { register char *p, *a; int result, tmpno = 0; socklen_t len; int on = 1; int tos; u_long a1,a2,a3,a4,p1,p2; if (passivemode) { data = socket(AF_INET, SOCK_STREAM, 0); if (data < 0) { perror("ftp: socket"); return(1); } if (options & SO_DEBUG && setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) perror("ftp: setsockopt (ignored)"); if (command("PASV") != COMPLETE) { printf("Passive mode refused.\n"); return(1); } /* * What we've got at this point is a string of comma separated * one-byte unsigned integer values, separated by commas. * The first four are the an IP address. The fifth is the MSB * of the port number, the sixth is the LSB. From that we'll * prepare a sockaddr_in. */ if (sscanf(pasv,"%ld,%ld,%ld,%ld,%ld,%ld", &a1,&a2,&a3,&a4,&p1,&p2) != 6) { printf("Passive mode address scan failure. Shouldn't happen!\n"); return(1); } data_addr.sin_family = AF_INET; data_addr.sin_addr.s_addr = htonl((a1 << 24) | (a2 << 16) | (a3 << 8) | a4); data_addr.sin_port = htons((p1 << 8) | p2); if (connect(data, (struct sockaddr *) &data_addr, sizeof(data_addr))<0) { perror("ftp: connect"); return(1); } #ifdef IP_TOS tos = IPTOS_THROUGHPUT; if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(tos)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif return(0); } noport: data_addr = myctladdr; if (sendport) data_addr.sin_port = 0; /* let system pick one */ if (data != -1) (void) close(data); data = socket(AF_INET, SOCK_STREAM, 0); if (data < 0) { perror("ftp: socket"); if (tmpno) sendport = 1; return (1); } if (!sendport) if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { perror("ftp: setsockopt (reuse address)"); goto bad; } if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { perror("ftp: bind"); goto bad; } if (options & SO_DEBUG && setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) perror("ftp: setsockopt (ignored)"); len = sizeof (data_addr); if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { perror("ftp: getsockname"); goto bad; } if (listen(data, 1) < 0) perror("ftp: listen"); if (sendport) { a = (char *)&data_addr.sin_addr; p = (char *)&data_addr.sin_port; #define UC(b) (((int)b)&0xff) result = command("PORT %d,%d,%d,%d,%d,%d", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); if (result == ERROR && sendport == -1) { sendport = 0; tmpno = 1; goto noport; } return (result != COMPLETE); } if (tmpno) sendport = 1; #ifdef IP_TOS on = IPTOS_THROUGHPUT; if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif return (0); bad: (void) close(data), data = -1; if (tmpno) sendport = 1; return (1); } static FILE * dataconn(const char *lmode) { struct sockaddr_in from; int s, tos; socklen_t fromlen = sizeof(from); if (passivemode) return (fdopen(data, lmode)); s = accept(data, (struct sockaddr *) &from, &fromlen); if (s < 0) { perror("ftp: accept"); (void) close(data), data = -1; return (NULL); } (void) close(data); data = s; #ifdef IP_TOS tos = IPTOS_THROUGHPUT; if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) perror("ftp: setsockopt TOS (ignored)"); #endif return (fdopen(data, lmode)); } static void ptransfer(const char *direction, long bytes, const struct timeval *t0, const struct timeval *t1) { struct timeval td; float s, bs; if (verbose) { tvsub(&td, t1, t0); s = td.tv_sec + (td.tv_usec / 1000000.); #define nz(x) ((x) == 0 ? 1 : (x)) bs = bytes / nz(s); printf("%ld bytes %s in %.3g secs (%.2g Kbytes/sec)\n", bytes, direction, s, bs / 1024.0); } } #if 0 tvadd(tsum, t0) struct timeval *tsum, *t0; { tsum->tv_sec += t0->tv_sec; tsum->tv_usec += t0->tv_usec; if (tsum->tv_usec > 1000000) tsum->tv_sec++, tsum->tv_usec -= 1000000; } #endif static void tvsub(struct timeval *tdiff, const struct timeval *t1, const struct timeval *t0) { tdiff->tv_sec = t1->tv_sec - t0->tv_sec; tdiff->tv_usec = t1->tv_usec - t0->tv_usec; if (tdiff->tv_usec < 0) tdiff->tv_sec--, tdiff->tv_usec += 1000000; } static void psabort(int ignore) { (void)ignore; abrtflag++; } void pswitch(int flag) { void (*oldintr)(int); static struct comvars { int connect; char name[MAXHOSTNAMELEN]; struct sockaddr_in mctl; struct sockaddr_in hctl; FILE *in; FILE *out; int tpe; int curtpe; int cpnd; int sunqe; int runqe; int mcse; int ntflg; char nti[17]; char nto[17]; int mapflg; char mi[MAXPATHLEN]; char mo[MAXPATHLEN]; } proxstruct, tmpstruct; struct comvars *ip, *op; abrtflag = 0; oldintr = signal(SIGINT, psabort); if (flag) { if (proxy) return; ip = &tmpstruct; op = &proxstruct; proxy++; } else { if (!proxy) return; ip = &proxstruct; op = &tmpstruct; proxy = 0; } ip->connect = connected; connected = op->connect; if (hostname) { (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); ip->name[strlen(ip->name)] = '\0'; } else { ip->name[0] = 0; } hostname = op->name; ip->hctl = hisctladdr; hisctladdr = op->hctl; ip->mctl = myctladdr; myctladdr = op->mctl; ip->in = cin; cin = op->in; ip->out = cout; cout = op->out; ip->tpe = type; type = op->tpe; ip->curtpe = curtype; curtype = op->curtpe; ip->cpnd = cpend; cpend = op->cpnd; ip->sunqe = sunique; sunique = op->sunqe; ip->runqe = runique; runique = op->runqe; ip->mcse = mcase; mcase = op->mcse; ip->ntflg = ntflag; ntflag = op->ntflg; (void) strncpy(ip->nti, ntin, 16); (ip->nti)[strlen(ip->nti)] = '\0'; (void) strcpy(ntin, op->nti); (void) strncpy(ip->nto, ntout, 16); (ip->nto)[strlen(ip->nto)] = '\0'; (void) strcpy(ntout, op->nto); ip->mapflg = mapflag; mapflag = op->mapflg; (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); (ip->mi)[strlen(ip->mi)] = '\0'; (void) strcpy(mapin, op->mi); (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); (ip->mo)[strlen(ip->mo)] = '\0'; (void) strcpy(mapout, op->mo); (void) signal(SIGINT, oldintr); if (abrtflag) { abrtflag = 0; (*oldintr)(SIGINT); } } static void abortpt(int ignore) { (void)ignore; printf("\n"); fflush(stdout); ptabflg++; mflag = 0; abrtflag = 0; siglongjmp(ptabort, 1); } static void proxtrans(const char *cmd, char *local, char *remote) { void (*volatile oldintr)(int); volatile int secndflag = 0, prox_type, nfnd; const char *volatile cmd2; fd_set mask; if (strcmp(cmd, "RETR")) cmd2 = "RETR"; else cmd2 = runique ? "STOU" : "STOR"; if ((prox_type = type) == 0) { if (unix_server && unix_proxy) prox_type = TYPE_I; else prox_type = TYPE_A; } if (curtype != prox_type) changetype(prox_type, 1); if (command("PASV") != COMPLETE) { printf("proxy server does not support third party transfers.\n"); return; } pswitch(0); if (!connected) { printf("No primary connection\n"); pswitch(1); code = -1; return; } if (curtype != prox_type) changetype(prox_type, 1); if (command("PORT %s", pasv) != COMPLETE) { pswitch(1); return; } if (sigsetjmp(ptabort, 1)) goto abort; oldintr = signal(SIGINT, abortpt); if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); pswitch(1); return; } sleep(2); pswitch(1); secndflag++; if (command("%s %s", cmd2, local) != PRELIM) goto abort; ptflag++; (void) getreply(0); pswitch(0); (void) getreply(0); (void) signal(SIGINT, oldintr); pswitch(1); ptflag = 0; printf("local: %s remote: %s\n", local, remote); return; abort: (void) signal(SIGINT, SIG_IGN); ptflag = 0; if (strcmp(cmd, "RETR") && !proxy) pswitch(1); else if (!strcmp(cmd, "RETR") && proxy) pswitch(0); if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ if (command("%s %s", cmd2, local) != PRELIM) { pswitch(0); if (cpend) abort_remote((FILE *) NULL); } pswitch(1); if (ptabflg) code = -1; (void) signal(SIGINT, oldintr); return; } if (cpend) abort_remote((FILE *) NULL); pswitch(!proxy); if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ if (command("%s %s", cmd2, local) != PRELIM) { pswitch(0); if (cpend) abort_remote((FILE *) NULL); pswitch(1); if (ptabflg) code = -1; (void) signal(SIGINT, oldintr); return; } } if (cpend) abort_remote((FILE *) NULL); pswitch(!proxy); if (cpend) { FD_ZERO(&mask); FD_SET(fileno(cin), &mask); if ((nfnd = empty(&mask, fileno(cin), 10)) <= 0) { if (nfnd < 0) { perror("abort"); } if (ptabflg) code = -1; lostpeer(0); } (void) getreply(0); (void) getreply(0); } if (proxy) pswitch(0); pswitch(1); if (ptabflg) code = -1; (void) signal(SIGINT, oldintr); } void reset(void) { fd_set mask; int nfnd = 1; FD_ZERO(&mask); while (nfnd > 0) { FD_SET(fileno(cin), &mask); if ((nfnd = empty(&mask, fileno(cin), 0)) < 0) { perror("reset"); code = -1; lostpeer(0); } else if (nfnd) { (void) getreply(0); } } } static char * gunique(char *local) { static char new[MAXPATHLEN]; char *cp = rindex(local, '/'); int d, count=0; char ext = '1'; if (cp) *cp = '\0'; d = access(cp ? local : ".", W_OK); if (cp) *cp = '/'; if (d < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); return((char *) 0); } (void) strcpy(new, local); cp = new + strlen(new); *cp++ = '.'; while (!d) { if (++count == 100) { printf("runique: can't find unique file name.\n"); return((char *) 0); } *cp++ = ext; *cp = '\0'; if (ext == '9') ext = '0'; else ext++; if ((d = access(new, F_OK)) < 0) break; if (ext != '0') cp--; else if (*(cp - 2) == '.') *(cp - 1) = '1'; else { *(cp - 2) = *(cp - 2) + 1; cp--; } } return(new); } static void abort_remote(FILE *din) { char buf[BUFSIZ]; int nfnd, hifd; fd_set mask; /* * send IAC in urgent mode instead of DM because 4.3BSD places oob mark * after urgent byte rather than before as is protocol now */ snprintf(buf, sizeof(buf), "%c%c%c", IAC, IP, IAC); if (send(fileno(cout), buf, 3, MSG_OOB) != 3) perror("abort"); fprintf(cout,"%cABOR\r\n", DM); (void) fflush(cout); FD_ZERO(&mask); FD_SET(fileno(cin), &mask); hifd = fileno(cin); if (din) { FD_SET(fileno(din), &mask); if (hifd < fileno(din)) hifd = fileno(din); } if ((nfnd = empty(&mask, hifd, 10)) <= 0) { if (nfnd < 0) { perror("abort"); } if (ptabflg) code = -1; lostpeer(0); } if (din && FD_ISSET(fileno(din), &mask)) { while (read(fileno(din), buf, BUFSIZ) > 0) /* LOOP */; } if (getreply(0) == ERROR && code == 552) { /* 552 needed for nic style abort */ (void) getreply(0); } (void) getreply(0); } netkit-ftp-0.17/ftp/ftp_var.h100644 144 144 15162 6775450525 15501 0ustar dhollandpeople/* * Copyright (c) 1985, 1989 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. * * from: @(#)ftp_var.h 5.9 (Berkeley) 6/1/90 * $Id: ftp_var.h,v 1.12 1999/10/02 18:39:17 dholland Exp $ */ /* * FTP global variables. */ #include #include /* * Tick counter step size. */ #define TICKBYTES 10240 #ifndef Extern #define Extern extern #endif /* * Options and other state info. */ Extern int rl_inhibit; /* disable readline support */ Extern int traceflag; /* trace packets exchanged */ Extern int hash; /* print # for each buffer transferred */ Extern int tick; /* print byte counter during transfers */ Extern int sendport; /* use PORT cmd for each data connection */ Extern int verbose; /* print messages coming back from server */ Extern int connected; /* connected to server */ Extern int fromatty; /* input is from a terminal */ Extern int interactive; /* interactively prompt on m* cmds */ Extern int debug; /* debugging level */ Extern int bell; /* ring bell on cmd completion */ Extern int doglob; /* glob local file names */ Extern int autologin; /* establish user account on connection */ Extern int proxy; /* proxy server connection active */ Extern int proxflag; /* proxy connection exists */ Extern int sunique; /* store files on server with unique name */ Extern int runique; /* store local files with unique name */ Extern int mcase; /* map upper to lower case for mget names */ Extern int ntflag; /* use ntin ntout tables for name xlation */ Extern int mapflag; /* use mapin mapout templates on file names */ Extern int code; /* return/reply code for ftp command */ Extern int crflag; /* if 1, strip car. rets. on ascii gets */ Extern char pasv[64]; /* passive port for proxy data connection */ Extern int passivemode; /* passive mode enabled */ Extern char *altarg; /* argv[1] with no shell-like preprocessing */ Extern char ntin[17]; /* input translation table */ Extern char ntout[17]; /* output translation table */ Extern char mapin[MAXPATHLEN]; /* input map template */ Extern char mapout[MAXPATHLEN]; /* output map template */ Extern char typename[32]; /* name of file transfer type */ Extern int type; /* requested file transfer type */ Extern int curtype; /* current file transfer type */ Extern char structname[32]; /* name of file transfer structure */ Extern int stru; /* file transfer structure */ Extern char formname[32]; /* name of file transfer format */ Extern int form; /* file transfer format */ Extern char modename[32]; /* name of file transfer mode */ Extern int mode; /* file transfer mode */ Extern char bytename[32]; /* local byte size in ascii */ Extern int bytesize; /* local byte size in binary */ Extern char *hostname; /* name of host connected to */ Extern int unix_server; /* server is unix, can use binary for ascii */ Extern int unix_proxy; /* proxy is unix, can use binary for ascii */ /*Extern struct servent *sp;*/ /* service spec for tcp/ftp */ Extern int ftp_port; /* htons'd port number for ftp service */ Extern sigjmp_buf toplevel; /* non-local goto stuff for cmd scanner */ Extern char line[200]; /* input line buffer */ Extern char *stringbase; /* current scan point in line buffer */ Extern char argbuf[200]; /* argument storage buffer */ Extern char *argbase; /* current storage point in arg buffer */ Extern int cpend; /* flag: if != 0, then pending server reply */ Extern int mflag; /* flag: if != 0, then active multi command */ Extern int options; /* used during socket creation */ /* * 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 */ /* Exactly one of these should be non-NULL. */ void (*c_handler_v)(int, char **); /* function to call */ void (*c_handler_0)(void); void (*c_handler_1)(const char *); }; struct macel { char mac_name[9]; /* macro name */ char *mac_start; /* start of macro in macbuf */ char *mac_end; /* end of macro in macbuf */ }; Extern int macnum; /* number of defined macros */ Extern struct macel macros[16]; Extern char macbuf[4096]; #define MACBUF_SIZE 4096 char *hookup(char *host, int port); struct cmd *getcmd(const char *); char **makeargv(int *pargc, char **parg); int dologin(const char *host); int command(const char *fmt, ...); void sendrequest(const char *cmd, char *local, char *remote, int printnames); void recvrequest(const char *cmd, char *local, char *remote, const char *lmode, int printnames); int another(int *pargc, char ***pargv, const char *prompt); void blkfree(char **av0); void fatal(const char *msg); int getreply(int expecteof); void domacro(int argc, char *argv[]); void pswitch(int flag); int xruserpass(const char *host, char **aname, char **apass, char **aacct); void setpeer(int argc, char *argv[]); void quit(void); void changetype(int newtype, int show); netkit-ftp-0.17/ftp/glob.c100644 144 144 31044 6775403703 14747 0ustar dhollandpeople/* * Copyright (c) 1980 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ /* * From: @(#)glob.c 5.9 (Berkeley) 2/25/91 */ char glob_rcsid[] = "$Id: glob.c,v 1.9 1999/10/02 13:25:23 netbug Exp $"; /* * C-shell glob for random programs. */ #include #include #include #include #include #include #include #include #include "ftp_var.h" /* for protos only */ #include "glob.h" #define QUOTE 0200 #define TRIM 0177 #define eq(a,b) (strcmp(a, b)==0) #define GAVSIZ (ARG_MAX/6) #define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) const char *globerr; extern const char *home; typedef struct { const char *text; } centry; typedef struct { char *text; } entry; static entry *gargv; /* Pointer to the (stack) arglist */ static entry *sortbas; static int gargc; /* Number args in gargv */ static int gnleft; /* space left before we hit max args length */ static short gflag; static int globcnt; static const char *globchars = "`{[*?"; static char *gpath; static char *gpathp, *lastgpathp; static int globbed; static const char *entp; static int tglob(char c); static char *strspl(const char *, const char *); static char *strend(char *); static char **copyblk(entry *); static char **cloneblk(const centry *); static void addpath(char c); static void acollect(const char *); static void collect(const char *); static void expand(const char *); static void Gcat(const char *, const char *); static void ginit(entry *); static void matchdir(const char *); static void rscan(centry *, int (*f)(char)); static void sort(void); static void efree(entry *); static int amatch(const char *, const char *); static int execbrc(const char *, const char *); static int match(const char *, const char *); static int gethdir(char *homedir); static int letter(char c); static int digit(char c); static int any(int c, const char *s); char ** ftpglob(const char *v) { char agpath[BUFSIZ]; entry agargv[GAVSIZ]; centry vv[2]; vv[0].text = v; vv[1].text = NULL; gflag = 0; rscan(vv, tglob); if (gflag == 0) { return cloneblk(vv); } globerr = 0; gpath = agpath; gpathp = gpath; *gpathp = 0; /* added ()'s to sizeof, (ambigious math for the compiler) */ lastgpathp = agpath + (sizeof(agpath)- 2); ginit(agargv); globcnt = 0; collect(v); if (globcnt == 0 && (gflag&1)) { efree(gargv); gargv = NULL; return NULL; } else { char **rv = copyblk(gargv); gargv = NULL; return rv; } } static void ginit(entry *agargv) { agargv[0].text = NULL; gargv = agargv; sortbas = agargv; gargc = 0; gnleft = ARG_MAX - 4; } static void collect(const char *as) { if (eq(as, "{") || eq(as, "{}")) { Gcat(as, ""); sort(); } else { acollect(as); } } static void acollect(const char *as) { int ogargc = gargc; gpathp = gpath; *gpathp = 0; globbed = 0; expand(as); if (gargc != ogargc) sort(); } static void sort(void) { entry *p1, *p2, c; entry *Gvp = &gargv[gargc]; p1 = sortbas; while (p1 < Gvp-1) { p2 = p1; while (++p2 < Gvp) if (strcmp(p1->text, p2->text) > 0) c = *p1, *p1 = *p2, *p2 = c; p1++; } sortbas = Gvp; } static void expand(const char *as) { const char *cs; const char *oldcs; char *sgpathp; struct stat stb; sgpathp = gpathp; cs = as; if (*cs == '~' && gpathp == gpath) { addpath('~'); for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) addpath(*cs++); if (!*cs || *cs == '/') { if (gpathp != gpath + 1) { *gpathp = 0; if (gethdir(gpath + 1)) globerr = "Unknown user name after ~"; /* * Was: strcpy(gpath, gpath + 1); * but that's WRONG */ memmove(gpath, gpath+1, strlen(gpath+1)+1); } else { (void) strcpy(gpath, home); } gpathp = strend(gpath); } } while (!any(*cs, globchars)) { if (*cs == 0) { if (!globbed) Gcat(gpath, ""); else if (stat(gpath, &stb) >= 0) { Gcat(gpath, ""); globcnt++; } goto endit; } addpath(*cs++); } oldcs = cs; while (cs > as && *cs != '/') cs--, gpathp--; if (*cs == '/') cs++, gpathp++; *gpathp = 0; if (*oldcs == '{') { (void) execbrc(cs, ((char *)0)); return; } matchdir(cs); endit: gpathp = sgpathp; *gpathp = 0; } static void matchdir(const char *pattern) { struct stat stb; register struct dirent *dp; DIR *dirp; #if 0 #ifdef __linux__ if (gpath == NULL || *gpath == '\0') gpath = "./"; #endif #endif dirp = opendir((!gpath || !*gpath) ? "./" : gpath); if (dirp == NULL) { if (globbed) return; goto patherr2; } if (fstat(dirfd(dirp), &stb) < 0) goto patherr1; if (!isdir(stb)) { errno = ENOTDIR; goto patherr1; } while ((dp = readdir(dirp)) != NULL) { if (dp->d_ino == 0) continue; if (match(dp->d_name, pattern)) { Gcat(gpath, dp->d_name); globcnt++; } } closedir(dirp); return; patherr1: closedir(dirp); patherr2: globerr = "Bad directory components"; } static int execbrc(const char *p, const char *s) { char restbuf[BUFSIZ + 2]; const char *pe, *pm, *pl; int brclev = 0; char *lm, *sgpathp; for (lm = restbuf; *p != '{'; *lm++ = *p++) continue; for (pe = ++p; *pe; pe++) switch (*pe) { case '{': brclev++; continue; case '}': if (brclev == 0) goto pend; brclev--; continue; case '[': for (pe++; *pe && *pe != ']'; pe++) continue; continue; } pend: brclev = 0; for (pl = pm = p; pm <= pe; pm++) switch (*pm & (QUOTE|TRIM)) { case '{': brclev++; continue; case '}': if (brclev) { brclev--; continue; } goto doit; case ','|QUOTE: case ',': if (brclev) continue; doit: #if 0 savec = *pm; *pm = 0; strcpy(lm, pl); *pm = savec; #else strncpy(lm, pl, pm-pl); lm[pm-pl] = 0; #endif (void) strcat(restbuf, pe + 1); if (s == 0) { sgpathp = gpathp; expand(restbuf); gpathp = sgpathp; *gpathp = 0; } else if (amatch(s, restbuf)) { return (1); } sort(); pl = pm + 1; if (brclev) return (0); continue; case '[': for (pm++; *pm && *pm != ']'; pm++) continue; if (!*pm) pm--; continue; } if (brclev) goto doit; return (0); } static int match(const char *s, const char *p) { int c; const char *sentp; char sglobbed = globbed; if (*s == '.' && *p != '.') return (0); sentp = entp; entp = s; c = amatch(s, p); entp = sentp; globbed = sglobbed; return (c); } static int amatch(const char *s, const char *p) { register int scc; int ok, lc; char *sgpathp; struct stat stb; int c, cc; globbed = 1; for (;;) { scc = *s++ & TRIM; switch (c = *p++) { case '{': return (execbrc(p - 1, s - 1)); case '[': ok = 0; lc = 077777; while ((cc = *p++) != 0) { if (cc == ']') { if (ok) break; return (0); } if (cc == '-') { if (lc <= scc && scc <= *p++) ok++; } else if (scc == (lc = cc)) ok++; } if (cc == 0) { if (ok) p--; else return 0; } continue; case '*': if (!*p) return (1); if (*p == '/') { p++; goto slash; } s--; do { if (amatch(s, p)) return (1); } while (*s++); return (0); case 0: return (scc == 0); default: if (c != scc) return (0); continue; case '?': if (scc == 0) return (0); continue; case '/': if (scc) return (0); slash: s = entp; sgpathp = gpathp; while (*s) addpath(*s++); addpath('/'); if (stat(gpath, &stb) == 0 && isdir(stb)) { if (*p == 0) { Gcat(gpath, ""); globcnt++; } else { expand(p); } } gpathp = sgpathp; *gpathp = 0; return (0); } } } #if 0 /* dead code */ static int Gmatch(const char *s, const char *p) { register int scc; int ok, lc; int c, cc; for (;;) { scc = *s++ & TRIM; switch (c = *p++) { case '[': ok = 0; lc = 077777; while ((cc = *p++) != 0) { if (cc == ']') { if (ok) break; return (0); } if (cc == '-') { if (lc <= scc && scc <= *p++) ok++; } else if (scc == (lc = cc)) ok++; } if (cc == 0) if (ok) p--; else return 0; continue; case '*': if (!*p) return (1); for (s--; *s; s++) if (Gmatch(s, p)) return (1); return (0); case 0: return (scc == 0); default: if ((c & TRIM) != scc) return (0); continue; case '?': if (scc == 0) return (0); continue; } } } #endif static void Gcat(const char *s1, const char *s2) { int len = strlen(s1) + strlen(s2) + 1; if (len >= gnleft || gargc >= GAVSIZ - 1) { globerr = "Arguments too long"; } else { gargc++; gnleft -= len; gargv[gargc].text = NULL; gargv[gargc - 1].text = strspl(s1, s2); } } static void addpath(char c) { if (gpathp >= lastgpathp) globerr = "Pathname too long"; else { *gpathp++ = c; *gpathp = 0; } } static void rscan(centry *t, int (*f)(char)) { const char *p; char c; while ((p = (t++)->text) != NULL) { if (f == tglob) { if (*p == '~') gflag |= 2; else if (eq(p, "{") || eq(p, "{}")) continue; } while ((c = *p++) != 0) (*f)(c); } } static int tglob(char c) { if (any(c, globchars)) gflag |= c == '{' ? 2 : 1; return (c); } static int letter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } static int digit(char c) { return (c >= '0' && c <= '9'); } static int any(int c, const char *s) { while (*s) if (*s++ == c) return 1; return 0; } static int cblklen(const centry *av) { int i = 0; while ((av++)->text) i++; return i; } static int blklen(const entry *av) { int i = 0; while ((av++)->text) i++; return i; } void blkfree(char **av) { int i; for (i=0; av[i]; i++) free(av[i]); } static void efree(entry *av) { int i; for (i=0; av[i].text; i++) free(av[i].text); } static char * strspl(const char *cp, const char *dp) { char *ep = malloc(strlen(cp) + strlen(dp) + 1); if (ep == NULL) fatal("Out of memory"); strcpy(ep, cp); strcat(ep, dp); return ep; } static char ** copyblk(entry *v) { int i; char **nv = malloc((blklen(v) + 1) * sizeof(char **)); if (nv == NULL) fatal("Out of memory"); for (i=0; v[i].text; i++) { nv[i] = v[i].text; v[i].text = NULL; } nv[i] = NULL; return nv; } static char ** cloneblk(const centry *v) { int i; char **nv = malloc((cblklen(v) + 1) * sizeof(char **)); if (nv == NULL) fatal("Out of memory"); for (i=0; v[i].text; i++) { nv[i] = strdup(v[i].text); } nv[i] = NULL; return nv; } static char * strend(char *cp) { while (*cp) cp++; return (cp); } /* * Extract a home directory from the password file * The argument points to a buffer where the name of the * user whose home directory is sought is currently. * We write the home directory of the user back there. * * XXX, this needs buffer length checking and stuff. */ static int gethdir(char *homedir) { register struct passwd *pp = getpwnam(homedir); if (!pp || homedir + strlen(pp->pw_dir) >= lastgpathp) return 1; strcpy(homedir, pp->pw_dir); return 0; } netkit-ftp-0.17/ftp/glob.h100644 144 144 3663 6204460340 14725 0ustar dhollandpeople/* * Copyright (c) 1980 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 const char *globerr; extern const char *home; /* we expect this to be set for us */ char **ftpglob(const char *v); void blkfree(char **av0); netkit-ftp-0.17/ftp/main.c100644 144 144 27044 6775403703 14755 0ustar dhollandpeople/* * Copyright (c) 1985, 1989 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ char copyright[] = "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n" "All rights reserved.\n"; /* * from: @(#)main.c 5.18 (Berkeley) 3/1/91 */ char main_rcsid[] = "$Id: main.c,v 1.15 1999/10/02 13:25:23 netbug Exp $"; /* * FTP User Program -- Command Interface. */ #include #include #include /* #include <--- unused? */ #include #include #include #include #include #include #include #include #include #ifdef __USE_READLINE__ #include #include #endif #define Extern #include "ftp_var.h" int traceflag = 0; const char *home = "/"; extern FILE *cout; extern int data; extern struct cmd cmdtab[]; extern int NCMDS; void intr(int); void lostpeer(int); void help(int argc, char *argv[]); static void cmdscanner(int top); static char *slurpstring(void); static void usage(void) { printf("\n\tUsage: { ftp | pftp } [-pinegvtd] [hostname]\n"); printf("\t -p: enable passive mode (default for pftp)\n"); printf("\t -i: turn off prompting during mget\n"); printf("\t -n: inhibit auto-login\n"); printf("\t -e: disable readline support, if present\n"); printf("\t -g: disable filename globbing\n"); printf("\t -v: verbose mode\n"); printf("\t -t: enable packet tracing [nonfunctional]\n"); printf("\t -d: enable debugging\n"); printf("\n"); } int main(volatile int argc, char **volatile argv) { register char *cp; struct servent *sp; int top; struct passwd *pw = NULL; char homedir[MAXPATHLEN]; tick = 0; sp = getservbyname("ftp", "tcp"); if (sp == 0) { fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); exit(1); } ftp_port = sp->s_port; doglob = 1; interactive = 1; autologin = 1; passivemode = 0; cp = strrchr(argv[0], '/'); cp = (cp == NULL) ? argv[0] : cp+1; if (strcmp(cp, "pftp") == 0) passivemode = 1; #ifdef __USE_READLINE__ /* * Set terminal type so libreadline can parse .inputrc correctly */ rl_terminal_name = getenv("TERM"); #endif argc--, argv++; while (argc > 0 && **argv == '-') { for (cp = *argv + 1; *cp; cp++) switch (*cp) { case 'd': options |= SO_DEBUG; debug++; break; case 'v': verbose++; break; case 't': traceflag++; break; case 'i': interactive = 0; break; case 'n': autologin = 0; break; case 'p': passivemode = 1; break; case 'g': doglob = 0; break; case 'e': rl_inhibit = 1; break; case 'h': usage(); exit(0); default: fprintf(stdout, "ftp: %c: unknown option\n", *cp); exit(1); } argc--, argv++; } fromatty = isatty(fileno(stdin)); if (fromatty) verbose++; cpend = 0; /* no pending replies */ proxy = 0; /* proxy not active */ crflag = 1; /* strip c.r. on ascii gets */ sendport = -1; /* not using ports */ /* * Set up the home directory in case we're globbing. */ cp = getlogin(); if (cp != NULL) { pw = getpwnam(cp); } if (pw == NULL) pw = getpwuid(getuid()); if (pw != NULL) { strncpy(homedir, pw->pw_dir, sizeof(homedir)); homedir[sizeof(homedir)-1] = 0; home = homedir; } if (argc > 0) { if (sigsetjmp(toplevel, 1)) exit(0); (void) signal(SIGINT, intr); (void) signal(SIGPIPE, lostpeer); setpeer(argc + 1, argv - 1); } top = sigsetjmp(toplevel, 1) == 0; if (top) { (void) signal(SIGINT, intr); (void) signal(SIGPIPE, lostpeer); } for (;;) { cmdscanner(top); top = 1; } } void intr(int ignore) { (void)ignore; siglongjmp(toplevel, 1); } void lostpeer(int ignore) { (void)ignore; if (connected) { if (cout != NULL) { shutdown(fileno(cout), 1+1); fclose(cout); cout = NULL; } if (data >= 0) { shutdown(data, 1+1); close(data); data = -1; } connected = 0; } pswitch(1); if (connected) { if (cout != NULL) { shutdown(fileno(cout), 1+1); fclose(cout); cout = NULL; } connected = 0; } proxflag = 0; pswitch(0); } /*char * tail(filename) char *filename; { register char *s; while (*filename) { s = rindex(filename, '/'); if (s == NULL) break; if (s[1]) return (s + 1); *s = '\0'; } return (filename); } */ static char *get_input_line(char *buf, int buflen) { #ifdef __USE_READLINE__ if (fromatty && !rl_inhibit) { char *lineread = readline("ftp> "); if (!lineread) return NULL; strncpy(buf, lineread, buflen); buf[buflen-1] = 0; if (lineread[0]) add_history(lineread); free(lineread); return buf; } #endif if (fromatty) { printf("ftp> "); fflush(stdout); } return fgets(buf, buflen, stdin); } /* * Command parser. */ static void cmdscanner(int top) { int margc; char *marg; char **margv; register struct cmd *c; register int l; if (!top) (void) putchar('\n'); for (;;) { if (!get_input_line(line, sizeof(line))) { quit(); } l = strlen(line); if (l == 0) break; if (line[--l] == '\n') { if (l == 0) break; line[l] = '\0'; } else if (l == sizeof(line) - 2) { printf("sorry, input line too long\n"); while ((l = getchar()) != '\n' && l != EOF) /* void */; break; } /* else it was a line without a newline */ margv = makeargv(&margc, &marg); if (margc == 0) { continue; } c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); continue; } if (c == NULL) { printf("?Invalid command\n"); continue; } if (c->c_conn && !connected) { printf("Not connected.\n"); continue; } if (c->c_handler_v) c->c_handler_v(margc, margv); else if (c->c_handler_0) c->c_handler_0(); else c->c_handler_1(marg); if (bell && c->c_bell) putchar('\007'); if (c->c_handler_v != help) break; } (void) signal(SIGINT, intr); (void) signal(SIGPIPE, lostpeer); } struct cmd * getcmd(const char *name) { const char *p, *q; struct cmd *c, *found; int nmatches, longest; longest = 0; nmatches = 0; found = 0; for (c = cmdtab; (p = c->c_name) != NULL; c++) { for (q = name; *q == *p++; q++) if (*q == 0) /* exact match? */ return (c); if (!*q) { /* the name was a prefix */ if (q - name > longest) { longest = q - name; nmatches = 1; found = c; } else if (q - name == longest) nmatches++; } } if (nmatches > 1) return ((struct cmd *)-1); return (found); } /* * Slice a string up into argc/argv. */ int slrflag; char ** makeargv(int *pargc, char **parg) { static char *rargv[20]; int rargc = 0; char **argp; argp = rargv; stringbase = line; /* scan from first of buffer */ argbase = argbuf; /* store from first of buffer */ slrflag = 0; while ((*argp++ = slurpstring())!=NULL) rargc++; *pargc = rargc; if (parg) *parg = altarg; return rargv; } /* * Parse string into argbuf; * implemented with FSM to * handle quoting and strings */ static char * slurpstring(void) { static char excl[] = "!", dols[] = "$"; int got_one = 0; register char *sb = stringbase; register char *ap = argbase; char *tmp = argbase; /* will return this if token found */ if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ switch (slrflag) { /* and $ as token for macro invoke */ case 0: slrflag++; stringbase++; return ((*sb == '!') ? excl : dols); /* NOTREACHED */ case 1: slrflag++; altarg = stringbase; break; default: break; } } S0: switch (*sb) { case '\0': goto OUT; case ' ': case '\t': sb++; goto S0; default: switch (slrflag) { case 0: slrflag++; break; case 1: slrflag++; altarg = sb; break; default: break; } goto S1; } S1: switch (*sb) { case ' ': case '\t': case '\0': goto OUT; /* end of token */ case '\\': sb++; goto S2; /* slurp next character */ case '"': sb++; goto S3; /* slurp quoted string */ default: *ap++ = *sb++; /* add character to token */ got_one = 1; goto S1; } S2: switch (*sb) { case '\0': goto OUT; default: *ap++ = *sb++; got_one = 1; goto S1; } S3: switch (*sb) { case '\0': goto OUT; case '"': sb++; goto S1; default: *ap++ = *sb++; got_one = 1; goto S3; } OUT: if (got_one) *ap++ = '\0'; argbase = ap; /* update storage pointer */ stringbase = sb; /* update scan pointer */ if (got_one) { return(tmp); } switch (slrflag) { case 0: slrflag++; break; case 1: slrflag++; altarg = NULL; break; default: break; } return NULL; } #define HELPINDENT ((int) sizeof ("directory")) /* * Help command. * Call each command handler with argc == 0 and argv[0] == name. */ void help(int argc, char *argv[]) { struct cmd *c; if (argc == 1) { int i, j, w; unsigned k; int columns, width = 0, lines; printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { int len = strlen(c->c_name); if (len > width) width = len; } width = (width + 8) &~ 7; columns = 80 / width; if (columns == 0) columns = 1; lines = (NCMDS + columns - 1) / columns; for (i = 0; i < lines; i++) { for (j = 0; j < columns; j++) { c = cmdtab + j * lines + i; if (c->c_name && (!proxy || c->c_proxy)) { printf("%s", c->c_name); } else if (c->c_name) { for (k=0; k < strlen(c->c_name); k++) { (void) putchar(' '); } } if (c + lines >= &cmdtab[NCMDS]) { printf("\n"); break; } w = strlen(c->c_name); while (w < width) { w = (w + 8) &~ 7; (void) putchar('\t'); } } } return; } while (--argc > 0) { register char *arg; arg = *++argv; c = getcmd(arg); if (c == (struct cmd *)-1) printf("?Ambiguous help command %s\n", arg); else if (c == NULL) printf("?Invalid help command %s\n", arg); else printf("%-*s\t%s\n", HELPINDENT, c->c_name, c->c_help); } } netkit-ftp-0.17/ftp/netrc.5100644 144 144 11061 7141140313 15035 0ustar dhollandpeople.\" Copyright (c) 1985, 1989, 1990 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. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. 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. .\" .\" from: @(#)ftp.1 6.18 (Berkeley) 7/30/91 .\" from: ftp.1,v 1.2 1997/06/08 20:01:35 dholland Exp .\" $Id: netrc.5,v 1.12 2000/07/30 23:56:59 dholland Exp $ .\" .Dd September 23, 1997 .Dt NETRC 5 .Os "Linux NetKit (0.17)" .Sh NAME .Nm netrc, .netrc .Nd user configuration for ftp .Sh DESCRIPTION This file contains configuration and autologin information for the File Transfer Protocol client .Xr ftp 1 . .Pp The .Pa .netrc file contains login and initialization information used by the auto-login process. It resides in the user's home directory. The following tokens are recognized; they may be separated by spaces, tabs, or new-lines: .Bl -tag -width password .It Ic machine Ar name Identify a remote machine .Ar name . The auto-login process searches the .Pa .netrc file for a .Ic machine token that matches the remote machine specified on the .Nm ftp command line or as an .Ic open command argument. Once a match is made, the subsequent .Pa .netrc tokens are processed, stopping when the end of file is reached or another .Ic machine or a .Ic default token is encountered. .It Ic default This is the same as .Ic machine .Ar name except that .Ic default matches any name. There can be only one .Ic default token, and it must be after all .Ic machine tokens. This is normally used as: .Pp .Dl default login anonymous password user@site .Pp thereby giving the user .Ar automatic anonymous ftp login to machines not specified in .Pa .netrc . This can be overridden by using the .Fl n flag to disable auto-login. .It Ic login Ar name Identify a user on the remote machine. If this token is present, the auto-login process will initiate a login using the specified .Ar name . .It Ic password Ar string Supply a password. If this token is present, the auto-login process will supply the specified string if the remote server requires a password as part of the login process. Note that if this token is present in the .Pa .netrc file for any user other than .Ar anonymous , .Nm ftp will abort the auto-login process if the .Pa .netrc is readable by anyone besides the user. .It Ic account Ar string Supply an additional account password. If this token is present, the auto-login process will supply the specified string if the remote server requires an additional account password, or the auto-login process will initiate an .Dv ACCT command if it does not. .It Ic macdef Ar name Define a macro. This token functions like the .Nm ftp .Ic macdef command functions. A macro is defined with the specified name; its contents begin with the next .Pa .netrc line and continue until a null line (consecutive new-line characters) is encountered. If a macro named .Ic init is defined, it is automatically executed as the last step in the auto-login process. .El .Sh SEE ALSO .Xr ftp 1 , .Xr ftpd 8 netkit-ftp-0.17/ftp/pathnames.h100644 144 144 3730 6172032477 15767 0ustar dhollandpeople/* * Copyright (c) 1989 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. * * from: @(#)pathnames.h 5.2 (Berkeley) 6/1/90 * $Id: pathnames.h,v 1.1 1996/07/13 23:46:07 dholland Exp $ */ #include #undef _PATH_TMP #define _PATH_TMP "/tmp/ftpXXXXXX" netkit-ftp-0.17/ftp/ruserpass.c100644 144 144 16510 6775454441 16061 0ustar dhollandpeople/* * Copyright (c) 1985 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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. */ /* * from: @(#)ruserpass.c 5.3 (Berkeley) 3/1/91 */ char ruserpass_rcsid[] = "$Id: ruserpass.c,v 1.9 1999/10/02 19:12:33 dholland Exp $"; #include #include #include #include #include #include #include #include #include "ftp_var.h" static FILE *cfile; static int token(void); #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 xruserpass(const char *host, char **aname, char **apass, char **aacct) { const char *hdir; char buf[BUFSIZ], *tmp; char myname[MAXHOSTNAMELEN]; const char *mydomain; int t, i, c, usedefault = 0; struct stat stb; hdir = getenv("HOME"); if (hdir == NULL) hdir = "."; snprintf(buf, sizeof(buf), "%s/.netrc", hdir); cfile = fopen(buf, "r"); if (cfile == NULL) { if (errno != ENOENT) perror(buf); return(0); } if (gethostname(myname, sizeof(myname)) < 0) myname[0] = '\0'; if ((mydomain = strchr(myname, '.')) == NULL) mydomain = ""; next: while ((t = token())) switch(t) { case DEFAULT: usedefault = 1; /* FALL THROUGH */ case MACH: if (!usedefault) { if (token() != 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 = index(hostname, '.')) != NULL && strcasecmp(tmp, mydomain) == 0 && strncasecmp(hostname, tokval, tmp-hostname) == 0 && tokval[tmp - hostname] == '\0') goto match; if ((tmp = index(host, '.')) != NULL && strcasecmp(tmp, mydomain) == 0 && strncasecmp(host, tokval, tmp - host) == 0 && tokval[tmp - host] == '\0') goto match; continue; } match: while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { case LOGIN: if (token()) { if (*aname == 0) { *aname = malloc((unsigned) strlen(tokval) + 1); (void) strcpy(*aname, tokval); } else { if (strcmp(*aname, tokval)) goto next; } } break; case PASSWD: if (*aname==NULL) { fprintf(stderr, "Error: `password' must follow `login' in .netrc\n"); goto bad; } if (strcmp(*aname, "anonymous") && fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { fprintf(stderr, "Error - .netrc file not correct permissions.\n"); fprintf(stderr, "Remove password or correct mode (should be 600).\n"); goto bad; } if (token() && *apass == 0) { *apass = malloc((unsigned) strlen(tokval) + 1); (void) strcpy(*apass, tokval); } break; case ACCOUNT: if (fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { fprintf(stderr, "Error - .netrc file not correct permissions.\n"); fprintf(stderr, "Remove account or correct mode (should be 600).\n"); goto bad; } if (token() && *aacct == 0) { *aacct = malloc((unsigned) strlen(tokval) + 1); (void) strcpy(*aacct, tokval); } break; case MACDEF: if (proxy) { (void) fclose(cfile); return(0); } while ((c=getc(cfile)) != EOF && (c == ' ' || c == '\t')); if (c == EOF || c == '\n') { printf("Missing macdef name argument.\n"); goto bad; } if (macnum == 16) { printf("Limit of 16 macros have already been defined\n"); 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) { printf("Macro definition missing null line terminator.\n"); goto bad; } *tmp = '\0'; if (c != '\n') { while ((c=getc(cfile)) != EOF && c != '\n'); } if (c == EOF) { printf("Macro definition missing null line terminator.\n"); 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 + MACBUF_SIZE) { if ((c=getc(cfile)) == EOF) { printf("Macro definition missing null line terminator.\n"); goto bad; } *tmp = c; if (*tmp == '\n') { if (*(tmp-1) == '\0') { macros[macnum++].mac_end = tmp - 1; break; } *tmp = '\0'; } tmp++; } if (tmp == macbuf + MACBUF_SIZE) { printf("4K macro buffer exceeded\n"); goto bad; } break; default: fprintf(stderr, "Unknown .netrc keyword %s\n", tokval); break; } goto done; } done: (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)) 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 == '\\') c = getc(cfile); *cp++ = c; } } else { *cp++ = c; while ((c = getc(cfile)) != EOF && c != '\n' && c != '\t' && c != ' ' && c != ',') { if (c == '\\') c = getc(cfile); *cp++ = c; } } *cp = 0; if (tokval[0] == 0) return (0); for (t = toktab; t->tokstr; t++) if (!strcmp(t->tokstr, tokval)) return (t->tval); return (ID); } netkit-ftp-0.17/.cvsignore100644 144 144 10 6775463647 15011 0ustar dhollandpeopleMCONFIG netkit-ftp-0.17/BUGS100644 144 144 116 6411664605 13503 0ustar dhollandpeople- Cleartext passwords should be erased as soon as they are no longer needed. netkit-ftp-0.17/ChangeLog100644 144 144 6571 7136446200 14617 0ustar dhollandpeople8-Jul-2000: Fix misused printf-function call (not %n-exploitable though). 14-Dec-1999: netkit-ftp-0.16 is released. 13-Dec-1999: Add fix from Olaf Kirch for some rather severe lossage with aliased file descriptors. 12-Dec-1999: Add Olaf Kirch's ftp mget fix on top of the existing one. Portions of the old fix probably ought to be backed out. However, what's really needed is a massive cleanup of the code... 14-Sep-1999: Extensive small fixes and cleanups. (Alan Curry, pacman@londo.cqc.com) Security fix relating to passive mode. (Alan Cox, alan@redhat.com) 1-Aug-1999: Complete y2k and y2038 audit. 31-Jul-1999: Redid makefiles/config stuff for new confgen version. 23-Sep-1997: Fix some suspicious strncpys. Don't print an uninitialized buffer if someone EOFs at the username prompt. (Olaf Kirch, okir@ns.lst.de) Added a netrc(5) man page. Added -h option to ftp for help, and -e option to inhibit editing support. Cleaned up readline handling. Various fixes to the ftp(1) man page. (Larry Doolittle, ldoolitt@jlab.org) 17-Aug-1997: Fixed security holes: automatically generated local file paths (those that are supplied by the server or copies of server filenames) are filtered so that they cannot: 1. be pipes or "-" for standard output. 2. be absolute paths. 3. contain ".." path elements. 12-Jun-1997: netkit-ftp-0.10 released. 08-Jun-1997: Fixed doc for "newer" command. (Roderick Schertler, roderick@argon.org) 05-Apr-1997: Added configure script to generate MCONFIG. glibc fixes from HJ Lu. 20-Mar-1997: If using readline, pass it the terminal type, so certain .inputrc constructions work. (Christian Groessler, chris@fast-ag.de) 08-Mar-1997: Split from full NetKit package. Generated this change log from NetKit's. 07-Mar-1997 Changed order of includes in ftp/cmds.c due to a report of breakage with libc 5.4.x. Fixed crash in ftp caused by certain syntax errors in .netrc. Fix symbol name conflict on "trace" between ftp and ncurses. 29-Dec-1996 NetKit-0.09 released. Assorted alpha/glibc patches. (Erik Troan, ewt@redhat.com) Assorted bug fixes from Debian. (Peter Tobias, tobias@et-inf.fho-emden.de) Hardened programs against DNS h_length spoofing attacks. Use inet_aton() everywhere instead of inet_addr(). Fixed crash in ftp if you did "lcd" with no args. Fixed bug in ftp where you couldn't abort an mget. Fixed /tmp security problem in ftp. 22-Aug-1996 NetKit-B-0.08 released. (almost) everything now compiles with lots of warnings turned on. Fixed some memory allocation bugs in ftp. 25-Jul-1996 NetKit-B-0.07A released. 23-Jul-1996 NetKit-B-0.07 released. Integrated a collection of patches that had been lurking on the net, including the 256-ptys support for telnetd and passive mode ftp. Major security fixes, including to fingerd, lpr, rlogin, rsh, talkd, and telnetd. Do *not* use the sliplogin from earlier versions of this package, either. Much of the code builds without libbsd.a or bsd includes. Massive code cleanup. Almost everything compiles clean with gcc -Wall now. rusers and rusersd do not; patches to rpcgen to fix this would be appreciated if anyone feels like it. New maintainer: David A. Holland, dholland@hcs.harvard.edu date not known NetKit-B-0.06 released. date not known NetKit-B-0.05 released. date not known NetKit-B-0.04 released. date not known NetKit-B-0.03 released. netkit-ftp-0.17/MCONFIG.in100644 144 144 267 6775404124 14442 0ustar dhollandpeople# Dirs INSTALLROOT BINDIR MANDIR # Modes BINMODE MANMODE # Compiling ALLWARNINGS CC CFLAGS LDFLAGS LIBS # Features LIBTERMCAP GLIBC READLINE BSDSIGNAL FN(snprintf) TYPE(socklen_t) netkit-ftp-0.17/MRULES100644 144 144 173 6310313706 13744 0ustar dhollandpeople# Standard compilation rules (don't use make builtins) %.o: %.c $(CC) $(CFLAGS) $< -c %.o: %.cc $(CC) $(CFLAGS) $< -c netkit-ftp-0.17/Makefile100644 144 144 736 7024720305 14457 0ustar dhollandpeople# You can do "make SUB=blah" to make only a few, or edit here, or both # You can also run make directly in the subdirs you want. SUB = ftp %.build: (cd $(patsubst %.build, %, $@) && $(MAKE)) %.install: (cd $(patsubst %.install, %, $@) && $(MAKE) install) %.clean: (cd $(patsubst %.clean, %, $@) && $(MAKE) clean) all: $(patsubst %, %.build, $(SUB)) install: $(patsubst %, %.install, $(SUB)) clean: $(patsubst %, %.clean, $(SUB)) distclean: clean rm -f MCONFIG netkit-ftp-0.17/README100644 144 144 7617 7141137760 13733 0ustar dhollandpeopleThis is netkit-ftp-0.17 for Linux. This package updates netkit-ftp-0.16. If you're reading this off a CD, go right away and check the net archives for later versions and security fixes. As of this writing the home site for NetKit is ftp://ftp.uk.linux.org/pub/linux/Networking/netkit Contents: ftp Client program for the ftp protocol. Requires: Working compiler, libc, and kernel. libreadline (GNU readline library) is optional but recommended. If you use it, you will need a recent ncurses or libtermcap as well. Security: This release contains no security fixes relative to netkit-ftp-0.16. However, versions prior to netkit-ftp-0.16 are insecure and should not be used. Note: To compile ftp with readline support you'll need a copy of the readline library installed. If you don't have it, get readline-2.0 (or higher) from ftp.gnu.org. You'll probably need to apply the enclosed patch, or ftp will have problems with ^C handling. (Feedback on readline 3.x or higher would be appreciated.) Installation: Patch your readline library if necessary. Do "./configure --help" and decide what options you want. The defaults should be suitable for most Linux systems. Then run the configure script. Do "make" to compile. Then (as root) do "make install". Save a backup copy of any mission-critical program in case the new one doesn't work, and so forth. We warned you. If you get gcc warnings from files in /usr/include, they are due to problems in your libc, not netkit. (You may only see them when compiling netkit because netkit turns on a lot of compiler warnings.) DEC CC: The DEC compiler for the Alpha is now freely available. This is a much better compiler with gcc, that is, it generates much better code. If you have the DEC compiler, you can explicitly use the DEC compiler instead of gcc by configuring like this: ./configure --with-c-compiler=ccc It is known to generate spurious warnings on some files. Also, some headers from some versions of glibc confuse it; that may prevent netkit from working. Other problems should be reported as bugs. Bugs: Please make sure the header files in /usr/include match the libc version installed in /lib and /usr/lib. If you have weird problems this is the most likely culprit. Also, before reporting a bug, be sure you're working with the latest version. If something doesn't compile for you, fix it and send diffs. If you can't, send the compiler's error output. If it compiles but doesn't work, send as complete a bug report as you can. Patches and fixes are welcome, as long as you describe adequately what they're supposed to fix. Please, one patch per distinct fix. Please do NOT send the whole archive back or reindent the source. Be sure to send all correspondence in e-mail to the netkit address. Postings to netnews or mailing lists will not be seen due to the enormous volume. Also, anything that doesn't get filed in the bug database is quite likely to end up forgotten. Please don't report known bugs (see the BUGS file(s)) unless you are including fixes. :-) Mail should be sent to: netbug@ftp.uk.linux.org Early in April 2000, a hacker broke into the machine that was hosting the netkit bug database for me and trashed it. Unfortunately, it seems backups hadn't gotten done for a while, so three months of mail (since mid-January) was lost. So, if you sent something and didn't hear back, or you sent something, heard back, but the changes failed to appear in this release (unlikely but possible) - please resend. Please see http://www.hcs.harvard.edu/~dholland/computers/netkit.html if you are curious why it was so long between the 0.10 and 0.16 releases. Future plans for netkit maintenance are still up in the air, but in the meantime new releases will still appear from time to time. I don't have a whole lot of cycles to spare to work on netkit, so things are likely to continue to be fairly slow. David A. Holland 23 July 2000 netkit-ftp-0.17/configure100755 144 144 24122 7140615674 14774 0ustar dhollandpeople#!/bin/sh # # This file was generated by confgen version 2. # Do not edit. # PREFIX='/usr' #EXECPREFIX='$PREFIX' INSTALLROOT='' BINMODE='755' MANMODE='644' while [ x$1 != x ]; do case $1 in --help) cat < __conftest.c int main() { int class=0; return class; } EOF if [ x"$CC" = x ]; then echo -n 'Looking for a C compiler... ' for TRY in egcs gcc g++ CC c++ cc; do ( $TRY __conftest.c -o __conftest || exit 1; ./__conftest || exit 1; ) >/dev/null 2>&1 || continue; CC=$TRY break; done if [ x"$CC" = x ]; then echo 'failed.' echo 'Cannot find a C compiler. Run configure with --with-c-compiler.' rm -f __conftest* exit fi echo "$CC" else echo -n 'Checking if C compiler works... ' if ( $CC __conftest.c -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else echo 'no' echo 'Compiler '"$CC"' does not exist or cannot compile C; try another.' rm -f __conftest* exit fi fi echo -n "Checking if $CC accepts gcc warnings... " if ( $CC $WARNINGS __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' CC_WARNINGS=1 else echo 'no' fi if [ x$DEBUG = x ]; then echo -n "Checking if $CC accepts -O2... " if ( $CC -O2 __conftest.c -o __conftest ) >/dev/null 2>&1; then echo 'yes' CFLAGS="$CFLAGS -O2" else echo 'no' echo -n "Checking if $CC accepts -O... " if ( $CC -O __conftest.c -o __conftest ) >/dev/null 2>&1; then echo 'yes' CFLAGS="$CFLAGS -O" else echo 'no' fi fi else echo -n "Checking if $CC accepts -g... " if ( $CC -g __conftest.c -o __conftest ) >/dev/null 2>&1; then echo 'yes' CFLAGS="$CFLAGS -g" else echo 'no' fi fi LDFLAGS= LIBS= rm -f __conftest* ################################################## echo -n 'Checking for BSD signal semantics... ' cat <__conftest.c #include #include int count=0; void handle(int foo) { count++; } int main() { int pid=getpid(); signal(SIGINT, handle); kill(pid,SIGINT); kill(pid,SIGINT); kill(pid,SIGINT); if (count!=3) return 1; return 0; } EOF if ( $CC $CFLAGS __conftest.c -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else if ( $CC $CFLAGS -D__USE_BSD_SIGNAL __conftest.c -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-D__USE_BSD_SIGNAL' CFLAGS="$CFLAGS -D__USE_BSD_SIGNAL" else echo 'no' echo 'This package needs BSD signal semantics to run.' rm -f __conftest* exit fi fi rm -f __conftest* ################################################## echo -n 'Checking for ncurses... ' cat <__conftest.c #include #include #ifndef KEY_DOWN syntax error. /* not ncurses */ #endif int main() { endwin(); return 0; } EOF if ( $CC $CFLAGS __conftest.c -lncurses -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' NCURSES=1 else if ( $CC $CFLAGS -I/usr/include/ncurses __conftest.c -lncurses -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-I/usr/include/ncurses' CFLAGS="$CFLAGS -I/usr/include/ncurses" NCURSES=1 else echo 'no' fi fi if [ x$NCURSES != x ]; then LIBTERMCAP=-lncurses else echo -n 'Checking for traditional termcap... ' cat <__conftest.c #include #include int main() { tgetent(NULL, NULL); return 0; } EOF if ( $CC $CFLAGS __conftest.c -ltermcap -o __conftest || exit 1 ) >/dev/null 2>&1; then echo '-ltermcap' LIBTERMCAP=-ltermcap else echo 'not found' echo 'This package needs termcap to run.' rm -f __conftest* exit fi fi rm -f __conftest* ################################################## echo -n 'Checking for GNU libc... ' cat <__conftest.c #include #if defined(__GLIBC__) && (__GLIBC__ >= 2) int tester; #endif int main() { tester=6; return 0; } EOF if ( $CC $CFLAGS __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' USE_GLIBC=1 else echo 'no' fi rm -f __conftest* ################################################## echo -n 'Checking for libreadline... ' if [ x$WITHOUT_READLINE != x ]; then echo disabled else cat <__conftest.c #include #include #include int main() { readline("foo"); return 0; } EOF if ( $CC $CFLAGS __conftest.c -lreadline $LIBTERMCAP -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' USE_READLINE=1 else echo 'no' fi fi rm -f __conftest* ################################################## echo -n 'Checking for socklen_t... ' cat <__conftest.c #include #include #include int main() { struct sockaddr_in sn; socklen_t len = sizeof(sn); getpeername(0, (struct sockaddr *)&sn, &len); return 0; } EOF if ( $CC $CFLAGS __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'yes' else if ( $CC $CFLAGS -Dsocklen_t=int __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'int' CFLAGS="$CFLAGS -Dsocklen_t=int" else if ( $CC $CFLAGS -Dsocklen_t=size_t __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'size_t' CFLAGS="$CFLAGS -Dsocklen_t=size_t" else echo 'no' echo 'Cannot work out what to use for socklen_t. Help...' rm -f __conftest* exit fi fi fi rm -f __conftest* ################################################## echo -n 'Checking for snprintf declaration... ' cat <__conftest.c #include int main() { void *x = (void *)snprintf; printf("%lx", (long)x); return 0; } EOF if ( $CC $CFLAGS __conftest.c -o __conftest || exit 1 ) >/dev/null 2>&1; then echo 'ok' else if ( $CC $CFLAGS -D_GNU_SOURCE __conftest.c -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-D_GNU_SOURCE' CFLAGS="$CFLAGS -D_GNU_SOURCE" else echo 'manual' CFLAGS="$CFLAGS -DDECLARE_SNPRINTF" fi fi rm -f __conftest* echo -n 'Checking for snprintf implementation... ' cat <__conftest.c #include #include #ifdef DECLARE_SNPRINTF #ifdef __cplusplus extern "C" #endif /*__cplusplus*/ int snprintf(char *, int, const char *, ...); #endif /*DECLARE_SNPRINTF*/ int main() { char buf[32]; snprintf(buf, 8, "%s", "1234567890"); if (strlen(buf)!=7) return 1; return 0; } EOF if ( $CC $CFLAGS __conftest.c $LIBBSD -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo 'ok' else if ( $CC $CFLAGS __conftest.c -lsnprintf $LIBBSD -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-lsnprintf' LIBS="$LIBS -lsnprintf" else if ( $CC $CFLAGS __conftest.c -ldb $LIBBSD -o __conftest || exit 1 ./__conftest || exit 1 ) >/dev/null 2>&1; then echo '-ldb' LIBS="$LIBS -ldb" else echo 'missing' echo 'This package requires snprintf.' rm -f __conftest* exit fi fi fi rm -f __conftest* ################################################## ## libbsd should go last in case it's broken if [ "x$LIBBSD" != x ]; then LIBS="$LIBS $LIBBSD" fi echo 'Generating MCONFIG...' ( echo -n '# Generated by configure (confgen version 2) on ' date echo '#' echo echo "BINDIR=$BINDIR" echo "MANDIR=$MANDIR" echo "BINMODE=$BINMODE" echo "MANMODE=$MANMODE" echo "PREFIX=$PREFIX" echo "EXECPREFIX=$EXECPREFIX" echo "INSTALLROOT=$INSTALLROOT" echo "CC=$CC" if [ x$CC_WARNINGS != x ]; then CFLAGS="$CFLAGS $WARNINGS" fi echo "CFLAGS=$CFLAGS" | sed 's/= */=/' echo "LDFLAGS=$LDFLAGS" | sed 's/= */=/' echo "LIBS=$LIBS" | sed 's/= */=/' echo "LIBTERMCAP=$LIBTERMCAP" echo "USE_GLIBC=$USE_GLIBC" echo "USE_READLINE=$USE_READLINE" ) > MCONFIG netkit-ftp-0.17/readline-2.0.patch100644 144 144 742 6204410670 16115 0ustar dhollandpeopleThis patch corrects a config mistake in GNU readline-2.0 that causes it to mishandle signals, resulting in problems with ftp's ^C handling. *** signals.c.dist Wed Aug 3 11:25:57 1994 --- signals.c Wed Aug 14 13:23:30 1996 *************** *** 21,26 **** --- 21,30 ---- 675 Mass Ave, Cambridge, MA 02139, USA. */ #define READLINE_LIBRARY + #if defined (HAVE_CONFIG_H) + # include "config.h" + #endif + #include #include #include netkit-ftp-0.17/version.h100644 144 144 144 7141140313 14641 0ustar dhollandpeople/* * String to embed in binaries to identify package */ char pkg[]="$NetKit: netkit-ftp-0.17 $";