diff --git a/appl/ftp/Makefile.in b/appl/ftp/Makefile.in new file mode 100644 index 000000000..832d54de6 --- /dev/null +++ b/appl/ftp/Makefile.in @@ -0,0 +1,38 @@ +# + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +SHELL = /bin/sh + +CC = @CC@ +RANLIB = @RANLIB@ +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ + +INSTALL = @INSTALL@ + +prefix = @prefix@ +exec_prefix = $(prefix) +libdir = $(exec_prefix)/lib + +SUBDIRS=common ftp ftpd + +all: + for i in $(SUBDIRS); \ + do (cd $$i && $(MAKE) $(MFLAGS) all); done + +install: + for i in $(SUBDIRS); \ + do (cd $$i && $(MAKE) $(MFLAGS) install); done + +clean cleandir: + for i in $(SUBDIRS); \ + do (cd $$i && $(MAKE) $(MFLAGS) clean); done + +distclean: + for i in $(SUBDIRS); \ + do (cd $$i && $(MAKE) $(MFLAGS) distclean); done + rm -f Makefile config.status config.cache config.log config.h *~ + rm -rf CVS diff --git a/appl/ftp/acconfig.h b/appl/ftp/acconfig.h new file mode 100644 index 000000000..55b8dec30 --- /dev/null +++ b/appl/ftp/acconfig.h @@ -0,0 +1,13 @@ + +@TOP@ + +@BOTTOM@ + +#ifdef __STDC__ +#define RCSID(msg) static const char *rcsid[] = { (char *)rcsid, "@(#)" msg } +#else +#define RCSID(msg) static char *rcsid[] = { (char *)rcsid, msg } +#endif + +#define WTMP_PATH "/var/adm/wtmp" + diff --git a/appl/ftp/common/Makefile.in b/appl/ftp/common/Makefile.in new file mode 100644 index 000000000..5d4e268fd --- /dev/null +++ b/appl/ftp/common/Makefile.in @@ -0,0 +1,41 @@ +# + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +SHELL = /bin/sh + +CC = @CC@ +RANLIB = @RANLIB@ +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ + +INSTALL = @INSTALL@ + +prefix = @prefix@ +exec_prefix = $(prefix) +libdir = $(exec_prefix)/lib + +ATHENA = /usr/athena + +libcommon_OBJS = base64.o glob.o @LIBOBJS@ + +all: libcommon.a + +.c.o: + $(CC) -c $(CFLAGS) -I. -I.. -I$(ATHENA)/include $(DEFS) $< + +libcommon.a: $(libcommon_OBJS) + ar cr libcommon.a $(libcommon_OBJS) + ranlib libcommon.a + + +install: + +clean cleandir: + rm -f *~ *.o ftp core \#* + +distclean: + rm -f Makefile + rm -rf CVS diff --git a/appl/ftp/common/base64.c b/appl/ftp/common/base64.c new file mode 100644 index 000000000..85a301e0b --- /dev/null +++ b/appl/ftp/common/base64.c @@ -0,0 +1,107 @@ +#include +#include +#include "base64.h" + +static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static int pos(char c) +{ + char *p; + for(p = base64; *p; p++) + if(*p == c) + return p - base64; + return -1; +} + +int base64_encode(const void *data, int size, char **str) +{ + char *s, *p; + int i; + int c; + unsigned char *q; + + p = s = (char*)malloc(size*4/3+4); + q = (unsigned char*)data; + i=0; + for(i = 0; i < size;){ + c=q[i++]; + c*=256; + if(i < size) + c+=q[i]; + i++; + c*=256; + if(i < size) + c+=q[i]; + i++; + p[0]=base64[(c&0x00fc0000) >> 18]; + p[1]=base64[(c&0x0003f000) >> 12]; + p[2]=base64[(c&0x00000fc0) >> 6]; + p[3]=base64[(c&0x0000003f) >> 0]; + if(i > size) + p[3]='='; + if(i > size+1) + p[2]='='; + p+=4; + } + *p=0; + *str = s; + return strlen(s); +} + +int base64_decode(const char *str, void *data) +{ + const char *p; + unsigned char *q; + int c; + int x; + int done = 0; + q=(unsigned char*)data; + for(p=str; *p && !done; p+=4){ + x = pos(p[0]); + if(x >= 0) + c = x; + else{ + done = 3; + break; + } + c*=64; + + x = pos(p[1]); + if(x >= 0) + c += x; + else + return -1; + c*=64; + + if(p[2] == '=') + done++; + else{ + x = pos(p[2]); + if(x >= 0) + c += x; + else + return -1; + } + c*=64; + + if(p[3] == '=') + done++; + else{ + if(done) + return -1; + x = pos(p[3]); + if(x >= 0) + c += x; + else + return -1; + } + if(done < 3) + *q++=(c&0x00ff0000)>>16; + + if(done < 2) + *q++=(c&0x0000ff00)>>8; + if(done < 1) + *q++=(c&0x000000ff)>>0; + } + return q - (unsigned char*)data; +} diff --git a/appl/ftp/common/base64.h b/appl/ftp/common/base64.h new file mode 100644 index 000000000..e4e7934e7 --- /dev/null +++ b/appl/ftp/common/base64.h @@ -0,0 +1,7 @@ +#ifndef _BASE64_H_ +#define _BASE64_H_ + +int base64_encode(const void *data, int size, char **str); +int base64_decode(const char *str, void *data); + +#endif diff --git a/appl/ftp/common/common.h b/appl/ftp/common/common.h new file mode 100644 index 000000000..191471508 --- /dev/null +++ b/appl/ftp/common/common.h @@ -0,0 +1,16 @@ +#ifndef __MISSING_H__ +#define __MISSING_H__ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "vsyslog.h" + +#include "err.h" + +#include "base64.h" + +#endif /* __MISSING_H__ */ diff --git a/appl/ftp/common/err.c b/appl/ftp/common/err.c new file mode 100644 index 000000000..0f567f5bc --- /dev/null +++ b/appl/ftp/common/err.c @@ -0,0 +1,16 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +err(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(eval, fmt, ap); + va_end(ap); +} diff --git a/appl/ftp/common/err.h b/appl/ftp/common/err.h new file mode 100644 index 000000000..40c08de8e --- /dev/null +++ b/appl/ftp/common/err.h @@ -0,0 +1,21 @@ +#ifndef __ERR_H__ +#define __ERR_H__ + +#include +#include +#include +#include +#include + +extern char *__progname; + +void verr(int eval, const char *fmt, va_list ap); +void err(int eval, const char *fmt, ...); +void verrx(int eval, const char *fmt, va_list ap); +void errx(int eval, const char *fmt, ...); +void vwarn(const char *fmt, va_list ap); +void warn(const char *fmt, ...); +void vwarnx(const char *fmt, va_list ap); +void warnx(const char *fmt, ...); + +#endif /* __ERR_H__ */ diff --git a/appl/ftp/common/errx.c b/appl/ftp/common/errx.c new file mode 100644 index 000000000..6b3b5a8a1 --- /dev/null +++ b/appl/ftp/common/errx.c @@ -0,0 +1,16 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(eval, fmt, ap); + va_end(ap); +} diff --git a/appl/ftp/common/glob.c b/appl/ftp/common/glob.c new file mode 100644 index 000000000..f8b0e63c1 --- /dev/null +++ b/appl/ftp/common/glob.c @@ -0,0 +1,853 @@ +/* $NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; +#else +static char rcsid[] = "$NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_NOMAGIC: + * Same as GLOB_NOCHECK, but it will only append pattern if it did + * not contain any magic characters. [Used in csh style globbing] + * GLOB_ALTDIRFUNC: + * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glob.h" + +#define DOLLAR '$' +#define DOT '.' +#define EOS '\0' +#define LBRACKET '[' +#define NOT '!' +#define QUESTION '?' +#define QUOTE '\\' +#define RANGE '-' +#define RBRACKET ']' +#define SEP '/' +#define STAR '*' +#define TILDE '~' +#define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG + +#define M_QUOTE 0x8000 +#define M_PROTECT 0x4000 +#define M_MASK 0xffff +#define M_ASCII 0x00ff + +typedef u_short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define M_ALL META('*') +#define M_END META(']') +#define M_NOT META('!') +#define M_ONE META('?') +#define M_RNG META('-') +#define M_SET META('[') +#define ismeta(c) (((c)&M_QUOTE) != 0) + + +static int compare __P((const void *, const void *)); +static void g_Ctoc __P((const Char *, char *)); +static int g_lstat __P((Char *, struct stat *, glob_t *)); +static DIR *g_opendir __P((Char *, glob_t *)); +static Char *g_strchr __P((Char *, int)); +#ifdef notdef +static Char *g_strcat __P((Char *, const Char *)); +#endif +static int g_stat __P((Char *, struct stat *, glob_t *)); +static int glob0 __P((const Char *, glob_t *)); +static int glob1 __P((Char *, glob_t *)); +static int glob2 __P((Char *, Char *, Char *, glob_t *)); +static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *)); +static int globextend __P((const Char *, glob_t *)); +static const Char * globtilde __P((const Char *, Char *, glob_t *)); +static int globexp1 __P((const Char *, glob_t *)); +static int globexp2 __P((const Char *, const Char *, glob_t *, int *)); +static int match __P((Char *, Char *, Char *)); +#ifdef DEBUG +static void qprintf __P((const char *, Char *)); +#endif + +int +glob(pattern, flags, errfunc, pglob) + const char *pattern; + int flags, (*errfunc) __P((const char *, int)); + glob_t *pglob; +{ + const u_char *patnext; + int c; + Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; + + patnext = (u_char *) pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN; + if (flags & GLOB_QUOTE) { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } + else + *bufnext++ = c; + } + else + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int globexp1(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int globexp2(ptr, pattern, pglob, rv) + const Char *ptr, *pattern; + glob_t *pglob; + int *rv; +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[MAXPATHLEN + 1]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(pattern, patbuf, pglob) + const Char *pattern; + Char *patbuf; + glob_t *pglob; +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH; + *h++ = *p++) + continue; + + *h = EOS; + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ + if ((h = getenv("HOME")) == NULL) { + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + } + else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; *h; *b++ = *h++) + continue; + + /* Append the rest of the pattern */ + while ((*b++ = *p++) != EOS) + continue; + + return patbuf; +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[MAXPATHLEN+1]; + + qpatnext = globtilde(pattern, patbuf, pglob); + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob)) != 0) + return(err); + + /* + * If there was no match we are going to append the pattern + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the pattern did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if (pglob->gl_pathc == oldpathc && + ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR)))) + return(globextend(pattern, pglob)); + else if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return(0); +} + +static int +compare(p, q) + const void *p, *q; +{ + return(strcmp(*(char **)p, *(char **)q)); +} + +static int +glob1(pattern, pglob) + Char *pattern; + glob_t *pglob; +{ + Char pathbuf[MAXPATHLEN+1]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return(0); + return(glob2(pathbuf, pathbuf, pattern, pglob)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(pathbuf, pathend, pattern, pglob) + Char *pathbuf, *pathend, *pattern; + glob_t *pglob; +{ + struct stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return(0); + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) + || (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb, pglob) == 0) && + S_ISDIR(sb.st_mode)))) { + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return(globextend(pathbuf, pglob)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && *p != SEP) { + if (ismeta(*p)) + anymeta = 1; + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (*pattern == SEP) + *pathend++ = *pattern++; + } else /* Need expansion, recurse. */ + return(glob3(pathbuf, pathend, pattern, p, pglob)); + } + /* NOTREACHED */ +} + +static int +glob3(pathbuf, pathend, pattern, restpattern, pglob) + Char *pathbuf, *pathend, *pattern, *restpattern; + glob_t *pglob; +{ + register struct dirent *dp; + DIR *dirp; + int err; + char buf[MAXPATHLEN]; + + /* + * The readdirfunc declaration can't be prototyped, because it is + * assigned, below, to two functions which are prototyped in glob.h + * and dirent.h as taking pointers to differently typed opaque + * structures. + */ + struct dirent *(*readdirfunc)(); + + *pathend = EOS; + errno = 0; + + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + /* TODO: don't call for ENOENT or ENOTDIR? */ + if (pglob->gl_errfunc) { + g_Ctoc(pathbuf, buf); + if (pglob->gl_errfunc(buf, errno) || + pglob->gl_flags & GLOB_ERR) + return (GLOB_ABEND); + } + return(0); + } + + err = 0; + + /* Search directory for matching names. */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = pglob->gl_readdir; + else + readdirfunc = readdir; + while ((dp = (*readdirfunc)(dirp))) { + register u_char *sc; + register Char *dc; + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == DOT && *pattern != DOT) + continue; + for (sc = (u_char *) dp->d_name, dc = pathend; + (*dc++ = *sc++) != EOS;) + continue; + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + err = glob2(pathbuf, --dc, restpattern, pglob); + if (err) + break; + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + return(err); +} + + +/* + * Extend the gl_pathv member of a glob_t structure to accomodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(path, pglob) + const Char *path; + glob_t *pglob; +{ + register char **pathv; + register int i; + u_int newsize; + char *copy; + const Char *p; + + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + pathv = pglob->gl_pathv ? + realloc((char *)pglob->gl_pathv, newsize) : + malloc(newsize); + if (pathv == NULL) + return(GLOB_NOSPACE); + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + for (p = path; *p++;) + continue; + if ((copy = malloc(p - path)) != NULL) { + g_Ctoc(path, copy); + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return(copy == NULL ? GLOB_NOSPACE : 0); +} + + +/* + * pattern matching function for filenames. Each occurrence of the * + * pattern causes a recursion level. + */ +static int +match(name, pat, patend) + register Char *name, *pat, *patend; +{ + int ok, negate_range; + Char c, k; + + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return(1); + do + if (match(name, pat, patend)) + return(1); + while (*name++ != EOS); + return(0); + case M_ONE: + if (*name++ == EOS) + return(0); + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + return(0); + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (c <= k && k <= pat[1]) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + return(0); + break; + default: + if (*name++ != c) + return(0); + break; + } + } + return(*name == EOS); +} + +/* Free allocated data belonging to a glob_t structure. */ +void +globfree(pglob) + glob_t *pglob; +{ + register int i; + register char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + } +} + +static DIR * +g_opendir(str, pglob) + register Char *str; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (!*str) + strcpy(buf, "."); + else + g_Ctoc(str, buf); + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_opendir)(buf)); + + return(opendir(buf)); +} + +static int +g_lstat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return(lstat(buf, sb)); +} + +static int +g_stat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_stat)(buf, sb)); + return(stat(buf, sb)); +} + +static Char * +g_strchr(str, ch) + Char *str; + int ch; +{ + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +#ifdef notdef +static Char * +g_strcat(dst, src) + Char *dst; + const Char* src; +{ + Char *sdst = dst; + + while (*dst++) + continue; + --dst; + while((*dst++ = *src++) != EOS) + continue; + + return (sdst); +} +#endif + +static void +g_Ctoc(str, buf) + register const Char *str; + char *buf; +{ + register char *dc; + + for (dc = buf; (*dc++ = *str++) != EOS;) + continue; +} + +#ifdef DEBUG +static void +qprintf(str, s) + const char *str; + register Char *s; +{ + register Char *p; + + (void)printf("%s:\n", str); + for (p = s; *p; p++) + (void)printf("%c", CHAR(*p)); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", ismeta(*p) ? '_' : ' '); + (void)printf("\n"); +} +#endif diff --git a/appl/ftp/common/glob.h b/appl/ftp/common/glob.h new file mode 100644 index 000000000..5d85f17b0 --- /dev/null +++ b/appl/ftp/common/glob.h @@ -0,0 +1,90 @@ +/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +#ifndef __P +#define __P(protos) protos +#endif + +struct stat; +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc) __P((const char *, int)); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir) __P((void *)); + struct dirent *(*gl_readdir) __P((void *)); + void *(*gl_opendir) __P((const char *)); + int (*gl_lstat) __P((const char *, struct stat *)); + int (*gl_stat) __P((const char *, struct stat *)); +} glob_t; + +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ + +#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ +#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ +#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ +#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ + +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABEND (-2) /* Unignored error. */ + +int glob __P((const char *, int, int (*)(const char *, int), glob_t *)); +void globfree __P((glob_t *)); + +#endif /* !_GLOB_H_ */ diff --git a/appl/ftp/common/hstrerror.c b/appl/ftp/common/hstrerror.c new file mode 100644 index 000000000..42e5975c1 --- /dev/null +++ b/appl/ftp/common/hstrerror.c @@ -0,0 +1,26 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_HSTRERROR + +#include +#include + +static char *msg[] = { + "No error", + "Authoritative Answer Host not found", + "Non-Authoritive Host not found, or SERVERFAIL", + "Non recoverable errors, FORMERR, REFUSED, NOTIMP", + "Valid name, no data record of requested type" +}; + +char *hstrerror(int herr) +{ + if(herr >= 0 && herr <= 4) + return msg[herr]; + return "Error number out of range (hstrerror)"; +} + +#endif + diff --git a/appl/ftp/common/inet_aton.c b/appl/ftp/common/inet_aton.c new file mode 100644 index 000000000..537838720 --- /dev/null +++ b/appl/ftp/common/inet_aton.c @@ -0,0 +1,23 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +RCSID("$Id$"); + +int inet_aton(char *cp, struct in_addr *adr) +{ + int a, b, c, d; + + if(sscanf(cp, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) + return 0; + if(a < 0 || a > 255 || + b < 0 || b > 255 || + c < 0 || c > 255 || + d < 0 || d > 255) + return 0; + adr->s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d); + return 1; +} diff --git a/appl/ftp/common/krb_get_err_text.c b/appl/ftp/common/krb_get_err_text.c new file mode 100644 index 000000000..64d94b7c5 --- /dev/null +++ b/appl/ftp/common/krb_get_err_text.c @@ -0,0 +1,13 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +RCSID("$Id$"); + +const char * +krb_get_err_text(int n) +{ + return krb_err_txt[n]; +} diff --git a/appl/ftp/common/memmove.c b/appl/ftp/common/memmove.c new file mode 100644 index 000000000..8604af68a --- /dev/null +++ b/appl/ftp/common/memmove.c @@ -0,0 +1,33 @@ +/* + * memmove for systems that doesn't have it + * + * $Id$ + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +RCSID("$Id$"); + +void* memmove(void *s1, const void *s2, size_t n) +{ + char *s=(char*)s2, *d=(char*)s1; + + if(d > s){ + s+=n-1; + d+=n-1; + while(n){ + *d--=*s--; + n--; + } + }else if(d < s) + while(n){ + *d++=*s++; + n--; + } + return s1; +} diff --git a/appl/ftp/common/snprintf.c b/appl/ftp/common/snprintf.c new file mode 100644 index 000000000..9d35de6b4 --- /dev/null +++ b/appl/ftp/common/snprintf.c @@ -0,0 +1,18 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +RCSID("$Id$"); + +int snprintf(char *s, int n, char *fmt, ...) +{ + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsprintf(s, fmt, ap); + va_end(ap); + return ret; +} diff --git a/appl/ftp/common/verr.c b/appl/ftp/common/verr.c new file mode 100644 index 000000000..04fa0a37a --- /dev/null +++ b/appl/ftp/common/verr.c @@ -0,0 +1,22 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +verr(int eval, const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": "); + } + fprintf(stderr, "%s\n", strerror(sverrno)); + exit(eval); +} diff --git a/appl/ftp/common/verrx.c b/appl/ftp/common/verrx.c new file mode 100644 index 000000000..001d25336 --- /dev/null +++ b/appl/ftp/common/verrx.c @@ -0,0 +1,17 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +verrx(int eval, const char *fmt, va_list ap) +{ + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + exit(eval); +} diff --git a/appl/ftp/common/vsyslog.c b/appl/ftp/common/vsyslog.c new file mode 100644 index 000000000..395d07b08 --- /dev/null +++ b/appl/ftp/common/vsyslog.c @@ -0,0 +1,17 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_VSYSLOG + +#include +#include + +void vsyslog(int pri, const char *fmt, va_list ap) +{ + char buf[10240]; + vsprintf(buf, fmt, ap); + syslog(pri, buf); +} + +#endif diff --git a/appl/ftp/common/vsyslog.h b/appl/ftp/common/vsyslog.h new file mode 100644 index 000000000..83fb89ee9 --- /dev/null +++ b/appl/ftp/common/vsyslog.h @@ -0,0 +1,8 @@ +#ifndef __VSYSLOG_H__ +#define __VSYSLOG_H__ + +#ifndef HAVE_VSYSLOG +void vsyslog(int pri, const char *fmt, ...); +#endif + +#endif /* __VSYSLOG_H__ */ diff --git a/appl/ftp/common/vwarn.c b/appl/ftp/common/vwarn.c new file mode 100644 index 000000000..f2effc3ee --- /dev/null +++ b/appl/ftp/common/vwarn.c @@ -0,0 +1,21 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +vwarn(const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": "); + } + fprintf(stderr, "%s\n", strerror(sverrno)); +} diff --git a/appl/ftp/common/vwarnx.c b/appl/ftp/common/vwarnx.c new file mode 100644 index 000000000..9e58676de --- /dev/null +++ b/appl/ftp/common/vwarnx.c @@ -0,0 +1,16 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +vwarnx(const char *fmt, va_list ap) +{ + fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); +} diff --git a/appl/ftp/common/warn.c b/appl/ftp/common/warn.c new file mode 100644 index 000000000..dec5abf48 --- /dev/null +++ b/appl/ftp/common/warn.c @@ -0,0 +1,16 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} diff --git a/appl/ftp/common/warnx.c b/appl/ftp/common/warnx.c new file mode 100644 index 000000000..ef8bfec2d --- /dev/null +++ b/appl/ftp/common/warnx.c @@ -0,0 +1,16 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "err.h" + +RCSID("$Id$"); + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} diff --git a/appl/ftp/configure.in b/appl/ftp/configure.in new file mode 100644 index 000000000..0dff23ea5 --- /dev/null +++ b/appl/ftp/configure.in @@ -0,0 +1,30 @@ +# +# configure script for kftp +# +# $Id$ +# + + +AC_INIT(ftp/main.c) +AC_CONFIG_HEADER(config.h) + +# This may be overridden using --prefix=/usr to configure +AC_PREFIX_DEFAULT(/usr/athena) + +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_CPP + +AC_SUBST(CFLAGS)dnl +AC_SUBST(LDFLAGS)dnl + +AC_CHECK_HEADERS(sys/select.h paths.h) + +AC_CHECK_LIB(socket, socket) +AC_CHECK_LIB(nsl, gethostbyname) +AC_CHECK_LIB(krb, krb_mk_req) + + +AC_REPLACE_FUNCS(errx hstrerror inet_aton krb_get_err_text memmove snprintf vsyslog verrx vwarn vwarnx warn warnx) + +AC_OUTPUT(Makefile common/Makefile ftp/Makefile ftpd/Makefile) \ No newline at end of file diff --git a/appl/ftp/ftp/Makefile b/appl/ftp/ftp/Makefile deleted file mode 100644 index 16f6dfb9d..000000000 --- a/appl/ftp/ftp/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -CC=cc -std1 -#CC=gcc -CFLAGS=-g -DHAVE_CONFIG_H -I.. -I../libmissing -I$(ATHENA)/include -I. - -ATHENA = /usr/athena - -ftp_OBJS = cmds.o cmdtab.o ftp.o main.o ruserpass.o domacro.o globals.o - -ftp: $(ftp_OBJS) - $(CC) -o ftp $(ftp_OBJS) ../libmissing/libmissing.a -L$(ATHENA)/lib -lkrb -ldes - -clean: - rm -f *~ *.o core ftpd ftpcmd.c \#* diff --git a/appl/ftp/ftp/Makefile.in b/appl/ftp/ftp/Makefile.in new file mode 100644 index 000000000..71b2d105e --- /dev/null +++ b/appl/ftp/ftp/Makefile.in @@ -0,0 +1,41 @@ +# + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +SHELL = /bin/sh + +CC = @CC@ +RANLIB = @RANLIB@ +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ +LIBS = @LIBS@ + +INSTALL = @INSTALL@ + +prefix = @prefix@ +exec_prefix = $(prefix) +libdir = $(exec_prefix)/lib + +ATHENA = /usr/athena + +ftp_OBJS = cmds.o cmdtab.o ftp.o main.o ruserpass.o domacro.o globals.o + +all: ftp + +.c.o: + $(CC) -c $(CFLAGS) -I.. -I$(srcdir)/.. -I../common -I$(srcdir)/../common -I$(ATHENA)/include $(DEFS) $< + +install: + + +ftp: $(ftp_OBJS) ../common/libcommon.a + $(CC) -o ftp $(ftp_OBJS) ../common/libcommon.a -L$(ATHENA)/lib -lkrb -ldes $(LIBS) + +clean cleandir: + rm -f *~ *.o core ftpd ftpcmd.c \#* + +distclean: + rm -f Makefile + rm -rf CVS diff --git a/appl/ftp/ftp/extern.h b/appl/ftp/ftp/extern.h index ebd59227f..686d6a6b2 100644 --- a/appl/ftp/ftp/extern.h +++ b/appl/ftp/ftp/extern.h @@ -38,7 +38,9 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H #include +#endif #ifndef __P #ifdef __STDC__ @@ -60,7 +62,7 @@ void cdup __P((int, char **)); void changetype __P((int, int)); void cmdabort __P((int)); void cmdscanner __P((int)); -int command __((char *fmt, ...)); +int command __P((char *fmt, ...)); int confirm __P((char *, char *)); FILE *dataconn __P((char *)); void delete __P((int, char **)); diff --git a/appl/ftp/ftp/ftp.c b/appl/ftp/ftp/ftp.c index 5e93c27c3..3de9c0eeb 100644 --- a/appl/ftp/ftp/ftp.c +++ b/appl/ftp/ftp/ftp.c @@ -35,6 +35,8 @@ #include "ftp_locl.h" + + struct sockaddr_in hisctladdr; struct sockaddr_in data_addr; int data = -1; @@ -157,6 +159,77 @@ bad: return ((char *)0); } +#include +#include + +int krb4_auth = 0; +KTEXT_ST krb4_adat; + +static des_cblock key; +static des_key_schedule schedule; + +int do_auth(char *service, char *host) +{ + int ret; + CREDENTIALS cred; + char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ]; + strcpy(sname, service); + strcpy(inst, krb_get_phost(host)); + strcpy(realm, krb_realmofhost(host)); + ret = krb_mk_req(&krb4_adat, sname, inst, realm, 0); + if(ret) + return ret; + strcpy(sname, service); + strcpy(inst, krb_get_phost(host)); + strcpy(realm, krb_realmofhost(host)); + ret = krb_get_cred(sname, inst, realm, &cred); + memmove(&key, &cred.session, sizeof(des_cblock)); + des_key_sched(&key, schedule); + memset(&cred, 0, sizeof(cred)); + return ret; +} + + +int do_klogin(char *host) +{ + int ret; + char *phost; + char *p, *q; + int len; + char *serv = "ftp"; + char adat[1024]; + MSG_DAT msg_data; + int checksum; + + ret = command("AUTH KERBEROS_V4"); + if(ret == CONTINUE){ + ret = do_auth("ftp", host); + if(ret == KDC_PR_UNKNOWN) + ret = do_auth("rcmd", host); + if(ret) + return ret; + base64_encode(krb4_adat.dat, krb4_adat.length, &p); + ret = command("ADAT %s", p); + free(p); + if(ret == COMPLETE){ + p = strstr(reply_string, "ADAT="); + if(p){ + p+=5; + for(q = p; isalnum(*q) || strchr("/+=", *q); q++); + *q = 0; + len = base64_decode(p, adat); + ret = krb_rd_safe(adat, len, &key, + &hisctladdr, &myctladdr, &msg_data); + memmove(&checksum, msg_data.app_data, 4); + checksum = ntohl(checksum); + } + krb4_auth = 1; + return 0; + } + } + return -1; +} + int login(char *host) { @@ -189,6 +262,9 @@ login(char *host) else user = tmp; } + if(strcmp(user, "ftp") && strcmp(user, "anonymous")){ + do_klogin(host); + } n = command("USER %s", user); if (n == CONTINUE) { if (pass == NULL) @@ -230,6 +306,69 @@ cmdabort(int sig) longjmp(ptabort,1); } +int krb4_write_enc(FILE *F, char *fmt, va_list ap) +{ + int len; + char *p; + char buf[1024]; + char enc[1024]; + vsprintf(buf, fmt, ap); + len = krb_mk_priv(buf, enc, strlen(buf), schedule, &key, + &myctladdr, &hisctladdr); + base64_encode(enc, len, &p); + + fprintf(F, "ENC %s", p); + return 0; +} + + +int krb4_read_msg(char *s, int priv) +{ + int len; + int ret; + char buf[1024]; + MSG_DAT m; + int code; + + len = base64_decode(s + 4, buf); + if(priv) + ret = krb_rd_priv(buf, len, schedule, &key, + &hisctladdr, &myctladdr, &m); + else + ret = krb_rd_safe(buf, len, &key, &myctladdr, &hisctladdr, &m); + if(ret){ + fprintf(stderr, "%s\n", krb_get_err_text(ret)); + return -1; + } + + m.app_data[m.app_length] = 0; + if(m.app_data[3] == '-') + code = 0; + else + sscanf((char*)m.app_data, "%d", &code); + strncpy(s, (char*)m.app_data, strlen((char*)m.app_data)); + + s[m.app_length] = 0; + len = strlen(s); + if(s[len-1] == '\n') + s[len-1] = 0; + + return code; +} + +int +krb4_read_mic(char *s) +{ + return krb4_read_msg(s, 0); +} + +int +krb4_read_enc(char *s) +{ + return krb4_read_msg(s, 1); +} + + int command(char *fmt, ...) { @@ -252,7 +391,10 @@ command(char *fmt, ...) printf("PASS XXXX"); else vfprintf(stdout, fmt, ap); - vfprintf(cout, fmt, ap); + if(krb4_auth) + krb4_write_enc(cout, fmt, ap); + else + vfprintf(cout, fmt, ap); va_end(ap); if(debug){ printf("\n"); @@ -270,6 +412,93 @@ command(char *fmt, ...) char reply_string[BUFSIZ]; /* last line of previous reply */ +int +getreply(int expecteof) +{ + char *p; + int c; + struct sigaction sa, osa; + char buf[1024]; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = cmdabort; + sigaction(SIGINT, &sa, &osa); + + p = buf; + + while(1){ + c = getc(cin); + switch(c){ + case EOF: + if (expecteof) { + sigaction(SIGINT,&osa, NULL); + code = 221; + return 0; + } + lostpeer(0); + if (verbose) { + printf("421 Service not available, remote server has closed connection\n"); + fflush(stdout); + } + code = 421; + return (4); + break; + case IAC: + c = getc(cin); + if(c == WILL || c == WONT) + fprintf(cout, "%c%c%c", IAC, DONT, getc(cin)); + if(c == DO || c == DONT) + fprintf(cout, "%c%c%c", IAC, WONT, getc(cin)); + continue; + case '\n': + *p++ = 0; + if(isdigit(buf[0])){ + sscanf(buf, "%d", &code); + if(code == 631){ + krb4_read_mic(buf); + sscanf(buf, "%d", &code); + fprintf(stdout, "S:"); + } else if(code == 632){ + krb4_read_enc(buf); + sscanf(buf, "%d", &code); + fprintf(stdout, "P:"); + }else if(code == 633){ + fprintf(stdout, "Confidentiality is meaningless:/n"); + }else if(krb4_auth) + fprintf(stdout, "!!"); /* clear text */ + fprintf(stdout, "%s\n", buf); + if(buf[3] == ' '){ + strcpy(reply_string, buf); + if (code < 200) + cpend = 0; + sigaction(SIGINT, &osa, NULL); + if (code == 421) + lostpeer(0); +#if 0 + if (abrtflag && + osa.sa_handler != cmdabort && + osa.sa_handler != SIG_IGN) + osa.sa_handler(SIGINT); +#endif + return code / 100; + } + }else{ + if(krb4_auth) + fprintf(stdout, "!!"); + fprintf(stdout, "%s\n", buf); + } + p = buf; + continue; + default: + *p++ = c; + } + } + +} + + +#if 0 int getreply(int expecteof) { @@ -360,6 +589,16 @@ getreply(int expecteof) continue; } *cp = '\0'; + if(krb4_auth){ + if(code == 631) + krb4_read_mic(reply_string); + else + krb4_read_enc(reply_string); + n = code / 100 + '0'; + } + + + if (n != '1') cpend = 0; (void) signal(SIGINT,oldintr); @@ -370,6 +609,7 @@ getreply(int expecteof) return (n - '0'); } } +#endif int empty(struct fd_set *mask, int sec) @@ -1109,8 +1349,8 @@ ptransfer(char *direction, long int bytes, long bs; if (verbose) { - td.tv_sec = t0->tv_sec - t1->tv_sec; - td.tv_usec = t0->tv_usec - t1->tv_usec; + td.tv_sec = t1->tv_sec - t0->tv_sec; + td.tv_usec = t1->tv_usec - t0->tv_usec; if(td.tv_usec < 0){ td.tv_sec--; td.tv_usec += 1000000; diff --git a/appl/ftp/ftp/ftp_locl.h b/appl/ftp/ftp/ftp_locl.h new file mode 100644 index 000000000..6c4ada391 --- /dev/null +++ b/appl/ftp/ftp/ftp_locl.h @@ -0,0 +1,41 @@ +#ifndef __FTP_LOCL_H__ +#define __FTP_LOCL_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "extern.h" +#include "common.h" +#include "ftp_var.h" +#include "pathnames.h" + +#if defined(__sun__) && !defined(__svr4) +int fclose(FILE*); +int pclose(FILE*); +extern int optind; +#endif + +#endif /* __FTP_LOCL_H__ */ diff --git a/appl/ftp/ftp/pathnames.h b/appl/ftp/ftp/pathnames.h index 7f17578e3..46e8728a8 100644 --- a/appl/ftp/ftp/pathnames.h +++ b/appl/ftp/ftp/pathnames.h @@ -35,7 +35,13 @@ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 */ +#ifdef HAVE_PATHS_H #include +#endif #undef _PATH_TMP #define _PATH_TMP "/tmp/ftpXXXXXX" + +#ifndef _PATH_BSHELL +#define _PATH_BSHELL "/bin/sh" +#endif diff --git a/appl/ftp/ftpd/Makefile b/appl/ftp/ftpd/Makefile deleted file mode 100644 index 3b0e1ca20..000000000 --- a/appl/ftp/ftpd/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# $NetBSD: Makefile,v 1.12 1995/04/11 02:44:45 cgd Exp $ -# @(#)Makefile 8.2 (Berkeley) 4/4/94 - -PROG= ftpd -CFLAGS+=-DHASSETPROCTITLE -DSKEY -SRCS= ftpd.c ftpcmd.c logwtmp.c popen.c -MAN= ftpd.8 -CLEANFILES+=ftpcmd.c y.tab.h -.PATH: ${.CURDIR}/../../usr.bin/ftp ${.CURDIR}/../../usr.bin/login - -LDADD+= -lcrypt -lskey -DPADD+= ${LIBCRYPT} ${LIBSKEY} - -.if defined(KERBEROS) -SRCS+= klogin.c -CFLAGS+= -DKERBEROS -LDADD+= -lkrb -ldes -DPADD+= ${LIBKRB} ${LIBDES} -.endif - -.include diff --git a/appl/ftp/ftpd/Makefile.in b/appl/ftp/ftpd/Makefile.in new file mode 100644 index 000000000..3de323c44 --- /dev/null +++ b/appl/ftp/ftpd/Makefile.in @@ -0,0 +1,45 @@ +# + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ + +SHELL = /bin/sh + +CC = @CC@ +RANLIB = @RANLIB@ +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ + +INSTALL = @INSTALL@ + +prefix = @prefix@ +exec_prefix = $(prefix) +libdir = $(exec_prefix)/lib + +ATHENA = /usr/athena + +ftpd_OBJS = ftpd.o ftpcmd.o logwtmp.o popen.o auth.o krb4.o + +all: ftpd + +.c.o: + $(CC) -c $(CFLAGS) -I.. -I$(srcdir)/.. -I../common -I$(srcdir)/../common -I$(ATHENA)/include $(DEFS) $< + +install: + + +ftpd: $(ftpd_OBJS) ../common/libcommon.a + $(CC) -o ftpd $(ftpd_OBJS) ../common/libcommon.a -L$(ATHENA)/lib -lkrb -ldes + +ftpcmd.c: ftpcmd.y + $(YACC) $(YFLAGS) $< + chmod a-w y.tab.c + mv -f y.tab.c ftpcmd.c + +clean cleandir: + rm -f *~ *.o core ftpd ftpcmd.c \#* + +distclean: + rm -f Makefile + rm -rf CVS diff --git a/appl/ftp/ftpd/auth.c b/appl/ftp/ftpd/auth.c new file mode 100644 index 000000000..589a25c54 --- /dev/null +++ b/appl/ftp/ftpd/auth.c @@ -0,0 +1,131 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include "extern.h" +#include "krb4.h" +#include "auth.h" + +static struct at auth_types [] = { + { "KERBEROS_V4", krb4_auth, krb4_adat, krb4_pbsz, krb4_prot, krb4_ccc, + krb4_mic, krb4_conf, krb4_enc, krb4_userok, krb4_vprintf }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +struct at *ct; + +int data_protection; +int buffer_size; +int auth_complete; + + +void auth_init(void) +{ +} + +char *ftp_command; +int prot_level; + +void new_ftp_command(char *command) +{ + ftp_command = command; +} + +void delete_ftp_command(void) +{ + if(ftp_command){ + free(ftp_command); + ftp_command = NULL; + } +} + +void auth(char *auth) +{ + for(ct=auth_types; ct->name; ct++){ + if(!strcmp(auth, ct->name)){ + ct->auth(auth); + return; + } + } + reply(504, "%s is not a known security mechanism", auth); +} + +void adat(char *auth) +{ + if(ct) + ct->adat(auth); + else + reply(503, "Error, error"); +} + +void pbsz(int size) +{ + if(ct) + ct->pbsz(size); + else + reply(503, "Error, error"); +} + +void prot(char *pl) +{ + if(ct) + ct->prot(pl); + else + reply(503, "Error, error"); +} + +void ccc(void) +{ + if(ct) + ct->ccc(); + else + reply(503, "Error, error"); +} + +void mic(char *msg) +{ + prot_level = prot_safe; + if(ct) + ct->mic(msg); + else + reply(500, "Command unrecognized"); +} + +void conf(char *msg) +{ + prot_level = prot_confidential; + if(ct) + ct->conf(msg); + else + reply(500, "Command unrecognized"); +} + +void enc(char *msg) +{ + prot_level = prot_private; + if(ct) + ct->enc(msg); + else + reply(500, "Command unrecognized"); +} + +void auth_vprintf(const char *fmt, va_list ap) +{ + if(ct && auth_complete && prot_level){ + ct->vprintf(fmt, ap); + }else + vprintf(fmt, ap); +} + +void auth_printf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + auth_vprintf(fmt, ap); + va_end(ap); +} diff --git a/appl/ftp/ftpd/auth.h b/appl/ftp/ftpd/auth.h new file mode 100644 index 000000000..8f4b5bad0 --- /dev/null +++ b/appl/ftp/ftpd/auth.h @@ -0,0 +1,49 @@ +#ifndef _AUTH_H_ +#define _AUTH_H_ + +#include + +struct at { + char *name; + int (*auth)(char*); + int (*adat)(char*); + int (*pbsz)(int); + int (*prot)(char*); + int (*ccc)(void); + int (*mic)(char*); + int (*conf)(char*); + int (*enc)(char*); + int (*userok)(char*); + int (*vprintf)(const char*, va_list); +}; + +struct at *ct; + +enum protection_levels { + prot_clear, prot_safe, prot_confidential, prot_private +}; + +extern char *ftp_command; +extern int prot_level; + +int data_protection; +int buffer_size; +int auth_complete; + +void auth_init(void); + +void auth(char*); +void adat(char*); +void pbsz(int); +void prot(char*); +void ccc(void); +void mic(char*); +void conf(char*); +void enc(char*); + +void auth_vprintf(const char *fmt, va_list ap); +void auth_printf(const char *fmt, ...); + +void new_ftp_command(char *command); + +#endif /* _AUTH_H_ */ diff --git a/appl/ftp/ftpd/commands.c b/appl/ftp/ftpd/commands.c new file mode 100644 index 000000000..bd0e02a81 --- /dev/null +++ b/appl/ftp/ftpd/commands.c @@ -0,0 +1,115 @@ + +enum form_code { form_code_N, form_code_T, form_code_C }; +enum type_code { type_code_A, type_code_E, type_code_I, type_code_L }; +enum structure_code { structure_code_F, structure_code_R, structure_code_P }; +enum mode_code { mode_code_S, mode_code_B, mode_code_C }; + +enum prot_code { prot_code_C, prot_code_S, prot_code_E, prot_code_P }; + +struct ftp_commands{ + char *name; + int (*user)(char *username); + int (*pass)(char *password); + int (*acct)(char *account); + int (*cwd)(char *pathname); + + int (*auth)(char *mechanism_name); + int (*adat)(char *base64data); + int (*pbsz)(int buffer_size); + int (*prot)(int protection_code); + int (*ccc)(void); + int (*mic)(char *command); + int (*conf)(char *command); + int (*enc)(char *command); + + int (*cdup)(void); + int (*smnt)(char *pathname); + int (*quit)(void); + int (*rein)(void); + int (*port)(char *host_port); + int (*pasv)(void); + int (*type)(int type_code, int form_code); + int (*stru)(int structure_code); + int (*mode)(int mode_code); + int (*retr)(char *pathname); + int (*stor)(char *pathname); + int (*stou)(void); + int (*appe)(char *pathname); + int (*allo)(int decimal_integer, char r, int decimal_integer); + int (*rest)(char *marker); + int (*rnfr)(char *pathname); + int (*rnto)(char *pathname); + int (*abor)(void); + int (*dele)(char *pathname); + int (*rmd)(char *pathname); + int (*mkd)(char *pathname); + int (*pwd)(void); + int (*list)(char *pathname); + int (*nlst)(char *pathname); + int (*site)(char *string); + int (*syst)(void); + int (*stat)(char *pathname); + int (*help)(char *string); + int (*noop)(void); + + int (*reply)(int code, char *msg); + int (*lreply)(int code, char *msg); +}; + + +struct ftp_commands commands [] = { + { + "noauth", + + user, pass, acct, cwd, + + NULL, /* AUTH */ + NULL, /* ADAT */ + NULL, /* PBSZ */ + NULL, /* PROT */ + NULL, /* CCC */ + NULL, /* MIC */ + NULL, /* CONF */ + NULL, /* ENC */ + + cdup, smnt, quit, rein, port, pasv, type, stru, mode, retr, stor, + stou, appe, allo, rest, rnfr, rnto, abor, dele, rmd, mkd, pwd, list, + nlst, site, syst, stat, help, noop, + + reply, lreply + } + { + "KERBEROS_V4", + + krb4_user, krb4_pass, krb4_acct, NULL, krb4_auth, krb4_adat, +}; + + + ::= + ::= + ::= + ::= | + ::= any of the 128 ASCII characters except and + + ::= + ::= | + ::= printable characters, any + ASCII code 33 through 126 + ::= + ::= , + ::= ,,, + ::= , + ::= any decimal integer 1 through 255 + ::= N | T | C + ::= A [ ] + | E [ ] + | I + | L + ::= F | R | P + ::= S | B | C + ::= + ::= any decimal integer + + + + diff --git a/appl/ftp/ftpd/extern.h b/appl/ftp/ftpd/extern.h index 9f825d7ba..416f6a7a0 100644 --- a/appl/ftp/ftpd/extern.h +++ b/appl/ftp/ftpd/extern.h @@ -35,33 +35,72 @@ * @(#)extern.h 8.2 (Berkeley) 4/4/94 */ -void blkfree __P((char **)); -char **copyblk __P((char **)); -void cwd __P((char *)); -void delete __P((char *)); -void dologout __P((int)); -void fatal __P((char *)); -int ftpd_pclose __P((FILE *)); -FILE *ftpd_popen __P((char *, char *)); -char *getline __P((char *, int, FILE *)); -void logwtmp __P((char *, char *, char *)); -void lreply __P((int, const char *, ...)); -void makedir __P((char *)); -void nack __P((char *)); -void pass __P((char *)); -void passive __P((void)); -void perror_reply __P((int, char *)); -void pwd __P((void)); -void removedir __P((char *)); -void renamecmd __P((char *, char *)); -char *renamefrom __P((char *)); -void reply __P((int, const char *, ...)); -void retrieve __P((char *, char *)); -void send_file_list __P((char *)); -void setproctitle __P((const char *, ...)); -void statcmd __P((void)); -void statfilecmd __P((char *)); -void store __P((char *, char *, int)); -void upper __P((char *)); -void user __P((char *)); -void yyerror __P((char *)); +#ifndef _EXTERN_H_ +#define _EXTERN_H_ + +#include +#include + +#include +#include +#include +#include + +void blkfree(char **); +char **copyblk(char **); +void cwd(char *); +void delete(char *); +void dologout(int); +void fatal(char *); +int ftpd_pclose(FILE *); +FILE *ftpd_popen(char *, char *); +char *getline(char *, int); +void logwtmp(char *, char *, char *); +void lreply(int, const char *, ...); +void makedir(char *); +void nack(char *); +void pass(char *); +void passive(void); +void perror_reply(int, char *); +void pwd(void); +void removedir(char *); +void renamecmd(char *, char *); +char *renamefrom(char *); +void reply(int, const char *, ...); +void retrieve(char *, char *); +void send_file_list(char *); +void setproctitle(const char *, ...); +void statcmd(void); +void statfilecmd(char *); +void store(char *, char *, int); +void upper(char *); +void user(char *); +void yyerror(char *); + +extern struct sockaddr_in ctrl_addr, his_addr; +extern char hostname[]; + +extern struct sockaddr_in data_dest; +extern int logged_in; +extern struct passwd *pw; +extern int guest; +extern int logging; +extern int type; +extern int oobflag; +extern off_t file_size; +extern off_t byte_count; +extern jmp_buf urgcatch; + +extern int form; +extern int debug; +extern int timeout; +extern int maxtimeout; +extern int pdata; +extern char hostname[], remotehost[]; +extern char proctitle[]; +extern int usedefault; +extern int transflag; +extern char tmpline[]; + + +#endif /* _EXTERN_H_ */ diff --git a/appl/ftp/ftpd/ftpcmd.y b/appl/ftp/ftpd/ftpcmd.y index 98c2d8350..391685816 100644 --- a/appl/ftp/ftpd/ftpcmd.y +++ b/appl/ftp/ftpd/ftpcmd.y @@ -71,23 +71,7 @@ static char rcsid[] = "$NetBSD: ftpcmd.y,v 1.6 1995/06/03 22:46:45 mycroft Exp $ #include #include "extern.h" - -extern struct sockaddr_in data_dest; -extern int logged_in; -extern struct passwd *pw; -extern int guest; -extern int logging; -extern int type; -extern int form; -extern int debug; -extern int timeout; -extern int maxtimeout; -extern int pdata; -extern char hostname[], remotehost[]; -extern char proctitle[]; -extern int usedefault; -extern int transflag; -extern char tmpline[]; +#include "auth.h" off_t restart_point; @@ -120,6 +104,9 @@ char *fromname; UMASK IDLE CHMOD + AUTH ADAT PROT PBSZ CCC MIC + CONF ENC + LEXERR %token STRING @@ -149,6 +136,43 @@ cmd user($3); free($3); } + | AUTH SP STRING CRLF + { + auth($3); + free($3); + } + | ADAT SP STRING CRLF + { + adat($3); + free($3); + } + | PBSZ SP NUMBER CRLF + { + pbsz($3); + } + | PROT SP STRING CRLF + { + prot($3); + } + | CCC CRLF + { + ccc(); + } + | MIC SP STRING CRLF + { + mic($3); + free($3); + } + | CONF SP STRING CRLF + { + conf($3); + free($3); + } + | ENC SP STRING CRLF + { + enc($3); + free($3); + } | PASS SP password CRLF { pass($3); @@ -288,8 +312,15 @@ cmd } | STAT CRLF { - statcmd(); - } + if(oobflag){ + if (file_size != (off_t) -1) + reply(213, "Status: %ld of %ld bytes transferred", + byte_count, file_size); + else + reply(213, "Status: %ld bytes transferred", byte_count); + }else + statcmd(); + } | DELE check_login SP pathname CRLF { if ($2 && $4 != NULL) @@ -310,7 +341,13 @@ cmd } | ABOR CRLF { - reply(225, "ABOR command successful."); + if(oobflag){ + reply(426, "Transfer aborted. Data connection closed."); + reply(226, "Abort successful"); + oobflag = 0; + longjmp(urgcatch, 1); + }else + reply(225, "ABOR command successful."); } | CWD check_login CRLF { @@ -531,7 +568,7 @@ rcmd { fromname = (char *) 0; restart_point = $3; /* XXX $3 is only "int" */ - reply(350, "Restarting at %qd. %s", restart_point, + reply(350, "Restarting at %ld. %s", restart_point, "Send STORE or RETRIEVE to initiate transfer."); } ; @@ -558,7 +595,6 @@ host_port { char *a, *p; - data_dest.sin_len = sizeof(struct sockaddr_in); data_dest.sin_family = AF_INET; p = (char *)&data_dest.sin_port; p[0] = $9; p[1] = $11; @@ -717,11 +753,15 @@ octal_number check_login : /* empty */ { + if(auth_complete && prot_level == prot_clear){ + reply(533, "Command protection level denied for paranoid reasons."); + $$ = 0; + }else if (logged_in) - $$ = 1; + $$ = 1; else { - reply(530, "Please login with USER and PASS."); - $$ = 0; + reply(530, "Please login with USER and PASS."); + $$ = 0; } } ; @@ -796,6 +836,17 @@ struct tab cmdtab[] = { /* In order defined in RFC 765 */ { "STOU", STOU, STR1, 1, " file-name" }, { "SIZE", SIZE, OSTR, 1, " path-name" }, { "MDTM", MDTM, OSTR, 1, " path-name" }, + + /* extensions from draft-ietf-cat-ftpsec-08 */ + { "AUTH", AUTH, STR1, 1, " auth-type" }, + { "ADAT", ADAT, STR1, 1, " auth-data" }, + { "PBSZ", PBSZ, ARGS, 1, " buffer-size" }, + { "PROT", PROT, ARGS, 1, " prot-level" }, + { "CCC", CCC, ARGS, 1, "" }, + { "MIC", MIC, STR1, 1, " integrity command" }, + { "CONF", CONF, STR1, 1, " confidentiality command" }, + { "ENC", ENC, STR1, 1, " privacy command" }, + { NULL, 0, 0, 0, 0 } }; @@ -833,43 +884,38 @@ lookup(p, cmd) * getline - a hacked up version of fgets to ignore TELNET escape codes. */ char * -getline(s, n, iop) - char *s; - int n; - FILE *iop; +getline(char *s, int n) { int c; register char *cs; cs = s; /* tmpline may contain saved command from urgent mode interruption */ - for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { - *cs++ = tmpline[c]; - if (tmpline[c] == '\n') { - *cs++ = '\0'; - if (debug) - syslog(LOG_DEBUG, "command: %s", s); - tmpline[0] = '\0'; - return(s); - } - if (c == 0) - tmpline[0] = '\0'; + if(ftp_command){ + strncpy(s, ftp_command, n); + if (debug) + syslog(LOG_DEBUG, "command: %s", s); +#if 0 + fprintf(stderr, "%s\n", s); +#endif + return s; } - while ((c = getc(iop)) != EOF) { + prot_level = prot_clear; + while ((c = getc(stdin)) != EOF) { c &= 0377; if (c == IAC) { - if ((c = getc(iop)) != EOF) { + if ((c = getc(stdin)) != EOF) { c &= 0377; switch (c) { case WILL: case WONT: - c = getc(iop); + c = getc(stdin); printf("%c%c%c", IAC, DONT, 0377&c); (void) fflush(stdout); continue; case DO: case DONT: - c = getc(iop); + c = getc(stdin); printf("%c%c%c", IAC, WONT, 0377&c); (void) fflush(stdout); continue; @@ -905,6 +951,9 @@ getline(s, n, iop) syslog(LOG_DEBUG, "command: %.*s", len, s); } } +#if 0 + fprintf(stderr, "%s\n", s); +#endif return (s); } @@ -936,7 +985,7 @@ yylex() case CMD: (void) signal(SIGALRM, toolong); (void) alarm((unsigned) timeout); - if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + if (getline(cbuf, sizeof(cbuf)-1) == NULL) { reply(221, "You could at least say goodbye."); dologout(0); } @@ -1171,6 +1220,7 @@ help(ctab, s) struct tab *c; int width, NCMDS; char *type; + char buf[1024]; if (ctab == sitetab) type = "SITE "; @@ -1196,22 +1246,21 @@ help(ctab, s) columns = 1; lines = (NCMDS + columns - 1) / columns; for (i = 0; i < lines; i++) { - printf(" "); - for (j = 0; j < columns; j++) { - c = ctab + j * lines + i; - printf("%s%c", c->name, - c->implemented ? ' ' : '*'); - if (c + lines >= &ctab[NCMDS]) - break; - w = strlen(c->name) + 1; - while (w < width) { - putchar(' '); - w++; - } + sprintf(buf, " "); + for (j = 0; j < columns; j++) { + c = ctab + j * lines + i; + sprintf(buf + strlen(buf), "%s%c", c->name, + c->implemented ? ' ' : '*'); + if (c + lines >= &ctab[NCMDS]) + break; + w = strlen(c->name) + 1; + while (w < width) { + strcat(buf, " "); + w++; } - printf("\r\n"); + } + lreply(214, buf); } - (void) fflush(stdout); reply(214, "Direct comments to ftp-bugs@%s.", hostname); return; } @@ -1265,7 +1314,7 @@ sizecmd(filename) } (void) fclose(fin); - reply(213, "%qd", count); + reply(213, "%ld", count); break; } default: reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); diff --git a/appl/ftp/ftpd/ftpd.c b/appl/ftp/ftpd/ftpd.c index 67d310563..d241c105d 100644 --- a/appl/ftp/ftpd/ftpd.c +++ b/appl/ftp/ftpd/ftpd.c @@ -47,6 +47,10 @@ static char rcsid[] = "$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $" #endif #endif /* not lint */ +#ifdef HAVE_CONFIG_H +#include +#endif + /* * FTP server. */ @@ -67,7 +71,6 @@ static char rcsid[] = "$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $" #include #include -#include #include #include #include @@ -82,14 +85,19 @@ static char rcsid[] = "$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $" #include #include #include +#include + +#include #include "pathnames.h" #include "extern.h" +#include "common.h" -#if __STDC__ -#include -#else -#include +#include "auth.h" + + +#ifndef LOG_FTP +#define LOG_FTP LOG_DAEMON #endif static char version[] = "Version 6.00"; @@ -105,6 +113,7 @@ struct sockaddr_in pasv_addr; int data; jmp_buf errcatch, urgcatch; +int oobflag; int logged_in; struct passwd *pw; int debug; @@ -119,7 +128,7 @@ int stru; /* avoid C keyword */ int mode; int usedefault = 1; /* for data transfers */ int pdata = -1; /* for passive mode */ -sig_atomic_t transflag; +int transflag; off_t file_size; off_t byte_count; #if !defined(CMASK) || CMASK == 0 @@ -127,7 +136,7 @@ off_t byte_count; #define CMASK 027 #endif int defumask = CMASK; /* default umask value */ -char tmpline[7]; +char tmpline[10240]; char hostname[MAXHOSTNAMELEN]; char remotehost[MAXHOSTNAMELEN]; static char ttyline[20]; @@ -138,6 +147,19 @@ int notickets = 1; char *krbtkfile_env = NULL; #endif +char *getusershell(void); +int endusershell(void); +int setusershell(void); + +#ifdef sun +extern char *optarg; +extern int optind, opterr; + +int fclose(FILE*); +char* crypt(char*, char*); +char* getwd(char*); +#endif + /* * Timeout intervals for retrying connections * to hosts that don't accept PORT cmds. This @@ -168,7 +190,7 @@ char proctitle[BUFSIZ]; /* initial part of title */ syslog(LOG_INFO,"%s %s%s", cmd, \ *(file) == '/' ? "" : curdir(), file); \ else \ - syslog(LOG_INFO, "%s %s%s = %qd bytes", \ + syslog(LOG_INFO, "%s %s%s = %ld bytes", \ cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \ } @@ -177,19 +199,16 @@ static void myoob __P((int)); static int checkuser __P((char *, char *)); static FILE *dataconn __P((char *, off_t, char *)); static void dolog __P((struct sockaddr_in *)); -static char *curdir __P((void)); static void end_login __P((void)); static FILE *getdatasock __P((char *)); static char *gunique __P((char *)); static void lostconn __P((int)); static int receive_data __P((FILE *, FILE *)); static void send_data __P((FILE *, FILE *, off_t)); -static struct passwd * - sgetpwnam __P((char *)); -static char *sgetsave __P((char *)); +static struct passwd * sgetpwnam __P((char *)); static char * -curdir() +curdir(void) { static char path[MAXPATHLEN+1+1]; /* path + '/' + '\0' */ @@ -201,16 +220,46 @@ curdir() return (guest ? path+1 : path); } +#ifndef LINE_MAX +#define LINE_MAX 1024 +#endif + +static void gurka(void) +{ + int s, t; + struct sockaddr_in sa; + int one = 1; + s = socket(AF_INET, SOCK_STREAM, 0); + + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + memset(&sa, 0, sizeof(sa)); + sa.sin_port = htons(21); + sa.sin_addr.s_addr = INADDR_ANY; + bind(s, (struct sockaddr*)&sa, sizeof(sa)); + listen(s, 5); + t = accept(s, NULL, 0); + close(s); + dup2(t, 0); + dup2(t, 1); + if(t > 2) + close(t); +} + + + +#ifndef HAVE___PROGNAME +char *__progname = "ftpd"; +#endif + int -main(argc, argv, envp) - int argc; - char *argv[]; - char **envp; +main(int argc, char **argv, char **envp) { int addrlen, ch, on = 1, tos; char *cp, line[LINE_MAX]; FILE *fd; + gurka(); + /* * LOG_NDELAY sets up the logging connection immediately, * necessary for anonymous ftp's that chroot and can't do it later. @@ -276,16 +325,18 @@ main(argc, argv, envp) break; default: - warnx("unknown flag -%c ignored", optopt); + warnx("unknown flag -%c ignored", argv[optind-1][0]); break; } } - (void) freopen(_PATH_DEVNULL, "w", stderr); + /* (void) freopen(_PATH_DEVNULL, "w", stderr); */ (void) signal(SIGPIPE, lostconn); (void) signal(SIGCHLD, SIG_IGN); if ((long)signal(SIGURG, myoob) < 0) syslog(LOG_ERR, "signal: %m"); + auth_init(); + /* Try to handle urgent data inline */ #ifdef SO_OOBINLINE if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) @@ -338,8 +389,7 @@ main(argc, argv, envp) } static void -lostconn(signo) - int signo; +lostconn(int signo) { if (debug) @@ -351,8 +401,7 @@ lostconn(signo) * Helper function for sgetpwnam(). */ static char * -sgetsave(s) - char *s; +sgetsave(char *s) { char *new = malloc((unsigned) strlen(s) + 1); @@ -371,8 +420,7 @@ sgetsave(s) * (e.g., globbing). */ static struct passwd * -sgetpwnam(name) - char *name; +sgetpwnam(char *name) { static struct passwd save; struct passwd *p; @@ -411,8 +459,7 @@ static char curname[10]; /* current USER name */ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. */ void -user(name) - char *name; +user(char *name) { char *cp, *shell; @@ -473,9 +520,12 @@ user(name) myskey ? myskey : "error getting challenge", name); } else #endif - reply(331, "Password required for %s.", name); - - askpasswd = 1; + if(ct) + ct->userok(name); + else{ + reply(331, "Password required for %s.", name); + askpasswd = 1; + } /* * Delay before reading passwd after first failed * attempt to slow down passwd-guessing programs. @@ -488,9 +538,7 @@ user(name) * Check if a user is in the file "fname" */ static int -checkuser(fname, name) - char *fname; - char *name; +checkuser(char *fname, char *name) { FILE *fd; int found = 0; @@ -512,12 +560,95 @@ checkuser(fname, name) return (found); } +int do_login(int code, char *passwd) +{ + FILE *fd; + login_attempts = 0; /* this time successful */ + if (setegid((gid_t)pw->pw_gid) < 0) { + reply(550, "Can't set gid."); + return -1; + } + (void) initgroups(pw->pw_name, pw->pw_gid); + + /* open wtmp before chroot */ + logwtmp(ttyline, pw->pw_name, remotehost); + logged_in = 1; + + dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name); + if (guest) { + /* + * We MUST do a chdir() after the chroot. Otherwise + * the old current directory will be accessible as "." + * outside the new root! + */ + if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { + reply(550, "Can't set guest privileges."); + return -1; + } + } else if (dochroot) { + if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { + reply(550, "Can't change root."); + return -1; + } + } else if (chdir(pw->pw_dir) < 0) { + if (chdir("/") < 0) { + reply(530, "User %s: can't change directory to %s.", + pw->pw_name, pw->pw_dir); + return -1; + } else + lreply(code, "No directory! Logging in with home=/"); + } + if (seteuid((uid_t)pw->pw_uid) < 0) { + reply(550, "Can't set uid."); + return -1; + } + /* + * Display a login message, if it exists. + * N.B. reply(code,) must follow the message. + */ + if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { + char *cp, line[LINE_MAX]; + + while (fgets(line, sizeof(line), fd) != NULL) { + if ((cp = strchr(line, '\n')) != NULL) + *cp = '\0'; + lreply(code, "%s", line); + } + } + if (guest) { + reply(code, "Guest login ok, access restrictions apply."); +#ifdef HASSETPROCTITLE + snprintf(proctitle, sizeof(proctitle), + "%s: anonymous/%.*s", remotehost, + sizeof(proctitle) - sizeof(remotehost) - + sizeof(": anonymous/"), passwd); + setproctitle(proctitle); +#endif /* HASSETPROCTITLE */ + if (logging) + syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", + remotehost, passwd); + } else { + reply(code, "User %s logged in.", pw->pw_name); +#ifdef HASSETPROCTITLE + snprintf(proctitle, sizeof(proctitle), + "%s: %s", remotehost, pw->pw_name); + setproctitle(proctitle); +#endif /* HASSETPROCTITLE */ + if (logging) + syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", + remotehost, pw->pw_name); + } + (void) umask(defumask); + return 0; +} + + /* * Terminate login as previous user, if any, resetting state; * used when USER command is given or login fails. */ static void -end_login() +end_login(void) { (void) seteuid((uid_t)0); @@ -530,11 +661,14 @@ end_login() } void -pass(passwd) - char *passwd; +pass(char *passwd) { int rval; - FILE *fd; + /* some clients insists on sending a password */ + if (logged_in && askpasswd == 0){ + reply(230, "Dumpucko!"); + return; + } if (logged_in || askpasswd == 0) { reply(503, "Login with USER first."); @@ -588,93 +722,16 @@ skip: return; } } - login_attempts = 0; /* this time successful */ - if (setegid((gid_t)pw->pw_gid) < 0) { - reply(550, "Can't set gid."); - return; - } - (void) initgroups(pw->pw_name, pw->pw_gid); - - /* open wtmp before chroot */ - logwtmp(ttyline, pw->pw_name, remotehost); - logged_in = 1; - - dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name); - if (guest) { - /* - * We MUST do a chdir() after the chroot. Otherwise - * the old current directory will be accessible as "." - * outside the new root! - */ - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't set guest privileges."); - goto bad; - } - } else if (dochroot) { - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't change root."); - goto bad; - } - } else if (chdir(pw->pw_dir) < 0) { - if (chdir("/") < 0) { - reply(530, "User %s: can't change directory to %s.", - pw->pw_name, pw->pw_dir); - goto bad; - } else - lreply(230, "No directory! Logging in with home=/"); - } - if (seteuid((uid_t)pw->pw_uid) < 0) { - reply(550, "Can't set uid."); - goto bad; - } - /* - * Display a login message, if it exists. - * N.B. reply(230,) must follow the message. - */ - if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { - char *cp, line[LINE_MAX]; - - while (fgets(line, sizeof(line), fd) != NULL) { - if ((cp = strchr(line, '\n')) != NULL) - *cp = '\0'; - lreply(230, "%s", line); - } - (void) fflush(stdout); - (void) fclose(fd); - } - if (guest) { - reply(230, "Guest login ok, access restrictions apply."); -#ifdef HASSETPROCTITLE - snprintf(proctitle, sizeof(proctitle), - "%s: anonymous/%.*s", remotehost, - sizeof(proctitle) - sizeof(remotehost) - - sizeof(": anonymous/"), passwd); - setproctitle(proctitle); -#endif /* HASSETPROCTITLE */ - if (logging) - syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", - remotehost, passwd); - } else { - reply(230, "User %s logged in.", pw->pw_name); -#ifdef HASSETPROCTITLE - snprintf(proctitle, sizeof(proctitle), - "%s: %s", remotehost, pw->pw_name); - setproctitle(proctitle); -#endif /* HASSETPROCTITLE */ - if (logging) - syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", - remotehost, pw->pw_name); - } - (void) umask(defumask); - return; + if(!do_login(230, passwd)) + return; + bad: /* Forget all about it... */ end_login(); } void -retrieve(cmd, name) - char *cmd, *name; +retrieve(char *cmd, char *name) { FILE *fin, *dout; struct stat st; @@ -720,7 +777,7 @@ retrieve(cmd, name) if (c == '\n') i++; } - } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { + } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { perror_reply(550, name); goto done; } @@ -739,9 +796,7 @@ done: } void -store(name, mode, unique) - char *name, *mode; - int unique; +store(char *name, char *mode, int unique) { FILE *fout, *din; struct stat st; @@ -783,11 +838,11 @@ store(name, mode, unique) * because we are changing from reading to * writing. */ - if (fseek(fout, 0L, L_INCR) < 0) { + if (fseek(fout, 0L, SEEK_CUR) < 0) { perror_reply(550, name); goto done; } - } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { + } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { perror_reply(550, name); goto done; } @@ -811,8 +866,7 @@ done: } static FILE * -getdatasock(mode) - char *mode; +getdatasock(char *mode) { int on = 1, s, t, tries; @@ -826,7 +880,6 @@ getdatasock(mode) (char *) &on, sizeof(on)) < 0) goto bad; /* anchor socket to avoid multi-homing problems */ - data_source.sin_len = sizeof(struct sockaddr_in); data_source.sin_family = AF_INET; data_source.sin_addr = ctrl_addr.sin_addr; for (tries = 1; ; tries++) { @@ -854,10 +907,7 @@ bad: } static FILE * -dataconn(name, size, mode) - char *name; - off_t size; - char *mode; +dataconn(char *name, off_t size, char *mode) { char sizebuf[32]; FILE *file; @@ -866,7 +916,7 @@ dataconn(name, size, mode) file_size = size; byte_count = 0; if (size != (off_t) -1) - (void) sprintf(sizebuf, " (%qd bytes)", size); + (void) sprintf(sizebuf, " (%ld bytes)", size); else (void) strcpy(sizebuf, ""); if (pdata >= 0) { @@ -932,9 +982,7 @@ dataconn(name, size, mode) * NB: Form isn't handled. */ static void -send_data(instr, outstr, blksize) - FILE *instr, *outstr; - off_t blksize; +send_data(FILE *instr, FILE *outstr, off_t blksize) { int c, cnt, filefd, netfd; char *buf; @@ -1009,8 +1057,7 @@ file_err: * N.B.: Form isn't handled. */ static int -receive_data(instr, outstr) - FILE *instr, *outstr; +receive_data(FILE *instr, FILE *outstr) { int c; int cnt, bare_lfs = 0; @@ -1088,8 +1135,7 @@ file_err: } void -statfilecmd(filename) - char *filename; +statfilecmd(char *filename) { FILE *fin; int c; @@ -1120,8 +1166,9 @@ statfilecmd(filename) } void -statcmd() +statcmd(void) { +#if 0 struct sockaddr_in *sin; u_char *a, *p; @@ -1169,12 +1216,12 @@ printaddr: #undef UC } else printf(" No data connection\r\n"); +#endif reply(211, "End of status"); } void -fatal(s) - char *s; +fatal(char *s) { reply(451, "Error in server: %s\n", s); @@ -1183,69 +1230,52 @@ fatal(s) /* NOTREACHED */ } -void -#if __STDC__ -reply(int n, const char *fmt, ...) -#else -reply(n, fmt, va_alist) - int n; - char *fmt; - va_dcl -#endif +static void +int_reply(int n, char *c, const char *fmt, va_list ap) { - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)printf("%d ", n); - (void)vprintf(fmt, ap); - (void)printf("\r\n"); - (void)fflush(stdout); - if (debug) { - syslog(LOG_DEBUG, "<--- %d ", n); - vsyslog(LOG_DEBUG, fmt, ap); - } + char buf[10240]; + char *p; + p=buf; + sprintf(p, "%d%s", n, c); + p+=strlen(p); + vsprintf(p, fmt, ap); + p+=strlen(p); + sprintf(p, "\r\n"); + p+=strlen(p); + auth_printf("%s", buf); + fflush(stdout); + if (debug) + syslog(LOG_DEBUG, "<--- %s- ", buf); } void -#if __STDC__ -lreply(int n, const char *fmt, ...) -#else -lreply(n, fmt, va_alist) - int n; - char *fmt; - va_dcl -#endif +reply(int n, const char *fmt, ...) { - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)printf("%d- ", n); - (void)vprintf(fmt, ap); - (void)printf("\r\n"); - (void)fflush(stdout); - if (debug) { - syslog(LOG_DEBUG, "<--- %d- ", n); - vsyslog(LOG_DEBUG, fmt, ap); - } + va_list ap; + va_start(ap, fmt); + int_reply(n, " ", fmt, ap); + delete_ftp_command(); + va_end(ap); +} + +void +lreply(int n, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int_reply(n, "-", fmt, ap); + va_end(ap); } static void -ack(s) - char *s; +ack(char *s) { reply(250, "%s command successful.", s); } void -nack(s) - char *s; +nack(char *s) { reply(502, "%s command not implemented.", s); @@ -1253,8 +1283,7 @@ nack(s) /* ARGSUSED */ void -yyerror(s) - char *s; +yyerror(char *s) { char *cp; @@ -1264,8 +1293,7 @@ yyerror(s) } void -delete(name) - char *name; +delete(char *name) { struct stat st; @@ -1290,8 +1318,7 @@ done: } void -cwd(path) - char *path; +cwd(char *path) { if (chdir(path) < 0) @@ -1301,8 +1328,7 @@ cwd(path) } void -makedir(name) - char *name; +makedir(char *name) { LOGCMD("mkdir", name); @@ -1313,8 +1339,7 @@ makedir(name) } void -removedir(name) - char *name; +removedir(char *name) { LOGCMD("rmdir", name); @@ -1325,7 +1350,7 @@ removedir(name) } void -pwd() +pwd(void) { char path[MAXPATHLEN + 1]; @@ -1336,8 +1361,7 @@ pwd() } char * -renamefrom(name) - char *name; +renamefrom(char *name) { struct stat st; @@ -1350,8 +1374,7 @@ renamefrom(name) } void -renamecmd(from, to) - char *from, *to; +renamecmd(char *from, char *to) { LOGCMD2("rename", from, to); @@ -1362,8 +1385,7 @@ renamecmd(from, to) } static void -dolog(sin) - struct sockaddr_in *sin; +dolog(struct sockaddr_in *sin) { struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); @@ -1387,8 +1409,7 @@ dolog(sin) * and exit with supplied status. */ void -dologout(status) - int status; +dologout(int status) { if (logged_in) { @@ -1403,17 +1424,29 @@ dologout(status) _exit(status); } +void abor(void) +{ +} + static void -myoob(signo) - int signo; +myoob(int signo) { char *cp; /* only process if transfer occurring */ if (!transflag) return; + + oobflag = 1; + yyparse(); + oobflag = 0; + + /* hopefully this will work. this way we can send commands to + yyparse() from other sources than stdin */ + +#if 0 cp = tmpline; - if (getline(cp, 7, stdin) == NULL) { + if (getline(cp, 7) == NULL) { reply(221, "You could at least say goodbye."); dologout(0); } @@ -1426,11 +1459,12 @@ myoob(signo) } if (strcmp(cp, "STAT\r\n") == 0) { if (file_size != (off_t) -1) - reply(213, "Status: %qd of %qd bytes transferred", + reply(213, "Status: %ld of %ld bytes transferred", byte_count, file_size); else - reply(213, "Status: %qd bytes transferred", byte_count); + reply(213, "Status: %ld bytes transferred", byte_count); } +#endif } /* @@ -1440,7 +1474,7 @@ myoob(signo) * with Rick Adams on 25 Jan 89. */ void -passive() +passive(void) { int len; char *p, *a; @@ -1485,8 +1519,7 @@ pasv_error: * Generates failure reply on error. */ static char * -gunique(local) - char *local; +gunique(char *local) { static char new[MAXPATHLEN]; struct stat st; @@ -1518,9 +1551,7 @@ gunique(local) * Format and send reply containing system error number. */ void -perror_reply(code, string) - int code; - char *string; +perror_reply(int code, char *string) { reply(code, "%s: %s.", string, strerror(errno)); @@ -1532,8 +1563,7 @@ static char *onefile[] = { }; void -send_file_list(whichf) - char *whichf; +send_file_list(char *whichf) { struct stat st; DIR *dirp = NULL; diff --git a/appl/ftp/ftpd/krb4.c b/appl/ftp/ftpd/krb4.c new file mode 100644 index 000000000..ebafbb59e --- /dev/null +++ b/appl/ftp/ftpd/krb4.c @@ -0,0 +1,195 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include "base64.h" +#include "extern.h" +#include "auth.h" + +static AUTH_DAT auth_dat; +static des_key_schedule schedule; + +int krb4_auth(char *auth) +{ + auth_complete = 0; + reply(334, "Using authentication type %s; ADAT must follow", auth); + return 0; +} + +int krb4_adat(char *auth) +{ + KTEXT_ST tkt; + char *p; + int kerror; + u_int32_t cs; + char msg[35]; /* size of encrypted block */ + int len; + + char inst[INST_SZ]; + + memset(&tkt, 0, sizeof(tkt)); + tkt.length = base64_decode(auth, tkt.dat); + + strcpy(inst, "*"); + kerror = krb_rd_req(&tkt, "ftp", inst, 0, &auth_dat, ""); + if(kerror == RD_AP_UNDEC){ + strcpy(inst, "*"); + kerror = krb_rd_req(&tkt, "rcmd", inst, 0, &auth_dat, ""); + } + + des_key_sched(&auth_dat.session, schedule); + + if(kerror != RD_AP_OK){ + reply(535, "%s", krb_err_txt[kerror]); + return 1; + } + + cs = htonl(auth_dat.checksum + 1); + len = krb_mk_safe((u_char*)&cs, (u_char*)msg, sizeof(cs), + &auth_dat.session, &ctrl_addr, &his_addr); + base64_encode((unsigned char*)msg, len, &p); + reply(235, "ADAT=%s", p); + auth_complete = 1; + free(p); + return 0; +} + +int krb4_pbsz(int size) +{ + buffer_size = size; + reply(200, "OK"); + return 0; +} + +int krb4_prot(char *type) +{ + if(!strcmp(type, "C")){ + data_protection = prot_clear; + }else if(!strcmp(type, "S")){ + data_protection = prot_safe; + }else if(!strcmp(type, "E")){ + data_protection = prot_confidential; + }else if(!strcmp(type, "P")){ + data_protection = prot_private; + }else{ + reply(504, "Unrecognized protection level"); + return 1; + } + reply(200, "OK"); + return 0; +} + +int krb4_ccc(void) +{ + reply(500, "Gurka"); + return 1; +} + +int krb4_mic(char *msg) +{ + char *cmd = (char*)malloc(strlen(msg)); + int len; + int kerror; + MSG_DAT m_data; + char *p; + char tmp[1024]; + unsigned char enc[1024]; + + len = base64_decode(msg, cmd); + kerror = krb_rd_safe(cmd, len, &auth_dat.session, + &ctrl_addr, &his_addr, &m_data); + sprintf(tmp, "%.*s\r\n", m_data.app_length, m_data.app_data); + new_ftp_command(strdup(tmp)); + free(cmd); + return 0; +} + +int krb4_conf(char *msg) +{ + char tmp[1024]; + unsigned char enc[1024]; + int len; + char *p; + + sprintf(tmp, "%d %s\r\n", 536, + "Requested PROT level not supported by mechanism"); + len = krb_mk_safe((u_char*)tmp, (u_char*)enc, strlen(tmp), &auth_dat.session, + &ctrl_addr, &his_addr); + if(len > 0){ + base64_encode(enc, len, &p); + fprintf(stdout, "631 %s\r\n", p); + free(p); + } + return 1; +} + +int krb4_enc(char *msg) +{ + char *cmd = (char*)malloc(strlen(msg)); + int len; + int kerror; + MSG_DAT m_data; + char *p; + + char tmp[1024]; + unsigned char enc[1024]; + + len = base64_decode(msg, cmd); + + kerror = krb_rd_priv(cmd, len, schedule, &auth_dat.session, + &ctrl_addr, &his_addr, &m_data); + sprintf(tmp, "%.*s\r\n", m_data.app_length, m_data.app_data); + new_ftp_command(strdup(tmp)); + + free(cmd); + return 0; +} + +int krb4_userok(char *name) +{ + if(!kuserok(&auth_dat, name)){ + do_login(232, name); + }else{ + reply(530, "User %s access denied.", name); + } + return 0; +} + + +int krb4_vprintf(const char *fmt, va_list ap) +{ + char buf[10240]; + char *p; + char *enc; + int code; + int len; + + vsprintf(buf, fmt, ap); + enc = malloc(strlen(buf) + 31); + if(prot_level == prot_safe){ + len = krb_mk_safe((u_char*)buf, (u_char*)enc, strlen(buf), &auth_dat.session, + &ctrl_addr, &his_addr); + code = 631; + }else if(prot_level == prot_private){ + len = krb_mk_priv((u_char*)buf, (u_char*)enc, strlen(buf), schedule, + &auth_dat.session, &ctrl_addr, &his_addr); + code = 632; + }else{ + len = 0; /* XXX */ + code = 631; + } + base64_encode(enc, len, &p); + fprintf(stdout, "%d %s\r\n", code, p); + free(enc); + free(p); + return 0; +} diff --git a/appl/ftp/ftpd/krb4.h b/appl/ftp/ftpd/krb4.h new file mode 100644 index 000000000..3aaea8c65 --- /dev/null +++ b/appl/ftp/ftpd/krb4.h @@ -0,0 +1,17 @@ +#ifndef _KRB4_H_ +#define _KRB4_H_ + +#include + +extern int krb4_auth(char * auth); +extern int krb4_adat(char * auth); +extern int krb4_pbsz(int size); +extern int krb4_prot(char * type); +extern int krb4_ccc(void ); +extern int krb4_mic(char * msg); +extern int krb4_conf(char * msg); +extern int krb4_enc(char * msg); +extern int krb4_userok(char *name); +extern int krb4_vprintf(const char *fmt, va_list ap); + +#endif /* _KRB4_H_ */ diff --git a/appl/ftp/ftpd/logwtmp.c b/appl/ftp/ftpd/logwtmp.c index 5ecc443ac..b0a35d5bc 100644 --- a/appl/ftp/ftpd/logwtmp.c +++ b/appl/ftp/ftpd/logwtmp.c @@ -42,6 +42,10 @@ static char rcsid[] = "$NetBSD: logwtmp.c,v 1.4 1995/04/11 02:44:58 cgd Exp $"; #endif #endif /* not lint */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -61,13 +65,12 @@ static int fd = -1; * after login, but before logout). */ void -logwtmp(line, name, host) - char *line, *name, *host; +logwtmp(char *line, char *name, char *host) { struct utmp ut; struct stat buf; - if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) + if (fd < 0 && (fd = open(WTMP_PATH, O_WRONLY|O_APPEND, 0)) < 0) return; if (fstat(fd, &buf) == 0) { (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); diff --git a/appl/ftp/ftpd/pathnames.h b/appl/ftp/ftpd/pathnames.h index fd262360b..f1884e47a 100644 --- a/appl/ftp/ftpd/pathnames.h +++ b/appl/ftp/ftpd/pathnames.h @@ -35,7 +35,21 @@ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93 */ +#ifdef HAVE_PATH_H #include +#endif + +#ifndef _PATH_DEVNULL +#define _PATH_DEVNULL "/dev/null" +#endif + +#ifndef _PATH_NOLOGIN +#define _PATH_NOLOGIN "/etc/nologin" +#endif + +#ifndef _PATH_BSHELL +#define _PATH_BSHELL "/bin/sh" +#endif #define _PATH_FTPUSERS "/etc/ftpusers" #define _PATH_FTPCHROOT "/etc/ftpchroot" diff --git a/appl/ftp/ftpd/popen.c b/appl/ftp/ftpd/popen.c index 08ae3d13f..d9302774c 100644 --- a/appl/ftp/ftpd/popen.c +++ b/appl/ftp/ftpd/popen.c @@ -45,6 +45,10 @@ static char rcsid[] = "$NetBSD: popen.c,v 1.5 1995/04/11 02:45:00 cgd Exp $"; #endif #endif /* not lint */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include @@ -67,15 +71,14 @@ static int *pids; static int fds; FILE * -ftpd_popen(program, type) - char *program, *type; +ftpd_popen(char *program, char *type) { char *cp; FILE *iop; int argc, gargc, pdes[2], pid; char **pop, *argv[100], *gargv[1000]; - if (*type != 'r' && *type != 'w' || type[1]) + if (strcmp(type, "r") && strcmp(type, "w")) return (NULL); if (!pids) { @@ -151,10 +154,9 @@ pfree: for (argc = 1; gargv[argc] != NULL; argc++) } int -ftpd_pclose(iop) - FILE *iop; +ftpd_pclose(FILE *iop) { - int fdes, omask, status; + int fdes, status; pid_t pid; sigset_t sigset, osigset; diff --git a/lib/roken/glob.c b/lib/roken/glob.c new file mode 100644 index 000000000..f8b0e63c1 --- /dev/null +++ b/lib/roken/glob.c @@ -0,0 +1,853 @@ +/* $NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; +#else +static char rcsid[] = "$NetBSD: glob.c,v 1.5 1995/02/27 04:13:35 cgd Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_NOMAGIC: + * Same as GLOB_NOCHECK, but it will only append pattern if it did + * not contain any magic characters. [Used in csh style globbing] + * GLOB_ALTDIRFUNC: + * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glob.h" + +#define DOLLAR '$' +#define DOT '.' +#define EOS '\0' +#define LBRACKET '[' +#define NOT '!' +#define QUESTION '?' +#define QUOTE '\\' +#define RANGE '-' +#define RBRACKET ']' +#define SEP '/' +#define STAR '*' +#define TILDE '~' +#define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG + +#define M_QUOTE 0x8000 +#define M_PROTECT 0x4000 +#define M_MASK 0xffff +#define M_ASCII 0x00ff + +typedef u_short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define M_ALL META('*') +#define M_END META(']') +#define M_NOT META('!') +#define M_ONE META('?') +#define M_RNG META('-') +#define M_SET META('[') +#define ismeta(c) (((c)&M_QUOTE) != 0) + + +static int compare __P((const void *, const void *)); +static void g_Ctoc __P((const Char *, char *)); +static int g_lstat __P((Char *, struct stat *, glob_t *)); +static DIR *g_opendir __P((Char *, glob_t *)); +static Char *g_strchr __P((Char *, int)); +#ifdef notdef +static Char *g_strcat __P((Char *, const Char *)); +#endif +static int g_stat __P((Char *, struct stat *, glob_t *)); +static int glob0 __P((const Char *, glob_t *)); +static int glob1 __P((Char *, glob_t *)); +static int glob2 __P((Char *, Char *, Char *, glob_t *)); +static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *)); +static int globextend __P((const Char *, glob_t *)); +static const Char * globtilde __P((const Char *, Char *, glob_t *)); +static int globexp1 __P((const Char *, glob_t *)); +static int globexp2 __P((const Char *, const Char *, glob_t *, int *)); +static int match __P((Char *, Char *, Char *)); +#ifdef DEBUG +static void qprintf __P((const char *, Char *)); +#endif + +int +glob(pattern, flags, errfunc, pglob) + const char *pattern; + int flags, (*errfunc) __P((const char *, int)); + glob_t *pglob; +{ + const u_char *patnext; + int c; + Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; + + patnext = (u_char *) pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN; + if (flags & GLOB_QUOTE) { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } + else + *bufnext++ = c; + } + else + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int globexp1(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int globexp2(ptr, pattern, pglob, rv) + const Char *ptr, *pattern; + glob_t *pglob; + int *rv; +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[MAXPATHLEN + 1]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(pattern, patbuf, pglob) + const Char *pattern; + Char *patbuf; + glob_t *pglob; +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH; + *h++ = *p++) + continue; + + *h = EOS; + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ + if ((h = getenv("HOME")) == NULL) { + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + } + else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; *h; *b++ = *h++) + continue; + + /* Append the rest of the pattern */ + while ((*b++ = *p++) != EOS) + continue; + + return patbuf; +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[MAXPATHLEN+1]; + + qpatnext = globtilde(pattern, patbuf, pglob); + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob)) != 0) + return(err); + + /* + * If there was no match we are going to append the pattern + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the pattern did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if (pglob->gl_pathc == oldpathc && + ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR)))) + return(globextend(pattern, pglob)); + else if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return(0); +} + +static int +compare(p, q) + const void *p, *q; +{ + return(strcmp(*(char **)p, *(char **)q)); +} + +static int +glob1(pattern, pglob) + Char *pattern; + glob_t *pglob; +{ + Char pathbuf[MAXPATHLEN+1]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return(0); + return(glob2(pathbuf, pathbuf, pattern, pglob)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(pathbuf, pathend, pattern, pglob) + Char *pathbuf, *pathend, *pattern; + glob_t *pglob; +{ + struct stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return(0); + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) + || (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb, pglob) == 0) && + S_ISDIR(sb.st_mode)))) { + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return(globextend(pathbuf, pglob)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && *p != SEP) { + if (ismeta(*p)) + anymeta = 1; + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (*pattern == SEP) + *pathend++ = *pattern++; + } else /* Need expansion, recurse. */ + return(glob3(pathbuf, pathend, pattern, p, pglob)); + } + /* NOTREACHED */ +} + +static int +glob3(pathbuf, pathend, pattern, restpattern, pglob) + Char *pathbuf, *pathend, *pattern, *restpattern; + glob_t *pglob; +{ + register struct dirent *dp; + DIR *dirp; + int err; + char buf[MAXPATHLEN]; + + /* + * The readdirfunc declaration can't be prototyped, because it is + * assigned, below, to two functions which are prototyped in glob.h + * and dirent.h as taking pointers to differently typed opaque + * structures. + */ + struct dirent *(*readdirfunc)(); + + *pathend = EOS; + errno = 0; + + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + /* TODO: don't call for ENOENT or ENOTDIR? */ + if (pglob->gl_errfunc) { + g_Ctoc(pathbuf, buf); + if (pglob->gl_errfunc(buf, errno) || + pglob->gl_flags & GLOB_ERR) + return (GLOB_ABEND); + } + return(0); + } + + err = 0; + + /* Search directory for matching names. */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = pglob->gl_readdir; + else + readdirfunc = readdir; + while ((dp = (*readdirfunc)(dirp))) { + register u_char *sc; + register Char *dc; + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == DOT && *pattern != DOT) + continue; + for (sc = (u_char *) dp->d_name, dc = pathend; + (*dc++ = *sc++) != EOS;) + continue; + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + err = glob2(pathbuf, --dc, restpattern, pglob); + if (err) + break; + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + return(err); +} + + +/* + * Extend the gl_pathv member of a glob_t structure to accomodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(path, pglob) + const Char *path; + glob_t *pglob; +{ + register char **pathv; + register int i; + u_int newsize; + char *copy; + const Char *p; + + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + pathv = pglob->gl_pathv ? + realloc((char *)pglob->gl_pathv, newsize) : + malloc(newsize); + if (pathv == NULL) + return(GLOB_NOSPACE); + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + for (p = path; *p++;) + continue; + if ((copy = malloc(p - path)) != NULL) { + g_Ctoc(path, copy); + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return(copy == NULL ? GLOB_NOSPACE : 0); +} + + +/* + * pattern matching function for filenames. Each occurrence of the * + * pattern causes a recursion level. + */ +static int +match(name, pat, patend) + register Char *name, *pat, *patend; +{ + int ok, negate_range; + Char c, k; + + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return(1); + do + if (match(name, pat, patend)) + return(1); + while (*name++ != EOS); + return(0); + case M_ONE: + if (*name++ == EOS) + return(0); + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + return(0); + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (c <= k && k <= pat[1]) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + return(0); + break; + default: + if (*name++ != c) + return(0); + break; + } + } + return(*name == EOS); +} + +/* Free allocated data belonging to a glob_t structure. */ +void +globfree(pglob) + glob_t *pglob; +{ + register int i; + register char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + } +} + +static DIR * +g_opendir(str, pglob) + register Char *str; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (!*str) + strcpy(buf, "."); + else + g_Ctoc(str, buf); + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_opendir)(buf)); + + return(opendir(buf)); +} + +static int +g_lstat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return(lstat(buf, sb)); +} + +static int +g_stat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_stat)(buf, sb)); + return(stat(buf, sb)); +} + +static Char * +g_strchr(str, ch) + Char *str; + int ch; +{ + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +#ifdef notdef +static Char * +g_strcat(dst, src) + Char *dst; + const Char* src; +{ + Char *sdst = dst; + + while (*dst++) + continue; + --dst; + while((*dst++ = *src++) != EOS) + continue; + + return (sdst); +} +#endif + +static void +g_Ctoc(str, buf) + register const Char *str; + char *buf; +{ + register char *dc; + + for (dc = buf; (*dc++ = *str++) != EOS;) + continue; +} + +#ifdef DEBUG +static void +qprintf(str, s) + const char *str; + register Char *s; +{ + register Char *p; + + (void)printf("%s:\n", str); + for (p = s; *p; p++) + (void)printf("%c", CHAR(*p)); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", ismeta(*p) ? '_' : ' '); + (void)printf("\n"); +} +#endif diff --git a/lib/roken/glob.h b/lib/roken/glob.h new file mode 100644 index 000000000..5d85f17b0 --- /dev/null +++ b/lib/roken/glob.h @@ -0,0 +1,90 @@ +/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +#ifndef __P +#define __P(protos) protos +#endif + +struct stat; +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc) __P((const char *, int)); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir) __P((void *)); + struct dirent *(*gl_readdir) __P((void *)); + void *(*gl_opendir) __P((const char *)); + int (*gl_lstat) __P((const char *, struct stat *)); + int (*gl_stat) __P((const char *, struct stat *)); +} glob_t; + +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ + +#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ +#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ +#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ +#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ + +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABEND (-2) /* Unignored error. */ + +int glob __P((const char *, int, int (*)(const char *, int), glob_t *)); +void globfree __P((glob_t *)); + +#endif /* !_GLOB_H_ */ diff --git a/lib/roken/glob.hin b/lib/roken/glob.hin new file mode 100644 index 000000000..5d85f17b0 --- /dev/null +++ b/lib/roken/glob.hin @@ -0,0 +1,90 @@ +/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +#ifndef __P +#define __P(protos) protos +#endif + +struct stat; +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc) __P((const char *, int)); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir) __P((void *)); + struct dirent *(*gl_readdir) __P((void *)); + void *(*gl_opendir) __P((const char *)); + int (*gl_lstat) __P((const char *, struct stat *)); + int (*gl_stat) __P((const char *, struct stat *)); +} glob_t; + +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ + +#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ +#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ +#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ +#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ + +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABEND (-2) /* Unignored error. */ + +int glob __P((const char *, int, int (*)(const char *, int), glob_t *)); +void globfree __P((glob_t *)); + +#endif /* !_GLOB_H_ */