summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/appl/ftp/ftpd
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/appl/ftp/ftpd')
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/Makefile.am56
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/Makefile.in768
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/extern.h160
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ftpcmd.y1455
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ftpd.8473
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ftpd.c2249
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ftpd_locl.h170
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ftpusers.538
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/gss_userok.c69
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/kauth.c365
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/logwtmp.c137
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/ls.c588
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/pathnames.h58
-rw-r--r--crypto/heimdal/appl/ftp/ftpd/popen.c224
14 files changed, 6810 insertions, 0 deletions
diff --git a/crypto/heimdal/appl/ftp/ftpd/Makefile.am b/crypto/heimdal/appl/ftp/ftpd/Makefile.am
new file mode 100644
index 0000000..92d8e7c
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/Makefile.am
@@ -0,0 +1,56 @@
+# $Id: Makefile.am,v 1.21 2000/01/06 15:10:57 assar Exp $
+
+include $(top_srcdir)/Makefile.am.common
+
+INCLUDES += -I$(srcdir)/../common $(INCLUDE_krb4) -DFTP_SERVER
+
+libexec_PROGRAMS = ftpd
+
+CHECK_LOCAL =
+
+if KRB4
+krb4_sources = krb4.c kauth.c
+endif
+if KRB5
+krb5_sources = gssapi.c gss_userok.c
+endif
+
+ftpd_SOURCES = \
+ extern.h \
+ ftpcmd.y \
+ ftpd.c \
+ ftpd_locl.h \
+ logwtmp.c \
+ ls.c \
+ pathnames.h \
+ popen.c \
+ security.c \
+ $(krb4_sources) \
+ $(krb5_sources)
+
+EXTRA_ftpd_SOURCES = krb4.c kauth.c gssapi.c gss_userok.c
+
+$(ftpd_OBJECTS): security.h
+
+security.c:
+ @test -f security.c || $(LN_S) $(srcdir)/../ftp/security.c .
+security.h:
+ @test -f security.h || $(LN_S) $(srcdir)/../ftp/security.h .
+krb4.c:
+ @test -f krb4.c || $(LN_S) $(srcdir)/../ftp/krb4.c .
+gssapi.c:
+ @test -f gssapi.c || $(LN_S) $(srcdir)/../ftp/gssapi.c .
+
+CLEANFILES = security.c security.h krb4.c gssapi.c ftpcmd.c
+
+man_MANS = ftpd.8 ftpusers.5
+
+LDADD = ../common/libcommon.a \
+ $(LIB_kafs) \
+ $(LIB_gssapi) \
+ $(LIB_krb5) \
+ $(LIB_krb4) \
+ $(LIB_otp) \
+ $(top_builddir)/lib/des/libdes.la \
+ $(LIB_roken) \
+ $(DBLIB)
diff --git a/crypto/heimdal/appl/ftp/ftpd/Makefile.in b/crypto/heimdal/appl/ftp/ftpd/Makefile.in
new file mode 100644
index 0000000..1cd211b
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/Makefile.in
@@ -0,0 +1,768 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# $Id: Makefile.am,v 1.21 2000/01/06 15:10:57 assar Exp $
+
+
+# $Id: Makefile.am.common,v 1.3 1999/04/01 14:58:43 joda Exp $
+
+
+# $Id: Makefile.am.common,v 1.13 1999/11/01 03:19:58 assar Exp $
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AFS_EXTRA_LD = @AFS_EXTRA_LD@
+AIX_EXTRA_KAFS = @AIX_EXTRA_KAFS@
+AWK = @AWK@
+CANONICAL_HOST = @CANONICAL_HOST@
+CATMAN = @CATMAN@
+CATMANEXT = @CATMANEXT@
+CC = @CC@
+DBLIB = @DBLIB@
+EXEEXT = @EXEEXT@
+EXTRA_LIB45 = @EXTRA_LIB45@
+GROFF = @GROFF@
+INCLUDE_ = @INCLUDE_@
+LD = @LD@
+LEX = @LEX@
+LIBOBJS = @LIBOBJS@
+LIBTOOL = @LIBTOOL@
+LIB_ = @LIB_@
+LIB_AUTH_SUBDIRS = @LIB_AUTH_SUBDIRS@
+LIB_kdb = @LIB_kdb@
+LIB_otp = @LIB_otp@
+LIB_roken = @LIB_roken@
+LIB_security = @LIB_security@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MAKE_X_PROGS_BIN_PROGS = @MAKE_X_PROGS_BIN_PROGS@
+MAKE_X_PROGS_BIN_SCRPTS = @MAKE_X_PROGS_BIN_SCRPTS@
+MAKE_X_PROGS_LIBEXEC_PROGS = @MAKE_X_PROGS_LIBEXEC_PROGS@
+NEED_WRITEAUTH_FALSE = @NEED_WRITEAUTH_FALSE@
+NEED_WRITEAUTH_TRUE = @NEED_WRITEAUTH_TRUE@
+NM = @NM@
+NROFF = @NROFF@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+VOID_RETSIGTYPE = @VOID_RETSIGTYPE@
+WFLAGS = @WFLAGS@
+WFLAGS_NOIMPLICITINT = @WFLAGS_NOIMPLICITINT@
+WFLAGS_NOUNUSED = @WFLAGS_NOUNUSED@
+YACC = @YACC@
+
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+SUFFIXES = .et .h .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 .x
+
+INCLUDES = -I$(top_builddir)/include -I$(srcdir)/../common $(INCLUDE_krb4) -DFTP_SERVER
+
+AM_CFLAGS = $(WFLAGS)
+
+COMPILE_ET = $(top_builddir)/lib/com_err/compile_et
+
+buildinclude = $(top_builddir)/include
+
+LIB_XauReadAuth = @LIB_XauReadAuth@
+LIB_crypt = @LIB_crypt@
+LIB_dbm_firstkey = @LIB_dbm_firstkey@
+LIB_dbopen = @LIB_dbopen@
+LIB_dlopen = @LIB_dlopen@
+LIB_dn_expand = @LIB_dn_expand@
+LIB_el_init = @LIB_el_init@
+LIB_getattr = @LIB_getattr@
+LIB_gethostbyname = @LIB_gethostbyname@
+LIB_getpwent_r = @LIB_getpwent_r@
+LIB_getpwnam_r = @LIB_getpwnam_r@
+LIB_getsockopt = @LIB_getsockopt@
+LIB_logout = @LIB_logout@
+LIB_logwtmp = @LIB_logwtmp@
+LIB_odm_initialize = @LIB_odm_initialize@
+LIB_readline = @LIB_readline@
+LIB_res_search = @LIB_res_search@
+LIB_setpcred = @LIB_setpcred@
+LIB_setsockopt = @LIB_setsockopt@
+LIB_socket = @LIB_socket@
+LIB_syslog = @LIB_syslog@
+LIB_tgetent = @LIB_tgetent@
+
+HESIODLIB = @HESIODLIB@
+HESIODINCLUDE = @HESIODINCLUDE@
+INCLUDE_hesiod = @INCLUDE_hesiod@
+LIB_hesiod = @LIB_hesiod@
+
+INCLUDE_krb4 = @INCLUDE_krb4@
+LIB_krb4 = @LIB_krb4@
+
+INCLUDE_readline = @INCLUDE_readline@
+
+LEXLIB = @LEXLIB@
+
+cat1dir = $(mandir)/cat1
+cat3dir = $(mandir)/cat3
+cat5dir = $(mandir)/cat5
+cat8dir = $(mandir)/cat8
+
+MANRX = \(.*\)\.\([0-9]\)
+CATSUFFIX = @CATSUFFIX@
+
+NROFF_MAN = groff -mandoc -Tascii
+
+@KRB4_TRUE@LIB_kafs = $(top_builddir)/lib/kafs/libkafs.la $(AIX_EXTRA_KAFS)
+
+@KRB5_TRUE@LIB_krb5 = $(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/asn1/libasn1.la
+@KRB5_TRUE@LIB_gssapi = $(top_builddir)/lib/gssapi/libgssapi.la
+
+CHECK_LOCAL =
+
+libexec_PROGRAMS = ftpd
+
+@KRB4_TRUE@krb4_sources = krb4.c kauth.c
+@KRB5_TRUE@krb5_sources = gssapi.c gss_userok.c
+
+ftpd_SOURCES = extern.h ftpcmd.y ftpd.c ftpd_locl.h logwtmp.c ls.c pathnames.h popen.c security.c $(krb4_sources) $(krb5_sources)
+
+
+EXTRA_ftpd_SOURCES = krb4.c kauth.c gssapi.c gss_userok.c
+
+CLEANFILES = security.c security.h krb4.c gssapi.c ftpcmd.c
+
+man_MANS = ftpd.8 ftpusers.5
+
+LDADD = ../common/libcommon.a $(LIB_kafs) $(LIB_gssapi) $(LIB_krb5) $(LIB_krb4) $(LIB_otp) $(top_builddir)/lib/des/libdes.la $(LIB_roken) $(DBLIB)
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../../include/config.h
+CONFIG_CLEAN_FILES =
+libexec_PROGRAMS = ftpd$(EXEEXT)
+PROGRAMS = $(libexec_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../../../include
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+@KRB4_TRUE@@KRB5_FALSE@ftpd_OBJECTS = ftpcmd.$(OBJEXT) ftpd.$(OBJEXT) \
+@KRB4_TRUE@@KRB5_FALSE@logwtmp.$(OBJEXT) ls.$(OBJEXT) popen.$(OBJEXT) \
+@KRB4_TRUE@@KRB5_FALSE@security.$(OBJEXT) krb4.$(OBJEXT) \
+@KRB4_TRUE@@KRB5_FALSE@kauth.$(OBJEXT)
+@KRB4_FALSE@@KRB5_TRUE@ftpd_OBJECTS = ftpcmd.$(OBJEXT) ftpd.$(OBJEXT) \
+@KRB4_FALSE@@KRB5_TRUE@logwtmp.$(OBJEXT) ls.$(OBJEXT) popen.$(OBJEXT) \
+@KRB4_FALSE@@KRB5_TRUE@security.$(OBJEXT) gssapi.$(OBJEXT) \
+@KRB4_FALSE@@KRB5_TRUE@gss_userok.$(OBJEXT)
+@KRB4_FALSE@@KRB5_FALSE@ftpd_OBJECTS = ftpcmd.$(OBJEXT) ftpd.$(OBJEXT) \
+@KRB4_FALSE@@KRB5_FALSE@logwtmp.$(OBJEXT) ls.$(OBJEXT) popen.$(OBJEXT) \
+@KRB4_FALSE@@KRB5_FALSE@security.$(OBJEXT)
+@KRB4_TRUE@@KRB5_TRUE@ftpd_OBJECTS = ftpcmd.$(OBJEXT) ftpd.$(OBJEXT) \
+@KRB4_TRUE@@KRB5_TRUE@logwtmp.$(OBJEXT) ls.$(OBJEXT) popen.$(OBJEXT) \
+@KRB4_TRUE@@KRB5_TRUE@security.$(OBJEXT) krb4.$(OBJEXT) kauth.$(OBJEXT) \
+@KRB4_TRUE@@KRB5_TRUE@gssapi.$(OBJEXT) gss_userok.$(OBJEXT)
+ftpd_LDADD = $(LDADD)
+@KRB4_TRUE@@KRB5_FALSE@ftpd_DEPENDENCIES = ../common/libcommon.a \
+@KRB4_TRUE@@KRB5_FALSE@$(top_builddir)/lib/kafs/libkafs.la \
+@KRB4_TRUE@@KRB5_FALSE@$(top_builddir)/lib/des/libdes.la
+@KRB4_FALSE@@KRB5_TRUE@ftpd_DEPENDENCIES = ../common/libcommon.a \
+@KRB4_FALSE@@KRB5_TRUE@$(top_builddir)/lib/gssapi/libgssapi.la \
+@KRB4_FALSE@@KRB5_TRUE@$(top_builddir)/lib/krb5/libkrb5.la \
+@KRB4_FALSE@@KRB5_TRUE@$(top_builddir)/lib/asn1/libasn1.la \
+@KRB4_FALSE@@KRB5_TRUE@$(top_builddir)/lib/des/libdes.la
+@KRB4_FALSE@@KRB5_FALSE@ftpd_DEPENDENCIES = ../common/libcommon.a \
+@KRB4_FALSE@@KRB5_FALSE@$(top_builddir)/lib/des/libdes.la
+@KRB4_TRUE@@KRB5_TRUE@ftpd_DEPENDENCIES = ../common/libcommon.a \
+@KRB4_TRUE@@KRB5_TRUE@$(top_builddir)/lib/kafs/libkafs.la \
+@KRB4_TRUE@@KRB5_TRUE@$(top_builddir)/lib/gssapi/libgssapi.la \
+@KRB4_TRUE@@KRB5_TRUE@$(top_builddir)/lib/krb5/libkrb5.la \
+@KRB4_TRUE@@KRB5_TRUE@$(top_builddir)/lib/asn1/libasn1.la \
+@KRB4_TRUE@@KRB5_TRUE@$(top_builddir)/lib/des/libdes.la
+ftpd_LDFLAGS =
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+DIST_COMMON = Makefile.am Makefile.in ftpcmd.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(ftpd_SOURCES) $(EXTRA_ftpd_SOURCES)
+OBJECTS = $(ftpd_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .1 .3 .5 .8 .S .c .cat1 .cat3 .cat5 .cat8 .et .h .lo .o .obj .s .x .y
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/Makefile.am.common $(top_srcdir)/cf/Makefile.am.common
+ cd $(top_srcdir) && $(AUTOMAKE) --foreign appl/ftp/ftpd/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-libexecPROGRAMS:
+
+clean-libexecPROGRAMS:
+ -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS)
+
+distclean-libexecPROGRAMS:
+
+maintainer-clean-libexecPROGRAMS:
+
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(libexecdir)
+ @list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.s.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+ $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+ftpd$(EXEEXT): $(ftpd_OBJECTS) $(ftpd_DEPENDENCIES)
+ @rm -f ftpd$(EXEEXT)
+ $(LINK) $(ftpd_LDFLAGS) $(ftpd_OBJECTS) $(ftpd_LDADD) $(LIBS)
+.y.c:
+ $(YACC) $(AM_YFLAGS) $(YFLAGS) $< && mv y.tab.c $*.c
+ if test -f y.tab.h; then \
+ if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
+ else :; fi
+ftpcmd.h: ftpcmd.c
+
+
+install-man5:
+ $(mkinstalldirs) $(DESTDIR)$(man5dir)
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+uninstall-man5:
+ @list='$(man5_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.5*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man5dir)/$$inst; \
+ done
+
+install-man8:
+ $(mkinstalldirs) $(DESTDIR)$(man8dir)
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+ done
+
+uninstall-man8:
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man8dir)/$$inst; \
+ done
+install-man: $(MANS)
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-man5 install-man8
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-man5 uninstall-man8
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = appl/ftp/ftpd
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-libexecPROGRAMS
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+install-exec: install-exec-am
+
+install-data-am: install-man install-data-local
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-libexecPROGRAMS uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS) $(MANS) all-local
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(libexecdir) $(DESTDIR)$(mandir)/man5 \
+ $(DESTDIR)$(mandir)/man8
+
+
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ -test -z "ftpcmdhftpcmdc" || rm -f ftpcmdh ftpcmdc
+mostlyclean-am: mostlyclean-libexecPROGRAMS mostlyclean-compile \
+ mostlyclean-libtool mostlyclean-tags \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-libexecPROGRAMS clean-compile clean-libtool clean-tags \
+ clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-libexecPROGRAMS distclean-compile \
+ distclean-libtool distclean-tags distclean-generic \
+ clean-am
+ -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-libexecPROGRAMS \
+ maintainer-clean-compile maintainer-clean-libtool \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-libexecPROGRAMS distclean-libexecPROGRAMS \
+clean-libexecPROGRAMS maintainer-clean-libexecPROGRAMS \
+uninstall-libexecPROGRAMS install-libexecPROGRAMS mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile \
+mostlyclean-libtool distclean-libtool clean-libtool \
+maintainer-clean-libtool install-man5 uninstall-man5 install-man8 \
+uninstall-man8 install-man uninstall-man tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check-local check check-am installcheck-am installcheck \
+install-exec-am install-exec install-data-local install-data-am \
+install-data install-am install uninstall-am uninstall all-local \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+install-suid-programs:
+ @foo='$(bin_SUIDS)'; \
+ for file in $$foo; do \
+ x=$(DESTDIR)$(bindir)/$$file; \
+ if chown 0:0 $$x && chmod u+s $$x; then :; else \
+ chmod 0 $$x; fi; done
+
+install-exec-hook: install-suid-programs
+
+install-build-headers:: $(include_HEADERS) $(build_HEADERZ)
+ @foo='$(include_HEADERS) $(build_HEADERZ)'; \
+ for f in $$foo; do \
+ f=`basename $$f`; \
+ if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \
+ else file="$$f"; fi; \
+ if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \
+ : ; else \
+ echo " cp $$file $(buildinclude)/$$f"; \
+ cp $$file $(buildinclude)/$$f; \
+ fi ; \
+ done
+
+all-local: install-build-headers
+#NROFF_MAN = nroff -man
+.1.cat1:
+ $(NROFF_MAN) $< > $@
+.3.cat3:
+ $(NROFF_MAN) $< > $@
+.5.cat5:
+ $(NROFF_MAN) $< > $@
+.8.cat8:
+ $(NROFF_MAN) $< > $@
+
+dist-cat1-mans:
+ @foo='$(man1_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.1) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat1/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-cat3-mans:
+ @foo='$(man3_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.3) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat3/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-cat5-mans:
+ @foo='$(man5_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.5) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat5/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-cat8-mans:
+ @foo='$(man8_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.8) foo="$$foo $$i";; \
+ esac; done ;\
+ for i in $$foo; do \
+ x=`echo $$i | sed 's/\.[^.]*$$/.cat8/'`; \
+ echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \
+ $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \
+ done
+
+dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-cat8-mans
+
+install-cat1-mans:
+ @ext=1;\
+ foo='$(man1_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.1) foo="$$foo $$i";; \
+ esac; done; \
+ if test "$$foo"; then \
+ $(mkinstalldirs) $(DESTDIR)$(cat1dir); \
+ for x in $$foo; do \
+ f=`echo $$x | sed 's/\.[^.]*$$/.cat1/'`; \
+ if test -f "$(srcdir)/$$f"; then \
+ b=`echo $$x | sed 's!$(MANRX)!\1!'`; \
+ echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat1dir)/$$b.$(CATSUFFIX)";\
+ $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat1dir)/$$b.$(CATSUFFIX);\
+ fi; \
+ done ;\
+ fi
+
+install-cat3-mans:
+ @ext=3;\
+ foo='$(man3_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.3) foo="$$foo $$i";; \
+ esac; done; \
+ if test "$$foo"; then \
+ $(mkinstalldirs) $(DESTDIR)$(cat3dir); \
+ for x in $$foo; do \
+ f=`echo $$x | sed 's/\.[^.]*$$/.cat3/'`; \
+ if test -f "$(srcdir)/$$f"; then \
+ b=`echo $$x | sed 's!$(MANRX)!\1!'`; \
+ echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat3dir)/$$b.$(CATSUFFIX)";\
+ $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat3dir)/$$b.$(CATSUFFIX);\
+ fi; \
+ done ;\
+ fi
+
+install-cat5-mans:
+ @ext=5;\
+ foo='$(man5_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.5) foo="$$foo $$i";; \
+ esac; done; \
+ if test "$$foo"; then \
+ $(mkinstalldirs) $(DESTDIR)$(cat5dir); \
+ for x in $$foo; do \
+ f=`echo $$x | sed 's/\.[^.]*$$/.cat5/'`; \
+ if test -f "$(srcdir)/$$f"; then \
+ b=`echo $$x | sed 's!$(MANRX)!\1!'`; \
+ echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat5dir)/$$b.$(CATSUFFIX)";\
+ $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat5dir)/$$b.$(CATSUFFIX);\
+ fi; \
+ done ;\
+ fi
+
+install-cat8-mans:
+ @ext=8;\
+ foo='$(man8_MANS)'; \
+ bar='$(man_MANS)'; \
+ for i in $$bar; do \
+ case $$i in \
+ *.8) foo="$$foo $$i";; \
+ esac; done; \
+ if test "$$foo"; then \
+ $(mkinstalldirs) $(DESTDIR)$(cat8dir); \
+ for x in $$foo; do \
+ f=`echo $$x | sed 's/\.[^.]*$$/.cat8/'`; \
+ if test -f "$(srcdir)/$$f"; then \
+ b=`echo $$x | sed 's!$(MANRX)!\1!'`; \
+ echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat8dir)/$$b.$(CATSUFFIX)";\
+ $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat8dir)/$$b.$(CATSUFFIX);\
+ fi; \
+ done ;\
+ fi
+
+install-cat-mans: install-cat1-mans install-cat3-mans install-cat5-mans install-cat8-mans
+
+install-data-local: install-cat-mans
+
+.et.h:
+ $(COMPILE_ET) $<
+.et.c:
+ $(COMPILE_ET) $<
+
+.x.c:
+ @cmp -s $< $@ 2> /dev/null || cp $< $@
+
+check-local::
+ @foo='$(CHECK_LOCAL)'; \
+ if test "$$foo"; then \
+ failed=0; all=0; \
+ for i in $$foo; do \
+ all=`expr $$all + 1`; \
+ if ./$$i --version > /dev/null 2>&1; then \
+ echo "PASS: $$i"; \
+ else \
+ echo "FAIL: $$i"; \
+ failed=`expr $$failed + 1`; \
+ fi; \
+ done; \
+ if test "$$failed" -eq 0; then \
+ banner="All $$all tests passed"; \
+ else \
+ banner="$$failed of $$all tests failed"; \
+ fi; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"; \
+ test "$$failed" -eq 0; \
+ fi
+
+$(ftpd_OBJECTS): security.h
+
+security.c:
+ @test -f security.c || $(LN_S) $(srcdir)/../ftp/security.c .
+security.h:
+ @test -f security.h || $(LN_S) $(srcdir)/../ftp/security.h .
+krb4.c:
+ @test -f krb4.c || $(LN_S) $(srcdir)/../ftp/krb4.c .
+gssapi.c:
+ @test -f gssapi.c || $(LN_S) $(srcdir)/../ftp/gssapi.c .
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/crypto/heimdal/appl/ftp/ftpd/extern.h b/crypto/heimdal/appl/ftp/ftpd/extern.h
new file mode 100644
index 0000000..2e1e0d0
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/extern.h
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/4/94
+ */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef NBBY
+#define NBBY CHAR_BIT
+#endif
+
+void abor(void);
+void blkfree(char **);
+char **copyblk(char **);
+void cwd(char *);
+void do_delete(char *);
+void dologout(int);
+void eprt(char *);
+void epsv(char *);
+void fatal(char *);
+int filename_check(char *);
+int ftpd_pclose(FILE *);
+FILE *ftpd_popen(char *, char *, int, int);
+char *ftpd_getline(char *, int);
+void ftpd_logwtmp(char *, char *, char *);
+void lreply(int, const char *, ...)
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+;
+void makedir(char *);
+void nack(char *);
+void nreply(const char *, ...)
+#ifdef __GNUC__
+__attribute__ ((format (printf, 1, 2)))
+#endif
+;
+void pass(char *);
+void pasv(void);
+void perror_reply(int, const char *);
+void pwd(void);
+void removedir(char *);
+void renamecmd(char *, char *);
+char *renamefrom(char *);
+void reply(int, const char *, ...)
+#ifdef __GNUC__
+__attribute__ ((format (printf, 2, 3)))
+#endif
+;
+void retrieve(const char *, char *);
+void send_file_list(char *);
+void setproctitle(const char *, ...)
+#ifdef __GNUC__
+__attribute__ ((format (printf, 1, 2)))
+#endif
+;
+void statcmd(void);
+void statfilecmd(char *);
+void do_store(char *, char *, int);
+void upper(char *);
+void user(char *);
+void yyerror(char *);
+
+void list_file(char*);
+
+void kauth(char *, char*);
+void klist(void);
+void cond_kdestroy(void);
+void kdestroy(void);
+void krbtkfile(const char *tkfile);
+void afslog(const char *cell);
+void afsunlog(void);
+
+int find(char *);
+
+void builtin_ls(FILE*, const char*);
+
+int do_login(int code, char *passwd);
+int klogin(char *name, char *password);
+
+const char *ftp_rooted(const char *path);
+
+extern struct sockaddr *ctrl_addr, *his_addr;
+extern char hostname[];
+
+extern struct sockaddr *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 ftpd_timeout;
+extern int maxtimeout;
+extern int pdata;
+extern char hostname[], remotehost[];
+extern char proctitle[];
+extern int usedefault;
+extern int transflag;
+extern char tmpline[];
+
+#endif /* _EXTERN_H_ */
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpcmd.y b/crypto/heimdal/appl/ftp/ftpd/ftpcmd.y
new file mode 100644
index 0000000..07ff9a5
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/ftpcmd.y
@@ -0,0 +1,1455 @@
+/* $NetBSD: ftpcmd.y,v 1.6 1995/06/03 22:46:45 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1985, 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. 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.
+ *
+ * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94
+ */
+
+/*
+ * Grammar for FTP commands.
+ * See RFC 959.
+ */
+
+%{
+
+#include "ftpd_locl.h"
+RCSID("$Id: ftpcmd.y,v 1.56 1999/10/26 11:56:23 assar Exp $");
+
+off_t restart_point;
+
+static int cmd_type;
+static int cmd_form;
+static int cmd_bytesz;
+char cbuf[2048];
+char *fromname;
+
+struct tab {
+ char *name;
+ short token;
+ short state;
+ short implemented; /* 1 if command is implemented */
+ char *help;
+};
+
+extern struct tab cmdtab[];
+extern struct tab sitetab[];
+
+static char *copy (char *);
+static void help (struct tab *, char *);
+static struct tab *
+ lookup (struct tab *, char *);
+static void sizecmd (char *);
+static RETSIGTYPE toolong (int);
+static int yylex (void);
+
+/* This is for bison */
+
+#if !defined(alloca) && !defined(HAVE_ALLOCA)
+#define alloca(x) malloc(x)
+#endif
+
+%}
+
+%union {
+ int i;
+ char *s;
+}
+
+%token
+ A B C E F I
+ L N P R S T
+
+ SP CRLF COMMA
+
+ USER PASS ACCT REIN QUIT PORT
+ PASV TYPE STRU MODE RETR STOR
+ APPE MLFL MAIL MSND MSOM MSAM
+ MRSQ MRCP ALLO REST RNFR RNTO
+ ABOR DELE CWD LIST NLST SITE
+ sTAT HELP NOOP MKD RMD PWD
+ CDUP STOU SMNT SYST SIZE MDTM
+ EPRT EPSV
+
+ UMASK IDLE CHMOD
+
+ AUTH ADAT PROT PBSZ CCC MIC
+ CONF ENC
+
+ KAUTH KLIST KDESTROY KRBTKFILE AFSLOG
+ LOCATE URL
+
+ FEAT OPTS
+
+ LEXERR
+
+%token <s> STRING
+%token <i> NUMBER
+
+%type <i> check_login check_login_no_guest check_secure octal_number byte_size
+%type <i> struct_code mode_code type_code form_code
+%type <s> pathstring pathname password username
+
+%start cmd_list
+
+%%
+
+cmd_list
+ : /* empty */
+ | cmd_list cmd
+ {
+ fromname = (char *) 0;
+ restart_point = (off_t) 0;
+ }
+ | cmd_list rcmd
+ ;
+
+cmd
+ : USER SP username CRLF
+ {
+ user($3);
+ free($3);
+ }
+ | PASS SP password CRLF
+ {
+ pass($3);
+ memset ($3, 0, strlen($3));
+ free($3);
+ }
+ | PORT SP host_port CRLF
+ {
+ usedefault = 0;
+ if (pdata >= 0) {
+ close(pdata);
+ pdata = -1;
+ }
+ reply(200, "PORT command successful.");
+ }
+ | EPRT SP STRING CRLF
+ {
+ eprt ($3);
+ free ($3);
+ }
+ | PASV CRLF
+ {
+ pasv ();
+ }
+ | EPSV CRLF
+ {
+ epsv (NULL);
+ }
+ | EPSV SP STRING CRLF
+ {
+ epsv ($3);
+ free ($3);
+ }
+ | TYPE SP type_code CRLF
+ {
+ switch (cmd_type) {
+
+ case TYPE_A:
+ if (cmd_form == FORM_N) {
+ reply(200, "Type set to A.");
+ type = cmd_type;
+ form = cmd_form;
+ } else
+ reply(504, "Form must be N.");
+ break;
+
+ case TYPE_E:
+ reply(504, "Type E not implemented.");
+ break;
+
+ case TYPE_I:
+ reply(200, "Type set to I.");
+ type = cmd_type;
+ break;
+
+ case TYPE_L:
+#if NBBY == 8
+ if (cmd_bytesz == 8) {
+ reply(200,
+ "Type set to L (byte size 8).");
+ type = cmd_type;
+ } else
+ reply(504, "Byte size must be 8.");
+#else /* NBBY == 8 */
+ UNIMPLEMENTED for NBBY != 8
+#endif /* NBBY == 8 */
+ }
+ }
+ | STRU SP struct_code CRLF
+ {
+ switch ($3) {
+
+ case STRU_F:
+ reply(200, "STRU F ok.");
+ break;
+
+ default:
+ reply(504, "Unimplemented STRU type.");
+ }
+ }
+ | MODE SP mode_code CRLF
+ {
+ switch ($3) {
+
+ case MODE_S:
+ reply(200, "MODE S ok.");
+ break;
+
+ default:
+ reply(502, "Unimplemented MODE type.");
+ }
+ }
+ | ALLO SP NUMBER CRLF
+ {
+ reply(202, "ALLO command ignored.");
+ }
+ | ALLO SP NUMBER SP R SP NUMBER CRLF
+ {
+ reply(202, "ALLO command ignored.");
+ }
+ | RETR SP pathname CRLF check_login
+ {
+ char *name = $3;
+
+ if ($5 && name != NULL)
+ retrieve(0, name);
+ if (name != NULL)
+ free(name);
+ }
+ | STOR SP pathname CRLF check_login
+ {
+ char *name = $3;
+
+ if ($5 && name != NULL)
+ do_store(name, "w", 0);
+ if (name != NULL)
+ free(name);
+ }
+ | APPE SP pathname CRLF check_login
+ {
+ char *name = $3;
+
+ if ($5 && name != NULL)
+ do_store(name, "a", 0);
+ if (name != NULL)
+ free(name);
+ }
+ | NLST CRLF check_login
+ {
+ if ($3)
+ send_file_list(".");
+ }
+ | NLST SP STRING CRLF check_login
+ {
+ char *name = $3;
+
+ if ($5 && name != NULL)
+ send_file_list(name);
+ if (name != NULL)
+ free(name);
+ }
+ | LIST CRLF check_login
+ {
+ if($3)
+ list_file(".");
+ }
+ | LIST SP pathname CRLF check_login
+ {
+ if($5)
+ list_file($3);
+ free($3);
+ }
+ | sTAT SP pathname CRLF check_login
+ {
+ if ($5 && $3 != NULL)
+ statfilecmd($3);
+ if ($3 != NULL)
+ free($3);
+ }
+ | sTAT CRLF
+ {
+ if(oobflag){
+ if (file_size != (off_t) -1)
+ reply(213, "Status: %lu of %lu bytes transferred",
+ (unsigned long)byte_count,
+ (unsigned long)file_size);
+ else
+ reply(213, "Status: %lu bytes transferred",
+ (unsigned long)byte_count);
+ }else
+ statcmd();
+ }
+ | DELE SP pathname CRLF check_login_no_guest
+ {
+ if ($5 && $3 != NULL)
+ do_delete($3);
+ if ($3 != NULL)
+ free($3);
+ }
+ | RNTO SP pathname CRLF check_login_no_guest
+ {
+ if($5){
+ if (fromname) {
+ renamecmd(fromname, $3);
+ free(fromname);
+ fromname = (char *) 0;
+ } else {
+ reply(503, "Bad sequence of commands.");
+ }
+ }
+ if ($3 != NULL)
+ free($3);
+ }
+ | ABOR CRLF
+ {
+ 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 CRLF check_login
+ {
+ if ($3)
+ cwd(pw->pw_dir);
+ }
+ | CWD SP pathname CRLF check_login
+ {
+ if ($5 && $3 != NULL)
+ cwd($3);
+ if ($3 != NULL)
+ free($3);
+ }
+ | HELP CRLF
+ {
+ help(cmdtab, (char *) 0);
+ }
+ | HELP SP STRING CRLF
+ {
+ char *cp = $3;
+
+ if (strncasecmp(cp, "SITE", 4) == 0) {
+ cp = $3 + 4;
+ if (*cp == ' ')
+ cp++;
+ if (*cp)
+ help(sitetab, cp);
+ else
+ help(sitetab, (char *) 0);
+ } else
+ help(cmdtab, $3);
+ }
+ | NOOP CRLF
+ {
+ reply(200, "NOOP command successful.");
+ }
+ | MKD SP pathname CRLF check_login
+ {
+ if ($5 && $3 != NULL)
+ makedir($3);
+ if ($3 != NULL)
+ free($3);
+ }
+ | RMD SP pathname CRLF check_login_no_guest
+ {
+ if ($5 && $3 != NULL)
+ removedir($3);
+ if ($3 != NULL)
+ free($3);
+ }
+ | PWD CRLF check_login
+ {
+ if ($3)
+ pwd();
+ }
+ | CDUP CRLF check_login
+ {
+ if ($3)
+ cwd("..");
+ }
+ | FEAT CRLF
+ {
+ lreply(211, "Supported features:");
+ lreply(0, " MDTM");
+ lreply(0, " REST STREAM");
+ lreply(0, " SIZE");
+ reply(211, "End");
+ }
+ | OPTS SP STRING CRLF
+ {
+ free ($3);
+ reply(501, "Bad options");
+ }
+
+ | SITE SP HELP CRLF
+ {
+ help(sitetab, (char *) 0);
+ }
+ | SITE SP HELP SP STRING CRLF
+ {
+ help(sitetab, $5);
+ }
+ | SITE SP UMASK CRLF check_login
+ {
+ if ($5) {
+ int oldmask = umask(0);
+ umask(oldmask);
+ reply(200, "Current UMASK is %03o", oldmask);
+ }
+ }
+ | SITE SP UMASK SP octal_number CRLF check_login_no_guest
+ {
+ if ($7) {
+ if (($5 == -1) || ($5 > 0777)) {
+ reply(501, "Bad UMASK value");
+ } else {
+ int oldmask = umask($5);
+ reply(200,
+ "UMASK set to %03o (was %03o)",
+ $5, oldmask);
+ }
+ }
+ }
+ | SITE SP CHMOD SP octal_number SP pathname CRLF check_login_no_guest
+ {
+ if ($9 && $7 != NULL) {
+ if ($5 > 0777)
+ reply(501,
+ "CHMOD: Mode value must be between 0 and 0777");
+ else if (chmod($7, $5) < 0)
+ perror_reply(550, $7);
+ else
+ reply(200, "CHMOD command successful.");
+ }
+ if ($7 != NULL)
+ free($7);
+ }
+ | SITE SP IDLE CRLF
+ {
+ reply(200,
+ "Current IDLE time limit is %d seconds; max %d",
+ ftpd_timeout, maxtimeout);
+ }
+ | SITE SP IDLE SP NUMBER CRLF
+ {
+ if ($5 < 30 || $5 > maxtimeout) {
+ reply(501,
+ "Maximum IDLE time must be between 30 and %d seconds",
+ maxtimeout);
+ } else {
+ ftpd_timeout = $5;
+ alarm((unsigned) ftpd_timeout);
+ reply(200,
+ "Maximum IDLE time set to %d seconds",
+ ftpd_timeout);
+ }
+ }
+
+ | SITE SP KAUTH SP STRING CRLF check_login
+ {
+#ifdef KRB4
+ char *p;
+
+ if(guest)
+ reply(500, "Can't be done as guest.");
+ else{
+ if($7 && $5 != NULL){
+ p = strpbrk($5, " \t");
+ if(p){
+ *p++ = 0;
+ kauth($5, p + strspn(p, " \t"));
+ }else
+ kauth($5, NULL);
+ }
+ }
+ if($5 != NULL)
+ free($5);
+#else
+ reply(500, "Command not implemented.");
+#endif
+ }
+ | SITE SP KLIST CRLF check_login
+ {
+#ifdef KRB4
+ if($5)
+ klist();
+#else
+ reply(500, "Command not implemented.");
+#endif
+ }
+ | SITE SP KDESTROY CRLF check_login
+ {
+#ifdef KRB4
+ if($5)
+ kdestroy();
+#else
+ reply(500, "Command not implemented.");
+#endif
+ }
+ | SITE SP KRBTKFILE SP STRING CRLF check_login
+ {
+#ifdef KRB4
+ if(guest)
+ reply(500, "Can't be done as guest.");
+ else if($7 && $5)
+ krbtkfile($5);
+ if($5)
+ free($5);
+#else
+ reply(500, "Command not implemented.");
+#endif
+ }
+ | SITE SP AFSLOG CRLF check_login
+ {
+#ifdef KRB4
+ if(guest)
+ reply(500, "Can't be done as guest.");
+ else if($5)
+ afslog(NULL);
+#else
+ reply(500, "Command not implemented.");
+#endif
+ }
+ | SITE SP AFSLOG SP STRING CRLF check_login
+ {
+#ifdef KRB4
+ if(guest)
+ reply(500, "Can't be done as guest.");
+ else if($7)
+ afslog($5);
+ if($5)
+ free($5);
+#else
+ reply(500, "Command not implemented.");
+#endif
+ }
+ | SITE SP LOCATE SP STRING CRLF check_login
+ {
+ if($7 && $5 != NULL)
+ find($5);
+ if($5 != NULL)
+ free($5);
+ }
+ | SITE SP URL CRLF
+ {
+ reply(200, "http://www.pdc.kth.se/kth-krb/");
+ }
+ | STOU SP pathname CRLF check_login
+ {
+ if ($5 && $3 != NULL)
+ do_store($3, "w", 1);
+ if ($3 != NULL)
+ free($3);
+ }
+ | SYST CRLF
+ {
+#if defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY)
+ reply(215, "UNIX Type: L%d", NBBY);
+#else
+ reply(215, "UNKNOWN Type: L%d", NBBY);
+#endif
+ }
+
+ /*
+ * SIZE is not in RFC959, but Postel has blessed it and
+ * it will be in the updated RFC.
+ *
+ * Return size of file in a format suitable for
+ * using with RESTART (we just count bytes).
+ */
+ | SIZE SP pathname CRLF check_login
+ {
+ if ($5 && $3 != NULL)
+ sizecmd($3);
+ if ($3 != NULL)
+ free($3);
+ }
+
+ /*
+ * MDTM is not in RFC959, but Postel has blessed it and
+ * it will be in the updated RFC.
+ *
+ * Return modification time of file as an ISO 3307
+ * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx
+ * where xxx is the fractional second (of any precision,
+ * not necessarily 3 digits)
+ */
+ | MDTM SP pathname CRLF check_login
+ {
+ if ($5 && $3 != NULL) {
+ struct stat stbuf;
+ if (stat($3, &stbuf) < 0)
+ reply(550, "%s: %s",
+ $3, strerror(errno));
+ else if (!S_ISREG(stbuf.st_mode)) {
+ reply(550,
+ "%s: not a plain file.", $3);
+ } else {
+ struct tm *t;
+ t = gmtime(&stbuf.st_mtime);
+ reply(213,
+ "%04d%02d%02d%02d%02d%02d",
+ t->tm_year + 1900,
+ t->tm_mon + 1,
+ t->tm_mday,
+ t->tm_hour,
+ t->tm_min,
+ t->tm_sec);
+ }
+ }
+ if ($3 != NULL)
+ free($3);
+ }
+ | QUIT CRLF
+ {
+ reply(221, "Goodbye.");
+ dologout(0);
+ }
+ | error CRLF
+ {
+ yyerrok;
+ }
+ ;
+rcmd
+ : RNFR SP pathname CRLF check_login_no_guest
+ {
+ restart_point = (off_t) 0;
+ if ($5 && $3) {
+ fromname = renamefrom($3);
+ if (fromname == (char *) 0 && $3) {
+ free($3);
+ }
+ }
+ }
+ | REST SP byte_size CRLF
+ {
+ fromname = (char *) 0;
+ restart_point = $3; /* XXX $3 is only "int" */
+ reply(350, "Restarting at %ld. %s",
+ (long)restart_point,
+ "Send STORE or RETRIEVE to initiate transfer.");
+ }
+ | 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
+ {
+ mec($3, prot_safe);
+ free($3);
+ }
+ | CONF SP STRING CRLF
+ {
+ mec($3, prot_confidential);
+ free($3);
+ }
+ | ENC SP STRING CRLF
+ {
+ mec($3, prot_private);
+ free($3);
+ }
+ ;
+
+username
+ : STRING
+ ;
+
+password
+ : /* empty */
+ {
+ $$ = (char *)calloc(1, sizeof(char));
+ }
+ | STRING
+ ;
+
+byte_size
+ : NUMBER
+ ;
+
+host_port
+ : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA
+ NUMBER COMMA NUMBER
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)data_dest;
+
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons($9 * 256 + $11);
+ sin->sin_addr.s_addr =
+ htonl(($1 << 24) | ($3 << 16) | ($5 << 8) | $7);
+ }
+ ;
+
+form_code
+ : N
+ {
+ $$ = FORM_N;
+ }
+ | T
+ {
+ $$ = FORM_T;
+ }
+ | C
+ {
+ $$ = FORM_C;
+ }
+ ;
+
+type_code
+ : A
+ {
+ cmd_type = TYPE_A;
+ cmd_form = FORM_N;
+ }
+ | A SP form_code
+ {
+ cmd_type = TYPE_A;
+ cmd_form = $3;
+ }
+ | E
+ {
+ cmd_type = TYPE_E;
+ cmd_form = FORM_N;
+ }
+ | E SP form_code
+ {
+ cmd_type = TYPE_E;
+ cmd_form = $3;
+ }
+ | I
+ {
+ cmd_type = TYPE_I;
+ }
+ | L
+ {
+ cmd_type = TYPE_L;
+ cmd_bytesz = NBBY;
+ }
+ | L SP byte_size
+ {
+ cmd_type = TYPE_L;
+ cmd_bytesz = $3;
+ }
+ /* this is for a bug in the BBN ftp */
+ | L byte_size
+ {
+ cmd_type = TYPE_L;
+ cmd_bytesz = $2;
+ }
+ ;
+
+struct_code
+ : F
+ {
+ $$ = STRU_F;
+ }
+ | R
+ {
+ $$ = STRU_R;
+ }
+ | P
+ {
+ $$ = STRU_P;
+ }
+ ;
+
+mode_code
+ : S
+ {
+ $$ = MODE_S;
+ }
+ | B
+ {
+ $$ = MODE_B;
+ }
+ | C
+ {
+ $$ = MODE_C;
+ }
+ ;
+
+pathname
+ : pathstring
+ {
+ /*
+ * Problem: this production is used for all pathname
+ * processing, but only gives a 550 error reply.
+ * This is a valid reply in some cases but not in others.
+ */
+ if (logged_in && $1 && *$1 == '~') {
+ glob_t gl;
+ int flags =
+ GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
+
+ memset(&gl, 0, sizeof(gl));
+ if (glob($1, flags, NULL, &gl) ||
+ gl.gl_pathc == 0) {
+ reply(550, "not found");
+ $$ = NULL;
+ } else {
+ $$ = strdup(gl.gl_pathv[0]);
+ }
+ globfree(&gl);
+ free($1);
+ } else
+ $$ = $1;
+ }
+ ;
+
+pathstring
+ : STRING
+ ;
+
+octal_number
+ : NUMBER
+ {
+ int ret, dec, multby, digit;
+
+ /*
+ * Convert a number that was read as decimal number
+ * to what it would be if it had been read as octal.
+ */
+ dec = $1;
+ multby = 1;
+ ret = 0;
+ while (dec) {
+ digit = dec%10;
+ if (digit > 7) {
+ ret = -1;
+ break;
+ }
+ ret += digit * multby;
+ multby *= 8;
+ dec /= 10;
+ }
+ $$ = ret;
+ }
+ ;
+
+
+check_login_no_guest : check_login
+ {
+ $$ = $1 && !guest;
+ if($1 && !$$)
+ reply(550, "Permission denied");
+ }
+ ;
+
+check_login : check_secure
+ {
+ if($1) {
+ if(($$ = logged_in) == 0)
+ reply(530, "Please login with USER and PASS.");
+ } else
+ $$ = 0;
+ }
+ ;
+
+check_secure : /* empty */
+ {
+ $$ = 1;
+ if(sec_complete && !secure_command()) {
+ $$ = 0;
+ reply(533, "Command protection level denied "
+ "for paranoid reasons.");
+ }
+ }
+ ;
+
+%%
+
+extern jmp_buf errcatch;
+
+#define CMD 0 /* beginning of command */
+#define ARGS 1 /* expect miscellaneous arguments */
+#define STR1 2 /* expect SP followed by STRING */
+#define STR2 3 /* expect STRING */
+#define OSTR 4 /* optional SP then STRING */
+#define ZSTR1 5 /* SP then optional STRING */
+#define ZSTR2 6 /* optional STRING after SP */
+#define SITECMD 7 /* SITE command */
+#define NSTR 8 /* Number followed by a string */
+
+struct tab cmdtab[] = { /* In order defined in RFC 765 */
+ { "USER", USER, STR1, 1, "<sp> username" },
+ { "PASS", PASS, ZSTR1, 1, "<sp> password" },
+ { "ACCT", ACCT, STR1, 0, "(specify account)" },
+ { "SMNT", SMNT, ARGS, 0, "(structure mount)" },
+ { "REIN", REIN, ARGS, 0, "(reinitialize server state)" },
+ { "QUIT", QUIT, ARGS, 1, "(terminate service)", },
+ { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" },
+ { "EPRT", EPRT, STR1, 1, "<sp> string" },
+ { "PASV", PASV, ARGS, 1, "(set server in passive mode)" },
+ { "EPSV", EPSV, OSTR, 1, "[<sp> foo]" },
+ { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" },
+ { "STRU", STRU, ARGS, 1, "(specify file structure)" },
+ { "MODE", MODE, ARGS, 1, "(specify transfer mode)" },
+ { "RETR", RETR, STR1, 1, "<sp> file-name" },
+ { "STOR", STOR, STR1, 1, "<sp> file-name" },
+ { "APPE", APPE, STR1, 1, "<sp> file-name" },
+ { "MLFL", MLFL, OSTR, 0, "(mail file)" },
+ { "MAIL", MAIL, OSTR, 0, "(mail to user)" },
+ { "MSND", MSND, OSTR, 0, "(mail send to terminal)" },
+ { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" },
+ { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" },
+ { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" },
+ { "MRCP", MRCP, STR1, 0, "(mail recipient)" },
+ { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" },
+ { "REST", REST, ARGS, 1, "<sp> offset (restart command)" },
+ { "RNFR", RNFR, STR1, 1, "<sp> file-name" },
+ { "RNTO", RNTO, STR1, 1, "<sp> file-name" },
+ { "ABOR", ABOR, ARGS, 1, "(abort operation)" },
+ { "DELE", DELE, STR1, 1, "<sp> file-name" },
+ { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
+ { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" },
+ { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" },
+ { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" },
+ { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" },
+ { "SYST", SYST, ARGS, 1, "(get type of operating system)" },
+ { "STAT", sTAT, OSTR, 1, "[ <sp> path-name ]" },
+ { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
+ { "NOOP", NOOP, ARGS, 1, "" },
+ { "MKD", MKD, STR1, 1, "<sp> path-name" },
+ { "XMKD", MKD, STR1, 1, "<sp> path-name" },
+ { "RMD", RMD, STR1, 1, "<sp> path-name" },
+ { "XRMD", RMD, STR1, 1, "<sp> path-name" },
+ { "PWD", PWD, ARGS, 1, "(return current directory)" },
+ { "XPWD", PWD, ARGS, 1, "(return current directory)" },
+ { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" },
+ { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" },
+ { "STOU", STOU, STR1, 1, "<sp> file-name" },
+ { "SIZE", SIZE, OSTR, 1, "<sp> path-name" },
+ { "MDTM", MDTM, OSTR, 1, "<sp> path-name" },
+
+ /* extensions from RFC2228 */
+ { "AUTH", AUTH, STR1, 1, "<sp> auth-type" },
+ { "ADAT", ADAT, STR1, 1, "<sp> auth-data" },
+ { "PBSZ", PBSZ, ARGS, 1, "<sp> buffer-size" },
+ { "PROT", PROT, STR1, 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" },
+
+ /* RFC2389 */
+ { "FEAT", FEAT, ARGS, 1, "" },
+ { "OPTS", OPTS, ARGS, 1, "<sp> command [<sp> options]" },
+
+ { NULL, 0, 0, 0, 0 }
+};
+
+struct tab sitetab[] = {
+ { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" },
+ { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" },
+ { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" },
+ { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" },
+
+ { "KAUTH", KAUTH, STR1, 1, "<sp> principal [ <sp> ticket ]" },
+ { "KLIST", KLIST, ARGS, 1, "(show ticket file)" },
+ { "KDESTROY", KDESTROY, ARGS, 1, "(destroy tickets)" },
+ { "KRBTKFILE", KRBTKFILE, STR1, 1, "<sp> ticket-file" },
+ { "AFSLOG", AFSLOG, OSTR, 1, "[<sp> cell]" },
+
+ { "LOCATE", LOCATE, STR1, 1, "<sp> globexpr" },
+ { "FIND", LOCATE, STR1, 1, "<sp> globexpr" },
+
+ { "URL", URL, ARGS, 1, "?" },
+
+ { NULL, 0, 0, 0, 0 }
+};
+
+static struct tab *
+lookup(struct tab *p, char *cmd)
+{
+
+ for (; p->name != NULL; p++)
+ if (strcmp(cmd, p->name) == 0)
+ return (p);
+ return (0);
+}
+
+/*
+ * ftpd_getline - a hacked up version of fgets to ignore TELNET escape codes.
+ */
+char *
+ftpd_getline(char *s, int n)
+{
+ int c;
+ char *cs;
+
+ cs = s;
+/* tmpline may contain saved command from urgent mode interruption */
+ if(ftp_command){
+ strlcpy(s, ftp_command, n);
+ if (debug)
+ syslog(LOG_DEBUG, "command: %s", s);
+#ifdef XXX
+ fprintf(stderr, "%s\n", s);
+#endif
+ return s;
+ }
+ while ((c = getc(stdin)) != EOF) {
+ c &= 0377;
+ if (c == IAC) {
+ if ((c = getc(stdin)) != EOF) {
+ c &= 0377;
+ switch (c) {
+ case WILL:
+ case WONT:
+ c = getc(stdin);
+ printf("%c%c%c", IAC, DONT, 0377&c);
+ fflush(stdout);
+ continue;
+ case DO:
+ case DONT:
+ c = getc(stdin);
+ printf("%c%c%c", IAC, WONT, 0377&c);
+ fflush(stdout);
+ continue;
+ case IAC:
+ break;
+ default:
+ continue; /* ignore command */
+ }
+ }
+ }
+ *cs++ = c;
+ if (--n <= 0 || c == '\n')
+ break;
+ }
+ if (c == EOF && cs == s)
+ return (NULL);
+ *cs++ = '\0';
+ if (debug) {
+ if (!guest && strncasecmp("pass ", s, 5) == 0) {
+ /* Don't syslog passwords */
+ syslog(LOG_DEBUG, "command: %.5s ???", s);
+ } else {
+ char *cp;
+ int len;
+
+ /* Don't syslog trailing CR-LF */
+ len = strlen(s);
+ cp = s + len - 1;
+ while (cp >= s && (*cp == '\n' || *cp == '\r')) {
+ --cp;
+ --len;
+ }
+ syslog(LOG_DEBUG, "command: %.*s", len, s);
+ }
+ }
+#ifdef XXX
+ fprintf(stderr, "%s\n", s);
+#endif
+ return (s);
+}
+
+static RETSIGTYPE
+toolong(int signo)
+{
+
+ reply(421,
+ "Timeout (%d seconds): closing control connection.",
+ ftpd_timeout);
+ if (logging)
+ syslog(LOG_INFO, "User %s timed out after %d seconds",
+ (pw ? pw -> pw_name : "unknown"), ftpd_timeout);
+ dologout(1);
+ SIGRETURN(0);
+}
+
+static int
+yylex(void)
+{
+ static int cpos, state;
+ char *cp, *cp2;
+ struct tab *p;
+ int n;
+ char c;
+
+ for (;;) {
+ switch (state) {
+
+ case CMD:
+ signal(SIGALRM, toolong);
+ alarm((unsigned) ftpd_timeout);
+ if (ftpd_getline(cbuf, sizeof(cbuf)-1) == NULL) {
+ reply(221, "You could at least say goodbye.");
+ dologout(0);
+ }
+ alarm(0);
+#ifdef HAVE_SETPROCTITLE
+ if (strncasecmp(cbuf, "PASS", 4) != NULL)
+ setproctitle("%s: %s", proctitle, cbuf);
+#endif /* HAVE_SETPROCTITLE */
+ if ((cp = strchr(cbuf, '\r'))) {
+ *cp++ = '\n';
+ *cp = '\0';
+ }
+ if ((cp = strpbrk(cbuf, " \n")))
+ cpos = cp - cbuf;
+ if (cpos == 0)
+ cpos = 4;
+ c = cbuf[cpos];
+ cbuf[cpos] = '\0';
+ strupr(cbuf);
+ p = lookup(cmdtab, cbuf);
+ cbuf[cpos] = c;
+ if (p != 0) {
+ if (p->implemented == 0) {
+ nack(p->name);
+ longjmp(errcatch,0);
+ /* NOTREACHED */
+ }
+ state = p->state;
+ yylval.s = p->name;
+ return (p->token);
+ }
+ break;
+
+ case SITECMD:
+ if (cbuf[cpos] == ' ') {
+ cpos++;
+ return (SP);
+ }
+ cp = &cbuf[cpos];
+ if ((cp2 = strpbrk(cp, " \n")))
+ cpos = cp2 - cbuf;
+ c = cbuf[cpos];
+ cbuf[cpos] = '\0';
+ strupr(cp);
+ p = lookup(sitetab, cp);
+ cbuf[cpos] = c;
+ if (p != 0) {
+ if (p->implemented == 0) {
+ state = CMD;
+ nack(p->name);
+ longjmp(errcatch,0);
+ /* NOTREACHED */
+ }
+ state = p->state;
+ yylval.s = p->name;
+ return (p->token);
+ }
+ state = CMD;
+ break;
+
+ case OSTR:
+ if (cbuf[cpos] == '\n') {
+ state = CMD;
+ return (CRLF);
+ }
+ /* FALLTHROUGH */
+
+ case STR1:
+ case ZSTR1:
+ dostr1:
+ if (cbuf[cpos] == ' ') {
+ cpos++;
+ if(state == OSTR)
+ state = STR2;
+ else
+ state++;
+ return (SP);
+ }
+ break;
+
+ case ZSTR2:
+ if (cbuf[cpos] == '\n') {
+ state = CMD;
+ return (CRLF);
+ }
+ /* FALLTHROUGH */
+
+ case STR2:
+ cp = &cbuf[cpos];
+ n = strlen(cp);
+ cpos += n - 1;
+ /*
+ * Make sure the string is nonempty and \n terminated.
+ */
+ if (n > 1 && cbuf[cpos] == '\n') {
+ cbuf[cpos] = '\0';
+ yylval.s = copy(cp);
+ cbuf[cpos] = '\n';
+ state = ARGS;
+ return (STRING);
+ }
+ break;
+
+ case NSTR:
+ if (cbuf[cpos] == ' ') {
+ cpos++;
+ return (SP);
+ }
+ if (isdigit(cbuf[cpos])) {
+ cp = &cbuf[cpos];
+ while (isdigit(cbuf[++cpos]))
+ ;
+ c = cbuf[cpos];
+ cbuf[cpos] = '\0';
+ yylval.i = atoi(cp);
+ cbuf[cpos] = c;
+ state = STR1;
+ return (NUMBER);
+ }
+ state = STR1;
+ goto dostr1;
+
+ case ARGS:
+ if (isdigit(cbuf[cpos])) {
+ cp = &cbuf[cpos];
+ while (isdigit(cbuf[++cpos]))
+ ;
+ c = cbuf[cpos];
+ cbuf[cpos] = '\0';
+ yylval.i = atoi(cp);
+ cbuf[cpos] = c;
+ return (NUMBER);
+ }
+ switch (cbuf[cpos++]) {
+
+ case '\n':
+ state = CMD;
+ return (CRLF);
+
+ case ' ':
+ return (SP);
+
+ case ',':
+ return (COMMA);
+
+ case 'A':
+ case 'a':
+ return (A);
+
+ case 'B':
+ case 'b':
+ return (B);
+
+ case 'C':
+ case 'c':
+ return (C);
+
+ case 'E':
+ case 'e':
+ return (E);
+
+ case 'F':
+ case 'f':
+ return (F);
+
+ case 'I':
+ case 'i':
+ return (I);
+
+ case 'L':
+ case 'l':
+ return (L);
+
+ case 'N':
+ case 'n':
+ return (N);
+
+ case 'P':
+ case 'p':
+ return (P);
+
+ case 'R':
+ case 'r':
+ return (R);
+
+ case 'S':
+ case 's':
+ return (S);
+
+ case 'T':
+ case 't':
+ return (T);
+
+ }
+ break;
+
+ default:
+ fatal("Unknown state in scanner.");
+ }
+ yyerror((char *) 0);
+ state = CMD;
+ longjmp(errcatch,0);
+ }
+}
+
+static char *
+copy(char *s)
+{
+ char *p;
+
+ p = strdup(s);
+ if (p == NULL)
+ fatal("Ran out of memory.");
+ return p;
+}
+
+static void
+help(struct tab *ctab, char *s)
+{
+ struct tab *c;
+ int width, NCMDS;
+ char *type;
+ char buf[1024];
+
+ if (ctab == sitetab)
+ type = "SITE ";
+ else
+ type = "";
+ width = 0, NCMDS = 0;
+ for (c = ctab; c->name != NULL; c++) {
+ int len = strlen(c->name);
+
+ if (len > width)
+ width = len;
+ NCMDS++;
+ }
+ width = (width + 8) &~ 7;
+ if (s == 0) {
+ int i, j, w;
+ int columns, lines;
+
+ lreply(214, "The following %scommands are recognized %s.",
+ type, "(* =>'s unimplemented)");
+ columns = 76 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (NCMDS + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ strlcpy (buf, " ", sizeof(buf));
+ for (j = 0; j < columns; j++) {
+ c = ctab + j * lines + i;
+ snprintf (buf + strlen(buf),
+ sizeof(buf) - strlen(buf),
+ "%s%c",
+ c->name,
+ c->implemented ? ' ' : '*');
+ if (c + lines >= &ctab[NCMDS])
+ break;
+ w = strlen(c->name) + 1;
+ while (w < width) {
+ strlcat (buf,
+ " ",
+ sizeof(buf));
+ w++;
+ }
+ }
+ lreply(214, "%s", buf);
+ }
+ reply(214, "Direct comments to kth-krb-bugs@pdc.kth.se");
+ return;
+ }
+ strupr(s);
+ c = lookup(ctab, s);
+ if (c == (struct tab *)0) {
+ reply(502, "Unknown command %s.", s);
+ return;
+ }
+ if (c->implemented)
+ reply(214, "Syntax: %s%s %s", type, c->name, c->help);
+ else
+ reply(214, "%s%-*s\t%s; unimplemented.", type, width,
+ c->name, c->help);
+}
+
+static void
+sizecmd(char *filename)
+{
+ switch (type) {
+ case TYPE_L:
+ case TYPE_I: {
+ struct stat stbuf;
+ if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
+ reply(550, "%s: not a plain file.", filename);
+ else
+ reply(213, "%lu", (unsigned long)stbuf.st_size);
+ break;
+ }
+ case TYPE_A: {
+ FILE *fin;
+ int c;
+ size_t count;
+ struct stat stbuf;
+ fin = fopen(filename, "r");
+ if (fin == NULL) {
+ perror_reply(550, filename);
+ return;
+ }
+ if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
+ reply(550, "%s: not a plain file.", filename);
+ fclose(fin);
+ return;
+ }
+
+ count = 0;
+ while((c=getc(fin)) != EOF) {
+ if (c == '\n') /* will get expanded to \r\n */
+ count++;
+ count++;
+ }
+ fclose(fin);
+
+ reply(213, "%lu", (unsigned long)count);
+ break;
+ }
+ default:
+ reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
+ }
+}
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpd.8 b/crypto/heimdal/appl/ftp/ftpd/ftpd.8
new file mode 100644
index 0000000..c51de1c
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/ftpd.8
@@ -0,0 +1,473 @@
+.\" $NetBSD: ftpd.8,v 1.7 1995/04/11 02:44:53 cgd Exp $
+.\"
+.\" Copyright (c) 1985, 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1997
+.Dt FTPD 8
+.Os BSD 4.2
+.Sh NAME
+.Nm ftpd
+.Nd
+Internet File Transfer Protocol server
+.Sh SYNOPSIS
+.Nm ftpd
+.Op Fl a Ar authmode
+.Op Fl dilv
+.Op Fl g Ar umask
+.Op Fl p Ar port
+.Op Fl T Ar maxtimeout
+.Op Fl t Ar timeout
+.Op Fl u Ar default umask
+.Sh DESCRIPTION
+.Nm Ftpd
+is the
+Internet File Transfer Protocol
+server process. The server uses the
+.Tn TCP
+protocol
+and listens at the port specified in the
+.Dq ftp
+service specification; see
+.Xr services 5 .
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+Select the level of authentication required. Kerberised login can not
+be turned off. The default is to only allow kerberised login. Other
+possibilities can be turned on by giving a string of comma separated
+flags as argument to
+.Fl a .
+Recognised flags are:
+.Bl -tag -width plain
+.It Ar plain
+Allow logging in with plaintext password. The password can be a(n) OTP
+or an ordinary password.
+.It Ar otp
+Same as
+.Ar plain ,
+but only OTP is allowed.
+.It Ar ftp
+Allow anonymous login.
+.El
+
+The following combination modes exists for backwards compatibility:
+.Bl -tag -width plain
+.It Ar none
+Same as
+.Ar plain,ftp .
+.It Ar safe
+Same as
+.Ar ftp .
+.It Ar user
+Ignored.
+.El
+.It Fl d
+Debugging information is written to the syslog using LOG_FTP.
+.It Fl g
+Anonymous users will get a umask of
+.Ar umask .
+.It Fl i
+Open a socket and wait for a connection. This is mainly used for
+debugging when ftpd isn't started by inetd.
+.It Fl l
+Each successful and failed
+.Xr ftp 1
+session is logged using syslog with a facility of LOG_FTP.
+If this option is specified twice, the retrieve (get), store (put), append,
+delete, make directory, remove directory and rename operations and
+their filename arguments are also logged.
+.It Fl p
+Use
+.Ar port
+(a service name or number) instead of the default
+.Ar ftp/tcp .
+.It Fl T
+A client may also request a different timeout period;
+the maximum period allowed may be set to
+.Ar timeout
+seconds with the
+.Fl T
+option.
+The default limit is 2 hours.
+.It Fl t
+The inactivity timeout period is set to
+.Ar timeout
+seconds (the default is 15 minutes).
+.It Fl u
+Set the initial umask to something else than the default 027.
+.It Fl v
+Verbose mode.
+.El
+.Pp
+The file
+.Pa /etc/nologin
+can be used to disable ftp access.
+If the file exists,
+.Nm
+displays it and exits.
+If the file
+.Pa /etc/ftpwelcome
+exists,
+.Nm
+prints it before issuing the
+.Dq ready
+message.
+If the file
+.Pa /etc/motd
+exists,
+.Nm
+prints it after a successful login.
+.Pp
+The ftp server currently supports the following ftp requests.
+The case of the requests is ignored.
+.Bl -column "Request" -offset indent
+.It Request Ta "Description"
+.It ABOR Ta "abort previous command"
+.It ACCT Ta "specify account (ignored)"
+.It ALLO Ta "allocate storage (vacuously)"
+.It APPE Ta "append to a file"
+.It CDUP Ta "change to parent of current working directory"
+.It CWD Ta "change working directory"
+.It DELE Ta "delete a file"
+.It HELP Ta "give help information"
+.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA"
+.It MKD Ta "make a directory"
+.It MDTM Ta "show last modification time of file"
+.It MODE Ta "specify data transfer" Em mode
+.It NLST Ta "give name list of files in directory"
+.It NOOP Ta "do nothing"
+.It PASS Ta "specify password"
+.It PASV Ta "prepare for server-to-server transfer"
+.It PORT Ta "specify data connection port"
+.It PWD Ta "print the current working directory"
+.It QUIT Ta "terminate session"
+.It REST Ta "restart incomplete transfer"
+.It RETR Ta "retrieve a file"
+.It RMD Ta "remove a directory"
+.It RNFR Ta "specify rename-from file name"
+.It RNTO Ta "specify rename-to file name"
+.It SITE Ta "non-standard commands (see next section)"
+.It SIZE Ta "return size of file"
+.It STAT Ta "return status of server"
+.It STOR Ta "store a file"
+.It STOU Ta "store a file with a unique name"
+.It STRU Ta "specify data transfer" Em structure
+.It SYST Ta "show operating system type of server system"
+.It TYPE Ta "specify data transfer" Em type
+.It USER Ta "specify user name"
+.It XCUP Ta "change to parent of current working directory (deprecated)"
+.It XCWD Ta "change working directory (deprecated)"
+.It XMKD Ta "make a directory (deprecated)"
+.It XPWD Ta "print the current working directory (deprecated)"
+.It XRMD Ta "remove a directory (deprecated)"
+.El
+.Pp
+The following commands are specified by RFC2228.
+.Bl -column Request -offset indent
+.It AUTH Ta "authentication/security mechanism"
+.It ADAT Ta "authentication/security data"
+.It PROT Ta "data channel protection level"
+.It PBSZ Ta "protection buffer size"
+.It MIC Ta "integrity protected command"
+.It CONF Ta "confidentiality protected command"
+.It ENC Ta "privacy protected command"
+.It CCC Ta "clear command channel"
+.El
+.Pp
+The following non-standard or
+.Tn UNIX
+specific commands are supported
+by the
+SITE request.
+.Pp
+.Bl -column Request -offset indent
+.It UMASK Ta change umask, (e.g.
+.Ic "SITE UMASK 002" )
+.It IDLE Ta set idle-timer, (e.g.
+.Ic "SITE IDLE 60" )
+.It CHMOD Ta change mode of a file (e.g.
+.Ic "SITE CHMOD 755 filename" )
+.It FIND Ta quickly find a specific file with GNU
+.Xr locate 1 .
+.It HELP Ta give help information.
+.El
+.Pp
+The following Kerberos related site commands are understood.
+.Bl -column Request -offset indent
+.It KAUTH Ta obtain remote tickets.
+.It KLIST Ta show remote tickets
+.El
+.Pp
+The remaining ftp requests specified in Internet RFC 959
+are
+recognized, but not implemented.
+MDTM and SIZE are not specified in RFC 959, but will appear in the
+next updated FTP RFC.
+.Pp
+The ftp server will abort an active file transfer only when the
+ABOR
+command is preceded by a Telnet "Interrupt Process" (IP)
+signal and a Telnet "Synch" signal in the command Telnet stream,
+as described in Internet RFC 959.
+If a
+STAT
+command is received during a data transfer, preceded by a Telnet IP
+and Synch, transfer status will be returned.
+.Pp
+.Nm Ftpd
+interprets file names according to the
+.Dq globbing
+conventions used by
+.Xr csh 1 .
+This allows users to utilize the metacharacters
+.Dq Li \&*?[]{}~ .
+.Pp
+.Nm Ftpd
+authenticates users according to these rules.
+.Pp
+.Bl -enum -offset indent
+.It
+If Kerberos authentication is used, the user must pass valid tickets
+and the principal must be allowed to login as the remote user.
+.It
+The login name must be in the password data base, and not have a null
+password (if kerberos is used the password field is not checked). In
+this case a password must be provided by the client before any file
+operations may be performed. If the user has an OTP key, the response
+from a successful USER command will include an OTP challenge. The
+client may choose to respond with a PASS command giving either a
+standard password or an OTP one-time password. The server will
+automatically determine which type of password it has been given and
+attempt to authenticate accordingly. See
+.Xr otp 1
+for more information on OTP authentication.
+.It
+The login name must not appear in the file
+.Pa /etc/ftpusers .
+.It
+The user must have a standard shell returned by
+.Xr getusershell 3 .
+.It
+If the user name appears in the file
+.Pa /etc/ftpchroot
+the session's root will be changed to the user's login directory by
+.Xr chroot 2
+as for an
+.Dq anonymous
+or
+.Dq ftp
+account (see next item). However, the user must still supply a password.
+This feature is intended as a compromise between a fully anonymous account
+and a fully privileged account. The account should also be set up as for an
+anonymous account.
+.It
+If the user name is
+.Dq anonymous
+or
+.Dq ftp ,
+an
+anonymous ftp account must be present in the password
+file (user
+.Dq ftp ) .
+In this case the user is allowed
+to log in by specifying any password (by convention an email address for
+the user should be used as the password).
+.El
+.Pp
+In the last case,
+.Nm ftpd
+takes special measures to restrict the client's access privileges.
+The server performs a
+.Xr chroot 2
+to the home directory of the
+.Dq ftp
+user.
+In order that system security is not breached, it is recommended
+that the
+.Dq ftp
+subtree be constructed with care, consider following these guidelines
+for anonymous ftp.
+
+In general all files should be owned by
+.Dq root ,
+and have non-write permissions (644 or 755 depending on the kind of
+file). No files should be owned or writable by
+.Dq ftp
+(possibly with exception for the
+.Pa ~ftp/incoming ,
+as specified below).
+.Bl -tag -width "~ftp/pub" -offset indent
+.It Pa ~ftp
+The
+.Dq ftp
+homedirectory should be owned by root.
+.It Pa ~ftp/bin
+The directory for external programs (such as
+.Xr ls 1 ) .
+These programs must either be statically linked, or you must setup an
+environment for dynamic linking when running chrooted.
+These programs will be used if present:
+.Bl -tag -width "locate" -offset indent
+.It ls
+Used when listing files.
+.It compress
+When retrieving a filename that ends in
+.Pa .Z ,
+and that file isn't present,
+.Nm
+will try to find the filename without
+.Pa .Z
+and compress it on the fly.
+.It gzip
+Same as compress, just with files ending in
+.Pa .gz .
+.It gtar
+Enables retrieval of whole directories as files ending in
+.Pa .tar .
+Can also be combined with compression. You must use GNU Tar (or some
+other that supports the
+.Fl z
+and
+.Fl Z
+flags).
+.It locate
+Will enable ``fast find'' with the
+.Ic SITE FIND
+command. You must also create a
+.Pa locatedb
+file in
+.Pa ~ftp/etc .
+.El
+.It Pa ~ftp/etc
+If you put copies of the
+.Xr passwd 5
+and
+.Xr group 5
+files here, ls will be able to produce owner names rather than
+numbers. Remember to remove any passwords from these files.
+
+The file
+.Pa motd ,
+if present, will be printed after a successful login.
+.It Pa ~ftp/dev
+Put a copy of
+.Xr /dev/null 7
+here.
+.It Pa ~ftp/pub
+Traditional place to put whatever you want to make public.
+.El
+
+If you want guests to be able to upload files, create a
+.Pa ~ftp/incoming
+directory owned by
+.Dq root ,
+and group
+.Dq ftp
+with mode 730 (make sure
+.Dq ftp
+is member of group
+.Dq ftp ) .
+The following restrictions apply to anonymous users:
+.Bl -bullet
+.It
+Directories created will have mode 700.
+.It
+Uploaded files will be created with an umask of 777, if not changed
+with the
+.Fl g
+option.
+.It
+These command are not accessible:
+.Ic DELE , RMD , RNTO , RNFR ,
+.Ic SITE UMASK ,
+and
+.Ic SITE CHMOD .
+.It
+Filenames must start with an alpha-numeric character, and consist of
+alpha-numeric characters or any of the following:
+.Li \&+
+(plus),
+.Li \&-
+(minus),
+.Li \&=
+(equal),
+.Li \&_
+(underscore),
+.Li \&.
+(period), and
+.Li \&,
+(comma).
+.El
+.Sh FILES
+.Bl -tag -width /etc/ftpwelcome -compact
+.It Pa /etc/ftpusers
+Access list for users.
+.It Pa /etc/ftpchroot
+List of normal users who should be chroot'd.
+.It Pa /etc/ftpwelcome
+Welcome notice.
+.It Pa /etc/motd
+Welcome notice after login.
+.It Pa /etc/nologin
+Displayed and access refused.
+.It Pa ~/.klogin
+Login access for Kerberos.
+.El
+.Sh SEE ALSO
+.Xr ftp 1 ,
+.Xr otp 1 ,
+.Xr getusershell 3 ,
+.Xr ftpusers 5 ,
+.Xr syslogd 8 ,
+.Sh STANDARDS
+.Bl -tag -compact -width "RFC 1938"
+.It Cm RFC 959
+FTP PROTOCOL SPECIFICATION
+.It Cm RFC 1938
+OTP Specification
+.It Cm RFC 2228
+FTP Security Extensions.
+.Sh BUGS
+The server must run as the super-user
+to create sockets with privileged port numbers. It maintains
+an effective user id of the logged in user, reverting to
+the super-user only when binding addresses to sockets. The
+possible security holes have been extensively
+scrutinized, but are possibly incomplete.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpd.c b/crypto/heimdal/appl/ftp/ftpd/ftpd.c
new file mode 100644
index 0000000..8c5ddf3
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/ftpd.c
@@ -0,0 +1,2249 @@
+/*
+ * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. 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.
+ */
+
+#define FTP_NAMES
+#include "ftpd_locl.h"
+#ifdef KRB5
+#include <krb5.h>
+#endif
+#include "getarg.h"
+
+RCSID("$Id: ftpd.c,v 1.137 2000/01/05 13:46:04 joda Exp $");
+
+static char version[] = "Version 6.00";
+
+extern off_t restart_point;
+extern char cbuf[];
+
+struct sockaddr_storage ctrl_addr_ss;
+struct sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
+
+struct sockaddr_storage data_source_ss;
+struct sockaddr *data_source = (struct sockaddr *)&data_source_ss;
+
+struct sockaddr_storage data_dest_ss;
+struct sockaddr *data_dest = (struct sockaddr *)&data_dest_ss;
+
+struct sockaddr_storage his_addr_ss;
+struct sockaddr *his_addr = (struct sockaddr *)&his_addr_ss;
+
+struct sockaddr_storage pasv_addr_ss;
+struct sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
+
+int data;
+jmp_buf errcatch, urgcatch;
+int oobflag;
+int logged_in;
+struct passwd *pw;
+int debug = 0;
+int ftpd_timeout = 900; /* timeout after 15 minutes of inactivity */
+int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
+int logging;
+int guest;
+int dochroot;
+int type;
+int form;
+int stru; /* avoid C keyword */
+int mode;
+int usedefault = 1; /* for data transfers */
+int pdata = -1; /* for passive mode */
+int transflag;
+off_t file_size;
+off_t byte_count;
+#if !defined(CMASK) || CMASK == 0
+#undef CMASK
+#define CMASK 027
+#endif
+int defumask = CMASK; /* default umask value */
+int guest_umask = 0777; /* Paranoia for anonymous users */
+char tmpline[10240];
+char hostname[MaxHostNameLen];
+char remotehost[MaxHostNameLen];
+static char ttyline[20];
+
+#define AUTH_PLAIN (1 << 0) /* allow sending passwords */
+#define AUTH_OTP (1 << 1) /* passwords are one-time */
+#define AUTH_FTP (1 << 2) /* allow anonymous login */
+
+static int auth_level = 0; /* Only allow kerberos login by default */
+
+/*
+ * Timeout intervals for retrying connections
+ * to hosts that don't accept PORT cmds. This
+ * is a kludge, but given the problems with TCP...
+ */
+#define SWAITMAX 90 /* wait at most 90 seconds */
+#define SWAITINT 5 /* interval between retries */
+
+int swaitmax = SWAITMAX;
+int swaitint = SWAITINT;
+
+#ifdef HAVE_SETPROCTITLE
+char proctitle[BUFSIZ]; /* initial part of title */
+#endif /* HAVE_SETPROCTITLE */
+
+#define LOGCMD(cmd, file) \
+ if (logging > 1) \
+ syslog(LOG_INFO,"%s %s%s", cmd, \
+ *(file) == '/' ? "" : curdir(), file);
+#define LOGCMD2(cmd, file1, file2) \
+ if (logging > 1) \
+ syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
+ *(file1) == '/' ? "" : curdir(), file1, \
+ *(file2) == '/' ? "" : curdir(), file2);
+#define LOGBYTES(cmd, file, cnt) \
+ if (logging > 1) { \
+ if (cnt == (off_t)-1) \
+ syslog(LOG_INFO,"%s %s%s", cmd, \
+ *(file) == '/' ? "" : curdir(), file); \
+ else \
+ syslog(LOG_INFO, "%s %s%s = %ld bytes", \
+ cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
+ }
+
+static void ack (char *);
+static void myoob (int);
+static int checkuser (char *, char *);
+static int checkaccess (char *);
+static FILE *dataconn (const char *, off_t, const char *);
+static void dolog (struct sockaddr *sa, int len);
+static void end_login (void);
+static FILE *getdatasock (const char *);
+static char *gunique (char *);
+static RETSIGTYPE lostconn (int);
+static int receive_data (FILE *, FILE *);
+static void send_data (FILE *, FILE *);
+static struct passwd * sgetpwnam (char *);
+
+static char *
+curdir(void)
+{
+ static char path[MaxPathLen+1]; /* path + '/' + '\0' */
+
+ if (getcwd(path, sizeof(path)-1) == NULL)
+ return ("");
+ if (path[1] != '\0') /* special case for root dir. */
+ strlcat(path, "/", sizeof(path));
+ /* For guest account, skip / since it's chrooted */
+ return (guest ? path+1 : path);
+}
+
+#ifndef LINE_MAX
+#define LINE_MAX 1024
+#endif
+
+static int
+parse_auth_level(char *str)
+{
+ char *p;
+ int ret = 0;
+ char *foo = NULL;
+
+ for(p = strtok_r(str, ",", &foo);
+ p;
+ p = strtok_r(NULL, ",", &foo)) {
+ if(strcmp(p, "user") == 0)
+ ;
+#ifdef OTP
+ else if(strcmp(p, "otp") == 0)
+ ret |= AUTH_PLAIN|AUTH_OTP;
+#endif
+ else if(strcmp(p, "ftp") == 0 ||
+ strcmp(p, "safe") == 0)
+ ret |= AUTH_FTP;
+ else if(strcmp(p, "plain") == 0)
+ ret |= AUTH_PLAIN;
+ else if(strcmp(p, "none") == 0)
+ ret |= AUTH_PLAIN|AUTH_FTP;
+ else
+ warnx("bad value for -a: `%s'", p);
+ }
+ return ret;
+}
+
+/*
+ * Print usage and die.
+ */
+
+static int debug_flag;
+static int interactive_flag;
+static char *guest_umask_string;
+static char *port_string;
+static char *umask_string;
+static char *auth_string;
+
+int use_builtin_ls = -1;
+
+static int help_flag;
+static int version_flag;
+
+struct getargs args[] = {
+ { NULL, 'a', arg_string, &auth_string, "required authentication" },
+ { NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" },
+ { NULL, 'p', arg_string, &port_string, "what port to listen to" },
+ { NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" },
+ { NULL, 'l', arg_counter, &logging, "log more stuff", "" },
+ { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" },
+ { NULL, 'T', arg_integer, &maxtimeout, "max timeout" },
+ { NULL, 'u', arg_string, &umask_string, "umask for user logins" },
+ { NULL, 'd', arg_flag, &debug_flag, "enable debugging" },
+ { NULL, 'v', arg_flag, &debug_flag, "enable debugging" },
+ { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
+ { "version", 0, arg_flag, &version_flag },
+ { "help", 'h', arg_flag, &help_flag }
+};
+
+static int num_args = sizeof(args) / sizeof(args[0]);
+
+static void
+usage (int code)
+{
+ arg_printusage(args, num_args, NULL, "");
+ exit (code);
+}
+
+/* output contents of a file */
+static int
+show_file(const char *file, int code)
+{
+ FILE *f;
+ char buf[128];
+
+ f = fopen(file, "r");
+ if(f == NULL)
+ return -1;
+ while(fgets(buf, sizeof(buf), f)){
+ buf[strcspn(buf, "\r\n")] = '\0';
+ lreply(code, "%s", buf);
+ }
+ fclose(f);
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int his_addr_len, ctrl_addr_len, on = 1, tos;
+ char *cp, line[LINE_MAX];
+ FILE *fd;
+ int port;
+ struct servent *sp;
+
+ int optind = 0;
+
+ set_progname (argv[0]);
+
+#ifdef KRB4
+ /* detach from any tickets and tokens */
+ {
+ char tkfile[1024];
+ snprintf(tkfile, sizeof(tkfile),
+ "/tmp/ftp_%u", (unsigned)getpid());
+ krb_set_tkt_string(tkfile);
+ if(k_hasafs())
+ k_setpag();
+ }
+#endif
+ if(getarg(args, num_args, argc, argv, &optind))
+ usage(1);
+
+ if(help_flag)
+ usage(0);
+
+ if(version_flag) {
+ print_version(NULL);
+ exit(0);
+ }
+
+ if(auth_string)
+ auth_level = parse_auth_level(auth_string);
+ {
+ char *p;
+ long val = 0;
+
+ if(guest_umask_string) {
+ val = strtol(guest_umask_string, &p, 8);
+ if (*p != '\0' || val < 0)
+ warnx("bad value for -g");
+ else
+ guest_umask = val;
+ }
+ if(umask_string) {
+ val = strtol(umask_string, &p, 8);
+ if (*p != '\0' || val < 0)
+ warnx("bad value for -u");
+ else
+ defumask = val;
+ }
+ }
+ if(port_string) {
+ sp = getservbyname(port_string, "tcp");
+ if(sp)
+ port = sp->s_port;
+ else
+ if(isdigit(port_string[0]))
+ port = htons(atoi(port_string));
+ else
+ warnx("bad value for -p");
+ } else {
+ sp = getservbyname("ftp", "tcp");
+ if(sp)
+ port = sp->s_port;
+ else
+ port = htons(21);
+ }
+
+ if (maxtimeout < ftpd_timeout)
+ maxtimeout = ftpd_timeout;
+
+#if 0
+ if (ftpd_timeout > maxtimeout)
+ ftpd_timeout = maxtimeout;
+#endif
+
+ if(interactive_flag)
+ mini_inetd (port);
+
+ /*
+ * LOG_NDELAY sets up the logging connection immediately,
+ * necessary for anonymous ftp's that chroot and can't do it later.
+ */
+ openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+ his_addr_len = sizeof(his_addr_ss);
+ if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) {
+ syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
+ exit(1);
+ }
+ ctrl_addr_len = sizeof(ctrl_addr_ss);
+ if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) {
+ syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
+ exit(1);
+ }
+#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
+ tos = IPTOS_LOWDELAY;
+ if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS,
+ (void *)&tos, sizeof(int)) < 0)
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif
+ data_source->sa_family = ctrl_addr->sa_family;
+ socket_set_port (data_source,
+ htons(ntohs(socket_get_port(ctrl_addr)) - 1));
+
+ /* set this here so it can be put in wtmp */
+ snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
+
+
+ /* freopen(_PATH_DEVNULL, "w", stderr); */
+ signal(SIGPIPE, lostconn);
+ signal(SIGCHLD, SIG_IGN);
+#ifdef SIGURG
+ if (signal(SIGURG, myoob) == SIG_ERR)
+ syslog(LOG_ERR, "signal: %m");
+#endif
+
+ /* Try to handle urgent data inline */
+#if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
+ if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on,
+ sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt: %m");
+#endif
+
+#ifdef F_SETOWN
+ if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
+ syslog(LOG_ERR, "fcntl F_SETOWN: %m");
+#endif
+ dolog(his_addr, his_addr_len);
+ /*
+ * Set up default state
+ */
+ data = -1;
+ type = TYPE_A;
+ form = FORM_N;
+ stru = STRU_F;
+ mode = MODE_S;
+ tmpline[0] = '\0';
+
+ /* If logins are disabled, print out the message. */
+ if(show_file(_PATH_NOLOGIN, 530) == 0) {
+ reply(530, "System not available.");
+ exit(0);
+ }
+ show_file(_PATH_FTPWELCOME, 220);
+ /* reply(220,) must follow */
+ gethostname(hostname, sizeof(hostname));
+
+ reply(220, "%s FTP server (%s"
+#ifdef KRB5
+ "+%s"
+#endif
+#ifdef KRB4
+ "+%s"
+#endif
+ ") ready.", hostname, version
+#ifdef KRB5
+ ,heimdal_version
+#endif
+#ifdef KRB4
+ ,krb4_version
+#endif
+ );
+
+ setjmp(errcatch);
+ for (;;)
+ yyparse();
+ /* NOTREACHED */
+}
+
+static RETSIGTYPE
+lostconn(int signo)
+{
+
+ if (debug)
+ syslog(LOG_DEBUG, "lost connection");
+ dologout(-1);
+}
+
+/*
+ * Helper function for sgetpwnam().
+ */
+static char *
+sgetsave(char *s)
+{
+ char *new = strdup(s);
+
+ if (new == NULL) {
+ perror_reply(421, "Local resource failure: malloc");
+ dologout(1);
+ /* NOTREACHED */
+ }
+ return new;
+}
+
+/*
+ * Save the result of a getpwnam. Used for USER command, since
+ * the data returned must not be clobbered by any other command
+ * (e.g., globbing).
+ */
+static struct passwd *
+sgetpwnam(char *name)
+{
+ static struct passwd save;
+ struct passwd *p;
+
+ if ((p = k_getpwnam(name)) == NULL)
+ return (p);
+ if (save.pw_name) {
+ free(save.pw_name);
+ free(save.pw_passwd);
+ free(save.pw_gecos);
+ free(save.pw_dir);
+ free(save.pw_shell);
+ }
+ save = *p;
+ save.pw_name = sgetsave(p->pw_name);
+ save.pw_passwd = sgetsave(p->pw_passwd);
+ save.pw_gecos = sgetsave(p->pw_gecos);
+ save.pw_dir = sgetsave(p->pw_dir);
+ save.pw_shell = sgetsave(p->pw_shell);
+ return (&save);
+}
+
+static int login_attempts; /* number of failed login attempts */
+static int askpasswd; /* had user command, ask for passwd */
+static char curname[10]; /* current USER name */
+#ifdef OTP
+OtpContext otp_ctx;
+#endif
+
+/*
+ * USER command.
+ * Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected. If logged in previously,
+ * need to reset state. If name is "ftp" or "anonymous", the name is not in
+ * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway. Otherwise, check user
+ * requesting login privileges. Disallow anyone who does not have a standard
+ * shell as returned by getusershell(). Disallow anyone mentioned in the file
+ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
+ */
+void
+user(char *name)
+{
+ char *cp, *shell;
+
+ if(auth_level == 0 && !sec_complete){
+ reply(530, "No login allowed without authorization.");
+ return;
+ }
+
+ if (logged_in) {
+ if (guest) {
+ reply(530, "Can't change user from guest login.");
+ return;
+ } else if (dochroot) {
+ reply(530, "Can't change user from chroot user.");
+ return;
+ }
+ end_login();
+ }
+
+ guest = 0;
+ if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
+ if ((auth_level & AUTH_FTP) == 0 ||
+ checkaccess("ftp") ||
+ checkaccess("anonymous"))
+ reply(530, "User %s access denied.", name);
+ else if ((pw = sgetpwnam("ftp")) != NULL) {
+ guest = 1;
+ defumask = guest_umask; /* paranoia for incoming */
+ askpasswd = 1;
+ reply(331, "Guest login ok, type your name as password.");
+ } else
+ reply(530, "User %s unknown.", name);
+ if (!askpasswd && logging) {
+ char data_addr[256];
+
+ if (inet_ntop (his_addr->sa_family,
+ socket_get_address(his_addr),
+ data_addr, sizeof(data_addr)) == NULL)
+ strlcpy (data_addr, "unknown address",
+ sizeof(data_addr));
+
+ syslog(LOG_NOTICE,
+ "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
+ remotehost, data_addr);
+ }
+ return;
+ }
+ if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
+ reply(530, "Only authorized and anonymous login allowed.");
+ return;
+ }
+ if ((pw = sgetpwnam(name))) {
+ if ((shell = pw->pw_shell) == NULL || *shell == 0)
+ shell = _PATH_BSHELL;
+ while ((cp = getusershell()) != NULL)
+ if (strcmp(cp, shell) == 0)
+ break;
+ endusershell();
+
+ if (cp == NULL || checkaccess(name)) {
+ reply(530, "User %s access denied.", name);
+ if (logging) {
+ char data_addr[256];
+
+ if (inet_ntop (his_addr->sa_family,
+ socket_get_address(his_addr),
+ data_addr,
+ sizeof(data_addr)) == NULL)
+ strlcpy (data_addr,
+ "unknown address",
+ sizeof(data_addr));
+
+ syslog(LOG_NOTICE,
+ "FTP LOGIN REFUSED FROM %s(%s), %s",
+ remotehost,
+ data_addr,
+ name);
+ }
+ pw = (struct passwd *) NULL;
+ return;
+ }
+ }
+ if (logging)
+ strlcpy(curname, name, sizeof(curname));
+ if(sec_complete) {
+ if(sec_userok(name) == 0)
+ do_login(232, name);
+ else
+ reply(530, "User %s access denied.", name);
+ } else {
+ char ss[256];
+
+#ifdef OTP
+ if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) {
+ reply(331, "Password %s for %s required.",
+ ss, name);
+ askpasswd = 1;
+ } else
+#endif
+ if ((auth_level & AUTH_OTP) == 0) {
+ reply(331, "Password required for %s.", name);
+ askpasswd = 1;
+ } else {
+ char *s;
+
+#ifdef OTP
+ if ((s = otp_error (&otp_ctx)) != NULL)
+ lreply(530, "OTP: %s", s);
+#endif
+ reply(530,
+ "Only authorized, anonymous"
+#ifdef OTP
+ " and OTP "
+#endif
+ "login allowed.");
+ }
+
+ }
+ /*
+ * Delay before reading passwd after first failed
+ * attempt to slow down passwd-guessing programs.
+ */
+ if (login_attempts)
+ sleep(login_attempts);
+}
+
+/*
+ * Check if a user is in the file "fname"
+ */
+static int
+checkuser(char *fname, char *name)
+{
+ FILE *fd;
+ int found = 0;
+ char *p, line[BUFSIZ];
+
+ if ((fd = fopen(fname, "r")) != NULL) {
+ while (fgets(line, sizeof(line), fd) != NULL)
+ if ((p = strchr(line, '\n')) != NULL) {
+ *p = '\0';
+ if (line[0] == '#')
+ continue;
+ if (strcmp(line, name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ fclose(fd);
+ }
+ return (found);
+}
+
+
+/*
+ * Determine whether a user has access, based on information in
+ * _PATH_FTPUSERS. The users are listed one per line, with `allow'
+ * or `deny' after the username. If anything other than `allow', or
+ * just nothing, is given after the username, `deny' is assumed.
+ *
+ * If the user is not found in the file, but the pseudo-user `*' is,
+ * the permission is taken from that line.
+ *
+ * This preserves the old semantics where if a user was listed in the
+ * file he was denied, otherwise he was allowed.
+ *
+ * Return 1 if the user is denied, or 0 if he is allowed. */
+
+static int
+match(const char *pattern, const char *string)
+{
+ return fnmatch(pattern, string, FNM_NOESCAPE);
+}
+
+static int
+checkaccess(char *name)
+{
+#define ALLOWED 0
+#define NOT_ALLOWED 1
+ FILE *fd;
+ int allowed = ALLOWED;
+ char *user, *perm, line[BUFSIZ];
+ char *foo;
+
+ fd = fopen(_PATH_FTPUSERS, "r");
+
+ if(fd == NULL)
+ return allowed;
+
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ foo = NULL;
+ user = strtok_r(line, " \t\n", &foo);
+ if (user == NULL || user[0] == '#')
+ continue;
+ perm = strtok_r(NULL, " \t\n", &foo);
+ if (match(user, name) == 0){
+ if(perm && strcmp(perm, "allow") == 0)
+ allowed = ALLOWED;
+ else
+ allowed = NOT_ALLOWED;
+ break;
+ }
+ }
+ fclose(fd);
+ return allowed;
+}
+#undef ALLOWED
+#undef NOT_ALLOWED
+
+
+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;
+ }
+ initgroups(pw->pw_name, pw->pw_gid);
+
+ /* open wtmp before chroot */
+ ftpd_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;
+ }
+
+ if(use_builtin_ls == -1) {
+ struct stat st;
+ /* if /bin/ls exist and is a regular file, use it, otherwise
+ use built-in ls */
+ if(stat("/bin/ls", &st) == 0 &&
+ S_ISREG(st.st_mode))
+ use_builtin_ls = 0;
+ else
+ use_builtin_ls = 1;
+ }
+
+ /*
+ * Display a login message, if it exists.
+ * N.B. reply(code,) must follow the message.
+ */
+ show_file(_PATH_FTPLOGINMESG, code);
+ if(show_file(_PATH_ISSUE_NET, code) != 0)
+ show_file(_PATH_ISSUE, code);
+ if (guest) {
+ reply(code, "Guest login ok, access restrictions apply.");
+#ifdef HAVE_SETPROCTITLE
+ snprintf (proctitle, sizeof(proctitle),
+ "%s: anonymous/%s",
+ remotehost,
+ passwd);
+ setproctitle(proctitle);
+#endif /* HAVE_SETPROCTITLE */
+ if (logging) {
+ char data_addr[256];
+
+ if (inet_ntop (his_addr->sa_family,
+ socket_get_address(his_addr),
+ data_addr, sizeof(data_addr)) == NULL)
+ strlcpy (data_addr, "unknown address",
+ sizeof(data_addr));
+
+ syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
+ remotehost,
+ data_addr,
+ passwd);
+ }
+ } else {
+ reply(code, "User %s logged in.", pw->pw_name);
+#ifdef HAVE_SETPROCTITLE
+ snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
+ setproctitle(proctitle);
+#endif /* HAVE_SETPROCTITLE */
+ if (logging) {
+ char data_addr[256];
+
+ if (inet_ntop (his_addr->sa_family,
+ socket_get_address(his_addr),
+ data_addr, sizeof(data_addr)) == NULL)
+ strlcpy (data_addr, "unknown address",
+ sizeof(data_addr));
+
+ syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
+ remotehost,
+ data_addr,
+ pw->pw_name);
+ }
+ }
+ 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(void)
+{
+
+ seteuid((uid_t)0);
+ if (logged_in)
+ ftpd_logwtmp(ttyline, "", "");
+ pw = NULL;
+ logged_in = 0;
+ guest = 0;
+ dochroot = 0;
+}
+
+void
+pass(char *passwd)
+{
+ int rval;
+
+ /* 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.");
+ return;
+ }
+ askpasswd = 0;
+ rval = 1;
+ if (!guest) { /* "ftp" is only account allowed no password */
+ if (pw == NULL)
+ rval = 1; /* failure below */
+#ifdef OTP
+ else if (otp_verify_user (&otp_ctx, passwd) == 0) {
+ rval = 0;
+ }
+#endif
+ else if((auth_level & AUTH_OTP) == 0) {
+#ifdef KRB4
+ char realm[REALM_SZ];
+ if((rval = krb_get_lrealm(realm, 1)) == KSUCCESS)
+ rval = krb_verify_user(pw->pw_name,
+ "", realm,
+ passwd,
+ KRB_VERIFY_SECURE, NULL);
+ if (rval == KSUCCESS ) {
+ chown (tkt_string(), pw->pw_uid, pw->pw_gid);
+ if(k_hasafs())
+ krb_afslog(0, 0);
+ } else
+#endif
+ rval = unix_verify_user(pw->pw_name, passwd);
+ } else {
+ char *s;
+
+#ifdef OTP
+ if ((s = otp_error(&otp_ctx)) != NULL)
+ lreply(530, "OTP: %s", s);
+#endif
+ }
+ memset (passwd, 0, strlen(passwd));
+
+ /*
+ * If rval == 1, the user failed the authentication
+ * check above. If rval == 0, either Kerberos or
+ * local authentication succeeded.
+ */
+ if (rval) {
+ char data_addr[256];
+
+ if (inet_ntop (his_addr->sa_family,
+ socket_get_address(his_addr),
+ data_addr, sizeof(data_addr)) == NULL)
+ strlcpy (data_addr, "unknown address",
+ sizeof(data_addr));
+
+ reply(530, "Login incorrect.");
+ if (logging)
+ syslog(LOG_NOTICE,
+ "FTP LOGIN FAILED FROM %s(%s), %s",
+ remotehost,
+ data_addr,
+ curname);
+ pw = NULL;
+ if (login_attempts++ >= 5) {
+ syslog(LOG_NOTICE,
+ "repeated login failures from %s(%s)",
+ remotehost,
+ data_addr);
+ exit(0);
+ }
+ return;
+ }
+ }
+ if(!do_login(230, passwd))
+ return;
+
+ /* Forget all about it... */
+ end_login();
+}
+
+void
+retrieve(const char *cmd, char *name)
+{
+ FILE *fin = NULL, *dout;
+ struct stat st;
+ int (*closefunc) (FILE *);
+ char line[BUFSIZ];
+
+
+ if (cmd == 0) {
+ fin = fopen(name, "r");
+ closefunc = fclose;
+ st.st_size = 0;
+ if(fin == NULL){
+ int save_errno = errno;
+ struct cmds {
+ const char *ext;
+ const char *cmd;
+ const char *rev_cmd;
+ } cmds[] = {
+ {".tar", "/bin/gtar cPf - %s", NULL},
+ {".tar.gz", "/bin/gtar zcPf - %s", NULL},
+ {".tar.Z", "/bin/gtar ZcPf - %s", NULL},
+ {".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"},
+ {".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"},
+ {NULL, NULL}
+ };
+ struct cmds *p;
+ for(p = cmds; p->ext; p++){
+ char *tail = name + strlen(name) - strlen(p->ext);
+ char c = *tail;
+
+ if(strcmp(tail, p->ext) == 0 &&
+ (*tail = 0) == 0 &&
+ access(name, R_OK) == 0){
+ snprintf (line, sizeof(line), p->cmd, name);
+ *tail = c;
+ break;
+ }
+ *tail = c;
+ if (p->rev_cmd != NULL) {
+ char *ext;
+
+ asprintf(&ext, "%s%s", name, p->ext);
+ if (ext != NULL) {
+ if (access(ext, R_OK) == 0) {
+ snprintf (line, sizeof(line),
+ p->rev_cmd, ext);
+ free(ext);
+ break;
+ }
+ free(ext);
+ }
+ }
+
+ }
+ if(p->ext){
+ fin = ftpd_popen(line, "r", 0, 0);
+ closefunc = ftpd_pclose;
+ st.st_size = -1;
+ cmd = line;
+ } else
+ errno = save_errno;
+ }
+ } else {
+ snprintf(line, sizeof(line), cmd, name);
+ name = line;
+ fin = ftpd_popen(line, "r", 1, 0);
+ closefunc = ftpd_pclose;
+ st.st_size = -1;
+ }
+ if (fin == NULL) {
+ if (errno != 0) {
+ perror_reply(550, name);
+ if (cmd == 0) {
+ LOGCMD("get", name);
+ }
+ }
+ return;
+ }
+ byte_count = -1;
+ if (cmd == 0){
+ if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
+ reply(550, "%s: not a plain file.", name);
+ goto done;
+ }
+ }
+ if (restart_point) {
+ if (type == TYPE_A) {
+ off_t i, n;
+ int c;
+
+ n = restart_point;
+ i = 0;
+ while (i++ < n) {
+ if ((c=getc(fin)) == EOF) {
+ perror_reply(550, name);
+ goto done;
+ }
+ if (c == '\n')
+ i++;
+ }
+ } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
+ perror_reply(550, name);
+ goto done;
+ }
+ }
+ dout = dataconn(name, st.st_size, "w");
+ if (dout == NULL)
+ goto done;
+ set_buffer_size(fileno(dout), 0);
+ send_data(fin, dout);
+ fclose(dout);
+ data = -1;
+ pdata = -1;
+done:
+ if (cmd == 0)
+ LOGBYTES("get", name, byte_count);
+ (*closefunc)(fin);
+}
+
+/* filename sanity check */
+
+int
+filename_check(char *filename)
+{
+ static const char good_chars[] = "+-=_,.";
+ char *p;
+
+ p = strrchr(filename, '/');
+ if(p)
+ filename = p + 1;
+
+ p = filename;
+
+ if(isalnum(*p)){
+ p++;
+ while(*p && (isalnum(*p) || strchr(good_chars, *p)))
+ p++;
+ if(*p == '\0')
+ return 0;
+ }
+ lreply(553, "\"%s\" is an illegal filename.", filename);
+ lreply(553, "The filename must start with an alphanumeric "
+ "character and must only");
+ reply(553, "consist of alphanumeric characters or any of the following: %s",
+ good_chars);
+ return 1;
+}
+
+void
+do_store(char *name, char *mode, int unique)
+{
+ FILE *fout, *din;
+ struct stat st;
+ int (*closefunc) (FILE *);
+
+ if(guest && filename_check(name))
+ return;
+ if (unique && stat(name, &st) == 0 &&
+ (name = gunique(name)) == NULL) {
+ LOGCMD(*mode == 'w' ? "put" : "append", name);
+ return;
+ }
+
+ if (restart_point)
+ mode = "r+";
+ fout = fopen(name, mode);
+ closefunc = fclose;
+ if (fout == NULL) {
+ perror_reply(553, name);
+ LOGCMD(*mode == 'w' ? "put" : "append", name);
+ return;
+ }
+ byte_count = -1;
+ if (restart_point) {
+ if (type == TYPE_A) {
+ off_t i, n;
+ int c;
+
+ n = restart_point;
+ i = 0;
+ while (i++ < n) {
+ if ((c=getc(fout)) == EOF) {
+ perror_reply(550, name);
+ goto done;
+ }
+ if (c == '\n')
+ i++;
+ }
+ /*
+ * We must do this seek to "current" position
+ * because we are changing from reading to
+ * writing.
+ */
+ if (fseek(fout, 0L, SEEK_CUR) < 0) {
+ perror_reply(550, name);
+ goto done;
+ }
+ } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
+ perror_reply(550, name);
+ goto done;
+ }
+ }
+ din = dataconn(name, (off_t)-1, "r");
+ if (din == NULL)
+ goto done;
+ set_buffer_size(fileno(din), 1);
+ if (receive_data(din, fout) == 0) {
+ if (unique)
+ reply(226, "Transfer complete (unique file name:%s).",
+ name);
+ else
+ reply(226, "Transfer complete.");
+ }
+ fclose(din);
+ data = -1;
+ pdata = -1;
+done:
+ LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
+ (*closefunc)(fout);
+}
+
+static FILE *
+getdatasock(const char *mode)
+{
+ int s, t, tries;
+
+ if (data >= 0)
+ return (fdopen(data, mode));
+ seteuid(0);
+ s = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
+ if (s < 0)
+ goto bad;
+ socket_set_reuseaddr (s, 1);
+ /* anchor socket to avoid multi-homing problems */
+ socket_set_address_and_port (data_source,
+ socket_get_address (ctrl_addr),
+ socket_get_port (data_source));
+
+ for (tries = 1; ; tries++) {
+ if (bind(s, data_source,
+ socket_sockaddr_size (data_source)) >= 0)
+ break;
+ if (errno != EADDRINUSE || tries > 10)
+ goto bad;
+ sleep(tries);
+ }
+ seteuid(pw->pw_uid);
+#ifdef IPTOS_THROUGHPUT
+ socket_set_tos (s, IPTOS_THROUGHPUT);
+#endif
+ return (fdopen(s, mode));
+bad:
+ /* Return the real value of errno (close may change it) */
+ t = errno;
+ seteuid((uid_t)pw->pw_uid);
+ close(s);
+ errno = t;
+ return (NULL);
+}
+
+static FILE *
+dataconn(const char *name, off_t size, const char *mode)
+{
+ char sizebuf[32];
+ FILE *file;
+ int retry = 0;
+
+ file_size = size;
+ byte_count = 0;
+ if (size >= 0)
+ snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size);
+ else
+ *sizebuf = '\0';
+ if (pdata >= 0) {
+ struct sockaddr_storage from_ss;
+ struct sockaddr *from = (struct sockaddr *)&from_ss;
+ int s;
+ int fromlen = sizeof(from_ss);
+
+ s = accept(pdata, from, &fromlen);
+ if (s < 0) {
+ reply(425, "Can't open data connection.");
+ close(pdata);
+ pdata = -1;
+ return (NULL);
+ }
+ close(pdata);
+ pdata = s;
+#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
+ {
+ int tos = IPTOS_THROUGHPUT;
+
+ setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos,
+ sizeof(tos));
+ }
+#endif
+ reply(150, "Opening %s mode data connection for '%s'%s.",
+ type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+ return (fdopen(pdata, mode));
+ }
+ if (data >= 0) {
+ reply(125, "Using existing data connection for '%s'%s.",
+ name, sizebuf);
+ usedefault = 1;
+ return (fdopen(data, mode));
+ }
+ if (usedefault)
+ data_dest = his_addr;
+ usedefault = 1;
+ file = getdatasock(mode);
+ if (file == NULL) {
+ char data_addr[256];
+
+ if (inet_ntop (data_source->sa_family,
+ socket_get_address(data_source),
+ data_addr, sizeof(data_addr)) == NULL)
+ strlcpy (data_addr, "unknown address",
+ sizeof(data_addr));
+
+ reply(425, "Can't create data socket (%s,%d): %s.",
+ data_addr,
+ socket_get_port (data_source),
+ strerror(errno));
+ return (NULL);
+ }
+ data = fileno(file);
+ while (connect(data, data_dest,
+ socket_sockaddr_size(data_dest)) < 0) {
+ if (errno == EADDRINUSE && retry < swaitmax) {
+ sleep(swaitint);
+ retry += swaitint;
+ continue;
+ }
+ perror_reply(425, "Can't build data connection");
+ fclose(file);
+ data = -1;
+ return (NULL);
+ }
+ reply(150, "Opening %s mode data connection for '%s'%s.",
+ type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
+ return (file);
+}
+
+/*
+ * Tranfer the contents of "instr" to "outstr" peer using the appropriate
+ * encapsulation of the data subject * to Mode, Structure, and Type.
+ *
+ * NB: Form isn't handled.
+ */
+static void
+send_data(FILE *instr, FILE *outstr)
+{
+ int c, cnt, filefd, netfd;
+ static char *buf;
+ static size_t bufsize;
+
+ transflag++;
+ if (setjmp(urgcatch)) {
+ transflag = 0;
+ return;
+ }
+ switch (type) {
+
+ case TYPE_A:
+ while ((c = getc(instr)) != EOF) {
+ byte_count++;
+ if(c == '\n')
+ sec_putc('\r', outstr);
+ sec_putc(c, outstr);
+ }
+ sec_fflush(outstr);
+ transflag = 0;
+ if (ferror(instr))
+ goto file_err;
+ if (ferror(outstr))
+ goto data_err;
+ reply(226, "Transfer complete.");
+ return;
+
+ case TYPE_I:
+ case TYPE_L:
+#if defined(HAVE_MMAP) && !defined(NO_MMAP)
+#ifndef MAP_FAILED
+#define MAP_FAILED (-1)
+#endif
+ {
+ struct stat st;
+ char *chunk;
+ int in = fileno(instr);
+ if(fstat(in, &st) == 0 && S_ISREG(st.st_mode)
+ && st.st_size > 0) {
+ /*
+ * mmap zero bytes has potential of loosing, don't do it.
+ */
+ chunk = mmap(0, st.st_size, PROT_READ,
+ MAP_SHARED, in, 0);
+ if((void *)chunk != (void *)MAP_FAILED) {
+ cnt = st.st_size - restart_point;
+ sec_write(fileno(outstr), chunk + restart_point, cnt);
+ if (munmap(chunk, st.st_size) < 0)
+ warn ("munmap");
+ sec_fflush(outstr);
+ byte_count = cnt;
+ transflag = 0;
+ }
+ }
+ }
+#endif
+ if(transflag) {
+ struct stat st;
+
+ netfd = fileno(outstr);
+ filefd = fileno(instr);
+ buf = alloc_buffer (buf, &bufsize,
+ fstat(filefd, &st) >= 0 ? &st : NULL);
+ if (buf == NULL) {
+ transflag = 0;
+ perror_reply(451, "Local resource failure: malloc");
+ return;
+ }
+ while ((cnt = read(filefd, buf, bufsize)) > 0 &&
+ sec_write(netfd, buf, cnt) == cnt)
+ byte_count += cnt;
+ sec_fflush(outstr); /* to end an encrypted stream */
+ transflag = 0;
+ if (cnt != 0) {
+ if (cnt < 0)
+ goto file_err;
+ goto data_err;
+ }
+ }
+ reply(226, "Transfer complete.");
+ return;
+ default:
+ transflag = 0;
+ reply(550, "Unimplemented TYPE %d in send_data", type);
+ return;
+ }
+
+data_err:
+ transflag = 0;
+ perror_reply(426, "Data connection");
+ return;
+
+file_err:
+ transflag = 0;
+ perror_reply(551, "Error on input file");
+}
+
+/*
+ * Transfer data from peer to "outstr" using the appropriate encapulation of
+ * the data subject to Mode, Structure, and Type.
+ *
+ * N.B.: Form isn't handled.
+ */
+static int
+receive_data(FILE *instr, FILE *outstr)
+{
+ int cnt, bare_lfs = 0;
+ static char *buf;
+ static size_t bufsize;
+ struct stat st;
+
+ transflag++;
+ if (setjmp(urgcatch)) {
+ transflag = 0;
+ return (-1);
+ }
+
+ buf = alloc_buffer (buf, &bufsize,
+ fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
+ if (buf == NULL) {
+ transflag = 0;
+ perror_reply(451, "Local resource failure: malloc");
+ return -1;
+ }
+
+ switch (type) {
+
+ case TYPE_I:
+ case TYPE_L:
+ while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) {
+ if (write(fileno(outstr), buf, cnt) != cnt)
+ goto file_err;
+ byte_count += cnt;
+ }
+ if (cnt < 0)
+ goto data_err;
+ transflag = 0;
+ return (0);
+
+ case TYPE_E:
+ reply(553, "TYPE E not implemented.");
+ transflag = 0;
+ return (-1);
+
+ case TYPE_A:
+ {
+ char *p, *q;
+ int cr_flag = 0;
+ while ((cnt = sec_read(fileno(instr),
+ buf + cr_flag,
+ bufsize - cr_flag)) > 0){
+ byte_count += cnt;
+ cnt += cr_flag;
+ cr_flag = 0;
+ for(p = buf, q = buf; p < buf + cnt;) {
+ if(*p == '\n')
+ bare_lfs++;
+ if(*p == '\r') {
+ if(p == buf + cnt - 1){
+ cr_flag = 1;
+ p++;
+ continue;
+ }else if(p[1] == '\n'){
+ *q++ = '\n';
+ p += 2;
+ continue;
+ }
+ }
+ *q++ = *p++;
+ }
+ fwrite(buf, q - buf, 1, outstr);
+ if(cr_flag)
+ buf[0] = '\r';
+ }
+ if(cr_flag)
+ putc('\r', outstr);
+ fflush(outstr);
+ if (ferror(instr))
+ goto data_err;
+ if (ferror(outstr))
+ goto file_err;
+ transflag = 0;
+ if (bare_lfs) {
+ lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
+ " File may not have transferred correctly.\r\n",
+ bare_lfs);
+ }
+ return (0);
+ }
+ default:
+ reply(550, "Unimplemented TYPE %d in receive_data", type);
+ transflag = 0;
+ return (-1);
+ }
+
+data_err:
+ transflag = 0;
+ perror_reply(426, "Data Connection");
+ return (-1);
+
+file_err:
+ transflag = 0;
+ perror_reply(452, "Error writing file");
+ return (-1);
+}
+
+void
+statfilecmd(char *filename)
+{
+ FILE *fin;
+ int c;
+ char line[LINE_MAX];
+
+ snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename);
+ fin = ftpd_popen(line, "r", 1, 0);
+ lreply(211, "status of %s:", filename);
+ while ((c = getc(fin)) != EOF) {
+ if (c == '\n') {
+ if (ferror(stdout)){
+ perror_reply(421, "control connection");
+ ftpd_pclose(fin);
+ dologout(1);
+ /* NOTREACHED */
+ }
+ if (ferror(fin)) {
+ perror_reply(551, filename);
+ ftpd_pclose(fin);
+ return;
+ }
+ putc('\r', stdout);
+ }
+ putc(c, stdout);
+ }
+ ftpd_pclose(fin);
+ reply(211, "End of Status");
+}
+
+void
+statcmd(void)
+{
+#if 0
+ struct sockaddr_in *sin;
+ u_char *a, *p;
+
+ lreply(211, "%s FTP server (%s) status:", hostname, version);
+ printf(" %s\r\n", version);
+ printf(" Connected to %s", remotehost);
+ if (!isdigit(remotehost[0]))
+ printf(" (%s)", inet_ntoa(his_addr.sin_addr));
+ printf("\r\n");
+ if (logged_in) {
+ if (guest)
+ printf(" Logged in anonymously\r\n");
+ else
+ printf(" Logged in as %s\r\n", pw->pw_name);
+ } else if (askpasswd)
+ printf(" Waiting for password\r\n");
+ else
+ printf(" Waiting for user name\r\n");
+ printf(" TYPE: %s", typenames[type]);
+ if (type == TYPE_A || type == TYPE_E)
+ printf(", FORM: %s", formnames[form]);
+ if (type == TYPE_L)
+#if NBBY == 8
+ printf(" %d", NBBY);
+#else
+ printf(" %d", bytesize); /* need definition! */
+#endif
+ printf("; STRUcture: %s; transfer MODE: %s\r\n",
+ strunames[stru], modenames[mode]);
+ if (data != -1)
+ printf(" Data connection open\r\n");
+ else if (pdata != -1) {
+ printf(" in Passive mode");
+ sin = &pasv_addr;
+ goto printaddr;
+ } else if (usedefault == 0) {
+ printf(" PORT");
+ sin = &data_dest;
+printaddr:
+ a = (u_char *) &sin->sin_addr;
+ p = (u_char *) &sin->sin_port;
+#define UC(b) (((int) b) & 0xff)
+ printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
+ UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+#undef UC
+ } else
+ printf(" No data connection\r\n");
+#endif
+ reply(211, "End of status");
+}
+
+void
+fatal(char *s)
+{
+
+ reply(451, "Error in server: %s\n", s);
+ reply(221, "Closing connection due to server error.");
+ dologout(0);
+ /* NOTREACHED */
+}
+
+static void
+int_reply(int, char *, const char *, va_list)
+#ifdef __GNUC__
+__attribute__ ((format (printf, 3, 0)))
+#endif
+;
+
+static void
+int_reply(int n, char *c, const char *fmt, va_list ap)
+{
+ char buf[10240];
+ char *p;
+ p=buf;
+ if(n){
+ snprintf(p, sizeof(buf), "%d%s", n, c);
+ p+=strlen(p);
+ }
+ vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap);
+ p+=strlen(p);
+ snprintf(p, sizeof(buf) - strlen(p), "\r\n");
+ p+=strlen(p);
+ sec_fprintf(stdout, "%s", buf);
+ fflush(stdout);
+ if (debug)
+ syslog(LOG_DEBUG, "<--- %s- ", buf);
+}
+
+void
+reply(int n, const char *fmt, ...)
+{
+ 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);
+}
+
+void
+nreply(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int_reply(0, NULL, fmt, ap);
+ va_end(ap);
+}
+
+static void
+ack(char *s)
+{
+
+ reply(250, "%s command successful.", s);
+}
+
+void
+nack(char *s)
+{
+
+ reply(502, "%s command not implemented.", s);
+}
+
+/* ARGSUSED */
+void
+yyerror(char *s)
+{
+ char *cp;
+
+ if ((cp = strchr(cbuf,'\n')))
+ *cp = '\0';
+ reply(500, "'%s': command not understood.", cbuf);
+}
+
+void
+do_delete(char *name)
+{
+ struct stat st;
+
+ LOGCMD("delete", name);
+ if (stat(name, &st) < 0) {
+ perror_reply(550, name);
+ return;
+ }
+ if ((st.st_mode&S_IFMT) == S_IFDIR) {
+ if (rmdir(name) < 0) {
+ perror_reply(550, name);
+ return;
+ }
+ goto done;
+ }
+ if (unlink(name) < 0) {
+ perror_reply(550, name);
+ return;
+ }
+done:
+ ack("DELE");
+}
+
+void
+cwd(char *path)
+{
+
+ if (chdir(path) < 0)
+ perror_reply(550, path);
+ else
+ ack("CWD");
+}
+
+void
+makedir(char *name)
+{
+
+ LOGCMD("mkdir", name);
+ if(guest && filename_check(name))
+ return;
+ if (mkdir(name, 0777) < 0)
+ perror_reply(550, name);
+ else{
+ if(guest)
+ chmod(name, 0700); /* guest has umask 777 */
+ reply(257, "MKD command successful.");
+ }
+}
+
+void
+removedir(char *name)
+{
+
+ LOGCMD("rmdir", name);
+ if (rmdir(name) < 0)
+ perror_reply(550, name);
+ else
+ ack("RMD");
+}
+
+void
+pwd(void)
+{
+ char path[MaxPathLen];
+ char *ret;
+
+ /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
+ * failes miserably when running chroot
+ */
+ ret = getcwd(path, sizeof(path));
+ if (ret == NULL)
+ reply(550, "%s.", strerror(errno));
+ else
+ reply(257, "\"%s\" is current directory.", path);
+}
+
+char *
+renamefrom(char *name)
+{
+ struct stat st;
+
+ if (stat(name, &st) < 0) {
+ perror_reply(550, name);
+ return NULL;
+ }
+ reply(350, "File exists, ready for destination name");
+ return (name);
+}
+
+void
+renamecmd(char *from, char *to)
+{
+
+ LOGCMD2("rename", from, to);
+ if(guest && filename_check(to))
+ return;
+ if (rename(from, to) < 0)
+ perror_reply(550, "rename");
+ else
+ ack("RNTO");
+}
+
+static void
+dolog(struct sockaddr *sa, int len)
+{
+ getnameinfo_verified (sa, len, remotehost, sizeof(remotehost),
+ NULL, 0, 0);
+#ifdef HAVE_SETPROCTITLE
+ snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
+ setproctitle(proctitle);
+#endif /* HAVE_SETPROCTITLE */
+
+ if (logging) {
+ char data_addr[256];
+
+ if (inet_ntop (his_addr->sa_family,
+ socket_get_address(his_addr),
+ data_addr, sizeof(data_addr)) == NULL)
+ strlcpy (data_addr, "unknown address",
+ sizeof(data_addr));
+
+
+ syslog(LOG_INFO, "connection from %s(%s)",
+ remotehost,
+ data_addr);
+ }
+}
+
+/*
+ * Record logout in wtmp file
+ * and exit with supplied status.
+ */
+void
+dologout(int status)
+{
+ transflag = 0;
+ if (logged_in) {
+ seteuid((uid_t)0);
+ ftpd_logwtmp(ttyline, "", "");
+#ifdef KRB4
+ cond_kdestroy();
+#endif
+ }
+ /* beware of flushing buffers after a SIGPIPE */
+#ifdef XXX
+ exit(status);
+#else
+ _exit(status);
+#endif
+}
+
+void abor(void)
+{
+}
+
+static void
+myoob(int signo)
+{
+#if 0
+ char *cp;
+#endif
+
+ /* only process if transfer occurring */
+ if (!transflag)
+ return;
+
+ /* This is all XXX */
+ oobflag = 1;
+ /* if the command resulted in a new command,
+ parse that as well */
+ do{
+ yyparse();
+ } while(ftp_command);
+ oobflag = 0;
+
+#if 0
+ cp = tmpline;
+ if (ftpd_getline(cp, 7) == NULL) {
+ reply(221, "You could at least say goodbye.");
+ dologout(0);
+ }
+ upper(cp);
+ if (strcmp(cp, "ABOR\r\n") == 0) {
+ tmpline[0] = '\0';
+ reply(426, "Transfer aborted. Data connection closed.");
+ reply(226, "Abort successful");
+ longjmp(urgcatch, 1);
+ }
+ if (strcmp(cp, "STAT\r\n") == 0) {
+ if (file_size != (off_t) -1)
+ reply(213, "Status: %ld of %ld bytes transferred",
+ (long)byte_count,
+ (long)file_size);
+ else
+ reply(213, "Status: %ld bytes transferred"
+ (long)byte_count);
+ }
+#endif
+}
+
+/*
+ * Note: a response of 425 is not mentioned as a possible response to
+ * the PASV command in RFC959. However, it has been blessed as
+ * a legitimate response by Jon Postel in a telephone conversation
+ * with Rick Adams on 25 Jan 89.
+ */
+void
+pasv(void)
+{
+ int len;
+ char *p, *a;
+ struct sockaddr_in *sin;
+
+ if (ctrl_addr->sa_family != AF_INET) {
+ reply(425,
+ "You cannot do PASV with something that's not IPv4");
+ return;
+ }
+
+ pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
+ if (pdata < 0) {
+ perror_reply(425, "Can't open passive connection");
+ return;
+ }
+ pasv_addr->sa_family = ctrl_addr->sa_family;
+ socket_set_address_and_port (pasv_addr,
+ socket_get_address (ctrl_addr),
+ 0);
+ seteuid(0);
+ if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
+ seteuid(pw->pw_uid);
+ goto pasv_error;
+ }
+ seteuid(pw->pw_uid);
+ len = sizeof(pasv_addr_ss);
+ if (getsockname(pdata, pasv_addr, &len) < 0)
+ goto pasv_error;
+ if (listen(pdata, 1) < 0)
+ goto pasv_error;
+ sin = (struct sockaddr_in *)pasv_addr;
+ a = (char *) &sin->sin_addr;
+ p = (char *) &sin->sin_port;
+
+#define UC(b) (((int) b) & 0xff)
+
+ reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
+ UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
+ return;
+
+pasv_error:
+ close(pdata);
+ pdata = -1;
+ perror_reply(425, "Can't open passive connection");
+ return;
+}
+
+void
+epsv(char *proto)
+{
+ int len;
+
+ pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
+ if (pdata < 0) {
+ perror_reply(425, "Can't open passive connection");
+ return;
+ }
+ pasv_addr->sa_family = ctrl_addr->sa_family;
+ socket_set_address_and_port (pasv_addr,
+ socket_get_address (ctrl_addr),
+ 0);
+ seteuid(0);
+ if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
+ seteuid(pw->pw_uid);
+ goto pasv_error;
+ }
+ seteuid(pw->pw_uid);
+ len = sizeof(pasv_addr_ss);
+ if (getsockname(pdata, pasv_addr, &len) < 0)
+ goto pasv_error;
+ if (listen(pdata, 1) < 0)
+ goto pasv_error;
+
+ reply(229, "Entering Extended Passive Mode (|||%d|)",
+ ntohs(socket_get_port (pasv_addr)));
+ return;
+
+pasv_error:
+ close(pdata);
+ pdata = -1;
+ perror_reply(425, "Can't open passive connection");
+ return;
+}
+
+void
+eprt(char *str)
+{
+ char *end;
+ char sep;
+ int af;
+ int ret;
+ int port;
+
+ usedefault = 0;
+ if (pdata >= 0) {
+ close(pdata);
+ pdata = -1;
+ }
+
+ sep = *str++;
+ if (sep == '\0') {
+ reply(500, "Bad syntax in EPRT");
+ return;
+ }
+ af = strtol (str, &end, 0);
+ if (af == 0 || *end != sep) {
+ reply(500, "Bad syntax in EPRT");
+ return;
+ }
+ str = end + 1;
+ switch (af) {
+#ifdef HAVE_IPV6
+ case 2 :
+ data_dest->sa_family = AF_INET6;
+ break;
+#endif
+ case 1 :
+ data_dest->sa_family = AF_INET;
+ break;
+ default :
+ reply(522, "Network protocol %d not supported, use (1"
+#ifdef HAVE_IPV6
+ ",2"
+#endif
+ ")", af);
+ return;
+ }
+ end = strchr (str, sep);
+ if (end == NULL) {
+ reply(500, "Bad syntax in EPRT");
+ return;
+ }
+ *end = '\0';
+ ret = inet_pton (data_dest->sa_family, str,
+ socket_get_address (data_dest));
+
+ if (ret != 1) {
+ reply(500, "Bad address syntax in EPRT");
+ return;
+ }
+ str = end + 1;
+ port = strtol (str, &end, 0);
+ if (port == 0 || *end != sep) {
+ reply(500, "Bad port syntax in EPRT");
+ return;
+ }
+ socket_set_port (data_dest, htons(port));
+ reply(200, "EPRT command successful.");
+}
+
+/*
+ * Generate unique name for file with basename "local".
+ * The file named "local" is already known to exist.
+ * Generates failure reply on error.
+ */
+static char *
+gunique(char *local)
+{
+ static char new[MaxPathLen];
+ struct stat st;
+ int count;
+ char *cp;
+
+ cp = strrchr(local, '/');
+ if (cp)
+ *cp = '\0';
+ if (stat(cp ? local : ".", &st) < 0) {
+ perror_reply(553, cp ? local : ".");
+ return NULL;
+ }
+ if (cp)
+ *cp = '/';
+ for (count = 1; count < 100; count++) {
+ snprintf (new, sizeof(new), "%s.%d", local, count);
+ if (stat(new, &st) < 0)
+ return (new);
+ }
+ reply(452, "Unique file name cannot be created.");
+ return (NULL);
+}
+
+/*
+ * Format and send reply containing system error number.
+ */
+void
+perror_reply(int code, const char *string)
+{
+ reply(code, "%s: %s.", string, strerror(errno));
+}
+
+static char *onefile[] = {
+ "",
+ 0
+};
+
+void
+list_file(char *file)
+{
+ if(use_builtin_ls) {
+ FILE *dout;
+ dout = dataconn(file, -1, "w");
+ if (dout == NULL)
+ return;
+ set_buffer_size(fileno(dout), 0);
+ builtin_ls(dout, file);
+ reply(226, "Transfer complete.");
+ fclose(dout);
+ data = -1;
+ pdata = -1;
+ } else {
+#ifdef HAVE_LS_A
+ const char *cmd = "/bin/ls -lA -- %s";
+#else
+ const char *cmd = "/bin/ls -la -- %s";
+#endif
+ retrieve(cmd, file);
+ }
+}
+
+void
+send_file_list(char *whichf)
+{
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ FILE *dout = NULL;
+ char **dirlist, *dirname;
+ int simple = 0;
+ int freeglob = 0;
+ glob_t gl;
+ char buf[MaxPathLen];
+
+ if (strpbrk(whichf, "~{[*?") != NULL) {
+ int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
+
+ memset(&gl, 0, sizeof(gl));
+ freeglob = 1;
+ if (glob(whichf, flags, 0, &gl)) {
+ reply(550, "not found");
+ goto out;
+ } else if (gl.gl_pathc == 0) {
+ errno = ENOENT;
+ perror_reply(550, whichf);
+ goto out;
+ }
+ dirlist = gl.gl_pathv;
+ } else {
+ onefile[0] = whichf;
+ dirlist = onefile;
+ simple = 1;
+ }
+
+ if (setjmp(urgcatch)) {
+ transflag = 0;
+ goto out;
+ }
+ while ((dirname = *dirlist++)) {
+ if (stat(dirname, &st) < 0) {
+ /*
+ * If user typed "ls -l", etc, and the client
+ * used NLST, do what the user meant.
+ */
+ if (dirname[0] == '-' && *dirlist == NULL &&
+ transflag == 0) {
+ retrieve("/bin/ls -- %s", dirname);
+ goto out;
+ }
+ perror_reply(550, whichf);
+ if (dout != NULL) {
+ fclose(dout);
+ transflag = 0;
+ data = -1;
+ pdata = -1;
+ }
+ goto out;
+ }
+
+ if (S_ISREG(st.st_mode)) {
+ if (dout == NULL) {
+ dout = dataconn("file list", (off_t)-1, "w");
+ if (dout == NULL)
+ goto out;
+ transflag++;
+ }
+ snprintf(buf, sizeof(buf), "%s%s\n", dirname,
+ type == TYPE_A ? "\r" : "");
+ sec_write(fileno(dout), buf, strlen(buf));
+ byte_count += strlen(dirname) + 1;
+ continue;
+ } else if (!S_ISDIR(st.st_mode))
+ continue;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ continue;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MaxPathLen];
+
+ if (!strcmp(dir->d_name, "."))
+ continue;
+ if (!strcmp(dir->d_name, ".."))
+ continue;
+
+ snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
+
+ /*
+ * We have to do a stat to insure it's
+ * not a directory or special file.
+ */
+ if (simple || (stat(nbuf, &st) == 0 &&
+ S_ISREG(st.st_mode))) {
+ if (dout == NULL) {
+ dout = dataconn("file list", (off_t)-1, "w");
+ if (dout == NULL)
+ goto out;
+ transflag++;
+ }
+ if(strncmp(nbuf, "./", 2) == 0)
+ snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
+ type == TYPE_A ? "\r" : "");
+ else
+ snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
+ type == TYPE_A ? "\r" : "");
+ sec_write(fileno(dout), buf, strlen(buf));
+ byte_count += strlen(nbuf) + 1;
+ }
+ }
+ closedir(dirp);
+ }
+ if (dout == NULL)
+ reply(550, "No files found.");
+ else if (ferror(dout) != 0)
+ perror_reply(550, "Data connection");
+ else
+ reply(226, "Transfer complete.");
+
+ transflag = 0;
+ if (dout != NULL){
+ sec_write(fileno(dout), buf, 0); /* XXX flush */
+
+ fclose(dout);
+ }
+ data = -1;
+ pdata = -1;
+out:
+ if (freeglob) {
+ freeglob = 0;
+ globfree(&gl);
+ }
+}
+
+
+int
+find(char *pattern)
+{
+ char line[1024];
+ FILE *f;
+
+ snprintf(line, sizeof(line),
+ "/bin/locate -d %s -- %s",
+ ftp_rooted("/etc/locatedb"),
+ pattern);
+ f = ftpd_popen(line, "r", 1, 1);
+ if(f == NULL){
+ perror_reply(550, "/bin/locate");
+ return 1;
+ }
+ lreply(200, "Output from find.");
+ while(fgets(line, sizeof(line), f)){
+ if(line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = 0;
+ nreply("%s", line);
+ }
+ reply(200, "Done");
+ ftpd_pclose(f);
+ return 0;
+}
+
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpd_locl.h b/crypto/heimdal/appl/ftp/ftpd/ftpd_locl.h
new file mode 100644
index 0000000..5cb4904
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/ftpd_locl.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+/* $Id: ftpd_locl.h,v 1.9 1999/12/02 16:58:30 joda Exp $ */
+
+#ifndef __ftpd_locl_h__
+#define __ftpd_locl_h__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/*
+ * FTP server.
+ */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if defined(HAVE_SYS_IOCTL_H) && SunOS != 40
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include <arpa/ftp.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_TELNET_H
+#include <arpa/telnet.h>
+#endif
+
+#include <ctype.h>
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <glob.h>
+#include <limits.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#include <time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#include <fnmatch.h>
+
+#ifdef HAVE_BSD_BSD_H
+#include <bsd/bsd.h>
+#endif
+
+#include <err.h>
+
+#include "pathnames.h"
+#include "extern.h"
+#include "common.h"
+
+#include "security.h"
+
+#include "roken.h"
+
+#ifdef KRB4
+#include <krb.h>
+#include <kafs.h>
+#endif
+
+#ifdef OTP
+#include <otp.h>
+#endif
+
+#ifdef SOCKS
+#include <socks.h>
+extern int LIBPREFIX(fclose) (FILE *);
+#endif
+
+/* SunOS doesn't have any declaration of fclose */
+
+int fclose(FILE *stream);
+
+int yyparse();
+
+#ifndef LOG_FTP
+#define LOG_FTP LOG_DAEMON
+#endif
+
+#endif /* __ftpd_locl_h__ */
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpusers.5 b/crypto/heimdal/appl/ftp/ftpd/ftpusers.5
new file mode 100644
index 0000000..dfd66f9
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/ftpusers.5
@@ -0,0 +1,38 @@
+.\" $Id: ftpusers.5,v 1.2 1997/05/07 20:11:11 joda Exp $
+.\"
+.Dd May 7, 1997
+.Dt FTPUSERS 5
+.Os KTH-KRB
+.Sh NAME
+.Pa /etc/ftpusers
+.Nd
+FTP access list file.
+.Sh DESCRIPTION
+.Pa /etc/ftpusers
+contains a list of users that should be allowed or denied FTP
+access. Each line contains a user, optionally followed by
+.Dq allow
+(anything but
+.Dq allow
+is ignored). The semi-user
+.Dq *
+matches any user. Users that has an explicit
+.Dq allow ,
+or that does not match any line, are allowed access. Anyone else is
+denied access.
+
+Note that this is compatible with the old format, where this file
+contained a list of users that should be denied access.
+.Sh EXAMPLES
+This will deny anyone but
+.Dq foo
+and
+.Dq bar
+to use FTP:
+.Bd -literal
+foo allow
+bar allow
+*
+.Ed
+.Sh SEE ALSO
+.Xr ftpd 8
diff --git a/crypto/heimdal/appl/ftp/ftpd/gss_userok.c b/crypto/heimdal/appl/ftp/ftpd/gss_userok.c
new file mode 100644
index 0000000..28e3596
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/gss_userok.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+#include "ftpd_locl.h"
+#include <gssapi.h>
+#include <krb5.h>
+
+RCSID("$Id: gss_userok.c,v 1.2 1999/12/02 16:58:31 joda Exp $");
+
+/* XXX a bit too much of krb5 dependency here...
+ What is the correct way to do this?
+ */
+
+extern krb5_context gssapi_krb5_context;
+
+/* XXX sync with gssapi.c */
+struct gss_data {
+ gss_ctx_id_t context_hdl;
+ char *client_name;
+};
+
+int gss_userok(void*, char*); /* to keep gcc happy */
+
+int
+gss_userok(void *app_data, char *username)
+{
+ struct gss_data *data = app_data;
+ if(gssapi_krb5_context) {
+ krb5_principal client;
+ krb5_error_code ret;
+ ret = krb5_parse_name(gssapi_krb5_context, data->client_name, &client);
+ if(ret)
+ return 1;
+ ret = krb5_kuserok(gssapi_krb5_context, client, username);
+ krb5_free_principal(gssapi_krb5_context, client);
+ return !ret;
+ }
+ return 1;
+}
diff --git a/crypto/heimdal/appl/ftp/ftpd/kauth.c b/crypto/heimdal/appl/ftp/ftpd/kauth.c
new file mode 100644
index 0000000..dad4de5
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/kauth.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1998 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+#include "ftpd_locl.h"
+
+RCSID("$Id: kauth.c,v 1.25 1999/12/02 16:58:31 joda Exp $");
+
+static KTEXT_ST cip;
+static unsigned int lifetime;
+static time_t local_time;
+
+static krb_principal pr;
+
+static int do_destroy_tickets = 1;
+
+static int
+save_tkt(const char *user,
+ const char *instance,
+ const char *realm,
+ const void *arg,
+ key_proc_t key_proc,
+ KTEXT *cipp)
+{
+ local_time = time(0);
+ memmove(&cip, *cipp, sizeof(cip));
+ return -1;
+}
+
+static int
+store_ticket(KTEXT cip)
+{
+ char *ptr;
+ des_cblock session;
+ krb_principal sp;
+ unsigned char kvno;
+ KTEXT_ST tkt;
+ int left = cip->length;
+ int len;
+ int kerror;
+
+ ptr = (char *) cip->dat;
+
+ /* extract session key */
+ memmove(session, ptr, 8);
+ ptr += 8;
+ left -= 8;
+
+ len = strnlen(ptr, left);
+ if (len == left)
+ return(INTK_BADPW);
+
+ /* extract server's name */
+ strlcpy(sp.name, ptr, sizeof(sp.name));
+ ptr += len + 1;
+ left -= len + 1;
+
+ len = strnlen(ptr, left);
+ if (len == left)
+ return(INTK_BADPW);
+
+ /* extract server's instance */
+ strlcpy(sp.instance, ptr, sizeof(sp.instance));
+ ptr += len + 1;
+ left -= len + 1;
+
+ len = strnlen(ptr, left);
+ if (len == left)
+ return(INTK_BADPW);
+
+ /* extract server's realm */
+ strlcpy(sp.realm, ptr, sizeof(sp.realm));
+ ptr += len + 1;
+ left -= len + 1;
+
+ if(left < 3)
+ return INTK_BADPW;
+ /* extract ticket lifetime, server key version, ticket length */
+ /* be sure to avoid sign extension on lifetime! */
+ lifetime = (unsigned char) ptr[0];
+ kvno = (unsigned char) ptr[1];
+ tkt.length = (unsigned char) ptr[2];
+ ptr += 3;
+ left -= 3;
+
+ if (tkt.length > left)
+ return(INTK_BADPW);
+
+ /* extract ticket itself */
+ memmove(tkt.dat, ptr, tkt.length);
+ ptr += tkt.length;
+ left -= tkt.length;
+
+ /* Here is where the time should be verified against the KDC.
+ * Unfortunately everything is sent in host byte order (receiver
+ * makes wrong) , and at this stage there is no way for us to know
+ * which byteorder the KDC has. So we simply ignore the time,
+ * there are no security risks with this, the only thing that can
+ * happen is that we might receive a replayed ticket, which could
+ * at most be useless.
+ */
+
+#if 0
+ /* check KDC time stamp */
+ {
+ time_t kdc_time;
+
+ memmove(&kdc_time, ptr, sizeof(kdc_time));
+ if (swap_bytes) swap_u_long(kdc_time);
+
+ ptr += 4;
+
+ if (abs((int)(local_time - kdc_time)) > CLOCK_SKEW) {
+ return(RD_AP_TIME); /* XXX should probably be better
+ code */
+ }
+ }
+#endif
+
+ /* initialize ticket cache */
+
+ if (tf_create(TKT_FILE) != KSUCCESS)
+ return(INTK_ERR);
+
+ if (tf_put_pname(pr.name) != KSUCCESS ||
+ tf_put_pinst(pr.instance) != KSUCCESS) {
+ tf_close();
+ return(INTK_ERR);
+ }
+
+
+ kerror = tf_save_cred(sp.name, sp.instance, sp.realm, session,
+ lifetime, kvno, &tkt, local_time);
+ tf_close();
+
+ return(kerror);
+}
+
+void
+kauth(char *principal, char *ticket)
+{
+ char *p;
+ int ret;
+
+ if(get_command_prot() != prot_private) {
+ reply(500, "Request denied (bad protection level)");
+ return;
+ }
+ ret = krb_parse_name(principal, &pr);
+ if(ret){
+ reply(500, "Bad principal: %s.", krb_get_err_text(ret));
+ return;
+ }
+ if(pr.realm[0] == 0)
+ krb_get_lrealm(pr.realm, 1);
+
+ if(ticket){
+ cip.length = base64_decode(ticket, &cip.dat);
+ if(cip.length == -1){
+ reply(500, "Failed to decode data.");
+ return;
+ }
+ ret = store_ticket(&cip);
+ if(ret){
+ reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
+ memset(&cip, 0, sizeof(cip));
+ return;
+ }
+ do_destroy_tickets = 1;
+
+ if(k_hasafs())
+ krb_afslog(0, 0);
+ reply(200, "Tickets will be destroyed on exit.");
+ return;
+ }
+
+ ret = krb_get_in_tkt (pr.name,
+ pr.instance,
+ pr.realm,
+ KRB_TICKET_GRANTING_TICKET,
+ pr.realm,
+ DEFAULT_TKT_LIFE,
+ NULL, save_tkt, NULL);
+ if(ret != INTK_BADPW){
+ reply(500, "Kerberos error: %s.", krb_get_err_text(ret));
+ return;
+ }
+ if(base64_encode(cip.dat, cip.length, &p) < 0) {
+ reply(500, "Out of memory while base64-encoding.");
+ return;
+ }
+ reply(300, "P=%s T=%s", krb_unparse_name(&pr), p);
+ free(p);
+ memset(&cip, 0, sizeof(cip));
+}
+
+
+static char *
+short_date(int32_t dp)
+{
+ char *cp;
+ time_t t = (time_t)dp;
+
+ if (t == (time_t)(-1L)) return "*** Never *** ";
+ cp = ctime(&t) + 4;
+ cp[15] = '\0';
+ return (cp);
+}
+
+void
+klist(void)
+{
+ int err;
+
+ char *file = tkt_string();
+
+ krb_principal pr;
+
+ char buf1[128], buf2[128];
+ int header = 1;
+ CREDENTIALS c;
+
+
+
+ err = tf_init(file, R_TKT_FIL);
+ if(err != KSUCCESS){
+ reply(500, "%s", krb_get_err_text(err));
+ return;
+ }
+ tf_close();
+
+ /*
+ * We must find the realm of the ticket file here before calling
+ * tf_init because since the realm of the ticket file is not
+ * really stored in the principal section of the file, the
+ * routine we use must itself call tf_init and tf_close.
+ */
+ err = krb_get_tf_realm(file, pr.realm);
+ if(err != KSUCCESS){
+ reply(500, "%s", krb_get_err_text(err));
+ return;
+ }
+
+ err = tf_init(file, R_TKT_FIL);
+ if(err != KSUCCESS){
+ reply(500, "%s", krb_get_err_text(err));
+ return;
+ }
+
+ err = tf_get_pname(pr.name);
+ if(err != KSUCCESS){
+ reply(500, "%s", krb_get_err_text(err));
+ return;
+ }
+ err = tf_get_pinst(pr.instance);
+ if(err != KSUCCESS){
+ reply(500, "%s", krb_get_err_text(err));
+ return;
+ }
+
+ /*
+ * You may think that this is the obvious place to get the
+ * realm of the ticket file, but it can't be done here as the
+ * routine to do this must open the ticket file. This is why
+ * it was done before tf_init.
+ */
+
+ lreply(200, "Ticket file: %s", tkt_string());
+
+ lreply(200, "Principal: %s", krb_unparse_name(&pr));
+ while ((err = tf_get_cred(&c)) == KSUCCESS) {
+ if (header) {
+ lreply(200, "%-15s %-15s %s",
+ " Issued", " Expires", " Principal (kvno)");
+ header = 0;
+ }
+ strlcpy(buf1, short_date(c.issue_date), sizeof(buf1));
+ c.issue_date = krb_life_to_time(c.issue_date, c.lifetime);
+ if (time(0) < (unsigned long) c.issue_date)
+ strlcpy(buf2, short_date(c.issue_date), sizeof(buf2));
+ else
+ strlcpy(buf2, ">>> Expired <<< ", sizeof(buf2));
+ lreply(200, "%s %s %s (%d)", buf1, buf2,
+ krb_unparse_name_long(c.service, c.instance, c.realm), c.kvno);
+ }
+ if (header && err == EOF) {
+ lreply(200, "No tickets in file.");
+ }
+ reply(200, " ");
+}
+
+/*
+ * Only destroy if we created the tickets
+ */
+
+void
+cond_kdestroy(void)
+{
+ if (do_destroy_tickets)
+ dest_tkt();
+ afsunlog();
+}
+
+void
+kdestroy(void)
+{
+ dest_tkt();
+ afsunlog();
+ reply(200, "Tickets destroyed");
+}
+
+void
+krbtkfile(const char *tkfile)
+{
+ do_destroy_tickets = 0;
+ krb_set_tkt_string(tkfile);
+ reply(200, "Using ticket file %s", tkfile);
+}
+
+void
+afslog(const char *cell)
+{
+ if(k_hasafs()) {
+ krb_afslog(cell, 0);
+ reply(200, "afslog done");
+ } else {
+ reply(200, "no AFS present");
+ }
+}
+
+void
+afsunlog(void)
+{
+ if(k_hasafs())
+ k_unlog();
+}
diff --git a/crypto/heimdal/appl/ftp/ftpd/logwtmp.c b/crypto/heimdal/appl/ftp/ftpd/logwtmp.c
new file mode 100644
index 0000000..019cc2d
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/logwtmp.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: logwtmp.c,v 1.14 1999/12/02 16:58:31 joda Exp $");
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#endif
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#include "extern.h"
+
+#ifndef WTMP_FILE
+#ifdef _PATH_WTMP
+#define WTMP_FILE _PATH_WTMP
+#else
+#define WTMP_FILE "/var/adm/wtmp"
+#endif
+#endif
+
+void
+ftpd_logwtmp(char *line, char *name, char *host)
+{
+ static int init = 0;
+ static int fd;
+#ifdef WTMPX_FILE
+ static int fdx;
+#endif
+ struct utmp ut;
+#ifdef WTMPX_FILE
+ struct utmpx utx;
+#endif
+
+ memset(&ut, 0, sizeof(struct utmp));
+#ifdef HAVE_STRUCT_UTMP_UT_TYPE
+ if(name[0])
+ ut.ut_type = USER_PROCESS;
+ else
+ ut.ut_type = DEAD_PROCESS;
+#endif
+ strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+#ifdef HAVE_STRUCT_UTMP_UT_PID
+ ut.ut_pid = getpid();
+#endif
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+ strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif
+ ut.ut_time = time(NULL);
+
+#ifdef WTMPX_FILE
+ strncpy(utx.ut_line, line, sizeof(utx.ut_line));
+ strncpy(utx.ut_user, name, sizeof(utx.ut_user));
+ strncpy(utx.ut_host, host, sizeof(utx.ut_host));
+#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
+ utx.ut_syslen = strlen(host) + 1;
+ if (utx.ut_syslen > sizeof(utx.ut_host))
+ utx.ut_syslen = sizeof(utx.ut_host);
+#endif
+ {
+ struct timeval tv;
+
+ gettimeofday (&tv, 0);
+ utx.ut_tv.tv_sec = tv.tv_sec;
+ utx.ut_tv.tv_usec = tv.tv_usec;
+ }
+
+ if(name[0])
+ utx.ut_type = USER_PROCESS;
+ else
+ utx.ut_type = DEAD_PROCESS;
+#endif
+
+ if(!init){
+ fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0);
+#ifdef WTMPX_FILE
+ fdx = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0);
+#endif
+ init = 1;
+ }
+ if(fd >= 0) {
+ write(fd, &ut, sizeof(struct utmp)); /* XXX */
+#ifdef WTMPX_FILE
+ write(fdx, &utx, sizeof(struct utmpx));
+#endif
+ }
+}
diff --git a/crypto/heimdal/appl/ftp/ftpd/ls.c b/crypto/heimdal/appl/ftp/ftpd/ls.c
new file mode 100644
index 0000000..2c85487
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/ls.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of KTH 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 KTH AND ITS 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 KTH OR ITS 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. */
+
+#include "ftpd_locl.h"
+
+RCSID("$Id: ls.c,v 1.14 2000/01/05 13:48:58 joda Exp $");
+
+struct fileinfo {
+ struct stat st;
+ int inode;
+ int bsize;
+ char mode[11];
+ int n_link;
+ char *user;
+ char *group;
+ char *size;
+ char *major;
+ char *minor;
+ char *date;
+ char *filename;
+ char *link;
+};
+
+static void
+free_fileinfo(struct fileinfo *f)
+{
+ free(f->user);
+ free(f->group);
+ free(f->size);
+ free(f->major);
+ free(f->minor);
+ free(f->date);
+ free(f->filename);
+ free(f->link);
+}
+
+#define LS_DIRS 1
+#define LS_IGNORE_DOT 2
+#define LS_SORT_MODE 12
+#define SORT_MODE(f) ((f) & LS_SORT_MODE)
+#define LS_SORT_NAME 4
+#define LS_SORT_MTIME 8
+#define LS_SORT_SIZE 12
+#define LS_SORT_REVERSE 16
+
+#define LS_SIZE 32
+#define LS_INODE 64
+
+#ifndef S_ISTXT
+#define S_ISTXT S_ISVTX
+#endif
+
+#ifndef S_ISSOCK
+#define S_ISSOCK(mode) (((mode) & _S_IFMT) == S_IFSOCK)
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(mode) (((mode) & _S_IFMT) == S_IFLNK)
+#endif
+
+static void
+make_fileinfo(const char *filename, struct fileinfo *file, int flags)
+{
+ char buf[128];
+ struct stat *st = &file->st;
+
+ file->inode = st->st_ino;
+#ifdef S_BLKSIZE
+ file->bsize = st->st_blocks * S_BLKSIZE / 1024;
+#else
+ file->bsize = st->st_blocks * 512 / 1024;
+#endif
+
+ if(S_ISDIR(st->st_mode))
+ file->mode[0] = 'd';
+ else if(S_ISCHR(st->st_mode))
+ file->mode[0] = 'c';
+ else if(S_ISBLK(st->st_mode))
+ file->mode[0] = 'b';
+ else if(S_ISREG(st->st_mode))
+ file->mode[0] = '-';
+ else if(S_ISFIFO(st->st_mode))
+ file->mode[0] = 'p';
+ else if(S_ISLNK(st->st_mode))
+ file->mode[0] = 'l';
+ else if(S_ISSOCK(st->st_mode))
+ file->mode[0] = 's';
+#ifdef S_ISWHT
+ else if(S_ISWHT(st->st_mode))
+ file->mode[0] = 'w';
+#endif
+ else
+ file->mode[0] = '?';
+ {
+ char *x[] = { "---", "--x", "-w-", "-wx",
+ "r--", "r-x", "rw-", "rwx" };
+ strcpy(file->mode + 1, x[(st->st_mode & S_IRWXU) >> 6]);
+ strcpy(file->mode + 4, x[(st->st_mode & S_IRWXG) >> 3]);
+ strcpy(file->mode + 7, x[(st->st_mode & S_IRWXO) >> 0]);
+ if((st->st_mode & S_ISUID)) {
+ if((st->st_mode & S_IXUSR))
+ file->mode[3] = 's';
+ else
+ file->mode[3] = 'S';
+ }
+ if((st->st_mode & S_ISGID)) {
+ if((st->st_mode & S_IXGRP))
+ file->mode[6] = 's';
+ else
+ file->mode[6] = 'S';
+ }
+ if((st->st_mode & S_ISTXT)) {
+ if((st->st_mode & S_IXOTH))
+ file->mode[9] = 't';
+ else
+ file->mode[9] = 'T';
+ }
+ }
+ file->n_link = st->st_nlink;
+ {
+ struct passwd *pwd;
+ pwd = getpwuid(st->st_uid);
+ if(pwd == NULL)
+ asprintf(&file->user, "%u", (unsigned)st->st_uid);
+ else
+ file->user = strdup(pwd->pw_name);
+ }
+ {
+ struct group *grp;
+ grp = getgrgid(st->st_gid);
+ if(grp == NULL)
+ asprintf(&file->group, "%u", (unsigned)st->st_gid);
+ else
+ file->group = strdup(grp->gr_name);
+ }
+
+ if(S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+#if defined(major) && defined(minor)
+ asprintf(&file->major, "%u", (unsigned)major(st->st_rdev));
+ asprintf(&file->minor, "%u", (unsigned)minor(st->st_rdev));
+#else
+ /* Don't want to use the DDI/DKI crap. */
+ asprintf(&file->major, "%u", (unsigned)st->st_rdev);
+ asprintf(&file->minor, "%u", 0);
+#endif
+ } else
+ asprintf(&file->size, "%lu", (unsigned long)st->st_size);
+
+ {
+ time_t t = time(NULL);
+ struct tm *tm = localtime(&st->st_mtime);
+ if((t - st->st_mtime > 6*30*24*60*60) ||
+ (st->st_mtime - t > 6*30*24*60*60))
+ strftime(buf, sizeof(buf), "%b %e %Y", tm);
+ else
+ strftime(buf, sizeof(buf), "%b %e %H:%M", tm);
+ file->date = strdup(buf);
+ }
+ {
+ const char *p = strrchr(filename, '/');
+ if(p)
+ p++;
+ else
+ p = filename;
+ file->filename = strdup(p);
+ }
+ if(S_ISLNK(st->st_mode)) {
+ int n;
+ n = readlink((char *)filename, buf, sizeof(buf));
+ if(n >= 0) {
+ buf[n] = '\0';
+ file->link = strdup(buf);
+ } else
+ warn("%s: readlink", filename);
+ }
+}
+
+static void
+print_file(FILE *out,
+ int flags,
+ struct fileinfo *f,
+ int max_inode,
+ int max_bsize,
+ int max_n_link,
+ int max_user,
+ int max_group,
+ int max_size,
+ int max_major,
+ int max_minor,
+ int max_date)
+{
+ if(f->filename == NULL)
+ return;
+
+ if(flags & LS_INODE) {
+ sec_fprintf2(out, "%*d", max_inode, f->inode);
+ sec_fprintf2(out, " ");
+ }
+ if(flags & LS_SIZE) {
+ sec_fprintf2(out, "%*d", max_bsize, f->bsize);
+ sec_fprintf2(out, " ");
+ }
+ sec_fprintf2(out, "%s", f->mode);
+ sec_fprintf2(out, " ");
+ sec_fprintf2(out, "%*d", max_n_link, f->n_link);
+ sec_fprintf2(out, " ");
+ sec_fprintf2(out, "%-*s", max_user, f->user);
+ sec_fprintf2(out, " ");
+ sec_fprintf2(out, "%-*s", max_group, f->group);
+ sec_fprintf2(out, " ");
+ if(f->major != NULL && f->minor != NULL)
+ sec_fprintf2(out, "%*s, %*s", max_major, f->major, max_minor, f->minor);
+ else
+ sec_fprintf2(out, "%*s", max_size, f->size);
+ sec_fprintf2(out, " ");
+ sec_fprintf2(out, "%*s", max_date, f->date);
+ sec_fprintf2(out, " ");
+ sec_fprintf2(out, "%s", f->filename);
+ if(f->link)
+ sec_fprintf2(out, " -> %s", f->link);
+ sec_fprintf2(out, "\r\n");
+}
+
+static int
+compare_filename(struct fileinfo *a, struct fileinfo *b)
+{
+ if(a->filename == NULL)
+ return 1;
+ if(b->filename == NULL)
+ return -1;
+ return strcmp(a->filename, b->filename);
+}
+
+static int
+compare_mtime(struct fileinfo *a, struct fileinfo *b)
+{
+ if(a->filename == NULL)
+ return 1;
+ if(b->filename == NULL)
+ return -1;
+ return a->st.st_mtime - b->st.st_mtime;
+}
+
+static int
+compare_size(struct fileinfo *a, struct fileinfo *b)
+{
+ if(a->filename == NULL)
+ return 1;
+ if(b->filename == NULL)
+ return -1;
+ return a->st.st_size - b->st.st_size;
+}
+
+static void
+list_dir(FILE *out, const char *directory, int flags);
+
+static int
+log10(int num)
+{
+ int i = 1;
+ while(num > 10) {
+ i++;
+ num /= 10;
+ }
+ return i;
+}
+
+/*
+ * Operate as lstat but fake up entries for AFS mount points so we don't
+ * have to fetch them.
+ */
+
+static int
+lstat_file (const char *file, struct stat *sb)
+{
+#ifdef KRB4
+ if (k_hasafs()
+ && strcmp(file, ".")
+ && strcmp(file, ".."))
+ {
+ struct ViceIoctl a_params;
+ char *last;
+ char *path_bkp;
+ static ino_t ino_counter = 0, ino_last = 0;
+ int ret;
+ const int maxsize = 2048;
+
+ path_bkp = strdup (file);
+ if (path_bkp == NULL)
+ return -1;
+
+ a_params.out = malloc (maxsize);
+ if (a_params.out == NULL) {
+ free (path_bkp);
+ return -1;
+ }
+
+ /* If path contains more than the filename alone - split it */
+
+ last = strrchr (path_bkp, '/');
+ if (last != NULL) {
+ *last = '\0';
+ a_params.in = last + 1;
+ } else
+ a_params.in = (char *)file;
+
+ a_params.in_size = strlen (a_params.in) + 1;
+ a_params.out_size = maxsize;
+
+ ret = k_pioctl (last ? path_bkp : "." ,
+ VIOC_AFS_STAT_MT_PT, &a_params, 0);
+ free (a_params.out);
+ if (ret < 0) {
+ free (path_bkp);
+
+ if (errno != EINVAL)
+ return ret;
+ else
+ /* if we get EINVAL this is probably not a mountpoint */
+ return lstat (file, sb);
+ }
+
+ /*
+ * wow this was a mountpoint, lets cook the struct stat
+ * use . as a prototype
+ */
+
+ ret = lstat (path_bkp, sb);
+ free (path_bkp);
+ if (ret < 0)
+ return ret;
+
+ if (ino_last == sb->st_ino)
+ ino_counter++;
+ else {
+ ino_last = sb->st_ino;
+ ino_counter = 0;
+ }
+ sb->st_ino += ino_counter;
+ sb->st_nlink = 3;
+
+ return 0;
+ }
+#endif /* KRB4 */
+ return lstat (file, sb);
+}
+
+static void
+list_files(FILE *out, const char **files, int n_files, int flags)
+{
+ struct fileinfo *fi;
+ int i;
+
+ fi = calloc(n_files, sizeof(*fi));
+ if (fi == NULL) {
+ sec_fprintf2(out, "ouf of memory\r\n");
+ return;
+ }
+ for(i = 0; i < n_files; i++) {
+ if(lstat_file(files[i], &fi[i].st) < 0) {
+ sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno));
+ fi[i].filename = NULL;
+ } else {
+ if((flags & LS_DIRS) == 0 && S_ISDIR(fi[i].st.st_mode)) {
+ if(n_files > 1)
+ sec_fprintf2(out, "%s:\r\n", files[i]);
+ list_dir(out, files[i], flags);
+ } else {
+ make_fileinfo(files[i], &fi[i], flags);
+ }
+ }
+ }
+ switch(SORT_MODE(flags)) {
+ case LS_SORT_NAME:
+ qsort(fi, n_files, sizeof(*fi),
+ (int (*)(const void*, const void*))compare_filename);
+ break;
+ case LS_SORT_MTIME:
+ qsort(fi, n_files, sizeof(*fi),
+ (int (*)(const void*, const void*))compare_mtime);
+ break;
+ case LS_SORT_SIZE:
+ qsort(fi, n_files, sizeof(*fi),
+ (int (*)(const void*, const void*))compare_size);
+ break;
+ }
+ {
+ int max_inode = 0;
+ int max_bsize = 0;
+ int max_n_link = 0;
+ int max_user = 0;
+ int max_group = 0;
+ int max_size = 0;
+ int max_major = 0;
+ int max_minor = 0;
+ int max_date = 0;
+ for(i = 0; i < n_files; i++) {
+ if(fi[i].filename == NULL)
+ continue;
+ if(fi[i].inode > max_inode)
+ max_inode = fi[i].inode;
+ if(fi[i].bsize > max_bsize)
+ max_bsize = fi[i].bsize;
+ if(fi[i].n_link > max_n_link)
+ max_n_link = fi[i].n_link;
+ if(strlen(fi[i].user) > max_user)
+ max_user = strlen(fi[i].user);
+ if(strlen(fi[i].group) > max_group)
+ max_group = strlen(fi[i].group);
+ if(fi[i].major != NULL && strlen(fi[i].major) > max_major)
+ max_major = strlen(fi[i].major);
+ if(fi[i].minor != NULL && strlen(fi[i].minor) > max_minor)
+ max_minor = strlen(fi[i].minor);
+ if(fi[i].size != NULL && strlen(fi[i].size) > max_size)
+ max_size = strlen(fi[i].size);
+ if(strlen(fi[i].date) > max_date)
+ max_date = strlen(fi[i].date);
+ }
+ if(max_size < max_major + max_minor + 2)
+ max_size = max_major + max_minor + 2;
+ else if(max_size - max_minor - 2 > max_major)
+ max_major = max_size - max_minor - 2;
+ max_inode = log10(max_inode);
+ max_bsize = log10(max_bsize);
+ max_n_link = log10(max_n_link);
+
+ if(flags & LS_SORT_REVERSE)
+ for(i = n_files - 1; i >= 0; i--)
+ print_file(out,
+ flags,
+ &fi[i],
+ max_inode,
+ max_bsize,
+ max_n_link,
+ max_user,
+ max_group,
+ max_size,
+ max_major,
+ max_minor,
+ max_date);
+ else
+ for(i = 0; i < n_files; i++)
+ print_file(out,
+ flags,
+ &fi[i],
+ max_inode,
+ max_bsize,
+ max_n_link,
+ max_user,
+ max_group,
+ max_size,
+ max_major,
+ max_minor,
+ max_date);
+ for(i = 0; i < n_files; i++)
+ free_fileinfo(&fi[i]);
+ free(fi);
+ }
+}
+
+static void
+free_files (char **files, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ free (files[i]);
+ free (files);
+}
+
+static void
+list_dir(FILE *out, const char *directory, int flags)
+{
+ DIR *d = opendir(directory);
+ struct dirent *ent;
+ char **files = NULL;
+ int n_files = 0;
+
+ if(d == NULL) {
+ sec_fprintf2(out, "%s: %s\r\n", directory, strerror(errno));
+ return;
+ }
+ while((ent = readdir(d)) != NULL) {
+ void *tmp;
+
+ if(ent->d_name[0] == '.') {
+ if (flags & LS_IGNORE_DOT)
+ continue;
+ if (ent->d_name[1] == 0) /* Ignore . */
+ continue;
+ if (ent->d_name[1] == '.' && ent->d_name[2] == 0) /* Ignore .. */
+ continue;
+ }
+ tmp = realloc(files, (n_files + 1) * sizeof(*files));
+ if (tmp == NULL) {
+ sec_fprintf2(out, "%s: out of memory\r\n", directory);
+ free_files (files, n_files);
+ closedir (d);
+ return;
+ }
+ files = tmp;
+ asprintf(&files[n_files], "%s/%s", directory, ent->d_name);
+ if (files[n_files] == NULL) {
+ sec_fprintf2(out, "%s: out of memory\r\n", directory);
+ free_files (files, n_files);
+ closedir (d);
+ return;
+ }
+ ++n_files;
+ }
+ closedir(d);
+ list_files(out, (const char**)files, n_files, flags | LS_DIRS);
+}
+
+void
+builtin_ls(FILE *out, const char *file)
+{
+ int flags = LS_SORT_NAME;
+
+ if(*file == '-') {
+ const char *p;
+ for(p = file + 1; *p; p++) {
+ switch(*p) {
+ case 'a':
+ case 'A':
+ flags &= ~LS_IGNORE_DOT;
+ break;
+ case 'C':
+ break;
+ case 'd':
+ flags |= LS_DIRS;
+ break;
+ case 'f':
+ flags = (flags & ~LS_SORT_MODE);
+ break;
+ case 'i':
+ flags |= flags | LS_INODE;
+ break;
+ case 'l':
+ break;
+ case 't':
+ flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME;
+ break;
+ case 's':
+ flags |= LS_SIZE;
+ break;
+ case 'S':
+ flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE;
+ break;
+ case 'r':
+ flags |= LS_SORT_REVERSE;
+ break;
+ }
+ }
+ file = ".";
+ }
+ list_files(out, &file, 1, flags);
+ sec_fflush(out);
+}
diff --git a/crypto/heimdal/appl/ftp/ftpd/pathnames.h b/crypto/heimdal/appl/ftp/ftpd/pathnames.h
new file mode 100644
index 0000000..ff2041b
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/pathnames.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ */
+
+#ifdef HAVE_PATHS_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"
+#define _PATH_FTPWELCOME "/etc/ftpwelcome"
+#define _PATH_FTPLOGINMESG "/etc/motd"
+
+#define _PATH_ISSUE "/etc/issue"
+#define _PATH_ISSUE_NET "/etc/issue.net"
diff --git a/crypto/heimdal/appl/ftp/ftpd/popen.c b/crypto/heimdal/appl/ftp/ftpd/popen.c
new file mode 100644
index 0000000..5f36813
--- /dev/null
+++ b/crypto/heimdal/appl/ftp/ftpd/popen.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: popen.c,v 1.19 1999/09/16 20:38:45 assar Exp $");
+#endif
+
+#include <sys/types.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <glob.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#include <roken.h>
+
+/*
+ * Special version of popen which avoids call to shell. This ensures
+ * no one may create a pipe to a hidden program as a side effect of a
+ * list or dir command.
+ */
+static int *pids;
+static int fds;
+
+extern int dochroot;
+
+/* return path prepended with ~ftp if that file exists, otherwise
+ * return path unchanged
+ */
+
+const char *
+ftp_rooted(const char *path)
+{
+ static char home[MaxPathLen] = "";
+ static char newpath[MaxPathLen];
+ struct passwd *pwd;
+
+ if(!home[0])
+ if((pwd = k_getpwnam("ftp")))
+ strlcpy(home, pwd->pw_dir, sizeof(home));
+ snprintf(newpath, sizeof(newpath), "%s/%s", home, path);
+ if(access(newpath, X_OK))
+ strlcpy(newpath, path, sizeof(newpath));
+ return newpath;
+}
+
+
+FILE *
+ftpd_popen(char *program, char *type, int do_stderr, int no_glob)
+{
+ char *cp;
+ FILE *iop;
+ int argc, gargc, pdes[2], pid;
+ char **pop, *argv[100], *gargv[1000];
+ char *foo;
+
+ if (strcmp(type, "r") && strcmp(type, "w"))
+ return (NULL);
+
+ if (!pids) {
+
+ /* This function is ugly and should be rewritten, in
+ * modern unices there is no such thing as a maximum
+ * filedescriptor.
+ */
+
+ fds = getdtablesize();
+ pids = (int*)calloc(fds, sizeof(int));
+ if(!pids)
+ return NULL;
+ }
+ if (pipe(pdes) < 0)
+ return (NULL);
+
+ /* break up string into pieces */
+ foo = NULL;
+ for (argc = 0, cp = program;; cp = NULL) {
+ if (!(argv[argc++] = strtok_r(cp, " \t\n", &foo)))
+ break;
+ }
+
+ gargv[0] = (char*)ftp_rooted(argv[0]);
+ /* glob each piece */
+ for (gargc = argc = 1; argv[argc]; argc++) {
+ glob_t gl;
+ int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
+
+ memset(&gl, 0, sizeof(gl));
+ if (no_glob || glob(argv[argc], flags, NULL, &gl))
+ gargv[gargc++] = strdup(argv[argc]);
+ else
+ for (pop = gl.gl_pathv; *pop; pop++)
+ gargv[gargc++] = strdup(*pop);
+ globfree(&gl);
+ }
+ gargv[gargc] = NULL;
+
+ iop = NULL;
+ switch(pid = fork()) {
+ case -1: /* error */
+ close(pdes[0]);
+ close(pdes[1]);
+ goto pfree;
+ /* NOTREACHED */
+ case 0: /* child */
+ if (*type == 'r') {
+ if (pdes[1] != STDOUT_FILENO) {
+ dup2(pdes[1], STDOUT_FILENO);
+ close(pdes[1]);
+ }
+ if(do_stderr)
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ close(pdes[0]);
+ } else {
+ if (pdes[0] != STDIN_FILENO) {
+ dup2(pdes[0], STDIN_FILENO);
+ close(pdes[0]);
+ }
+ close(pdes[1]);
+ }
+ execv(gargv[0], gargv);
+ gargv[0] = argv[0];
+ execv(gargv[0], gargv);
+ _exit(1);
+ }
+ /* parent; assume fdopen can't fail... */
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
+ close(pdes[1]);
+ } else {
+ iop = fdopen(pdes[1], type);
+ close(pdes[0]);
+ }
+ pids[fileno(iop)] = pid;
+
+pfree:
+ for (argc = 1; gargv[argc] != NULL; argc++)
+ free(gargv[argc]);
+
+
+ return (iop);
+}
+
+int
+ftpd_pclose(FILE *iop)
+{
+ int fdes, status;
+ pid_t pid;
+ sigset_t sigset, osigset;
+
+ /*
+ * pclose returns -1 if stream is not associated with a
+ * `popened' command, or, if already `pclosed'.
+ */
+ if (pids == 0 || pids[fdes = fileno(iop)] == 0)
+ return (-1);
+ fclose(iop);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGINT);
+ sigaddset(&sigset, SIGQUIT);
+ sigaddset(&sigset, SIGHUP);
+ sigprocmask(SIG_BLOCK, &sigset, &osigset);
+ while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
+ continue;
+ sigprocmask(SIG_SETMASK, &osigset, NULL);
+ pids[fdes] = 0;
+ if (pid < 0)
+ return (pid);
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ return (1);
+}
OpenPOWER on IntegriCloud