Edit

IABSD.fr/src/usr.bin/ftp/small.c

Branch :

  • Show log

    Commit

  • Author : deraadt
    Date : 2019-11-18 04:37:35
    Hash : 544013c6
    Message : various knf and whitespace; ok jca

  • usr.bin/ftp/small.c
  • /*	$OpenBSD: small.c,v 1.12 2019/11/18 04:37:35 deraadt 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.
     */
    /*ARGSUSED*/
    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. */
    /* ARGSUSED */
    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.
     */
    /* ARGSUSED */
    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);
    }