Compare commits

..

No commits in common. "master" and "tftp-hpa-0.42" have entirely different histories.

67 changed files with 3612 additions and 5439 deletions

View file

@ -1,11 +0,0 @@
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[{*.c,*.h}]
indent_style = space
indent_size = 4
tab_width = 8

21
.gitignore vendored
View file

@ -1,21 +0,0 @@
/config/MCONFIG
/config/config.h
/config/config.h.in
/autoconf/aclocal.m4
/autoconf/clean.sh
/autoconf/helpers/
/autom4te.cache
/config.log
/config.status
/configure
/version.h
/tftp/tftp
/tftpd/tftpd
*.1
*.8
*.a
*.o
*.i
*.s
*~
\#*

75
CHANGES
View file

@ -1,78 +1,3 @@
Changes in 5.2:
Fix breakage on newer Linux when a single interface has
multiple IP addresses.
Changes in 5.1:
Add -P option to write a PID file. Patch by Ferenc Wagner.
Bounce the syslog socket in standalone mode, in case the
syslog daemon has been restarted. Patch by Ferenc Wagner.
Build fixes.
Fix handling of block number wraparound after a successful
options negotiation.
Fix a buffer overflow in option parsing.
Changes in 5.0:
Try to on platforms with getaddrinfo() without AI_ADDRCONFIG or
AI_CANONNAME.
Implement the "rollover" option, for clients which want block
number to rollover to anything other than zero.
Correctly disable PMTU in standalone mode. Patch by Florian
Lohoff.
Changes in 0.49:
Add IPv6 support. Patch by Karsten Keil.
Support systems with editline instead of readline.
Support long options in the server.
Changes in 0.48:
Unbreak -l -s in the server, which was broken in 0.47.
Changes in 0.47:
Add -L option to the server to run standalone without
detaching from the shell.
Parallel make fix.
Changes in 0.46:
Minor portability improvements.
Changes in 0.45:
Add -l (literal) option to the client, to override the special
treatment of the colon (:) character as a hostname separator.
Changes in 0.44:
Allow the client to specify a range of local port numbers,
just like the server can.
Fix sending SIGHUP to update the regular expression table.
Changes in 0.43:
Fix double-free error on ^c in client.
Try to deal with clients that send TFTP requests to broadcasts
(apparently some recent Sun boxes do this instead of using the
address told by DHCP. Bad Sun! Bad Sun!)
Portability fixes.
Changes in 0.42: Changes in 0.42:
Try to disable path MTU discovery for TFTP connections (it's Try to disable path MTU discovery for TFTP connections (it's
useless anyway.) useless anyway.)

View file

@ -1,3 +1,5 @@
$Id$
Specific installation instructions Specific installation instructions
================================== ==================================

View file

@ -1,12 +1,13 @@
## -*- makefile -*- ------------------------------------------------------ ## -*- makefile -*- ------------------------------------------------------
## ##
## Copyright 2001-2007 H. Peter Anvin - All Rights Reserved ## Copyright 2001 H. Peter Anvin - All Rights Reserved
## ##
## This program is free software available under the same license ## This program is free software available under the same license
## as the "OpenBSD" operating system, distributed at ## as the "OpenBSD" operating system, distributed at
## http://www.openbsd.org/. ## http://www.openbsd.org/.
## ##
## ----------------------------------------------------------------------- ## -----------------------------------------------------------------------
## $Id$
## ##
## MCONFIG.in ## MCONFIG.in
@ -31,9 +32,6 @@ MANDIR = @mandir@
# System binaries # System binaries
SBINDIR = @sbindir@ SBINDIR = @sbindir@
# Data root directory
datarootdir = @datarootdir@
# Binary suffixes # Binary suffixes
O = @OBJEXT@ O = @OBJEXT@
X = @EXEEXT@ X = @EXEEXT@
@ -57,8 +55,8 @@ CFLAGS = @CFLAGS@ -I$(SRCROOT)
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
# Libraries (client and server) # Libraries (client and server)
TFTP_LIBS = ../common/libcommon.a @TFTP_LIBS@ TFTP_LIBS = @TFTP_LIBS@
TFTPD_LIBS = ../common/libcommon.a @TFTPD_LIBS@ TFTPD_LIBS = @TFTPD_LIBS@
# Additional library we need to build # Additional library we need to build
LIBOBJS = @LIBOBJS@ LIBOBJS = @LIBOBJS@

View file

@ -1,12 +1,12 @@
# You can do "make SUB=blah" to make only a few, or edit here, or both # You can do "make SUB=blah" to make only a few, or edit here, or both
# You can also run make directly in the subdirs you want. # You can also run make directly in the subdirs you want.
SUB = lib common tftp tftpd SUB = lib tftp tftpd
%.build: config/MCONFIG config/config.h version.h %.build: MCONFIG aconfig.h version.h
$(MAKE) -C $(patsubst %.build, %, $@) $(MAKE) -C $(patsubst %.build, %, $@)
%.install: config/MCONFIG config/config.h version.h %.install: MCONFIG aconfig.h version.h
$(MAKE) -C $(patsubst %.install, %, $@) install $(MAKE) -C $(patsubst %.install, %, $@) install
%.clean: %.clean:
@ -15,12 +15,12 @@ SUB = lib common tftp tftpd
%.distclean: %.distclean:
$(MAKE) -C $(patsubst %.distclean, %, $@) distclean $(MAKE) -C $(patsubst %.distclean, %, $@) distclean
all: config/MCONFIG $(patsubst %, %.build, $(SUB)) all: MCONFIG $(patsubst %, %.build, $(SUB))
tftp.build: lib.build common.build tftp.build: lib.build
tftpd.build: lib.build common.build tftpd.build: lib.build
install: config/MCONFIG $(patsubst %, %.install, $(SUB)) install: MCONFIG $(patsubst %, %.install, $(SUB))
clean: localclean $(patsubst %, %.clean, $(SUB)) clean: localclean $(patsubst %, %.clean, $(SUB))
@ -30,40 +30,46 @@ localclean:
distclean: localdistclean $(patsubst %, %.distclean, $(SUB)) distclean: localdistclean $(patsubst %, %.distclean, $(SUB))
localdistclean: localclean localdistclean: localclean
rm -f config/config/MCONFIG config.status config.log config/config.h *~ \#* rm -f MCONFIG config.status config.log aconfig.h *~ \#*
rm -rf *.cache rm -rf *.cache
find . -type f \( -name \*.orig -o -name \*.rej \) | xargs rm -f find . -type f \( -name \*.orig -o -name \*.rej \) | xargs rm -f
spotless: distclean spotless: distclean
rm -f configure config/config.h.in tftp.spec rm -f configure aconfig.h.in tftp.spec
autoconf: configure config/config.h.in autoconf: configure aconfig.h.in
config: config/MCONFIG config/config.h config: MCONFIG aconfig.h
release: release:
$(MAKE) autoconf $(MAKE) autoconf
$(MAKE) tftp.spec $(MAKE) tftp.spec
$(MAKE) distclean $(MAKE) distclean
config/MCONFIG: configure config/MCONFIG.in config/config.h.in MCONFIG: configure MCONFIG.in aconfig.h.in
if test -x config.status; then \ if test -x config.status; then \
./config.status --recheck && ./config.status ; \ ./config.status --recheck && ./config.status ; \
else \ else \
./configure ; \ ./configure ; \
fi fi
config/config.h: config/MCONFIG aconfig.h: MCONFIG
: Generated by side effect : Generated by side effect
configure: configure.ac # Adding "configure" to the dependencies serializes this with running
sh autogen.sh # autoconf, because there are apparently race conditions between
# autoconf and autoheader.
aconfig.h.in: configure.in configure aclocal.m4
rm -f aconfig.h.in aconfig.h
autoheader
config/config.h.in: configure configure: configure.in aclocal.m4
: Generated by side effect rm -rf MCONFIG configure config.log aconfig.h *.cache
autoconf
version.h: version version.h: version
echo \#define VERSION \"tftp-hpa `cat version`\" > version.h echo \#define VERSION \"tftp-hpa `cat version`\" > version.h
tftp.spec: tftp.spec.in version tftp.spec: tftp.spec.in version
sed -e "s/@@VERSION@@/`cat version`/g" < $< > $@ || rm -f $@ sed -e "s/@@VERSION@@/`cat version`/g" < $< > $@ || rm -f $@

View file

@ -1,3 +1,7 @@
$Id$
=======================================
Starting in version 0.27, tftp-hpa has the option of a "use Unix Starting in version 0.27, tftp-hpa has the option of a "use Unix
permissions" mode. In this mode, tftpd can access any file accessible permissions" mode. In this mode, tftpd can access any file accessible
by the tftpd effective user, specified via the -u option. This means by the tftpd effective user, specified via the -u option. This means

206
aclocal.m4 vendored Normal file
View file

@ -0,0 +1,206 @@
dnl $Id$
dnl -----------------------------------------------------------------------
dnl
dnl Copyright 1999-2002 H. Peter Anvin - All Rights Reserved
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation, Inc., 53 Temple Place Ste 330,
dnl Bostom MA 02111-1307, USA; either version 2 of the License, or
dnl (at your option) any later version; incorporated herein by reference.
dnl
dnl -----------------------------------------------------------------------
dnl --------------------------------------------------------------------------
dnl PA_ADD_CFLAGS()
dnl
dnl Attempt to add the given option to CFLAGS, if it doesn't break compilation
dnl --------------------------------------------------------------------------
AC_DEFUN(PA_ADD_CFLAGS,
[AC_MSG_CHECKING([if $CC accepts $1])
pa_add_cflags__old_cflags="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_TRY_LINK([#include <stdio.h>],
[printf("Hello, World!\n");],
AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no])
CFLAGS="$pa_add_cflags__old_cflags")])
dnl --------------------------------------------------------------------------
dnl PA_SIGSETJMP
dnl
dnl Do we have sigsetjmp/siglongjmp? (AC_CHECK_FUNCS doesn't seem to work
dnl for these particular functions.)
dnl --------------------------------------------------------------------------
AC_DEFUN(PA_SIGSETJMP,
[AC_MSG_CHECKING([for sigsetjmp])
AC_TRY_LINK([
#ifdef HAVE_SETJMP_H
#include <setjmp.h>
#endif],
[sigjmp_buf buf;
sigsetjmp(buf,1);
siglongjmp(buf,2);],
AC_MSG_RESULT([yes])
$1,
AC_MSG_RESULT([no])
$2)])
dnl --------------------------------------------------------------------------
dnl PA_MSGHDR_MSG_CONTROL
dnl
dnl Does struct msghdr have the msg_control field?
dnl --------------------------------------------------------------------------
AH_TEMPLATE([HAVE_MSGHDR_MSG_CONTROL],
[Define if struct msghdr has the msg_control field.])
AC_DEFUN(PA_MSGHDR_MSG_CONTROL,
[AC_CHECK_MEMBER(struct msghdr.msg_control,
[AC_DEFINE(HAVE_MSGHDR_MSG_CONTROL)],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
])])
dnl ------------------------------------------------------------------------
dnl PA_STRUCT_IN_PKTINFO
dnl
dnl Look for definition of struct in_pktinfo, which at least has an
dnl ipi_addr member. Some versions of glibc lack struct in_pktinfo;
dnl if so we need to include the definition ourselves -- but we only
dnl want to do that if absolutely necessary!
dnl
dnl We don't use AC_CHECK_MEMBER() here, since at least in autoconf 2.52
dnl this is broken for a member of structure type.
dnl ------------------------------------------------------------------------
AH_TEMPLATE([HAVE_STRUCT_IN_PKTINFO],
[Define if struct in_pktinfo is defined.])
AC_DEFUN(PA_STRUCT_IN_PKTINFO,
[AC_MSG_CHECKING([for definition of struct in_pktinfo])
AC_TRY_COMPILE(
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/uio.h>
],
[
struct in_pktinfo pktinfo;
int foo = sizeof(struct in_pktinfo);
void *quux = (void *)(&pktinfo.ipi_addr);
],
[
AC_DEFINE(HAVE_STRUCT_IN_PKTINFO)
AC_MSG_RESULT(yes)
],
[
AC_MSG_RESULT(no)
])])
dnl --------------------------------------------------------------------------
dnl PA_HAVE_TCPWRAPPERS
dnl
dnl Do we have the tcpwrappers -lwrap? This can't be done using AC_CHECK_LIBS
dnl due to the need to provide "allow_severity" and "deny_severity" variables
dnl --------------------------------------------------------------------------
AH_TEMPLATE([HAVE_TCPWRAPPERS],
[Define if we have tcpwrappers (-lwrap) and <tcpd.h>.])
AC_DEFUN(PA_HAVE_TCPWRAPPERS,
[AC_CHECK_LIB([wrap], [main])
AC_MSG_CHECKING([for tcpwrappers])
AC_TRY_LINK(
[
#include <tcpd.h>
int allow_severity = 0;
int deny_severity = 0;
],
[
hosts_ctl("sample_daemon", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN);
],
[
AC_DEFINE(HAVE_TCPWRAPPERS)
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
])])
dnl ------------------------------------------------------------------------
dnl PA_CHECK_INTTYPES_H_SANE
dnl
dnl At least some versions of AIX 4 have <inttypes.h> macros which are
dnl completely broken. Try to detect those.
dnl --------------------------------------------------------------------------
AH_TEMPLATE([INTTYPES_H_IS_SANE],
[Define if the macros in <inttypes.h> are usable])
AC_DEFUN(PA_CHECK_INTTYPES_H_SANE,
[AC_CHECK_HEADERS(inttypes.h,
[
AC_MSG_CHECKING([if inttypes.h is sane])
AC_TRY_LINK(
[
#include <inttypes.h>
#include <stdio.h>
],
[uintmax_t max = UINTMAX_C(0);
printf("%"PRIuMAX"\n", max);],
AC_MSG_RESULT([yes])
AC_DEFINE(INTTYPES_H_IS_SANE),
AC_MSG_RESULT([no (AIX, eh?)]))
])
])
dnl ------------------------------------------------------------------------
dnl PA_WITH_BOOL
dnl
dnl PA_WITH_BOOL(option, default, help, enable, disable)
dnl
dnl Provides a more convenient way to specify --with-option and
dnl --without-option, with a default. default should be either 0 or 1.
dnl ------------------------------------------------------------------------
AC_DEFUN(PA_WITH_BOOL,
[AC_ARG_WITH([$1], [$3],
if test ["$withval"] != no; then
[$4]
else
[$5]
fi,
if test [$2] -ne 0; then
[$4]
else
[$5]
fi)])
dnl --------------------------------------------------------------------------
dnl PA_HEADER_DEFINES
dnl
dnl PA_HEADER_DEFINES(header, type, value)
dnl --------------------------------------------------------------------------
AC_DEFUN(PA_HEADER_DEFINES,
[AC_MSG_CHECKING([if $1 defines $3])
AH_TEMPLATE([HAVE_$3_DEFINITION], [Define if $1 defines $3])
AC_TRY_COMPILE([
#include <$1>
],
[
int main()
{
$2 dummy = $3;
return 0;
}
],
[
pa_header_define=`echo HAVE_$3_DEFINITION | tr '[a-z]' '[A-Z]'`
AC_DEFINE_UNQUOTED($pa_header_define)
AC_MSG_RESULT(yes)
],
[
AC_MSG_RESULT(no)
])])

View file

@ -1,9 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_CFLAGS(variable, flag [,actual_flag [,success [,failure]]]])
dnl
dnl Attempt to add the given option to xFLAGS, if it doesn't break
dnl compilation. If the option to be tested is different than the
dnl option that should actually be added, add the option to be
dnl actually added as a second argument.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_ADD_CFLAGS], [PA_ADD_FLAGS(CFLAGS, [$1], [$2], [$3], [$4])])

View file

@ -1,39 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_FLAGS(flagvar, flags)
dnl
dnl Add [flags] to the variable [flagvar] if and only if it is accepted
dnl by all languages affected by [flagvar], if those languages have
dnl been previously seen in the script.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_ADD_FLAGS],
[
AS_VAR_PUSHDEF([old], [_$0_$1_orig])
AS_VAR_PUSHDEF([ok], [_$0_$1_ok])
AS_VAR_PUSHDEF([flags], [$1])
AS_VAR_COPY([old], [flags])
AS_VAR_SET([flags], ["$flags $2"])
AS_VAR_SET([ok], [yes])
PA_LANG_FOREACH(PA_FLAGS_LANGLIST($1),
[AS_VAR_IF([ok], [yes],
[AC_MSG_CHECKING([if $]_AC_CC[ accepts $2])
PA_BUILD_IFELSE([],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AS_VAR_SET([ok], [no])])])
])
AS_VAR_IF([ok], [yes],
[m4_ifnblank([$3],[AS_VAR_SET([flags], ["$old $3"])])
m4_foreach_w([_pa_add_flags_flag], [m4_ifblank([$3],[$2],[$3])],
[AC_DEFINE(PA_SYM([$1_]_pa_add_flags_flag), 1,
[Define to 1 if compiled with the ]_pa_add_flags_flag[ compiler flag])])
$4],
[AS_VAR_SET([flags], ["$old"])
$5])
AS_VAR_POPDEF([flags])
AS_VAR_POPDEF([ok])
AS_VAR_POPDEF([old])
])

View file

@ -1,13 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_HEADERS(headers...)
dnl
dnl Call AC_CHECK_HEADERS(), and add to ac_includes_default if found
dnl --------------------------------------------------------------------------
AC_DEFUN([_PA_ADD_HEADER],
[AC_CHECK_HEADERS([$1],[ac_includes_default="$ac_includes_default
#include <$1>"
])
])
AC_DEFUN([PA_ADD_HEADERS],
[m4_map_args_w([$1],[_PA_ADD_HEADER(],[)])])

View file

@ -1,27 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_LANGFLAGS(flag...)
dnl
dnl Attempt to add the option in the given list to each compiler flags
dnl (CFLAGS, CXXFLAGS, ...), if it doesn't break compilation.
dnl --------------------------------------------------------------------------
m4_defun([_PA_LANGFLAG_VAR],
[m4_case([$1],
[C], [CFLAGS],
[C++], [CXXFLAGS],
[Fortran 77], [FFLAGS],
[Fortran], [FCFLAGS],
[Erlang], [ERLCFLAGS],
[Objective C], [OBJCFLAGS],
[Objective C++], [OBJCXXFLAGS],
[Go], [GOFLAGS],
[m4_fatal([PA_ADD_LANGFLAGS: Unknown language: $1])])])
AC_DEFUN([PA_ADD_LANGFLAGS],
[m4_pushdef([_pa_langflags],m4_dquote($1))dnl
m4_set_foreach(_PA_LANG_SEEN_SET,[_pa_lang],dnl
[_pa_flag_found=no
m4_foreach_w([_pa_flag], _pa_langflags,
[AS_IF([test $_pa_flag_found = no],
[PA_ADD_FLAGS(_PA_LANGFLAG_VAR(_pa_lang),_pa_flag,[],[_pa_flag_found=yes])])
])])
m4_popdef([_pa_langflags])])

View file

@ -1,19 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ARG_BOOL(option,helptext,default,enabled_action,disabled_action)
dnl
dnl The last three arguments are optional; default can be yes or no.
dnl
dnl Simpler-to-use versions of AC_ARG_ENABLED, that include the
dnl test for $enableval and the AS_HELP_STRING definition. This is only
dnl to be used for boolean options.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_ARG_BOOL],
[m4_pushdef([pa_default],m4_default(m4_normalize([$3]),[no]))
m4_pushdef([pa_option],m4_case(pa_default,[yes],[disable],[enable]))
AC_ARG_ENABLE([$1],
[AS_HELP_STRING([--]m4_defn([pa_option])[-$1],[$2])],
[pa_arg_bool_enableval="$enableval"],
[pa_arg_bool_enableval="]m4_defn([pa_default])["])
m4_popdef([pa_option], [pa_default])
AS_IF([test x"$pa_arg_bool_enableval" != xno], [$4], [$5])
])

View file

@ -1,4 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ARG_DISABLED(option,helptext,disabled_action,enabled_action)
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_ARG_DISABLED],[PA_ARG_BOOL([$1],[$2],yes,[$4],[$3])])

View file

@ -1,4 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_ARG_ENABLED(option,helptext,enabled_action,disabled_action)
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_ARG_ENABLED],[PA_ARG_BOOL([$1],[$2],no,[$3],[$4])])

View file

@ -1,16 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_BUILD_IFELSE(input [,success [,failure]])
dnl
dnl Same as AC_LINK_IFELSE for languages where linking is applicable,
dnl otherwise AC_COMPILE_IFELSE.
dnl
dnl If the first argument is empty, use _AC_LANG_IO_PROGRAM.
dnl --------------------------------------------------------------------------
m4_defun([_PA_BUILD_IFELSE],
[m4_case(_AC_LANG,
[Erlang], [AC_COMPILE_IFELSE($@)],
[AC_LINK_IFELSE($@)])])
AC_DEFUN([PA_BUILD_IFELSE],
[_PA_BUILD_IFELSE([m4_ifblank([$1],[AC_LANG_SOURCE(_AC_LANG_IO_PROGRAM)],
[$1])],[$2],[$3])])

View file

@ -1,32 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_C_TYPEOF
dnl
dnl Find if typeof() exists, or an equivalent (__typeof__, decltype,
dnl __decltype__)
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_C_TYPEOF],
[AC_CACHE_CHECK([if $CC supports typeof], [pa_cv_typeof],
[pa_cv_typeof=no
for pa_typeof_try in typeof __typeof __typeof__ decltype __decltype __decltype__ _Decltype
do
AS_IF([test $pa_cv_typeof = no],
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
AC_INCLUDES_DEFAULT
int testme(int x);
int testme(int x)
{
$pa_typeof_try(x) y = x*x;
return y;
}
])],
[pa_cv_typeof=$pa_typeof_try])])
done
])
AS_IF([test $pa_cv_typeof = no],
[],
[AC_DEFINE([HAVE_TYPEOF], 1,
[Define to 1 if you have some version of the typeof operator.])
AS_IF([test $pa_cv_typeof = typeof],
[],
[AC_DEFINE_UNQUOTED([typeof], [$pa_cv_typeof],
[Define if your typeof operator is not named `typeof'.])])])])

View file

@ -1,26 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_CHECK_BAD_STDC_INLINE
dnl
dnl Some versions of gcc seem to apply -Wmissing-prototypes to C99
dnl inline functions, which means we need to use GNU inline syntax
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_CHECK_BAD_STDC_INLINE],
[AC_MSG_CHECKING([if $CC supports C99 external inlines])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
AC_INCLUDES_DEFAULT
/* Don't mistake GNU inlines for c99 */
#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
# error "Using gnu inline standard"
#endif
inline int foo(int x)
{
return x+1;
}
])],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_STDC_INLINE], 1,
[Define to 1 if your compiler supports C99 extern inline])],
[AC_MSG_RESULT([no])
PA_ADD_CFLAGS([-fgnu89-inline])])])

View file

@ -1,17 +0,0 @@
dnl ------------------------------------------------------------------------
dnl PA_CHECK_INTTYPES_H_SANE
dnl
dnl At least some versions of AIX 4 have <inttypes.h> macros which are
dnl completely broken. Try to detect those.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_CHECK_INTTYPES_H_SANE],
[AC_CHECK_HEADERS_ONCE(inttypes.h)
AS_IF([test "x$ac_cv_header_inttypes_h" = xyes],[
AC_MSG_CHECKING([if inttypes.h is sane])
AC_LINK_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
[uintmax_t max = UINTMAX_C(0);
printf("%"PRIuMAX"\n", max);])],
[AC_MSG_RESULT([yes])
AC_DEFINE(INTTYPES_H_IS_SANE, 1,
[Define if the macros in <inttypes.h> are usable])],
[AC_MSG_RESULT([no (AIX, eh?)])])])])

View file

@ -1,41 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_CROSS_COMPILE
dnl
dnl Get the canonical name for the build and host (runtime) systems;
dnl then figure out if this is cross-compilation. Specifically, this
dnl disables invoking WINE on non-Windows systems which are configured
dnl to run WINE automatically.
dnl
dnl Use PA_CROSS_COMPILE_TOOL if the target system (output of a code-
dnl generation tool) is applicable.
dnl
dnl This doesn't explicitly print any messages as that is automatically
dnl done elsewhere.
dnl --------------------------------------------------------------------------
AC_DEFUN_ONCE([PA_CROSS_COMPILE],
[
AC_BEFORE([$0], [AC_LANG_COMPILER])
AC_BEFORE([$0], [AC_LANG])
AC_BEFORE([$0], [AC_PROG_CC])
AC_BEFORE([$0], [AC_PROG_CPP])
AC_BEFORE([$0], [AC_PROG_CXX])
AC_BEFORE([$0], [AC_PROG_CXXCPP])
AC_BEFORE([$0], [AC_PROG_OBJC])
AC_BEFORE([$0], [AC_PROG_OBJCPP])
AC_BEFORE([$0], [AC_PROG_OBJCXX])
AC_BEFORE([$0], [AC_PROG_OBJCXXCPP])
AC_BEFORE([$0], [AC_PROG_F77])
AC_BEFORE([$0], [AC_PROG_FC])
AC_BEFORE([$0], [AC_PROG_GO])
# Disable WINE
WINELOADER=/dev/null
export WINELOADER
WINESERVER=/dev/null
export WINESERVER
WINEPREFIX=/dev/null
export WINEPREFIX
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
])

View file

@ -1,19 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_FLAGS_LANGLIST(flagvar)
dnl
dnl Return a list of languages affected by the variable flagvar.
dnl If flagvar is unknown, assume it affects the current language.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_FLAGS_LANGLIST],
[m4_dquote(m4_case([$1],
[CPPFLAGS], [[C],[C++],[Objective C],[Objective C++]],
[CFLAGS], [[C]],
[CXXFLAGS], [[C++]],
[FFLAGS], [[Fortran 77]],
[FCFLAGS], [[Fortran]],
[ERLCFLAGS], [[Erlang]],
[OBJCFLAGS], [[Objective C]],
[OBJCXXFLAGS], [[Objective C++]],
[GOFLAGS], [[Go]],
[LDFLAGS], [[C],[C++],[Fortran 77],[Fortran],[Objective C],[Objective C++],[Go]],
m4_dquote(_AC_LANG)))])

View file

@ -1,26 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_HAVE_TCPWRAPPERS
dnl
dnl Do we have the tcpwrappers -lwrap? This can't be done using AC_CHECK_LIBS
dnl due to the need to provide "allow_severity" and "deny_severity" variables
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_HAVE_TCPWRAPPERS],
[AC_CHECK_LIB([wrap], [main])
AC_MSG_CHECKING([for tcpwrappers])
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[
#include <tcpd.h>
int allow_severity = 0;
int deny_severity = 0;
]],
[[
hosts_ctl("sample_daemon", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN);
]])],
[
AC_DEFINE(HAVE_TCPWRAPPERS, 1,
[Define if we have tcpwrappers (-lwrap) and <tcpd.h>.])
AC_MSG_RESULT([yes])
],
[
AC_MSG_RESULT([no])
])])

View file

@ -1,15 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_LANG_FOREACH(subset, body)
dnl
dnl Expand [body] for each language encountered in the configure script also
dnl present in [subset], or all if [subset] is empty
dnl --------------------------------------------------------------------------
AC_DEFUN([_PA_LANG_DO],dnl
[AC_LANG([$2])dnl
$1])
AC_DEFUN([PA_LANG_FOREACH],dnl
[m4_pushdef([_pa_lang_foreach_current],[_AC_LANG])dnl
m4_map_args([m4_curry([_PA_LANG_DO],[$2])],m4_unquote(PA_LANG_SEEN_LIST($1)))dnl
AC_LANG(_pa_lang_foreach_current)dnl
m4_popdef([_pa_lang_foreach_current])])

View file

@ -1,20 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_LANG_SEEN_LIST(subset)
dnl
dnl List of the language lang has been used in the configuration
dnl script so far, possibly subset by [subset].
dnl
dnl This relies on overriding _AC_LANG_SET(from, to),
dnl the internal implementation of _AC_LANG.
dnl --------------------------------------------------------------------------
m4_ifndef([_PA_LANG_SET],
[m4_rename([_AC_LANG_SET], [_PA_LANG_SET])dnl
m4_defun([_AC_LANG_SET], [m4_set_add([_PA_LANG_SEEN_SET],[$2])dnl
_PA_LANG_SET($@)])])
AC_DEFUN([PA_LANG_SEEN_LIST],
[m4_set_delete([_pa_lang_seen_subset])dnl
m4_pushdef([_pa_lang_seen_subset_list],m4_ifnblank([$1],[$1],m4_dquote(m4_set_list([_PA_LANG_SEEN_SET]))))dnl
m4_set_add_all([_pa_lang_seen_subset],_pa_lang_seen_subset_list)dnl
m4_cdr(m4_set_intersection([_pa_lang_seen_subset],[_PA_LANG_SEEN_SET]))dnl
m4_popdef([_pa_lang_seen_subset_list])])

View file

@ -1,13 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_OPTION_DEBUG(with_debug, without_debug)
dnl
dnl Set debug flags and optimization flags depending on if
dnl --enable-debug is set or not. Some flags are set regardless...
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_OPTION_DEBUG],
[PA_ARG_DISABLED([gdb], [disable gdb debug extensions],
[PA_ADD_LANGFLAGS([-g3])], [PA_ADD_LANGFLAGS([-ggdb3 -g3])])
PA_ARG_ENABLED([debug], [optimize for debugging],
[PA_ADD_LANGFLAGS([-Og -O0])
$1],
[$2])])

View file

@ -1,8 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_OPTION_PROFILING(with_profiling, without_profiling)
dnl
dnl Try to enable profiling if --enable-profiling is set.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_OPTION_PROFILING],
[PA_ARG_ENABLED([profiling], [compile with profiling (-pg option)],
[PA_ADD_LANGFLAGS([-pg])])])

View file

@ -1,13 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_PROG_CC()
dnl
dnl Similar to AC_PROG_CC, but add a prototype for main() to
dnl AC_INCLUDES_DEFAULT to avoid -Werror from breaking compilation.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_PROG_CC],
[AC_PROG_CC
AS_IF([test x$ac_cv_prog != xno],
[ac_includes_default="$ac_includes_default
#ifndef __cplusplus
extern int main(void);
#endif"])])

View file

@ -1,22 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_SEARCH_LIBS_AND_ADD
dnl
dnl PA_SEARCH_LIBS_AND_ADD(function, libraries [,function to add])
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_SEARCH_LIBS_AND_ADD],
[
AH_TEMPLATE(AS_TR_CPP(HAVE_$1), [Define if $1 function was found])
AC_SEARCH_LIBS($1, $2,
[
AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1))
pa_add_$1=false;
],
[
XTRA=true;
if test $# -eq 3; then
AC_LIBOBJ($3)
else
AC_LIBOBJ($1)
fi
pa_add_$1=true;
])])

View file

@ -1,25 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_SIGSETJMP
dnl
dnl Do we have sigsetjmp/siglongjmp? (AC_CHECK_FUNCS doesn't seem to work
dnl for these particular functions.)
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_SIGSETJMP],
[AC_MSG_CHECKING([for sigsetjmp])
AC_LINK_IFELSE([AC_LANG_SOURCE(
[
AC_INCLUDES_DEFAULT
#include <setjmp.h>
int main(void) {
sigjmp_buf buf;
if (sigsetjmp(buf,1))
return 0;
siglongjmp(buf,2);
return 1;
}
])],
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_SIGSETJMP], 1,
[Define to 1 if your system has sigsetjmp/siglongjmp])],
[AC_MSG_RESULT([no])])])

View file

@ -1,11 +0,0 @@
dnl --------------------------------------------------------------------------
dnl PA_SYM(prefix, string)
dnl
dnl Convert a (semi-) arbitrary string to a CPP symbol
dnl Compact underscores and convert non-C characters to underscore,
dnl except + which is converted to X (so C++ -> CXX).
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_SYM],
[m4_bpatsubsts(m4_quote(m4_toupper([$*])),
[,],[],[\+],[X],[[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]+],[_],dnl
[^._?\(.*\)_.$],[[\1]])])

View file

@ -1,83 +0,0 @@
#!/bin/sh -x
#
# Run this script to regenerate autoconf files
#
recheck=false
for arg; do
case x"$arg" in
x--recheck)
recheck=true
config=$(sh config.status --config 2>/dev/null)
;;
x--clearenv)
unset AUTOCONF AUTOMAKE ACLOCAL AUTOHEADER ACLOCAL_PATH
;;
*)
echo "$0: unknown option: $arg" 1>&2
;;
esac
done
# This allows for overriding the default autoconf programs
AUTOCONF="${AUTOCONF:-${AUTOTOOLS_PREFIX}autoconf}"
AUTOMAKE="${AUTOMAKE:-${AUTOTOOLS_PREFIX}automake}"
ACLOCAL="${ACLOCAL:-${AUTOTOOLS_PREFIX}aclocal}"
AUTOHEADER="${AUTOHEADER:-${AUTOTOOLS_PREFIX}autoheader}"
mkdir -p autoconf autoconf/helpers config
autolib="`"$AUTOMAKE" --print-libdir`"
if test ! x"$autolib" = x; then
for prg in install-sh compile config.guess config.sub; do
# Update autoconf helpers if and only if newer ones are available
if test -f "$autolib"/"$prg" && \
( set -e ; \
test -f autoconf/helpers/"$prg" && sed -n \
-e 's/^scriptver=/scriptversion=/' \
-e 's/^timestamp=/scriptversion=/' \
-e 's/^scriptversion=['\''"]?\([^'\''"]*\).*$/\1/p' \
"$autolib"/"$prg" autoconf/helpers/"$prg" | \
sort -c 2>/dev/null ; \
test $? -ne 0 )
then
cp -f "$autolib"/"$prg" autoconf/helpers
fi
done
fi
mv -f autoconf/aclocal.m4 autoconf/aclocal.m4.old
mkdir -p autoconf/m4.old autoconf/m4
mv -f autoconf/m4/*.m4 autoconf/m4.old/ 2>/dev/null || true
ACLOCAL_PATH="${ACLOCAL_PATH}${ACLOCAL_PATH:+:}`pwd`/autoconf/m4.old"
export ACLOCAL_PATH
"$ACLOCAL" --install --output=autoconf/aclocal.m4 -I autoconf/m4
if test ! -f autoconf/aclocal.m4; then
# aclocal failed, revert to previous files
mv -f autoconf/m4.old/*.m4 autoconf/m4/
mv -f autoconf/aclocal.m4.old autoconf/aclocal.m4
exit 1
fi
rm -rf autoconf/*m4.old
"$AUTOHEADER" -B autoconf
"$AUTOCONF" -B autoconf
(
echo '#!/bin/sh'
"$AUTOCONF" -B autoconf \
-t AC_CONFIG_HEADERS:'rm -f $*' \
-t AC_CONFIG_FILES:'rm -f $*'
echo 'rm -f config.log config.status'
echo 'rm -rf autom4te.cache'
) > autoconf/clean.sh
chmod +x autoconf/clean.sh
sh autoconf/clean.sh
rm -f configure~ || true
# Try to regenerate unconfig.h if Perl is available and unconfig.pl
# is present in the autoconf directory.
if [ -n "$(which perl)" -a -f autoconf/unconfig.pl ]; then
perl autoconf/unconfig.pl . config/config.h.in config/unconfig.h
fi
if $recheck; then
# This bizarre statement has to do with how config.status quotes its output
echo exec sh configure $config | sh -
fi

View file

@ -1,25 +0,0 @@
SRCROOT = ..
VERSION = $(shell cat ../version)
-include ../config/MCONFIG
include ../MRULES
OBJS = tftpsubs.$(O) signal.$(O)
LIB = libcommon.a
all: $(LIB)
$(LIB): $(OBJS)
-rm -f $(LIB)
$(AR) $(LIB) $(OBJS)
$(RANLIB) $(LIB)
$(OBJS): tftpsubs.h
install:
clean:
rm -f *.o *.obj *.exe $(LIB)
distclean: clean
rm -f *~

View file

@ -1,19 +0,0 @@
/*
* signal.c
*
* User-friendly wrapper around sigaction().
*/
#include "config.h"
int tftp_signal(int signum, sighandler_t handler, int flags)
{
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = flags;
return sigaction(signum, &sa, NULL);
}

View file

@ -1,406 +0,0 @@
/*
* Copyright (c) 1983, 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.
*/
#include "tftpsubs.h"
/* Simple minded read-ahead/write-behind subroutines for tftp user and
server. Written originally with multiple buffers in mind, but current
implementation has two buffer logic wired in.
Todo: add some sort of final error check so when the write-buffer
is finally flushed, the caller can detect if the disk filled up
(or had an i/o error) and return a nak to the other side.
Jim Guyton 10/85
*/
#include <sys/ioctl.h>
#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
int segsize = SEGSIZE; /* Default segsize */
struct bf {
int counter; /* size of data in buffer, or flag */
char buf[PKTSIZE]; /* room for data packet */
} bfs[2];
/* Values for bf.counter */
#define BF_ALLOC -3 /* alloc'd but not yet filled */
#define BF_FREE -2 /* free */
/* [-1 .. segsize] = size of data in the data buffer */
static int nextone; /* index of next buffer to use */
static int current; /* index of buffer in use */
/* control flags for crlf conversions */
int newline = 0; /* fillbuf: in middle of newline expansion */
int prevchar = -1; /* putbuf: previous char (cr check) */
static struct tftphdr *rw_init(int);
struct tftphdr *w_init()
{
return rw_init(0);
} /* write-behind */
struct tftphdr *r_init()
{
return rw_init(1);
} /* read-ahead */
/* init for either read-ahead or write-behind */
/* x == zero for write-behind, one for read-head */
static struct tftphdr *rw_init(int x)
{
newline = 0; /* init crlf flag */
prevchar = -1;
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
current = 0;
bfs[1].counter = BF_FREE;
nextone = x; /* ahead or behind? */
return (struct tftphdr *)bfs[0].buf;
}
/* Have emptied current buffer by sending to net and getting ack.
Free it and return next buffer filled with data.
*/
int readit(FILE * file, struct tftphdr **dpp, int convert)
{
struct bf *b;
bfs[current].counter = BF_FREE; /* free old one */
current = !current; /* "incr" current */
b = &bfs[current]; /* look at new buffer */
if (b->counter == BF_FREE) /* if it's empty */
read_ahead(file, convert); /* fill it */
/* assert(b->counter != BF_FREE);*//* check */
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
return b->counter;
}
/*
* fill the input buffer, doing ascii conversions if requested
* conversions are lf -> cr,lf and cr -> cr, nul
*/
void read_ahead(FILE * file, int convert)
{
int i;
char *p;
int c;
struct bf *b;
struct tftphdr *dp;
b = &bfs[nextone]; /* look at "next" buffer */
if (b->counter != BF_FREE) /* nop if not free */
return;
nextone = !nextone; /* "incr" next buffer ptr */
dp = (struct tftphdr *)b->buf;
if (convert == 0) {
b->counter = read(fileno(file), dp->th_data, segsize);
return;
}
p = dp->th_data;
for (i = 0; i < segsize; i++) {
if (newline) {
if (prevchar == '\n')
c = '\n'; /* lf to cr,lf */
else
c = '\0'; /* cr to cr,nul */
newline = 0;
} else {
c = getc(file);
if (c == EOF)
break;
if (c == '\n' || c == '\r') {
prevchar = c;
c = '\r';
newline = 1;
}
}
*p++ = c;
}
b->counter = (int)(p - dp->th_data);
}
/* Update count associated with the buffer, get new buffer
from the queue. Calls write_behind only if next buffer not
available.
*/
int writeit(FILE * file, struct tftphdr **dpp, int ct, int convert)
{
bfs[current].counter = ct; /* set size of data to write */
current = !current; /* switch to other buffer */
if (bfs[current].counter != BF_FREE) /* if not free */
(void)write_behind(file, convert); /* flush it */
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
*dpp = (struct tftphdr *)bfs[current].buf;
return ct; /* this is a lie of course */
}
/*
* Output a buffer to a file, converting from netascii if requested.
* CR,NUL -> CR and CR,LF => LF.
* Note spec is undefined if we get CR as last byte of file or a
* CR followed by anything else. In this case we leave it alone.
*/
int write_behind(FILE * file, int convert)
{
char *buf;
int count;
int ct;
char *p;
int c; /* current character */
struct bf *b;
struct tftphdr *dp;
b = &bfs[nextone];
if (b->counter < -1) /* anything to flush? */
return 0; /* just nop if nothing to do */
count = b->counter; /* remember byte count */
b->counter = BF_FREE; /* reset flag */
dp = (struct tftphdr *)b->buf;
nextone = !nextone; /* incr for next time */
buf = dp->th_data;
if (count <= 0)
return -1; /* nak logic? */
if (convert == 0)
return write(fileno(file), buf, count);
p = buf;
ct = count;
while (ct--) { /* loop over the buffer */
c = *p++; /* pick up a character */
if (prevchar == '\r') { /* if prev char was cr */
if (c == '\n') /* if have cr,lf then just */
fseek(file, -1, 1); /* smash lf on top of the cr */
else if (c == '\0') /* if have cr,nul then */
goto skipit; /* just skip over the putc */
/* else just fall through and allow it */
}
putc(c, file);
skipit:
prevchar = c;
}
return count;
}
/* When an error has occurred, it is possible that the two sides
* are out of synch. Ie: that what I think is the other side's
* response to packet N is really their response to packet N-1.
*
* So, to try to prevent that, we flush all the input queued up
* for us on the network connection on our host.
*
* We return the number of packets we flushed (mostly for reporting
* when trace is active).
*/
int synchnet(int f)
{ /* socket to flush */
int pktcount = 0;
char rbuf[PKTSIZE];
union sock_addr from;
socklen_t fromlen;
fd_set socketset;
struct timeval notime;
while (1) {
notime.tv_sec = notime.tv_usec = 0;
FD_ZERO(&socketset);
FD_SET(f, &socketset);
if (select(f, &socketset, NULL, NULL, &notime) <= 0)
break; /* Nothing to read */
/* Otherwise drain the packet */
pktcount++;
fromlen = sizeof(from);
(void)recvfrom(f, rbuf, sizeof(rbuf), 0,
&from.sa, &fromlen);
}
return pktcount; /* Return packets drained */
}
int pick_port_bind(int sockfd, union sock_addr *myaddr,
unsigned int port_range_from,
unsigned int port_range_to)
{
unsigned int port, firstport;
int port_range = 0;
if (port_range_from != 0 && port_range_to != 0) {
port_range = 1;
}
firstport = port_range
? port_range_from + rand() % (port_range_to - port_range_from + 1)
: 0;
port = firstport;
do {
sa_set_port(myaddr, htons(port));
if (bind(sockfd, &myaddr->sa, SOCKLEN(myaddr)) < 0) {
/* Some versions of Linux return EINVAL instead of EADDRINUSE */
if (!(port_range && (errno == EINVAL || errno == EADDRINUSE)))
return -1;
/* Normally, we shouldn't have to loop, but some situations involving
aborted transfers make it possible. */
} else {
return 0;
}
port++;
if (port > port_range_to)
port = port_range_from;
} while (port != firstport);
return -1;
}
int
set_sock_addr(char *host,union sock_addr *s, char **name)
{
struct addrinfo *addrResult;
struct addrinfo hints;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_family = s->sa.sa_family;
hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
err = getaddrinfo(strip_address(host), NULL, &hints, &addrResult);
if (err)
return err;
if (addrResult == NULL)
return EAI_NONAME;
memcpy(s, addrResult->ai_addr, addrResult->ai_addrlen);
if (name) {
if (addrResult->ai_canonname)
*name = xstrdup(addrResult->ai_canonname);
else
*name = xstrdup(host);
}
freeaddrinfo(addrResult);
return 0;
}
#ifdef HAVE_IPV6
int is_numeric_ipv6(const char *p)
{
/* A numeric IPv6 address consist at least of 2 ':' and
* it may have sequences of hex-digits and maybe contain
* a '.' from a IPv4 mapped address and maybe is enclosed in []
* we do not check here, if it is a valid IPv6 address
* only if is something like a numeric IPv6 address or something else
*/
int colon = 0;
int dot = 0;
int bracket = 0;
char c;
if (!p)
return 0;
if (*p == '[') {
bracket = 1;
p++;
}
while ((c = *p++) && c != ']') {
switch (c) {
case ':':
colon++;
break;
case '.':
dot++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
break;
default:
return 0; /* Invalid character */
}
}
if (colon < 2 || colon > 7)
return 0;
if (dot) {
/* An IPv4-mapped address in dot-quad form will have 3 dots */
if (dot != 3)
return 0;
/* The IPv4-mapped address takes the space of one colon */
if (colon > 6)
return 0;
}
/* If bracketed, must be closed, and vice versa */
if (bracket ^ (c == ']'))
return 0;
/* Otherwise, assume we're okay */
return 1;
}
/* strip [] from numeric IPv6 addreses */
char *strip_address(char *addr)
{
char *p;
if (is_numeric_ipv6(addr) && (*addr == '[')) {
p = addr + strlen(addr);
p--;
if (*p == ']') {
*p = 0;
addr++;
}
}
return addr;
}
#endif

130
config.h
View file

@ -1,12 +1,13 @@
/* -*- c -*- ------------------------------------------------------------- * /* -*- c -*- ------------------------------------------------------------- *
* *
* Copyright 2001-2024 H. Peter Anvin - All Rights Reserved * Copyright 2001 H. Peter Anvin - All Rights Reserved
* *
* This program is free software available under the same license * This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at * as the "OpenBSD" operating system, distributed at
* http://www.openbsd.org/. * http://www.openbsd.org/.
* *
* ----------------------------------------------------------------------- */ * ----------------------------------------------------------------------- */
/* $Id$ */
/* /*
* config.h * config.h
@ -17,23 +18,12 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H 1 #define CONFIG_H 1
/* Feature enables for specific environments */
#ifdef __APPLE__
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1070
#define __APPLE_USE_RFC_3542 1
#endif
#endif
/* Must be included before we include any system headers! */ /* Must be included before we include any system headers! */
#include "config/config.h" /* autogenerated configuration header */ #include "aconfig.h" /* autogenerated configuration header */
/* Standard includes */ /* Standard includes */
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
#include <sys/types.h> #include <sys/types.h>
@ -43,6 +33,21 @@
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <stddef.h>
#else
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#endif
#ifdef HAVE_MEMORY_H
#ifndef STDC_HEADERS
#include <memory.h>
#endif
#endif
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>
#endif #endif
@ -69,8 +74,15 @@
#include <setjmp.h> #include <setjmp.h>
#endif #endif
#ifdef HAVE_SYS_TIME_H #ifdef TIME_WITH_SYS_TIME
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif #endif
#ifdef HAVE_GRP_H #ifdef HAVE_GRP_H
@ -81,6 +93,9 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#include <errno.h>
#include <signal.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> #include <sys/socket.h>
#else #else
@ -92,14 +107,12 @@
#endif #endif
#endif #endif
#endif #endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#else #else
#include "lib/getopt.h" extern char *optarg;
extern int optind, opterr, optopt;
#endif #endif
/* Test for EAGAIN/EWOULDBLOCK */ /* Test for EAGAIN/EWOULDBLOCK */
@ -115,10 +128,10 @@
/* Some broken systems care about text versus binary, but /* Some broken systems care about text versus binary, but
real Unix systems don't... */ real Unix systems don't... */
#if !HAVE_DECL_O_TEXT #ifndef HAVE_O_TEXT_DEFINITION
#define O_TEXT 0 #define O_TEXT 0
#endif #endif
#if !HAVE_DECL_O_BINARY #ifndef HAVE_O_BINARY_DEFINITION
#define O_BINARY 0 #define O_BINARY 0
#endif #endif
@ -204,11 +217,6 @@ typedef unsigned long u_long;
#endif #endif
#endif #endif
/* socklen_t */
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
/* sysexits.h */ /* sysexits.h */
#ifdef HAVE_SYSEXITS_H #ifdef HAVE_SYSEXITS_H
@ -253,9 +261,11 @@ typedef int socklen_t;
#include <netinet/in.h> #include <netinet/in.h>
#if !HAVE_DECL_IPPORT_TFTP && !defined(IPPORT_TFTP) #ifndef HAVE_IPPORT_TFTP_DEFINITION
#ifndef IPPORT_TFTP
#define IPPORT_TFTP 69 #define IPPORT_TFTP 69
#endif #endif
#endif
/* arpa/{inet,tftp}.h, and possible missing pieces */ /* arpa/{inet,tftp}.h, and possible missing pieces */
@ -272,72 +282,6 @@ typedef int socklen_t;
#define EOPTNEG 8 #define EOPTNEG 8
#endif #endif
/* Prototypes for libxtra functions */
void *xmalloc(size_t);
char *xstrdup(const char *);
#ifndef HAVE_SIGHANDLER_T
typedef void (*sighandler_t)(int);
#endif
int tftp_signal(int, sighandler_t, int);
#ifndef HAVE_DUP2
int dup2(int, int);
#endif
#ifndef HAVE_DAEMON
int daemon(int, int);
#endif
#ifndef HAVE_GETADDRINFO
#ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
#endif
int getaddrinfo(const char *, const char *, const struct addrinfo *,
struct addrinfo **);
void freeaddrinfo(struct addrinfo *);
const char *gai_strerror(int);
#ifndef EAI_NONAME
#define EAI_NONAME -2 /* NAME or SERVICE is unknown. */
#endif
#ifndef EAI_ADDRFAMILY
#define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */
#endif
#ifndef EAI_MEMORY
#define EAI_MEMORY -10 /* Memory allocation failure. */
#endif
#ifndef EAI_SYSTEM
#define EAI_SYSTEM -11 /* System error returned in `errno'. */
#endif
#endif
#ifndef AI_CANONNAME
#define AI_CANONNAME 0
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0
#endif
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif
#ifndef HAVE_INET_NTOP
const char *inet_ntop(int, const void *, char *, socklen_t);
#endif
/* tftp-hpa version and configuration strings */ /* tftp-hpa version and configuration strings */
#include "version.h" #include "version.h"

View file

@ -1,283 +0,0 @@
dnl Process this file with autoconf 2.71 or later to produce
dnl a configure script.
AC_PREREQ([2.71])
AC_INIT
AC_CONFIG_SRCDIR([MRULES])
AC_PREFIX_DEFAULT([/usr])
AC_CONFIG_AUX_DIR([autoconf/helpers])
dnl This prevents us from running Wine and thinking we are not
dnl cross-compiling when in fact we are; running Wine here is at
dnl the best very slow and doesn't buy us a single thing at all.
PA_CROSS_COMPILE
dnl Enable any available C extensions
PA_PROG_CC
AC_USE_SYSTEM_EXTENSIONS
dnl Options for debugging and profiling
PA_OPTION_DEBUG
PA_OPTION_PROFILING
dnl LLVM doesn't error out on invalid -W options unless this option is
dnl specified first. Enable this so this script can actually discover
dnl which -W options are possible for this compiler.
PA_ADD_CFLAGS([-Werror=unknown-warning-option])
dnl Force gcc and gcc-compatible compilers treat signed integers
dnl as 2's complement
PA_ADD_CFLAGS([-fwrapv])
dnl Force clang to behave in a predictable manner, in order to make bugs
dnl possible to track down. gcc appears to have this behavior by default.
PA_ADD_CFLAGS([-ftrivial-auto-var-init=zero])
dnl Some environments abuse __STRICT_ANSI__ to disable some
dnl function declarations
PA_ADD_CFLAGS([-U__STRICT_ANSI__])
dnl Don't put things in common if we can avoid it. We don't want to
dnl assume all compilers support common, and this will help find those
dnl problems. This also works around an OSX linker problem.
PA_ADD_CFLAGS([-fno-common])
dnl Tests which may trigger warnings on some compilers
AC_C_CONST
AC_C_INLINE
AC_C_RESTRICT
dnl Checks for header files.
AC_CHECK_INCLUDES_DEFAULT
dnl See if we need extra libraries
XTRA=false
AC_SEARCH_LIBS([strerror],[cposix])
AC_CHECK_HEADERS_ONCE(inttypes.h)
AC_CHECK_HEADERS_ONCE(stdint.h)
AC_CHECK_HEADERS_ONCE(grp.h)
AC_CHECK_HEADERS_ONCE(libgen.h)
AC_CHECK_HEADERS_ONCE(setjmp.h)
AC_CHECK_HEADERS_ONCE(strings.h)
AC_CHECK_HEADERS_ONCE(sysexits.h)
AC_CHECK_HEADERS_ONCE(unistd.h)
AC_CHECK_HEADERS_ONCE(sys/filio.h)
AC_CHECK_HEADERS_ONCE(sys/stat.h)
AC_CHECK_HEADERS_ONCE(sys/time.h)
PA_CHECK_INTTYPES_H_SANE
dnl This is needed on some versions of FreeBSD...
AC_CHECK_HEADERS_ONCE(machine/param.h)
dnl Windows...
PA_ADD_HEADERS(windows.h)
PA_ADD_HEADERS(winsock2.h)
AS_IF([test "x$ac_cv_header_winsock2_h" != xyes],
[PA_ADD_HEADERS(winsock.h)])
PA_ADD_HEADERS(fcntl.h)
PA_ADD_HEADERS(sys/types.h)
PA_ADD_HEADERS(arpa/inet.h)
PA_ADD_HEADERS(sys/socket.h)
PA_ADD_HEADERS(sys/file.h)
PA_ADD_HEADERS(netinet/in.h)
PA_ADD_HEADERS(sys/uio.h)
PA_ADD_HEADERS(netdb.h)
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_MODE_T
AC_TYPE_SIZE_T
AC_CHECK_TYPES(intmax_t)
AC_CHECK_TYPES(long long)
AC_CHECK_TYPES(uint16_t)
AC_CHECK_TYPES(uint32_t)
AC_CHECK_TYPES(u_short)
AC_CHECK_TYPES(u_long)
AC_CHECK_TYPES(socklen_t)
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], ,
[AC_MSG_ERROR(socket library not found)])
AC_CHECK_FUNCS(fcntl)
AC_CHECK_FUNCS(flock)
AC_CHECK_FUNCS(setsid)
AC_CHECK_FUNCS(recvmsg)
AC_CHECK_FUNCS(ftruncate)
AC_CHECK_FUNCS(setresuid)
AC_CHECK_FUNCS(setreuid)
AC_CHECK_FUNCS(setresgid)
AC_CHECK_FUNCS(setregid)
AC_CHECK_FUNCS(initgroups)
AC_CHECK_FUNCS(setgroups)
AC_CHECK_TYPES(sighandler_t)
dnl Solaris 8 has [u]intmax_t but not strtoumax(). How utterly braindamaged.
AC_CHECK_FUNCS(strtoumax)
AC_CHECK_FUNCS(strtoull)
AC_CHECK_MEMBERS(struct msghdr.msg_control)
AC_CHECK_MEMBERS(struct in_pktinfo.ipi_addr)
AC_CHECK_MEMBERS(struct addrinfo.ai_addr)
AC_CHECK_DECLS([O_NONBLOCK, O_BINARY, O_TEXT])
AC_CHECK_DECLS([F_SETLK])
AC_CHECK_DECLS([LOCK_SH, LOCK_EX])
PA_SIGSETJMP
dnl
dnl Get common paths
dnl
SRCROOT=`cd $srcdir && pwd`
OBJROOT=`pwd`
PA_SEARCH_LIBS_AND_ADD(xmalloc, iberty)
PA_SEARCH_LIBS_AND_ADD(xstrdup, iberty)
PA_SEARCH_LIBS_AND_ADD(getopt_long, getopt, getopt_long)
PA_SEARCH_LIBS_AND_ADD(getaddrinfo, [nsl resolv])
AS_IF([$pa_add_getaddrinfo],
[AC_SEARCH_LIBS(gethostbyname, [nsl resolv],
[AC_SEARCH_LIBS(herror, [nsl resolv], ,
[AC_MSG_ERROR(herror not found)])],
[AC_MSG_ERROR(gethostbyname not found)])],
[AC_SEARCH_LIBS(freeaddrinfo, [nsl resolv], ,
[AC_MSG_ERROR(getaddrinfo but not freeaddrinfo found)])
AC_SEARCH_LIBS(gai_strerror, [nsl resolv], ,
[AC_MSG_ERROR(getaddrinfo but not gai_strerror found)])])
PA_SEARCH_LIBS_AND_ADD(inet_ntop, [nsl resolv])
AS_IF([$pa_add_inet_ntop],
[AC_SEARCH_LIBS(inet_ntoa, [nsl resolv], ,
[AC_MSG_ERROR(inet_ntoa not found)])])
AC_SEARCH_LIBS(inet_aton, [nsl resolv], ,[AC_MSG_ERROR(inet_aton not found)])
PA_SEARCH_LIBS_AND_ADD(daemon)
PA_SEARCH_LIBS_AND_ADD(dup2)
AS_IF([$XTRA], [XTRALIBS="$OBJROOT/lib/libxtra.a $XTRALIBS"])
dnl
dnl These libraries apply to the server only
dnl
common_libs="$LIBS"
AC_CHECK_DECLS(IPPORT_TFTP)
PA_ARG_DISABLED([tcpwrappers],
[disable tcpwrapper permissions checking], [],
[
AC_SEARCH_LIBS(yp_get_default_domain, [nsl resolv])
PA_HAVE_TCPWRAPPERS
])
AC_CHECK_HEADERS_ONCE([regex.h])
PA_ARG_DISABLED([remap],
[disable regex-based filename remapping], [],
[AS_IF([test x"$ac_cv_header_regex_h" = xyes],
[AC_SEARCH_LIBS(regcomp, [regex rx],
[AC_DEFINE([WITH_REGEX], 1,
[Define if we are compiling with regex filename remapping.])
TFTPDOBJS="remap.\$(O) $TFTPOBJS"])])])
TFTPD_LIBS="$LIBS $XTRALIBS"
LIBS="$common_libs"
dnl
dnl These libraries apply to the client only
dnl
AH_TEMPLATE([WITH_READLINE],
[Define if we are compiling with readline/editline command-line editing.])
PA_ARG_DISABLED([readline],
[disable the use of readline command-line editing], [],
[
AC_CHECK_HEADER([readline/readline.h],
[
dnl readline may need libtermcap or somesuch...
AC_SEARCH_LIBS(tputs, [termcap terminfo])
AC_SEARCH_LIBS(readline, [readline history],
[AC_DEFINE(WITH_READLINE)])
AC_CHECK_HEADERS(readline/history.h)
],
[AC_CHECK_HEADER([editline/readline.h],
[
dnl editline may need libtermcap or somesuch...
AC_SEARCH_LIBS(tputs, [termcap terminfo])
AC_SEARCH_LIBS(editline, [edit],
[AC_DEFINE(WITH_READLINE)])
])])
],:)
TFTP_LIBS="$LIBS $XTRALIBS"
LIBS="$common_libs"
dnl
dnl Check for IPV6 and disable-ipv6
dnl
AC_CHECK_MEMBERS(struct sockaddr_in6.sin6_addr)
AC_MSG_CHECKING([for IPv6 support])
PA_ARG_DISABLED([ipv6],
[disable support for IPv6],
[AC_MSG_RESULT(disabled)],
[AS_IF([test x"$ac_cv_member_struct_sockaddr_in6_sin6_addr$ac_cv_member_struct_addrinfo_ai_addr" = xyesyes],
[AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_IPV6, 1, [define if IPv6 support is enabled])],
[AC_MSG_RESULT(no)
AC_MSG_WARN([*** we do not have required IPv6 structs - IPv6 will be disabled])])])
AC_SUBST(SRCROOT)
AC_SUBST(OBJROOT)
AC_SUBST(TFTP_LIBS)
AC_SUBST(TFTPD_LIBS)
AC_SUBST(TFTPDOBJS)
AC_PROG_LN_S
AC_PROG_RANLIB
dnl
dnl Make sure the install program has an absolute path if it
dnl has a path at all. autoconf doesn't do this "in order
dnl to not pollute the cache." Sigh.
dnl Note: the $ needs to be double-quoted for reasons unknown.
dnl
AC_PROG_INSTALL
[if echo "$INSTALL" | grep '^[^/].*/' > /dev/null 2>&1; then
INSTALL='\${SRCROOT}'/"$INSTALL"
fi]
PA_ADD_CFLAGS(-W)
PA_ADD_CFLAGS(-Wall)
PA_ADD_CFLAGS(-Wpointer-arith)
PA_ADD_CFLAGS(-Wbad-function-cast)
PA_ADD_CFLAGS(-Wcast-equal)
PA_ADD_CFLAGS(-Wstrict-prototypes)
PA_ADD_CFLAGS(-Wmissing-prototypes)
PA_ADD_CFLAGS(-Wmissing-declarations)
PA_ADD_CFLAGS(-Wnested-externs)
PA_ADD_CFLAGS(-Winline)
PA_ADD_CFLAGS(-Wwrite-strings)
PA_ADD_CFLAGS(-Wundef)
PA_ADD_CFLAGS(-Wshadow)
PA_ADD_CFLAGS(-Wsign-compare)
PA_ADD_CFLAGS(-fno-strict-aliasing)
dnl
dnl Test compiler features. On some compilers, this can be affected
dnl by -Werror options, so run this *after* those options are added.
dnl
PA_CHECK_BAD_STDC_INLINE
PA_C_TYPEOF
AC_CONFIG_HEADERS([config/config.h])
AC_CONFIG_FILES([config/MCONFIG])
AC_OUTPUT

225
configure.in Normal file
View file

@ -0,0 +1,225 @@
dnl
dnl autoconf input file to generate MCONFIG
dnl
AC_PREREQ(2.52)
AC_REVISION([$Id$])
AC_INIT(MCONFIG.in)
AC_PREFIX_DEFAULT(/usr)
AC_ISC_POSIX
AC_AIX
AC_MINIX
AC_PROG_CC
dnl
dnl Feature-test macros. These need to be set in CFLAGS, rather in
dnl aconfig.h, or "configure" will run in a different environment than
dnl we eventually we build in.
dnl
dnl Needed on Solaris/cc or Solaris/gcc
CFLAGS="$CFLAGS -D_XPG4_2"
CFLAGS="$CFLAGS -D_XOPEN_SOURCE"
CFLAGS="$CFLAGS -D__EXTENSIONS__"
dnl Needed on some glibc systems
CFLAGS="$CFLAGS -D_GNU_SOURCE"
dnl Needed on Digital Unix
CFLAGS="$CFLAGS -D_OSF_SOURCE"
CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED"
AC_C_CONST
AC_C_INLINE
AC_SYS_LARGEFILE
PA_ADD_CFLAGS(-W)
PA_ADD_CFLAGS(-Wall)
PA_ADD_CFLAGS(-Wpointer-arith)
PA_ADD_CFLAGS(-Wbad-function-cast)
PA_ADD_CFLAGS(-Wcast-equal)
PA_ADD_CFLAGS(-Wstrict-prototypes)
PA_ADD_CFLAGS(-Wmissing-prototypes)
PA_ADD_CFLAGS(-Wmissing-declarations)
PA_ADD_CFLAGS(-Wnested-externs)
PA_ADD_CFLAGS(-Winline)
PA_ADD_CFLAGS(-Wwrite-strings)
PA_ADD_CFLAGS(-Wundef)
PA_ADD_CFLAGS(-Wshadow)
PA_ADD_CFLAGS(-Wsign-compare)
PA_ADD_CFLAGS(-pipe)
PA_ADD_CFLAGS(-fno-strict-aliasing)
AC_HEADER_STDC
AC_CHECK_HEADERS(inttypes.h)
AC_CHECK_HEADERS(stdint.h)
PA_CHECK_INTTYPES_H_SANE
AC_CHECK_HEADERS(fcntl.h)
AC_CHECK_HEADERS(getopt.h)
AC_CHECK_HEADERS(grp.h)
AC_CHECK_HEADERS(libgen.h)
AC_CHECK_HEADERS(memory.h)
AC_CHECK_HEADERS(setjmp.h)
AC_CHECK_HEADERS(stddef.h)
AC_CHECK_HEADERS(stdlib.h)
AC_CHECK_HEADERS(string.h)
AC_CHECK_HEADERS(strings.h)
AC_CHECK_HEADERS(sysexits.h)
AC_CHECK_HEADERS(time.h)
AC_CHECK_HEADERS(unistd.h)
AC_CHECK_HEADERS(sys/filio.h)
AC_CHECK_HEADERS(sys/stat.h)
AC_CHECK_HEADERS(sys/time.h)
AC_CHECK_HEADERS(sys/types.h)
AC_CHECK_HEADERS(arpa/inet.h)
AC_HEADER_TIME
dnl This is needed on some versions of FreeBSD...
AC_CHECK_HEADERS(machine/param.h)
AC_CHECK_HEADERS(sys/socket.h)
AC_CHECK_HEADERS(winsock2.h)
AC_CHECK_HEADERS(winsock.h)
AC_CHECK_TYPES(intmax_t)
AC_CHECK_TYPES(long long)
AC_CHECK_TYPES(uint16_t)
AC_CHECK_TYPES(uint32_t)
AC_CHECK_TYPES(u_short)
AC_CHECK_TYPES(u_long)
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_MODE_T
AC_TYPE_SIZE_T
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], , [AC_MSG_ERROR(socket library not found)])
AC_SEARCH_LIBS(gethostbyname, [nsl resolv], , [AC_MSG_ERROR(gethostbyname not found)])
AC_SEARCH_LIBS(inet_aton, [nsl resolv], , [AC_MSG_ERROR(inet_aton not found)])
AC_SEARCH_LIBS(herror, [nsl resolv], , [AC_MSG_ERROR(herror not found)])
AC_CHECK_FUNCS(dup2)
AC_CHECK_FUNCS(fcntl)
AC_CHECK_FUNCS(setsid)
AC_CHECK_FUNCS(recvmsg)
AC_CHECK_FUNCS(ftruncate)
AC_CHECK_FUNCS(setreuid)
AC_CHECK_FUNCS(setregid)
AC_CHECK_FUNCS(initgroups)
AC_CHECK_FUNCS(setgroups)
dnl Solaris 8 has [u]intmax_t but not strtoumax(). How utterly braindamaged.
AC_CHECK_FUNCS(strtoumax)
AC_CHECK_FUNCS(strtoull)
PA_MSGHDR_MSG_CONTROL
PA_STRUCT_IN_PKTINFO
PA_HEADER_DEFINES(fcntl.h, int, O_NONBLOCK)
PA_HEADER_DEFINES(fcntl.h, int, O_BINARY)
PA_HEADER_DEFINES(fcntl.h, int, O_TEXT)
AH_TEMPLATE([HAVE_SIGSETJMP],
[Define if we have sigsetjmp, siglongjmp and sigjmp_buf.])
PA_SIGSETJMP([AC_DEFINE(HAVE_SIGSETJMP)])
dnl
dnl Get common paths
dnl
SRCROOT=`cd $srcdir && pwd`
OBJROOT=`pwd`
XTRA=false
AC_SEARCH_LIBS(xmalloc, iberty, , [XTRA=true ; AC_LIBOBJ(xmalloc)])
AC_SEARCH_LIBS(xstrdup, iberty, , [XTRA=true ; AC_LIBOBJ(xstrdup)])
AC_SEARCH_LIBS(bsd_signal, bsd, , [XTRA=true ; AC_LIBOBJ(bsdsignal)])
if $XTRA
then
XTRALIBS="$OBJROOT/lib/libxtra.a $XTRALIBS"
fi
dnl
dnl These libraries apply to the server only
dnl
common_libs="$LIBS"
PA_HEADER_DEFINES(netinet/in.h, int, IPPORT_TFTP)
PA_WITH_BOOL(tcpwrappers, 1,
[ --without-tcpwrappers disable tcpwrapper permissions checking],
[
AC_SEARCH_LIBS(yp_get_default_domain, [nsl resolv])
PA_HAVE_TCPWRAPPERS
],:)
AH_TEMPLATE([WITH_REGEX],
[Define if we are compiling with regex filename remapping.])
PA_WITH_BOOL(remap, 1,
[ --without-remap disable regex-based filename remapping],
[
AC_CHECK_HEADER(regex.h,
[
AC_SEARCH_LIBS(regcomp, [regex rx],
[
AC_DEFINE(WITH_REGEX)
TFTPDOBJS="remap.${OBJEXT} $TFTPDOBJS"
])
])
],:)
TFTPD_LIBS="$LIBS $XTRALIBS"
LIBS="$common_libs"
dnl
dnl These libraries apply to the client only
dnl
AH_TEMPLATE([WITH_READLINE],
[Define if we are compiling with readline command-line editing.])
PA_WITH_BOOL(readline, 1,
[ --without-readline disable the use of readline command-line editing],
[
AC_CHECK_HEADER(readline/readline.h,
[
dnl readline may need libtermcap or somesuch...
AC_SEARCH_LIBS(tputs, [termcap terminfo])
AC_SEARCH_LIBS(readline, [readline history],
[
AC_DEFINE(WITH_READLINE)
],
[],
[-ltermcap])
AC_CHECK_HEADERS(readline/history.h)
])
],:)
TFTP_LIBS="$LIBS $XTRALIBS"
LIBS="$common_libs"
AC_SUBST(SRCROOT)
AC_SUBST(OBJROOT)
AC_SUBST(TFTP_LIBS)
AC_SUBST(TFTPD_LIBS)
AC_SUBST(TFTPDOBJS)
AC_PROG_LN_S
AC_PROG_RANLIB
dnl
dnl Make sure the install program has an absolute path if it
dnl has a path at all. autoconf doesn't do this "in order
dnl to not pollute the cache." Sigh.
dnl Note: the $ needs to be double-quoted for reasons unknown.
dnl
AC_PROG_INSTALL
[if echo "$INSTALL" | grep '^[^/].*/' > /dev/null 2>&1; then
INSTALL='\${SRCROOT}'/"$INSTALL"
fi]
AC_CONFIG_HEADERS(aconfig.h)
AC_OUTPUT(MCONFIG)

View file

@ -4,7 +4,7 @@
SRCROOT = .. SRCROOT = ..
-include ../config/MCONFIG -include ../MCONFIG
include ../MRULES include ../MRULES
ifeq ($(LIBOBJS),) ifeq ($(LIBOBJS),)
@ -25,3 +25,5 @@ libxtra.a: $(LIBOBJS)
-rm -f libxtra.a -rm -f libxtra.a
$(AR) libxtra.a $(LIBOBJS) $(AR) libxtra.a $(LIBOBJS)
$(RANLIB) libxtra.a $(RANLIB) libxtra.a

32
lib/bsdsignal.c Normal file
View file

@ -0,0 +1,32 @@
/*
* bsdsignal.c
*
* Use sigaction() to simulate BSD signal()
*/
#include <signal.h>
#include <stdlib.h>
#include <string.h>
void (*bsd_signal(int, void (*)(int)))(int);
void (*bsd_signal(int signum, void (*handler)(int)))(int)
{
struct sigaction action, oldaction;
memset(&action, 0, sizeof action);
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, signum);
action.sa_flags = SA_RESTART;
if (sigaction(signum, &action, &oldaction) == -1) {
#ifdef SIG_ERR
return SIG_ERR;
#else
return NULL;
#endif
}
return oldaction.sa_handler;
}

View file

@ -1,36 +0,0 @@
/*
* daemon.c - "daemonize" a process
*/
#include "config.h"
int daemon(int nochdir, int noclose)
{
int nullfd;
pid_t f;
if (!nochdir) {
if (chdir("/"))
return -1;
}
if (!noclose) {
if ((nullfd = open("/dev/null", O_RDWR)) < 0 ||
dup2(nullfd, 0) < 0 ||
dup2(nullfd, 1) < 0 || dup2(nullfd, 2) < 0)
return -1;
close(nullfd);
}
f = fork();
if (f < 0)
return -1;
else if (f > 0)
_exit(0);
#ifdef HAVE_SETSID
return setsid();
#else
return 0;
#endif
}

View file

@ -1,23 +0,0 @@
/*
* dup2.c
*
* Ersatz dup2() for really ancient systems
*/
#include "config.h"
int dup2(int oldfd, int newfd)
{
int rv, nfd;
close(newfd);
nfd = rv = dup(oldfd);
if (rv >= 0 && rv != newfd) {
rv = dup2(oldfd, newfd);
close(nfd);
}
return rv;
}

View file

@ -1,121 +0,0 @@
/*
* getaddrinfo.c
*
* Simple version of getaddrinfo()
*
*/
#include "config.h"
extern int errno;
extern int h_errno;
void freeaddrinfo(struct addrinfo *res)
{
if (!res)
return;
if (res->ai_next)
freeaddrinfo(res->ai_next);
if (res->ai_addr)
free(res->ai_addr);
if (res->ai_canonname)
free(res->ai_canonname);
free(res);
}
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
struct addrinfo **res)
{
struct hostent *host;
struct sockaddr *sa;
int err, size = 0;
if ((!node) || (!res)) {
errno = EINVAL;
return EAI_SYSTEM;
}
*res = NULL;
/* we do not support service in this version */
if (service) {
errno = EINVAL;
return EAI_SYSTEM;
}
host = gethostbyname(node);
if (!host)
return EAI_NONAME;
if (hints) {
if (hints->ai_family != AF_UNSPEC) {
if (hints->ai_family != host->h_addrtype)
return EAI_ADDRFAMILY;
}
}
*res = malloc(sizeof(struct addrinfo));
if (!*res) {
return EAI_MEMORY;
}
memset(*res, 0, sizeof(struct addrinfo));
(*res)->ai_family = host->h_addrtype;
if (host->h_length) {
if (host->h_addrtype == AF_INET)
size = sizeof(struct sockaddr_in);
#ifdef HAVE_IPV6
else if (host->h_addrtype == AF_INET6)
size = sizeof(struct sockaddr_in6);
#endif
else {
free(*res);
*res = NULL;
return EAI_ADDRFAMILY;
}
sa = malloc(size);
if (!sa) {
free(*res);
*res = NULL;
return EAI_MEMORY;
}
memset(sa, 0, size);
(*res)->ai_addr = sa;
(*res)->ai_addrlen = size;
sa->sa_family = host->h_addrtype;
if (host->h_addrtype == AF_INET)
memcpy(&((struct sockaddr_in *)sa)->sin_addr, host->h_addr, host->h_length);
#ifdef HAVE_IPV6
else
memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, host->h_addr, host->h_length);
#endif
}
if (host->h_name)
(*res)->ai_canonname = strdup(host->h_name);
/* we only handle the first address entry and do not build a list now */
return 0;
}
const char *gai_strerror(int errcode)
{
const char *s = NULL;
switch(errcode) {
case 0:
s = "no error";
break;
case EAI_MEMORY:
s = "no memory";
break;
case EAI_SYSTEM:
s = strerror(errno);
break;
case EAI_NONAME:
s = hstrerror(h_errno);
break;
case EAI_ADDRFAMILY:
s = "address does not match address family";
break;
default:
s = "unknown error code";
break;
}
return s;
}

View file

@ -1,23 +0,0 @@
#ifndef LIB_GETOPT_H
#define LIB_GETOPT_H
extern char *optarg;
extern int optind, opterr, optopt;
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
enum {
no_argument = 0,
required_argument = 1,
optional_argument = 2,
};
int getopt_long(int, char *const *, const char *,
const struct option *, int *);
#endif /* LIB_GETOPT_H */

View file

@ -1,150 +0,0 @@
/*
* getopt_long.c
*
* getopt_long(), or at least a common subset thereof:
*
* - Option reordering is not supported
* - -W foo is not supported
* - First optstring character "-" not supported.
*/
#include "config.h"
char *optarg;
int optind, opterr, optopt;
static struct getopt_private_state {
const char *optptr;
const char *last_optstring;
char *const *last_argv;
} pvt;
static inline const char *option_matches(const char *arg_str,
const char *opt_name)
{
while (*arg_str != '\0' && *arg_str != '=') {
if (*arg_str++ != *opt_name++)
return NULL;
}
if (*opt_name)
return NULL;
return arg_str;
}
int getopt_long(int argc, char *const *argv, const char *optstring,
const struct option *longopts, int *longindex)
{
const char *carg;
const char *osptr;
int opt;
/* getopt() relies on a number of different global state
variables, which can make this really confusing if there is
more than one use of getopt() in the same program. This
attempts to detect that situation by detecting if the
"optstring" or "argv" argument have changed since last time
we were called; if so, reinitialize the query state. */
if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
optind < 1 || optind > argc) {
/* optind doesn't match the current query */
pvt.last_optstring = optstring;
pvt.last_argv = argv;
optind = 1;
pvt.optptr = NULL;
}
carg = argv[optind];
/* First, eliminate all non-option cases */
if (!carg || carg[0] != '-' || !carg[1])
return -1;
if (carg[1] == '-') {
const struct option *lo;
const char *opt_end = NULL;
optind++;
/* Either it's a long option, or it's -- */
if (!carg[2]) {
/* It's -- */
return -1;
}
for (lo = longopts; lo->name; lo++) {
if ((opt_end = option_matches(carg+2, lo->name)))
break;
}
if (!opt_end)
return '?';
if (longindex)
*longindex = lo-longopts;
if (*opt_end == '=') {
if (lo->has_arg)
optarg = (char *)opt_end+1;
else
return '?';
} else if (lo->has_arg == 1) {
if (!(optarg = argv[optind]))
return '?';
optind++;
}
if (lo->flag) {
*lo->flag = lo->val;
return 0;
} else {
return lo->val;
}
}
if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
/* Someone frobbed optind, change to new opt. */
pvt.optptr = carg + 1;
}
opt = *pvt.optptr++;
if (opt != ':' && (osptr = strchr(optstring, opt))) {
if (osptr[1] == ':') {
if (*pvt.optptr) {
/* Argument-taking option with attached
argument */
optarg = (char *)pvt.optptr;
optind++;
} else {
/* Argument-taking option with non-attached
argument */
if (argv[optind + 1]) {
optarg = (char *)argv[optind+1];
optind += 2;
} else {
/* Missing argument */
optind++;
return (optstring[0] == ':')
? ':' : '?';
}
}
return opt;
} else {
/* Non-argument-taking option */
/* pvt.optptr will remember the exact position to
resume at */
if (!*pvt.optptr)
optind++;
return opt;
}
} else {
/* Unknown option */
optopt = opt;
if (!*pvt.optptr)
optind++;
return '?';
}
}

View file

@ -1,52 +0,0 @@
/*
* inet_ntop.c
*
* Simple version of inet_ntop()
*
*/
#include "config.h"
extern int errno;
const char *inet_ntop(int af, const void *src,
char *dst, socklen_t cnt)
{
char *p;
switch(af) {
case AF_INET:
p = inet_ntoa(*((struct in_addr *)src));
if (p) {
if (cnt <= strlen(p)) {
errno = ENOSPC;
dst = NULL;
} else
strcpy(dst, p);
} else
dst = NULL;
break;
#ifdef HAVE_IPV6
case AF_INET6:
if (cnt < 40) {
errno = ENOSPC;
dst = NULL;
} else {
struct in6_addr *a = src;
int i;
p = (char *)dst;
/* we do not compress :0: to :: */
for (i = 0; i < 8; i++)
p += sprintf(p, "%x:", ntohs(a->s6_addr16[i]));
p--;
*p = 0;
}
break;
#endif
default:
errno = EAFNOSUPPORT;
dst = NULL;
}
return dst;
}

View file

@ -5,7 +5,8 @@
* *
*/ */
#include "config.h" #include <stdlib.h>
#include <stdio.h>
void *xmalloc(size_t size) void *xmalloc(size_t size)
{ {

View file

@ -5,7 +5,9 @@
* *
*/ */
#include "config.h" #include <stdlib.h>
#include <string.h>
#include <stdio.h>
char *xstrdup(const char *s) char *xstrdup(const char *s)
{ {

View file

@ -17,25 +17,20 @@ releasedir=$PACKAGE-$release
GIT_DIR=`cd "${GIT_DIR-.git}" && pwd` GIT_DIR=`cd "${GIT_DIR-.git}" && pwd`
export GIT_DIR export GIT_DIR
if [ `git diff --cached | wc -l` -ne 0 ]; then
echo "$0: index not clean" 1>&2
exit 1
fi
if [ x"$release" = x'test' ]; then if [ x"$release" = x'test' ]; then
release=`cat version` release=`cat version`
releasetag=HEAD releasetag=HEAD
releasedir=$PACKAGE-$release releasedir=$PACKAGE-$release
else else
echo $release > version echo $release > version.new
if [ `git diff version | wc -l` -ne 0 ]; then if ! cmp -s version version.new ; then
git add version mv -f version.new version
git commit -m "Update version for release $release" version cg-commit -m 'Update version for release' version
else else
git checkout version rm -f version.new
fi fi
rm -f "$GIT_DIR"/refs/tags/$releasetag rm -f "$GIT_DIR"/refs/tags/$releasetag
git tag -a -m "$releasetag" -f "$releasetag" cg-tag $releasetag
fi fi
here=`pwd` here=`pwd`
@ -44,8 +39,7 @@ tmpdir=/var/tmp/release.$$
rm -rf $tmpdir rm -rf $tmpdir
mkdir -p $tmpdir mkdir -p $tmpdir
cd $tmpdir cd $tmpdir
mkdir -p $releasedir cg-export -r $releasetag $releasedir
git archive --format=tar $releasetag | tar -xf - -C $releasedir
cd $releasedir cd $releasedir
make release make release
rm -f release.sh rm -f release.sh

View file

@ -5,7 +5,7 @@ Release: 1
License: BSD License: BSD
Group: Applications/Internet Group: Applications/Internet
Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{version}.tar.gz Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{version}.tar.gz
BuildRequires: tcp_wrappers-devel BuildPreReq: tcp_wrappers
BuildRoot: %{_tmppath}/%{name}-root BuildRoot: %{_tmppath}/%{name}-root
%description %description

View file

@ -1,17 +1,17 @@
SRCROOT = .. SRCROOT = ..
VERSION = $(shell cat ../version) VERSION = $(shell cat ../version)
-include ../config/MCONFIG -include ../MCONFIG
include ../MRULES include ../MRULES
OBJS = tftp.$(O) main.$(O) OBJS = tftp.$(O) main.$(O) tftpsubs.$(O)
all: tftp$(X) tftp.1 all: tftp$(X) tftp.1
tftp$(X): $(OBJS) tftp$(X): $(OBJS)
$(CC) $(LDFLAGS) $^ $(TFTP_LIBS) -o $@ $(CC) $(LDFLAGS) $^ $(TFTP_LIBS) -o $@
$(OBJS): ../common/tftpsubs.h $(OBJS): tftpsubs.h
tftp.1: tftp.1.in ../version tftp.1: tftp.1.in ../version
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@ sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@

View file

@ -1,3 +1,8 @@
/* $Id$ */
/* $OpenBSD: extern.h,v 1.2 1996/06/26 05:40:33 deraadt Exp $ */
/* $NetBSD: extern.h,v 1.2 1994/12/08 09:51:24 jtc Exp $ */
/* /*
* Copyright (c) 1993 * Copyright (c) 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@ -29,15 +34,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * 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 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
*/ */
#ifndef EXTERN_H #ifndef RECVFILE_H
#define EXTERN_H #define RECVFILE_H
#include "config.h"
void tftp_recvfile (int, const char *, const char *); void tftp_recvfile (int, const char *, const char *);
void tftp_sendfile (int, const char *, const char *); void tftp_sendfile (int, const char *, const char *);
extern sigjmp_buf toplevel;
#endif #endif

View file

@ -1,3 +1,6 @@
/* $OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert Exp $ */
/* $NetBSD: main.c,v 1.6 1995/05/21 16:54:10 mycroft Exp $ */
/* /*
* Copyright (c) 1983, 1993 * Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@ -31,7 +34,17 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include "common/tftpsubs.h" #include "tftpsubs.h"
#ifndef lint
static const char *copyright UNUSED =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
/* static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; */
/* static char rcsid[] = "$OpenBSD: main.c,v 1.4 1997/01/17 07:13:30 millert Exp $"; */
static const char *rcsid UNUSED =
"tftp-hpa $Id$";
#endif /* not lint */
/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
@ -40,6 +53,7 @@
*/ */
#include <sys/file.h> #include <sys/file.h>
#include <ctype.h> #include <ctype.h>
#include <netdb.h>
#ifdef WITH_READLINE #ifdef WITH_READLINE
#include <readline/readline.h> #include <readline/readline.h>
#ifdef HAVE_READLINE_HISTORY_H #ifdef HAVE_READLINE_HISTORY_H
@ -66,25 +80,15 @@ static const struct modes modes[] = {
{ "image", "octet", O_BINARY }, { "image", "octet", O_BINARY },
{ 0, 0, 0 } { 0, 0, 0 }
}; };
#define MODE_OCTET (&modes[2]) #define MODE_OCTET (&modes[2])
#define MODE_NETASCII (&modes[0]) #define MODE_NETASCII (&modes[0])
#define MODE_DEFAULT MODE_NETASCII #define MODE_DEFAULT MODE_NETASCII
#ifdef HAVE_IPV6 struct sockaddr_in peeraddr;
int ai_fam = AF_UNSPEC; int f;
int ai_fam_sock = AF_UNSPEC;
#else
int ai_fam = AF_INET;
int ai_fam_sock = AF_INET;
#endif
union sock_addr peeraddr;
int f = -1;
u_short port; u_short port;
int trace; int trace;
int verbose; int verbose;
int literal;
int connected; int connected;
const struct modes *mode; const struct modes *mode;
#ifdef WITH_READLINE #ifdef WITH_READLINE
@ -98,9 +102,6 @@ const char *prompt = "tftp> ";
sigjmp_buf toplevel; sigjmp_buf toplevel;
void intr(int); void intr(int);
struct servent *sp; struct servent *sp;
int portrange = 0;
unsigned int portrange_from = 0;
unsigned int portrange_to = 0;
void get (int, char **); void get (int, char **);
void help (int, char **); void help (int, char **);
@ -115,7 +116,6 @@ void settimeout(int, char **);
void settrace (int, char **); void settrace (int, char **);
void setverbose (int, char **); void setverbose (int, char **);
void status (int, char **); void status (int, char **);
void setliteral(int, char **);
static void command (void); static void command (void);
@ -154,9 +154,6 @@ struct cmd cmdtab[] = {
{ "trace", { "trace",
"toggle packet tracing", "toggle packet tracing",
settrace }, settrace },
{"literal",
"toggle literal mode, ignore ':' in file name",
setliteral},
{ "status", { "status",
"show current status", "show current status",
status }, status },
@ -188,21 +185,16 @@ char *xstrdup(const char *);
const char *program; const char *program;
static void usage(int errcode) static inline void usage(int errcode)
{ {
fprintf(stderr, fprintf(stderr, "Usage: %s [-v][-m mode] [host [port]] [-c command]\n", program);
#ifdef HAVE_IPV6
"Usage: %s [-4][-6][-v][-l][-m mode] [host [port]] [-c command]\n",
#else
"Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n",
#endif
program);
exit(errcode); exit(errcode);
} }
int main(int argc, char *argv[]) int
main(int argc, char *argv[])
{ {
union sock_addr sa; struct sockaddr_in s_in;
int arg; int arg;
static int pargc, peerargc; static int pargc, peerargc;
static int iscmd = 0; static int iscmd = 0;
@ -221,14 +213,6 @@ int main(int argc, char *argv[])
if ( argv[arg][0] == '-' ) { if ( argv[arg][0] == '-' ) {
for ( optx = &argv[arg][1] ; *optx ; optx++ ) { for ( optx = &argv[arg][1] ; *optx ; optx++ ) {
switch ( *optx ) { switch ( *optx ) {
case '4':
ai_fam = AF_INET;
break;
#ifdef HAVE_IPV6
case '6':
ai_fam = AF_INET6;
break;
#endif
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
@ -236,9 +220,6 @@ int main(int argc, char *argv[])
/* Print version and configuration to stdout and exit */ /* Print version and configuration to stdout and exit */
printf("%s\n", TFTP_CONFIG_STR); printf("%s\n", TFTP_CONFIG_STR);
exit(0); exit(0);
case 'l':
literal = 1;
break;
case 'm': case 'm':
if ( ++arg >= argc ) if ( ++arg >= argc )
usage(EX_USAGE); usage(EX_USAGE);
@ -252,8 +233,7 @@ int main(int argc, char *argv[])
if (p->m_name) { if (p->m_name) {
settftpmode(p); settftpmode(p);
} else { } else {
fprintf(stderr, "%s: invalid mode: %s\n", fprintf(stderr, "%s: invalid mode: %s\n", argv[0], argv[arg]);
argv[0], argv[arg]);
exit(EX_USAGE); exit(EX_USAGE);
} }
} }
@ -261,19 +241,6 @@ int main(int argc, char *argv[])
case 'c': case 'c':
iscmd = 1; iscmd = 1;
break; break;
case 'R':
if (++arg >= argc)
usage(EX_USAGE);
if (sscanf
(argv[arg], "%u:%u", &portrange_from,
&portrange_to) != 2
|| portrange_from > portrange_to
|| portrange_to > 65535) {
fprintf(stderr, "Bad port range: %s\n", argv[arg]);
exit(EX_USAGE);
}
portrange = 1;
break;
case 'h': case 'h':
default: default:
usage(*optx == 'h' ? 0 : EX_USAGE); usage(*optx == 'h' ? 0 : EX_USAGE);
@ -287,8 +254,6 @@ int main(int argc, char *argv[])
} }
} }
ai_fam_sock = ai_fam;
pargv = argv + arg; pargv = argv + arg;
pargc = argc - arg; pargc = argc - arg;
@ -296,16 +261,26 @@ int main(int argc, char *argv[])
if (sp == 0) { if (sp == 0) {
/* Use canned values */ /* Use canned values */
if (verbose) if (verbose)
fprintf(stderr, fprintf(stderr, "tftp: tftp/udp: unknown service, faking it...\n");
"tftp: tftp/udp: unknown service, faking it...\n");
sp = xmalloc(sizeof(struct servent)); sp = xmalloc(sizeof(struct servent));
sp->s_name = (char *)"tftp"; sp->s_name = (char *)"tftp";
sp->s_aliases = NULL; sp->s_aliases = NULL;
sp->s_port = htons(IPPORT_TFTP); sp->s_port = htons(IPPORT_TFTP);
sp->s_proto = (char *)"udp"; sp->s_proto = (char *)"udp";
} }
port = sp->s_port; /* Default port */
tftp_signal(SIGINT, intr, 0); f = socket(AF_INET, SOCK_DGRAM, 0);
if (f < 0) {
perror("tftp: socket");
exit(EX_OSERR);
}
bzero((char *)&s_in, sizeof (s_in));
s_in.sin_family = AF_INET;
if (bind(f, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
perror("tftp: bind");
exit(EX_OSERR);
}
bsd_signal(SIGINT, intr);
if ( peerargc ) { if ( peerargc ) {
/* Set peer */ /* Set peer */
@ -314,21 +289,6 @@ int main(int argc, char *argv[])
setpeer(peerargc, peerargv); setpeer(peerargc, peerargv);
} }
if (ai_fam_sock == AF_UNSPEC)
ai_fam_sock = AF_INET;
f = socket(ai_fam_sock, SOCK_DGRAM, 0);
if (f < 0) {
perror("tftp: socket");
exit(EX_OSERR);
}
bzero(&sa, sizeof(sa));
sa.sa.sa_family = ai_fam_sock;
if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
perror("tftp: bind");
exit(EX_OSERR);
}
if ( iscmd && pargc ) { if ( iscmd && pargc ) {
/* -c specified; execute command and exit */ /* -c specified; execute command and exit */
struct cmd *c; struct cmd *c;
@ -338,21 +298,21 @@ int main(int argc, char *argv[])
c = getcmd(pargv[0]); c = getcmd(pargv[0]);
if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) { if ( c == (struct cmd *)-1 || c == (struct cmd *)0 ) {
fprintf(stderr, "%s: invalid command: %s\n", argv[0], fprintf(stderr, "%s: invalid command: %s\n", argv[0], pargv[1]);
pargv[1]);
exit(EX_USAGE); exit(EX_USAGE);
} }
(*c->handler)(pargc, pargv); (*c->handler)(pargc, pargv);
exit(0); exit(0);
} }
if (sigsetjmp(toplevel,1) != 0)
(void)putchar('\n');
#ifdef WITH_READLINE #ifdef WITH_READLINE
#ifdef HAVE_READLINE_HISTORY_H #ifdef HAVE_READLINE_HISTORY_H
using_history(); using_history();
#endif #endif
#endif #endif
if (sigsetjmp(toplevel, 1) != 0)
(void)putchar('\n');
command(); command();
return 0; /* Never reached */ return 0; /* Never reached */
@ -362,7 +322,8 @@ char *hostname;
/* Called when a command is incomplete; modifies /* Called when a command is incomplete; modifies
the global variable "line" */ the global variable "line" */
static void getmoreargs(const char *partial, const char *mprompt) static void
getmoreargs(const char *partial, const char *mprompt)
{ {
#ifdef WITH_READLINE #ifdef WITH_READLINE
char *eline; char *eline;
@ -375,10 +336,8 @@ static void getmoreargs(const char *partial, const char *mprompt)
elen = strlen(eline); elen = strlen(eline);
if (line) { if (line)
free(line); free(line);
line = NULL;
}
line = xmalloc(len+elen+1); line = xmalloc(len+elen+1);
strcpy(line, partial); strcpy(line, partial);
strcpy(line+len, eline); strcpy(line+len, eline);
@ -398,9 +357,10 @@ static void getmoreargs(const char *partial, const char *mprompt)
#endif #endif
} }
void setpeer(int argc, char *argv[]) void
setpeer(int argc, char *argv[])
{ {
int err; struct hostent *host;
if (argc < 2) { if (argc < 2) {
getmoreargs("connect ", "(to) "); getmoreargs("connect ", "(to) ");
@ -413,36 +373,16 @@ void setpeer(int argc, char *argv[])
return; return;
} }
peeraddr.sa.sa_family = ai_fam; host = gethostbyname(argv[1]);
err = set_sock_addr(argv[1], &peeraddr, &hostname); if (host == 0) {
if (err) {
printf("Error: %s\n", gai_strerror(err));
printf("%s: unknown host\n", argv[1]);
connected = 0; connected = 0;
printf("%s: unknown host\n", argv[1]);
return; return;
} }
ai_fam = peeraddr.sa.sa_family; peeraddr.sin_family = host->h_addrtype;
if (f == -1) { /* socket not open */ bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
ai_fam_sock = ai_fam; hostname = xstrdup(host->h_name);
} else { /* socket was already open */
if (ai_fam_sock != ai_fam) { /* need reopen socken for new family */
union sock_addr sa;
close(f);
ai_fam_sock = ai_fam;
f = socket(ai_fam_sock, SOCK_DGRAM, 0);
if (f < 0) {
perror("tftp: socket");
exit(EX_OSERR);
}
bzero((char *)&sa, sizeof (sa));
sa.sa.sa_family = ai_fam_sock;
if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
perror("tftp: bind");
exit(EX_OSERR);
}
}
}
port = sp->s_port; port = sp->s_port;
if (argc == 3) { if (argc == 3) {
struct servent *usp; struct servent *usp;
@ -463,18 +403,15 @@ void setpeer(int argc, char *argv[])
} }
if (verbose) { if (verbose) {
char tmp[INET6_ADDRSTRLEN], *tp;
tp = (char *)inet_ntop(peeraddr.sa.sa_family, SOCKADDR_P(&peeraddr),
tmp, INET6_ADDRSTRLEN);
if (!tp)
tp = (char *)"???";
printf("Connected to %s (%s), port %u\n", printf("Connected to %s (%s), port %u\n",
hostname, tp, (unsigned int)ntohs(port)); hostname, inet_ntoa(peeraddr.sin_addr),
(unsigned int)ntohs(port));
} }
connected = 1; connected = 1;
} }
void modecmd(int argc, char *argv[]) void
modecmd(int argc, char *argv[])
{ {
const struct modes *p; const struct modes *p;
const char *sep; const char *sep;
@ -506,34 +443,37 @@ void modecmd(int argc, char *argv[])
return; return;
} }
void setbinary(int argc, char *argv[]) void
setbinary(int argc, char *argv[])
{ {
(void)argc; (void)argc; (void)argv; /* Quiet unused warning */
(void)argv; /* Quiet unused warning */
settftpmode(MODE_OCTET); settftpmode(MODE_OCTET);
} }
void setascii(int argc, char *argv[]) void
setascii(int argc, char *argv[])
{ {
(void)argc; (void)argc; (void)argv; /* Quiet unused warning */
(void)argv; /* Quiet unused warning */
settftpmode(MODE_NETASCII); settftpmode(MODE_NETASCII);
} }
static void settftpmode(const struct modes *newmode) static void
settftpmode(const struct modes *newmode)
{ {
mode = newmode; mode = newmode;
if (verbose) if (verbose)
printf("mode set to %s\n", mode->m_mode); printf("mode set to %s\n", mode->m_mode);
} }
/* /*
* Send file(s). * Send file(s).
*/ */
void put(int argc, char *argv[]) void
put(int argc, char *argv[])
{ {
int fd; int fd;
int n, err; int n;
char *cp, *targ; char *cp, *targ;
if (argc < 2) { if (argc < 2) {
@ -547,7 +487,9 @@ void put(int argc, char *argv[])
return; return;
} }
targ = argv[argc - 1]; targ = argv[argc - 1];
if (!literal && strchr(argv[argc - 1], ':')) { if (strchr(argv[argc - 1], ':')) {
struct hostent *hp;
for (n = 1; n < argc - 1; n++) for (n = 1; n < argc - 1; n++)
if (strchr(argv[n], ':')) { if (strchr(argv[n], ':')) {
putusage(argv[0]); putusage(argv[0]);
@ -556,16 +498,16 @@ void put(int argc, char *argv[])
cp = argv[argc - 1]; cp = argv[argc - 1];
targ = strchr(cp, ':'); targ = strchr(cp, ':');
*targ++ = 0; *targ++ = 0;
peeraddr.sa.sa_family = ai_fam; hp = gethostbyname(cp);
err = set_sock_addr(cp, &peeraddr,&hostname); if (hp == NULL) {
if (err) { fprintf(stderr, "tftp: %s: ", cp);
printf("Error: %s\n", gai_strerror(err)); herror((char *)NULL);
printf("%s: unknown host\n", argv[1]);
connected = 0;
return; return;
} }
ai_fam = peeraddr.sa.sa_family; bcopy(hp->h_addr, &peeraddr.sin_addr, hp->h_length);
peeraddr.sin_family = hp->h_addrtype;
connected = 1; connected = 1;
hostname = xstrdup(hp->h_name);
} }
if (!connected) { if (!connected) {
printf("No target machine specified.\n"); printf("No target machine specified.\n");
@ -575,14 +517,13 @@ void put(int argc, char *argv[])
cp = argc == 2 ? tail(targ) : argv[1]; cp = argc == 2 ? tail(targ) : argv[1];
fd = open(cp, O_RDONLY|mode->m_openflags); fd = open(cp, O_RDONLY|mode->m_openflags);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "tftp: "); fprintf(stderr, "tftp: "); perror(cp);
perror(cp);
return; return;
} }
if (verbose) if (verbose)
printf("putting %s to %s:%s [%s]\n", printf("putting %s to %s:%s [%s]\n",
cp, hostname, targ, mode->m_mode); cp, hostname, targ, mode->m_mode);
sa_set_port(&peeraddr, port); peeraddr.sin_port = port;
tftp_sendfile(fd, targ, mode->m_mode); tftp_sendfile(fd, targ, mode->m_mode);
return; return;
} }
@ -594,19 +535,19 @@ void put(int argc, char *argv[])
strcpy(cp, tail(argv[n])); strcpy(cp, tail(argv[n]));
fd = open(argv[n], O_RDONLY|mode->m_openflags); fd = open(argv[n], O_RDONLY|mode->m_openflags);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "tftp: "); fprintf(stderr, "tftp: "); perror(argv[n]);
perror(argv[n]);
continue; continue;
} }
if (verbose) if (verbose)
printf("putting %s to %s:%s [%s]\n", printf("putting %s to %s:%s [%s]\n",
argv[n], hostname, targ, mode->m_mode); argv[n], hostname, targ, mode->m_mode);
sa_set_port(&peeraddr, port); peeraddr.sin_port = port;
tftp_sendfile(fd, targ, mode->m_mode); tftp_sendfile(fd, targ, mode->m_mode);
} }
} }
static void putusage(char *s) static void
putusage(char *s)
{ {
printf("usage: %s file ... host:target, or\n", s); printf("usage: %s file ... host:target, or\n", s);
printf(" %s file ... target (when already connected)\n", s); printf(" %s file ... target (when already connected)\n", s);
@ -615,7 +556,8 @@ static void putusage(char *s)
/* /*
* Receive file(s). * Receive file(s).
*/ */
void get(int argc, char *argv[]) void
get(int argc, char *argv[])
{ {
int fd; int fd;
int n; int n;
@ -634,62 +576,61 @@ void get(int argc, char *argv[])
} }
if (!connected) { if (!connected) {
for (n = 1; n < argc ; n++) for (n = 1; n < argc ; n++)
if (literal || strchr(argv[n], ':') == 0) { if (strchr(argv[n], ':') == 0) {
getusage(argv[0]); getusage(argv[0]);
return; return;
} }
} }
for (n = 1; n < argc ; n++) { for (n = 1; n < argc ; n++) {
src = strchr(argv[n], ':'); src = strchr(argv[n], ':');
if (literal || src == NULL) if (src == NULL)
src = argv[n]; src = argv[n];
else { else {
int err; struct hostent *hp;
*src++ = 0; *src++ = 0;
peeraddr.sa.sa_family = ai_fam; hp = gethostbyname(argv[n]);
err = set_sock_addr(argv[n], &peeraddr, &hostname); if (hp == NULL) {
if (err) { fprintf(stderr, "tftp: %s: ", argv[n]);
printf("Warning: %s\n", gai_strerror(err)); herror((char *)NULL);
printf("%s: unknown host\n", argv[1]);
continue; continue;
} }
ai_fam = peeraddr.sa.sa_family; bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
hp->h_length);
peeraddr.sin_family = hp->h_addrtype;
connected = 1; connected = 1;
hostname = xstrdup(hp->h_name);
} }
if (argc < 4) { if (argc < 4) {
cp = argc == 3 ? argv[2] : tail(src); cp = argc == 3 ? argv[2] : tail(src);
fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags, fd = open(cp, O_WRONLY|O_CREAT|O_TRUNC|mode->m_openflags, 0666);
0666);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "tftp: "); fprintf(stderr, "tftp: "); perror(cp);
perror(cp);
return; return;
} }
if (verbose) if (verbose)
printf("getting from %s:%s to %s [%s]\n", printf("getting from %s:%s to %s [%s]\n",
hostname, src, cp, mode->m_mode); hostname, src, cp, mode->m_mode);
sa_set_port(&peeraddr, port); peeraddr.sin_port = port;
tftp_recvfile(fd, src, mode->m_mode); tftp_recvfile(fd, src, mode->m_mode);
break; break;
} }
cp = tail(src); /* new .. jdg */ cp = tail(src); /* new .. jdg */
fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags, fd = open(cp, O_WRONLY|O_CREAT|O_TRUNC|mode->m_openflags, 0666);
0666);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "tftp: "); fprintf(stderr, "tftp: "); perror(cp);
perror(cp);
continue; continue;
} }
if (verbose) if (verbose)
printf("getting from %s:%s to %s [%s]\n", printf("getting from %s:%s to %s [%s]\n",
hostname, src, cp, mode->m_mode); hostname, src, cp, mode->m_mode);
sa_set_port(&peeraddr, port); peeraddr.sin_port = port;
tftp_recvfile(fd, src, mode->m_mode); tftp_recvfile(fd, src, mode->m_mode);
} }
} }
static void getusage(char *s) static void
getusage(char *s)
{ {
printf("usage: %s host:file host:file ... file, or\n", s); printf("usage: %s host:file host:file ... file, or\n", s);
printf(" %s file file ... file if connected\n", s); printf(" %s file file ... file if connected\n", s);
@ -697,7 +638,8 @@ static void getusage(char *s)
int rexmtval = TIMEOUT; int rexmtval = TIMEOUT;
void setrexmt(int argc, char *argv[]) void
setrexmt(int argc, char *argv[])
{ {
int t; int t;
@ -720,7 +662,8 @@ void setrexmt(int argc, char *argv[])
int maxtimeout = 5 * TIMEOUT; int maxtimeout = 5 * TIMEOUT;
void settimeout(int argc, char *argv[]) void
settimeout(int argc, char *argv[])
{ {
int t; int t;
@ -741,39 +684,32 @@ void settimeout(int argc, char *argv[])
maxtimeout = t; maxtimeout = t;
} }
void setliteral(int argc, char *argv[]) void
status(int argc, char *argv[])
{ {
(void)argc; (void)argc; (void)argv; /* Quiet unused warning */
(void)argv; /* Quiet unused warning */
literal = !literal;
printf("Literal mode %s.\n", literal ? "on" : "off");
}
void status(int argc, char *argv[])
{
(void)argc;
(void)argv; /* Quiet unused warning */
if (connected) if (connected)
printf("Connected to %s.\n", hostname); printf("Connected to %s.\n", hostname);
else else
printf("Not connected.\n"); printf("Not connected.\n");
printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode->m_mode, printf("Mode: %s Verbose: %s Tracing: %s\n", mode->m_mode,
verbose ? "on" : "off", trace ? "on" : "off", verbose ? "on" : "off", trace ? "on" : "off");
literal ? "on" : "off");
printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
rexmtval, maxtimeout); rexmtval, maxtimeout);
} }
void intr(int sig) void
intr(int sig)
{ {
(void)sig; /* Quiet unused warning */ (void)sig; /* Quiet unused warning */
bsd_signal(SIGALRM, SIG_IGN);
alarm(0); alarm(0);
tftp_signal(SIGALRM, SIG_DFL, 0);
siglongjmp(toplevel, -1); siglongjmp(toplevel, -1);
} }
char *tail(char *filename) char *
tail(char *filename)
{ {
char *s; char *s;
@ -791,22 +727,20 @@ char *tail(char *filename)
/* /*
* Command parser. * Command parser.
*/ */
static void command(void) static void
command(void)
{ {
struct cmd *c; struct cmd *c;
for (;;) { for (;;) {
#ifdef WITH_READLINE #ifdef WITH_READLINE
if (line) { if ( line )
free(line); free(line);
line = NULL;
}
line = readline(prompt); line = readline(prompt);
if ( !line ) if ( !line )
exit(0); /* EOF */ exit(0); /* EOF */
#else #else
fputs(prompt, stdout); fputs(prompt, stdout);
fflush(stdout);
if (fgets(line, LBUFLEN, stdin) == 0) { if (fgets(line, LBUFLEN, stdin) == 0) {
if (feof(stdin)) { if (feof(stdin)) {
exit(0); exit(0);
@ -839,7 +773,8 @@ static void command(void)
} }
} }
struct cmd *getcmd(char *name) struct cmd *
getcmd(char *name)
{ {
const char *p; const char *p;
char *q; char *q;
@ -870,7 +805,8 @@ struct cmd *getcmd(char *name)
/* /*
* Slice a string up into argc/argv. * Slice a string up into argc/argv.
*/ */
static void makeargv(void) static void
makeargv(void)
{ {
char *cp; char *cp;
char **argp = margv; char **argp = margv;
@ -892,17 +828,18 @@ static void makeargv(void)
*argp++ = 0; *argp++ = 0;
} }
void quit(int argc, char *argv[]) void
quit(int argc, char *argv[])
{ {
(void)argc; (void)argc; (void)argv; /* Quiet unused warning */
(void)argv; /* Quiet unused warning */
exit(0); exit(0);
} }
/* /*
* Help command. * Help command.
*/ */
void help(int argc, char *argv[]) void
help(int argc, char *argv[])
{ {
struct cmd *c; struct cmd *c;
@ -927,19 +864,19 @@ void help(int argc, char *argv[])
} }
} }
void settrace(int argc, char *argv[]) void
settrace(int argc, char *argv[])
{ {
(void)argc; (void)argc; (void)argv; /* Quiet unused warning */
(void)argv; /* Quiet unused warning */
trace = !trace; trace = !trace;
printf("Packet tracing %s.\n", trace ? "on" : "off"); printf("Packet tracing %s.\n", trace ? "on" : "off");
} }
void setverbose(int argc, char *argv[]) void
setverbose(int argc, char *argv[])
{ {
(void)argc; (void)argc; (void)argv; /* Quiet unused warning */
(void)argv; /* Quiet unused warning */
verbose = !verbose; verbose = !verbose;
printf("Verbose mode %s.\n", verbose ? "on" : "off"); printf("Verbose mode %s.\n", verbose ? "on" : "off");

View file

@ -1,4 +1,5 @@
.\" -*- nroff -*- --------------------------------------------------------- * .\" -*- nroff -*- --------------------------------------------------------- *
.\" $Id$
.\" .\"
.\" Copyright (c) 1990, 1993, 1994 .\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -30,7 +31,7 @@
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\"----------------------------------------------------------------------- */ .\"----------------------------------------------------------------------- */
.TH TFTP 1 "23 July 2008" "tftp-hpa @@VERSION@@" "User's Manual" .TH TFTP 1 "2 February 2003" "tftp-hpa @@VERSION@@" "User's Manual"
.SH NAME .SH NAME
.B tftp .B tftp
\- IPv4 Trivial File Transfer Protocol client \- IPv4 Trivial File Transfer Protocol client
@ -42,7 +43,7 @@
.br .br
.SH DESCRIPTION .SH DESCRIPTION
.B tftp .B tftp
is a client for the Trivial file Transfer Protocol, which can be is a client for the IPv4 Trivial file Transfer Protocol, which can be
used to transfer files to and from remote machines, including some used to transfer files to and from remote machines, including some
very minimalistic, usually embedded, systems. The remote very minimalistic, usually embedded, systems. The remote
.I host .I host
@ -55,27 +56,13 @@ as the default host for future transfers (see the
command below.) command below.)
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-4
Connect with IPv4 only, even if IPv6 support was compiled in.
.TP
.B \-6
Connect with IPv6 only, if compiled in.
.TP
\fB\-c\fP \fIcommand\fP \fB\-c\fP \fIcommand\fP
Execute \fIcommand\fP as if it had been entered on the tftp prompt. Execute \fIcommand\fP as if it had been entered on the tftp prompt.
Must be specified last on the command line. Must be specified last on the command line.
.TP .TP
.B \-l
Default to literal mode. Used to avoid special processing of ':' in a
file name.
.TP
\fB\-m\fP \fImode\fP \fB\-m\fP \fImode\fP
Set the default transfer mode to \fImode\fP. This is usually used with \-c. Set the default transfer mode to \fImode\fP. This is usually used with \-c.
.TP .TP
\fB\-R\fP \fIport:port\fP
Force the originating port number to be in the specified range of port
numbers.
.TP
.B \-v .B \-v
Default to verbose mode. Default to verbose mode.
.TP .TP
@ -132,12 +119,7 @@ host, if the host has already been specified, or a string of the form
.I "host:filename" .I "host:filename"
to specify both a host and filename at the same time. If the latter to specify both a host and filename at the same time. If the latter
form is used, the last hostname specified becomes the default for form is used, the last hostname specified becomes the default for
future transfers. Enable future transfers.
.B literal
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
.TP
.B literal
Toggle literal mode. When set, this mode prevents special treatment of ':' in filenames.
.TP .TP
\fBmode\fP \fItransfer-mode\fP \fBmode\fP \fItransfer-mode\fP
Specify the mode for transfers; Specify the mode for transfers;
@ -169,9 +151,7 @@ form is used, the hostname specified becomes the default for future
transfers. If the remote-directory form is used, the remote host is transfers. If the remote-directory form is used, the remote host is
assumed to be a UNIX system or another system using assumed to be a UNIX system or another system using
.B / .B /
as directory separator. Enable as directory separator.
.B literal
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
.TP .TP
.B quit .B quit
Exit Exit

View file

@ -1,3 +1,8 @@
/* $Id$ */
/* $OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $ */
/* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $ */
/* /*
* Copyright (c) 1983, 1993 * Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@ -31,14 +36,23 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include "common/tftpsubs.h" #include "tftpsubs.h"
#ifndef lint
/* static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; */
/* static char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $"; */
static const char *rcsid UNUSED =
"tftp-hpa $Id$";
#endif /* not lint */
/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
/* /*
* TFTP User Program -- Protocol Machines * TFTP User Program -- Protocol Machines
*/ */
#include "extern.h" #include "extern.h"
extern union sock_addr peeraddr; /* filled in by main */ extern struct sockaddr_in peeraddr; /* filled in by main */
extern int f; /* the opened socket */ extern int f; /* the opened socket */
extern int trace; extern int trace;
extern int verbose; extern int verbose;
@ -48,7 +62,8 @@ extern int maxtimeout;
#define PKTSIZE SEGSIZE+4 #define PKTSIZE SEGSIZE+4
char ackbuf[PKTSIZE]; char ackbuf[PKTSIZE];
int timeout; int timeout;
static sigjmp_buf timeoutbuf; sigjmp_buf toplevel;
sigjmp_buf timeoutbuf;
static void nak(int, const char *); static void nak(int, const char *);
static int makerequest(int, const char *, struct tftphdr *, const char *); static int makerequest(int, const char *, struct tftphdr *, const char *);
@ -61,7 +76,8 @@ static void tpacket(const char *, struct tftphdr *, int);
/* /*
* Send the requested file. * Send the requested file.
*/ */
void tftp_sendfile(int fd, const char *name, const char *mode) void
tftp_sendfile(int fd, const char *name, const char *mode)
{ {
struct tftphdr *ap; /* data and ack packets */ struct tftphdr *ap; /* data and ack packets */
struct tftphdr *dp; struct tftphdr *dp;
@ -70,8 +86,8 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
volatile u_short block; volatile u_short block;
volatile int size, convert; volatile int size, convert;
volatile off_t amount; volatile off_t amount;
union sock_addr from; struct sockaddr_in from;
socklen_t fromlen; int fromlen;
FILE *file; FILE *file;
u_short ap_opcode, ap_block; u_short ap_opcode, ap_block;
@ -84,7 +100,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
is_request = 1; /* First packet is the actual WRQ */ is_request = 1; /* First packet is the actual WRQ */
amount = 0; amount = 0;
tftp_signal(SIGALRM, timer, 0); bsd_signal(SIGALRM, timer);
do { do {
if (is_request) { if (is_request) {
size = makerequest(WRQ, name, dp, mode) - 4; size = makerequest(WRQ, name, dp, mode) - 4;
@ -104,7 +120,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
if (trace) if (trace)
tpacket("sent", dp, size + 4); tpacket("sent", dp, size + 4);
n = sendto(f, dp, size + 4, 0, n = sendto(f, dp, size + 4, 0,
&peeraddr.sa, SOCKLEN(&peeraddr)); (struct sockaddr *)&peeraddr, sizeof(peeraddr));
if (n != size + 4) { if (n != size + 4) {
perror("tftp: sendto"); perror("tftp: sendto");
goto abort; goto abort;
@ -115,21 +131,22 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
do { do {
fromlen = sizeof(from); fromlen = sizeof(from);
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
&from.sa, &fromlen); (struct sockaddr *)&from, &fromlen);
} while (n <= 0); } while (n <= 0);
alarm(0); alarm(0);
if (n < 0) { if (n < 0) {
perror("tftp: recvfrom"); perror("tftp: recvfrom");
goto abort; goto abort;
} }
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */ peeraddr.sin_port = from.sin_port; /* added */
if (trace) if (trace)
tpacket("received", ap, n); tpacket("received", ap, n);
/* should verify packet came from server */ /* should verify packet came from server */
ap_opcode = ntohs((u_short)ap->th_opcode); ap_opcode = ntohs((u_short)ap->th_opcode);
ap_block = ntohs((u_short)ap->th_block); ap_block = ntohs((u_short)ap->th_block);
if (ap_opcode == ERROR) { if (ap_opcode == ERROR) {
printf("Error code %d: %s\n", ap_block, ap->th_msg); printf("Error code %d: %s\n", ap_block,
ap->th_msg);
goto abort; goto abort;
} }
if (ap_opcode == ACK) { if (ap_opcode == ACK) {
@ -143,7 +160,8 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
*/ */
j = synchnet(f); j = synchnet(f);
if (j && trace) { if (j && trace) {
printf("discarded %d packets\n", j); printf("discarded %d packets\n",
j);
} }
/* /*
* RFC1129/RFC1350: We MUST NOT re-send the DATA * RFC1129/RFC1350: We MUST NOT re-send the DATA
@ -167,7 +185,8 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
/* /*
* Receive a file. * Receive a file.
*/ */
void tftp_recvfile(int fd, const char *name, const char *mode) void
tftp_recvfile(int fd, const char *name, const char *mode)
{ {
struct tftphdr *ap; struct tftphdr *ap;
struct tftphdr *dp; struct tftphdr *dp;
@ -175,8 +194,8 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
volatile u_short block; volatile u_short block;
volatile int size, firsttrip; volatile int size, firsttrip;
volatile unsigned long amount; volatile unsigned long amount;
union sock_addr from; struct sockaddr_in from;
socklen_t fromlen; int fromlen;
FILE *file; FILE *file;
volatile int convert; /* true if converting crlf -> lf */ volatile int convert; /* true if converting crlf -> lf */
u_short dp_opcode, dp_block; u_short dp_opcode, dp_block;
@ -190,7 +209,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
firsttrip = 1; firsttrip = 1;
amount = 0; amount = 0;
tftp_signal(SIGALRM, timer, 0); bsd_signal(SIGALRM, timer);
do { do {
if (firsttrip) { if (firsttrip) {
size = makerequest(RRQ, name, ap, mode); size = makerequest(RRQ, name, ap, mode);
@ -206,8 +225,8 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
send_ack: send_ack:
if (trace) if (trace)
tpacket("sent", ap, size); tpacket("sent", ap, size);
if (sendto(f, ackbuf, size, 0, &peeraddr.sa, if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
SOCKLEN(&peeraddr)) != size) { sizeof(peeraddr)) != size) {
alarm(0); alarm(0);
perror("tftp: sendto"); perror("tftp: sendto");
goto abort; goto abort;
@ -218,14 +237,14 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
do { do {
fromlen = sizeof(from); fromlen = sizeof(from);
n = recvfrom(f, dp, PKTSIZE, 0, n = recvfrom(f, dp, PKTSIZE, 0,
&from.sa, &fromlen); (struct sockaddr *)&from, &fromlen);
} while (n <= 0); } while (n <= 0);
alarm(0); alarm(0);
if (n < 0) { if (n < 0) {
perror("tftp: recvfrom"); perror("tftp: recvfrom");
goto abort; goto abort;
} }
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */ peeraddr.sin_port = from.sin_port; /* added */
if (trace) if (trace)
tpacket("received", dp, n); tpacket("received", dp, n);
/* should verify client address */ /* should verify client address */
@ -265,7 +284,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
ap->th_block = htons((u_short)block); ap->th_block = htons((u_short)block);
(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr, (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
SOCKLEN(&peeraddr)); sizeof(peeraddr));
write_behind(file, convert); /* flush last buffer */ write_behind(file, convert); /* flush last buffer */
fclose(file); fclose(file);
stopclock(); stopclock();
@ -278,20 +297,20 @@ makerequest(int request, const char *name,
struct tftphdr *tp, const char *mode) struct tftphdr *tp, const char *mode)
{ {
char *cp; char *cp;
size_t len;
tp->th_opcode = htons((u_short)request); tp->th_opcode = htons((u_short)request);
cp = (char *) &(tp->th_stuff); cp = (char *) &(tp->th_stuff);
len = strlen(name) + 1; strcpy(cp, name);
memcpy(cp, name, len); cp += strlen(name);
cp += len; *cp++ = '\0';
len = strlen(mode) + 1; strcpy(cp, mode);
memcpy(cp, mode, len); cp += strlen(mode);
cp += len; *cp++ = '\0';
return (cp - (char *)tp); return (cp - (char *)tp);
} }
static const char *const errmsgs[] = { static const char * const errmsgs[] =
{
"Undefined error code", /* 0 - EUNDEF */ "Undefined error code", /* 0 - EUNDEF */
"File not found", /* 1 - ENOTFOUND */ "File not found", /* 1 - ENOTFOUND */
"Access denied", /* 2 - EACCESS */ "Access denied", /* 2 - EACCESS */
@ -302,7 +321,6 @@ static const char *const errmsgs[] = {
"No such user", /* 7 - ENOUSER */ "No such user", /* 7 - ENOUSER */
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */ "Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
}; };
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *)) #define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
/* /*
@ -311,7 +329,8 @@ static const char *const errmsgs[] = {
* standard TFTP codes, or a UNIX errno * standard TFTP codes, or a UNIX errno
* offset by 100. * offset by 100.
*/ */
static void nak(int error, const char *msg) static void
nak(int error, const char *msg)
{ {
struct tftphdr *tp; struct tftphdr *tp;
int length; int length;
@ -341,12 +360,13 @@ static void nak(int error, const char *msg)
if (trace) if (trace)
tpacket("sent", tp, length); tpacket("sent", tp, length);
if (sendto(f, ackbuf, length, 0, &peeraddr.sa, if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
SOCKLEN(&peeraddr)) != length) sizeof(peeraddr)) != length)
perror("nak"); perror("nak");
} }
static void tpacket(const char *s, struct tftphdr *tp, int n) static void
tpacket(const char *s, struct tftphdr *tp, int n)
{ {
static const char *opcodes[] = static const char *opcodes[] =
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" }; { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
@ -384,18 +404,21 @@ static void tpacket(const char *s, struct tftphdr *tp, int n)
struct timeval tstart; struct timeval tstart;
struct timeval tstop; struct timeval tstop;
static void startclock(void) static void
startclock(void)
{ {
(void)gettimeofday(&tstart, NULL); (void)gettimeofday(&tstart, NULL);
} }
static void stopclock(void) static void
stopclock(void)
{ {
(void)gettimeofday(&tstop, NULL); (void)gettimeofday(&tstop, NULL);
} }
static void printstats(const char *direction, unsigned long amount) static void
printstats(const char *direction, unsigned long amount)
{ {
double delta; double delta;
@ -408,7 +431,8 @@ static void printstats(const char *direction, unsigned long amount)
} }
} }
static void timer(int sig) static void
timer(int sig)
{ {
int save_errno = errno; int save_errno = errno;

274
tftp/tftpsubs.c Normal file
View file

@ -0,0 +1,274 @@
/* tftp-hpa: $Id$ */
/* $OpenBSD: tftpsubs.c,v 1.2 1996/06/26 05:40:36 deraadt Exp $ */
/* $NetBSD: tftpsubs.c,v 1.3 1994/12/08 09:51:31 jtc Exp $ */
/*
* Copyright (c) 1983, 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.
*/
#include "tftpsubs.h"
#ifndef lint
/* static char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93"; */
/* static char rcsid[] = "$OpenBSD: tftpsubs.c,v 1.2 1996/06/26 05:40:36 deraadt Exp $"; */
static const char *rcsid UNUSED =
"tftp-hpa: $Id$";
#endif /* not lint */
/* Simple minded read-ahead/write-behind subroutines for tftp user and
server. Written originally with multiple buffers in mind, but current
implementation has two buffer logic wired in.
Todo: add some sort of final error check so when the write-buffer
is finally flushed, the caller can detect if the disk filled up
(or had an i/o error) and return a nak to the other side.
Jim Guyton 10/85
*/
#include <sys/ioctl.h>
#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
int segsize = SEGSIZE; /* Default segsize */
struct bf {
int counter; /* size of data in buffer, or flag */
char buf[PKTSIZE]; /* room for data packet */
} bfs[2];
/* Values for bf.counter */
#define BF_ALLOC -3 /* alloc'd but not yet filled */
#define BF_FREE -2 /* free */
/* [-1 .. segsize] = size of data in the data buffer */
static int nextone; /* index of next buffer to use */
static int current; /* index of buffer in use */
/* control flags for crlf conversions */
int newline = 0; /* fillbuf: in middle of newline expansion */
int prevchar = -1; /* putbuf: previous char (cr check) */
static struct tftphdr *rw_init(int);
struct tftphdr *w_init() { return rw_init(0); } /* write-behind */
struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */
/* init for either read-ahead or write-behind */
/* x == zero for write-behind, one for read-head */
static struct tftphdr *
rw_init(int x)
{
newline = 0; /* init crlf flag */
prevchar = -1;
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
current = 0;
bfs[1].counter = BF_FREE;
nextone = x; /* ahead or behind? */
return (struct tftphdr *)bfs[0].buf;
}
/* Have emptied current buffer by sending to net and getting ack.
Free it and return next buffer filled with data.
*/
int
readit(FILE *file, struct tftphdr **dpp, int convert)
{
struct bf *b;
bfs[current].counter = BF_FREE; /* free old one */
current = !current; /* "incr" current */
b = &bfs[current]; /* look at new buffer */
if (b->counter == BF_FREE) /* if it's empty */
read_ahead(file, convert); /* fill it */
/* assert(b->counter != BF_FREE);*//* check */
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
return b->counter;
}
/*
* fill the input buffer, doing ascii conversions if requested
* conversions are lf -> cr,lf and cr -> cr, nul
*/
void
read_ahead(FILE *file, int convert)
{
int i;
char *p;
int c;
struct bf *b;
struct tftphdr *dp;
b = &bfs[nextone]; /* look at "next" buffer */
if (b->counter != BF_FREE) /* nop if not free */
return;
nextone = !nextone; /* "incr" next buffer ptr */
dp = (struct tftphdr *)b->buf;
if (convert == 0) {
b->counter = read(fileno(file), dp->th_data, segsize);
return;
}
p = dp->th_data;
for (i = 0 ; i < segsize; i++) {
if (newline) {
if (prevchar == '\n')
c = '\n'; /* lf to cr,lf */
else c = '\0'; /* cr to cr,nul */
newline = 0;
}
else {
c = getc(file);
if (c == EOF) break;
if (c == '\n' || c == '\r') {
prevchar = c;
c = '\r';
newline = 1;
}
}
*p++ = c;
}
b->counter = (int)(p - dp->th_data);
}
/* Update count associated with the buffer, get new buffer
from the queue. Calls write_behind only if next buffer not
available.
*/
int
writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
{
bfs[current].counter = ct; /* set size of data to write */
current = !current; /* switch to other buffer */
if (bfs[current].counter != BF_FREE) /* if not free */
(void)write_behind(file, convert); /* flush it */
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
*dpp = (struct tftphdr *)bfs[current].buf;
return ct; /* this is a lie of course */
}
/*
* Output a buffer to a file, converting from netascii if requested.
* CR,NUL -> CR and CR,LF => LF.
* Note spec is undefined if we get CR as last byte of file or a
* CR followed by anything else. In this case we leave it alone.
*/
int
write_behind(FILE *file, int convert)
{
char *buf;
int count;
int ct;
char *p;
int c; /* current character */
struct bf *b;
struct tftphdr *dp;
b = &bfs[nextone];
if (b->counter < -1) /* anything to flush? */
return 0; /* just nop if nothing to do */
count = b->counter; /* remember byte count */
b->counter = BF_FREE; /* reset flag */
dp = (struct tftphdr *)b->buf;
nextone = !nextone; /* incr for next time */
buf = dp->th_data;
if (count <= 0) return -1; /* nak logic? */
if (convert == 0)
return write(fileno(file), buf, count);
p = buf;
ct = count;
while (ct--) { /* loop over the buffer */
c = *p++; /* pick up a character */
if (prevchar == '\r') { /* if prev char was cr */
if (c == '\n') /* if have cr,lf then just */
fseek(file, -1, 1); /* smash lf on top of the cr */
else
if (c == '\0') /* if have cr,nul then */
goto skipit; /* just skip over the putc */
/* else just fall through and allow it */
}
putc(c, file);
skipit:
prevchar = c;
}
return count;
}
/* When an error has occurred, it is possible that the two sides
* are out of synch. Ie: that what I think is the other side's
* response to packet N is really their response to packet N-1.
*
* So, to try to prevent that, we flush all the input queued up
* for us on the network connection on our host.
*
* We return the number of packets we flushed (mostly for reporting
* when trace is active).
*/
int
synchnet(int f) /* socket to flush */
{
int pktcount = 0;
char rbuf[PKTSIZE];
struct sockaddr_in from;
int fromlen;
fd_set socketset;
struct timeval notime;
while ( 1 ) {
notime.tv_sec = notime.tv_usec = 0;
FD_ZERO(&socketset);
FD_SET(f, &socketset);
if ( select(f, &socketset, NULL, NULL, &notime) <= 0 )
break; /* Nothing to read */
/* Otherwise drain the packet */
pktcount++;
fromlen = sizeof from;
(void) recvfrom(f, rbuf, sizeof (rbuf), 0,
(struct sockaddr *)&from, &fromlen);
}
return pktcount; /* Return packets drained */
}

View file

@ -1,3 +1,8 @@
/* $Id$ */
/* $OpenBSD: tftpsubs.h,v 1.2 1996/06/26 05:40:37 deraadt Exp $ */
/* $NetBSD: tftpsubs.h,v 1.2 1994/12/08 09:51:32 jtc Exp $ */
/* /*
* Copyright (c) 1993 * Copyright (c) 1993
* The Regents of the University of California. All rights reserved. * The Regents of the University of California. All rights reserved.
@ -29,6 +34,8 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * 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 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
*
* @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
*/ */
/* /*
@ -40,66 +47,6 @@
#include "config.h" #include "config.h"
union sock_addr {
struct sockaddr sa;
struct sockaddr_in si;
#ifdef HAVE_IPV6
struct sockaddr_in6 s6;
#endif
};
#define SOCKLEN(sock) \
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
(sizeof(struct sockaddr_in)) : \
(sizeof(union sock_addr)))
#ifdef HAVE_IPV6
#define SOCKPORT(sock) \
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
((union sock_addr*)sock)->si.sin_port : \
((union sock_addr*)sock)->s6.sin6_port)
#else
#define SOCKPORT(sock) \
(((union sock_addr*)sock)->si.sin_port)
#endif
#ifdef HAVE_IPV6
#define SOCKADDR_P(sock) \
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
(void *)&((union sock_addr*)sock)->si.sin_addr : \
(void *)&((union sock_addr*)sock)->s6.sin6_addr)
#else
#define SOCKADDR_P(sock) \
(void *)&((union sock_addr*)sock)->si.sin_addr
#endif
#ifdef HAVE_IPV6
int is_numeric_ipv6(const char *);
char *strip_address(char *);
#else
#define is_numeric_ipv6(a) 0
#define strip_address(a) (a)
#endif
static inline int sa_set_port(union sock_addr *s, u_short port)
{
switch (s->sa.sa_family) {
case AF_INET:
s->si.sin_port = port;
break;
#ifdef HAVE_IPV6
case AF_INET6:
s->s6.sin6_port = port;
break;
#endif
default:
return -1;
}
return 0;
}
int set_sock_addr(char *, union sock_addr *, char **);
struct tftphdr; struct tftphdr;
struct tftphdr *r_init(void); struct tftphdr *r_init(void);
@ -115,7 +62,15 @@ int writeit(FILE *, struct tftphdr **, int, int);
extern int segsize; extern int segsize;
#define MAX_SEGSIZE 65464 #define MAX_SEGSIZE 65464
int pick_port_bind(int sockfd, union sock_addr *myaddr, /*
unsigned int from, unsigned int to); * Prototype for xmalloc/xstrdup
*/
extern void *xmalloc(size_t);
extern char *xstrdup(const char *);
/*
* Signal-related stuff
*/
void (*bsd_signal(int, void (*)(int)))(int);
#endif #endif

View file

@ -1,17 +1,23 @@
SRCROOT = .. SRCROOT = ..
VERSION = $(shell cat ../version) VERSION = $(shell cat ../version)
-include ../config/MCONFIG -include ../MCONFIG
include ../MRULES include ../MRULES
OBJS = tftpd.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS) OBJS = tftpd.$(O) tftpsubs.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS)
all: tftpd$(X) tftpd.8 all: tftpd$(X) tftpd.8
tftpd$(X): $(OBJS) tftpd$(X): $(OBJS)
$(CC) $(LDFLAGS) $^ $(TFTPD_LIBS) -o $@ $(CC) $(LDFLAGS) $^ $(TFTPD_LIBS) -o $@
$(OBJS): ../common/tftpsubs.h tftpsubs.c:
$(LN_S) -f ../tftp/tftpsubs.c .
tftpsubs.h:
$(LN_S) -f ../tftp/tftpsubs.h .
$(OBJS): tftpsubs.h
tftpd.8: tftpd.8.in ../version tftpd.8: tftpd.8.in ../version
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@ sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@

View file

@ -1,6 +1,7 @@
/* $Id$ */
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved * Copyright 2001 H. Peter Anvin - All Rights Reserved
* *
* This program is free software available under the same license * This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at * as the "OpenBSD" operating system, distributed at
@ -19,11 +20,19 @@
#include "tftpd.h" #include "tftpd.h"
/* /*
* Set the signal handler and flags, and error out on failure. * Set the signal handler and flags. Basically a user-friendly
* wrapper around sigaction().
*/ */
void set_signal(int signum, sighandler_t handler, int flags) void set_signal(int signum, void (*handler)(int), int flags)
{ {
if (tftp_signal(signum, handler, flags)) { struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = flags;
if ( sigaction(signum, &sa, NULL) ) {
syslog(LOG_ERR, "sigaction: %m"); syslog(LOG_ERR, "sigaction: %m");
exit(EX_OSERR); exit(EX_OSERR);
} }
@ -58,3 +67,4 @@ char *tfstrdup(const char *str)
return p; return p;
} }

View file

@ -18,20 +18,18 @@
*/ */
#include "config.h" /* Must be included first! */ #include "config.h" /* Must be included first! */
#include "common/tftpsubs.h"
#include "recvfrom.h" #include "recvfrom.h"
#include "tftpsubs.h"
#ifdef HAVE_MACHINE_PARAM_H #ifdef HAVE_MACHINE_PARAM_H
#include <machine/param.h> /* Needed on some versions of FreeBSD */ #include <machine/param.h> /* Needed on some versions of FreeBSD */
#endif #endif
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL) #if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h> #include <sys/uio.h>
#endif
#ifdef IP_PKTINFO #ifdef IP_PKTINFO
# ifndef HAVE_STRUCT_IN_PKTINFO_IPI_ADDR # ifndef HAVE_STRUCT_IN_PKTINFO
# ifdef __linux__ # ifdef __linux__
/* Assume this version of glibc simply lacks the definition */ /* Assume this version of glibc simply lacks the definition */
struct in_pktinfo { struct in_pktinfo {
@ -52,94 +50,10 @@ struct in_pktinfo {
# define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size)) # define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
#endif #endif
/*
* Check to see if this is a valid local address, meaning that we can
* legally bind to it.
*/
static int address_is_local(const union sock_addr *addr)
{
union sock_addr sa1, sa2;
int sockfd = -1;
int e;
int rv = 0;
socklen_t addrlen;
memcpy(&sa1, addr, sizeof sa1);
/* Multicast or universal broadcast address? */
if (sa1.sa.sa_family == AF_INET) {
if (ntohl(sa1.si.sin_addr.s_addr) >= (224UL << 24))
return 0;
sa1.si.sin_port = 0; /* Any port */
}
#ifdef HAVE_IPV6
else if (sa1.sa.sa_family == AF_INET6) {
if (IN6_IS_ADDR_MULTICAST(&sa1.s6.sin6_addr))
return 0;
sa1.s6.sin6_port = 0; /* Any port */
}
#endif
else
return 0;
sockfd = socket(sa1.sa.sa_family, SOCK_DGRAM, 0);
if (sockfd < 0)
goto err;
if (bind(sockfd, &sa1.sa, SOCKLEN(&sa1)))
goto err;
addrlen = SOCKLEN(addr);
if (getsockname(sockfd, (struct sockaddr *)&sa2, &addrlen))
goto err;
if (sa1.sa.sa_family != sa2.sa.sa_family)
goto err;
if (sa2.sa.sa_family == AF_INET)
rv = sa1.si.sin_addr.s_addr == sa2.si.sin_addr.s_addr;
#ifdef HAVE_IPV6
else if (sa2.sa.sa_family == AF_INET6)
rv = IN6_ARE_ADDR_EQUAL(&sa1.s6.sin6_addr, &sa2.s6.sin6_addr);
#endif
else
rv = 0;
err:
e = errno;
if (sockfd >= 0)
close(sockfd);
errno = e;
return rv;
}
static void normalize_ip6_compat(union sock_addr *myaddr)
{
#ifdef HAVE_IPV6
static const uint8_t ip6_compat_prefix[12] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
struct sockaddr_in in;
if (myaddr->sa.sa_family == AF_INET6 &&
!memcmp(&myaddr->s6.sin6_addr, ip6_compat_prefix,
sizeof ip6_compat_prefix)) {
bzero(&in, sizeof in);
in.sin_family = AF_INET;
in.sin_port = myaddr->s6.sin6_port;
memcpy(&in.sin_addr, (const char *)&myaddr->s6.sin6_addr +
sizeof ip6_compat_prefix, sizeof in.sin_addr);
memcpy(&myaddr->si, &in, sizeof in);
}
#else
(void)myaddr;
#endif
}
int int
myrecvfrom(int s, void *buf, int len, unsigned int flags, myrecvfrom(int s, void *buf, int len, unsigned int flags,
union sock_addr *from, union sock_addr *myaddr) struct sockaddr *from, int *fromlen,
struct sockaddr_in *myaddr)
{ {
struct msghdr msg; struct msghdr msg;
struct iovec iov; struct iovec iov;
@ -152,46 +66,28 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
CMSG_SPACE(sizeof(struct in_pktinfo))]; CMSG_SPACE(sizeof(struct in_pktinfo))];
#else #else
char control[CMSG_SPACE(sizeof(struct in_addr))]; char control[CMSG_SPACE(sizeof(struct in_addr))];
#endif
#ifdef HAVE_IPV6
#ifdef HAVE_STRUCT_IN6_PKTINFO
char control6[CMSG_SPACE(sizeof(struct in6_addr)) +
CMSG_SPACE(sizeof(struct in6_pktinfo))];
#else
char control6[CMSG_SPACE(sizeof(struct in6_addr))];
#endif
#endif #endif
} control_un; } control_un;
int on = 1; int on = 1;
#ifdef IP_PKTINFO #ifdef IP_PKTINFO
struct in_pktinfo pktinfo; struct in_pktinfo pktinfo;
#endif #endif
#ifdef HAVE_STRUCT_IN6_PKTINFO
struct in6_pktinfo pktinfo6;
#endif
/* Try to enable getting the return address */ /* Try to enable getting the return address */
#ifdef IP_RECVDSTADDR #ifdef IP_RECVDSTADDR
if (from->sa.sa_family == AF_INET)
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
#endif #endif
#ifdef IP_PKTINFO #ifdef IP_PKTINFO
if (from->sa.sa_family == AF_INET)
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
#endif #endif
#ifdef HAVE_IPV6
#ifdef IPV6_RECVPKTINFO
if (from->sa.sa_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
#endif
#endif
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */ bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
msg.msg_control = control_un.control; msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un); msg.msg_controllen = sizeof(control_un.control);
msg.msg_flags = 0; msg.msg_flags = 0;
msg.msg_name = &from->sa; msg.msg_name = from;
msg.msg_namelen = sizeof(*from); msg.msg_namelen = *fromlen;
iov.iov_base = buf; iov.iov_base = buf;
iov.iov_len = len; iov.iov_len = len;
msg.msg_iov = &iov; msg.msg_iov = &iov;
@ -200,9 +96,11 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
if ( (n = recvmsg(s, &msg, flags)) < 0 ) if ( (n = recvmsg(s, &msg, flags)) < 0 )
return n; /* Error */ return n; /* Error */
*fromlen = msg.msg_namelen;
if ( myaddr ) { if ( myaddr ) {
bzero(myaddr, sizeof(*myaddr)); bzero(myaddr, sizeof(struct sockaddr_in));
myaddr->sa.sa_family = from->sa.sa_family; myaddr->sin_family = AF_INET;
if ( msg.msg_controllen < sizeof(struct cmsghdr) || if ( msg.msg_controllen < sizeof(struct cmsghdr) ||
(msg.msg_flags & MSG_CTRUNC) ) (msg.msg_flags & MSG_CTRUNC) )
@ -211,12 +109,10 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ; for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ;
cmptr = CMSG_NXTHDR(&msg, cmptr) ) { cmptr = CMSG_NXTHDR(&msg, cmptr) ) {
if (from->sa.sa_family == AF_INET) {
myaddr->sa.sa_family = AF_INET;
#ifdef IP_RECVDSTADDR #ifdef IP_RECVDSTADDR
if ( cmptr->cmsg_level == IPPROTO_IP && if ( cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVDSTADDR ) { cmptr->cmsg_type == IP_RECVDSTADDR ) {
memcpy(&myaddr->si.sin_addr, CMSG_DATA(cmptr), memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr),
sizeof(struct in_addr)); sizeof(struct in_addr));
} }
#endif #endif
@ -224,57 +120,14 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
#ifdef IP_PKTINFO #ifdef IP_PKTINFO
if ( cmptr->cmsg_level == IPPROTO_IP && if ( cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_PKTINFO ) { cmptr->cmsg_type == IP_PKTINFO ) {
memcpy(&pktinfo, CMSG_DATA(cmptr), memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo));
sizeof(struct in_pktinfo)); memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr));
memcpy(&myaddr->si.sin_addr, &pktinfo.ipi_addr,
sizeof(struct in_addr));
} }
#endif #endif
}
#ifdef HAVE_IPV6
else if (from->sa.sa_family == AF_INET6) {
myaddr->sa.sa_family = AF_INET6;
#ifdef IP6_RECVDSTADDR
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
cmptr->cmsg_type == IPV6_RECVDSTADDR )
memcpy(&myaddr->s6.sin6_addr, CMSG_DATA(cmptr),
sizeof(struct in6_addr));
#endif
#ifdef HAVE_STRUCT_IN6_PKTINFO
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
(
#ifdef IPV6_RECVPKTINFO
cmptr->cmsg_type == IPV6_RECVPKTINFO ||
#endif
cmptr->cmsg_type == IPV6_PKTINFO)) {
memcpy(&pktinfo6, CMSG_DATA(cmptr),
sizeof(struct in6_pktinfo));
memcpy(&myaddr->s6.sin6_addr, &pktinfo6.ipi6_addr,
sizeof(struct in6_addr));
}
#endif
}
#endif
}
normalize_ip6_compat(myaddr);
/* If the address is not a valid local address,
* then bind to any address...
*/
if (address_is_local(myaddr) != 1) {
if (myaddr->sa.sa_family == AF_INET)
((struct sockaddr_in *)myaddr)->sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_IPV6
else if (myaddr->sa.sa_family == AF_INET6)
memset(&myaddr->s6.sin6_addr, 0, sizeof(struct in6_addr));
#endif
} }
} }
normalize_ip6_compat(from);
return n; return n;
} }
@ -282,16 +135,18 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
int int
myrecvfrom(int s, void *buf, int len, unsigned int flags, myrecvfrom(int s, void *buf, int len, unsigned int flags,
union sock_addr *from, union sock_addr *myaddr) struct sockaddr *from, int *fromlen,
struct sockaddr_in *myaddr)
{ {
/* There is no way we can get the local address, fudge it */ /* There is no way we can get the local address, fudge it */
socklen_t fromlen = sizeof(*from);
bzero(myaddr, sizeof(*myaddr)); bzero(myaddr, sizeof(struct sockaddr_in));
myaddr->sa.sa_family = from->sa.sa_family; myaddr->sin_family = AF_INET;
sa_set_port(myaddr, htons(IPPORT_TFTP));
return recvfrom(s, buf, len, flags, &from->sa, &fromlen); myaddr->sin_port = htons(IPPORT_TFTP);
bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr));
return recvfrom(s,buf,len,flags,from,fromlen);
} }
#endif #endif

View file

@ -1,6 +1,7 @@
/* $Id$ */
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2001-2006 H. Peter Anvin - All Rights Reserved * Copyright 2001 H. Peter Anvin - All Rights Reserved
* *
* This program is free software available under the same license * This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at * as the "OpenBSD" operating system, distributed at
@ -19,4 +20,5 @@
int int
myrecvfrom(int s, void *buf, int len, unsigned int flags, myrecvfrom(int s, void *buf, int len, unsigned int flags,
union sock_addr *from, union sock_addr *myaddr); struct sockaddr *from, int *fromlen,
struct sockaddr_in *myaddr);

View file

@ -1,6 +1,7 @@
/* $Id$ */
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2001-2024 H. Peter Anvin - All Rights Reserved * Copyright 2001-2004 H. Peter Anvin - All Rights Reserved
* *
* This program is free software available under the same license * This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at * as the "OpenBSD" operating system, distributed at
@ -22,7 +23,7 @@
#include "tftpd.h" #include "tftpd.h"
#include "remap.h" #include "remap.h"
#define DEADMAN_MAX_STEPS 4096 /* Timeout after this many steps */ #define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
#define MAXLINE 16384 /* Truncate a line at this many bytes */ #define MAXLINE 16384 /* Truncate a line at this many bytes */
#define RULE_REWRITE 0x01 /* This is a rewrite rule */ #define RULE_REWRITE 0x01 /* This is a rewrite rule */
@ -30,21 +31,14 @@
#define RULE_EXIT 0x04 /* Exit after matching this rule */ #define RULE_EXIT 0x04 /* Exit after matching this rule */
#define RULE_RESTART 0x08 /* Restart at the top after matching this rule */ #define RULE_RESTART 0x08 /* Restart at the top after matching this rule */
#define RULE_ABORT 0x10 /* Terminate processing with an error */ #define RULE_ABORT 0x10 /* Terminate processing with an error */
#define RULE_INVERSE 0x20 /* Execute if regex *doesn't* match */ #define RULE_GETONLY 0x20 /* Applicable to GET only */
#define RULE_IPV4 0x40 /* IPv4 only */ #define RULE_PUTONLY 0x40 /* Applicable to PUT only */
#define RULE_IPV6 0x80 /* IPv6 only */ #define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */
#define RULE_HASFILE 0x100 /* Valid if rule results in a valid filename */
#define RULE_RRQ 0x200 /* Get (read) only */
#define RULE_WRQ 0x400 /* Put (write) only */
#define RULE_SEDG 0x800 /* sed-style global */
int deadman_max_steps = DEADMAN_MAX_STEPS;
struct rule { struct rule {
struct rule *next; struct rule *next;
int nrule; int nrule;
unsigned int rule_flags; int rule_flags;
regex_t rx; regex_t rx;
const char *pattern; const char *pattern;
}; };
@ -64,30 +58,21 @@ static int xform_tolower(int c)
return tolower(c); return tolower(c);
} }
/* /* Do \-substitution. Call with string == NULL to get length only. */
* Do \-substitution. Call with string == NULL to get length only. static int genmatchstring(char *string, const char *pattern, const char *input,
* "start" indicates an offset into the input buffer where the pattern const regmatch_t *pmatch, match_pattern_callback macrosub)
* match was started.
*/
static int do_genmatchstring(char *string, const char *pattern,
const char *ibuf,
const regmatch_t * pmatch,
match_pattern_callback macrosub,
int start, int *nextp)
{ {
int (*xform)(int) = xform_null; int (*xform)(int) = xform_null;
int len = 0; int len = 0;
int n, mlen, sublen; int n, mlen, sublen;
int endbytes; int endbytes;
const char *input = ibuf + start;
/* Get section before match; note pmatch[0] is the whole match */ /* Get section before match; note pmatch[0] is the whole match */
endbytes = strlen(input) - pmatch[0].rm_eo; endbytes = strlen(input) - pmatch[0].rm_eo;
len = start + pmatch[0].rm_so; len = pmatch[0].rm_so + endbytes;
if ( string ) { if ( string ) {
/* Copy the prefix before "start" as well! */ memcpy(string, input, pmatch[0].rm_so);
memcpy(string, ibuf, start + pmatch[0].rm_so); string += pmatch[0].rm_so;
string += start + pmatch[0].rm_so;
} }
/* Transform matched section */ /* Transform matched section */
@ -97,23 +82,15 @@ static int do_genmatchstring(char *string, const char *pattern,
if ( *pattern == '\\' && pattern[1] != '\0' ) { if ( *pattern == '\\' && pattern[1] != '\0' ) {
char macro = pattern[1]; char macro = pattern[1];
switch ( macro ) { switch ( macro ) {
case '0': case '0': case '1': case '2': case '3': case '4':
case '1': case '5': case '6': case '7': case '8': case '9':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
n = pattern[1] - '0'; n = pattern[1] - '0';
if ( pmatch[n].rm_so != -1 ) { if ( pmatch[n].rm_so != -1 ) {
mlen = pmatch[n].rm_eo - pmatch[n].rm_so; mlen = pmatch[n].rm_eo - pmatch[n].rm_so;
len += mlen; len += mlen;
if ( string ) { if ( string ) {
const char *p = input + start + pmatch[n].rm_so; const char *p = input+pmatch[n].rm_so;
while ( mlen-- ) while ( mlen-- )
*string++ = xform(*p++); *string++ = xform(*p++);
} }
@ -133,7 +110,8 @@ static int do_genmatchstring(char *string, const char *pattern,
break; break;
default: default:
if (macrosub && (sublen = macrosub(macro, string)) >= 0) { if ( macrosub &&
(sublen = macrosub(macro, string)) >= 0 ) {
while ( sublen-- ) { while ( sublen-- ) {
len++; len++;
if ( string ) { if ( string ) {
@ -156,12 +134,7 @@ static int do_genmatchstring(char *string, const char *pattern,
} }
} }
/* Pointer to post-substitution tail */
if (nextp)
*nextp = len;
/* Copy section after match */ /* Copy section after match */
len += endbytes;
if ( string ) { if ( string ) {
memcpy(string, input+pmatch[0].rm_eo, endbytes); memcpy(string, input+pmatch[0].rm_eo, endbytes);
string[endbytes] = '\0'; string[endbytes] = '\0';
@ -170,26 +143,6 @@ static int do_genmatchstring(char *string, const char *pattern,
return len; return len;
} }
/*
* Ditto, but allocate the string in a new buffer
*/
static int genmatchstring(char **string, const char *pattern,
const char *ibuf,
const regmatch_t * pmatch,
match_pattern_callback macrosub,
int start, int *nextp)
{
int len;
char *buf;
len = do_genmatchstring(NULL, pattern, ibuf, pmatch,
macrosub, start, NULL);
*string = buf = tfmalloc(len + 1);
return do_genmatchstring(buf, pattern, ibuf, pmatch,
macrosub, start, nextp);
}
/* /*
* Extract a string terminated by non-escaped whitespace; ignoring * Extract a string terminated by non-escaped whitespace; ignoring
* leading whitespace. Consider an unescaped # to be a comment marker, * leading whitespace. Consider an unescaped # to be a comment marker,
@ -247,17 +200,11 @@ static int parseline(char *line, struct rule *r, int lineno)
r->rule_flags |= RULE_REWRITE; r->rule_flags |= RULE_REWRITE;
break; break;
case 'g': case 'g':
if (r->rule_flags & RULE_GLOBAL)
r->rule_flags |= RULE_SEDG;
else
r->rule_flags |= RULE_GLOBAL; r->rule_flags |= RULE_GLOBAL;
break; break;
case 'e': case 'e':
r->rule_flags |= RULE_EXIT; r->rule_flags |= RULE_EXIT;
break; break;
case 'E':
r->rule_flags |= RULE_HASFILE;
break;
case 's': case 's':
r->rule_flags |= RULE_RESTART; r->rule_flags |= RULE_RESTART;
break; break;
@ -267,46 +214,32 @@ static int parseline(char *line, struct rule *r, int lineno)
case 'i': case 'i':
rxflags |= REG_ICASE; rxflags |= REG_ICASE;
break; break;
case 'G':
r->rule_flags |= RULE_GETONLY;
break;
case 'P':
r->rule_flags |= RULE_PUTONLY;
break;
case '~': case '~':
r->rule_flags |= RULE_INVERSE; r->rule_flags |= RULE_INVERSE;
break; break;
case '4':
r->rule_flags |= RULE_IPV4;
break;
case '6':
r->rule_flags |= RULE_IPV6;
break;
case 'G':
r->rule_flags |= RULE_RRQ;
break;
case 'P':
r->rule_flags |= RULE_WRQ;
break;
default: default:
syslog(LOG_ERR, syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",
"Remap command \"%s\" on line %d contains invalid char \"%c\"",
buffer, lineno, *p); buffer, lineno, *p);
return -1; /* Error */ return -1; /* Error */
break; break;
} }
} }
if (r->rule_flags & RULE_REWRITE) { /* RULE_GLOBAL only applies when RULE_REWRITE specified */
if (r->rule_flags & RULE_INVERSE) { if ( !(r->rule_flags & RULE_REWRITE) )
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", r->rule_flags &= ~RULE_GLOBAL;
lineno, line);
if ( (r->rule_flags & (RULE_INVERSE|RULE_REWRITE)) ==
(RULE_INVERSE|RULE_REWRITE) ) {
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", lineno, line);
return -1; /* Error */ return -1; /* Error */
} }
if ((r->rule_flags & (RULE_GLOBAL|RULE_SEDG|RULE_HASFILE))
== (RULE_GLOBAL|RULE_HASFILE)) {
syslog(LOG_ERR, "E rules cannot be combined with g (but gg is OK), line %d: %s\n",
lineno, line);
return -1; /* Error */
}
} else {
/* RULE_GLOBAL and RULE_SEDG are meaningless without RULE_REWRITE */
r->rule_flags &= ~(RULE_GLOBAL|RULE_SEDG);
}
/* Read and compile the regex */ /* Read and compile the regex */
if ( !readescstring(buffer, &line) ) { if ( !readescstring(buffer, &line) ) {
@ -317,8 +250,7 @@ static int parseline(char *line, struct rule *r, int lineno)
if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) { if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) {
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
regerror(rv, &r->rx, errbuf, BUFSIZ); regerror(rv, &r->rx, errbuf, BUFSIZ);
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, errbuf);
errbuf);
return -1; /* Error */ return -1; /* Error */
} }
@ -386,24 +318,17 @@ void freerules(struct rule *r)
} }
/* Execute a rule set on a string; returns a malloc'd new string. */ /* Execute a rule set on a string; returns a malloc'd new string. */
char *rewrite_string(const struct formats *pf, char *rewrite_string(const char *input, const struct rule *rules,
const char *input, const struct rule *rules, int is_put, match_pattern_callback macrosub,
int mode, int af, match_pattern_callback macrosub,
const char **errmsg) const char **errmsg)
{ {
char *current = tfstrdup(input); char *current = tfstrdup(input);
char *newstr, *newerstr; char *newstr;
const char *accerr;
const struct rule *ruleptr = rules; const struct rule *ruleptr = rules;
regmatch_t pmatch[10]; regmatch_t pmatch[10];
int i;
int len; int len;
int was_match = 0; int was_match = 0;
int deadman = deadman_max_steps; int deadman = DEADMAN_MAX_STEPS;
int matchsense;
int pmatches;
unsigned int bad_flags;
int ggoffset;
/* Default error */ /* Default error */
*errmsg = "Remap table failure"; *errmsg = "Remap table failure";
@ -412,36 +337,32 @@ char *rewrite_string(const struct formats *pf,
syslog(LOG_INFO, "remap: input: %s", current); syslog(LOG_INFO, "remap: input: %s", current);
} }
bad_flags = 0;
if (mode != RRQ) bad_flags |= RULE_RRQ;
if (mode != WRQ) bad_flags |= RULE_WRQ;
if (af != AF_INET) bad_flags |= RULE_IPV4;
if (af != AF_INET6) bad_flags |= RULE_IPV6;
for ( ruleptr = rules ; ruleptr ; ruleptr = ruleptr->next ) { for ( ruleptr = rules ; ruleptr ; ruleptr = ruleptr->next ) {
if (ruleptr->rule_flags & bad_flags) if ( ((ruleptr->rule_flags & RULE_GETONLY) && is_put) ||
continue; /* This rule is excluded by flags */ ((ruleptr->rule_flags & RULE_PUTONLY) && !is_put) ) {
continue; /* Rule not applicable, try next */
}
matchsense = ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0; if ( ! deadman-- ) {
pmatches = ruleptr->rule_flags & RULE_INVERSE ? 0 : 10; syslog(LOG_WARNING, "remap: Breaking loop, input = %s, last = %s",
input, current);
/* Clear the pmatch[] array */ free(current);
for (i = 0; i < 10; i++) return NULL; /* Did not terminate! */
pmatch[i].rm_so = pmatch[i].rm_eo = -1; }
was_match = 0;
do { do {
if (!deadman--) if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) ==
goto dead; (ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0) ) {
if (regexec(&ruleptr->rx, current, pmatches, pmatch, 0)
!= matchsense)
break; /* No match, break out of do loop */
/* Match on this rule */ /* Match on this rule */
was_match = 1; was_match = 1;
if ( ruleptr->rule_flags & RULE_INVERSE ) {
/* No actual match, so clear out the pmatch array */
int i;
for ( i = 0 ; i < 10 ; i++ )
pmatch[i].rm_so = pmatch[i].rm_eo = -1;
}
if ( ruleptr->rule_flags & RULE_ABORT ) { if ( ruleptr->rule_flags & RULE_ABORT ) {
if ( verbosity >= 3 ) { if ( verbosity >= 3 ) {
syslog(LOG_INFO, "remap: rule %d: abort: %s", syslog(LOG_INFO, "remap: rule %d: abort: %s",
@ -449,8 +370,11 @@ char *rewrite_string(const struct formats *pf,
} }
if ( ruleptr->pattern[0] ) { if ( ruleptr->pattern[0] ) {
/* Custom error message */ /* Custom error message */
genmatchstring(&newstr, ruleptr->pattern, current, len = genmatchstring(NULL, ruleptr->pattern, current,
pmatch, macrosub, 0, NULL); pmatch, macrosub);
newstr = tfmalloc(len+1);
genmatchstring(newstr, ruleptr->pattern, current,
pmatch, macrosub);
*errmsg = newstr; *errmsg = newstr;
} else { } else {
*errmsg = NULL; *errmsg = NULL;
@ -460,73 +384,37 @@ char *rewrite_string(const struct formats *pf,
} }
if ( ruleptr->rule_flags & RULE_REWRITE ) { if ( ruleptr->rule_flags & RULE_REWRITE ) {
len = genmatchstring(&newstr, ruleptr->pattern, current, len = genmatchstring(NULL, ruleptr->pattern, current,
pmatch, macrosub, 0, &ggoffset); pmatch, macrosub);
newstr = tfmalloc(len+1);
if (ruleptr->rule_flags & RULE_SEDG) { genmatchstring(newstr, ruleptr->pattern, current,
/* sed-style partial-matching global */ pmatch, macrosub);
while (ggoffset < len &&
regexec(&ruleptr->rx, newstr + ggoffset,
pmatches, pmatch,
ggoffset ? REG_NOTBOL : 0)
== matchsense) {
if (!deadman--) {
free(current);
current = newstr;
goto dead;
}
len = genmatchstring(&newerstr, ruleptr->pattern,
newstr, pmatch, macrosub,
ggoffset, &ggoffset);
free(newstr);
newstr = newerstr;
}
}
if ((ruleptr->rule_flags & RULE_HASFILE) &&
pf->f_validate(newstr, mode, pf, &accerr)) {
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: ignored rewrite (%s): %s",
ruleptr->nrule, accerr, newstr);
}
free(newstr);
was_match = 0;
break;
}
free(current); free(current);
current = newstr; current = newstr;
if ( verbosity >= 3 ) { if ( verbosity >= 3 ) {
syslog(LOG_INFO, "remap: rule %d: rewrite: %s", syslog(LOG_INFO, "remap: rule %d: rewrite: %s",
ruleptr->nrule, current); ruleptr->nrule, current);
} }
} else if (ruleptr->rule_flags & RULE_HASFILE) {
if (pf->f_validate(current, mode, pf, &accerr)) {
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: not exiting (%s)\n",
ruleptr->nrule, accerr);
} }
} else {
break; /* No match, terminate unconditionally */
}
/* If the rule is global, keep going until no match */
} while ( ruleptr->rule_flags & RULE_GLOBAL );
if ( was_match ) {
was_match = 0; was_match = 0;
break;
}
}
/* If the rule is (old-style) global, keep going until no match */
} while ((ruleptr->rule_flags & (RULE_GLOBAL|RULE_SEDG)) == RULE_GLOBAL);
if (!was_match) if ( ruleptr->rule_flags & RULE_EXIT ) {
continue; /* Next rule */
if (ruleptr->rule_flags & (RULE_EXIT|RULE_HASFILE)) {
if ( verbosity >= 3 ) { if ( verbosity >= 3 ) {
syslog(LOG_INFO, "remap: rule %d: exit", syslog(LOG_INFO, "remap: rule %d: exit", ruleptr->nrule);
ruleptr->nrule);
} }
return current; /* Exit here, we're done */ return current; /* Exit here, we're done */
} else if ( ruleptr->rule_flags & RULE_RESTART ) { } else if ( ruleptr->rule_flags & RULE_RESTART ) {
ruleptr = rules; /* Start from the top */ ruleptr = rules; /* Start from the top */
if ( verbosity >= 3 ) { if ( verbosity >= 3 ) {
syslog(LOG_INFO, "remap: rule %d: restart", syslog(LOG_INFO, "remap: rule %d: restart", ruleptr->nrule);
ruleptr->nrule); }
} }
} }
} }
@ -535,11 +423,4 @@ char *rewrite_string(const struct formats *pf,
syslog(LOG_INFO, "remap: done"); syslog(LOG_INFO, "remap: done");
} }
return current; return current;
dead: /* Deadman expired */
syslog(LOG_ERR,
"remap: Breaking loop after %d steps, input = %s, last = %s",
deadman_max_steps, input, current);
free(current);
return NULL; /* Did not terminate! */
} }

View file

@ -1,6 +1,7 @@
/* $Id$ */
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved * Copyright 2001 H. Peter Anvin - All Rights Reserved
* *
* This program is free software available under the same license * This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at * as the "OpenBSD" operating system, distributed at
@ -35,13 +36,9 @@ struct rule *parserulefile(FILE *);
void freerules(struct rule *); void freerules(struct rule *);
/* Execute a rule set on a string; returns a malloc'd new string. */ /* Execute a rule set on a string; returns a malloc'd new string. */
struct formats; char *rewrite_string(const char *, const struct rule *, int,
char *rewrite_string(const struct formats *, const char *,
const struct rule *, int, int,
match_pattern_callback, const char **); match_pattern_callback, const char **);
/* Remapping deadman counter */
extern int deadman_max_steps;
#endif /* WITH_REGEX */ #endif /* WITH_REGEX */
#endif /* TFTPD_REMAP_H */ #endif /* TFTPD_REMAP_H */

View file

@ -1,3 +1,4 @@
# $Id$
# #
# Sample rule file for the -m (remapping option) # Sample rule file for the -m (remapping option)
# #

View file

@ -1,9 +1,10 @@
.\" -*- nroff -*- --------------------------------------------------------- * .\" -*- nroff -*- --------------------------------------------------------- *
.\" $Id$
.\" .\"
.\" Copyright (c) 1990, 1993, 1994 .\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
.\" .\"
.\" Copyright 2001-2009 H. Peter Anvin - All Rights Reserved .\" Copyright 2001 H. Peter Anvin - All Rights Reserved
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions .\" modification, are permitted provided that the following conditions
@ -30,17 +31,17 @@
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\"----------------------------------------------------------------------- */ .\"----------------------------------------------------------------------- */
.TH TFTPD 8 "7 June 2014" "tftp-hpa @@VERSION@@" "System Manager's Manual" .TH TFTPD 8 "16 February 2006" "tftp-hpa @@VERSION@@" "System Manager's Manual"
.SH NAME .SH NAME
.B tftpd .B tftpd
\- Trivial File Transfer Protocol server \- IPv4 Trivial File Transfer Protocol server
.SH SYNOPSIS .SH SYNOPSIS
.B in.tftpd .B in.tftpd
.RI [ options... ] .RI [ options... ]
.I directory... .I directory...
.SH DESCRIPTION .SH DESCRIPTION
.B tftpd .B tftpd
is a server for the Trivial File Transfer Protocol. The TFTP is a server for the IPv4 Trivial File Transfer Protocol. The TFTP
protocol is extensively used to support remote booting of diskless protocol is extensively used to support remote booting of diskless
devices. The server is normally started by devices. The server is normally started by
.BR inetd , .BR inetd ,
@ -48,70 +49,52 @@ but can also run standalone.
.PP .PP
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-\-ipv4\fP, \fB\-4\fP .B \-l
Connect with IPv4 only, even if IPv6 support was compiled in.
.TP
\fB\-\-ipv6\fP, \fB\-6\fP
Connect with IPv6 only, if compiled in.
.TP
\fB\-l\fP, \fB\-\-listen\fP
Run the server in standalone (listen) mode, rather than run from Run the server in standalone (listen) mode, rather than run from
.BR inetd . .BR inetd .
In listen mode, the In listen mode, the
.B \-\-timeout .B \-t
option is ignored, and the option is ignored, and the
.B \-\-address .B \-a
option can be used to specify a specific local address or port to option can be used to specify a specific local address or port to
listen to. listen to.
.TP .TP
\fB\-\-foreground\fP, \fB\-L\fP \fB\-a\fP \fI[address][:port]\fP
Similar to
.B \-\-listen
but do not detach from the foreground process. Implies
.BR \-\-listen .
.TP
\fB\-\-address\fP \fI[address][:port]\fP, \fB\-a\fP \fI[address][:port]\fP
Specify a specific Specify a specific
.I address .I address
and and
.I port .I port
to listen to when called with the to listen to when called with the
.B \-\-listen .B \-l
or
.B \-\-foreground
option. The default is to listen to the option. The default is to listen to the
.I tftp .I tftp
port specified in port specified in
.I /etc/services .I /etc/services
on all local addresses. on all local addresses.
.B Please note:
Numeric IPv6 adresses must be enclosed in square brackets
to avoid ambiguity with the optional port information.
.TP .TP
\fB\-\-create\fP, \fB\-c\fP .B \-c
Allow new files to be created. By default, Allow new files to be created. By default,
.B tftpd .B tftpd
will only allow upload of files that already exist. Files are created will only allow upload of files that already exist. Files are created
with default permissions allowing anyone to read or write them, unless with default permissions allowing anyone to read or write them, unless
the the
.B \-\-permissive .B \-p
or or
.B \-\-umask .B \-U
options are specified. options are specified.
.TP .TP
\fB\-\-secure\fP, \fB\-s\fP .B \-s
Change root directory on startup. This means the remote host does not Change root directory on startup. This means the remote host does not
need to pass along the directory as part of the transfer, and may add need to pass along the directory as part of the transfer, and may add
security. When security. When
.B \-\-secure .B \-s
is specified, exactly one is specified, exactly one
.I directory .I directory
should be specified on the command line. The use of this option is should be specified on the command line. The use of this option is
recommended for security as well as compatibility with some boot ROMs recommended for security as well as compatibility with some boot ROMs
which cannot be easily made to include a directory name in its request. which cannot be easily made to include a directory name in its request.
.TP .TP
\fB\-\-user\fP \fIusername\fP, \fB\-u\fP \fIusername\fP \fB\-u\fP \fIusername\fP
Specify the username which Specify the username which
.B tftpd .B tftpd
will run as; the default is "nobody". The user ID, group ID, and (if will run as; the default is "nobody". The user ID, group ID, and (if
@ -119,26 +102,21 @@ possible on the platform) the supplementary group IDs will be set to
the ones specified in the system permission database for this the ones specified in the system permission database for this
username. username.
.TP .TP
\fB\-\-umask\fP \fIumask\fP, \fB\-U\fP \fIumask\fP \fB\-U\fP \fIumask\fP
Sets the \fIumask\fP for newly created files to the specified value. Sets the \fIumask\fP for newly created files to the specified value.
The default is zero (anyone can read or write) if the The default is zero (anyone can read or write) if the
.B \-\-permissive .B \-p
option is not specified, or inherited from the invoking process if option is not specified, or inherited from the invoking process if
.B \-\-permissive .B \-p
is specified. is specified.
.TP .TP
\fB\-\-permissive\fP, \fB\-p\fP .B \-p
Perform no additional permissions checks above the normal Perform no additional permissions checks above the normal
system-provided access controls for the user specified via the system-provided access controls for the user specified via the
.B \-\-user .B \-u
option. option.
.TP .TP
\fB\-\-pidfile\fP \fIpidfile\fP, \fB\-P\fP \fIpidfile\fP \fB\-t\fP \fItimeout\fP
When run in standalone mode, write the process ID of the listening
server into \fIpidfile\fP. On normal termination (SIGTERM or SIGINT)
the pid file is automatically removed.
.TP
\fB\-\-timeout\fP \fItimeout\fP, \fB\-t\fP \fItimeout\fP
When run from When run from
.B inetd .B inetd
this specifies how long, in seconds, to wait for a second connection this specifies how long, in seconds, to wait for a second connection
@ -147,7 +125,7 @@ before terminating the server.
will then respawn the server when another request comes in. The will then respawn the server when another request comes in. The
default is 900 (15 minutes.) default is 900 (15 minutes.)
.TP .TP
\fB\-\-retransmit\fP \fItimeout, \fP\fB\-T\fP \fItimeout\fP \fB\-T\fP \fItimeout\fP
Determine the default timeout, in microseconds, before the first Determine the default timeout, in microseconds, before the first
packet is retransmitted. This can be modified by the client if the packet is retransmitted. This can be modified by the client if the
.B timeout .B timeout
@ -155,7 +133,7 @@ or
.B utimeout .B utimeout
option is negotiated. The default is 1000000 (1 second.) option is negotiated. The default is 1000000 (1 second.)
.TP .TP
\fB\-\-map-file\fP \fIremap-file\fP, \fB\-m\fP \fIremap-file\fP \fB\-m\fP \fIremap-file\fP
Specify the use of filename remapping. The Specify the use of filename remapping. The
.I remap-file .I remap-file
is a file containing the remapping rules. See the section on filename is a file containing the remapping rules. See the section on filename
@ -163,23 +141,16 @@ remapping below. This option may not be compiled in, see the output of
.B "in.tftpd \-V" .B "in.tftpd \-V"
to verify whether or not it is available. to verify whether or not it is available.
.TP .TP
.\fB\-\-map-steps\fP \fIsteps\fP .B \-v
Specify the number of remapping rules that may be executed before the
filename mapping fails. The default is 4096.
.TP
\fB\-\-verbose\fP, \fB\-v\fP
Increase the logging verbosity of Increase the logging verbosity of
.BR tftpd . .BR tftpd .
This flag can be specified multiple times for even higher verbosity. This flag can be specified multiple times for even higher verbosity.
.TP .TP
\fB\-\-verbosity\fP \fIvalue\fP \fB\-r\fP \fItftp-option\fP
Set the verbosity value to \fIvalue\fP.
.TP
\fB\-\-refuse\fP \fItftp-option\fP, \fB\-r\fP \fItftp-option\fP
Indicate that a specific RFC 2347 TFTP option should never be Indicate that a specific RFC 2347 TFTP option should never be
accepted. accepted.
.TP .TP
\fB\-\-blocksize\fP \fImax-block-size\fP, \fB\-B\fP \fImax-block-size\fP \fB\-B\fP \fImax-block-size\fP
Specifies the maximum permitted block size. The permitted range for Specifies the maximum permitted block size. The permitted range for
this parameter is from 512 to 65464. Some embedded clients request this parameter is from 512 to 65464. Some embedded clients request
large block sizes and yet do not handle fragmented packets correctly; large block sizes and yet do not handle fragmented packets correctly;
@ -188,11 +159,11 @@ MTU on your network minus 32 bytes (20 bytes for IP, 8 for UDP, and 4
for TFTP; less if you use IP options on your network.) For example, for TFTP; less if you use IP options on your network.) For example,
on a standard Ethernet (MTU 1500) a value of 1468 is reasonable. on a standard Ethernet (MTU 1500) a value of 1468 is reasonable.
.TP .TP
\fB\-\-port-range\fP \fIport:port\fP, \fB\-R\fP \fIport:port\fP \fB\-R\fP \fIport:port\fP
Force the server port number (the Transaction ID) to be in the Force the server port number (the Transaction ID) to be in the
specified range of port numbers. specified range of port numbers.
.TP .TP
\fB\-\-version\fP, \fB\-V\fP .B \-V
Print the version number and configuration to standard output, then Print the version number and configuration to standard output, then
exit gracefully. exit gracefully.
.SH "RFC 2347 OPTION NEGOTIATION" .SH "RFC 2347 OPTION NEGOTIATION"
@ -227,13 +198,9 @@ Set the time before the server retransmits a packet, in seconds.
.TP .TP
\fButimeout\fP (nonstandard) \fButimeout\fP (nonstandard)
Set the time before the server retransmits a packet, in microseconds. Set the time before the server retransmits a packet, in microseconds.
.TP
\fBrollover\fP (nonstandard)
Set the block number to resume at after a block number rollover. The
default and recommended value is zero.
.PP .PP
The The
.B \-\-refuse .B \-r
option can be used to disable specific options; this may be necessary option can be used to disable specific options; this may be necessary
to work around bugs in specific TFTP client implementations. For to work around bugs in specific TFTP client implementations. For
example, some TFTP clients have been found to request the example, some TFTP clients have been found to request the
@ -242,7 +209,7 @@ option, but crash with an error if they actually get the option
accepted by the server. accepted by the server.
.SH "FILENAME REMAPPING" .SH "FILENAME REMAPPING"
The The
.B \-\-map-file .B \-m
option specifies a file which contains filename remapping rules. Each option specifies a file which contains filename remapping rules. Each
non-comment line (comments begin with hash marks, non-comment line (comments begin with hash marks,
.BR # ) .BR # )
@ -277,17 +244,6 @@ The replacement pattern may contain escape sequences; see below.
Repeat this rule until it no longer matches. This is always used with Repeat this rule until it no longer matches. This is always used with
.BR r . .BR r .
.TP .TP
.B gg
Repeat this rule until it no longer matches, but only on the portion
of the string that has not yet been matched, similar to how the
.B s
command with the
.B g
option works in
.BR sed (1).
This is always used with
.BR r .
.TP
.B i .B i
Match the Match the
.I regex .I regex
@ -296,17 +252,6 @@ case-insensitively. By default it is case sensitive.
.B e .B e
If this rule matches, end rule processing after executing the rule. If this rule matches, end rule processing after executing the rule.
.TP .TP
.B E
If this rule matches,
\fIand the result matches a filename that can be transferred\fP,
end rule processing after executing the rule. If this is combined with
.BR r ,
then if the substitution does \fInot\fP result in a valid filename,
the substitution is undone. This cannot be combined with
.BR g ,
but \fIcan\fP be combined with
.BR gg .
.TP
.B s .B s
If this rule matches, start rule processing over from the very first If this rule matches, start rule processing over from the very first
rule after executing this rule. rule after executing this rule.
@ -321,12 +266,6 @@ This rule applies to GET (RRQ) requests only.
.B P .B P
This rule applies to PUT (WRQ) requests only. This rule applies to PUT (WRQ) requests only.
.TP .TP
.B 4
This rule applies to IPv4 sessions only.
.TP
.B 6
This rule applies to IPv6 sessions only.
.TP
.B ~ .B ~
Inverse the sense of this rule, i.e. execute the Inverse the sense of this rule, i.e. execute the
.I operation .I operation
@ -336,7 +275,7 @@ only if the
match. Cannot used together with match. Cannot used together with
.BR r . .BR r .
.PP .PP
The following escape sequences are recognized as part of a The following escape sequences are recognized as part of the
.IR "replacement pattern" : .IR "replacement pattern" :
.TP .TP
\fB\\0\fP \fB\\0\fP
@ -350,14 +289,12 @@ subexpressions, \\( ... \\), of the
pattern. pattern.
.TP .TP
\fB\\i\fP \fB\\i\fP
The IP address of the requesting host, in dotted-quad notation for The IP address of the requesting host, in dotted-quad notation
IPv4 (e.g. 192.0.2.169) or conventional colon form for IPv6 (e.g. 192.0.2.169).
(e.g. 2001:db8::1).
.TP .TP
\fB\\x\fP \fB\\x\fP
The IP address of the requesting host, in expanded hexadecimal The IP address of the requesting host, in hexadecimal notation
notation (e.g. C00002A9 for IPv4, or 20010DB8000000000000000000000001 (e.g. C00002A9).
for IPv6).
.TP .TP
\fB\\\\\fP \fB\\\\\fP
Literal backslash. Literal backslash.
@ -387,17 +324,17 @@ The use of TFTP services does not require an account or password on
the server system. Due to the lack of authentication information, the server system. Due to the lack of authentication information,
.B tftpd .B tftpd
will allow only publicly readable files (o+r) to be accessed, unless the will allow only publicly readable files (o+r) to be accessed, unless the
.B \-\-permissive .B \-p
option is specified. Files may be written only if they already exist option is specified. Files may be written only if they already exist
and are publicly writable, unless the and are publicly writable, unless the
.B \-\-create .B \-c
option is specified. Note that this extends the concept of ``public'' option is specified. Note that this extends the concept of ``public''
to include all users on all hosts that can be reached through the to include all users on all hosts that can be reached through the
network; this may not be appropriate on all systems, and its network; this may not be appropriate on all systems, and its
implications should be considered before enabling TFTP service. implications should be considered before enabling TFTP service.
Typically, some kind of firewall or packet-filter solution should be Typically, some kind of firewall or packet-filter solution should be
employed. If appropriately compiled (see the output of employed. If appropriately compiled (see the output of
.BR "in.tftpd \-\-version" ) .BR "in.tftpd \-V" )
.B tftpd .B tftpd
will query the will query the
.BR hosts_access (5) .BR hosts_access (5)
@ -407,7 +344,7 @@ and rely on firewalling or kernel-based packet filters instead.
.PP .PP
The server should be set to run as the user with the lowest possible The server should be set to run as the user with the lowest possible
privilege; please see the privilege; please see the
.B \-\-user .B \-u
flag. It is probably a good idea to set up a specific user account for flag. It is probably a good idea to set up a specific user account for
.BR tftpd , .BR tftpd ,
rather than letting it run as "nobody", to guard against privilege rather than letting it run as "nobody", to guard against privilege
@ -417,14 +354,14 @@ Access to files can, and should, be restricted by invoking
.B tftpd .B tftpd
with a list of directories by including pathnames as server program with a list of directories by including pathnames as server program
arguments on the command line. In this case access is restricted to arguments on the command line. In this case access is restricted to
files whose names are prefixed by one of the given directories. If files whole names are prefixed by one of the given directories. If
possible, it is recommended that the possible, it is recommended that the
.B \-\-secure .B \-s
flag is used to set up a chroot() environment for the server to run in flag is used to set up a chroot() environment for the server to run in
once a connection has been set up. once a connection has been set up.
.PP .PP
Finally, the filename remapping Finally, the filename remapping
.RB ( \-\-map-file .RB ( \-m
flag) support can be used to provide a limited amount of additional flag) support can be used to provide a limited amount of additional
access control. access control.
.SH "CONFORMING TO" .SH "CONFORMING TO"

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
/* $Id$ */
/* ----------------------------------------------------------------------- * /* ----------------------------------------------------------------------- *
* *
* Copyright 2001 H. Peter Anvin - All Rights Reserved * Copyright 2001 H. Peter Anvin - All Rights Reserved
@ -23,13 +24,4 @@ char *tfstrdup(const char *);
extern int verbosity; extern int verbosity;
struct formats {
const char *f_mode;
char *(*f_rewrite) (const struct formats *, char *, int, int, const char **);
int (*f_validate) (char *, int, const struct formats *, const char **);
void (*f_send) (const struct formats *, struct tftphdr *, int);
void (*f_recv) (const struct formats *, struct tftphdr *, int);
int f_convert;
};
#endif #endif

View file

@ -1 +1 @@
5.3 0.42