diff options
Diffstat (limited to 'crypto/heimdal/appl/ftp/ftpd')
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/Makefile.am | 56 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/Makefile.in | 768 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/extern.h | 160 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ftpcmd.y | 1455 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ftpd.8 | 473 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ftpd.c | 2249 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ftpd_locl.h | 170 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ftpusers.5 | 38 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/gss_userok.c | 69 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/kauth.c | 365 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/logwtmp.c | 137 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ls.c | 588 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/pathnames.h | 58 | ||||
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/popen.c | 224 |
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); +} |