Version 0.0
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@387 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
38
appl/ftp/Makefile.in
Normal file
38
appl/ftp/Makefile.in
Normal file
@@ -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
|
13
appl/ftp/acconfig.h
Normal file
13
appl/ftp/acconfig.h
Normal file
@@ -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"
|
||||
|
41
appl/ftp/common/Makefile.in
Normal file
41
appl/ftp/common/Makefile.in
Normal file
@@ -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
|
107
appl/ftp/common/base64.c
Normal file
107
appl/ftp/common/base64.c
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
7
appl/ftp/common/base64.h
Normal file
7
appl/ftp/common/base64.h
Normal file
@@ -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
|
16
appl/ftp/common/common.h
Normal file
16
appl/ftp/common/common.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __MISSING_H__
|
||||
#define __MISSING_H__
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "vsyslog.h"
|
||||
|
||||
#include "err.h"
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#endif /* __MISSING_H__ */
|
16
appl/ftp/common/err.c
Normal file
16
appl/ftp/common/err.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#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);
|
||||
}
|
21
appl/ftp/common/err.h
Normal file
21
appl/ftp/common/err.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef __ERR_H__
|
||||
#define __ERR_H__
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
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__ */
|
16
appl/ftp/common/errx.c
Normal file
16
appl/ftp/common/errx.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#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);
|
||||
}
|
853
appl/ftp/common/glob.c
Normal file
853
appl/ftp/common/glob.c
Normal file
@@ -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 <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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
|
90
appl/ftp/common/glob.h
Normal file
90
appl/ftp/common/glob.h
Normal file
@@ -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_ */
|
26
appl/ftp/common/hstrerror.c
Normal file
26
appl/ftp/common/hstrerror.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_HSTRERROR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
|
||||
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
|
||||
|
23
appl/ftp/common/inet_aton.c
Normal file
23
appl/ftp/common/inet_aton.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
|
||||
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;
|
||||
}
|
13
appl/ftp/common/krb_get_err_text.c
Normal file
13
appl/ftp/common/krb_get_err_text.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <krb.h>
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
const char *
|
||||
krb_get_err_text(int n)
|
||||
{
|
||||
return krb_err_txt[n];
|
||||
}
|
33
appl/ftp/common/memmove.c
Normal file
33
appl/ftp/common/memmove.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* memmove for systems that doesn't have it
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
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;
|
||||
}
|
18
appl/ftp/common/snprintf.c
Normal file
18
appl/ftp/common/snprintf.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
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;
|
||||
}
|
22
appl/ftp/common/verr.c
Normal file
22
appl/ftp/common/verr.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#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);
|
||||
}
|
17
appl/ftp/common/verrx.c
Normal file
17
appl/ftp/common/verrx.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#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);
|
||||
}
|
17
appl/ftp/common/vsyslog.c
Normal file
17
appl/ftp/common/vsyslog.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VSYSLOG
|
||||
|
||||
#include <syslog.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void vsyslog(int pri, const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[10240];
|
||||
vsprintf(buf, fmt, ap);
|
||||
syslog(pri, buf);
|
||||
}
|
||||
|
||||
#endif
|
8
appl/ftp/common/vsyslog.h
Normal file
8
appl/ftp/common/vsyslog.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __VSYSLOG_H__
|
||||
#define __VSYSLOG_H__
|
||||
|
||||
#ifndef HAVE_VSYSLOG
|
||||
void vsyslog(int pri, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
#endif /* __VSYSLOG_H__ */
|
21
appl/ftp/common/vwarn.c
Normal file
21
appl/ftp/common/vwarn.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#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));
|
||||
}
|
16
appl/ftp/common/vwarnx.c
Normal file
16
appl/ftp/common/vwarnx.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#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");
|
||||
}
|
16
appl/ftp/common/warn.c
Normal file
16
appl/ftp/common/warn.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
void
|
||||
warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarn(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
16
appl/ftp/common/warnx.c
Normal file
16
appl/ftp/common/warnx.c
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "err.h"
|
||||
|
||||
RCSID("$Id$");
|
||||
|
||||
void
|
||||
warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
30
appl/ftp/configure.in
Normal file
30
appl/ftp/configure.in
Normal file
@@ -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)
|
@@ -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 \#*
|
41
appl/ftp/ftp/Makefile.in
Normal file
41
appl/ftp/ftp/Makefile.in
Normal file
@@ -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
|
@@ -38,7 +38,9 @@
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#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 **));
|
||||
|
@@ -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 <des.h>
|
||||
#include <krb.h>
|
||||
|
||||
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;
|
||||
|
41
appl/ftp/ftp/ftp_locl.h
Normal file
41
appl/ftp/ftp/ftp_locl.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef __FTP_LOCL_H__
|
||||
#define __FTP_LOCL_H__
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include <arpa/ftp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/telnet.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <glob.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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__ */
|
@@ -35,7 +35,13 @@
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#ifdef HAVE_PATHS_H
|
||||
#include <paths.h>
|
||||
#endif
|
||||
|
||||
#undef _PATH_TMP
|
||||
#define _PATH_TMP "/tmp/ftpXXXXXX"
|
||||
|
||||
#ifndef _PATH_BSHELL
|
||||
#define _PATH_BSHELL "/bin/sh"
|
||||
#endif
|
||||
|
@@ -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 <bsd.prog.mk>
|
45
appl/ftp/ftpd/Makefile.in
Normal file
45
appl/ftp/ftpd/Makefile.in
Normal file
@@ -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
|
131
appl/ftp/ftpd/auth.c
Normal file
131
appl/ftp/ftpd/auth.c
Normal file
@@ -0,0 +1,131 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
49
appl/ftp/ftpd/auth.h
Normal file
49
appl/ftp/ftpd/auth.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef _AUTH_H_
|
||||
#define _AUTH_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
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_ */
|
115
appl/ftp/ftpd/commands.c
Normal file
115
appl/ftp/ftpd/commands.c
Normal file
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
<username> ::= <string>
|
||||
<password> ::= <string>
|
||||
<account-information> ::= <string>
|
||||
<string> ::= <char> | <char><string>
|
||||
<char> ::= any of the 128 ASCII characters except <CR> and
|
||||
<LF>
|
||||
<marker> ::= <pr-string>
|
||||
<pr-string> ::= <pr-char> | <pr-char><pr-string>
|
||||
<pr-char> ::= printable characters, any
|
||||
ASCII code 33 through 126
|
||||
<byte-size> ::= <number>
|
||||
<host-port> ::= <host-number>,<port-number>
|
||||
<host-number> ::= <number>,<number>,<number>,<number>
|
||||
<port-number> ::= <number>,<number>
|
||||
<number> ::= any decimal integer 1 through 255
|
||||
<form-code> ::= N | T | C
|
||||
<type-code> ::= A [<sp> <form-code>]
|
||||
| E [<sp> <form-code>]
|
||||
| I
|
||||
| L <sp> <byte-size>
|
||||
<structure-code> ::= F | R | P
|
||||
<mode-code> ::= S | B | C
|
||||
<pathname> ::= <string>
|
||||
<decimal-integer> ::= any decimal integer
|
||||
|
||||
|
||||
|
||||
|
@@ -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 <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
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_ */
|
||||
|
@@ -71,23 +71,7 @@ static char rcsid[] = "$NetBSD: ftpcmd.y,v 1.6 1995/06/03 22:46:45 mycroft Exp $
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <s> 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, "<sp> file-name" },
|
||||
{ "SIZE", SIZE, OSTR, 1, "<sp> path-name" },
|
||||
{ "MDTM", MDTM, OSTR, 1, "<sp> path-name" },
|
||||
|
||||
/* extensions from draft-ietf-cat-ftpsec-08 */
|
||||
{ "AUTH", AUTH, STR1, 1, "<sp> auth-type" },
|
||||
{ "ADAT", ADAT, STR1, 1, "<sp> auth-data" },
|
||||
{ "PBSZ", PBSZ, ARGS, 1, "<sp> buffer-size" },
|
||||
{ "PROT", PROT, ARGS, 1, "<sp> prot-level" },
|
||||
{ "CCC", CCC, ARGS, 1, "" },
|
||||
{ "MIC", MIC, STR1, 1, "<sp> integrity command" },
|
||||
{ "CONF", CONF, STR1, 1, "<sp> confidentiality command" },
|
||||
{ "ENC", ENC, STR1, 1, "<sp> 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]);
|
||||
|
@@ -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 <config.h>
|
||||
#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 <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glob.h>
|
||||
@@ -82,14 +85,19 @@ static char rcsid[] = "$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $"
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
#include "extern.h"
|
||||
#include "common.h"
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#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;
|
||||
|
195
appl/ftp/ftpd/krb4.c
Normal file
195
appl/ftp/ftpd/krb4.c
Normal file
@@ -0,0 +1,195 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <krb.h>
|
||||
|
||||
#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;
|
||||
}
|
17
appl/ftp/ftpd/krb4.h
Normal file
17
appl/ftp/ftpd/krb4.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef _KRB4_H_
|
||||
#define _KRB4_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
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_ */
|
@@ -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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -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));
|
||||
|
@@ -35,7 +35,21 @@
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
#ifdef HAVE_PATH_H
|
||||
#include <paths.h>
|
||||
#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"
|
||||
|
@@ -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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
853
lib/roken/glob.c
Normal file
853
lib/roken/glob.c
Normal file
@@ -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 <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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
|
90
lib/roken/glob.h
Normal file
90
lib/roken/glob.h
Normal file
@@ -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_ */
|
90
lib/roken/glob.hin
Normal file
90
lib/roken/glob.hin
Normal file
@@ -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_ */
|
Reference in New Issue
Block a user