Compare commits

...

31 commits

Author SHA1 Message Date
H. Peter Anvin
2c86ff58dc remap: *actually* build, and fix masked logic errors
Well, now it is actually being compiled, and should hopefully work
again...

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 21:09:46 -07:00
H. Peter Anvin
33ec23c0dc remap: re-enable in autoconf; fix missing pointer assignment
Need to actually output something, too.

The whole section for remap had gotten dropped from autoconf, with the
obvious results...

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 20:56:27 -07:00
H. Peter Anvin
9a92dec1dc tftpd: make it possible to adjust the remap deadman
Allow the user to tweak the remap deadman counter if it is necessary
for whatever reason.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 20:36:22 -07:00
H. Peter Anvin
ac7f98e4d8 remap: fix timeouts for "g", add a "gg" flag to match sed s///g
Make sure that when using the global option, we still bump the deadman
timer.

The "g" option really should only have applied to the right-hand
unmatched part of the string, like in sed. Add a "gg" option which
does that.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 20:24:46 -07:00
H. Peter Anvin
74c5d8a020 .editorconfig: tabs are 8
The size of a tab is 8, even if the indentation is 4.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 19:31:17 -07:00
H. Peter Anvin
cb619257ed recvfrom: update config.h define for in_pktinfo.ipi_addr
configure.ac now explicitly checks for struct in_pktinfo.ipi_addr;
update the configure name to match.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 18:38:43 -07:00
H. Peter Anvin
fefaa2cc5c autoconf: modernize and modularize
Use my modular m4 library used for other things as well; update
autoconf macros to 2.71 standard.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 18:24:53 -07:00
H. Peter Anvin
33051a296c signals: require and always use sigaction()
tftpd already requires sigaction() to compile, so there is no reason
to use anything else. It also allows for nicer combination of flags.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-06-10 14:36:28 -07:00
Yegor Yefremov
e52af4207a Add EditorConfig support
Provide common indentation configuration for the source files.

For more information, visit https://editorconfig.org/.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
2024-05-31 11:11:09 -07:00
H. Peter Anvin
5e8d5c24b2 tftpd: Use setres*id() if available
POSIX apparently doesn't clearly specify the behavior of the saved ID
when calling setre*id(). If the system has setres*id() then use it to
make absolutely sure that the ID changes cannot be undone.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 18:10:41 -07:00
H. Peter Anvin
99112f0206 tftpd: allow initgroups() to rescue setgroups() failure
If setgroups() fails, but initgroups() succeeds (somehow) then allow
the process to continue, as initgroups() ought to have set the group
list properly.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 17:52:42 -07:00
H. Peter Anvin
416046e2ad tftpd: call setgroups() before initgroups()
Unconditionally call setgroups() before calling
initgroups(). That way if initgroups() fails for some reason (e.g. it
is unable to access /etc/groups or the equivalent) then at least the
group list will be empty.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 17:49:21 -07:00
H. Peter Anvin
b9f2335e88 tftpd: shut up one more setjmp complaint
One more place where the compiler complains about setjmp. Work around
it by creating yet another static variable. Ugly, but it works.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 17:35:14 -07:00
H. Peter Anvin
351907e3f0 tftpd: handle rule filter flags more cleanly
Instead of a bunch of ad hoc tests, keep a bitmask of flags that would
keep this rule from being executed. This also removes the ugly hack of
converting the request mode between opcode and character encodings for
really no good reason.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 17:28:53 -07:00
H. Peter Anvin
6f96fcd1b6 tftpd: allow a rewrite rule to probe for the existence of a file
This adds an "E" flag to the rewrite rules, which exits rule
processing if and only if the result is a valid, accessible
filename. If combined with "r", the rewrite is cancelled if the rule
is not applied.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 17:16:06 -07:00
H. Peter Anvin
1dc6d55811 tftpd: handle restricted user namespaces on Linux
If the tftpd process lacks the privilege to set its uid, gid, or
groups, then assume it is already restricted in the way the
administrator requested, if and only if EPERM is returned.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 16:01:54 -07:00
H. Peter Anvin
15c4f369ee Update version for release 5.3 2024-05-29 15:40:13 -07:00
H. Peter Anvin
aaaa76e8e7 tftpd: explicitly declare timer() static
Declare the function timer() as static, which is what it ought to be.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 15:37:44 -07:00
H. Peter Anvin
1f4b33a1f7 Modernize: use sigaction() whenever possible. Remove uses of common.
bsd_signal() may not be defined, and there is really no reason to even
try to use it if sigaction() is avaiable; using sigaction() guarantees
the semantics we really want.

Replace uses of common variables with explicit instantiation and
extern declarations in a header file.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 15:34:57 -07:00
H. Peter Anvin
9c0908a778 autoconf: remove workarounds for some very old systems
Remove workarounds for some ridiculously old systems; these
workarounds are basically untestable.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 15:15:34 -07:00
H. Peter Anvin
e83d71d394 autoconf: rename configure.in to configure.ac
Rename configure.in to configure.ac in accordance with current
practice.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2024-05-29 15:03:40 -07:00
H. Peter Anvin
b2b34cecc8 tftpd: Canonicalize myaddr before address_is_local()
The comparisons for forbidden addresses in address_is_local() only
work on canonicalized addresses.

Also, work in the case myaddr is NULL (if we ever call it that way...)

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2015-08-07 11:55:08 -07:00
H. Peter Anvin
7678ae7f14 tftpd: Canonicalize all the addresses
We cannot canonicalize myaddr and not the from address.  We need to
canonicalize both of them, or else we'll try to create an IPv4 socket
and bind an IPv6-mapped IPv4 address to it, which is going to fail.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2015-08-07 11:49:13 -07:00
Ron Lee
ff819b108a Make configure an order-only prerequisite of aconfig.h.in
On filesystems with subsecond resolution, like ext4, we can't trust the
timestamp of aconfig.h.in since autoheader leaves it truncated to second
resolution (apparently touch -r and cp -p can do this at the very least)
while configure has full subsecond resolution, so it can look newer even
when it was cleanly created first, leading to the build system looping
trying to recreate all of that again ...

So in the initial stage of a clean build we can get something like this:

$ make spotless
$ make autoconf
rm -rf MCONFIG configure config.log aconfig.h *.cache
autoconf
rm -f aconfig.h.in aconfig.h
autoheader

$ stat configure aconfig.h.in
  File: ‘configure’
Device: 807h/2055d	Inode: 9443466     Links: 1
Access: 2014-07-31 03:27:27.599293442 +0930
Modify: 2014-07-31 03:27:27.711290270 +0930
Change: 2014-07-31 03:27:27.711290270 +0930

  File: ‘aconfig.h.in’
Device: 807h/2055d	Inode: 9443467     Links: 1
Access: 2014-07-31 03:27:27.000000000 +0930
Modify: 2014-07-31 03:27:27.000000000 +0930
Change: 2014-07-31 03:27:27.903284841 +0930

And with a parallel build, that can then leave 'make all' racing to
remove and recreate aconfig.h (and possibly more things), while it
begins to build the first targets.  Which then fail horribly like
we see here:

https://buildd.debian.org/status/fetch.php?pkg=tftp-hpa&arch=i386&ver=5.2%2B20140608-1&stamp=1406736363

Possibly we also need to move the actual build job into the rule for
the 'all' target, so that the build system update prerequisites are
guaranteed to be completed before it runs (as opposed to running in
parallel with them), but this change might be enough for now.

Signed-off-by: Ron Lee <ron@debian.org>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2014-07-31 16:25:41 -07:00
Daniel Baumann
3ee2b27809 Update manpage to match source code for --map-file
The manpage had --mapfile but the code had --map-file.

Closes: #606267 in the Debian BTS

Reported-By: Jim Paris <jim@jtan.com>
Signed-off-by: Ron Lee <ron@debian.org>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2014-07-31 16:25:01 -07:00
Thorsten Glaser
18ac1e26f7 __progname[] is provided by libc
Rename local variable to tftpd_progname to avoid a clash with glibc
global symbols and work around Debian bug #519006 (Closes: #564052).

[ hpa: specifically, double-underscore symbols in C are reserved for
  the implementation, i.e. compiler/libc. ]

Signed-off-by: Ron Lee <ron@debian.org>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2014-07-31 16:24:37 -07:00
H. Peter Anvin
8ddf0d87d7 tftp: drop "inline" from definition of usage()
It is pointless and newer gcc say it is a lose.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2014-06-07 13:00:46 -07:00
H. Peter Anvin
2ac12abbc9 tftpd.8: document IPv6 handling in remapping rules
Document the "4" and "6" conditionals as well as how \i and \x handle
IPv6 addresses.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2014-06-07 12:59:44 -07:00
H. Peter Anvin
18ee96a03f tftpd: allow IPv4/6-specific remapping rules
Allow remapping rules to be conditional on IPv4 vs IPv6.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2014-06-07 12:59:33 -07:00
H. Peter Anvin
c89a63a441 tftp: convert IPv6-mapped IPv4 addresses to IPv4
If we receive IPv4 addresses mapped to IPv6, convert them back to IPv4
so that mapping scripts which use \i behave sanely.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2014-06-07 12:37:33 -07:00
H. Peter Anvin
128e6a3905 Support IPv6 on MacOS X systems
Add feature test macros for MacOS X, and don't require
IPV6_RECVPKTINFO to exist.

Reported-by: YJZ <vollkommen@gmx.net>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2012-03-01 22:44:32 -08:00
49 changed files with 1295 additions and 891 deletions

11
.editorconfig Normal file
View file

@ -0,0 +1,11 @@
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

11
.gitignore vendored
View file

@ -1,6 +1,9 @@
/MCONFIG
/aconfig.h
/aconfig.h.in
/config/MCONFIG
/config/config.h
/config/config.h.in
/autoconf/aclocal.m4
/autoconf/clean.sh
/autoconf/helpers/
/autom4te.cache
/config.log
/config.status
@ -12,5 +15,7 @@
*.8
*.a
*.o
*.i
*.s
*~
\#*

View file

@ -3,10 +3,10 @@
SUB = lib common tftp tftpd
%.build: MCONFIG aconfig.h version.h
%.build: config/MCONFIG config/config.h version.h
$(MAKE) -C $(patsubst %.build, %, $@)
%.install: MCONFIG aconfig.h version.h
%.install: config/MCONFIG config/config.h version.h
$(MAKE) -C $(patsubst %.install, %, $@) install
%.clean:
@ -15,12 +15,12 @@ SUB = lib common tftp tftpd
%.distclean:
$(MAKE) -C $(patsubst %.distclean, %, $@) distclean
all: MCONFIG $(patsubst %, %.build, $(SUB))
all: config/MCONFIG $(patsubst %, %.build, $(SUB))
tftp.build: lib.build common.build
tftpd.build: lib.build common.build
install: MCONFIG $(patsubst %, %.install, $(SUB))
install: config/MCONFIG $(patsubst %, %.install, $(SUB))
clean: localclean $(patsubst %, %.clean, $(SUB))
@ -30,46 +30,40 @@ localclean:
distclean: localdistclean $(patsubst %, %.distclean, $(SUB))
localdistclean: localclean
rm -f MCONFIG config.status config.log aconfig.h *~ \#*
rm -f config/config/MCONFIG config.status config.log config/config.h *~ \#*
rm -rf *.cache
find . -type f \( -name \*.orig -o -name \*.rej \) | xargs rm -f
spotless: distclean
rm -f configure aconfig.h.in tftp.spec
rm -f configure config/config.h.in tftp.spec
autoconf: configure aconfig.h.in
autoconf: configure config/config.h.in
config: MCONFIG aconfig.h
config: config/MCONFIG config/config.h
release:
$(MAKE) autoconf
$(MAKE) tftp.spec
$(MAKE) distclean
MCONFIG: configure MCONFIG.in aconfig.h.in
config/MCONFIG: configure config/MCONFIG.in config/config.h.in
if test -x config.status; then \
./config.status --recheck && ./config.status ; \
else \
./configure ; \
fi
aconfig.h: MCONFIG
config/config.h: config/MCONFIG
: Generated by side effect
# Adding "configure" to the dependencies serializes this with running
# 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
configure: configure.ac
sh autogen.sh
configure: configure.in aclocal.m4
rm -rf MCONFIG configure config.log aconfig.h *.cache
autoconf
config/config.h.in: configure
: Generated by side effect
version.h: version
echo \#define VERSION \"tftp-hpa `cat version`\" > version.h
tftp.spec: tftp.spec.in version
sed -e "s/@@VERSION@@/`cat version`/g" < $< > $@ || rm -f $@

280
aclocal.m4 vendored
View file

@ -1,280 +0,0 @@
dnl -----------------------------------------------------------------------
dnl
dnl Copyright 1999-2008 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 ------------------------------------------------------------------------
AH_TEMPLATE([HAVE_STRUCT_IN_PKTINFO],
[Define if struct in_pktinfo is defined.])
AC_DEFUN(PA_STRUCT_IN_PKTINFO,
[AC_CHECK_MEMBER(struct in_pktinfo.ipi_addr,
[AC_DEFINE(HAVE_STRUCT_IN_PKTINFO)],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/uio.h>
])])
dnl ------------------------------------------------------------------------
dnl PA_STRUCT_SOCKADDR_IN6
dnl
dnl Look for definition of struct sockaddr_in6, which at least has an
dnl sin6_addr member
dnl
AH_TEMPLATE([HAVE_STRUCT_SOCKADDR_IN6],
[Define if struct sockaddr_in6 is defined.])
AC_DEFUN(PA_STRUCT_SOCKADDR_IN6,
[AC_CHECK_MEMBER(struct sockaddr_in6.sin6_addr,
[
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)
HAVE_INET6=true;
],
[
HAVE_INET6=false;
],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
])])
dnl ------------------------------------------------------------------------
dnl PA_STRUCT_ADDRINFO
dnl
dnl Look for definition of struct addrinfo, which at least has an
dnl ai_addr member
dnl
AH_TEMPLATE([HAVE_STRUCT_ADDRINFO],
[Define if struct addrinfo is defined.])
AC_DEFUN(PA_STRUCT_ADDRINFO,
[AC_CHECK_MEMBER(struct addrinfo.ai_addr,
[AC_DEFINE(HAVE_STRUCT_ADDRINFO)],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
])])
dnl ------------------------------------------------------------------------
dnl PA_STRUCT_IN6_PKTINFO
dnl
dnl Look for definition of struct in6_pktinfo, which at least has an
dnl ipi6_addr member
dnl
AH_TEMPLATE([HAVE_STRUCT_IN6_PKTINFO],
[Define if struct in6_pktinfo is defined.])
AC_DEFUN(PA_STRUCT_IN6_PKTINFO,
[AC_CHECK_MEMBER(struct in6_pktinfo.ipi6_addr,
[AC_DEFINE(HAVE_STRUCT_IN6_PKTINFO)],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
])])
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)
])])
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

@ -0,0 +1,9 @@
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

@ -0,0 +1,39 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,4 @@
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

@ -0,0 +1,4 @@
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

@ -0,0 +1,16 @@
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

@ -0,0 +1,32 @@
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

@ -0,0 +1,26 @@
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

@ -0,0 +1,17 @@
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

@ -0,0 +1,41 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,26 @@
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

@ -0,0 +1,15 @@
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

@ -0,0 +1,20 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,8 @@
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])])])

13
autoconf/m4/pa_prog_cc.m4 Normal file
View file

@ -0,0 +1,13 @@
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

@ -0,0 +1,22 @@
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

@ -0,0 +1,25 @@
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])])])

11
autoconf/m4/pa_sym.m4 Normal file
View file

@ -0,0 +1,11 @@
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,2 +1,83 @@
#!/bin/sh
make autoconf
#!/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,10 +1,10 @@
SRCROOT = ..
VERSION = $(shell cat ../version)
-include ../MCONFIG
-include ../config/MCONFIG
include ../MRULES
OBJS = tftpsubs.$(O)
OBJS = tftpsubs.$(O) signal.$(O)
LIB = libcommon.a
all: $(LIB)

19
common/signal.c Normal file
View file

@ -0,0 +1,19 @@
/*
* 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,6 +1,6 @@
/* -*- c -*- ------------------------------------------------------------- *
*
* Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
* Copyright 2001-2024 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at
@ -17,12 +17,23 @@
#ifndef CONFIG_H
#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! */
#include "aconfig.h" /* autogenerated configuration header */
#include "config/config.h" /* autogenerated configuration header */
/* Standard includes */
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@ -32,21 +43,6 @@
#include <sys/stat.h>
#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
#include <string.h>
#endif
@ -73,15 +69,8 @@
#include <setjmp.h>
#endif
#ifdef TIME_WITH_SYS_TIME
#ifdef HAVE_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
#ifdef HAVE_GRP_H
@ -92,9 +81,6 @@
#include <fcntl.h>
#endif
#include <errno.h>
#include <signal.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#else
@ -129,10 +115,10 @@
/* Some broken systems care about text versus binary, but
real Unix systems don't... */
#ifndef HAVE_O_TEXT_DEFINITION
#if !HAVE_DECL_O_TEXT
#define O_TEXT 0
#endif
#ifndef HAVE_O_BINARY_DEFINITION
#if !HAVE_DECL_O_BINARY
#define O_BINARY 0
#endif
@ -267,11 +253,9 @@ typedef int socklen_t;
#include <netinet/in.h>
#ifndef HAVE_IPPORT_TFTP_DEFINITION
#ifndef IPPORT_TFTP
#if !HAVE_DECL_IPPORT_TFTP && !defined(IPPORT_TFTP)
#define IPPORT_TFTP 69
#endif
#endif
/* arpa/{inet,tftp}.h, and possible missing pieces */
@ -293,9 +277,11 @@ typedef int socklen_t;
void *xmalloc(size_t);
char *xstrdup(const char *);
#ifndef HAVE_BSD_SIGNAL
void (*bsd_signal(int, void (*)(int))) (int);
#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

283
configure.ac Normal file
View file

@ -0,0 +1,283 @@
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

View file

@ -1,303 +0,0 @@
dnl
dnl autoconf input file to generate MCONFIG
dnl
AC_PREREQ(2.61)
AC_INIT(MCONFIG.in)
AC_PREFIX_DEFAULT(/usr)
AC_USE_SYSTEM_EXTENSIONS
AC_ISC_POSIX
AC_PROG_CC
AC_C_CONST
AC_C_INLINE
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(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/file.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_CHECK_HEADERS(netdb.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_SYS_LARGEFILE
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)
dnl
dnl <sys/socket.h> isn't among the list of standard headers that autoconf checks,
dnl but POSIX requires <sys/socket.h> for socklen_t to be defined.
dnl
AC_CHECK_TYPES(socklen_t,,,
[
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#if STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# if HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#if HAVE_STRING_H
# if !STDC_HEADERS && HAVE_MEMORY_H
# include <memory.h>
# endif
# include <string.h>
#endif
#if HAVE_STRINGS_H
# include <strings.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
#else
# if HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
])
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], , [AC_MSG_ERROR(socket library not found)])
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_STRUCT_ADDRINFO
PA_HEADER_DEFINES(fcntl.h, int, O_NONBLOCK)
PA_HEADER_DEFINES(fcntl.h, int, O_BINARY)
PA_HEADER_DEFINES(fcntl.h, int, O_TEXT)
PA_HEADER_DEFINES(fcntl.h, int, F_SETLK)
PA_HEADER_DEFINES(sys/file.h, int, LOCK_SH)
PA_HEADER_DEFINES(sys/file.h, int, LOCK_EX)
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
PA_SEARCH_LIBS_AND_ADD(xmalloc, iberty)
PA_SEARCH_LIBS_AND_ADD(xstrdup, iberty)
PA_SEARCH_LIBS_AND_ADD(bsd_signal, bsd, bsdsignal)
PA_SEARCH_LIBS_AND_ADD(getopt_long, getopt, getopt_long)
PA_SEARCH_LIBS_AND_ADD(getaddrinfo, [nsl resolv])
if $pa_add_getaddrinfo
then
AC_SEARCH_LIBS(gethostbyname, [nsl resolv],
[AC_SEARCH_LIBS(herror, [nsl resolv], ,
[AC_MSG_ERROR(herror not found)])],
[AC_MSG_ERROR(gethostbyname not found)])
else
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)])
fi
PA_SEARCH_LIBS_AND_ADD(inet_ntop, [nsl resolv])
if $pa_add_inet_ntop
then
AC_SEARCH_LIBS(inet_ntoa, [nsl resolv], ,
[AC_MSG_ERROR(inet_ntoa not found)])
fi
AC_SEARCH_LIBS(inet_aton, [nsl resolv], ,[AC_MSG_ERROR(inet_aton not found)])
AC_CHECK_FUNCS(daemon, , [XTRA=true; AC_LIBOBJ(daemon)])
AC_CHECK_FUNCS(dup2, , [XTRA=true; AC_LIBOBJ(dup2)])
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/editline 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)])
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
PA_STRUCT_SOCKADDR_IN6
AC_MSG_CHECKING([for IPv6 support])
PA_WITH_BOOL(ipv6, 1,
[ --without-ipv6 disable the support for IPv6],
[
if $HAVE_INET6
then
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_IPV6, 1, [Define if IPv6 support is enabled.])
PA_STRUCT_IN6_PKTINFO
else
AC_MSG_RESULT(no)
AC_MSG_WARN([*** we do not have required IPv6 structs - IPv6 will be disabled])
fi
],
[AC_MSG_RESULT(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]
AC_CONFIG_HEADERS(aconfig.h)
AC_OUTPUT(MCONFIG)

View file

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

View file

@ -1,27 +0,0 @@
/*
* bsdsignal.c
*
* Use sigaction() to simulate BSD signal()
*/
#include "config.h"
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,7 +1,7 @@
SRCROOT = ..
VERSION = $(shell cat ../version)
-include ../MCONFIG
-include ../config/MCONFIG
include ../MRULES
OBJS = tftp.$(O) main.$(O)

View file

@ -31,10 +31,13 @@
* SUCH DAMAGE.
*/
#ifndef RECVFILE_H
#define RECVFILE_H
#ifndef EXTERN_H
#define EXTERN_H
#include "config.h"
void tftp_recvfile(int, const char *, const char *);
void tftp_sendfile(int, const char *, const char *);
extern sigjmp_buf toplevel;
#endif

View file

@ -188,7 +188,7 @@ char *xstrdup(const char *);
const char *program;
static inline void usage(int errcode)
static void usage(int errcode)
{
fprintf(stderr,
#ifdef HAVE_IPV6
@ -305,7 +305,7 @@ int main(int argc, char *argv[])
sp->s_proto = (char *)"udp";
}
bsd_signal(SIGINT, intr);
tftp_signal(SIGINT, intr, 0);
if (peerargc) {
/* Set peer */
@ -768,8 +768,8 @@ void intr(int sig)
{
(void)sig; /* Quiet unused warning */
bsd_signal(SIGALRM, SIG_IGN);
alarm(0);
tftp_signal(SIGALRM, SIG_DFL, 0);
siglongjmp(toplevel, -1);
}

View file

@ -48,8 +48,7 @@ extern int maxtimeout;
#define PKTSIZE SEGSIZE+4
char ackbuf[PKTSIZE];
int timeout;
sigjmp_buf toplevel;
sigjmp_buf timeoutbuf;
static sigjmp_buf timeoutbuf;
static void nak(int, const char *);
static int makerequest(int, const char *, struct tftphdr *, const char *);
@ -85,7 +84,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode)
is_request = 1; /* First packet is the actual WRQ */
amount = 0;
bsd_signal(SIGALRM, timer);
tftp_signal(SIGALRM, timer, 0);
do {
if (is_request) {
size = makerequest(WRQ, name, dp, mode) - 4;
@ -191,7 +190,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode)
firsttrip = 1;
amount = 0;
bsd_signal(SIGALRM, timer);
tftp_signal(SIGALRM, timer, 0);
do {
if (firsttrip) {
size = makerequest(RRQ, name, ap, mode);

View file

@ -1,7 +1,7 @@
SRCROOT = ..
VERSION = $(shell cat ../version)
-include ../MCONFIG
-include ../config/MCONFIG
include ../MRULES
OBJS = tftpd.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS)

View file

@ -19,19 +19,11 @@
#include "tftpd.h"
/*
* Set the signal handler and flags. Basically a user-friendly
* wrapper around sigaction().
* Set the signal handler and flags, and error out on failure.
*/
void set_signal(int signum, void (*handler) (int), int flags)
void set_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;
if (sigaction(signum, &sa, NULL)) {
if (tftp_signal(signum, handler, flags)) {
syslog(LOG_ERR, "sigaction: %m");
exit(EX_OSERR);
}

View file

@ -26,10 +26,12 @@
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
#include <sys/uio.h>
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef IP_PKTINFO
# ifndef HAVE_STRUCT_IN_PKTINFO
# ifndef HAVE_STRUCT_IN_PKTINFO_IPI_ADDR
# ifdef __linux__
/* Assume this version of glibc simply lacks the definition */
struct in_pktinfo {
@ -113,10 +115,31 @@ err:
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
myrecvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t * fromlen,
union sock_addr *myaddr)
union sock_addr *from, union sock_addr *myaddr)
{
struct msghdr msg;
struct iovec iov;
@ -149,16 +172,16 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
/* Try to enable getting the return address */
#ifdef IP_RECVDSTADDR
if (from->sa_family == AF_INET)
if (from->sa.sa_family == AF_INET)
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
#endif
#ifdef IP_PKTINFO
if (from->sa_family == AF_INET)
if (from->sa.sa_family == AF_INET)
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
#endif
#ifdef HAVE_IPV6
#ifdef IPV6_RECVPKTINFO
if (from->sa_family == AF_INET6)
if (from->sa.sa_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
#endif
#endif
@ -167,8 +190,8 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
msg.msg_controllen = sizeof(control_un);
msg.msg_flags = 0;
msg.msg_name = from;
msg.msg_namelen = *fromlen;
msg.msg_name = &from->sa;
msg.msg_namelen = sizeof(*from);
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_iov = &iov;
@ -177,11 +200,9 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
if ((n = recvmsg(s, &msg, flags)) < 0)
return n; /* Error */
*fromlen = msg.msg_namelen;
if (myaddr) {
bzero(myaddr, sizeof(*myaddr));
myaddr->sa.sa_family = from->sa_family;
myaddr->sa.sa_family = from->sa.sa_family;
if (msg.msg_controllen < sizeof(struct cmsghdr) ||
(msg.msg_flags & MSG_CTRUNC))
@ -190,7 +211,7 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
cmptr = CMSG_NXTHDR(&msg, cmptr)) {
if (from->sa_family == AF_INET) {
if (from->sa.sa_family == AF_INET) {
myaddr->sa.sa_family = AF_INET;
#ifdef IP_RECVDSTADDR
if (cmptr->cmsg_level == IPPROTO_IP &&
@ -211,7 +232,7 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
#endif
}
#ifdef HAVE_IPV6
else if (from->sa_family == AF_INET6) {
else if (from->sa.sa_family == AF_INET6) {
myaddr->sa.sa_family = AF_INET6;
#ifdef IP6_RECVDSTADDR
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
@ -222,17 +243,23 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
#ifdef HAVE_STRUCT_IN6_PKTINFO
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
(cmptr->cmsg_type == IPV6_RECVPKTINFO ||
(
#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));
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...
*/
@ -245,6 +272,9 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
#endif
}
}
normalize_ip6_compat(from);
return n;
}
@ -252,16 +282,16 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t * fromlen,
union sock_addr *myaddr)
union sock_addr *from, union sock_addr *myaddr)
{
/* There is no way we can get the local address, fudge it */
socklen_t fromlen = sizeof(*from);
bzero(myaddr, sizeof(*myaddr));
myaddr->sa.sa_family = from->sa_family;
myaddr->sa.sa_family = from->sa.sa_family;
sa_set_port(myaddr, htons(IPPORT_TFTP));
return recvfrom(s, buf, len, flags, from, fromlen);
return recvfrom(s, buf, len, flags, &from->sa, &fromlen);
}
#endif

View file

@ -19,5 +19,4 @@
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen,
union sock_addr *myaddr);
union sock_addr *from, union sock_addr *myaddr);

View file

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
* Copyright 2001-2024 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at
@ -22,7 +22,7 @@
#include "tftpd.h"
#include "remap.h"
#define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
#define DEADMAN_MAX_STEPS 4096 /* Timeout after this many steps */
#define MAXLINE 16384 /* Truncate a line at this many bytes */
#define RULE_REWRITE 0x01 /* This is a rewrite rule */
@ -31,12 +31,20 @@
#define RULE_RESTART 0x08 /* Restart at the top after matching this rule */
#define RULE_ABORT 0x10 /* Terminate processing with an error */
#define RULE_INVERSE 0x20 /* Execute if regex *doesn't* match */
#define RULE_IPV4 0x40 /* IPv4 only */
#define RULE_IPV6 0x80 /* IPv6 only */
#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 *next;
int nrule;
int rule_flags;
char rule_mode;
unsigned int rule_flags;
regex_t rx;
const char *pattern;
};
@ -56,22 +64,30 @@ static int xform_tolower(int c)
return tolower(c);
}
/* Do \-substitution. Call with string == NULL to get length only. */
static int genmatchstring(char *string, const char *pattern,
const char *input, const regmatch_t * pmatch,
match_pattern_callback macrosub)
/*
* Do \-substitution. Call with string == NULL to get length only.
* "start" indicates an offset into the input buffer where the pattern
* 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 len = 0;
int n, mlen, sublen;
int endbytes;
const char *input = ibuf + start;
/* Get section before match; note pmatch[0] is the whole match */
endbytes = strlen(input) - pmatch[0].rm_eo;
len = pmatch[0].rm_so + endbytes;
len = start + pmatch[0].rm_so;
if (string) {
memcpy(string, input, pmatch[0].rm_so);
string += pmatch[0].rm_so;
/* Copy the prefix before "start" as well! */
memcpy(string, ibuf, start + pmatch[0].rm_so);
string += start + pmatch[0].rm_so;
}
/* Transform matched section */
@ -97,7 +113,7 @@ static int genmatchstring(char *string, const char *pattern,
mlen = pmatch[n].rm_eo - pmatch[n].rm_so;
len += mlen;
if (string) {
const char *p = input + pmatch[n].rm_so;
const char *p = input + start + pmatch[n].rm_so;
while (mlen--)
*string++ = xform(*p++);
}
@ -140,7 +156,12 @@ static int genmatchstring(char *string, const char *pattern,
}
}
/* Pointer to post-substitution tail */
if (nextp)
*nextp = len;
/* Copy section after match */
len += endbytes;
if (string) {
memcpy(string, input + pmatch[0].rm_eo, endbytes);
string[endbytes] = '\0';
@ -149,6 +170,26 @@ static int genmatchstring(char *string, const char *pattern,
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
* leading whitespace. Consider an unescaped # to be a comment marker,
@ -206,11 +247,17 @@ static int parseline(char *line, struct rule *r, int lineno)
r->rule_flags |= RULE_REWRITE;
break;
case 'g':
r->rule_flags |= RULE_GLOBAL;
if (r->rule_flags & RULE_GLOBAL)
r->rule_flags |= RULE_SEDG;
else
r->rule_flags |= RULE_GLOBAL;
break;
case 'e':
r->rule_flags |= RULE_EXIT;
break;
case 'E':
r->rule_flags |= RULE_HASFILE;
break;
case 's':
r->rule_flags |= RULE_RESTART;
break;
@ -223,9 +270,17 @@ static int parseline(char *line, struct rule *r, int lineno)
case '~':
r->rule_flags |= RULE_INVERSE;
break;
case 'G':
case 'P':
r->rule_mode = *p;
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:
syslog(LOG_ERR,
@ -236,15 +291,21 @@ static int parseline(char *line, struct rule *r, int lineno)
}
}
/* RULE_GLOBAL only applies when RULE_REWRITE specified */
if (!(r->rule_flags & RULE_REWRITE))
r->rule_flags &= ~RULE_GLOBAL;
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 */
if (r->rule_flags & RULE_REWRITE) {
if (r->rule_flags & RULE_INVERSE) {
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n",
lineno, line);
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 */
@ -325,17 +386,24 @@ void freerules(struct rule *r)
}
/* Execute a rule set on a string; returns a malloc'd new string. */
char *rewrite_string(const char *input, const struct rule *rules,
char mode, match_pattern_callback macrosub,
char *rewrite_string(const struct formats *pf,
const char *input, const struct rule *rules,
int mode, int af, match_pattern_callback macrosub,
const char **errmsg)
{
char *current = tfstrdup(input);
char *newstr;
char *newstr, *newerstr;
const char *accerr;
const struct rule *ruleptr = rules;
regmatch_t pmatch[10];
int i;
int len;
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 */
*errmsg = "Remap table failure";
@ -344,86 +412,121 @@ char *rewrite_string(const char *input, const struct rule *rules,
syslog(LOG_INFO, "remap: input: %s", current);
}
for (ruleptr = rules; ruleptr; ruleptr = ruleptr->next) {
if (ruleptr->rule_mode && ruleptr->rule_mode != mode)
continue; /* Rule not applicable, try next */
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;
if (!deadman--) {
syslog(LOG_WARNING,
"remap: Breaking loop, input = %s, last = %s", input,
current);
free(current);
return NULL; /* Did not terminate! */
}
for (ruleptr = rules; ruleptr; ruleptr = ruleptr->next) {
if (ruleptr->rule_flags & bad_flags)
continue; /* This rule is excluded by flags */
matchsense = ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0;
pmatches = ruleptr->rule_flags & RULE_INVERSE ? 0 : 10;
/* Clear the pmatch[] array */
for (i = 0; i < 10; i++)
pmatch[i].rm_so = pmatch[i].rm_eo = -1;
was_match = 0;
do {
if (regexec(&ruleptr->rx, current, 10, pmatch, 0) ==
(ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0)) {
/* Match on this rule */
was_match = 1;
if (!deadman--)
goto dead;
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 (regexec(&ruleptr->rx, current, pmatches, pmatch, 0)
!= matchsense)
break; /* No match, break out of do loop */
if (ruleptr->rule_flags & RULE_ABORT) {
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: abort: %s",
ruleptr->nrule, current);
}
if (ruleptr->pattern[0]) {
/* Custom error message */
len =
genmatchstring(NULL, ruleptr->pattern, current,
pmatch, macrosub);
newstr = tfmalloc(len + 1);
genmatchstring(newstr, ruleptr->pattern, current,
pmatch, macrosub);
*errmsg = newstr;
} else {
*errmsg = NULL;
}
free(current);
return (NULL);
}
/* Match on this rule */
was_match = 1;
if (ruleptr->rule_flags & RULE_REWRITE) {
len = genmatchstring(NULL, ruleptr->pattern, current,
pmatch, macrosub);
newstr = tfmalloc(len + 1);
genmatchstring(newstr, ruleptr->pattern, current,
pmatch, macrosub);
free(current);
current = newstr;
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: rewrite: %s",
ruleptr->nrule, current);
}
if (ruleptr->rule_flags & RULE_ABORT) {
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: abort: %s",
ruleptr->nrule, current);
}
} else {
break; /* No match, terminate unconditionally */
if (ruleptr->pattern[0]) {
/* Custom error message */
genmatchstring(&newstr, ruleptr->pattern, current,
pmatch, macrosub, 0, NULL);
*errmsg = newstr;
} else {
*errmsg = NULL;
}
free(current);
return (NULL);
}
/* If the rule is global, keep going until no match */
} while (ruleptr->rule_flags & RULE_GLOBAL);
if (was_match) {
was_match = 0;
if (ruleptr->rule_flags & RULE_REWRITE) {
len = genmatchstring(&newstr, ruleptr->pattern, current,
pmatch, macrosub, 0, &ggoffset);
if (ruleptr->rule_flags & RULE_EXIT) {
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: exit",
ruleptr->nrule);
if (ruleptr->rule_flags & RULE_SEDG) {
/* sed-style partial-matching global */
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;
}
}
return current; /* Exit here, we're done */
} else if (ruleptr->rule_flags & RULE_RESTART) {
ruleptr = rules; /* Start from the top */
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: restart",
ruleptr->nrule);
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);
current = newstr;
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: rewrite: %s",
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);
}
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)
continue; /* Next rule */
if (ruleptr->rule_flags & (RULE_EXIT|RULE_HASFILE)) {
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: exit",
ruleptr->nrule);
}
return current; /* Exit here, we're done */
} else if (ruleptr->rule_flags & RULE_RESTART) {
ruleptr = rules; /* Start from the top */
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: rule %d: restart",
ruleptr->nrule);
}
}
}
@ -432,4 +535,11 @@ char *rewrite_string(const char *input, const struct rule *rules,
syslog(LOG_INFO, "remap: done");
}
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

@ -35,8 +35,13 @@ struct rule *parserulefile(FILE *);
void freerules(struct rule *);
/* Execute a rule set on a string; returns a malloc'd new string. */
char *rewrite_string(const char *, const struct rule *, char,
struct formats;
char *rewrite_string(const struct formats *, const char *,
const struct rule *, int, int,
match_pattern_callback, const char **);
/* Remapping deadman counter */
extern int deadman_max_steps;
#endif /* WITH_REGEX */
#endif /* TFTPD_REMAP_H */

View file

@ -1,5 +1,5 @@
.\" -*- nroff -*- --------------------------------------------------------- *
.\"
.\"
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\"----------------------------------------------------------------------- */
.TH TFTPD 8 "14 September 2009" "tftp-hpa @@VERSION@@" "System Manager's Manual"
.TH TFTPD 8 "7 June 2014" "tftp-hpa @@VERSION@@" "System Manager's Manual"
.SH NAME
.B tftpd
\- Trivial File Transfer Protocol server
@ -155,7 +155,7 @@ or
.B utimeout
option is negotiated. The default is 1000000 (1 second.)
.TP
\fB\-\-mapfile\fP \fIremap-file\fP, \fB\-m\fP \fIremap-file\fP
\fB\-\-map-file\fP \fIremap-file\fP, \fB\-m\fP \fIremap-file\fP
Specify the use of filename remapping. The
.I remap-file
is a file containing the remapping rules. See the section on filename
@ -163,6 +163,10 @@ remapping below. This option may not be compiled in, see the output of
.B "in.tftpd \-V"
to verify whether or not it is available.
.TP
.\fB\-\-map-steps\fP \fIsteps\fP
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
.BR tftpd .
@ -238,7 +242,7 @@ option, but crash with an error if they actually get the option
accepted by the server.
.SH "FILENAME REMAPPING"
The
.B \-\-mapfile
.B \-\-map-file
option specifies a file which contains filename remapping rules. Each
non-comment line (comments begin with hash marks,
.BR # )
@ -270,7 +274,18 @@ by the
The replacement pattern may contain escape sequences; see below.
.TP
.B g
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 .
.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
@ -281,6 +296,17 @@ case-insensitively. By default it is case sensitive.
.B e
If this rule matches, end rule processing after executing the rule.
.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
If this rule matches, start rule processing over from the very first
rule after executing this rule.
@ -295,16 +321,22 @@ This rule applies to GET (RRQ) requests only.
.B P
This rule applies to PUT (WRQ) requests only.
.TP
.B 4
This rule applies to IPv4 sessions only.
.TP
.B 6
This rule applies to IPv6 sessions only.
.TP
.B ~
Inverse the sense of this rule, i.e. execute the
.I operation
only if the
.I regex
.I doesn't
match. Cannot used together with
match. Cannot used together with
.BR r .
.PP
The following escape sequences are recognized as part of the
The following escape sequences are recognized as part of a
.IR "replacement pattern" :
.TP
\fB\\0\fP
@ -318,12 +350,14 @@ subexpressions, \\( ... \\), of the
pattern.
.TP
\fB\\i\fP
The IP address of the requesting host, in dotted-quad notation
(e.g. 192.0.2.169).
The IP address of the requesting host, in dotted-quad notation for
IPv4 (e.g. 192.0.2.169) or conventional colon form for IPv6
(e.g. 2001:db8::1).
.TP
\fB\\x\fP
The IP address of the requesting host, in hexadecimal notation
(e.g. C00002A9).
The IP address of the requesting host, in expanded hexadecimal
notation (e.g. C00002A9 for IPv4, or 20010DB8000000000000000000000001
for IPv6).
.TP
\fB\\\\\fP
Literal backslash.
@ -383,14 +417,14 @@ Access to files can, and should, be restricted by invoking
.B tftpd
with a list of directories by including pathnames as server program
arguments on the command line. In this case access is restricted to
files whole names are prefixed by one of the given directories. If
files whose names are prefixed by one of the given directories. If
possible, it is recommended that the
.B \-\-secure
flag is used to set up a chroot() environment for the server to run in
once a connection has been set up.
.PP
Finally, the filename remapping
.RB ( \-\-mapfile
.RB ( \-\-map-file
flag) support can be used to provide a limited amount of additional
access control.
.SH "CONFORMING TO"

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 1983 Regents of the University of California.
* Copyright (c) 1999-2009 H. Peter Anvin
* Copyright (c) 2011 Intel Corporation; author: H. Peter Anvin
* Copyright (c) 2011-2014 Intel Corporation; author: H. Peter Anvin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -76,7 +76,7 @@ static int ai_fam = AF_INET;
#define TRIES 6 /* Number of attempts to send each packet */
#define TIMEOUT_LIMIT ((1 << TRIES)-1)
const char *__progname;
const char *tftpd_progname;
static int peer;
static unsigned long timeout = TIMEOUT; /* Current timeout value */
static unsigned long rexmtval = TIMEOUT; /* Basic timeout value */
@ -93,7 +93,6 @@ static unsigned int max_blksize = MAX_SEGSIZE;
static char tmpbuf[INET6_ADDRSTRLEN], *tmp_p;
static union sock_addr from;
static socklen_t fromlen;
static off_t tsize;
static int tsize_ok;
@ -107,11 +106,12 @@ int portrange = 0;
unsigned int portrange_from, portrange_to;
int verbosity = 0;
struct formats;
#ifdef WITH_REGEX
static struct rule *rewrite_rules = NULL;
#endif
static FILE *file;
int tftp(struct tftphdr *, int);
static void nak(int, const char *);
static void timer(int);
@ -153,7 +153,7 @@ static void handle_exit(int sig)
}
/* Handle timeout signal or timeout event */
void timer(int sig)
static void timer(int sig)
{
(void)sig; /* Suppress unused warning */
timeout <<= 1;
@ -163,14 +163,14 @@ void timer(int sig)
}
#ifdef WITH_REGEX
static struct rule *read_remap_rules(const char *file)
static struct rule *read_remap_rules(const char *rulefile)
{
FILE *f;
struct rule *rulep;
f = fopen(file, "rt");
f = fopen(rulefile, "rt");
if (!f) {
syslog(LOG_ERR, "Cannot open map file: %s: %m", file);
syslog(LOG_ERR, "Cannot open map file: %s: %m", rulefile);
exit(EX_NOINPUT);
}
rulep = parserulefile(f);
@ -185,7 +185,8 @@ static struct rule *read_remap_rules(const char *file)
*/
static int lock_file(int fd, int lock_write)
{
#if defined(HAVE_FCNTL) && defined(HAVE_F_SETLK_DEFINITION)
(void)lock_write;
#if defined(HAVE_FCNTL) && HAVE_DECL_F_SETLK
struct flock fl;
fl.l_type = lock_write ? F_WRLCK : F_RDLCK;
@ -193,7 +194,7 @@ static int lock_file(int fd, int lock_write)
fl.l_start = 0;
fl.l_len = 0; /* Whole file */
return fcntl(fd, F_SETLK, &fl);
#elif defined(HAVE_LOCK_SH_DEFINITION)
#elif defined(HAVE_FLOCK) && HAVE_DECL_LOCK_SH && HAVE_DECL_LOCK_EX
return flock(fd, lock_write ? LOCK_EX|LOCK_NB : LOCK_SH|LOCK_NB);
#else
return 0; /* Hope & pray... */
@ -324,8 +325,9 @@ static int split_port(char **ap, char **pp)
enum long_only_options {
OPT_VERBOSITY = 256,
OPT_MAP_STEPS
};
static struct option long_options[] = {
{ "ipv4", 0, NULL, '4' },
{ "ipv6", 0, NULL, '6' },
@ -346,6 +348,7 @@ static struct option long_options[] = {
{ "retransmit", 1, NULL, 'T' },
{ "port-range", 1, NULL, 'R' },
{ "map-file", 1, NULL, 'm' },
{ "map-steps", 1, NULL, OPT_MAP_STEPS },
{ "pidfile", 1, NULL, 'P' },
{ NULL, 0, NULL, 0 }
};
@ -375,6 +378,7 @@ int main(int argc, char **argv)
int spec_umask = 0;
int c;
int setrv;
int die;
int waittime = 900; /* Default time to wait for a connect */
const char *user = "nobody"; /* Default user */
char *p, *ep;
@ -387,9 +391,9 @@ int main(int argc, char **argv)
/* basename() is way too much of a pain from a portability standpoint */
p = strrchr(argv[0], '/');
__progname = (p && p[1]) ? p + 1 : argv[0];
tftpd_progname = (p && p[1]) ? p + 1 : argv[0];
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
openlog(tftpd_progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
srand(time(NULL) ^ getpid());
@ -493,6 +497,17 @@ int main(int argc, char **argv)
}
rewrite_file = optarg;
break;
case OPT_MAP_STEPS:
{
unsigned long steps = strtoul(optarg, &ep, 0);
if (*optarg && *ep && steps > 0 && steps <= INT_MAX) {
deadman_max_steps = steps;
} else {
syslog(LOG_ERR, "Bad --map-steps option: %s", optarg);
exit(EX_USAGE);
}
break;
}
#endif
case 'v':
verbosity++;
@ -874,9 +889,7 @@ int main(int argc, char **argv)
set_socket_nonblock(fd, 0);
#endif
fromlen = sizeof(from);
n = myrecvfrom(fd, buf, sizeof(buf), 0,
(struct sockaddr *)&from, &fromlen, &myaddr);
n = myrecvfrom(fd, buf, sizeof(buf), 0, &from, &myaddr);
if (n < 0) {
if (E_WOULD_BLOCK(errno) || errno == EINTR) {
@ -938,14 +951,14 @@ int main(int argc, char **argv)
syslog daemon gets restarted by the time we get here. */
if (secure && standalone) {
closelog();
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
openlog(tftpd_progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
}
#ifdef HAVE_TCPWRAPPERS
/* Verify if this was a legal request for us. This has to be
done before the chroot, while /etc is still accessible. */
request_init(&wrap_request,
RQ_DAEMON, __progname,
RQ_DAEMON, tftpd_progname,
RQ_FILE, fd,
RQ_CLIENT_SIN, &from, RQ_SERVER_SIN, &myaddr, 0);
sock_methods(&wrap_request);
@ -977,21 +990,29 @@ int main(int argc, char **argv)
exit(EX_IOERR);
}
/* Set up the supplementary group access list if possible */
/* /etc/group still need to be accessible at this point */
/* Set up the supplementary group access list if possible
/etc/group still need to be accessible at this point.
If we get EPERM, this is already a restricted process, e.g.
using user namespaces on Linux. */
die = 0;
#ifdef HAVE_SETGROUPS
setrv = setgroups(0, NULL);
if (setrv && errno != EPERM) {
syslog(LOG_ERR, "cannot clear group list");
die = EX_OSERR;
}
#endif
#ifdef HAVE_INITGROUPS
setrv = initgroups(user, pw->pw_gid);
if (setrv) {
if (!setrv) {
die = 0;
} else if (errno != EPERM) {
syslog(LOG_ERR, "cannot set groups for user %s", user);
exit(EX_OSERR);
}
#else
#ifdef HAVE_SETGROUPS
if (setgroups(0, NULL)) {
syslog(LOG_ERR, "cannot clear group list");
die = EX_OSERR;
}
#endif
#endif
if (die)
exit(die);
/* Chroot and drop privileges */
if (secure) {
@ -1003,19 +1024,30 @@ int main(int argc, char **argv)
chdir("/"); /* Cygwin chroot() bug workaround */
#endif
}
#ifdef HAVE_SETREGID
#ifdef HAVE_SETRESGID
setrv = setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid);
#elif defined(HAVE_SETREGID)
setrv = setregid(pw->pw_gid, pw->pw_gid);
#else
setrv = setegid(pw->pw_gid) || setgid(pw->pw_gid);
#endif
if (setrv && errno == EPERM) {
setrv = 0; /* Assume already restricted by system policy */
}
#ifdef HAVE_SETREUID
#ifdef HAVE_SETRESUID
setrv = setrv || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
#elif defined(HAVE_SETREUID)
setrv = setrv || setreuid(pw->pw_uid, pw->pw_uid);
#else
/* Important: setuid() must come first */
setrv = setrv || setuid(pw->pw_uid) ||
(geteuid() != pw->pw_uid && seteuid(pw->pw_uid));
#endif
if (setrv && errno == EPERM) {
setrv = 0; /* Assume already restricted by system policy */
}
if (setrv) {
syslog(LOG_ERR, "cannot drop privileges: %m");
@ -1039,23 +1071,16 @@ int main(int argc, char **argv)
tp = (struct tftphdr *)buf;
tp_opcode = ntohs(tp->th_opcode);
if (tp_opcode == RRQ || tp_opcode == WRQ)
tftp(tp, n);
tftp(tp, n);
exit(0);
}
static char *rewrite_access(char *, int, const char **);
static char *rewrite_access(const struct formats *,
char *, int, int, const char **);
static int validate_access(char *, int, const struct formats *, const char **);
static void tftp_sendfile(const struct formats *, struct tftphdr *, int);
static void tftp_recvfile(const struct formats *, struct tftphdr *, int);
struct formats {
const char *f_mode;
char *(*f_rewrite) (char *, 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;
};
static const struct formats formats[] = {
{
"netascii", rewrite_access, validate_access, tftp_sendfile,
@ -1112,9 +1137,9 @@ int tftp(struct tftphdr *tp, int size)
nak(EBADOP, "Unknown mode");
exit(0);
}
if (!(filename =
(*pf->f_rewrite) (origfilename, tp_opcode,
&errmsgptr))) {
file = NULL;
if (!(filename = (*pf->f_rewrite)
(pf, origfilename, tp_opcode, from.sa.sa_family, &errmsgptr))) {
nak(EACCESS, errmsgptr); /* File denied by mapping rule */
exit(0);
}
@ -1137,12 +1162,18 @@ int tftp(struct tftphdr *tp, int size)
tmp_p, origfilename,
filename);
}
ecode =
(*pf->f_validate) (filename, tp_opcode, pf, &errmsgptr);
if (ecode) {
nak(ecode, errmsgptr);
exit(0);
}
/*
* If "file" is already set, then a file was already validated
* and opened during remap processing.
*/
if (!file) {
ecode =
(*pf->f_validate) (filename, tp_opcode, pf, &errmsgptr);
if (ecode) {
nak(ecode, errmsgptr);
exit(0);
}
}
opt = ++cp;
} else if (argn & 1) {
val = ++cp;
@ -1229,7 +1260,7 @@ static int set_blksize2(uintmax_t *vp)
static int set_rollover(uintmax_t *vp)
{
uintmax_t ro = *vp;
if (ro > 65535)
return 0;
@ -1328,7 +1359,7 @@ static void do_opt(const char *opt, const char *val, char **ap)
nak(EOPTNEG, "Insufficient space for options");
exit(0);
}
memcpy(p, opt, optlen+1);
p += optlen+1;
memcpy(p, retbuf, retlen+1);
@ -1398,12 +1429,12 @@ static int rewrite_macros(char macro, char *output)
/*
* Modify the filename, if applicable. If it returns NULL, deny the access.
*/
static char *rewrite_access(char *filename, int mode, const char **msg)
static char *rewrite_access(const struct formats *pf, char *filename,
int mode, int af, const char **msg)
{
if (rewrite_rules) {
char *newname =
rewrite_string(filename, rewrite_rules,
mode != RRQ ? 'P' : 'G',
rewrite_string(pf, filename, rewrite_rules, mode, af,
rewrite_macros, msg);
filename = newname;
}
@ -1411,15 +1442,17 @@ static char *rewrite_access(char *filename, int mode, const char **msg)
}
#else
static char *rewrite_access(char *filename, int mode, const char **msg)
static char *rewrite_access(const struct formats *pf, char *filename,
int mode, int af, const char **msg)
{
(void)pf;
(void)mode; /* Avoid warning */
(void)msg;
(void)af;
return filename;
}
#endif
static FILE *file;
/*
* Validate file access. Since we
* have no uid or gid, for now require
@ -1644,17 +1677,21 @@ static void tftp_sendfile(const struct formats *pf, struct tftphdr *oap, int oac
/*
* Receive a file.
*/
static void tftp_recvfile(const struct formats *pf, struct tftphdr *oap, int oacklen)
static void tftp_recvfile(const struct formats *pf,
struct tftphdr *oack, int oacklen)
{
struct tftphdr *dp;
int n, size;
/* These are "static" to avoid longjmp funnies */
static struct tftphdr *oap;
static struct tftphdr *ap; /* ack buffer */
static u_short block = 0;
static int acksize;
u_short dp_opcode, dp_block;
unsigned long r_timeout;
oap = oack;
dp = w_init();
do {
timeout = rexmtval;

View file

@ -23,4 +23,13 @@ char *tfstrdup(const char *);
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

View file

@ -1 +1 @@
5.2
5.3