Compare commits

...

100 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
H. Peter Anvin
b9708e2201 Update version for release 5.2 2011-12-11 14:13:52 -08:00
H. Peter Anvin
f08a34ede1 CHANGES: document is address local fix
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2011-12-11 14:13:13 -08:00
H. Peter Anvin
c6d2c36b1a tftpd: the "is this address local" algorithm no longer works on Linux
Linux no longer tries to match the local address with the remote one,
so address_is_local() fails.  Try instead to simply see if we can bind
to the explicit address.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2011-12-08 21:48:06 -08:00
H. Peter Anvin
badf05140d spec: BuildPreReq -> BuildRequires; need -devel package
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2011-06-22 16:32:56 -07:00
H. Peter Anvin
f6a1282fec Update version for release 5.1 2011-06-22 16:29:59 -07:00
H. Peter Anvin
464be3090b tftpd: add Intel copyright header
Part of my Intel job now...

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2011-06-22 16:28:38 -07:00
H. Peter Anvin
bd250a597f CHANGES: Document bug fix
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2011-06-22 16:27:48 -07:00
H. Peter Anvin
f3035c45bc tftpd: simplify option parsing
Simplify the option parsing to make use of the fact that all the
options we support are integer options.  This fixes a buffer overflow
in the utimeout option.

Reported-by: Timo Warns <warns@pre-sense.de>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
2011-06-10 11:49:00 -07:00
H. Peter Anvin
2864d83fea tftpd: try to handle duplicate WRQ packets
Duplicate WRQ packets can really hurt, since they end up accessing the
same file.  This attempts to lock the file, which should work for the
case where a correctly implemented TFTP stack uses the same session ID
(port number) for each retry; in any other case they look like
multiple sessions to the same file and it is a crapshoot if we end up
with the correct one.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2011-05-12 19:16:17 -07:00
H. Peter Anvin
05ffcecaa8 Merge remote-tracking branch 'origin/master' 2011-05-09 21:09:18 -07:00
H. Peter Anvin
ad5aab9281 tftpd: constipate struct formats
struct formats should be static const; make it so and mark all users
const.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2011-05-05 10:11:59 -07:00
H. Peter Anvin
0b5732e263 remap: change the mode argument from a boolean to a character
Instead of taking a boolean value for get/put, pass a character; this
allows us to extend the number of possibilities in the future.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2011-05-05 10:08:53 -07:00
H. Peter Anvin
915f62f5c7 CHANGES: document wraparound fix 2010-09-20 17:49:10 -07:00
Tim Newsome
aeb1c31bae tftpd: Don't resend the OACK packet on block number wrap
When uploading a file that is larger than 32MB (with standard block
size), the block number will roll over. If it rolls over to 0, the code
mistakenly resends the option ack frame instead of acknowledging the 0
data block. This change fixes that behavior.
2010-09-20 17:48:33 -07:00
H. Peter Anvin
a63534e6e6 recvfrom: fix the type of the fallthrough case
If we can't figure out the source address, we have the "fall on our
face" version of myrecvfrom(); make sure its prototype matches.  This
handles building on machines where sockaddr_t != int and yet there is
no way to get the source address.  This apparently affects at least
one version of Solaris.

Reported-by: Georg Schwarz <georg.schwarz@freenet.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-12-11 16:07:10 -08:00
H. Peter Anvin
e7a7b19483 Update CHANGES for future 5.1 release
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-09-14 14:46:34 -07:00
H. Peter Anvin
ab382980ae Fix man page formatting 2009-09-14 14:44:54 -07:00
Ferenc Wagner
c86f82532e Implement the --pidfile option
Setting the umask moved later, right before entering the select loop,
so that it does not affect the permissions of the pid file.

Signed-off-by: Ferenc Wagner <wferi@niif.hu>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-09-14 14:41:13 -07:00
Ferenc Wagner
5a27e30ec2 Untabify tftpd.c
Signed-off-by: Ferenc Wagner <wferi@niif.hu>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-09-14 14:41:10 -07:00
Ferenc Wagner
85029077c8 Fix comment typo
Signed-off-by: Ferenc Wagner <wferi@niif.hu>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-09-14 14:41:07 -07:00
Ferenc Wagner
3f2bc9833d Ensure that the log socket is available for the child
Just in case syslog has been restarted, bounce the log socket before
the chroot.

Signed-off-by: Ferenc Wagner <wferi@niif.hu>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-09-14 14:41:02 -07:00
Ferenc Wagner
44c98cf8b6 Downcase datarootdir, so mandir et al. find their defaults
mandir et all uses $(datarootdir), not $(DATAROOTDIR)

Signed-off-by: Ferenc Wagner <wferi@niif.hu>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2009-09-14 14:40:17 -07:00
H. Peter Anvin
338648870e tftpd.8: we're no longer limited to IPv4 2009-02-24 16:27:27 -08:00
H. Peter Anvin
9ba4e118d2 tftpd.c: update copyright notice 2009-02-24 16:26:16 -08:00
H. Peter Anvin
2f3a775f85 autogen.sh: just do "make autoconf"
We require GNU make, so we can have autoconf built from inside the
Makefile.  Just make autogen.sh do "make autoconf" for convenience.
2009-02-16 14:53:50 -08:00
H. Peter Anvin
e7a5fc2d68 Update CHANGES for 5.0 release 2009-02-16 14:51:22 -08:00
H. Peter Anvin
878b024bcd Update version for release 5.0 2009-02-16 14:49:43 -08:00
Florian Lohoff
acf818880c tftpd: correctly disable PMTU discovery in standalone mode
Use the correct file descriptors so we correctly turn off PMTU.
2009-02-16 14:40:01 -08:00
H. Peter Anvin
932277c9a5 tftpd: implement the "rollover" option
Implement the "rollover" option, to set the rollover block number to
anything other than zero.  Apparently some idiots have gotten the idea
that block numbers should roll over to one, rather than zero.
2009-02-02 15:14:27 -08:00
H. Peter Anvin
fcdd859a75 autogen.sh: script to run relevant autotools 2009-02-02 15:14:05 -08:00
Georg Schwarz
b0a2a17864 Cast IPv6 address from SOCKADDR_P() to struct in6_addr *
We need to cast IPv6 addresses from SOCKADDR_P() to struct in6_addr *
on some platforms, including at least MacOS X.
2008-11-14 08:37:49 -08:00
H. Peter Anvin
12996491c2 Document getaddrinfo() workaround. 2008-11-14 08:32:29 -08:00
H. Peter Anvin
dd50e8b75c If AI_CANONNAME or AI_ADDRCONFIG don't exist, set them to zero
If the AI_CANONNAME or AI_ADDRCONFIG flags are missing, just set them
to zero.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-11-14 08:31:03 -08:00
H. Peter Anvin
920b99dfee Update version for release 0.49 2008-10-20 15:08:31 -07:00
H. Peter Anvin
4f715da294 Update CHANGES 2008-10-20 15:07:59 -07:00
Роман Донченко
ac5f0ab996 Compilation of tftp-hpa's Git HEAD with no IPv6, and misc
This patch does two things:
a) makes tftp-hpa to compile on systems with no IPv6 support (there were
some IPv6 macros used unconditionally);
b) removes a stray binary character, which was annoying.
2008-10-20 15:06:24 -07:00
H. Peter Anvin
a1dfd6baf8 Support editline instead of readline
Support editline as an alternative to readline.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-08-09 21:14:45 -07:00
Sridhar Samudrala
740871b0f5 Fix numeric IPv6 address handling
The following patch sets additional hints to restrict the addresses
returned by getaddrinfo() to specify preferred socket type, protocol
and a flag to return only v4/v6 addresses based on the configured
addresses.

Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-08-09 20:58:19 -07:00
Karsten Keil
544abd789e Add error messages if address types mismatch
If a user does supply a IPv4 or IPv6 address
but force the other type with -4 or -6, give an error.
The patch also fix the special [::ffff:127.0.1]
address handling, it work now if you bind to this
address but only if you not force IPv6 only, it seems
that the kernel does not signal connections to a
IPv6 socket listen on [::ffff:127.0.0.1], if it was bound
IPv6 only.
I think we can live with it and do not need a special test
for this address.

Signed-off-by: Karsten Keil <kkeil@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-08-01 08:24:16 -07:00
Karsten Keil
18fd18bd5c Improve address type error handling
This patch detects numeric address types to avoid unnecessary
warnings/errors.  It also cleans up error printing to not print error
messages on stderr in the deamon case.

Signed-off-by: Karsten Keil <kkeil@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-31 11:48:18 -07:00
H. Peter Anvin
bdb90cf176 Add .gitignore file
Add .gitignore file so "git status" is actually useful.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-30 17:18:17 -07:00
H. Peter Anvin
e4d3083006 tftpd: switch to getopt_long()
Switch to using getopt_long(); include a version in case the platform
lacks it.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-30 17:16:00 -07:00
H. Peter Anvin
77fbfeebee Implement is_numeric_ipv6() as a state machine
Implement is_numeric_ipv6() as a state machine, so we can avoid
in-place modification.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-30 16:34:44 -07:00
H. Peter Anvin
0c6f7f86d3 tftpd: mark symbols static
Mark symbols not accessed from other files static.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-30 16:17:02 -07:00
H. Peter Anvin
7670c83e5a release.sh: remove Cogito
Remove Cogito use in favour of plain git; make sure the index is
clean.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-30 15:36:46 -07:00
Karsten Keil
cfb85d4dec Fix numeric IPv6 address handling
This patch fix a issue with numeric IPv6 addresses in the
tftpd -a address[:port] option.

Since IPv6 addresses use colon ':' in differnt counts itself, we cannot detect,
if the last colon is a seperator, so it is needed to put the IPv6 address into
square brackets, e.g. [2001:db8::1], so a optional port assignment is
unambiguous.
The patch also allows to specify numeric IPv6 addresses in other places enclosed
in [], but in these cases it accept these also without [].

Signed-off-by: Karsten Keil <kkeil@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-30 15:20:31 -07:00
H. Peter Anvin
c3a5c712e2 Allow the -4 option even in an IPv4-only configuration
Allow the -4 option even if IPv6 isn't compiled in.
2008-07-23 14:36:18 -04:00
H. Peter Anvin
4bdac0b536 Document changes for 0.49 2008-07-23 14:31:48 -04:00
Karsten Keil
28f22b6591 Add support for IPv6 in the server and client.
Add support for IPv6 in the server and client.
You can force the use of IPv4 or IPv6 only with new
-4 and -6 commandline options, if IPv6 support was compiled in.

Signed-off-by: Karsten Keil <kkeil@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-23 14:29:41 -04:00
Karsten Keil
7fe0fb941c IPv6 infrastructure support
Add autoconf rules to detect IPv6 availability and some of the neeeded
support functions. Add stubs for getaddrinfo and inet_ntop.
You can disable IPv6 at compile time with
./configure --without-ipv6

Signed-off-by: Karsten Keil <kkeil@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-23 14:24:19 -04:00
H. Peter Anvin
57ca281980 Remove more obsolete $Id$ tags
Additional $Id$ tags from the CVS era...
2008-07-22 15:07:24 -04:00
H. Peter Anvin
40e20cc4a5 Remove workaround for autoconf 2.52
Remove obsolete workaround for autoconf 2.52 -- we don't support that
version of autoconf anymore.
2008-07-22 14:53:30 -04:00
H. Peter Anvin
3e7043c50f Define DATAROOTDIR in MCONFIG.in to shut up autoconf
Shut up autoconf warning by defining DATAROOTDIR in MCONFIG.in.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2008-07-22 14:44:40 -04:00
H. Peter Anvin
50f22a7ad2 Remove long since obsolete ID tags 2008-07-08 17:30:27 -04:00
H. Peter Anvin
9f83475779 Formatting cleanup 2008-07-08 17:26:18 -04:00
H. Peter Anvin
cd22c6ea31 Formatting cleanup
Clean up line break
2008-07-08 17:24:11 -04:00
H. Peter Anvin
22accddda0 Reformat the source code
The source code was a mix of different styles; normalize on NASM
style; basically K&R style with 4 space indentation.
2008-07-08 17:14:44 -04:00
H. Peter Anvin
62533e7441 AC_USE_SYSTEM_EXTENSIONS is a 2.61 feature, not 2.59 2007-12-10 17:37:52 -08:00
H. Peter Anvin
bbb17208a9 Use autoconf features to deal with feature-test macros. 2007-10-03 17:41:38 -07:00
H. Peter Anvin
80f86e5a04 Get rid of $Id$ tags and update copyright dates 2007-01-30 16:01:24 -08:00
H. Peter Anvin
1f57b0edd5 Update version for release 2007-01-30 15:51:04 -08:00
H. Peter Anvin
0eacf8823f Document fixing -l -s. 2007-01-30 15:51:00 -08:00
H. Peter Anvin
c7ecc59f86 When running in secure mode (-s), we must not chdir while daemonizing
When running in secure mode (-s), we must not chdir while daemonizing.
Thanks to Adrian Urquhart for spotting this bug.
2007-01-30 15:38:04 -08:00
H. Peter Anvin
077eac1fd6 Update version for release 2007-01-27 11:11:27 -08:00
H. Peter Anvin
ecf79bc97f Document user-visible changes 2007-01-27 11:11:22 -08:00
H. Peter Anvin
d15a61abe6 Prototype cleanup; use "config.h" where appropriate 2007-01-15 01:20:41 -08:00
H. Peter Anvin
d9938a7d83 Add -L option to not daemonize process 2007-01-15 01:12:52 -08:00
H. Peter Anvin
059de7ce20 Use replacement library functions to daemonize, rather than #ifdef hell 2007-01-15 01:11:26 -08:00
Mike Frysinger
6124dcbe2d [patch] fix parallel building of tftp-hpa
if you try to build tftp-hpa in parallel, it may fail as the tftp and tftpd
subdirs may try to link before the libcommon.a has a chance to be generated
in the common subdir

trivial patch attached to address this
-mike
2007-01-13 10:24:27 -08:00
66 changed files with 5220 additions and 3588 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

21
.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
/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
*~
\#*

49
CHANGES
View file

@ -1,3 +1,52 @@
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.

View file

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

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
tftpd.build: lib.build
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 $@

View file

@ -1,7 +1,3 @@
$Id$
=======================================
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
by the tftpd effective user, specified via the -u option. This means

206
aclocal.m4 vendored
View file

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

@ -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]])])

83
autogen.sh Executable file
View file

@ -0,0 +1,83 @@
#!/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,8 +1,3 @@
/* 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.
@ -38,13 +33,6 @@
#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.
@ -58,127 +46,130 @@ static const char *rcsid UNUSED =
#include <sys/ioctl.h>
#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
int segsize = SEGSIZE; /* Default segsize */
int segsize = SEGSIZE; /* Default segsize */
struct bf {
int counter; /* size of data in buffer, or flag */
char buf[PKTSIZE]; /* room for data packet */
int counter; /* size of data in buffer, or flag */
char buf[PKTSIZE]; /* room for data packet */
} bfs[2];
/* Values for bf.counter */
/* 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 */
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) */
/* 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 */
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)
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;
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)
int readit(FILE * file, struct tftphdr **dpp, int convert)
{
struct bf *b;
struct bf *b;
bfs[current].counter = BF_FREE; /* free old one */
current = !current; /* "incr" current */
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;
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)
void read_ahead(FILE * file, int convert)
{
int i;
char *p;
int c;
struct bf *b;
struct tftphdr *dp;
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 */
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;
dp = (struct tftphdr *)b->buf;
if (convert == 0) {
b->counter = read(fileno(file), dp->th_data, segsize);
return;
}
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);
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)
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 */
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 */
}
/*
@ -187,52 +178,50 @@ writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
* 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)
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;
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 */
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;
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 (count <= 0)
return -1; /* nak logic? */
if (convert == 0)
return write(fileno(file), buf, count);
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;
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.
@ -244,69 +233,174 @@ skipit:
* when trace is active).
*/
int
synchnet(int f) /* socket to flush */
{
int pktcount = 0;
char rbuf[PKTSIZE];
struct sockaddr_in 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,
(struct sockaddr *)&from, &fromlen);
}
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;
return pktcount; /* Return packets drained */
}
while (1) {
notime.tv_sec = notime.tv_usec = 0;
FD_ZERO(&socketset);
FD_SET(f, &socketset);
int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int port_range_from, unsigned int port_range_to)
{
unsigned int port, firstport;
int port_range = 0;
if (select(f, &socketset, NULL, NULL, &notime) <= 0)
break; /* Nothing to read */
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 {
myaddr->sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *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;
/* Otherwise drain the packet */
pktcount++;
fromlen = sizeof(from);
(void)recvfrom(f, rbuf, sizeof(rbuf), 0,
&from.sa, &fromlen);
}
port++;
if ( port > port_range_to )
port = port_range_from;
} while ( port != firstport );
return -1;
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

View file

@ -1,8 +1,3 @@
/* $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
* The Regents of the University of California. All rights reserved.
@ -34,8 +29,6 @@
* 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.
*
* @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
*/
/*
@ -47,33 +40,82 @@
#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 *r_init(void);
void read_ahead(FILE *, int);
int readit(FILE *, struct tftphdr **, int);
void read_ahead(FILE *, int);
int readit(FILE *, struct tftphdr **, int);
int synchnet(int);
int synchnet(int);
struct tftphdr *w_init(void);
int write_behind(FILE *, int);
int writeit(FILE *, struct tftphdr **, int, int);
int write_behind(FILE *, int);
int writeit(FILE *, struct tftphdr **, int, int);
extern int segsize;
#define MAX_SEGSIZE 65464
/*
* Prototype for xmalloc/xstrdup
*/
extern void *xmalloc(size_t);
extern char *xstrdup(const char *);
/*
* Signal-related stuff
*/
void (*bsd_signal(int, void (*)(int)))(int);
int pick_port_bind(int sockfd, union sock_addr *myaddr,
unsigned int from, unsigned int to);
#endif
int pick_port_bind(int sockfd, struct sockaddr_in *myaddr, unsigned int from, unsigned int to);

129
config.h
View file

@ -1,13 +1,12 @@
/* -*- 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
* http://www.openbsd.org/.
*
* ----------------------------------------------------------------------- */
/* $Id$ */
/*
* config.h
@ -18,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>
@ -33,28 +43,13 @@
#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
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#ifdef HAVE_INTTYPES_H
#ifdef INTTYPES_H_IS_SANE
@ -74,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
@ -93,9 +81,6 @@
#include <fcntl.h>
#endif
#include <errno.h>
#include <signal.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#else
@ -107,12 +92,14 @@
#endif
#endif
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_GETOPT_H
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
extern char *optarg;
extern int optind, opterr, optopt;
#include "lib/getopt.h"
#endif
/* Test for EAGAIN/EWOULDBLOCK */
@ -128,10 +115,10 @@ extern int optind, opterr, optopt;
/* 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
@ -266,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 */
@ -287,6 +272,72 @@ typedef int socklen_t;
#define EOPTNEG 8
#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 */
#include "version.h"

View file

@ -1,13 +1,12 @@
## -*- makefile -*- ------------------------------------------------------
##
## Copyright 2001 H. Peter Anvin - All Rights Reserved
## Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
##
## This program is free software available under the same license
## as the "OpenBSD" operating system, distributed at
## http://www.openbsd.org/.
##
## -----------------------------------------------------------------------
## $Id$
##
## MCONFIG.in
@ -32,6 +31,9 @@ MANDIR = @mandir@
# System binaries
SBINDIR = @sbindir@
# Data root directory
datarootdir = @datarootdir@
# Binary suffixes
O = @OBJEXT@
X = @EXEEXT@

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,270 +0,0 @@
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
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_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_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 = ..
-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,32 +0,0 @@
/*
* 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;
}

36
lib/daemon.c Normal file
View file

@ -0,0 +1,36 @@
/*
* 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
}

23
lib/dup2.c Normal file
View file

@ -0,0 +1,23 @@
/*
* 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;
}

121
lib/getaddrinfo.c Normal file
View file

@ -0,0 +1,121 @@
/*
* 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;
}

23
lib/getopt.h Normal file
View file

@ -0,0 +1,23 @@
#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 */

150
lib/getopt_long.c Normal file
View file

@ -0,0 +1,150 @@
/*
* 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 '?';
}
}

52
lib/inet_ntop.c Normal file
View file

@ -0,0 +1,52 @@
/*
* 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,17 +5,16 @@
*
*/
#include <stdlib.h>
#include <stdio.h>
#include "config.h"
void *xmalloc(size_t size)
{
void *p = malloc(size);
void *p = malloc(size);
if ( !p ) {
fprintf(stderr, "Out of memory!\n");
exit(128);
}
if (!p) {
fprintf(stderr, "Out of memory!\n");
exit(128);
}
return p;
return p;
}

View file

@ -5,18 +5,16 @@
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "config.h"
char *xstrdup(const char *s)
{
char *p = strdup(s);
char *p = strdup(s);
if ( !p ) {
fprintf(stderr, "Out of memory!\n");
exit(128);
}
if (!p) {
fprintf(stderr, "Out of memory!\n");
exit(128);
}
return p;
return p;
}

View file

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

View file

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

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

@ -1,8 +1,3 @@
/* $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
* The Regents of the University of California. All rights reserved.
@ -34,14 +29,15 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
*/
#ifndef RECVFILE_H
#define RECVFILE_H
#ifndef EXTERN_H
#define EXTERN_H
void tftp_recvfile (int, const char *, const char *);
void tftp_sendfile (int, const char *, const char *);
#include "config.h"
void tftp_recvfile(int, const char *, const char *);
void tftp_sendfile(int, const char *, const char *);
extern sigjmp_buf toplevel;
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
.\" -*- nroff -*- --------------------------------------------------------- *
.\" $Id$
.\"
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@ -31,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\"----------------------------------------------------------------------- */
.TH TFTP 1 "12 December 2006" "tftp-hpa @@VERSION@@" "User's Manual"
.TH TFTP 1 "23 July 2008" "tftp-hpa @@VERSION@@" "User's Manual"
.SH NAME
.B tftp
\- IPv4 Trivial File Transfer Protocol client
@ -43,7 +42,7 @@
.br
.SH DESCRIPTION
.B tftp
is a client for the IPv4 Trivial file Transfer Protocol, which can be
is a client for the Trivial file Transfer Protocol, which can be
used to transfer files to and from remote machines, including some
very minimalistic, usually embedded, systems. The remote
.I host
@ -56,6 +55,12 @@ as the default host for future transfers (see the
command below.)
.SH OPTIONS
.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
Execute \fIcommand\fP as if it had been entered on the tftp prompt.
Must be specified last on the command line.

View file

@ -1,6 +1,3 @@
/* $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
* The Regents of the University of California. All rights reserved.
@ -36,32 +33,22 @@
#include "common/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
*/
#include "extern.h"
extern struct sockaddr_in peeraddr; /* filled in by main */
extern int f; /* the opened socket */
extern int trace;
extern int verbose;
extern int rexmtval;
extern int maxtimeout;
extern union sock_addr peeraddr; /* filled in by main */
extern int f; /* the opened socket */
extern int trace;
extern int verbose;
extern int rexmtval;
extern int maxtimeout;
#define PKTSIZE SEGSIZE+4
char ackbuf[PKTSIZE];
int timeout;
sigjmp_buf toplevel;
sigjmp_buf timeoutbuf;
char ackbuf[PKTSIZE];
int timeout;
static sigjmp_buf timeoutbuf;
static void nak(int, const char *);
static int makerequest(int, const char *, struct tftphdr *, const char *);
@ -74,251 +61,247 @@ static void tpacket(const char *, struct tftphdr *, int);
/*
* 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 *dp;
int n;
volatile int is_request;
volatile u_short block;
volatile int size, convert;
volatile off_t amount;
struct sockaddr_in from;
socklen_t fromlen;
FILE *file;
u_short ap_opcode, ap_block;
struct tftphdr *ap; /* data and ack packets */
struct tftphdr *dp;
int n;
volatile int is_request;
volatile u_short block;
volatile int size, convert;
volatile off_t amount;
union sock_addr from;
socklen_t fromlen;
FILE *file;
u_short ap_opcode, ap_block;
startclock(); /* start stat's clock */
dp = r_init(); /* reset fillbuf/read-ahead code */
ap = (struct tftphdr *)ackbuf;
convert = !strcmp(mode, "netascii");
file = fdopen(fd, convert ? "rt" : "rb");
block = 0;
is_request = 1; /* First packet is the actual WRQ */
amount = 0;
startclock(); /* start stat's clock */
dp = r_init(); /* reset fillbuf/read-ahead code */
ap = (struct tftphdr *)ackbuf;
convert = !strcmp(mode, "netascii");
file = fdopen(fd, convert ? "rt" : "rb");
block = 0;
is_request = 1; /* First packet is the actual WRQ */
amount = 0;
bsd_signal(SIGALRM, timer);
do {
if (is_request) {
size = makerequest(WRQ, name, dp, mode) - 4;
} else {
/* size = read(fd, dp->th_data, SEGSIZE); */
size = readit(file, &dp, convert);
if (size < 0) {
nak(errno + 100, NULL);
break;
}
dp->th_opcode = htons((u_short)DATA);
dp->th_block = htons((u_short)block);
}
timeout = 0;
(void) sigsetjmp(timeoutbuf,1);
tftp_signal(SIGALRM, timer, 0);
do {
if (is_request) {
size = makerequest(WRQ, name, dp, mode) - 4;
} else {
/* size = read(fd, dp->th_data, SEGSIZE); */
size = readit(file, &dp, convert);
if (size < 0) {
nak(errno + 100, NULL);
break;
}
dp->th_opcode = htons((u_short) DATA);
dp->th_block = htons((u_short) block);
}
timeout = 0;
(void)sigsetjmp(timeoutbuf, 1);
if (trace)
tpacket("sent", dp, size + 4);
n = sendto(f, dp, size + 4, 0,
(struct sockaddr *)&peeraddr, sizeof(peeraddr));
if (n != size + 4) {
perror("tftp: sendto");
goto abort;
}
read_ahead(file, convert);
for ( ; ; ) {
alarm(rexmtval);
do {
fromlen = sizeof(from);
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
(struct sockaddr *)&from, &fromlen);
} while (n <= 0);
alarm(0);
if (n < 0) {
perror("tftp: recvfrom");
goto abort;
}
peeraddr.sin_port = from.sin_port; /* added */
if (trace)
tpacket("received", ap, n);
/* should verify packet came from server */
ap_opcode = ntohs((u_short)ap->th_opcode);
ap_block = ntohs((u_short)ap->th_block);
if (ap_opcode == ERROR) {
printf("Error code %d: %s\n", ap_block,
ap->th_msg);
goto abort;
}
if (ap_opcode == ACK) {
int j;
if (trace)
tpacket("sent", dp, size + 4);
n = sendto(f, dp, size + 4, 0,
&peeraddr.sa, SOCKLEN(&peeraddr));
if (n != size + 4) {
perror("tftp: sendto");
goto abort;
}
read_ahead(file, convert);
for (;;) {
alarm(rexmtval);
do {
fromlen = sizeof(from);
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
&from.sa, &fromlen);
} while (n <= 0);
alarm(0);
if (n < 0) {
perror("tftp: recvfrom");
goto abort;
}
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */
if (trace)
tpacket("received", ap, n);
/* should verify packet came from server */
ap_opcode = ntohs((u_short) ap->th_opcode);
ap_block = ntohs((u_short) ap->th_block);
if (ap_opcode == ERROR) {
printf("Error code %d: %s\n", ap_block, ap->th_msg);
goto abort;
}
if (ap_opcode == ACK) {
int j;
if (ap_block == block) {
break;
}
/* On an error, try to synchronize
* both sides.
*/
j = synchnet(f);
if (j && trace) {
printf("discarded %d packets\n",
j);
}
/*
* RFC1129/RFC1350: We MUST NOT re-send the DATA
* packet in response to an invalid ACK. Doing so
* would cause the Sorcerer's Apprentice bug.
*/
}
}
if ( !is_request )
amount += size;
is_request = 0;
block++;
} while (size == SEGSIZE || block == 1);
abort:
fclose(file);
stopclock();
if (amount > 0)
printstats("Sent", amount);
if (ap_block == block) {
break;
}
/* On an error, try to synchronize
* both sides.
*/
j = synchnet(f);
if (j && trace) {
printf("discarded %d packets\n", j);
}
/*
* RFC1129/RFC1350: We MUST NOT re-send the DATA
* packet in response to an invalid ACK. Doing so
* would cause the Sorcerer's Apprentice bug.
*/
}
}
if (!is_request)
amount += size;
is_request = 0;
block++;
} while (size == SEGSIZE || block == 1);
abort:
fclose(file);
stopclock();
if (amount > 0)
printstats("Sent", amount);
}
/*
* 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 *dp;
int n;
volatile u_short block;
volatile int size, firsttrip;
volatile unsigned long amount;
struct sockaddr_in from;
socklen_t fromlen;
FILE *file;
volatile int convert; /* true if converting crlf -> lf */
u_short dp_opcode, dp_block;
struct tftphdr *ap;
struct tftphdr *dp;
int n;
volatile u_short block;
volatile int size, firsttrip;
volatile unsigned long amount;
union sock_addr from;
socklen_t fromlen;
FILE *file;
volatile int convert; /* true if converting crlf -> lf */
u_short dp_opcode, dp_block;
startclock();
dp = w_init();
ap = (struct tftphdr *)ackbuf;
convert = !strcmp(mode, "netascii");
file = fdopen(fd, convert ?"wt":"wb");
block = 1;
firsttrip = 1;
amount = 0;
startclock();
dp = w_init();
ap = (struct tftphdr *)ackbuf;
convert = !strcmp(mode, "netascii");
file = fdopen(fd, convert ? "wt" : "wb");
block = 1;
firsttrip = 1;
amount = 0;
bsd_signal(SIGALRM, timer);
do {
if (firsttrip) {
size = makerequest(RRQ, name, ap, mode);
firsttrip = 0;
} else {
ap->th_opcode = htons((u_short)ACK);
ap->th_block = htons((u_short)block);
size = 4;
block++;
}
timeout = 0;
(void) sigsetjmp(timeoutbuf,1);
send_ack:
if (trace)
tpacket("sent", ap, size);
if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
sizeof(peeraddr)) != size) {
alarm(0);
perror("tftp: sendto");
goto abort;
}
write_behind(file, convert);
for ( ; ; ) {
alarm(rexmtval);
do {
fromlen = sizeof(from);
n = recvfrom(f, dp, PKTSIZE, 0,
(struct sockaddr *)&from, &fromlen);
} while (n <= 0);
alarm(0);
if (n < 0) {
perror("tftp: recvfrom");
goto abort;
}
peeraddr.sin_port = from.sin_port; /* added */
if (trace)
tpacket("received", dp, n);
/* should verify client address */
dp_opcode = ntohs((u_short)dp->th_opcode);
dp_block = ntohs((u_short)dp->th_block);
if (dp_opcode == ERROR) {
printf("Error code %d: %s\n", dp_block, dp->th_msg);
goto abort;
}
if (dp_opcode == DATA) {
int j;
tftp_signal(SIGALRM, timer, 0);
do {
if (firsttrip) {
size = makerequest(RRQ, name, ap, mode);
firsttrip = 0;
} else {
ap->th_opcode = htons((u_short) ACK);
ap->th_block = htons((u_short) block);
size = 4;
block++;
}
timeout = 0;
(void)sigsetjmp(timeoutbuf, 1);
send_ack:
if (trace)
tpacket("sent", ap, size);
if (sendto(f, ackbuf, size, 0, &peeraddr.sa,
SOCKLEN(&peeraddr)) != size) {
alarm(0);
perror("tftp: sendto");
goto abort;
}
write_behind(file, convert);
for (;;) {
alarm(rexmtval);
do {
fromlen = sizeof(from);
n = recvfrom(f, dp, PKTSIZE, 0,
&from.sa, &fromlen);
} while (n <= 0);
alarm(0);
if (n < 0) {
perror("tftp: recvfrom");
goto abort;
}
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */
if (trace)
tpacket("received", dp, n);
/* should verify client address */
dp_opcode = ntohs((u_short) dp->th_opcode);
dp_block = ntohs((u_short) dp->th_block);
if (dp_opcode == ERROR) {
printf("Error code %d: %s\n", dp_block, dp->th_msg);
goto abort;
}
if (dp_opcode == DATA) {
int j;
if (dp_block == block) {
break; /* have next packet */
}
/* On an error, try to synchronize
* both sides.
*/
j = synchnet(f);
if (j && trace) {
printf("discarded %d packets\n", j);
}
if (dp_block == (block-1)) {
goto send_ack; /* resend ack */
}
}
}
/* size = write(fd, dp->th_data, n - 4); */
size = writeit(file, &dp, n - 4, convert);
if (size < 0) {
nak(errno + 100, NULL);
break;
}
amount += size;
} while (size == SEGSIZE);
abort: /* ok to ack, since user */
ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
ap->th_block = htons((u_short)block);
(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
sizeof(peeraddr));
write_behind(file, convert); /* flush last buffer */
fclose(file);
stopclock();
if (amount > 0)
printstats("Received", amount);
if (dp_block == block) {
break; /* have next packet */
}
/* On an error, try to synchronize
* both sides.
*/
j = synchnet(f);
if (j && trace) {
printf("discarded %d packets\n", j);
}
if (dp_block == (block - 1)) {
goto send_ack; /* resend ack */
}
}
}
/* size = write(fd, dp->th_data, n - 4); */
size = writeit(file, &dp, n - 4, convert);
if (size < 0) {
nak(errno + 100, NULL);
break;
}
amount += size;
} while (size == SEGSIZE);
abort: /* ok to ack, since user */
ap->th_opcode = htons((u_short) ACK); /* has seen err msg */
ap->th_block = htons((u_short) block);
(void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
SOCKLEN(&peeraddr));
write_behind(file, convert); /* flush last buffer */
fclose(file);
stopclock();
if (amount > 0)
printstats("Received", amount);
}
static int
makerequest(int request, const char *name,
struct tftphdr *tp, const char *mode)
struct tftphdr *tp, const char *mode)
{
char *cp;
char *cp;
tp->th_opcode = htons((u_short)request);
cp = (char *) &(tp->th_stuff);
strcpy(cp, name);
cp += strlen(name);
*cp++ = '\0';
strcpy(cp, mode);
cp += strlen(mode);
*cp++ = '\0';
return (cp - (char *)tp);
tp->th_opcode = htons((u_short) request);
cp = (char *)&(tp->th_stuff);
strcpy(cp, name);
cp += strlen(name);
*cp++ = '\0';
strcpy(cp, mode);
cp += strlen(mode);
*cp++ = '\0';
return (cp - (char *)tp);
}
static const char * const errmsgs[] =
{
"Undefined error code", /* 0 - EUNDEF */
"File not found", /* 1 - ENOTFOUND */
"Access denied", /* 2 - EACCESS */
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
"Illegal TFTP operation", /* 4 - EBADOP */
"Unknown transfer ID", /* 5 - EBADID */
"File already exists", /* 6 - EEXISTS */
"No such user", /* 7 - ENOUSER */
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
static const char *const errmsgs[] = {
"Undefined error code", /* 0 - EUNDEF */
"File not found", /* 1 - ENOTFOUND */
"Access denied", /* 2 - EACCESS */
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
"Illegal TFTP operation", /* 4 - EBADOP */
"Unknown transfer ID", /* 5 - EBADID */
"File already exists", /* 6 - EEXISTS */
"No such user", /* 7 - ENOUSER */
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
};
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
/*
@ -327,121 +310,115 @@ static const char * const errmsgs[] =
* standard TFTP codes, or a UNIX errno
* offset by 100.
*/
static void
nak(int error, const char *msg)
static void nak(int error, const char *msg)
{
struct tftphdr *tp;
int length;
tp = (struct tftphdr *)ackbuf;
tp->th_opcode = htons((u_short)ERROR);
tp->th_code = htons((u_short)error);
struct tftphdr *tp;
int length;
if ( error >= 100 ) {
/* This is a Unix errno+100 */
if ( !msg )
msg = strerror(error - 100);
error = EUNDEF;
} else {
if ( (unsigned)error >= ERR_CNT )
error = EUNDEF;
if ( !msg )
msg = errmsgs[error];
}
tp = (struct tftphdr *)ackbuf;
tp->th_opcode = htons((u_short) ERROR);
tp->th_code = htons((u_short) error);
tp->th_code = htons((u_short)error);
if (error >= 100) {
/* This is a Unix errno+100 */
if (!msg)
msg = strerror(error - 100);
error = EUNDEF;
} else {
if ((unsigned)error >= ERR_CNT)
error = EUNDEF;
length = strlen(msg)+1;
memcpy(tp->th_msg, msg, length);
length += 4; /* Add space for header */
if (!msg)
msg = errmsgs[error];
}
if (trace)
tpacket("sent", tp, length);
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
sizeof(peeraddr)) != length)
perror("nak");
tp->th_code = htons((u_short) error);
length = strlen(msg) + 1;
memcpy(tp->th_msg, msg, length);
length += 4; /* Add space for header */
if (trace)
tpacket("sent", tp, length);
if (sendto(f, ackbuf, length, 0, &peeraddr.sa,
SOCKLEN(&peeraddr)) != length)
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[] =
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
char *cp, *file;
u_short op = ntohs((u_short)tp->th_opcode);
static const char *opcodes[] =
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
char *cp, *file;
u_short op = ntohs((u_short) tp->th_opcode);
if (op < RRQ || op > ERROR)
printf("%s opcode=%x ", s, op);
else
printf("%s %s ", s, opcodes[op]);
switch (op) {
if (op < RRQ || op > ERROR)
printf("%s opcode=%x ", s, op);
else
printf("%s %s ", s, opcodes[op]);
switch (op) {
case RRQ:
case WRQ:
n -= 2;
file = cp = (char *) &(tp->th_stuff);
cp = strchr(cp, '\0');
printf("<file=%s, mode=%s>\n", file, cp + 1);
break;
case RRQ:
case WRQ:
n -= 2;
file = cp = (char *)&(tp->th_stuff);
cp = strchr(cp, '\0');
printf("<file=%s, mode=%s>\n", file, cp + 1);
break;
case DATA:
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
break;
case DATA:
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
break;
case ACK:
printf("<block=%d>\n", ntohs(tp->th_block));
break;
case ACK:
printf("<block=%d>\n", ntohs(tp->th_block));
break;
case ERROR:
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
break;
}
case ERROR:
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
break;
}
}
struct timeval tstart;
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;
delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) -
(tstart.tv_sec+(tstart.tv_usec/100000.0));
if (verbose) {
printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
printf(" [%.0f bit/s]", (amount*8.)/delta);
putchar('\n');
}
delta = (tstop.tv_sec + (tstop.tv_usec / 100000.0)) -
(tstart.tv_sec + (tstart.tv_usec / 100000.0));
if (verbose) {
printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
printf(" [%.0f bit/s]", (amount * 8.) / delta);
putchar('\n');
}
}
static void
timer(int sig)
static void timer(int sig)
{
int save_errno = errno;
int save_errno = errno;
(void)sig; /* Shut up unused warning */
(void)sig; /* Shut up unused warning */
timeout += rexmtval;
if (timeout >= maxtimeout) {
printf("Transfer timed out.\n");
errno = save_errno;
siglongjmp(toplevel, -1);
}
errno = save_errno;
siglongjmp(timeoutbuf, 1);
timeout += rexmtval;
if (timeout >= maxtimeout) {
printf("Transfer timed out.\n");
errno = save_errno;
siglongjmp(toplevel, -1);
}
errno = save_errno;
siglongjmp(timeoutbuf, 1);
}

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

@ -1,7 +1,6 @@
/* $Id$ */
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 H. Peter Anvin - All Rights Reserved
*
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at
@ -15,27 +14,19 @@
* Minor help routines.
*/
#include "config.h" /* Must be included first! */
#include "config.h" /* Must be included first! */
#include <syslog.h>
#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) ) {
syslog(LOG_ERR, "sigaction: %m");
exit(EX_OSERR);
}
if (tftp_signal(signum, handler, flags)) {
syslog(LOG_ERR, "sigaction: %m");
exit(EX_OSERR);
}
}
/*
@ -43,14 +34,14 @@ void set_signal(int signum, void (*handler)(int), int flags)
*/
void *tfmalloc(size_t size)
{
void *p = malloc(size);
void *p = malloc(size);
if ( !p ) {
syslog(LOG_ERR, "malloc: %m");
exit(EX_OSERR);
}
if (!p) {
syslog(LOG_ERR, "malloc: %m");
exit(EX_OSERR);
}
return p;
return p;
}
/*
@ -58,13 +49,12 @@ void *tfmalloc(size_t size)
*/
char *tfstrdup(const char *str)
{
char *p = strdup(str);
char *p = strdup(str);
if ( !p ) {
syslog(LOG_ERR, "strdup: %m");
exit(EX_OSERR);
}
if (!p) {
syslog(LOG_ERR, "strdup: %m");
exit(EX_OSERR);
}
return p;
return p;
}

View file

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------- *
*
*
* Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
@ -17,28 +17,30 @@
*
*/
#include "config.h" /* Must be included first! */
#include "recvfrom.h"
#include "config.h" /* Must be included first! */
#include "common/tftpsubs.h"
#include "recvfrom.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
#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 {
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
};
# else
# undef IP_PKTINFO /* No definition, no way to get it */
# undef IP_PKTINFO /* No definition, no way to get it */
# endif
# endif
#endif
@ -51,147 +53,245 @@ struct in_pktinfo {
#endif
/*
* Check to see if this is a valid local address. If so, we should
* end up having the same local and remote address when trying to
* bind to it.
* Check to see if this is a valid local address, meaning that we can
* legally bind to it.
*/
static int address_is_local(const struct sockaddr_in *addr)
static int address_is_local(const union sock_addr *addr)
{
struct sockaddr_in sin;
int sockfd = -1;
int e;
int rv = 0;
socklen_t addrlen;
union sock_addr sa1, sa2;
int sockfd = -1;
int e;
int rv = 0;
socklen_t addrlen;
/* Multicast or universal broadcast address? */
if (ntohl(addr->sin_addr.s_addr) >= (224UL << 24))
return 0;
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
goto err;
if (connect(sockfd, (const struct sockaddr *)addr, sizeof *addr))
goto err;
addrlen = sizeof sin;
if (getsockname(sockfd, (struct sockaddr *)&sin, &addrlen))
goto err;
rv = sin.sin_addr.s_addr == addr->sin_addr.s_addr;
err:
e = errno;
if (sockfd >= 0)
close(sockfd);
errno = e;
return rv;
}
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen,
struct sockaddr_in *myaddr)
{
struct msghdr msg;
struct iovec iov;
int n;
struct cmsghdr *cmptr;
union {
struct cmsghdr cm;
#ifdef IP_PKTINFO
char control[CMSG_SPACE(sizeof(struct in_addr)) +
CMSG_SPACE(sizeof(struct in_pktinfo))];
#else
char control[CMSG_SPACE(sizeof(struct in_addr))];
#endif
} control_un;
int on = 1;
#ifdef IP_PKTINFO
struct in_pktinfo pktinfo;
#endif
/* Try to enable getting the return address */
#ifdef IP_RECVDSTADDR
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
#endif
#ifdef IP_PKTINFO
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
#endif
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
msg.msg_flags = 0;
msg.msg_name = from;
msg.msg_namelen = *fromlen;
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if ( (n = recvmsg(s, &msg, flags)) < 0 )
return n; /* Error */
*fromlen = msg.msg_namelen;
if ( myaddr ) {
bzero(myaddr, sizeof(struct sockaddr_in));
myaddr->sin_family = AF_INET;
if ( msg.msg_controllen < sizeof(struct cmsghdr) ||
(msg.msg_flags & MSG_CTRUNC) )
return n; /* No information available */
for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ;
cmptr = CMSG_NXTHDR(&msg, cmptr) ) {
#ifdef IP_RECVDSTADDR
if ( cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVDSTADDR ) {
memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr),
sizeof(struct in_addr));
}
#endif
#ifdef IP_PKTINFO
if ( cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_PKTINFO ) {
memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo));
memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr));
}
#endif
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;
/* If the address is not a valid local address, then bind to any address... */
if (address_is_local(myaddr) != 1)
myaddr->sin_addr.s_addr = INADDR_ANY;
sockfd = socket(sa1.sa.sa_family, SOCK_DGRAM, 0);
if (sockfd < 0)
goto err;
return n;
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;
}
#else /* pointless... */
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, int *fromlen,
struct sockaddr_in *myaddr)
union sock_addr *from, union sock_addr *myaddr)
{
/* There is no way we can get the local address, fudge it */
struct msghdr msg;
struct iovec iov;
int n;
struct cmsghdr *cmptr;
union {
struct cmsghdr cm;
#ifdef IP_PKTINFO
char control[CMSG_SPACE(sizeof(struct in_addr)) +
CMSG_SPACE(sizeof(struct in_pktinfo))];
#else
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
} control_un;
int on = 1;
#ifdef IP_PKTINFO
struct in_pktinfo pktinfo;
#endif
#ifdef HAVE_STRUCT_IN6_PKTINFO
struct in6_pktinfo pktinfo6;
#endif
bzero(myaddr, sizeof(struct sockaddr_in));
myaddr->sin_family = AF_INET;
/* Try to enable getting the return address */
#ifdef IP_RECVDSTADDR
if (from->sa.sa_family == AF_INET)
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
#endif
#ifdef IP_PKTINFO
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.sa_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
#endif
#endif
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un);
msg.msg_flags = 0;
myaddr->sin_port = htons(IPPORT_TFTP);
bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr));
msg.msg_name = &from->sa;
msg.msg_namelen = sizeof(*from);
iov.iov_base = buf;
iov.iov_len = len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
return recvfrom(s,buf,len,flags,from,fromlen);
if ((n = recvmsg(s, &msg, flags)) < 0)
return n; /* Error */
if (myaddr) {
bzero(myaddr, sizeof(*myaddr));
myaddr->sa.sa_family = from->sa.sa_family;
if (msg.msg_controllen < sizeof(struct cmsghdr) ||
(msg.msg_flags & MSG_CTRUNC))
return n; /* No information available */
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
cmptr = CMSG_NXTHDR(&msg, cmptr)) {
if (from->sa.sa_family == AF_INET) {
myaddr->sa.sa_family = AF_INET;
#ifdef IP_RECVDSTADDR
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_RECVDSTADDR) {
memcpy(&myaddr->si.sin_addr, CMSG_DATA(cmptr),
sizeof(struct in_addr));
}
#endif
#ifdef IP_PKTINFO
if (cmptr->cmsg_level == IPPROTO_IP &&
cmptr->cmsg_type == IP_PKTINFO) {
memcpy(&pktinfo, CMSG_DATA(cmptr),
sizeof(struct in_pktinfo));
memcpy(&myaddr->si.sin_addr, &pktinfo.ipi_addr,
sizeof(struct in_addr));
}
#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;
}
#else /* pointless... */
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
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.sa_family;
sa_set_port(myaddr, htons(IPPORT_TFTP));
return recvfrom(s, buf, len, flags, &from->sa, &fromlen);
}
#endif

View file

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------- *
*
*
* Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
@ -19,5 +19,4 @@
int
myrecvfrom(int s, void *buf, int len, unsigned int flags,
struct sockaddr *from, socklen_t *fromlen,
struct sockaddr_in *myaddr);
union sock_addr *from, union sock_addr *myaddr);

View file

@ -1,7 +1,6 @@
/* $Id$ */
/* ----------------------------------------------------------------------- *
*
* Copyright 2001-2004 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
@ -15,7 +14,7 @@
* Perform regular-expression based filename remapping.
*/
#include "config.h" /* Must be included first! */
#include "config.h" /* Must be included first! */
#include <ctype.h>
#include <syslog.h>
#include <regex.h>
@ -23,124 +22,172 @@
#include "tftpd.h"
#include "remap.h"
#define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
#define MAXLINE 16384 /* Truncate a line at this many bytes */
#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 */
#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */
#define RULE_EXIT 0x04 /* Exit 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_GETONLY 0x20 /* Applicable to GET only */
#define RULE_PUTONLY 0x40 /* Applicable to PUT only */
#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */
#define RULE_REWRITE 0x01 /* This is a rewrite rule */
#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */
#define RULE_EXIT 0x04 /* Exit 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_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;
regex_t rx;
const char *pattern;
struct rule *next;
int nrule;
unsigned int rule_flags;
regex_t rx;
const char *pattern;
};
static int xform_null(int c)
{
return c;
return c;
}
static int xform_toupper(int c)
{
return toupper(c);
return toupper(c);
}
static int xform_tolower(int c)
{
return tolower(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;
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;
if ( string ) {
memcpy(string, input, pmatch[0].rm_so);
string += pmatch[0].rm_so;
}
/* Transform matched section */
while ( *pattern ) {
mlen = 0;
if ( *pattern == '\\' && pattern[1] != '\0' ) {
char macro = pattern[1];
switch ( macro ) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = pattern[1] - '0';
if ( pmatch[n].rm_so != -1 ) {
mlen = pmatch[n].rm_eo - pmatch[n].rm_so;
len += mlen;
if ( string ) {
const char *p = input+pmatch[n].rm_so;
while ( mlen-- )
*string++ = xform(*p++);
}
}
break;
case 'L':
xform = xform_tolower;
break;
case 'U':
xform = xform_toupper;
break;
case 'E':
xform = xform_null;
break;
default:
if ( macrosub &&
(sublen = macrosub(macro, string)) >= 0 ) {
while ( sublen-- ) {
len++;
if ( string ) {
*string = xform(*string);
string++;
}
}
} else {
len++;
if ( string )
*string++ = xform(pattern[1]);
}
}
pattern += 2;
} else {
len++;
if ( string )
*string++ = xform(*pattern);
pattern++;
/* Get section before match; note pmatch[0] is the whole match */
endbytes = strlen(input) - pmatch[0].rm_eo;
len = start + pmatch[0].rm_so;
if (string) {
/* Copy the prefix before "start" as well! */
memcpy(string, ibuf, start + pmatch[0].rm_so);
string += start + pmatch[0].rm_so;
}
}
/* Copy section after match */
if ( string ) {
memcpy(string, input+pmatch[0].rm_eo, endbytes);
string[endbytes] = '\0';
}
/* Transform matched section */
while (*pattern) {
mlen = 0;
return len;
if (*pattern == '\\' && pattern[1] != '\0') {
char macro = pattern[1];
switch (macro) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
n = pattern[1] - '0';
if (pmatch[n].rm_so != -1) {
mlen = pmatch[n].rm_eo - pmatch[n].rm_so;
len += mlen;
if (string) {
const char *p = input + start + pmatch[n].rm_so;
while (mlen--)
*string++ = xform(*p++);
}
}
break;
case 'L':
xform = xform_tolower;
break;
case 'U':
xform = xform_toupper;
break;
case 'E':
xform = xform_null;
break;
default:
if (macrosub && (sublen = macrosub(macro, string)) >= 0) {
while (sublen--) {
len++;
if (string) {
*string = xform(*string);
string++;
}
}
} else {
len++;
if (string)
*string++ = xform(pattern[1]);
}
}
pattern += 2;
} else {
len++;
if (string)
*string++ = xform(*pattern);
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';
}
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);
}
/*
@ -150,277 +197,349 @@ static int genmatchstring(char *string, const char *pattern, const char *input,
*/
static int readescstring(char *buf, char **str)
{
char *p = *str;
int wasbs = 0, len = 0;
char *p = *str;
int wasbs = 0, len = 0;
while ( *p && isspace(*p) )
p++;
while (*p && isspace(*p))
p++;
if (!*p) {
*buf = '\0';
*str = p;
return 0;
}
while (*p) {
if (!wasbs && (isspace(*p) || *p == '#')) {
*buf = '\0';
*str = p;
return len;
}
/* Important: two backslashes leave us in the !wasbs state! */
wasbs = !wasbs && (*p == '\\');
*buf++ = *p++;
len++;
}
if ( ! *p ) {
*buf = '\0';
*str = p;
return 0;
}
while ( *p ) {
if ( !wasbs && (isspace(*p) || *p == '#') ) {
*buf = '\0';
*str = p;
return len;
}
/* Important: two backslashes leave us in the !wasbs state! */
wasbs = !wasbs && ( *p == '\\' );
*buf++ = *p++;
len++;
}
*buf = '\0';
*str = p;
return len;
return len;
}
/* Parse a line into a set of instructions */
static int parseline(char *line, struct rule *r, int lineno)
{
char buffer[MAXLINE];
char *p;
int rv;
int rxflags = REG_EXTENDED;
static int nrule;
char buffer[MAXLINE];
char *p;
int rv;
int rxflags = REG_EXTENDED;
static int nrule;
memset(r, 0, sizeof *r);
r->nrule = nrule;
memset(r, 0, sizeof *r);
r->nrule = nrule;
if ( !readescstring(buffer, &line) )
return 0; /* No rule found */
if (!readescstring(buffer, &line))
return 0; /* No rule found */
for ( p = buffer ; *p ; p++ ) {
switch(*p) {
case 'r':
r->rule_flags |= RULE_REWRITE;
break;
case 'g':
r->rule_flags |= RULE_GLOBAL;
break;
case 'e':
r->rule_flags |= RULE_EXIT;
break;
case 's':
r->rule_flags |= RULE_RESTART;
break;
case 'a':
r->rule_flags |= RULE_ABORT;
break;
case 'i':
rxflags |= REG_ICASE;
break;
case 'G':
r->rule_flags |= RULE_GETONLY;
break;
case 'P':
r->rule_flags |= RULE_PUTONLY;
break;
case '~':
r->rule_flags |= RULE_INVERSE;
break;
default:
syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",
buffer, lineno, *p);
return -1; /* Error */
break;
for (p = buffer; *p; p++) {
switch (*p) {
case 'r':
r->rule_flags |= RULE_REWRITE;
break;
case 'g':
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;
case 'a':
r->rule_flags |= RULE_ABORT;
break;
case 'i':
rxflags |= REG_ICASE;
break;
case '~':
r->rule_flags |= RULE_INVERSE;
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:
syslog(LOG_ERR,
"Remap command \"%s\" on line %d contains invalid char \"%c\"",
buffer, lineno, *p);
return -1; /* Error */
break;
}
}
}
/* RULE_GLOBAL only applies when RULE_REWRITE specified */
if ( !(r->rule_flags & RULE_REWRITE) )
r->rule_flags &= ~RULE_GLOBAL;
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);
}
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 */
}
/* Read and compile the regex */
if (!readescstring(buffer, &line)) {
syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);
return -1; /* Error */
}
/* Read and compile the regex */
if ( !readescstring(buffer, &line) ) {
syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);
return -1; /* Error */
}
if ((rv = regcomp(&r->rx, buffer, rxflags)) != 0) {
char errbuf[BUFSIZ];
regerror(rv, &r->rx, errbuf, BUFSIZ);
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno,
errbuf);
return -1; /* Error */
}
if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) {
char errbuf[BUFSIZ];
regerror(rv, &r->rx, errbuf, BUFSIZ);
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, errbuf);
return -1; /* Error */
}
/* Read the rewrite pattern, if any */
if (readescstring(buffer, &line)) {
r->pattern = tfstrdup(buffer);
} else {
r->pattern = "";
}
/* Read the rewrite pattern, if any */
if ( readescstring(buffer, &line) ) {
r->pattern = tfstrdup(buffer);
} else {
r->pattern = "";
}
nrule++;
return 1; /* Rule found */
nrule++;
return 1; /* Rule found */
}
/* Read a rule file */
struct rule *parserulefile(FILE *f)
struct rule *parserulefile(FILE * f)
{
char line[MAXLINE];
struct rule *first_rule = NULL;
struct rule **last_rule = &first_rule;
struct rule *this_rule = tfmalloc(sizeof(struct rule));
int rv;
int lineno = 0;
int err = 0;
char line[MAXLINE];
struct rule *first_rule = NULL;
struct rule **last_rule = &first_rule;
struct rule *this_rule = tfmalloc(sizeof(struct rule));
int rv;
int lineno = 0;
int err = 0;
while ( lineno++, fgets(line, MAXLINE, f) ) {
rv = parseline(line, this_rule, lineno);
if ( rv < 0 )
err = 1;
if ( rv > 0 ) {
*last_rule = this_rule;
last_rule = &this_rule->next;
this_rule = tfmalloc(sizeof(struct rule));
while (lineno++, fgets(line, MAXLINE, f)) {
rv = parseline(line, this_rule, lineno);
if (rv < 0)
err = 1;
if (rv > 0) {
*last_rule = this_rule;
last_rule = &this_rule->next;
this_rule = tfmalloc(sizeof(struct rule));
}
}
}
free(this_rule); /* Last one is always unused */
free(this_rule); /* Last one is always unused */
if ( err ) {
/* Bail on error, we have already logged an error message */
exit(EX_CONFIG);
}
if (err) {
/* Bail on error, we have already logged an error message */
exit(EX_CONFIG);
}
return first_rule;
return first_rule;
}
/* Destroy a rule file data structure */
void freerules(struct rule *r)
{
struct rule *next;
struct rule *next;
while ( r ) {
next = r->next;
while (r) {
next = r->next;
regfree(&r->rx);
regfree(&r->rx);
/* "" patterns aren't allocated by malloc() */
if ( r->pattern && *r->pattern )
free((void *)r->pattern);
free(r);
/* "" patterns aren't allocated by malloc() */
if (r->pattern && *r->pattern)
free((void *)r->pattern);
r = next;
}
free(r);
r = next;
}
}
/* Execute a rule set on a string; returns a malloc'd new string. */
char *rewrite_string(const char *input, const struct rule *rules,
int is_put, match_pattern_callback macrosub,
const char **errmsg)
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;
const struct rule *ruleptr = rules;
regmatch_t pmatch[10];
int len;
int was_match = 0;
int deadman = DEADMAN_MAX_STEPS;
char *current = tfstrdup(input);
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 matchsense;
int pmatches;
unsigned int bad_flags;
int ggoffset;
/* Default error */
*errmsg = "Remap table failure";
/* Default error */
*errmsg = "Remap table failure";
if ( verbosity >= 3 ) {
syslog(LOG_INFO, "remap: input: %s", current);
}
for ( ruleptr = rules ; ruleptr ; ruleptr = ruleptr->next ) {
if ( ((ruleptr->rule_flags & RULE_GETONLY) && is_put) ||
((ruleptr->rule_flags & RULE_PUTONLY) && !is_put) ) {
continue; /* Rule not applicable, try next */
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: input: %s", current);
}
if ( ! deadman-- ) {
syslog(LOG_WARNING, "remap: Breaking loop, input = %s, last = %s",
input, current);
free(current);
return NULL; /* Did not terminate! */
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) {
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 (!deadman--)
goto dead;
if (regexec(&ruleptr->rx, current, pmatches, pmatch, 0)
!= matchsense)
break; /* No match, break out of do loop */
/* Match on this rule */
was_match = 1;
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 */
genmatchstring(&newstr, ruleptr->pattern, current,
pmatch, macrosub, 0, NULL);
*errmsg = newstr;
} else {
*errmsg = NULL;
}
free(current);
return (NULL);
}
if (ruleptr->rule_flags & RULE_REWRITE) {
len = genmatchstring(&newstr, ruleptr->pattern, current,
pmatch, macrosub, 0, &ggoffset);
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;
}
}
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);
}
}
}
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 ( 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 ( 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);
}
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);
}
}
} 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;
if ( ruleptr->rule_flags & RULE_EXIT ) {
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);
}
}
if (verbosity >= 3) {
syslog(LOG_INFO, "remap: done");
}
}
return current;
if ( verbosity >= 3 ) {
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

@ -1,7 +1,6 @@
/* $Id$ */
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 H. Peter Anvin - All Rights Reserved
*
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
* as the "OpenBSD" operating system, distributed at
@ -27,7 +26,7 @@ struct rule;
macro character is passed as the first argument; the output buffer,
if any, is passed as the second argument. The function should return
the number of characters output, or -1 on failure. */
typedef int (*match_pattern_callback)(char, char *);
typedef int (*match_pattern_callback) (char, char *);
/* Read a rule file */
struct rule *parserulefile(FILE *);
@ -36,9 +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 *, int,
match_pattern_callback, const char **);
struct formats;
char *rewrite_string(const struct formats *, const char *,
const struct rule *, int, int,
match_pattern_callback, const char **);
#endif /* WITH_REGEX */
#endif /* TFTPD_REMAP_H */
/* Remapping deadman counter */
extern int deadman_max_steps;
#endif /* WITH_REGEX */
#endif /* TFTPD_REMAP_H */

View file

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

View file

@ -1,10 +1,9 @@
.\" -*- nroff -*- --------------------------------------------------------- *
.\" $Id$
.\"
.\"
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Copyright 2001 H. Peter Anvin - All Rights Reserved
.\" Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -31,17 +30,17 @@
.\" SUCH DAMAGE.
.\"
.\"----------------------------------------------------------------------- */
.TH TFTPD 8 "16 February 2006" "tftp-hpa @@VERSION@@" "System Manager's Manual"
.TH TFTPD 8 "7 June 2014" "tftp-hpa @@VERSION@@" "System Manager's Manual"
.SH NAME
.B tftpd
\- IPv4 Trivial File Transfer Protocol server
\- Trivial File Transfer Protocol server
.SH SYNOPSIS
.B in.tftpd
.RI [ options... ]
.I directory...
.SH DESCRIPTION
.B tftpd
is a server for the IPv4 Trivial File Transfer Protocol. The TFTP
is a server for the Trivial File Transfer Protocol. The TFTP
protocol is extensively used to support remote booting of diskless
devices. The server is normally started by
.BR inetd ,
@ -49,52 +48,70 @@ but can also run standalone.
.PP
.SH OPTIONS
.TP
.B \-l
\fB\-\-ipv4\fP, \fB\-4\fP
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
.BR inetd .
In listen mode, the
.B \-t
.B \-\-timeout
option is ignored, and the
.B \-a
.B \-\-address
option can be used to specify a specific local address or port to
listen to.
.TP
\fB\-a\fP \fI[address][:port]\fP
\fB\-\-foreground\fP, \fB\-L\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
.I address
and
.I port
to listen to when called with the
.B \-l
.B \-\-listen
or
.B \-\-foreground
option. The default is to listen to the
.I tftp
port specified in
.I /etc/services
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
.B \-c
\fB\-\-create\fP, \fB\-c\fP
Allow new files to be created. By default,
.B tftpd
will only allow upload of files that already exist. Files are created
with default permissions allowing anyone to read or write them, unless
the
.B \-p
.B \-\-permissive
or
.B \-U
.B \-\-umask
options are specified.
.TP
.B \-s
\fB\-\-secure\fP, \fB\-s\fP
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
security. When
.B \-s
.B \-\-secure
is specified, exactly one
.I directory
should be specified on the command line. The use of this option is
recommended for security as well as compatibility with some boot ROMs
which cannot be easily made to include a directory name in its request.
.TP
\fB\-u\fP \fIusername\fP
\fB\-\-user\fP \fIusername\fP, \fB\-u\fP \fIusername\fP
Specify the username which
.B tftpd
will run as; the default is "nobody". The user ID, group ID, and (if
@ -102,21 +119,26 @@ possible on the platform) the supplementary group IDs will be set to
the ones specified in the system permission database for this
username.
.TP
\fB\-U\fP \fIumask\fP
\fB\-\-umask\fP \fIumask\fP, \fB\-U\fP \fIumask\fP
Sets the \fIumask\fP for newly created files to the specified value.
The default is zero (anyone can read or write) if the
.B \-p
.B \-\-permissive
option is not specified, or inherited from the invoking process if
.B \-p
.B \-\-permissive
is specified.
.TP
.B \-p
\fB\-\-permissive\fP, \fB\-p\fP
Perform no additional permissions checks above the normal
system-provided access controls for the user specified via the
.B \-u
.B \-\-user
option.
.TP
\fB\-t\fP \fItimeout\fP
\fB\-\-pidfile\fP \fIpidfile\fP, \fB\-P\fP \fIpidfile\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
.B inetd
this specifies how long, in seconds, to wait for a second connection
@ -125,7 +147,7 @@ before terminating the server.
will then respawn the server when another request comes in. The
default is 900 (15 minutes.)
.TP
\fB\-T\fP \fItimeout\fP
\fB\-\-retransmit\fP \fItimeout, \fP\fB\-T\fP \fItimeout\fP
Determine the default timeout, in microseconds, before the first
packet is retransmitted. This can be modified by the client if the
.B timeout
@ -133,7 +155,7 @@ or
.B utimeout
option is negotiated. The default is 1000000 (1 second.)
.TP
\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
@ -141,16 +163,23 @@ 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
.B \-v
.\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 .
This flag can be specified multiple times for even higher verbosity.
.TP
\fB\-r\fP \fItftp-option\fP
\fB\-\-verbosity\fP \fIvalue\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
accepted.
.TP
\fB\-B\fP \fImax-block-size\fP
\fB\-\-blocksize\fP \fImax-block-size\fP, \fB\-B\fP \fImax-block-size\fP
Specifies the maximum permitted block size. The permitted range for
this parameter is from 512 to 65464. Some embedded clients request
large block sizes and yet do not handle fragmented packets correctly;
@ -159,11 +188,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,
on a standard Ethernet (MTU 1500) a value of 1468 is reasonable.
.TP
\fB\-R\fP \fIport:port\fP
\fB\-\-port-range\fP \fIport:port\fP, \fB\-R\fP \fIport:port\fP
Force the server port number (the Transaction ID) to be in the
specified range of port numbers.
.TP
.B \-V
\fB\-\-version\fP, \fB\-V\fP
Print the version number and configuration to standard output, then
exit gracefully.
.SH "RFC 2347 OPTION NEGOTIATION"
@ -198,9 +227,13 @@ Set the time before the server retransmits a packet, in seconds.
.TP
\fButimeout\fP (nonstandard)
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
The
.B \-r
.B \-\-refuse
option can be used to disable specific options; this may be necessary
to work around bugs in specific TFTP client implementations. For
example, some TFTP clients have been found to request the
@ -209,7 +242,7 @@ option, but crash with an error if they actually get the option
accepted by the server.
.SH "FILENAME REMAPPING"
The
.B \-m
.B \-\-map-file
option specifies a file which contains filename remapping rules. Each
non-comment line (comments begin with hash marks,
.BR # )
@ -241,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
@ -252,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.
@ -266,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
@ -289,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.
@ -324,17 +387,17 @@ The use of TFTP services does not require an account or password on
the server system. Due to the lack of authentication information,
.B tftpd
will allow only publicly readable files (o+r) to be accessed, unless the
.B \-p
.B \-\-permissive
option is specified. Files may be written only if they already exist
and are publicly writable, unless the
.B \-c
.B \-\-create
option is specified. Note that this extends the concept of ``public''
to include all users on all hosts that can be reached through the
network; this may not be appropriate on all systems, and its
implications should be considered before enabling TFTP service.
Typically, some kind of firewall or packet-filter solution should be
employed. If appropriately compiled (see the output of
.BR "in.tftpd \-V" )
.BR "in.tftpd \-\-version" )
.B tftpd
will query the
.BR hosts_access (5)
@ -344,7 +407,7 @@ and rely on firewalling or kernel-based packet filters instead.
.PP
The server should be set to run as the user with the lowest possible
privilege; please see the
.B \-u
.B \-\-user
flag. It is probably a good idea to set up a specific user account for
.BR tftpd ,
rather than letting it run as "nobody", to guard against privilege
@ -354,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 \-s
.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 ( \-m
.RB ( \-\-map-file
flag) support can be used to provide a limited amount of additional
access control.
.SH "CONFORMING TO"

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,5 @@
/* $Id$ */
/* ----------------------------------------------------------------------- *
*
*
* Copyright 2001 H. Peter Anvin - All Rights Reserved
*
* This program is free software available under the same license
@ -24,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 @@
0.46
5.3