diff options
Diffstat (limited to 'small.c')
| -rw-r--r-- | small.c | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/small.c b/small.c new file mode 100644 index 0000000..484d78f --- /dev/null +++ b/small.c @@ -0,0 +1,721 @@ +/* $OpenBSD: small.c,v 1.13 2023/03/08 04:43:11 guenther Exp $ */ +/* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */ + +/* + * Copyright (C) 1997 and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * FTP User Program -- Command Routines. + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <arpa/ftp.h> + +#include <ctype.h> +#include <err.h> +#include <fnmatch.h> +#include <glob.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "ftp_var.h" +#include "pathnames.h" +#include "small.h" + +jmp_buf jabort; +char *mname; +char *home = "/"; + +struct types { + char *t_name; + char *t_mode; + int t_type; +} types[] = { + { "ascii", "A", TYPE_A }, + { "binary", "I", TYPE_I }, + { "image", "I", TYPE_I }, + { NULL } +}; + +/* + * Set transfer type. + */ +void +settype(int argc, char *argv[]) +{ + struct types *p; + int comret; + + if (argc > 2) { + char *sep; + + fprintf(ttyout, "usage: %s [", argv[0]); + sep = ""; + for (p = types; p->t_name; p++) { + fprintf(ttyout, "%s%s", sep, p->t_name); + sep = " | "; + } + fputs("]\n", ttyout); + code = -1; + return; + } + if (argc < 2) { + fprintf(ttyout, "Using %s mode to transfer files.\n", typename); + code = 0; + return; + } + for (p = types; p->t_name; p++) + if (strcmp(argv[1], p->t_name) == 0) + break; + if (p->t_name == 0) { + fprintf(ttyout, "%s: unknown mode.\n", argv[1]); + code = -1; + return; + } + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) { + (void)strlcpy(typename, p->t_name, sizeof typename); + curtype = type = p->t_type; + } +} + +/* + * 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) +{ + struct types *p; + int comret, oldverbose = verbose; + + if (newtype == 0) + newtype = TYPE_I; + if (newtype == curtype) + return; + if ( +#ifndef SMALL + !debug && +#endif /* !SMALL */ + show == 0) + verbose = 0; + for (p = types; p->t_name; p++) + if (newtype == p->t_type) + break; + if (p->t_name == 0) { + warnx("internal error: unknown type %d.", 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; +} + +char *stype[] = { + "type", + "", + 0 +}; + +/* + * Set binary transfer type. + */ +void +setbinary(int argc, char *argv[]) +{ + + stype[1] = "binary"; + settype(2, stype); +} + +void +get(int argc, char *argv[]) +{ + + (void)getit(argc, argv, 0, restart_point ? "a+w" : "w" ); +} + +/* + * Receive one file. + */ +int +getit(int argc, char *argv[], int restartit, const char *mode) +{ + int loc = 0; + int rval = 0; + char *oldargv1, *oldargv2, *globargv2; + + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } +#ifndef SMALL + if (argc < 2 && !another(&argc, &argv, "remote-file")) + goto usage; + if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { +usage: + fprintf(ttyout, "usage: %s remote-file [local-file]\n", + argv[0]); + code = -1; + return (0); + } +#endif /* !SMALL */ + oldargv1 = argv[1]; + oldargv2 = argv[2]; + if (!globulize(&argv[2])) { + code = -1; + return (0); + } + globargv2 = argv[2]; + if (loc && mcase) { + char *tp = argv[1], *tp2, tmpbuf[PATH_MAX]; + + while (*tp && !islower((unsigned char)*tp)) { + tp++; + } + if (!*tp) { + tp = argv[2]; + tp2 = tmpbuf; + while ((*tp2 = *tp) != '\0') { + if (isupper((unsigned char)*tp2)) { + *tp2 = tolower((unsigned char)*tp2); + } + tp++; + tp2++; + } + argv[2] = tmpbuf; + } + } + if (loc && ntflag) + argv[2] = dotrans(argv[2]); + if (loc && mapflag) + argv[2] = domap(argv[2]); +#ifndef SMALL + if (restartit) { + struct stat stbuf; + int ret; + + ret = stat(argv[2], &stbuf); + if (restartit == 1) { + restart_point = (ret < 0) ? 0 : stbuf.st_size; + } else { + if (ret == 0) { + time_t mtime; + + mtime = remotemodtime(argv[1], 0); + if (mtime == -1) + goto freegetit; + if (stbuf.st_mtime >= mtime) { + rval = 1; + fprintf(ttyout, + "Local file \"%s\" is newer "\ + "than remote file \"%s\".\n", + argv[2], argv[1]); + goto freegetit; + } + } + } + } +#endif /* !SMALL */ + + recvrequest("RETR", argv[2], argv[1], mode, + argv[1] != oldargv1 || argv[2] != oldargv2 || !interactive, loc); + restart_point = 0; +#ifndef SMALL +freegetit: +#endif + if (oldargv2 != globargv2) /* free up after globulize() */ + free(globargv2); + return (rval); +} + +/* XXX - Signal race. */ +void +mabort(int signo) +{ + int save_errno = errno; + + alarmtimer(0); + (void) write(fileno(ttyout), "\n\r", 2); +#ifndef SMALL + if (mflag && fromatty) { + /* XXX signal race, crazy unbelievable stdio misuse */ + if (confirm(mname, NULL)) { + errno = save_errno; + longjmp(jabort, 1); + } + } +#endif /* !SMALL */ + mflag = 0; + errno = save_errno; + longjmp(jabort, 1); +} + +/* + * Get multiple files. + */ +void +mget(int argc, char *argv[]) +{ + extern int optind, optreset; + sig_t oldintr; + int xargc = 2; + char *cp, localcwd[PATH_MAX], *xargv[] = { argv[0], NULL, NULL }; + static int restartit = 0; +#ifndef SMALL + extern char *optarg; + const char *errstr; + int ch, i = 1; + char type = 0, *dummyargv[] = { argv[0], ".", NULL }; + FILE *ftemp = NULL; + static int depth = 0, max_depth = 0; + + optind = optreset = 1; + + if (depth) + depth++; + + while ((ch = getopt(argc, argv, "cd:nr")) != -1) { + switch(ch) { + case 'c': + restartit = 1; + break; + case 'd': + max_depth = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) { + fprintf(ttyout, "bad depth value, %s: %s\n", + errstr, optarg); + code = -1; + return; + } + break; + case 'n': + restartit = -1; + break; + case 'r': + depth = 1; + break; + default: + goto usage; + } + } + + if (argc - optind < 1 && !another(&argc, &argv, "remote-files")) { +usage: + fprintf(ttyout, "usage: %s [-cnr] [-d depth] remote-files\n", + argv[0]); + code = -1; + return; + } + + argv[optind - 1] = argv[0]; + argc -= optind - 1; + argv += optind - 1; +#endif /* !SMALL */ + + mname = argv[0]; + mflag = 1; + if (getcwd(localcwd, sizeof(localcwd)) == NULL) + err(1, "can't get cwd"); + + oldintr = signal(SIGINT, mabort); + (void)setjmp(jabort); + while ((cp = +#ifdef SMALL + remglob(argv, proxy, NULL)) != NULL + ) { +#else /* SMALL */ + depth ? remglob2(dummyargv, proxy, NULL, &ftemp, &type) : + remglob(argv, proxy, NULL)) != NULL + || (mflag && depth && ++i < argc) + ) { + if (cp == NULL) + continue; +#endif /* SMALL */ + if (*cp == '\0') { + mflag = 0; + continue; + } + if (!mflag) + continue; +#ifndef SMALL + if (depth && fnmatch(argv[i], cp, FNM_PATHNAME) != 0) + continue; +#endif /* !SMALL */ + if (!fileindir(cp, localcwd)) { + fprintf(ttyout, "Skipping non-relative filename `%s'\n", + cp); + continue; + } +#ifndef SMALL + if (type == 'd' && depth == max_depth) + continue; + if (!confirm(argv[0], cp)) + continue; + if (type == 'd') { + mkdir(cp, 0755); + if (chdir(cp) != 0) { + warn("local: %s", cp); + continue; + } + + xargv[1] = cp; + cd(xargc, xargv); + if (dirchange != 1) + goto out; + + xargv[1] = "*"; + mget(xargc, xargv); + + xargv[1] = ".."; + cd(xargc, xargv); + if (dirchange != 1) { + mflag = 0; + goto out; + } + +out: + if (chdir("..") != 0) { + warn("local: %s", cp); + mflag = 0; + } + continue; + } + if (type == 's') + /* Currently ignored. */ + continue; +#endif /* !SMALL */ + xargv[1] = cp; + (void)getit(xargc, xargv, restartit, + (restartit == 1 || restart_point) ? "a+w" : "w"); +#ifndef SMALL + if (!mflag && fromatty) { + if (confirm(argv[0], NULL)) + mflag = 1; + } +#endif /* !SMALL */ + } + (void)signal(SIGINT, oldintr); +#ifndef SMALL + if (depth) + depth--; + if (depth == 0 || mflag == 0) + depth = max_depth = mflag = restartit = 0; +#else /* !SMALL */ + mflag = 0; +#endif /* !SMALL */ +} + +/* + * Set current working directory on remote machine. + */ +void +cd(int argc, char *argv[]) +{ + int r; + +#ifndef SMALL + if ((argc < 2 && !another(&argc, &argv, "remote-directory")) || + argc > 2) { + fprintf(ttyout, "usage: %s remote-directory\n", argv[0]); + code = -1; + return; + } +#endif /* !SMALL */ + r = command("CWD %s", argv[1]); + if (r == ERROR && code == 500) { + if (verbose) + fputs("CWD command not recognized, trying XCWD.\n", ttyout); + r = command("XCWD %s", argv[1]); + } + if (r == ERROR && code == 550) { + dirchange = 0; + return; + } + if (r == COMPLETE) + dirchange = 1; +} + +/* + * Terminate session, but don't exit. + */ +void +disconnect(int argc, char *argv[]) +{ + + if (!connected) + return; + (void)command("QUIT"); + if (cout) { + (void)fclose(cout); + } + cout = NULL; + connected = 0; + data = -1; +#ifndef SMALL + if (!proxy) { + macnum = 0; + } +#endif /* !SMALL */ +} + +char * +dotrans(char *name) +{ + static char new[PATH_MAX]; + char *cp1, *cp2 = new; + int i, ostop, found; + + for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) + continue; + 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); +} + +char * +domap(char *name) +{ + static char new[PATH_MAX]; + 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)) { + toks[toknum = *cp2 - '1']++; + 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((unsigned char)*(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((unsigned char)*(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) { + fputs( +"nmap: unbalanced brackets.\n", ttyout); + return (name); + } + match = 1; + cp2--; + } + if (match) { + while (*++cp2 && *cp2 != ']') { + if (*cp2 == '\\' && *(cp2 + 1)) { + cp2++; + } + } + if (!*cp2) { + fputs( +"nmap: unbalanced brackets.\n", ttyout); + return (name); + } + break; + } + switch (*++cp2) { + case ',': + goto LOOP; + case ']': + break; + default: + cp2--; + goto LOOP; + } + break; + case '$': + if (isdigit((unsigned char)*(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; + } + /* FALLTHROUGH */ + default: + *cp1++ = *cp2; + break; + } + cp2++; + } + *cp1 = '\0'; + if (!*new) { + return (name); + } + return (new); +} + |