v5.2
This commit is contained in:
commit
7db43a3e87
|
@ -0,0 +1,16 @@
|
||||||
|
/MCONFIG
|
||||||
|
/aconfig.h
|
||||||
|
/aconfig.h.in
|
||||||
|
/autom4te.cache
|
||||||
|
/config.log
|
||||||
|
/config.status
|
||||||
|
/configure
|
||||||
|
/version.h
|
||||||
|
/tftp/tftp
|
||||||
|
/tftpd/tftpd
|
||||||
|
*.1
|
||||||
|
*.8
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
*~
|
||||||
|
\#*
|
|
@ -0,0 +1,402 @@
|
||||||
|
Changes in 5.2:
|
||||||
|
Fix breakage on newer Linux when a single interface has
|
||||||
|
multiple IP addresses.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 5.1:
|
||||||
|
Add -P option to write a PID file. Patch by Ferenc Wagner.
|
||||||
|
|
||||||
|
Bounce the syslog socket in standalone mode, in case the
|
||||||
|
syslog daemon has been restarted. Patch by Ferenc Wagner.
|
||||||
|
|
||||||
|
Build fixes.
|
||||||
|
|
||||||
|
Fix handling of block number wraparound after a successful
|
||||||
|
options negotiation.
|
||||||
|
|
||||||
|
Fix a buffer overflow in option parsing.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 5.0:
|
||||||
|
Try to on platforms with getaddrinfo() without AI_ADDRCONFIG or
|
||||||
|
AI_CANONNAME.
|
||||||
|
|
||||||
|
Implement the "rollover" option, for clients which want block
|
||||||
|
number to rollover to anything other than zero.
|
||||||
|
|
||||||
|
Correctly disable PMTU in standalone mode. Patch by Florian
|
||||||
|
Lohoff.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.49:
|
||||||
|
Add IPv6 support. Patch by Karsten Keil.
|
||||||
|
|
||||||
|
Support systems with editline instead of readline.
|
||||||
|
|
||||||
|
Support long options in the server.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.48:
|
||||||
|
Unbreak -l -s in the server, which was broken in 0.47.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.47:
|
||||||
|
Add -L option to the server to run standalone without
|
||||||
|
detaching from the shell.
|
||||||
|
|
||||||
|
Parallel make fix.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.46:
|
||||||
|
Minor portability improvements.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.45:
|
||||||
|
Add -l (literal) option to the client, to override the special
|
||||||
|
treatment of the colon (:) character as a hostname separator.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.44:
|
||||||
|
Allow the client to specify a range of local port numbers,
|
||||||
|
just like the server can.
|
||||||
|
|
||||||
|
Fix sending SIGHUP to update the regular expression table.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.43:
|
||||||
|
Fix double-free error on ^c in client.
|
||||||
|
|
||||||
|
Try to deal with clients that send TFTP requests to broadcasts
|
||||||
|
(apparently some recent Sun boxes do this instead of using the
|
||||||
|
address told by DHCP. Bad Sun! Bad Sun!)
|
||||||
|
|
||||||
|
Portability fixes.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.42:
|
||||||
|
Try to disable path MTU discovery for TFTP connections (it's
|
||||||
|
useless anyway.)
|
||||||
|
|
||||||
|
Add a hack to allow the admin to specify a range of local port
|
||||||
|
numbers to use.
|
||||||
|
|
||||||
|
Fix local IP number handling on systems which present
|
||||||
|
IP_RECVDSTADDR in recvmsg().
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.41:
|
||||||
|
Fix bug by which patterns of the form \U\1 weren't converted
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.40.1:
|
||||||
|
Solaris build fix.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.40:
|
||||||
|
Fix bug which would cause "r" remapping rules to be
|
||||||
|
incorrectly rejected.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.39:
|
||||||
|
Support Perl-style \U...\E and \L...\E, as well as allow
|
||||||
|
matching rules to be inverted (execute if rule *doesn't*
|
||||||
|
match.)
|
||||||
|
|
||||||
|
Fix a timeout bug.
|
||||||
|
|
||||||
|
Add an RPM spec file.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.38:
|
||||||
|
Portability fixes.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.37:
|
||||||
|
Fix a pathology where a client sending ACKs for the wrong
|
||||||
|
packet can prevent proper retransmission.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.36:
|
||||||
|
Portability fixes.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.35:
|
||||||
|
Add an option to control the maximum value of blksize
|
||||||
|
negotiated.
|
||||||
|
|
||||||
|
Removed workaround for obsolete Cygwin problem.
|
||||||
|
|
||||||
|
Don't use getopt() -- the -c option doesn't work correctly
|
||||||
|
since it depends on the ordering of arguments and options. It
|
||||||
|
is now possible to do:
|
||||||
|
|
||||||
|
tftp -m binary hostname -c get filename
|
||||||
|
|
||||||
|
This was previous possible by doing:
|
||||||
|
|
||||||
|
tftp -m binary -c get hostname:filename
|
||||||
|
|
||||||
|
... but it seemed that was counterintuitive to people.
|
||||||
|
|
||||||
|
Somewhat improved configure scripts.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.34:
|
||||||
|
Additional Solaris gcc compiler bug workarounds; these
|
||||||
|
actually make the code somewhat cleaner.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.33:
|
||||||
|
Even better error messages.
|
||||||
|
|
||||||
|
Work around a suspect Solaris gcc bug.
|
||||||
|
|
||||||
|
Configuration fix: readline needs termcap.
|
||||||
|
|
||||||
|
Support running the tftp client from the command line. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
tftp -m binary -c get hostname:file
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.32:
|
||||||
|
Better error messages; including the capability to send a
|
||||||
|
custom error message to the client when hitting an "a" rule in
|
||||||
|
a remapping table.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.31:
|
||||||
|
Put in a check to make sure xinetd (in particular) doesn't
|
||||||
|
pass us an IPv6 socket.
|
||||||
|
|
||||||
|
Fix some problems related to timeout negotiation.
|
||||||
|
|
||||||
|
Allow the user to set the default timeout speed.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.30:
|
||||||
|
(Hopefully) better timeout algorithm.
|
||||||
|
|
||||||
|
Add a "utimeout" option; like "timeout" but in microseconds.
|
||||||
|
|
||||||
|
Change the log level of client-side errors to LOG_WARNING.
|
||||||
|
|
||||||
|
autoconf portability improvements.
|
||||||
|
|
||||||
|
Minor bugfixes.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.29:
|
||||||
|
Posixly correctness.
|
||||||
|
|
||||||
|
Now compiles and runs on Win32 systems using Cygwin
|
||||||
|
(http://www.cygwin.com/).
|
||||||
|
(<http://www.cygwin.com/>).
|
||||||
|
|
||||||
|
Fixed a bug which could cause a standalone server to exit with
|
||||||
|
a "recvfrom: Interrupted system call" log message if signals
|
||||||
|
arrive at a particularly inopportune moment.
|
||||||
|
|
||||||
|
Fix a macro substitution bug (thanks to Richard Nyberg.)
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.28:
|
||||||
|
Fix stupid one-liner bug which broke standalone mode (-l).
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.27:
|
||||||
|
Make the Digital Unix 4.0F platform work again. Thanks to
|
||||||
|
Alan Sundell for helping out with this platform!
|
||||||
|
|
||||||
|
Make the AIX 4.3 platform work again. Thanks to Josef Siemes
|
||||||
|
for helping out with this platform!
|
||||||
|
|
||||||
|
Allow replacement patterns to include the IP address of the
|
||||||
|
requesting host (\i).
|
||||||
|
|
||||||
|
Allow relying on Unix permissions rather than o+r magic if the
|
||||||
|
-p option is specified. As part of this, set all groups if
|
||||||
|
initgroups() is specified on the platform.
|
||||||
|
|
||||||
|
Clean up race conditions inherited from the BSD source base.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.26:
|
||||||
|
Fix the configuration process so tftpd doesn't end up
|
||||||
|
depending on readline, which apparently could happen on some
|
||||||
|
platforms before.
|
||||||
|
|
||||||
|
Make parallel builds (make -j) work correctly.
|
||||||
|
|
||||||
|
Improve parsing of the "connect" command in the tftp client.
|
||||||
|
|
||||||
|
Add a -V option to both tftp and tftpd to print the version
|
||||||
|
number on stdout and immediately exit.
|
||||||
|
|
||||||
|
Add a -v option to tftp to start out in verbose mode.
|
||||||
|
|
||||||
|
Rewrite the man pages using standard "man" troff macros.
|
||||||
|
|
||||||
|
Enable the (limited) use of readline on systems which don't
|
||||||
|
have readline/history.h.
|
||||||
|
|
||||||
|
Support compiling under MacOS X with fink (see
|
||||||
|
<http://fink.sourceforge.net/>). Thanks for Justin Hallett
|
||||||
|
and Eric Eslinger for their help in getting this working!
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.25:
|
||||||
|
Fixed Sorcerer's Apprentice bug in both the client and the
|
||||||
|
server. These bugs were inherited from the original BSD code.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.24:
|
||||||
|
Fix bugs in both client and server dealing with block number
|
||||||
|
wraparound, usually manifesting themselves as failure to
|
||||||
|
handle files over 32 MB in size.
|
||||||
|
|
||||||
|
Officially make the client a part of the tftp-hpa project.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.23:
|
||||||
|
Correct memory overwrite bug in the tftp client when compiled
|
||||||
|
with readline.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.22:
|
||||||
|
Even more portability improvements: FreeBSD and
|
||||||
|
Tru64/Digital Unix.
|
||||||
|
|
||||||
|
Fix tsize option on systems on which off_t is "long long".
|
||||||
|
|
||||||
|
Support large files on systems which need _LARGE_FILE_BITS or
|
||||||
|
similar.
|
||||||
|
|
||||||
|
Some source cleanups; change to autoconf 2.52.
|
||||||
|
|
||||||
|
Add support for readline command-line editing in tftp.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.21:
|
||||||
|
Support running in standalone mode, without inetd.
|
||||||
|
|
||||||
|
Even more portability improvements. Now known to compile and
|
||||||
|
run on Linux, Solaris 5, 5.1, 6, 7 and 8, and AIX. Reports of
|
||||||
|
success or failure on other modern systems always appreciated.
|
||||||
|
|
||||||
|
Clean and modernize some really ugly old code.
|
||||||
|
|
||||||
|
Fix a potential illegal memory access when running in "totally
|
||||||
|
insecure mode" - no -s, no directories listed.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.20:
|
||||||
|
Portability improvements. Now known to compile and run on
|
||||||
|
Solaris 8.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.19:
|
||||||
|
Fork before performing tcpwrappers check.
|
||||||
|
|
||||||
|
Don't rely on nonstandard bsd_signal() function, instead
|
||||||
|
require that the platform has sigaction(). This is 2001,
|
||||||
|
after all. This may resolve some potential portability
|
||||||
|
problems.
|
||||||
|
|
||||||
|
Log a message if memory allocation fails, instead of dying
|
||||||
|
silently.
|
||||||
|
|
||||||
|
Clean up the main dispatch loop.
|
||||||
|
|
||||||
|
Use <sysexits.h> for exit codes, if it exists.
|
||||||
|
|
||||||
|
Add support for debugging remapping rulefiles; if logging with
|
||||||
|
-vvv tftpd will log all rules actions.
|
||||||
|
|
||||||
|
Correct the error code issued by an "abort" rule.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.18:
|
||||||
|
Support (almost) arbitrary filename remappings via regular
|
||||||
|
expression-based rulesets.
|
||||||
|
|
||||||
|
Added -v option for more verbose logging.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.17:
|
||||||
|
|
||||||
|
Add support for tcpwrapper checking (/etc/hosts.allow;
|
||||||
|
/etc/hosts.deny) in tftpd.
|
||||||
|
|
||||||
|
Compile correctly on glibc 2.1.2.
|
||||||
|
|
||||||
|
Add -u option to specify the user id to run as (default
|
||||||
|
"nobody".)
|
||||||
|
|
||||||
|
Operate in "daemon mode" as long as we keep getting requests.
|
||||||
|
This should speed up handling large amounts of requests at
|
||||||
|
once, as can happen when a client starts up, and avoids inetd
|
||||||
|
misconfiguration problems.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.16:
|
||||||
|
|
||||||
|
Correct massive lossage from 0.15: apparently 0.15 was based
|
||||||
|
on an out-of-date CVS repository, somehow.
|
||||||
|
|
||||||
|
Fix for ACKs in TFTP PUT; patch by Roger Venning.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.15:
|
||||||
|
|
||||||
|
If the operating system allows, try to obtain the local
|
||||||
|
address used for the request packet, and reply using the same
|
||||||
|
local IP address. Some embedded TFTP clients are (probably
|
||||||
|
incorrectly) picky about this.
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.14:
|
||||||
|
|
||||||
|
Hacks to signal handling to avoid "zombie servers."
|
||||||
|
|
||||||
|
|
||||||
|
Changes in 0.13:
|
||||||
|
|
||||||
|
Added the non-standard option "blksize2". The "blksize"
|
||||||
|
option is limited in its usability, since TFTP is designed to
|
||||||
|
be implemented in a ROM, and ROM code might find it painful to
|
||||||
|
deal with packets that don't meet certain alignment
|
||||||
|
restrictions.
|
||||||
|
|
||||||
|
The "blksize2" option tells the server that the block size
|
||||||
|
must be a power of 2 to be usable to the client. The server
|
||||||
|
SHALL respond with a block size that is a power of two, up to
|
||||||
|
a maximum of 32768, or reject the option. Furthermore, the
|
||||||
|
server SHALL grant a block size that is no smaller than 512
|
||||||
|
bytes unless the client explicitly requested a smaller block
|
||||||
|
size. If the client request both options, the server MAY
|
||||||
|
accept one or the other, but not both. At some point I will
|
||||||
|
probably write up an IETF draft for this option.
|
||||||
|
|
||||||
|
|
||||||
|
General information on the tftp-hpa series:
|
||||||
|
|
||||||
|
The core software was taken from OpenBSD (CVS source as of
|
||||||
|
1999-09-21). I believe this was the most secure source base available
|
||||||
|
at the time I obtained this code, and it included support for the -s
|
||||||
|
and -c options.
|
||||||
|
|
||||||
|
The un-BSD-ized Makefiles and a lot of the configure macros were taken
|
||||||
|
from netkit-tftp-0.10 by David Holland; I also followed this example
|
||||||
|
and modernized the code style throughout.
|
||||||
|
|
||||||
|
Patches by Markus Gutschke and Gero Kuhlmann were the basis for the
|
||||||
|
option negotiation as well as the "blksize" and "tsize" option
|
||||||
|
support, although I made a fair amount of mostly stylistic changes to
|
||||||
|
their code.
|
||||||
|
|
||||||
|
Adding the -r option (disable a specific option), the "timeout"
|
||||||
|
option, converting to using autoconf for setup, and any additions
|
||||||
|
listed in the Changes list above, has all been my own code, as are any
|
||||||
|
bugs introduced in the merge.
|
|
@ -0,0 +1,227 @@
|
||||||
|
Basic Installation
|
||||||
|
==================
|
||||||
|
|
||||||
|
These are generic installation instructions. See the file
|
||||||
|
INSTALL.tftp for specific install instructions for this package.
|
||||||
|
|
||||||
|
The `configure' shell script attempts to guess correct values for
|
||||||
|
various system-dependent variables used during compilation. It uses
|
||||||
|
those values to create a `Makefile' in each directory of the package.
|
||||||
|
It may also create one or more `.h' files containing system-dependent
|
||||||
|
definitions. Finally, it creates a shell script `config.status' that
|
||||||
|
you can run in the future to recreate the current configuration, and a
|
||||||
|
file `config.log' containing compiler output (useful mainly for
|
||||||
|
debugging `configure').
|
||||||
|
|
||||||
|
It can also use an optional file (typically called `config.cache'
|
||||||
|
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||||
|
the results of its tests to speed up reconfiguring. (Caching is
|
||||||
|
disabled by default to prevent problems with accidental use of stale
|
||||||
|
cache files.)
|
||||||
|
|
||||||
|
If you need to do unusual things to compile the package, please try
|
||||||
|
to figure out how `configure' could check whether to do them, and mail
|
||||||
|
diffs or instructions to the address given in the `README' so they can
|
||||||
|
be considered for the next release. If you are using the cache, and at
|
||||||
|
some point `config.cache' contains results you don't want to keep, you
|
||||||
|
may remove or edit it.
|
||||||
|
|
||||||
|
The file `configure.ac' (or `configure.in') is used to create
|
||||||
|
`configure' by a program called `autoconf'. You only need
|
||||||
|
`configure.ac' if you want to change it or regenerate `configure' using
|
||||||
|
a newer version of `autoconf'.
|
||||||
|
|
||||||
|
The simplest way to compile this package is:
|
||||||
|
|
||||||
|
1. `cd' to the directory containing the package's source code and type
|
||||||
|
`./configure' to configure the package for your system. If you're
|
||||||
|
using `csh' on an old version of System V, you might need to type
|
||||||
|
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||||
|
`configure' itself.
|
||||||
|
|
||||||
|
Running `configure' takes awhile. While running, it prints some
|
||||||
|
messages telling which features it is checking for.
|
||||||
|
|
||||||
|
2. Type `make' to compile the package.
|
||||||
|
|
||||||
|
3. Optionally, type `make check' to run any self-tests that come with
|
||||||
|
the package.
|
||||||
|
|
||||||
|
4. Type `make install' to install the programs and any data files and
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
5. You can remove the program binaries and object files from the
|
||||||
|
source code directory by typing `make clean'. To also remove the
|
||||||
|
files that `configure' created (so you can compile the package for
|
||||||
|
a different kind of computer), type `make distclean'. There is
|
||||||
|
also a `make maintainer-clean' target, but that is intended mainly
|
||||||
|
for the package's developers. If you use it, you may have to get
|
||||||
|
all sorts of other programs in order to regenerate files that came
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
Compilers and Options
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Some systems require unusual options for compilation or linking that
|
||||||
|
the `configure' script does not know about. Run `./configure --help'
|
||||||
|
for details on some of the pertinent environment variables.
|
||||||
|
|
||||||
|
You can give `configure' initial values for variables by setting
|
||||||
|
them in the environment. You can do that on the command line like this:
|
||||||
|
|
||||||
|
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
|
||||||
|
|
||||||
|
*Note Environment Variables::, for more details.
|
||||||
|
|
||||||
|
Compiling For Multiple Architectures
|
||||||
|
====================================
|
||||||
|
|
||||||
|
You can compile the package for more than one kind of computer at the
|
||||||
|
same time, by placing the object files for each architecture in their
|
||||||
|
own directory. To do this, you must use a version of `make' that
|
||||||
|
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||||
|
directory where you want the object files and executables to go and run
|
||||||
|
the `configure' script. `configure' automatically checks for the
|
||||||
|
source code in the directory that `configure' is in and in `..'.
|
||||||
|
|
||||||
|
If you have to use a `make' that does not support the `VPATH'
|
||||||
|
variable, you have to compile the package for one architecture at a time
|
||||||
|
in the source code directory. After you have installed the package for
|
||||||
|
one architecture, use `make distclean' before reconfiguring for another
|
||||||
|
architecture.
|
||||||
|
|
||||||
|
Installation Names
|
||||||
|
==================
|
||||||
|
|
||||||
|
By default, `make install' will install the package's files in
|
||||||
|
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||||
|
installation prefix other than `/usr/local' by giving `configure' the
|
||||||
|
option `--prefix=PATH'.
|
||||||
|
|
||||||
|
You can specify separate installation prefixes for
|
||||||
|
architecture-specific files and architecture-independent files. If you
|
||||||
|
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||||
|
PATH as the prefix for installing programs and libraries.
|
||||||
|
Documentation and other data files will still use the regular prefix.
|
||||||
|
|
||||||
|
In addition, if you use an unusual directory layout you can give
|
||||||
|
options like `--bindir=PATH' to specify different values for particular
|
||||||
|
kinds of files. Run `configure --help' for a list of the directories
|
||||||
|
you can set and what kinds of files go in them.
|
||||||
|
|
||||||
|
If the package supports it, you can cause programs to be installed
|
||||||
|
with an extra prefix or suffix on their names by giving `configure' the
|
||||||
|
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||||
|
|
||||||
|
Optional Features
|
||||||
|
=================
|
||||||
|
|
||||||
|
Some packages pay attention to `--enable-FEATURE' options to
|
||||||
|
`configure', where FEATURE indicates an optional part of the package.
|
||||||
|
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||||
|
is something like `gnu-as' or `x' (for the X Window System). The
|
||||||
|
`README' should mention any `--enable-' and `--with-' options that the
|
||||||
|
package recognizes.
|
||||||
|
|
||||||
|
For packages that use the X Window System, `configure' can usually
|
||||||
|
find the X include and library files automatically, but if it doesn't,
|
||||||
|
you can use the `configure' options `--x-includes=DIR' and
|
||||||
|
`--x-libraries=DIR' to specify their locations.
|
||||||
|
|
||||||
|
Specifying the System Type
|
||||||
|
==========================
|
||||||
|
|
||||||
|
There may be some features `configure' cannot figure out
|
||||||
|
automatically, but needs to determine by the type of host the package
|
||||||
|
will run on. Usually `configure' can figure that out, but if it prints
|
||||||
|
a message saying it cannot guess the host type, give it the
|
||||||
|
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||||
|
type, such as `sun4', or a canonical name which has the form:
|
||||||
|
|
||||||
|
CPU-COMPANY-SYSTEM
|
||||||
|
|
||||||
|
where SYSTEM can have one of these forms:
|
||||||
|
|
||||||
|
OS
|
||||||
|
KERNEL-OS
|
||||||
|
|
||||||
|
See the file `config.sub' for the possible values of each field. If
|
||||||
|
`config.sub' isn't included in this package, then this package doesn't
|
||||||
|
need to know the host type.
|
||||||
|
|
||||||
|
If you are _building_ compiler tools for cross-compiling, you should
|
||||||
|
use the `--target=TYPE' option to select the type of system they will
|
||||||
|
produce code for.
|
||||||
|
|
||||||
|
If you want to _use_ a cross compiler, that generates code for a
|
||||||
|
platform different from the build platform, you should specify the host
|
||||||
|
platform (i.e., that on which the generated programs will eventually be
|
||||||
|
run) with `--host=TYPE'. In this case, you should also specify the
|
||||||
|
build platform with `--build=TYPE', because, in this case, it may not
|
||||||
|
be possible to guess the build platform (it sometimes involves
|
||||||
|
compiling and running simple test programs, and this can't be done if
|
||||||
|
the compiler is a cross compiler).
|
||||||
|
|
||||||
|
Sharing Defaults
|
||||||
|
================
|
||||||
|
|
||||||
|
If you want to set default values for `configure' scripts to share,
|
||||||
|
you can create a site shell script called `config.site' that gives
|
||||||
|
default values for variables like `CC', `cache_file', and `prefix'.
|
||||||
|
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||||
|
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||||
|
`CONFIG_SITE' environment variable to the location of the site script.
|
||||||
|
A warning: not all `configure' scripts look for a site script.
|
||||||
|
|
||||||
|
Environment Variables
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Variables not defined in a site shell script can be set in the
|
||||||
|
environment passed to configure. However, some packages may run
|
||||||
|
configure again during the build, and the customized values of these
|
||||||
|
variables may be lost. In order to avoid this problem, you should set
|
||||||
|
them in the `configure' command line, using `VAR=value'. For example:
|
||||||
|
|
||||||
|
./configure CC=/usr/local2/bin/gcc
|
||||||
|
|
||||||
|
will cause the specified gcc to be used as the C compiler (unless it is
|
||||||
|
overridden in the site shell script).
|
||||||
|
|
||||||
|
`configure' Invocation
|
||||||
|
======================
|
||||||
|
|
||||||
|
`configure' recognizes the following options to control how it
|
||||||
|
operates.
|
||||||
|
|
||||||
|
`--help'
|
||||||
|
`-h'
|
||||||
|
Print a summary of the options to `configure', and exit.
|
||||||
|
|
||||||
|
`--version'
|
||||||
|
`-V'
|
||||||
|
Print the version of Autoconf used to generate the `configure'
|
||||||
|
script, and exit.
|
||||||
|
|
||||||
|
`--cache-file=FILE'
|
||||||
|
Enable the cache: use and save the results of the tests in FILE,
|
||||||
|
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||||
|
disable caching.
|
||||||
|
|
||||||
|
`--config-cache'
|
||||||
|
`-C'
|
||||||
|
Alias for `--cache-file=config.cache'.
|
||||||
|
|
||||||
|
`--quiet'
|
||||||
|
`--silent'
|
||||||
|
`-q'
|
||||||
|
Do not print messages saying which checks are being made. To
|
||||||
|
suppress all normal output, redirect it to `/dev/null' (any error
|
||||||
|
messages will still be shown).
|
||||||
|
|
||||||
|
`--srcdir=DIR'
|
||||||
|
Look for the package's source code in directory DIR. Usually
|
||||||
|
`configure' can determine that directory automatically.
|
||||||
|
|
||||||
|
`configure' also accepts some other, not widely useful, options. Run
|
||||||
|
`configure --help' for more details.
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
Specific installation instructions
|
||||||
|
==================================
|
||||||
|
|
||||||
|
In addition to what is described in the INSTALL file, the following
|
||||||
|
specifics apply to the tftp-hpa package:
|
||||||
|
|
||||||
|
The tftp-hpa package supports the following options to ./configure:
|
||||||
|
|
||||||
|
--without-tcpwrappers
|
||||||
|
Disables the use of the tcp wrapper library. This is
|
||||||
|
recommended, for performance reasons, on high-use sites.
|
||||||
|
Kernel-based firewalling is, in general, a better alternative.
|
||||||
|
|
||||||
|
--without-remap
|
||||||
|
Disables the use of regular-expression-based filename
|
||||||
|
remapping (the -m option to tftpd).
|
||||||
|
|
||||||
|
--without-readline
|
||||||
|
Disables the use of the readline command-line editing library
|
||||||
|
in the tftp client.
|
||||||
|
|
||||||
|
The default prefix for the tftp-hpa package is /usr, with the tftp
|
||||||
|
client installing as /usr/bin/tftp and the tftpd server installing as
|
||||||
|
/usr/sbin/in.tftpd on most systems. This can be overridden by setting
|
||||||
|
--bindir and --sbindir.
|
||||||
|
|
||||||
|
"make install" supports specifying an INSTALLROOT, which points to
|
||||||
|
what will be the root of the filesystem at runtime; this is typically
|
||||||
|
used when preparing packages for package-management systems.
|
||||||
|
|
||||||
|
You almost certainly will need GNU make to build tftp-hpa. If you
|
||||||
|
don't already have it, you can find GNU make at:
|
||||||
|
|
||||||
|
ftp://ftp.gnu.org/pub/make/
|
||||||
|
or
|
||||||
|
ftp://mirrors.kernel.org/gnu/make/
|
|
@ -0,0 +1,71 @@
|
||||||
|
## -*- makefile -*- ------------------------------------------------------
|
||||||
|
##
|
||||||
|
## 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/.
|
||||||
|
##
|
||||||
|
## -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
##
|
||||||
|
## MCONFIG.in
|
||||||
|
##
|
||||||
|
## Basic Makefile definitions
|
||||||
|
##
|
||||||
|
|
||||||
|
# Source and object root
|
||||||
|
SRCROOT = @SRCROOT@
|
||||||
|
OBJROOT = @OBJROOT@
|
||||||
|
|
||||||
|
# Prefixes
|
||||||
|
prefix = @prefix@
|
||||||
|
exec_prefix = @exec_prefix@
|
||||||
|
|
||||||
|
# Directory for user binaries
|
||||||
|
BINDIR = @bindir@
|
||||||
|
|
||||||
|
# Man page tree
|
||||||
|
MANDIR = @mandir@
|
||||||
|
|
||||||
|
# System binaries
|
||||||
|
SBINDIR = @sbindir@
|
||||||
|
|
||||||
|
# Data root directory
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
|
||||||
|
# Binary suffixes
|
||||||
|
O = @OBJEXT@
|
||||||
|
X = @EXEEXT@
|
||||||
|
|
||||||
|
# Install into alternate root area, e.g. for package generation
|
||||||
|
INSTALLROOT =
|
||||||
|
|
||||||
|
# Link
|
||||||
|
LN_S = @LN_S@
|
||||||
|
|
||||||
|
# Install program
|
||||||
|
INSTALL = @INSTALL@
|
||||||
|
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
|
|
||||||
|
# Compiler and compiler flags
|
||||||
|
CC = @CC@
|
||||||
|
CFLAGS = @CFLAGS@ -I$(SRCROOT)
|
||||||
|
|
||||||
|
# Link flags
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
|
# Libraries (client and server)
|
||||||
|
TFTP_LIBS = ../common/libcommon.a @TFTP_LIBS@
|
||||||
|
TFTPD_LIBS = ../common/libcommon.a @TFTPD_LIBS@
|
||||||
|
|
||||||
|
# Additional library we need to build
|
||||||
|
LIBOBJS = @LIBOBJS@
|
||||||
|
|
||||||
|
# Additional tftpd objects we need to build
|
||||||
|
TFTPDOBJS = @TFTPDOBJS@
|
||||||
|
|
||||||
|
# ar and ranlib (for making libraries)
|
||||||
|
AR = ar cq
|
||||||
|
RANLIB = @RANLIB@
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Standard compilation rules (don't use make builtins)
|
||||||
|
|
||||||
|
.SUFFIXES: .c .cc .o .s .S .i
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
.c.s:
|
||||||
|
$(CC) $(CFLAGS) -S -o $@ $<
|
||||||
|
|
||||||
|
.c.i:
|
||||||
|
$(CC) $(CFLAGS) -E -o $@ $<
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
$(CXX) $(CXXFLAGS) -c $<
|
||||||
|
|
||||||
|
.cc.s:
|
||||||
|
$(CXX) $(CXXFLAGS) -S -o $@ $<
|
||||||
|
|
||||||
|
.cc.i:
|
||||||
|
$(CXX) $(CXXFLAGS) -E -o $@ $<
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
# You can do "make SUB=blah" to make only a few, or edit here, or both
|
||||||
|
# You can also run make directly in the subdirs you want.
|
||||||
|
|
||||||
|
SUB = lib common tftp tftpd
|
||||||
|
|
||||||
|
%.build: MCONFIG aconfig.h version.h
|
||||||
|
$(MAKE) -C $(patsubst %.build, %, $@)
|
||||||
|
|
||||||
|
%.install: MCONFIG aconfig.h version.h
|
||||||
|
$(MAKE) -C $(patsubst %.install, %, $@) install
|
||||||
|
|
||||||
|
%.clean:
|
||||||
|
$(MAKE) -C $(patsubst %.clean, %, $@) clean
|
||||||
|
|
||||||
|
%.distclean:
|
||||||
|
$(MAKE) -C $(patsubst %.distclean, %, $@) distclean
|
||||||
|
|
||||||
|
all: MCONFIG $(patsubst %, %.build, $(SUB))
|
||||||
|
|
||||||
|
tftp.build: lib.build common.build
|
||||||
|
tftpd.build: lib.build common.build
|
||||||
|
|
||||||
|
install: MCONFIG $(patsubst %, %.install, $(SUB))
|
||||||
|
|
||||||
|
clean: localclean $(patsubst %, %.clean, $(SUB))
|
||||||
|
|
||||||
|
localclean:
|
||||||
|
rm -f version.h
|
||||||
|
|
||||||
|
distclean: localdistclean $(patsubst %, %.distclean, $(SUB))
|
||||||
|
|
||||||
|
localdistclean: localclean
|
||||||
|
rm -f MCONFIG config.status config.log aconfig.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
|
||||||
|
|
||||||
|
autoconf: configure aconfig.h.in
|
||||||
|
|
||||||
|
config: MCONFIG aconfig.h
|
||||||
|
|
||||||
|
release:
|
||||||
|
$(MAKE) autoconf
|
||||||
|
$(MAKE) tftp.spec
|
||||||
|
$(MAKE) distclean
|
||||||
|
|
||||||
|
MCONFIG: configure MCONFIG.in aconfig.h.in
|
||||||
|
if test -x config.status; then \
|
||||||
|
./config.status --recheck && ./config.status ; \
|
||||||
|
else \
|
||||||
|
./configure ; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
aconfig.h: 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.in aclocal.m4
|
||||||
|
rm -rf MCONFIG configure config.log aconfig.h *.cache
|
||||||
|
autoconf
|
||||||
|
|
||||||
|
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 $@
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
This is tftp-hpa, a conglomerate of a number of versions of the BSD
|
||||||
|
TFTP code, changed around to port to a whole collection of operating
|
||||||
|
systems. The goal is to work on any reasonably modern Unix with
|
||||||
|
sockets.
|
||||||
|
|
||||||
|
The tftp-hpa series is maintained by H. Peter Anvin <hpa@zytor.com>.
|
||||||
|
|
||||||
|
The latest version of this collection can be found at:
|
||||||
|
|
||||||
|
ftp://ftp.kernel.org/pub/software/network/tftp/
|
||||||
|
|
||||||
|
See the file CHANGES for a list of changes between versions.
|
||||||
|
|
||||||
|
|
||||||
|
Please see the INSTALL and INSTALL.tftp files for compilation and
|
||||||
|
installation instructions.
|
||||||
|
|
||||||
|
===> IMPORTANT: IF YOU ARE UPGRADING FROM ANOTHER TFTP SERVER, OR FROM
|
||||||
|
===> A VERSION OF TFTP-HPA OLDER THAN 0.17 SEE THE FILE
|
||||||
|
===> "README.security" FOR IMPORTANT SECURITY MODEL CHANGES!
|
||||||
|
|
||||||
|
|
||||||
|
This software can be discussed on the SYSLINUX mailing list. To
|
||||||
|
subscribe, go to the list subscription page at:
|
||||||
|
|
||||||
|
http://www.zytor.com/mailman/listinfo/syslinux
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
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
|
||||||
|
that files no longer need to be set to o+r or o+w.
|
||||||
|
|
||||||
|
If file creation is enabled (via the -c option), the -p option also
|
||||||
|
changes the default umask from 0 (anyone can read or write) to
|
||||||
|
"unchanged" (inherited from the calling process.) The -U option can
|
||||||
|
be used to override the default umask; this is recommended.
|
||||||
|
|
||||||
|
The sanest setup, from a security standpoint, for tftpd to run in is
|
||||||
|
probably the following:
|
||||||
|
|
||||||
|
1. Create a separate "tftpd" user and group only used for tftpd;
|
||||||
|
2. Have all your boot files in a single directory tree (usually called
|
||||||
|
/tftpboot).
|
||||||
|
3. Specify "-p -u tftpd -s /tftpboot" on the tftpd command line; if
|
||||||
|
you want clients to be able to create files use
|
||||||
|
"-p -c -U 002 -u tftpd -s /tftpboot" (replace 002 with whatever
|
||||||
|
umask is appropriate for your setup.)
|
||||||
|
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
Starting in version 0.17, tftp-hpa operates in genuine "wait" mode,
|
||||||
|
which means that an in.tftpd process hangs around for some time after
|
||||||
|
the last service request has arrived. This speeds up servicing a
|
||||||
|
subsequent request, which apparently has been a problem in the past,
|
||||||
|
resulting in "request storms" as the client keeps retrying, resulting
|
||||||
|
in multiple connections on the server which the client has already
|
||||||
|
abandoned.
|
||||||
|
|
||||||
|
This also means that spawning tftp via tcpd is useless (in fact, this
|
||||||
|
indirection seems to be part of the reason for these "request
|
||||||
|
storms.") Instead, tftp-hpa supports calling the tcpwrapper library
|
||||||
|
directly. Thus, if your /etc/inetd.conf looks like this (all on one
|
||||||
|
line):
|
||||||
|
|
||||||
|
tftp dgram udp wait root /usr/sbin/tcpd
|
||||||
|
/usr/sbin/in.tftpd -s /tftpboot -r blksize
|
||||||
|
|
||||||
|
... it's better to change to ...
|
||||||
|
|
||||||
|
tftp dgram udp wait root /usr/sbin/in.tftpd
|
||||||
|
in.tftpd -s /tftpboot -r blksize
|
||||||
|
|
||||||
|
You should make sure that you are using "wait" option in tftpd; you
|
||||||
|
also need to have tftpd spawned as root in order for chroot (-s) to
|
||||||
|
work. tftpd automatically drops privilege and changes user ID to
|
||||||
|
"nobody" by default; the appropriate user ID for tftpd can be
|
||||||
|
specified with the -u option (e.g. "-u tftpuser").
|
||||||
|
|
||||||
|
If you are running a busy boot server, I would suggest to instead use
|
||||||
|
kernel-based firewalling rules, and to compile tftpd without
|
||||||
|
tcpwrapper support, in order to provide significantly better
|
||||||
|
performance. To do so, specify the --without-tcpwrappers option to
|
||||||
|
configure when compiling; see the INSTALL.tftp file for more information.
|
|
@ -0,0 +1,280 @@
|
||||||
|
dnl -----------------------------------------------------------------------
|
||||||
|
dnl
|
||||||
|
dnl Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
|
||||||
|
dnl
|
||||||
|
dnl This program is free software; you can redistribute it and/or modify
|
||||||
|
dnl it under the terms of the GNU General Public License as published by
|
||||||
|
dnl the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
||||||
|
dnl Bostom MA 02111-1307, USA; either version 2 of the License, or
|
||||||
|
dnl (at your option) any later version; incorporated herein by reference.
|
||||||
|
dnl
|
||||||
|
dnl -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ADD_CFLAGS()
|
||||||
|
dnl
|
||||||
|
dnl Attempt to add the given option to CFLAGS, if it doesn't break compilation
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN(PA_ADD_CFLAGS,
|
||||||
|
[AC_MSG_CHECKING([if $CC accepts $1])
|
||||||
|
pa_add_cflags__old_cflags="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $1"
|
||||||
|
AC_TRY_LINK([#include <stdio.h>],
|
||||||
|
[printf("Hello, World!\n");],
|
||||||
|
AC_MSG_RESULT([yes]),
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
CFLAGS="$pa_add_cflags__old_cflags")])
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_SIGSETJMP
|
||||||
|
dnl
|
||||||
|
dnl Do we have sigsetjmp/siglongjmp? (AC_CHECK_FUNCS doesn't seem to work
|
||||||
|
dnl for these particular functions.)
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN(PA_SIGSETJMP,
|
||||||
|
[AC_MSG_CHECKING([for sigsetjmp])
|
||||||
|
AC_TRY_LINK([
|
||||||
|
#ifdef HAVE_SETJMP_H
|
||||||
|
#include <setjmp.h>
|
||||||
|
#endif],
|
||||||
|
[sigjmp_buf buf;
|
||||||
|
sigsetjmp(buf,1);
|
||||||
|
siglongjmp(buf,2);],
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
$1,
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
$2)])
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_MSGHDR_MSG_CONTROL
|
||||||
|
dnl
|
||||||
|
dnl Does struct msghdr have the msg_control field?
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AH_TEMPLATE([HAVE_MSGHDR_MSG_CONTROL],
|
||||||
|
[Define if struct msghdr has the msg_control field.])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_MSGHDR_MSG_CONTROL,
|
||||||
|
[AC_CHECK_MEMBER(struct msghdr.msg_control,
|
||||||
|
[AC_DEFINE(HAVE_MSGHDR_MSG_CONTROL)],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
])])
|
||||||
|
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_STRUCT_IN_PKTINFO
|
||||||
|
dnl
|
||||||
|
dnl Look for definition of struct in_pktinfo, which at least has an
|
||||||
|
dnl ipi_addr member. Some versions of glibc lack struct in_pktinfo;
|
||||||
|
dnl if so we need to include the definition ourselves -- but we only
|
||||||
|
dnl want to do that if absolutely necessary!
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
AH_TEMPLATE([HAVE_STRUCT_IN_PKTINFO],
|
||||||
|
[Define if struct in_pktinfo is defined.])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_STRUCT_IN_PKTINFO,
|
||||||
|
[AC_CHECK_MEMBER(struct in_pktinfo.ipi_addr,
|
||||||
|
[AC_DEFINE(HAVE_STRUCT_IN_PKTINFO)],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
])])
|
||||||
|
|
||||||
|
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_STRUCT_SOCKADDR_IN6
|
||||||
|
dnl
|
||||||
|
dnl Look for definition of struct sockaddr_in6, which at least has an
|
||||||
|
dnl sin6_addr member
|
||||||
|
dnl
|
||||||
|
AH_TEMPLATE([HAVE_STRUCT_SOCKADDR_IN6],
|
||||||
|
[Define if struct sockaddr_in6 is defined.])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_STRUCT_SOCKADDR_IN6,
|
||||||
|
[AC_CHECK_MEMBER(struct sockaddr_in6.sin6_addr,
|
||||||
|
[
|
||||||
|
AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)
|
||||||
|
HAVE_INET6=true;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
HAVE_INET6=false;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
])])
|
||||||
|
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_STRUCT_ADDRINFO
|
||||||
|
dnl
|
||||||
|
dnl Look for definition of struct addrinfo, which at least has an
|
||||||
|
dnl ai_addr member
|
||||||
|
dnl
|
||||||
|
AH_TEMPLATE([HAVE_STRUCT_ADDRINFO],
|
||||||
|
[Define if struct addrinfo is defined.])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_STRUCT_ADDRINFO,
|
||||||
|
[AC_CHECK_MEMBER(struct addrinfo.ai_addr,
|
||||||
|
[AC_DEFINE(HAVE_STRUCT_ADDRINFO)],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
])])
|
||||||
|
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_STRUCT_IN6_PKTINFO
|
||||||
|
dnl
|
||||||
|
dnl Look for definition of struct in6_pktinfo, which at least has an
|
||||||
|
dnl ipi6_addr member
|
||||||
|
dnl
|
||||||
|
AH_TEMPLATE([HAVE_STRUCT_IN6_PKTINFO],
|
||||||
|
[Define if struct in6_pktinfo is defined.])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_STRUCT_IN6_PKTINFO,
|
||||||
|
[AC_CHECK_MEMBER(struct in6_pktinfo.ipi6_addr,
|
||||||
|
[AC_DEFINE(HAVE_STRUCT_IN6_PKTINFO)],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
])])
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_HAVE_TCPWRAPPERS
|
||||||
|
dnl
|
||||||
|
dnl Do we have the tcpwrappers -lwrap? This can't be done using AC_CHECK_LIBS
|
||||||
|
dnl due to the need to provide "allow_severity" and "deny_severity" variables
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AH_TEMPLATE([HAVE_TCPWRAPPERS],
|
||||||
|
[Define if we have tcpwrappers (-lwrap) and <tcpd.h>.])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_HAVE_TCPWRAPPERS,
|
||||||
|
[AC_CHECK_LIB([wrap], [main])
|
||||||
|
AC_MSG_CHECKING([for tcpwrappers])
|
||||||
|
AC_TRY_LINK(
|
||||||
|
[
|
||||||
|
#include <tcpd.h>
|
||||||
|
int allow_severity = 0;
|
||||||
|
int deny_severity = 0;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
hosts_ctl("sample_daemon", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN);
|
||||||
|
],
|
||||||
|
[
|
||||||
|
AC_DEFINE(HAVE_TCPWRAPPERS)
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
],
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
])])
|
||||||
|
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_CHECK_INTTYPES_H_SANE
|
||||||
|
dnl
|
||||||
|
dnl At least some versions of AIX 4 have <inttypes.h> macros which are
|
||||||
|
dnl completely broken. Try to detect those.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AH_TEMPLATE([INTTYPES_H_IS_SANE],
|
||||||
|
[Define if the macros in <inttypes.h> are usable])
|
||||||
|
|
||||||
|
AC_DEFUN(PA_CHECK_INTTYPES_H_SANE,
|
||||||
|
[AC_CHECK_HEADERS(inttypes.h,
|
||||||
|
[
|
||||||
|
AC_MSG_CHECKING([if inttypes.h is sane])
|
||||||
|
AC_TRY_LINK(
|
||||||
|
[
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
],
|
||||||
|
[uintmax_t max = UINTMAX_C(0);
|
||||||
|
printf("%"PRIuMAX"\n", max);],
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE(INTTYPES_H_IS_SANE),
|
||||||
|
AC_MSG_RESULT([no (AIX, eh?)]))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_WITH_BOOL
|
||||||
|
dnl
|
||||||
|
dnl PA_WITH_BOOL(option, default, help, enable, disable)
|
||||||
|
dnl
|
||||||
|
dnl Provides a more convenient way to specify --with-option and
|
||||||
|
dnl --without-option, with a default. default should be either 0 or 1.
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
AC_DEFUN(PA_WITH_BOOL,
|
||||||
|
[AC_ARG_WITH([$1], [$3],
|
||||||
|
if test ["$withval"] != no; then
|
||||||
|
[$4]
|
||||||
|
else
|
||||||
|
[$5]
|
||||||
|
fi,
|
||||||
|
if test [$2] -ne 0; then
|
||||||
|
[$4]
|
||||||
|
else
|
||||||
|
[$5]
|
||||||
|
fi)])
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_HEADER_DEFINES
|
||||||
|
dnl
|
||||||
|
dnl PA_HEADER_DEFINES(header, type, value)
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN(PA_HEADER_DEFINES,
|
||||||
|
[AC_MSG_CHECKING([if $1 defines $3])
|
||||||
|
AH_TEMPLATE([HAVE_$3_DEFINITION], [Define if $1 defines $3])
|
||||||
|
AC_TRY_COMPILE([
|
||||||
|
#include <$1>
|
||||||
|
],
|
||||||
|
[
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
$2 dummy = $3;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
pa_header_define=`echo HAVE_$3_DEFINITION | tr '[a-z]' '[A-Z]'`
|
||||||
|
AC_DEFINE_UNQUOTED($pa_header_define)
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])])
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_SEARCH_LIBS_AND_ADD
|
||||||
|
dnl
|
||||||
|
dnl PA_SEARCH_LIBS_AND_ADD(function, libraries [,function to add])
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
AC_DEFUN(PA_SEARCH_LIBS_AND_ADD,
|
||||||
|
[
|
||||||
|
AH_TEMPLATE(AS_TR_CPP(HAVE_$1), [Define if $1 function was found])
|
||||||
|
AC_SEARCH_LIBS($1, $2,
|
||||||
|
[
|
||||||
|
AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1))
|
||||||
|
pa_add_$1=false;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
XTRA=true;
|
||||||
|
if test $# -eq 3; then
|
||||||
|
AC_LIBOBJ($3)
|
||||||
|
else
|
||||||
|
AC_LIBOBJ($1)
|
||||||
|
fi
|
||||||
|
pa_add_$1=true;
|
||||||
|
])])
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
make autoconf
|
|
@ -0,0 +1,25 @@
|
||||||
|
SRCROOT = ..
|
||||||
|
VERSION = $(shell cat ../version)
|
||||||
|
|
||||||
|
-include ../MCONFIG
|
||||||
|
include ../MRULES
|
||||||
|
|
||||||
|
OBJS = tftpsubs.$(O)
|
||||||
|
LIB = libcommon.a
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
$(LIB): $(OBJS)
|
||||||
|
-rm -f $(LIB)
|
||||||
|
$(AR) $(LIB) $(OBJS)
|
||||||
|
$(RANLIB) $(LIB)
|
||||||
|
|
||||||
|
$(OBJS): tftpsubs.h
|
||||||
|
|
||||||
|
install:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.obj *.exe $(LIB)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f *~
|
|
@ -0,0 +1,406 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1983, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tftpsubs.h"
|
||||||
|
|
||||||
|
/* Simple minded read-ahead/write-behind subroutines for tftp user and
|
||||||
|
server. Written originally with multiple buffers in mind, but current
|
||||||
|
implementation has two buffer logic wired in.
|
||||||
|
|
||||||
|
Todo: add some sort of final error check so when the write-buffer
|
||||||
|
is finally flushed, the caller can detect if the disk filled up
|
||||||
|
(or had an i/o error) and return a nak to the other side.
|
||||||
|
|
||||||
|
Jim Guyton 10/85
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
|
||||||
|
|
||||||
|
int segsize = SEGSIZE; /* Default segsize */
|
||||||
|
|
||||||
|
struct bf {
|
||||||
|
int counter; /* size of data in buffer, or flag */
|
||||||
|
char buf[PKTSIZE]; /* room for data packet */
|
||||||
|
} bfs[2];
|
||||||
|
|
||||||
|
/* Values for bf.counter */
|
||||||
|
#define BF_ALLOC -3 /* alloc'd but not yet filled */
|
||||||
|
#define BF_FREE -2 /* free */
|
||||||
|
/* [-1 .. segsize] = size of data in the data buffer */
|
||||||
|
|
||||||
|
static int nextone; /* index of next buffer to use */
|
||||||
|
static int current; /* index of buffer in use */
|
||||||
|
|
||||||
|
/* control flags for crlf conversions */
|
||||||
|
int newline = 0; /* fillbuf: in middle of newline expansion */
|
||||||
|
int prevchar = -1; /* putbuf: previous char (cr check) */
|
||||||
|
|
||||||
|
static struct tftphdr *rw_init(int);
|
||||||
|
|
||||||
|
struct tftphdr *w_init()
|
||||||
|
{
|
||||||
|
return rw_init(0);
|
||||||
|
} /* write-behind */
|
||||||
|
|
||||||
|
struct tftphdr *r_init()
|
||||||
|
{
|
||||||
|
return rw_init(1);
|
||||||
|
} /* read-ahead */
|
||||||
|
|
||||||
|
/* init for either read-ahead or write-behind */
|
||||||
|
/* x == zero for write-behind, one for read-head */
|
||||||
|
static struct tftphdr *rw_init(int x)
|
||||||
|
{
|
||||||
|
newline = 0; /* init crlf flag */
|
||||||
|
prevchar = -1;
|
||||||
|
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
|
||||||
|
current = 0;
|
||||||
|
bfs[1].counter = BF_FREE;
|
||||||
|
nextone = x; /* ahead or behind? */
|
||||||
|
return (struct tftphdr *)bfs[0].buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Have emptied current buffer by sending to net and getting ack.
|
||||||
|
Free it and return next buffer filled with data.
|
||||||
|
*/
|
||||||
|
int readit(FILE * file, struct tftphdr **dpp, int convert)
|
||||||
|
{
|
||||||
|
struct bf *b;
|
||||||
|
|
||||||
|
bfs[current].counter = BF_FREE; /* free old one */
|
||||||
|
current = !current; /* "incr" current */
|
||||||
|
|
||||||
|
b = &bfs[current]; /* look at new buffer */
|
||||||
|
if (b->counter == BF_FREE) /* if it's empty */
|
||||||
|
read_ahead(file, convert); /* fill it */
|
||||||
|
/* assert(b->counter != BF_FREE);*//* check */
|
||||||
|
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
|
||||||
|
return b->counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fill the input buffer, doing ascii conversions if requested
|
||||||
|
* conversions are lf -> cr,lf and cr -> cr, nul
|
||||||
|
*/
|
||||||
|
void read_ahead(FILE * file, int convert)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
int c;
|
||||||
|
struct bf *b;
|
||||||
|
struct tftphdr *dp;
|
||||||
|
|
||||||
|
b = &bfs[nextone]; /* look at "next" buffer */
|
||||||
|
if (b->counter != BF_FREE) /* nop if not free */
|
||||||
|
return;
|
||||||
|
nextone = !nextone; /* "incr" next buffer ptr */
|
||||||
|
|
||||||
|
dp = (struct tftphdr *)b->buf;
|
||||||
|
|
||||||
|
if (convert == 0) {
|
||||||
|
b->counter = read(fileno(file), dp->th_data, segsize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = dp->th_data;
|
||||||
|
for (i = 0; i < segsize; i++) {
|
||||||
|
if (newline) {
|
||||||
|
if (prevchar == '\n')
|
||||||
|
c = '\n'; /* lf to cr,lf */
|
||||||
|
else
|
||||||
|
c = '\0'; /* cr to cr,nul */
|
||||||
|
newline = 0;
|
||||||
|
} else {
|
||||||
|
c = getc(file);
|
||||||
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
if (c == '\n' || c == '\r') {
|
||||||
|
prevchar = c;
|
||||||
|
c = '\r';
|
||||||
|
newline = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = c;
|
||||||
|
}
|
||||||
|
b->counter = (int)(p - dp->th_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update count associated with the buffer, get new buffer
|
||||||
|
from the queue. Calls write_behind only if next buffer not
|
||||||
|
available.
|
||||||
|
*/
|
||||||
|
int writeit(FILE * file, struct tftphdr **dpp, int ct, int convert)
|
||||||
|
{
|
||||||
|
bfs[current].counter = ct; /* set size of data to write */
|
||||||
|
current = !current; /* switch to other buffer */
|
||||||
|
if (bfs[current].counter != BF_FREE) /* if not free */
|
||||||
|
(void)write_behind(file, convert); /* flush it */
|
||||||
|
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
|
||||||
|
*dpp = (struct tftphdr *)bfs[current].buf;
|
||||||
|
return ct; /* this is a lie of course */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output a buffer to a file, converting from netascii if requested.
|
||||||
|
* CR,NUL -> CR and CR,LF => LF.
|
||||||
|
* Note spec is undefined if we get CR as last byte of file or a
|
||||||
|
* CR followed by anything else. In this case we leave it alone.
|
||||||
|
*/
|
||||||
|
int write_behind(FILE * file, int convert)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int count;
|
||||||
|
int ct;
|
||||||
|
char *p;
|
||||||
|
int c; /* current character */
|
||||||
|
struct bf *b;
|
||||||
|
struct tftphdr *dp;
|
||||||
|
|
||||||
|
b = &bfs[nextone];
|
||||||
|
if (b->counter < -1) /* anything to flush? */
|
||||||
|
return 0; /* just nop if nothing to do */
|
||||||
|
|
||||||
|
count = b->counter; /* remember byte count */
|
||||||
|
b->counter = BF_FREE; /* reset flag */
|
||||||
|
dp = (struct tftphdr *)b->buf;
|
||||||
|
nextone = !nextone; /* incr for next time */
|
||||||
|
buf = dp->th_data;
|
||||||
|
|
||||||
|
if (count <= 0)
|
||||||
|
return -1; /* nak logic? */
|
||||||
|
|
||||||
|
if (convert == 0)
|
||||||
|
return write(fileno(file), buf, count);
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
ct = count;
|
||||||
|
while (ct--) { /* loop over the buffer */
|
||||||
|
c = *p++; /* pick up a character */
|
||||||
|
if (prevchar == '\r') { /* if prev char was cr */
|
||||||
|
if (c == '\n') /* if have cr,lf then just */
|
||||||
|
fseek(file, -1, 1); /* smash lf on top of the cr */
|
||||||
|
else if (c == '\0') /* if have cr,nul then */
|
||||||
|
goto skipit; /* just skip over the putc */
|
||||||
|
/* else just fall through and allow it */
|
||||||
|
}
|
||||||
|
putc(c, file);
|
||||||
|
skipit:
|
||||||
|
prevchar = c;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When an error has occurred, it is possible that the two sides
|
||||||
|
* are out of synch. Ie: that what I think is the other side's
|
||||||
|
* response to packet N is really their response to packet N-1.
|
||||||
|
*
|
||||||
|
* So, to try to prevent that, we flush all the input queued up
|
||||||
|
* for us on the network connection on our host.
|
||||||
|
*
|
||||||
|
* We return the number of packets we flushed (mostly for reporting
|
||||||
|
* when trace is active).
|
||||||
|
*/
|
||||||
|
|
||||||
|
int synchnet(int f)
|
||||||
|
{ /* socket to flush */
|
||||||
|
int pktcount = 0;
|
||||||
|
char rbuf[PKTSIZE];
|
||||||
|
union sock_addr from;
|
||||||
|
socklen_t fromlen;
|
||||||
|
fd_set socketset;
|
||||||
|
struct timeval notime;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
notime.tv_sec = notime.tv_usec = 0;
|
||||||
|
|
||||||
|
FD_ZERO(&socketset);
|
||||||
|
FD_SET(f, &socketset);
|
||||||
|
|
||||||
|
if (select(f, &socketset, NULL, NULL, ¬ime) <= 0)
|
||||||
|
break; /* Nothing to read */
|
||||||
|
|
||||||
|
/* Otherwise drain the packet */
|
||||||
|
pktcount++;
|
||||||
|
fromlen = sizeof(from);
|
||||||
|
(void)recvfrom(f, rbuf, sizeof(rbuf), 0,
|
||||||
|
&from.sa, &fromlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pktcount; /* Return packets drained */
|
||||||
|
}
|
||||||
|
|
||||||
|
int pick_port_bind(int sockfd, union sock_addr *myaddr,
|
||||||
|
unsigned int port_range_from,
|
||||||
|
unsigned int port_range_to)
|
||||||
|
{
|
||||||
|
unsigned int port, firstport;
|
||||||
|
int port_range = 0;
|
||||||
|
|
||||||
|
if (port_range_from != 0 && port_range_to != 0) {
|
||||||
|
port_range = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstport = port_range
|
||||||
|
? port_range_from + rand() % (port_range_to - port_range_from + 1)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
port = firstport;
|
||||||
|
|
||||||
|
do {
|
||||||
|
sa_set_port(myaddr, htons(port));
|
||||||
|
if (bind(sockfd, &myaddr->sa, SOCKLEN(myaddr)) < 0) {
|
||||||
|
/* Some versions of Linux return EINVAL instead of EADDRINUSE */
|
||||||
|
if (!(port_range && (errno == EINVAL || errno == EADDRINUSE)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Normally, we shouldn't have to loop, but some situations involving
|
||||||
|
aborted transfers make it possible. */
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
port++;
|
||||||
|
if (port > port_range_to)
|
||||||
|
port = port_range_from;
|
||||||
|
} while (port != firstport);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
set_sock_addr(char *host,union sock_addr *s, char **name)
|
||||||
|
{
|
||||||
|
struct addrinfo *addrResult;
|
||||||
|
struct addrinfo hints;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = s->sa.sa_family;
|
||||||
|
hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
err = getaddrinfo(strip_address(host), NULL, &hints, &addrResult);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (addrResult == NULL)
|
||||||
|
return EAI_NONAME;
|
||||||
|
memcpy(s, addrResult->ai_addr, addrResult->ai_addrlen);
|
||||||
|
if (name) {
|
||||||
|
if (addrResult->ai_canonname)
|
||||||
|
*name = xstrdup(addrResult->ai_canonname);
|
||||||
|
else
|
||||||
|
*name = xstrdup(host);
|
||||||
|
}
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_numeric_ipv6(const char *p)
|
||||||
|
{
|
||||||
|
/* A numeric IPv6 address consist at least of 2 ':' and
|
||||||
|
* it may have sequences of hex-digits and maybe contain
|
||||||
|
* a '.' from a IPv4 mapped address and maybe is enclosed in []
|
||||||
|
* we do not check here, if it is a valid IPv6 address
|
||||||
|
* only if is something like a numeric IPv6 address or something else
|
||||||
|
*/
|
||||||
|
int colon = 0;
|
||||||
|
int dot = 0;
|
||||||
|
int bracket = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (*p == '[') {
|
||||||
|
bracket = 1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = *p++) && c != ']') {
|
||||||
|
switch (c) {
|
||||||
|
case ':':
|
||||||
|
colon++;
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
dot++;
|
||||||
|
break;
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||||
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0; /* Invalid character */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colon < 2 || colon > 7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dot) {
|
||||||
|
/* An IPv4-mapped address in dot-quad form will have 3 dots */
|
||||||
|
if (dot != 3)
|
||||||
|
return 0;
|
||||||
|
/* The IPv4-mapped address takes the space of one colon */
|
||||||
|
if (colon > 6)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If bracketed, must be closed, and vice versa */
|
||||||
|
if (bracket ^ (c == ']'))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Otherwise, assume we're okay */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* strip [] from numeric IPv6 addreses */
|
||||||
|
|
||||||
|
char *strip_address(char *addr)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (is_numeric_ipv6(addr) && (*addr == '[')) {
|
||||||
|
p = addr + strlen(addr);
|
||||||
|
p--;
|
||||||
|
if (*p == ']') {
|
||||||
|
*p = 0;
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes for read-ahead/write-behind subroutines for tftp user and
|
||||||
|
* server.
|
||||||
|
*/
|
||||||
|
#ifndef TFTPSUBS_H
|
||||||
|
#define TFTPSUBS_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
union sock_addr {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_in si;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
struct sockaddr_in6 s6;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SOCKLEN(sock) \
|
||||||
|
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
|
||||||
|
(sizeof(struct sockaddr_in)) : \
|
||||||
|
(sizeof(union sock_addr)))
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#define SOCKPORT(sock) \
|
||||||
|
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
|
||||||
|
((union sock_addr*)sock)->si.sin_port : \
|
||||||
|
((union sock_addr*)sock)->s6.sin6_port)
|
||||||
|
#else
|
||||||
|
#define SOCKPORT(sock) \
|
||||||
|
(((union sock_addr*)sock)->si.sin_port)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#define SOCKADDR_P(sock) \
|
||||||
|
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
|
||||||
|
(void *)&((union sock_addr*)sock)->si.sin_addr : \
|
||||||
|
(void *)&((union sock_addr*)sock)->s6.sin6_addr)
|
||||||
|
#else
|
||||||
|
#define SOCKADDR_P(sock) \
|
||||||
|
(void *)&((union sock_addr*)sock)->si.sin_addr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_numeric_ipv6(const char *);
|
||||||
|
char *strip_address(char *);
|
||||||
|
#else
|
||||||
|
#define is_numeric_ipv6(a) 0
|
||||||
|
#define strip_address(a) (a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int sa_set_port(union sock_addr *s, u_short port)
|
||||||
|
{
|
||||||
|
switch (s->sa.sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
s->si.sin_port = port;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case AF_INET6:
|
||||||
|
s->s6.sin6_port = port;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_sock_addr(char *, union sock_addr *, char **);
|
||||||
|
|
||||||
|
struct tftphdr;
|
||||||
|
|
||||||
|
struct tftphdr *r_init(void);
|
||||||
|
void read_ahead(FILE *, int);
|
||||||
|
int readit(FILE *, struct tftphdr **, int);
|
||||||
|
|
||||||
|
int synchnet(int);
|
||||||
|
|
||||||
|
struct tftphdr *w_init(void);
|
||||||
|
int write_behind(FILE *, int);
|
||||||
|
int writeit(FILE *, struct tftphdr **, int, int);
|
||||||
|
|
||||||
|
extern int segsize;
|
||||||
|
#define MAX_SEGSIZE 65464
|
||||||
|
|
||||||
|
int pick_port_bind(int sockfd, union sock_addr *myaddr,
|
||||||
|
unsigned int from, unsigned int to);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,380 @@
|
||||||
|
/* -*- c -*- ------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2001-2006 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* config.h
|
||||||
|
*
|
||||||
|
* Sets up a common baseline environment, based on "autoconf" findings...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H 1
|
||||||
|
|
||||||
|
/* Must be included before we include any system headers! */
|
||||||
|
#include "aconfig.h" /* autogenerated configuration header */
|
||||||
|
|
||||||
|
/* Standard includes */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_STAT_H
|
||||||
|
#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
|
||||||
|
|
||||||
|
#ifdef HAVE_INTTYPES_H
|
||||||
|
#ifdef INTTYPES_H_IS_SANE
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_STDINT_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SETJMP_H
|
||||||
|
#include <setjmp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TIME_WITH_SYS_TIME
|
||||||
|
#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
|
||||||
|
#include <grp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_FCNTL_H
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_WINSOCK2_H
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_WINSOCK_H
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NETDB_H
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_GETOPT_LONG
|
||||||
|
#include <getopt.h>
|
||||||
|
#else
|
||||||
|
#include "lib/getopt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Test for EAGAIN/EWOULDBLOCK */
|
||||||
|
#ifdef EAGAIN
|
||||||
|
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
|
||||||
|
#define E_WOULD_BLOCK(x) ((x) == EAGAIN || (x) == EWOULDBLOCK)
|
||||||
|
#else
|
||||||
|
#define E_WOULD_BLOCK(x) ((x) == EAGAIN)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define E_WOULD_BLOCK(x) ((x) == EWOULDBLOCK)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Some broken systems care about text versus binary, but
|
||||||
|
real Unix systems don't... */
|
||||||
|
#ifndef HAVE_O_TEXT_DEFINITION
|
||||||
|
#define O_TEXT 0
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_O_BINARY_DEFINITION
|
||||||
|
#define O_BINARY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we don't have intmax_t, try creating it */
|
||||||
|
|
||||||
|
#ifndef HAVE_INTMAX_T
|
||||||
|
#ifdef HAVE_LONG_LONG
|
||||||
|
typedef long long intmax_t;
|
||||||
|
typedef unsigned long long uintmax_t;
|
||||||
|
#define PRIdMAX "lld"
|
||||||
|
#define PRIuMAX "llu"
|
||||||
|
#define PRIxMAX "llx"
|
||||||
|
#define INTMAX_C(x) (x##LL)
|
||||||
|
#define UINTMAX_C(x) (x##ULL)
|
||||||
|
#else
|
||||||
|
typedef long intmax_t;
|
||||||
|
typedef unsigned long uintmax_t;
|
||||||
|
#define PRIdMAX "ld"
|
||||||
|
#define PRIuMAX "lu"
|
||||||
|
#define PRIxMAX "lx"
|
||||||
|
#define INTMAX_C(x) (x##L)
|
||||||
|
#define UINTMAX_C(x) (x##UL)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* On some version of AIX, <inttypes.h> is buggy to the point of
|
||||||
|
unusability. We have to use macros here, not typedefs, to override. */
|
||||||
|
#ifdef HAVE_INTTYPES_H
|
||||||
|
#ifndef INTTYPES_H_IS_SANE
|
||||||
|
#undef PRIdMAX
|
||||||
|
#undef PRIuMAX
|
||||||
|
#undef PRIxMAX
|
||||||
|
#undef INTMAX_C
|
||||||
|
#undef UINTMAX_C
|
||||||
|
#undef HAVE_STRTOUMAX
|
||||||
|
|
||||||
|
#ifdef HAVE_LONG_LONG
|
||||||
|
#define intmax_t long long
|
||||||
|
#define uintmax_t unsigned long long
|
||||||
|
#define PRIdMAX "Ld"
|
||||||
|
#define PRIuMAX "Lu"
|
||||||
|
#define PRIxMAX "Lx"
|
||||||
|
#define INTMAX_C(x) (x##LL)
|
||||||
|
#define UINTMAX_C(x) (x##ULL)
|
||||||
|
#else
|
||||||
|
#define intmax_t long
|
||||||
|
#define uintmax_t unsigned long
|
||||||
|
#define PRIdMAX "ld"
|
||||||
|
#define PRIuMAX "lu"
|
||||||
|
#define PRIxMAX "lx"
|
||||||
|
#define INTMAX_C(x) (x##L)
|
||||||
|
#define UINTMAX_C(x) (x##UL)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Even if intmax_t is defined, we may need this (Solaris 8 braindamage) */
|
||||||
|
#ifndef HAVE_STRTOUMAX
|
||||||
|
#if defined(HAVE_LONG_LONG) && defined(HAVE_STRTOULL)
|
||||||
|
#define strtoumax(p,e,b) ((uintmax_t)strtoull(p,e,b))
|
||||||
|
#else
|
||||||
|
#define strtoumax(p,e,b) ((uintmax_t)strtoul(p,e,b))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A lot of this is old BSD code. Some newer systems don't approve. */
|
||||||
|
|
||||||
|
/* The type used by htons(), ntohs() */
|
||||||
|
#ifndef HAVE_U_SHORT
|
||||||
|
#ifdef HAVE_UINT16_T
|
||||||
|
typedef uint16_t u_short;
|
||||||
|
#else
|
||||||
|
typedef unsigned short u_short;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The type used to htonl(), ntohl() */
|
||||||
|
#ifndef HAVE_U_LONG
|
||||||
|
#ifdef HAVE_UINT32_T
|
||||||
|
typedef uint32_t u_long;
|
||||||
|
#else
|
||||||
|
typedef unsigned long u_long;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* socklen_t */
|
||||||
|
#ifndef HAVE_SOCKLEN_T
|
||||||
|
typedef int socklen_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* sysexits.h */
|
||||||
|
|
||||||
|
#ifdef HAVE_SYSEXITS_H
|
||||||
|
#include <sysexits.h>
|
||||||
|
#else
|
||||||
|
#define EX_USAGE 64 /* command line usage error */
|
||||||
|
#define EX_DATAERR 65 /* data format error */
|
||||||
|
#define EX_NOINPUT 66 /* cannot open input */
|
||||||
|
#define EX_NOUSER 67 /* addressee unknown */
|
||||||
|
#define EX_NOHOST 68 /* host name unknown */
|
||||||
|
#define EX_UNAVAILABLE 69 /* service unavailable */
|
||||||
|
#define EX_SOFTWARE 70 /* internal software error */
|
||||||
|
#define EX_OSERR 71 /* system error (e.g., can't fork) */
|
||||||
|
#define EX_OSFILE 72 /* critical OS file missing */
|
||||||
|
#define EX_CANTCREAT 73 /* can't create (user) output file */
|
||||||
|
#define EX_IOERR 74 /* input/output error */
|
||||||
|
#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
|
||||||
|
#define EX_PROTOCOL 76 /* remote error in protocol */
|
||||||
|
#define EX_NOPERM 77 /* permission denied */
|
||||||
|
#define EX_CONFIG 78 /* configuration error */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we don't have sigsetjmp() et all, setjmp() will have to do */
|
||||||
|
|
||||||
|
#ifndef HAVE_SIGSETJMP
|
||||||
|
#define sigsetjmp(x,y) setjmp(x)
|
||||||
|
#define siglongjmp(x,y) longjmp(x,y)
|
||||||
|
#define sigjmp_buf jmp_buf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* How do we annotate unused data items? */
|
||||||
|
|
||||||
|
#ifndef UNUSED
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define UNUSED __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define UNUSED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* netinet/in.h, and possible missing pieces */
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#ifndef HAVE_IPPORT_TFTP_DEFINITION
|
||||||
|
#ifndef IPPORT_TFTP
|
||||||
|
#define IPPORT_TFTP 69
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* arpa/{inet,tftp}.h, and possible missing pieces */
|
||||||
|
|
||||||
|
#ifdef HAVE_ARPA_INET_H
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#endif
|
||||||
|
/* If we don't have arpa/tftp.h we have problems... */
|
||||||
|
#include <arpa/tftp.h>
|
||||||
|
|
||||||
|
#ifndef OACK
|
||||||
|
#define OACK 6
|
||||||
|
#endif
|
||||||
|
#ifndef EOPTNEG
|
||||||
|
#define EOPTNEG 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Prototypes for libxtra functions */
|
||||||
|
|
||||||
|
void *xmalloc(size_t);
|
||||||
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
|
#ifndef HAVE_BSD_SIGNAL
|
||||||
|
void (*bsd_signal(int, void (*)(int))) (int);
|
||||||
|
#endif
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
#define WITH_READLINE_STR ", with readline"
|
||||||
|
#else
|
||||||
|
#define WITH_READLINE_STR ", without readline"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_REGEX
|
||||||
|
#define WITH_REGEX_STR ", with remap"
|
||||||
|
#else
|
||||||
|
#define WITH_REGEX_STR ", without remap"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBWRAP
|
||||||
|
#define HAVE_LIBWRAP_STR ", with tcpwrappers"
|
||||||
|
#else
|
||||||
|
#define HAVE_LIBWRAP_STR ", without tcpwrappers"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TFTP_CONFIG_STR VERSION WITH_READLINE_STR
|
||||||
|
#define TFTPD_CONFIG_STR VERSION WITH_REGEX_STR HAVE_LIBWRAP_STR
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,303 @@
|
||||||
|
dnl
|
||||||
|
dnl autoconf input file to generate MCONFIG
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_PREREQ(2.61)
|
||||||
|
AC_INIT(MCONFIG.in)
|
||||||
|
AC_PREFIX_DEFAULT(/usr)
|
||||||
|
|
||||||
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
|
AC_ISC_POSIX
|
||||||
|
AC_PROG_CC
|
||||||
|
|
||||||
|
AC_C_CONST
|
||||||
|
AC_C_INLINE
|
||||||
|
|
||||||
|
PA_ADD_CFLAGS(-W)
|
||||||
|
PA_ADD_CFLAGS(-Wall)
|
||||||
|
PA_ADD_CFLAGS(-Wpointer-arith)
|
||||||
|
PA_ADD_CFLAGS(-Wbad-function-cast)
|
||||||
|
PA_ADD_CFLAGS(-Wcast-equal)
|
||||||
|
PA_ADD_CFLAGS(-Wstrict-prototypes)
|
||||||
|
PA_ADD_CFLAGS(-Wmissing-prototypes)
|
||||||
|
PA_ADD_CFLAGS(-Wmissing-declarations)
|
||||||
|
PA_ADD_CFLAGS(-Wnested-externs)
|
||||||
|
PA_ADD_CFLAGS(-Winline)
|
||||||
|
PA_ADD_CFLAGS(-Wwrite-strings)
|
||||||
|
PA_ADD_CFLAGS(-Wundef)
|
||||||
|
PA_ADD_CFLAGS(-Wshadow)
|
||||||
|
PA_ADD_CFLAGS(-Wsign-compare)
|
||||||
|
PA_ADD_CFLAGS(-pipe)
|
||||||
|
PA_ADD_CFLAGS(-fno-strict-aliasing)
|
||||||
|
|
||||||
|
AC_HEADER_STDC
|
||||||
|
AC_CHECK_HEADERS(inttypes.h)
|
||||||
|
AC_CHECK_HEADERS(stdint.h)
|
||||||
|
PA_CHECK_INTTYPES_H_SANE
|
||||||
|
AC_CHECK_HEADERS(fcntl.h)
|
||||||
|
AC_CHECK_HEADERS(grp.h)
|
||||||
|
AC_CHECK_HEADERS(libgen.h)
|
||||||
|
AC_CHECK_HEADERS(memory.h)
|
||||||
|
AC_CHECK_HEADERS(setjmp.h)
|
||||||
|
AC_CHECK_HEADERS(stddef.h)
|
||||||
|
AC_CHECK_HEADERS(stdlib.h)
|
||||||
|
AC_CHECK_HEADERS(string.h)
|
||||||
|
AC_CHECK_HEADERS(strings.h)
|
||||||
|
AC_CHECK_HEADERS(sysexits.h)
|
||||||
|
AC_CHECK_HEADERS(time.h)
|
||||||
|
AC_CHECK_HEADERS(unistd.h)
|
||||||
|
AC_CHECK_HEADERS(sys/file.h)
|
||||||
|
AC_CHECK_HEADERS(sys/filio.h)
|
||||||
|
AC_CHECK_HEADERS(sys/stat.h)
|
||||||
|
AC_CHECK_HEADERS(sys/time.h)
|
||||||
|
AC_CHECK_HEADERS(sys/types.h)
|
||||||
|
AC_CHECK_HEADERS(arpa/inet.h)
|
||||||
|
AC_CHECK_HEADERS(netdb.h)
|
||||||
|
AC_HEADER_TIME
|
||||||
|
dnl This is needed on some versions of FreeBSD...
|
||||||
|
AC_CHECK_HEADERS(machine/param.h)
|
||||||
|
AC_CHECK_HEADERS(sys/socket.h)
|
||||||
|
AC_CHECK_HEADERS(winsock2.h)
|
||||||
|
AC_CHECK_HEADERS(winsock.h)
|
||||||
|
|
||||||
|
AC_SYS_LARGEFILE
|
||||||
|
|
||||||
|
AC_TYPE_OFF_T
|
||||||
|
AC_TYPE_PID_T
|
||||||
|
AC_TYPE_MODE_T
|
||||||
|
AC_TYPE_SIZE_T
|
||||||
|
AC_CHECK_TYPES(intmax_t)
|
||||||
|
AC_CHECK_TYPES(long long)
|
||||||
|
AC_CHECK_TYPES(uint16_t)
|
||||||
|
AC_CHECK_TYPES(uint32_t)
|
||||||
|
AC_CHECK_TYPES(u_short)
|
||||||
|
AC_CHECK_TYPES(u_long)
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl <sys/socket.h> isn't among the list of standard headers that autoconf checks,
|
||||||
|
dnl but POSIX requires <sys/socket.h> for socklen_t to be defined.
|
||||||
|
dnl
|
||||||
|
AC_CHECK_TYPES(socklen_t,,,
|
||||||
|
[
|
||||||
|
#include <stdio.h>
|
||||||
|
#if HAVE_SYS_TYPES_H
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#if HAVE_SYS_STAT_H
|
||||||
|
# include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
#if STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# if HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if HAVE_STRING_H
|
||||||
|
# if !STDC_HEADERS && HAVE_MEMORY_H
|
||||||
|
# include <memory.h>
|
||||||
|
# endif
|
||||||
|
# include <string.h>
|
||||||
|
#endif
|
||||||
|
#if HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
#endif
|
||||||
|
#if HAVE_INTTYPES_H
|
||||||
|
# include <inttypes.h>
|
||||||
|
#else
|
||||||
|
# if HAVE_STDINT_H
|
||||||
|
# include <stdint.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
# include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], , [AC_MSG_ERROR(socket library not found)])
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS(fcntl)
|
||||||
|
AC_CHECK_FUNCS(setsid)
|
||||||
|
AC_CHECK_FUNCS(recvmsg)
|
||||||
|
AC_CHECK_FUNCS(ftruncate)
|
||||||
|
AC_CHECK_FUNCS(setreuid)
|
||||||
|
AC_CHECK_FUNCS(setregid)
|
||||||
|
AC_CHECK_FUNCS(initgroups)
|
||||||
|
AC_CHECK_FUNCS(setgroups)
|
||||||
|
|
||||||
|
dnl Solaris 8 has [u]intmax_t but not strtoumax(). How utterly braindamaged.
|
||||||
|
AC_CHECK_FUNCS(strtoumax)
|
||||||
|
AC_CHECK_FUNCS(strtoull)
|
||||||
|
|
||||||
|
PA_MSGHDR_MSG_CONTROL
|
||||||
|
PA_STRUCT_IN_PKTINFO
|
||||||
|
PA_STRUCT_ADDRINFO
|
||||||
|
|
||||||
|
PA_HEADER_DEFINES(fcntl.h, int, O_NONBLOCK)
|
||||||
|
PA_HEADER_DEFINES(fcntl.h, int, O_BINARY)
|
||||||
|
PA_HEADER_DEFINES(fcntl.h, int, O_TEXT)
|
||||||
|
|
||||||
|
PA_HEADER_DEFINES(fcntl.h, int, F_SETLK)
|
||||||
|
|
||||||
|
PA_HEADER_DEFINES(sys/file.h, int, LOCK_SH)
|
||||||
|
PA_HEADER_DEFINES(sys/file.h, int, LOCK_EX)
|
||||||
|
|
||||||
|
AH_TEMPLATE([HAVE_SIGSETJMP],
|
||||||
|
[Define if we have sigsetjmp, siglongjmp and sigjmp_buf.])
|
||||||
|
PA_SIGSETJMP([AC_DEFINE(HAVE_SIGSETJMP)])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Get common paths
|
||||||
|
dnl
|
||||||
|
SRCROOT=`cd $srcdir && pwd`
|
||||||
|
OBJROOT=`pwd`
|
||||||
|
|
||||||
|
XTRA=false
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(xmalloc, iberty)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(xstrdup, iberty)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(bsd_signal, bsd, bsdsignal)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(getopt_long, getopt, getopt_long)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(getaddrinfo, [nsl resolv])
|
||||||
|
if $pa_add_getaddrinfo
|
||||||
|
then
|
||||||
|
AC_SEARCH_LIBS(gethostbyname, [nsl resolv],
|
||||||
|
[AC_SEARCH_LIBS(herror, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(herror not found)])],
|
||||||
|
[AC_MSG_ERROR(gethostbyname not found)])
|
||||||
|
else
|
||||||
|
AC_SEARCH_LIBS(freeaddrinfo, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(getaddrinfo but not freeaddrinfo found)])
|
||||||
|
AC_SEARCH_LIBS(gai_strerror, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(getaddrinfo but not gai_strerror found)])
|
||||||
|
fi
|
||||||
|
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(inet_ntop, [nsl resolv])
|
||||||
|
if $pa_add_inet_ntop
|
||||||
|
then
|
||||||
|
AC_SEARCH_LIBS(inet_ntoa, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(inet_ntoa not found)])
|
||||||
|
fi
|
||||||
|
AC_SEARCH_LIBS(inet_aton, [nsl resolv], ,[AC_MSG_ERROR(inet_aton not found)])
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS(daemon, , [XTRA=true; AC_LIBOBJ(daemon)])
|
||||||
|
AC_CHECK_FUNCS(dup2, , [XTRA=true; AC_LIBOBJ(dup2)])
|
||||||
|
if $XTRA
|
||||||
|
then
|
||||||
|
XTRALIBS="$OBJROOT/lib/libxtra.a $XTRALIBS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl These libraries apply to the server only
|
||||||
|
dnl
|
||||||
|
|
||||||
|
common_libs="$LIBS"
|
||||||
|
|
||||||
|
PA_HEADER_DEFINES(netinet/in.h, int, IPPORT_TFTP)
|
||||||
|
|
||||||
|
PA_WITH_BOOL(tcpwrappers, 1,
|
||||||
|
[ --without-tcpwrappers disable tcpwrapper permissions checking],
|
||||||
|
[
|
||||||
|
AC_SEARCH_LIBS(yp_get_default_domain, [nsl resolv])
|
||||||
|
PA_HAVE_TCPWRAPPERS
|
||||||
|
],:)
|
||||||
|
|
||||||
|
|
||||||
|
AH_TEMPLATE([WITH_REGEX],
|
||||||
|
[Define if we are compiling with regex filename remapping.])
|
||||||
|
|
||||||
|
PA_WITH_BOOL(remap, 1,
|
||||||
|
[ --without-remap disable regex-based filename remapping],
|
||||||
|
[
|
||||||
|
AC_CHECK_HEADER(regex.h,
|
||||||
|
[
|
||||||
|
AC_SEARCH_LIBS(regcomp, [regex rx],
|
||||||
|
[
|
||||||
|
AC_DEFINE(WITH_REGEX)
|
||||||
|
TFTPDOBJS="remap.${OBJEXT} $TFTPDOBJS"
|
||||||
|
])
|
||||||
|
])
|
||||||
|
],:)
|
||||||
|
|
||||||
|
TFTPD_LIBS="$LIBS $XTRALIBS"
|
||||||
|
LIBS="$common_libs"
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl These libraries apply to the client only
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AH_TEMPLATE([WITH_READLINE],
|
||||||
|
[Define if we are compiling with readline/editline command-line editing.])
|
||||||
|
|
||||||
|
PA_WITH_BOOL(readline, 1,
|
||||||
|
[ --without-readline disable the use of readline command-line editing],
|
||||||
|
[
|
||||||
|
AC_CHECK_HEADER(readline/readline.h,
|
||||||
|
[
|
||||||
|
dnl readline may need libtermcap or somesuch...
|
||||||
|
AC_SEARCH_LIBS(tputs, [termcap terminfo])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(readline, [readline history],
|
||||||
|
[AC_DEFINE(WITH_READLINE)])
|
||||||
|
AC_CHECK_HEADERS(readline/history.h)
|
||||||
|
],
|
||||||
|
[AC_CHECK_HEADER(editline/readline.h,
|
||||||
|
[
|
||||||
|
dnl editline may need libtermcap or somesuch...
|
||||||
|
AC_SEARCH_LIBS(tputs, [termcap terminfo])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(editline, [edit],
|
||||||
|
[AC_DEFINE(WITH_READLINE)])
|
||||||
|
])])
|
||||||
|
],:)
|
||||||
|
|
||||||
|
TFTP_LIBS="$LIBS $XTRALIBS"
|
||||||
|
LIBS="$common_libs"
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Check for IPV6 and disable-ipv6
|
||||||
|
dnl
|
||||||
|
PA_STRUCT_SOCKADDR_IN6
|
||||||
|
AC_MSG_CHECKING([for IPv6 support])
|
||||||
|
PA_WITH_BOOL(ipv6, 1,
|
||||||
|
[ --without-ipv6 disable the support for IPv6],
|
||||||
|
[
|
||||||
|
if $HAVE_INET6
|
||||||
|
then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_IPV6, 1, [Define if IPv6 support is enabled.])
|
||||||
|
PA_STRUCT_IN6_PKTINFO
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
AC_MSG_WARN([*** we do not have required IPv6 structs - IPv6 will be disabled])
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
[AC_MSG_RESULT(disabled)])
|
||||||
|
|
||||||
|
|
||||||
|
AC_SUBST(SRCROOT)
|
||||||
|
AC_SUBST(OBJROOT)
|
||||||
|
|
||||||
|
AC_SUBST(TFTP_LIBS)
|
||||||
|
AC_SUBST(TFTPD_LIBS)
|
||||||
|
AC_SUBST(TFTPDOBJS)
|
||||||
|
|
||||||
|
AC_PROG_LN_S
|
||||||
|
AC_PROG_RANLIB
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Make sure the install program has an absolute path if it
|
||||||
|
dnl has a path at all. autoconf doesn't do this "in order
|
||||||
|
dnl to not pollute the cache." Sigh.
|
||||||
|
dnl Note: the $ needs to be double-quoted for reasons unknown.
|
||||||
|
dnl
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
[if echo "$INSTALL" | grep '^[^/].*/' > /dev/null 2>&1; then
|
||||||
|
INSTALL='\${SRCROOT}'/"$INSTALL"
|
||||||
|
fi]
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS(aconfig.h)
|
||||||
|
AC_OUTPUT(MCONFIG)
|
|
@ -0,0 +1,251 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# install - install a program, script, or datafile
|
||||||
|
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||||
|
#
|
||||||
|
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
# documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
# the above copyright notice appear in all copies and that both that
|
||||||
|
# copyright notice and this permission notice appear in supporting
|
||||||
|
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||||
|
# publicity pertaining to distribution of the software without specific,
|
||||||
|
# written prior permission. M.I.T. makes no representations about the
|
||||||
|
# suitability of this software for any purpose. It is provided "as is"
|
||||||
|
# without express or implied warranty.
|
||||||
|
#
|
||||||
|
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||||
|
# `make' implicit rules from creating a file called install from it
|
||||||
|
# when there is no Makefile.
|
||||||
|
#
|
||||||
|
# This script is compatible with the BSD install script, but was written
|
||||||
|
# from scratch. It can only install one file at a time, a restriction
|
||||||
|
# shared with many OS's install programs.
|
||||||
|
|
||||||
|
|
||||||
|
# set DOITPROG to echo to test this script
|
||||||
|
|
||||||
|
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||||
|
doit="${DOITPROG-}"
|
||||||
|
|
||||||
|
|
||||||
|
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||||
|
|
||||||
|
mvprog="${MVPROG-mv}"
|
||||||
|
cpprog="${CPPROG-cp}"
|
||||||
|
chmodprog="${CHMODPROG-chmod}"
|
||||||
|
chownprog="${CHOWNPROG-chown}"
|
||||||
|
chgrpprog="${CHGRPPROG-chgrp}"
|
||||||
|
stripprog="${STRIPPROG-strip}"
|
||||||
|
rmprog="${RMPROG-rm}"
|
||||||
|
mkdirprog="${MKDIRPROG-mkdir}"
|
||||||
|
|
||||||
|
transformbasename=""
|
||||||
|
transform_arg=""
|
||||||
|
instcmd="$mvprog"
|
||||||
|
chmodcmd="$chmodprog 0755"
|
||||||
|
chowncmd=""
|
||||||
|
chgrpcmd=""
|
||||||
|
stripcmd=""
|
||||||
|
rmcmd="$rmprog -f"
|
||||||
|
mvcmd="$mvprog"
|
||||||
|
src=""
|
||||||
|
dst=""
|
||||||
|
dir_arg=""
|
||||||
|
|
||||||
|
while [ x"$1" != x ]; do
|
||||||
|
case $1 in
|
||||||
|
-c) instcmd="$cpprog"
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-d) dir_arg=true
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-m) chmodcmd="$chmodprog $2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-o) chowncmd="$chownprog $2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-g) chgrpcmd="$chgrpprog $2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-s) stripcmd="$stripprog"
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
*) if [ x"$src" = x ]
|
||||||
|
then
|
||||||
|
src=$1
|
||||||
|
else
|
||||||
|
# this colon is to work around a 386BSD /bin/sh bug
|
||||||
|
:
|
||||||
|
dst=$1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ x"$src" = x ]
|
||||||
|
then
|
||||||
|
echo "install: no input file specified"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$dir_arg" != x ]; then
|
||||||
|
dst=$src
|
||||||
|
src=""
|
||||||
|
|
||||||
|
if [ -d $dst ]; then
|
||||||
|
instcmd=:
|
||||||
|
chmodcmd=""
|
||||||
|
else
|
||||||
|
instcmd=$mkdirprog
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
|
||||||
|
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||||
|
# might cause directories to be created, which would be especially bad
|
||||||
|
# if $src (and thus $dsttmp) contains '*'.
|
||||||
|
|
||||||
|
if [ -f $src -o -d $src ]
|
||||||
|
then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo "install: $src does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$dst" = x ]
|
||||||
|
then
|
||||||
|
echo "install: no destination specified"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If destination is a directory, append the input filename; if your system
|
||||||
|
# does not like double slashes in filenames, you may need to add some logic
|
||||||
|
|
||||||
|
if [ -d $dst ]
|
||||||
|
then
|
||||||
|
dst="$dst"/`basename $src`
|
||||||
|
else
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
## this sed command emulates the dirname command
|
||||||
|
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||||
|
|
||||||
|
# Make sure that the destination directory exists.
|
||||||
|
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||||
|
|
||||||
|
# Skip lots of stat calls in the usual case.
|
||||||
|
if [ ! -d "$dstdir" ]; then
|
||||||
|
defaultIFS='
|
||||||
|
'
|
||||||
|
IFS="${IFS-${defaultIFS}}"
|
||||||
|
|
||||||
|
oIFS="${IFS}"
|
||||||
|
# Some sh's can't handle IFS=/ for some reason.
|
||||||
|
IFS='%'
|
||||||
|
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||||
|
IFS="${oIFS}"
|
||||||
|
|
||||||
|
pathcomp=''
|
||||||
|
|
||||||
|
while [ $# -ne 0 ] ; do
|
||||||
|
pathcomp="${pathcomp}${1}"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ ! -d "${pathcomp}" ] ;
|
||||||
|
then
|
||||||
|
$mkdirprog "${pathcomp}"
|
||||||
|
else
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
|
||||||
|
pathcomp="${pathcomp}/"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$dir_arg" != x ]
|
||||||
|
then
|
||||||
|
$doit $instcmd $dst &&
|
||||||
|
|
||||||
|
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
|
||||||
|
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
|
||||||
|
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
|
||||||
|
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
|
||||||
|
else
|
||||||
|
|
||||||
|
# If we're going to rename the final executable, determine the name now.
|
||||||
|
|
||||||
|
if [ x"$transformarg" = x ]
|
||||||
|
then
|
||||||
|
dstfile=`basename $dst`
|
||||||
|
else
|
||||||
|
dstfile=`basename $dst $transformbasename |
|
||||||
|
sed $transformarg`$transformbasename
|
||||||
|
fi
|
||||||
|
|
||||||
|
# don't allow the sed command to completely eliminate the filename
|
||||||
|
|
||||||
|
if [ x"$dstfile" = x ]
|
||||||
|
then
|
||||||
|
dstfile=`basename $dst`
|
||||||
|
else
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make a temp file name in the proper directory.
|
||||||
|
|
||||||
|
dsttmp=$dstdir/#inst.$$#
|
||||||
|
|
||||||
|
# Move or copy the file name to the temp name
|
||||||
|
|
||||||
|
$doit $instcmd $src $dsttmp &&
|
||||||
|
|
||||||
|
trap "rm -f ${dsttmp}" 0 &&
|
||||||
|
|
||||||
|
# and set any options; do chmod last to preserve setuid bits
|
||||||
|
|
||||||
|
# If any of these fail, we abort the whole thing. If we want to
|
||||||
|
# ignore errors from any of these, just make sure not to ignore
|
||||||
|
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||||
|
|
||||||
|
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
|
||||||
|
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
|
||||||
|
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
|
||||||
|
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
|
||||||
|
|
||||||
|
# Now rename the file to the real destination.
|
||||||
|
|
||||||
|
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||||
|
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||||
|
|
||||||
|
fi &&
|
||||||
|
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,29 @@
|
||||||
|
#
|
||||||
|
# Extra functions which may not be available everywhere
|
||||||
|
#
|
||||||
|
|
||||||
|
SRCROOT = ..
|
||||||
|
|
||||||
|
-include ../MCONFIG
|
||||||
|
include ../MRULES
|
||||||
|
|
||||||
|
ifeq ($(LIBOBJS),)
|
||||||
|
all:
|
||||||
|
else
|
||||||
|
all: libxtra.a
|
||||||
|
endif
|
||||||
|
|
||||||
|
install:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f *.a *.o *.obj *.exe
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
-rm -f *~
|
||||||
|
|
||||||
|
libxtra.a: $(LIBOBJS)
|
||||||
|
-rm -f libxtra.a
|
||||||
|
$(AR) libxtra.a $(LIBOBJS)
|
||||||
|
$(RANLIB) libxtra.a
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* bsdsignal.c
|
||||||
|
*
|
||||||
|
* Use sigaction() to simulate BSD signal()
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void (*bsd_signal(int signum, void (*handler) (int))) (int) {
|
||||||
|
struct sigaction action, oldaction;
|
||||||
|
|
||||||
|
memset(&action, 0, sizeof action);
|
||||||
|
action.sa_handler = handler;
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
sigaddset(&action.sa_mask, signum);
|
||||||
|
action.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
|
if (sigaction(signum, &action, &oldaction) == -1) {
|
||||||
|
#ifdef SIG_ERR
|
||||||
|
return SIG_ERR;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldaction.sa_handler;
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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 '?';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* xmalloc.c
|
||||||
|
*
|
||||||
|
* Simple error-checking version of malloc()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void *xmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *p = malloc(size);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
fprintf(stderr, "Out of memory!\n");
|
||||||
|
exit(128);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* xstrdup.c
|
||||||
|
*
|
||||||
|
* Simple error-checking version of strdup()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
char *xstrdup(const char *s)
|
||||||
|
{
|
||||||
|
char *p = strdup(s);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
fprintf(stderr, "Out of memory!\n");
|
||||||
|
exit(128);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
# default: off
|
||||||
|
# description: The tftp server serves files using the trivial file transfer \
|
||||||
|
# protocol. The tftp protocol is often used to boot diskless \
|
||||||
|
# workstations, download configuration files to network-aware printers, \
|
||||||
|
# and to start the installation process for some operating systems.
|
||||||
|
service tftp
|
||||||
|
{
|
||||||
|
socket_type = dgram
|
||||||
|
protocol = udp
|
||||||
|
wait = yes
|
||||||
|
user = root
|
||||||
|
server = /usr/sbin/in.tftpd
|
||||||
|
server_args = -s /tftpboot
|
||||||
|
disable = yes
|
||||||
|
per_source = 11
|
||||||
|
cps = 100 2
|
||||||
|
flags = IPv4
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
Summary: The client for the Trivial File Transfer Protocol (TFTP).
|
||||||
|
Name: tftp
|
||||||
|
Version: 5.2
|
||||||
|
Release: 1
|
||||||
|
License: BSD
|
||||||
|
Group: Applications/Internet
|
||||||
|
Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{version}.tar.gz
|
||||||
|
BuildRequires: tcp_wrappers-devel
|
||||||
|
BuildRoot: %{_tmppath}/%{name}-root
|
||||||
|
|
||||||
|
%description
|
||||||
|
The Trivial File Transfer Protocol (TFTP) is normally used only for
|
||||||
|
booting diskless workstations. The tftp package provides the user
|
||||||
|
interface for TFTP, which allows users to transfer files to and from a
|
||||||
|
remote machine. This program and TFTP provide very little security,
|
||||||
|
and should not be enabled unless it is expressly needed.
|
||||||
|
|
||||||
|
%package server
|
||||||
|
Group: System Environment/Daemons
|
||||||
|
Summary: The server for the Trivial File Transfer Protocol (TFTP).
|
||||||
|
Requires: xinetd
|
||||||
|
|
||||||
|
%description server
|
||||||
|
The Trivial File Transfer Protocol (TFTP) is normally used only for
|
||||||
|
booting diskless workstations. The tftp-server package provides the
|
||||||
|
server for TFTP, which allows users to transfer files to and from a
|
||||||
|
remote machine. TFTP provides very little security, and should not be
|
||||||
|
enabled unless it is expressly needed. The TFTP server is run from
|
||||||
|
/etc/xinetd.d/tftp, and is disabled by default on Red Hat Linux systems.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q -n tftp-hpa-%{version}
|
||||||
|
|
||||||
|
%build
|
||||||
|
|
||||||
|
%configure
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
|
%install
|
||||||
|
rm -rf ${RPM_BUILD_ROOT}
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man{1,8}
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_sbindir}
|
||||||
|
|
||||||
|
make INSTALLROOT=${RPM_BUILD_ROOT} \
|
||||||
|
SBINDIR=%{_sbindir} MANDIR=%{_mandir} \
|
||||||
|
install
|
||||||
|
install -m755 -d ${RPM_BUILD_ROOT}%{_sysconfdir}/xinetd.d/ ${RPM_BUILD_ROOT}/tftpboot
|
||||||
|
install -m644 tftp-xinetd ${RPM_BUILD_ROOT}%{_sysconfdir}/xinetd.d/tftp
|
||||||
|
|
||||||
|
%post server
|
||||||
|
/sbin/service xinetd reload > /dev/null 2>&1 || :
|
||||||
|
|
||||||
|
%postun server
|
||||||
|
if [ $1 = 0 ]; then
|
||||||
|
/sbin/service xinetd reload > /dev/null 2>&1 || :
|
||||||
|
fi
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf ${RPM_BUILD_ROOT}
|
||||||
|
|
||||||
|
%files
|
||||||
|
%defattr(-,root,root)
|
||||||
|
%{_bindir}/tftp
|
||||||
|
%{_mandir}/man1/*
|
||||||
|
|
||||||
|
%files server
|
||||||
|
%defattr(-,root,root)
|
||||||
|
%config(noreplace) %{_sysconfdir}/xinetd.d/tftp
|
||||||
|
%dir /tftpboot
|
||||||
|
%{_sbindir}/in.tftpd
|
||||||
|
%{_mandir}/man8/*
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Tue Sep 14 2004 H. Peter Anvin <hpa@zytor.com>
|
||||||
|
- removed completely broken "Malta" patch.
|
||||||
|
- integrated into build machinery so rpm -ta works.
|
||||||
|
|
||||||
|
* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Fri Apr 11 2003 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- 0.33
|
||||||
|
- Add /tftpboot directory (#88204)
|
||||||
|
|
||||||
|
* Mon Feb 24 2003 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Sun Feb 23 2003 Tim Powers <timp@redhat.com>
|
||||||
|
- add BuildPreReq on tcp_wrappers
|
||||||
|
|
||||||
|
* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Mon Nov 11 2002 Elliot Lee <sopwith@redhat.com> 0.32-1
|
||||||
|
- Update to 0.32
|
||||||
|
|
||||||
|
* Wed Oct 23 2002 Elliot Lee <sopwith@redhat.com> 0.30-1
|
||||||
|
- Fix #55789
|
||||||
|
- Update to 0.30
|
||||||
|
|
||||||
|
* Thu Jun 27 2002 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- Try applying HJ's patch from #65476
|
||||||
|
|
||||||
|
* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
|
||||||
|
- automated rebuild
|
||||||
|
|
||||||
|
* Mon Jun 17 2002 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- Update to 0.29
|
||||||
|
|
||||||
|
* Thu May 23 2002 Tim Powers <timp@redhat.com>
|
||||||
|
- automated rebuild
|
||||||
|
|
||||||
|
* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
|
||||||
|
- automated rebuild
|
||||||
|
|
||||||
|
* Tue Dec 18 2001 Elliot Lee <sopwith@redhat.com> 0.17-15
|
||||||
|
- Add patch4: netkit-tftp-0.17-defaultport.patch for bug #57562
|
||||||
|
- Update to tftp-hpa-0.28 (bug #56131)
|
||||||
|
- Remove include/arpa/tftp.h to fix #57259
|
||||||
|
- Add resource limits in tftp-xinetd (#56722)
|
||||||
|
|
||||||
|
* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- Bump release + rebuild.
|
||||||
|
|
||||||
|
* Tue Jun 12 2001 Helge Deller <hdeller@redhat.de> (0.17-13)
|
||||||
|
- updated tftp-hpa source to tftp-hpa-0.17
|
||||||
|
- tweaked specfile with different defines for tftp-netkit and tftp-hpa version
|
||||||
|
- use hpa's tftpd.8 man page instead of the netkits one
|
||||||
|
|
||||||
|
* Mon May 07 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- rebuilt in 7.1.x
|
||||||
|
|
||||||
|
* Wed Apr 18 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- fix tftp client's put problems (#29529)
|
||||||
|
- update to tftp-hpa-0.16
|
||||||
|
|
||||||
|
* Wed Apr 4 2001 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
- don't let configure to guess compiler, it can pick up egcs
|
||||||
|
|
||||||
|
* Thu Feb 08 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- changed "wait" in xinetd file to "yes" (hpa-tftpd forks and exits) (#26467)
|
||||||
|
- fixed hpa-tftpd to handle files greater than 32MB (#23725)
|
||||||
|
- added "-l" flag to hpa-tftpd for file-logging (#26467)
|
||||||
|
- added description for "-l" to the man-page
|
||||||
|
|
||||||
|
* Thu Feb 08 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- updated tftp client to 0.17 stable (#19640),
|
||||||
|
- drop dependency on xinetd for tftp client (#25051),
|
||||||
|
|
||||||
|
* Wed Jan 17 2001 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- xinetd shouldn't wait on tftp (which forks) (#23923).
|
||||||
|
|
||||||
|
* Sat Jan 6 2001 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- fix to permit tftp put's (#18128).
|
||||||
|
- startup as root with chroot to /tftpboot with early reversion to nobody
|
||||||
|
is preferable to starting as nobody w/o ability to chroot.
|
||||||
|
- %%post is needed by server, not client. Add %%postun for erasure as well.
|
||||||
|
|
||||||
|
* Wed Aug 23 2000 Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
- default to being disabled
|
||||||
|
|
||||||
|
* Thu Aug 17 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- correct group.
|
||||||
|
|
||||||
|
* Tue Jul 25 2000 Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
- change user from root to nobody
|
||||||
|
|
||||||
|
* Sat Jul 22 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- update to tftp-hpa-0.14 (#14003).
|
||||||
|
- add server_args (#14003).
|
||||||
|
- remove -D_BSD_SOURCE (#14003).
|
||||||
|
|
||||||
|
* Fri Jul 21 2000 Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
- cook up an xinetd config file for tftpd
|
||||||
|
|
||||||
|
* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
|
||||||
|
- automatic rebuild
|
||||||
|
|
||||||
|
* Sun Jun 18 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- FHS packaging.
|
||||||
|
- update to 0.17.
|
||||||
|
|
||||||
|
* Fri May 5 2000 Matt Wilson <msw@redhat.com>
|
||||||
|
- use _BSD_SOURCE for hpa's tftpd so we get BSD signal semantics.
|
||||||
|
|
||||||
|
* Fri Feb 11 2000 Bill Nottingham <notting@redhat.com>
|
||||||
|
- fix description
|
||||||
|
|
||||||
|
* Wed Feb 9 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- compress man pages (again).
|
||||||
|
|
||||||
|
* Wed Feb 02 2000 Cristian Gafton <gafton@redhat.com>
|
||||||
|
- man pages are compressed
|
||||||
|
- fix description and summary
|
||||||
|
|
||||||
|
* Tue Jan 4 2000 Bill Nottingham <notting@redhat.com>
|
||||||
|
- split client and server
|
||||||
|
|
||||||
|
* Tue Dec 21 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- update to 0.16.
|
||||||
|
|
||||||
|
* Sat Aug 28 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- update to 0.15.
|
||||||
|
|
||||||
|
* Wed Apr 7 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- tftpd should truncate file when overwriting (#412)
|
||||||
|
|
||||||
|
* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com>
|
||||||
|
- auto rebuild in the new build environment (release 22)
|
||||||
|
|
||||||
|
* Mon Mar 15 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- compile for 6.0.
|
||||||
|
|
||||||
|
* Fri Aug 7 1998 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- build root
|
||||||
|
|
||||||
|
* Mon Apr 27 1998 Prospector System <bugs@redhat.com>
|
||||||
|
- translations modified for de, fr, tr
|
||||||
|
|
||||||
|
* Mon Sep 22 1997 Erik Troan <ewt@redhat.com>
|
||||||
|
- added check for getpwnam() failure
|
||||||
|
|
||||||
|
* Tue Jul 15 1997 Erik Troan <ewt@redhat.com>
|
||||||
|
- initial build
|
|
@ -0,0 +1,228 @@
|
||||||
|
Summary: The client for the Trivial File Transfer Protocol (TFTP).
|
||||||
|
Name: tftp
|
||||||
|
Version: @@VERSION@@
|
||||||
|
Release: 1
|
||||||
|
License: BSD
|
||||||
|
Group: Applications/Internet
|
||||||
|
Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{version}.tar.gz
|
||||||
|
BuildRequires: tcp_wrappers-devel
|
||||||
|
BuildRoot: %{_tmppath}/%{name}-root
|
||||||
|
|
||||||
|
%description
|
||||||
|
The Trivial File Transfer Protocol (TFTP) is normally used only for
|
||||||
|
booting diskless workstations. The tftp package provides the user
|
||||||
|
interface for TFTP, which allows users to transfer files to and from a
|
||||||
|
remote machine. This program and TFTP provide very little security,
|
||||||
|
and should not be enabled unless it is expressly needed.
|
||||||
|
|
||||||
|
%package server
|
||||||
|
Group: System Environment/Daemons
|
||||||
|
Summary: The server for the Trivial File Transfer Protocol (TFTP).
|
||||||
|
Requires: xinetd
|
||||||
|
|
||||||
|
%description server
|
||||||
|
The Trivial File Transfer Protocol (TFTP) is normally used only for
|
||||||
|
booting diskless workstations. The tftp-server package provides the
|
||||||
|
server for TFTP, which allows users to transfer files to and from a
|
||||||
|
remote machine. TFTP provides very little security, and should not be
|
||||||
|
enabled unless it is expressly needed. The TFTP server is run from
|
||||||
|
/etc/xinetd.d/tftp, and is disabled by default on Red Hat Linux systems.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q -n tftp-hpa-%{version}
|
||||||
|
|
||||||
|
%build
|
||||||
|
|
||||||
|
%configure
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
|
%install
|
||||||
|
rm -rf ${RPM_BUILD_ROOT}
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man{1,8}
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_sbindir}
|
||||||
|
|
||||||
|
make INSTALLROOT=${RPM_BUILD_ROOT} \
|
||||||
|
SBINDIR=%{_sbindir} MANDIR=%{_mandir} \
|
||||||
|
install
|
||||||
|
install -m755 -d ${RPM_BUILD_ROOT}%{_sysconfdir}/xinetd.d/ ${RPM_BUILD_ROOT}/tftpboot
|
||||||
|
install -m644 tftp-xinetd ${RPM_BUILD_ROOT}%{_sysconfdir}/xinetd.d/tftp
|
||||||
|
|
||||||
|
%post server
|
||||||
|
/sbin/service xinetd reload > /dev/null 2>&1 || :
|
||||||
|
|
||||||
|
%postun server
|
||||||
|
if [ $1 = 0 ]; then
|
||||||
|
/sbin/service xinetd reload > /dev/null 2>&1 || :
|
||||||
|
fi
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf ${RPM_BUILD_ROOT}
|
||||||
|
|
||||||
|
%files
|
||||||
|
%defattr(-,root,root)
|
||||||
|
%{_bindir}/tftp
|
||||||
|
%{_mandir}/man1/*
|
||||||
|
|
||||||
|
%files server
|
||||||
|
%defattr(-,root,root)
|
||||||
|
%config(noreplace) %{_sysconfdir}/xinetd.d/tftp
|
||||||
|
%dir /tftpboot
|
||||||
|
%{_sbindir}/in.tftpd
|
||||||
|
%{_mandir}/man8/*
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Tue Sep 14 2004 H. Peter Anvin <hpa@zytor.com>
|
||||||
|
- removed completely broken "Malta" patch.
|
||||||
|
- integrated into build machinery so rpm -ta works.
|
||||||
|
|
||||||
|
* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Fri Apr 11 2003 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- 0.33
|
||||||
|
- Add /tftpboot directory (#88204)
|
||||||
|
|
||||||
|
* Mon Feb 24 2003 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Sun Feb 23 2003 Tim Powers <timp@redhat.com>
|
||||||
|
- add BuildPreReq on tcp_wrappers
|
||||||
|
|
||||||
|
* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
|
||||||
|
- rebuilt
|
||||||
|
|
||||||
|
* Mon Nov 11 2002 Elliot Lee <sopwith@redhat.com> 0.32-1
|
||||||
|
- Update to 0.32
|
||||||
|
|
||||||
|
* Wed Oct 23 2002 Elliot Lee <sopwith@redhat.com> 0.30-1
|
||||||
|
- Fix #55789
|
||||||
|
- Update to 0.30
|
||||||
|
|
||||||
|
* Thu Jun 27 2002 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- Try applying HJ's patch from #65476
|
||||||
|
|
||||||
|
* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
|
||||||
|
- automated rebuild
|
||||||
|
|
||||||
|
* Mon Jun 17 2002 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- Update to 0.29
|
||||||
|
|
||||||
|
* Thu May 23 2002 Tim Powers <timp@redhat.com>
|
||||||
|
- automated rebuild
|
||||||
|
|
||||||
|
* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
|
||||||
|
- automated rebuild
|
||||||
|
|
||||||
|
* Tue Dec 18 2001 Elliot Lee <sopwith@redhat.com> 0.17-15
|
||||||
|
- Add patch4: netkit-tftp-0.17-defaultport.patch for bug #57562
|
||||||
|
- Update to tftp-hpa-0.28 (bug #56131)
|
||||||
|
- Remove include/arpa/tftp.h to fix #57259
|
||||||
|
- Add resource limits in tftp-xinetd (#56722)
|
||||||
|
|
||||||
|
* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com>
|
||||||
|
- Bump release + rebuild.
|
||||||
|
|
||||||
|
* Tue Jun 12 2001 Helge Deller <hdeller@redhat.de> (0.17-13)
|
||||||
|
- updated tftp-hpa source to tftp-hpa-0.17
|
||||||
|
- tweaked specfile with different defines for tftp-netkit and tftp-hpa version
|
||||||
|
- use hpa's tftpd.8 man page instead of the netkits one
|
||||||
|
|
||||||
|
* Mon May 07 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- rebuilt in 7.1.x
|
||||||
|
|
||||||
|
* Wed Apr 18 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- fix tftp client's put problems (#29529)
|
||||||
|
- update to tftp-hpa-0.16
|
||||||
|
|
||||||
|
* Wed Apr 4 2001 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
- don't let configure to guess compiler, it can pick up egcs
|
||||||
|
|
||||||
|
* Thu Feb 08 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- changed "wait" in xinetd file to "yes" (hpa-tftpd forks and exits) (#26467)
|
||||||
|
- fixed hpa-tftpd to handle files greater than 32MB (#23725)
|
||||||
|
- added "-l" flag to hpa-tftpd for file-logging (#26467)
|
||||||
|
- added description for "-l" to the man-page
|
||||||
|
|
||||||
|
* Thu Feb 08 2001 Helge Deller <hdeller@redhat.de>
|
||||||
|
- updated tftp client to 0.17 stable (#19640),
|
||||||
|
- drop dependency on xinetd for tftp client (#25051),
|
||||||
|
|
||||||
|
* Wed Jan 17 2001 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- xinetd shouldn't wait on tftp (which forks) (#23923).
|
||||||
|
|
||||||
|
* Sat Jan 6 2001 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- fix to permit tftp put's (#18128).
|
||||||
|
- startup as root with chroot to /tftpboot with early reversion to nobody
|
||||||
|
is preferable to starting as nobody w/o ability to chroot.
|
||||||
|
- %%post is needed by server, not client. Add %%postun for erasure as well.
|
||||||
|
|
||||||
|
* Wed Aug 23 2000 Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
- default to being disabled
|
||||||
|
|
||||||
|
* Thu Aug 17 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- correct group.
|
||||||
|
|
||||||
|
* Tue Jul 25 2000 Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
- change user from root to nobody
|
||||||
|
|
||||||
|
* Sat Jul 22 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- update to tftp-hpa-0.14 (#14003).
|
||||||
|
- add server_args (#14003).
|
||||||
|
- remove -D_BSD_SOURCE (#14003).
|
||||||
|
|
||||||
|
* Fri Jul 21 2000 Nalin Dahyabhai <nalin@redhat.com>
|
||||||
|
- cook up an xinetd config file for tftpd
|
||||||
|
|
||||||
|
* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
|
||||||
|
- automatic rebuild
|
||||||
|
|
||||||
|
* Sun Jun 18 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- FHS packaging.
|
||||||
|
- update to 0.17.
|
||||||
|
|
||||||
|
* Fri May 5 2000 Matt Wilson <msw@redhat.com>
|
||||||
|
- use _BSD_SOURCE for hpa's tftpd so we get BSD signal semantics.
|
||||||
|
|
||||||
|
* Fri Feb 11 2000 Bill Nottingham <notting@redhat.com>
|
||||||
|
- fix description
|
||||||
|
|
||||||
|
* Wed Feb 9 2000 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- compress man pages (again).
|
||||||
|
|
||||||
|
* Wed Feb 02 2000 Cristian Gafton <gafton@redhat.com>
|
||||||
|
- man pages are compressed
|
||||||
|
- fix description and summary
|
||||||
|
|
||||||
|
* Tue Jan 4 2000 Bill Nottingham <notting@redhat.com>
|
||||||
|
- split client and server
|
||||||
|
|
||||||
|
* Tue Dec 21 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- update to 0.16.
|
||||||
|
|
||||||
|
* Sat Aug 28 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- update to 0.15.
|
||||||
|
|
||||||
|
* Wed Apr 7 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- tftpd should truncate file when overwriting (#412)
|
||||||
|
|
||||||
|
* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com>
|
||||||
|
- auto rebuild in the new build environment (release 22)
|
||||||
|
|
||||||
|
* Mon Mar 15 1999 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- compile for 6.0.
|
||||||
|
|
||||||
|
* Fri Aug 7 1998 Jeff Johnson <jbj@redhat.com>
|
||||||
|
- build root
|
||||||
|
|
||||||
|
* Mon Apr 27 1998 Prospector System <bugs@redhat.com>
|
||||||
|
- translations modified for de, fr, tr
|
||||||
|
|
||||||
|
* Mon Sep 22 1997 Erik Troan <ewt@redhat.com>
|
||||||
|
- added check for getpwnam() failure
|
||||||
|
|
||||||
|
* Tue Jul 15 1997 Erik Troan <ewt@redhat.com>
|
||||||
|
- initial build
|
|
@ -0,0 +1,28 @@
|
||||||
|
SRCROOT = ..
|
||||||
|
VERSION = $(shell cat ../version)
|
||||||
|
|
||||||
|
-include ../MCONFIG
|
||||||
|
include ../MRULES
|
||||||
|
|
||||||
|
OBJS = tftp.$(O) main.$(O)
|
||||||
|
|
||||||
|
all: tftp$(X) tftp.1
|
||||||
|
|
||||||
|
tftp$(X): $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) $^ $(TFTP_LIBS) -o $@
|
||||||
|
|
||||||
|
$(OBJS): ../common/tftpsubs.h
|
||||||
|
|
||||||
|
tftp.1: tftp.1.in ../version
|
||||||
|
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
|
||||||
|
|
||||||
|
install: all
|
||||||
|
mkdir -p $(INSTALLROOT)$(BINDIR) $(INSTALLROOT)$(MANDIR)/man1
|
||||||
|
$(INSTALL_PROGRAM) tftp$(X) $(INSTALLROOT)$(BINDIR)
|
||||||
|
$(INSTALL_DATA) tftp.1 $(INSTALLROOT)$(MANDIR)/man1
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.obj *.exe tftp tftp.1
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f *~
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RECVFILE_H
|
||||||
|
#define RECVFILE_H
|
||||||
|
|
||||||
|
void tftp_recvfile(int, const char *, const char *);
|
||||||
|
void tftp_sendfile(int, const char *, const char *);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,945 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1983, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/tftpsubs.h"
|
||||||
|
|
||||||
|
/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TFTP User Program -- Command Interface.
|
||||||
|
*/
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#ifdef HAVE_READLINE_HISTORY_H
|
||||||
|
#include <readline/history.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
#define TIMEOUT 5 /* secs between rexmt's */
|
||||||
|
#define LBUFLEN 200 /* size of input buffer */
|
||||||
|
|
||||||
|
struct modes {
|
||||||
|
const char *m_name;
|
||||||
|
const char *m_mode;
|
||||||
|
int m_openflags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct modes modes[] = {
|
||||||
|
{"netascii", "netascii", O_TEXT},
|
||||||
|
{"ascii", "netascii", O_TEXT},
|
||||||
|
{"octet", "octet", O_BINARY},
|
||||||
|
{"binary", "octet", O_BINARY},
|
||||||
|
{"image", "octet", O_BINARY},
|
||||||
|
{0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MODE_OCTET (&modes[2])
|
||||||
|
#define MODE_NETASCII (&modes[0])
|
||||||
|
#define MODE_DEFAULT MODE_NETASCII
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int ai_fam = AF_UNSPEC;
|
||||||
|
int ai_fam_sock = AF_UNSPEC;
|
||||||
|
#else
|
||||||
|
int ai_fam = AF_INET;
|
||||||
|
int ai_fam_sock = AF_INET;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
union sock_addr peeraddr;
|
||||||
|
int f = -1;
|
||||||
|
u_short port;
|
||||||
|
int trace;
|
||||||
|
int verbose;
|
||||||
|
int literal;
|
||||||
|
int connected;
|
||||||
|
const struct modes *mode;
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
char *line = NULL;
|
||||||
|
#else
|
||||||
|
char line[LBUFLEN];
|
||||||
|
#endif
|
||||||
|
int margc;
|
||||||
|
char *margv[20];
|
||||||
|
const char *prompt = "tftp> ";
|
||||||
|
sigjmp_buf toplevel;
|
||||||
|
void intr(int);
|
||||||
|
struct servent *sp;
|
||||||
|
int portrange = 0;
|
||||||
|
unsigned int portrange_from = 0;
|
||||||
|
unsigned int portrange_to = 0;
|
||||||
|
|
||||||
|
void get(int, char **);
|
||||||
|
void help(int, char **);
|
||||||
|
void modecmd(int, char **);
|
||||||
|
void put(int, char **);
|
||||||
|
void quit(int, char **);
|
||||||
|
void setascii(int, char **);
|
||||||
|
void setbinary(int, char **);
|
||||||
|
void setpeer(int, char **);
|
||||||
|
void setrexmt(int, char **);
|
||||||
|
void settimeout(int, char **);
|
||||||
|
void settrace(int, char **);
|
||||||
|
void setverbose(int, char **);
|
||||||
|
void status(int, char **);
|
||||||
|
void setliteral(int, char **);
|
||||||
|
|
||||||
|
static void command(void);
|
||||||
|
|
||||||
|
static void getusage(char *);
|
||||||
|
static void makeargv(void);
|
||||||
|
static void putusage(char *);
|
||||||
|
static void settftpmode(const struct modes *);
|
||||||
|
|
||||||
|
#define HELPINDENT (sizeof("connect"))
|
||||||
|
|
||||||
|
struct cmd {
|
||||||
|
const char *name;
|
||||||
|
const char *help;
|
||||||
|
void (*handler) (int, char **);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmd cmdtab[] = {
|
||||||
|
{"connect",
|
||||||
|
"connect to remote tftp",
|
||||||
|
setpeer},
|
||||||
|
{"mode",
|
||||||
|
"set file transfer mode",
|
||||||
|
modecmd},
|
||||||
|
{"put",
|
||||||
|
"send file",
|
||||||
|
put},
|
||||||
|
{"get",
|
||||||
|
"receive file",
|
||||||
|
get},
|
||||||
|
{"quit",
|
||||||
|
"exit tftp",
|
||||||
|
quit},
|
||||||
|
{"verbose",
|
||||||
|
"toggle verbose mode",
|
||||||
|
setverbose},
|
||||||
|
{"trace",
|
||||||
|
"toggle packet tracing",
|
||||||
|
settrace},
|
||||||
|
{"literal",
|
||||||
|
"toggle literal mode, ignore ':' in file name",
|
||||||
|
setliteral},
|
||||||
|
{"status",
|
||||||
|
"show current status",
|
||||||
|
status},
|
||||||
|
{"binary",
|
||||||
|
"set mode to octet",
|
||||||
|
setbinary},
|
||||||
|
{"ascii",
|
||||||
|
"set mode to netascii",
|
||||||
|
setascii},
|
||||||
|
{"rexmt",
|
||||||
|
"set per-packet transmission timeout",
|
||||||
|
setrexmt},
|
||||||
|
{"timeout",
|
||||||
|
"set total retransmission timeout",
|
||||||
|
settimeout},
|
||||||
|
{"?",
|
||||||
|
"print help information",
|
||||||
|
help},
|
||||||
|
{"help",
|
||||||
|
"print help information",
|
||||||
|
help},
|
||||||
|
{0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmd *getcmd(char *);
|
||||||
|
char *tail(char *);
|
||||||
|
|
||||||
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
|
const char *program;
|
||||||
|
|
||||||
|
static inline void usage(int errcode)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
"Usage: %s [-4][-6][-v][-l][-m mode] [host [port]] [-c command]\n",
|
||||||
|
#else
|
||||||
|
"Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n",
|
||||||
|
#endif
|
||||||
|
program);
|
||||||
|
exit(errcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
union sock_addr sa;
|
||||||
|
int arg;
|
||||||
|
static int pargc, peerargc;
|
||||||
|
static int iscmd = 0;
|
||||||
|
char **pargv;
|
||||||
|
const char *optx;
|
||||||
|
char *peerargv[3];
|
||||||
|
|
||||||
|
program = argv[0];
|
||||||
|
|
||||||
|
mode = MODE_DEFAULT;
|
||||||
|
|
||||||
|
peerargv[0] = argv[0];
|
||||||
|
peerargc = 1;
|
||||||
|
|
||||||
|
for (arg = 1; !iscmd && arg < argc; arg++) {
|
||||||
|
if (argv[arg][0] == '-') {
|
||||||
|
for (optx = &argv[arg][1]; *optx; optx++) {
|
||||||
|
switch (*optx) {
|
||||||
|
case '4':
|
||||||
|
ai_fam = AF_INET;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case '6':
|
||||||
|
ai_fam = AF_INET6;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'v':
|
||||||
|
verbose = 1;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
/* Print version and configuration to stdout and exit */
|
||||||
|
printf("%s\n", TFTP_CONFIG_STR);
|
||||||
|
exit(0);
|
||||||
|
case 'l':
|
||||||
|
literal = 1;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (++arg >= argc)
|
||||||
|
usage(EX_USAGE);
|
||||||
|
{
|
||||||
|
const struct modes *p;
|
||||||
|
|
||||||
|
for (p = modes; p->m_name; p++) {
|
||||||
|
if (!strcmp(argv[arg], p->m_name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p->m_name) {
|
||||||
|
settftpmode(p);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: invalid mode: %s\n",
|
||||||
|
argv[0], argv[arg]);
|
||||||
|
exit(EX_USAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
iscmd = 1;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
if (++arg >= argc)
|
||||||
|
usage(EX_USAGE);
|
||||||
|
if (sscanf
|
||||||
|
(argv[arg], "%u:%u", &portrange_from,
|
||||||
|
&portrange_to) != 2
|
||||||
|
|| portrange_from > portrange_to
|
||||||
|
|| portrange_to > 65535) {
|
||||||
|
fprintf(stderr, "Bad port range: %s\n", argv[arg]);
|
||||||
|
exit(EX_USAGE);
|
||||||
|
}
|
||||||
|
portrange = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
usage(*optx == 'h' ? 0 : EX_USAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (peerargc >= 3)
|
||||||
|
usage(EX_USAGE);
|
||||||
|
|
||||||
|
peerargv[peerargc++] = argv[arg];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_fam_sock = ai_fam;
|
||||||
|
|
||||||
|
pargv = argv + arg;
|
||||||
|
pargc = argc - arg;
|
||||||
|
|
||||||
|
sp = getservbyname("tftp", "udp");
|
||||||
|
if (sp == 0) {
|
||||||
|
/* Use canned values */
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr,
|
||||||
|
"tftp: tftp/udp: unknown service, faking it...\n");
|
||||||
|
sp = xmalloc(sizeof(struct servent));
|
||||||
|
sp->s_name = (char *)"tftp";
|
||||||
|
sp->s_aliases = NULL;
|
||||||
|
sp->s_port = htons(IPPORT_TFTP);
|
||||||
|
sp->s_proto = (char *)"udp";
|
||||||
|
}
|
||||||
|
|
||||||
|
bsd_signal(SIGINT, intr);
|
||||||
|
|
||||||
|
if (peerargc) {
|
||||||
|
/* Set peer */
|
||||||
|
if (sigsetjmp(toplevel, 1) != 0)
|
||||||
|
exit(EX_NOHOST);
|
||||||
|
setpeer(peerargc, peerargv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ai_fam_sock == AF_UNSPEC)
|
||||||
|
ai_fam_sock = AF_INET;
|
||||||
|
|
||||||
|
f = socket(ai_fam_sock, SOCK_DGRAM, 0);
|
||||||
|
if (f < 0) {
|
||||||
|
perror("tftp: socket");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
bzero(&sa, sizeof(sa));
|
||||||
|
sa.sa.sa_family = ai_fam_sock;
|
||||||
|
if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
|
||||||
|
perror("tftp: bind");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscmd && pargc) {
|
||||||
|
/* -c specified; execute command and exit */
|
||||||
|
struct cmd *c;
|
||||||
|
|
||||||
|
if (sigsetjmp(toplevel, 1) != 0)
|
||||||
|
exit(EX_UNAVAILABLE);
|
||||||
|
|
||||||
|
c = getcmd(pargv[0]);
|
||||||
|
if (c == (struct cmd *)-1 || c == (struct cmd *)0) {
|
||||||
|
fprintf(stderr, "%s: invalid command: %s\n", argv[0],
|
||||||
|
pargv[1]);
|
||||||
|
exit(EX_USAGE);
|
||||||
|
}
|
||||||
|
(*c->handler) (pargc, pargv);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
#ifdef HAVE_READLINE_HISTORY_H
|
||||||
|
using_history();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sigsetjmp(toplevel, 1) != 0)
|
||||||
|
(void)putchar('\n');
|
||||||
|
command();
|
||||||
|
|
||||||
|
return 0; /* Never reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
char *hostname;
|
||||||
|
|
||||||
|
/* Called when a command is incomplete; modifies
|
||||||
|
the global variable "line" */
|
||||||
|
static void getmoreargs(const char *partial, const char *mprompt)
|
||||||
|
{
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
char *eline;
|
||||||
|
int len, elen;
|
||||||
|
|
||||||
|
len = strlen(partial);
|
||||||
|
eline = readline(mprompt);
|
||||||
|
if (!eline)
|
||||||
|
exit(0); /* EOF */
|
||||||
|
|
||||||
|
elen = strlen(eline);
|
||||||
|
|
||||||
|
if (line) {
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
line = xmalloc(len + elen + 1);
|
||||||
|
strcpy(line, partial);
|
||||||
|
strcpy(line + len, eline);
|
||||||
|
free(eline);
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINE_HISTORY_H
|
||||||
|
add_history(line);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
int len = strlen(partial);
|
||||||
|
|
||||||
|
strcpy(line, partial);
|
||||||
|
fputs(mprompt, stdout);
|
||||||
|
if (fgets(line + len, LBUFLEN - len, stdin) == 0)
|
||||||
|
if (feof(stdin))
|
||||||
|
exit(0); /* EOF */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void setpeer(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
getmoreargs("connect ", "(to) ");
|
||||||
|
makeargv();
|
||||||
|
argc = margc;
|
||||||
|
argv = margv;
|
||||||
|
}
|
||||||
|
if ((argc < 2) || (argc > 3)) {
|
||||||
|
printf("usage: %s host-name [port]\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
peeraddr.sa.sa_family = ai_fam;
|
||||||
|
err = set_sock_addr(argv[1], &peeraddr, &hostname);
|
||||||
|
if (err) {
|
||||||
|
printf("Error: %s\n", gai_strerror(err));
|
||||||
|
printf("%s: unknown host\n", argv[1]);
|
||||||
|
connected = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ai_fam = peeraddr.sa.sa_family;
|
||||||
|
if (f == -1) { /* socket not open */
|
||||||
|
ai_fam_sock = ai_fam;
|
||||||
|
} else { /* socket was already open */
|
||||||
|
if (ai_fam_sock != ai_fam) { /* need reopen socken for new family */
|
||||||
|
union sock_addr sa;
|
||||||
|
|
||||||
|
close(f);
|
||||||
|
ai_fam_sock = ai_fam;
|
||||||
|
f = socket(ai_fam_sock, SOCK_DGRAM, 0);
|
||||||
|
if (f < 0) {
|
||||||
|
perror("tftp: socket");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
bzero((char *)&sa, sizeof (sa));
|
||||||
|
sa.sa.sa_family = ai_fam_sock;
|
||||||
|
if (pick_port_bind(f, &sa, portrange_from, portrange_to)) {
|
||||||
|
perror("tftp: bind");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port = sp->s_port;
|
||||||
|
if (argc == 3) {
|
||||||
|
struct servent *usp;
|
||||||
|
usp = getservbyname(argv[2], "udp");
|
||||||
|
if (usp) {
|
||||||
|
port = usp->s_port;
|
||||||
|
} else {
|
||||||
|
unsigned long myport;
|
||||||
|
char *ep;
|
||||||
|
myport = strtoul(argv[2], &ep, 10);
|
||||||
|
if (*ep || myport > 65535UL) {
|
||||||
|
printf("%s: bad port number\n", argv[2]);
|
||||||
|
connected = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
port = htons((u_short) myport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
char tmp[INET6_ADDRSTRLEN], *tp;
|
||||||
|
tp = (char *)inet_ntop(peeraddr.sa.sa_family, SOCKADDR_P(&peeraddr),
|
||||||
|
tmp, INET6_ADDRSTRLEN);
|
||||||
|
if (!tp)
|
||||||
|
tp = (char *)"???";
|
||||||
|
printf("Connected to %s (%s), port %u\n",
|
||||||
|
hostname, tp, (unsigned int)ntohs(port));
|
||||||
|
}
|
||||||
|
connected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void modecmd(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const struct modes *p;
|
||||||
|
const char *sep;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("Using %s mode to transfer files.\n", mode->m_mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (argc == 2) {
|
||||||
|
for (p = modes; p->m_name; p++)
|
||||||
|
if (strcmp(argv[1], p->m_name) == 0)
|
||||||
|
break;
|
||||||
|
if (p->m_name) {
|
||||||
|
settftpmode(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("%s: unknown mode\n", argv[1]);
|
||||||
|
/* drop through and print usage message */
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("usage: %s [", argv[0]);
|
||||||
|
sep = " ";
|
||||||
|
for (p = modes; p->m_name; p++) {
|
||||||
|
printf("%s%s", sep, p->m_name);
|
||||||
|
if (*sep == ' ')
|
||||||
|
sep = " | ";
|
||||||
|
}
|
||||||
|
printf(" ]\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setbinary(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
settftpmode(MODE_OCTET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setascii(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
settftpmode(MODE_NETASCII);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void settftpmode(const struct modes *newmode)
|
||||||
|
{
|
||||||
|
mode = newmode;
|
||||||
|
if (verbose)
|
||||||
|
printf("mode set to %s\n", mode->m_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send file(s).
|
||||||
|
*/
|
||||||
|
void put(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int n, err;
|
||||||
|
char *cp, *targ;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
getmoreargs("send ", "(file) ");
|
||||||
|
makeargv();
|
||||||
|
argc = margc;
|
||||||
|
argv = margv;
|
||||||
|
}
|
||||||
|
if (argc < 2) {
|
||||||
|
putusage(argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
targ = argv[argc - 1];
|
||||||
|
if (!literal && strchr(argv[argc - 1], ':')) {
|
||||||
|
for (n = 1; n < argc - 1; n++)
|
||||||
|
if (strchr(argv[n], ':')) {
|
||||||
|
putusage(argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cp = argv[argc - 1];
|
||||||
|
targ = strchr(cp, ':');
|
||||||
|
*targ++ = 0;
|
||||||
|
peeraddr.sa.sa_family = ai_fam;
|
||||||
|
err = set_sock_addr(cp, &peeraddr,&hostname);
|
||||||
|
if (err) {
|
||||||
|
printf("Error: %s\n", gai_strerror(err));
|
||||||
|
printf("%s: unknown host\n", argv[1]);
|
||||||
|
connected = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ai_fam = peeraddr.sa.sa_family;
|
||||||
|
connected = 1;
|
||||||
|
}
|
||||||
|
if (!connected) {
|
||||||
|
printf("No target machine specified.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (argc < 4) {
|
||||||
|
cp = argc == 2 ? tail(targ) : argv[1];
|
||||||
|
fd = open(cp, O_RDONLY | mode->m_openflags);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "tftp: ");
|
||||||
|
perror(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
printf("putting %s to %s:%s [%s]\n",
|
||||||
|
cp, hostname, targ, mode->m_mode);
|
||||||
|
sa_set_port(&peeraddr, port);
|
||||||
|
tftp_sendfile(fd, targ, mode->m_mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* this assumes the target is a directory */
|
||||||
|
/* on a remote unix system. hmmmm. */
|
||||||
|
cp = strchr(targ, '\0');
|
||||||
|
*cp++ = '/';
|
||||||
|
for (n = 1; n < argc - 1; n++) {
|
||||||
|
strcpy(cp, tail(argv[n]));
|
||||||
|
fd = open(argv[n], O_RDONLY | mode->m_openflags);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "tftp: ");
|
||||||
|
perror(argv[n]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
printf("putting %s to %s:%s [%s]\n",
|
||||||
|
argv[n], hostname, targ, mode->m_mode);
|
||||||
|
sa_set_port(&peeraddr, port);
|
||||||
|
tftp_sendfile(fd, targ, mode->m_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void putusage(char *s)
|
||||||
|
{
|
||||||
|
printf("usage: %s file ... host:target, or\n", s);
|
||||||
|
printf(" %s file ... target (when already connected)\n", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receive file(s).
|
||||||
|
*/
|
||||||
|
void get(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int n;
|
||||||
|
char *cp;
|
||||||
|
char *src;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
getmoreargs("get ", "(files) ");
|
||||||
|
makeargv();
|
||||||
|
argc = margc;
|
||||||
|
argv = margv;
|
||||||
|
}
|
||||||
|
if (argc < 2) {
|
||||||
|
getusage(argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!connected) {
|
||||||
|
for (n = 1; n < argc; n++)
|
||||||
|
if (literal || strchr(argv[n], ':') == 0) {
|
||||||
|
getusage(argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (n = 1; n < argc; n++) {
|
||||||
|
src = strchr(argv[n], ':');
|
||||||
|
if (literal || src == NULL)
|
||||||
|
src = argv[n];
|
||||||
|
else {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
*src++ = 0;
|
||||||
|
peeraddr.sa.sa_family = ai_fam;
|
||||||
|
err = set_sock_addr(argv[n], &peeraddr, &hostname);
|
||||||
|
if (err) {
|
||||||
|
printf("Warning: %s\n", gai_strerror(err));
|
||||||
|
printf("%s: unknown host\n", argv[1]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ai_fam = peeraddr.sa.sa_family;
|
||||||
|
connected = 1;
|
||||||
|
}
|
||||||
|
if (argc < 4) {
|
||||||
|
cp = argc == 3 ? argv[2] : tail(src);
|
||||||
|
fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags,
|
||||||
|
0666);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "tftp: ");
|
||||||
|
perror(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
printf("getting from %s:%s to %s [%s]\n",
|
||||||
|
hostname, src, cp, mode->m_mode);
|
||||||
|
sa_set_port(&peeraddr, port);
|
||||||
|
tftp_recvfile(fd, src, mode->m_mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cp = tail(src); /* new .. jdg */
|
||||||
|
fd = open(cp, O_WRONLY | O_CREAT | O_TRUNC | mode->m_openflags,
|
||||||
|
0666);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "tftp: ");
|
||||||
|
perror(cp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (verbose)
|
||||||
|
printf("getting from %s:%s to %s [%s]\n",
|
||||||
|
hostname, src, cp, mode->m_mode);
|
||||||
|
sa_set_port(&peeraddr, port);
|
||||||
|
tftp_recvfile(fd, src, mode->m_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getusage(char *s)
|
||||||
|
{
|
||||||
|
printf("usage: %s host:file host:file ... file, or\n", s);
|
||||||
|
printf(" %s file file ... file if connected\n", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rexmtval = TIMEOUT;
|
||||||
|
|
||||||
|
void setrexmt(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
getmoreargs("rexmt-timeout ", "(value) ");
|
||||||
|
makeargv();
|
||||||
|
argc = margc;
|
||||||
|
argv = margv;
|
||||||
|
}
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("usage: %s value\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = atoi(argv[1]);
|
||||||
|
if (t < 0)
|
||||||
|
printf("%s: bad value\n", argv[1]);
|
||||||
|
else
|
||||||
|
rexmtval = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxtimeout = 5 * TIMEOUT;
|
||||||
|
|
||||||
|
void settimeout(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
getmoreargs("maximum-timeout ", "(value) ");
|
||||||
|
makeargv();
|
||||||
|
argc = margc;
|
||||||
|
argv = margv;
|
||||||
|
}
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("usage: %s value\n", argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = atoi(argv[1]);
|
||||||
|
if (t < 0)
|
||||||
|
printf("%s: bad value\n", argv[1]);
|
||||||
|
else
|
||||||
|
maxtimeout = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setliteral(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
literal = !literal;
|
||||||
|
printf("Literal mode %s.\n", literal ? "on" : "off");
|
||||||
|
}
|
||||||
|
|
||||||
|
void status(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
if (connected)
|
||||||
|
printf("Connected to %s.\n", hostname);
|
||||||
|
else
|
||||||
|
printf("Not connected.\n");
|
||||||
|
printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode->m_mode,
|
||||||
|
verbose ? "on" : "off", trace ? "on" : "off",
|
||||||
|
literal ? "on" : "off");
|
||||||
|
printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
|
||||||
|
rexmtval, maxtimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intr(int sig)
|
||||||
|
{
|
||||||
|
(void)sig; /* Quiet unused warning */
|
||||||
|
|
||||||
|
bsd_signal(SIGALRM, SIG_IGN);
|
||||||
|
alarm(0);
|
||||||
|
siglongjmp(toplevel, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tail(char *filename)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
while (*filename) {
|
||||||
|
s = strrchr(filename, '/');
|
||||||
|
if (s == NULL)
|
||||||
|
break;
|
||||||
|
if (s[1])
|
||||||
|
return (s + 1);
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
|
return (filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command parser.
|
||||||
|
*/
|
||||||
|
static void command(void)
|
||||||
|
{
|
||||||
|
struct cmd *c;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
if (line) {
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
line = readline(prompt);
|
||||||
|
if (!line)
|
||||||
|
exit(0); /* EOF */
|
||||||
|
#else
|
||||||
|
fputs(prompt, stdout);
|
||||||
|
if (fgets(line, LBUFLEN, stdin) == 0) {
|
||||||
|
if (feof(stdin)) {
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ((line[0] == 0) || (line[0] == '\n'))
|
||||||
|
continue;
|
||||||
|
#ifdef WITH_READLINE
|
||||||
|
#ifdef HAVE_READLINE_HISTORY_H
|
||||||
|
add_history(line);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
makeargv();
|
||||||
|
if (margc == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
c = getcmd(margv[0]);
|
||||||
|
if (c == (struct cmd *)-1) {
|
||||||
|
printf("?Ambiguous command\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == 0) {
|
||||||
|
printf("?Invalid command\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*c->handler) (margc, margv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd *getcmd(char *name)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
char *q;
|
||||||
|
struct cmd *c, *found;
|
||||||
|
int nmatches, longest;
|
||||||
|
|
||||||
|
longest = 0;
|
||||||
|
nmatches = 0;
|
||||||
|
found = 0;
|
||||||
|
for (c = cmdtab; (p = c->name) != NULL; c++) {
|
||||||
|
for (q = name; *q == *p++; q++)
|
||||||
|
if (*q == 0) /* exact match? */
|
||||||
|
return (c);
|
||||||
|
if (!*q) { /* the name was a prefix */
|
||||||
|
if (q - name > longest) {
|
||||||
|
longest = q - name;
|
||||||
|
nmatches = 1;
|
||||||
|
found = c;
|
||||||
|
} else if (q - name == longest)
|
||||||
|
nmatches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nmatches > 1)
|
||||||
|
return ((struct cmd *)-1);
|
||||||
|
return (found);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slice a string up into argc/argv.
|
||||||
|
*/
|
||||||
|
static void makeargv(void)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
char **argp = margv;
|
||||||
|
|
||||||
|
margc = 0;
|
||||||
|
for (cp = line; *cp;) {
|
||||||
|
while (isspace(*cp))
|
||||||
|
cp++;
|
||||||
|
if (*cp == '\0')
|
||||||
|
break;
|
||||||
|
*argp++ = cp;
|
||||||
|
margc += 1;
|
||||||
|
while (*cp != '\0' && !isspace(*cp))
|
||||||
|
cp++;
|
||||||
|
if (*cp == '\0')
|
||||||
|
break;
|
||||||
|
*cp++ = '\0';
|
||||||
|
}
|
||||||
|
*argp++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Help command.
|
||||||
|
*/
|
||||||
|
void help(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct cmd *c;
|
||||||
|
|
||||||
|
printf("%s\n", VERSION);
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
printf("Commands may be abbreviated. Commands are:\n\n");
|
||||||
|
for (c = cmdtab; c->name; c++)
|
||||||
|
printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (--argc > 0) {
|
||||||
|
char *arg;
|
||||||
|
arg = *++argv;
|
||||||
|
c = getcmd(arg);
|
||||||
|
if (c == (struct cmd *)-1)
|
||||||
|
printf("?Ambiguous help command %s\n", arg);
|
||||||
|
else if (c == (struct cmd *)0)
|
||||||
|
printf("?Invalid help command %s\n", arg);
|
||||||
|
else
|
||||||
|
printf("%s\n", c->help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void settrace(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
|
||||||
|
trace = !trace;
|
||||||
|
printf("Packet tracing %s.\n", trace ? "on" : "off");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setverbose(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv; /* Quiet unused warning */
|
||||||
|
|
||||||
|
verbose = !verbose;
|
||||||
|
printf("Verbose mode %s.\n", verbose ? "on" : "off");
|
||||||
|
}
|
|
@ -0,0 +1,207 @@
|
||||||
|
.\" -*- nroff -*- --------------------------------------------------------- *
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 1990, 1993, 1994
|
||||||
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.\" Copyright 2001 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
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\" 3. Neither the name of the University nor the names of its contributors
|
||||||
|
.\" may be used to endorse or promote products derived from this software
|
||||||
|
.\" without specific prior written permission.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\"----------------------------------------------------------------------- */
|
||||||
|
.TH TFTP 1 "23 July 2008" "tftp-hpa @@VERSION@@" "User's Manual"
|
||||||
|
.SH NAME
|
||||||
|
.B tftp
|
||||||
|
\- IPv4 Trivial File Transfer Protocol client
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B tftp
|
||||||
|
[ \fIoptions...\fP ]
|
||||||
|
[\fIhost\fP [\fIport\fP]]
|
||||||
|
[\fB\-c\fP \fIcommand\fP]
|
||||||
|
.br
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B tftp
|
||||||
|
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
|
||||||
|
may be specified on the command line, in which case
|
||||||
|
.B tftp
|
||||||
|
uses
|
||||||
|
.I host
|
||||||
|
as the default host for future transfers (see the
|
||||||
|
.B connect
|
||||||
|
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.
|
||||||
|
.TP
|
||||||
|
.B \-l
|
||||||
|
Default to literal mode. Used to avoid special processing of ':' in a
|
||||||
|
file name.
|
||||||
|
.TP
|
||||||
|
\fB\-m\fP \fImode\fP
|
||||||
|
Set the default transfer mode to \fImode\fP. This is usually used with \-c.
|
||||||
|
.TP
|
||||||
|
\fB\-R\fP \fIport:port\fP
|
||||||
|
Force the originating port number to be in the specified range of port
|
||||||
|
numbers.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
Default to verbose mode.
|
||||||
|
.TP
|
||||||
|
.B \-V
|
||||||
|
Print the version number and configuration to standard output, then
|
||||||
|
exit gracefully.
|
||||||
|
.SH COMMANDS
|
||||||
|
Once
|
||||||
|
.B tftp
|
||||||
|
is running, it issues the prompt
|
||||||
|
\f(CWtftp>\fP
|
||||||
|
and recognizes the following commands:
|
||||||
|
.TP
|
||||||
|
\fB?\fP \fIcommand-name...\fP
|
||||||
|
.TP
|
||||||
|
\fBhelp\fP \fIcommand-name...\fP
|
||||||
|
Print help information
|
||||||
|
.TP
|
||||||
|
.B ascii
|
||||||
|
Shorthand for
|
||||||
|
.BR "mode ascii" .
|
||||||
|
.TP
|
||||||
|
.B binary
|
||||||
|
Shorthand for
|
||||||
|
.BR "mode binary" .
|
||||||
|
.TP
|
||||||
|
\fBconnect\fP \fIhost [port]\fP
|
||||||
|
Set the
|
||||||
|
.I host
|
||||||
|
(and optionally
|
||||||
|
.IR port )
|
||||||
|
for transfers. Note that the TFTP protocol, unlike the FTP protocol,
|
||||||
|
does not maintain connections between transfers; thus, the
|
||||||
|
.B connect
|
||||||
|
command does not actually create a connection, but merely remembers
|
||||||
|
what host is to be used for transfers. You do not have to use the
|
||||||
|
.B connect
|
||||||
|
command; the remote host can be specified as part of the
|
||||||
|
.B get
|
||||||
|
or
|
||||||
|
.B put
|
||||||
|
commands.
|
||||||
|
.TP
|
||||||
|
\fBget\fP \fIfile\fP
|
||||||
|
.sp -.6l
|
||||||
|
.TP
|
||||||
|
\fBget\fP \fIremotefile localfile\fP
|
||||||
|
.sp -.6l
|
||||||
|
.TP
|
||||||
|
\fBget\fP \fIfile1 file2 file3...\fP
|
||||||
|
Get a file or set of files from the specified sources. A remote
|
||||||
|
filename can be in one of two forms: a plain filename on the remote
|
||||||
|
host, if the host has already been specified, or a string of the form
|
||||||
|
.I "host:filename"
|
||||||
|
to specify both a host and filename at the same time. If the latter
|
||||||
|
form is used, the last hostname specified becomes the default for
|
||||||
|
future transfers. Enable
|
||||||
|
.B literal
|
||||||
|
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
|
||||||
|
.TP
|
||||||
|
.B literal
|
||||||
|
Toggle literal mode. When set, this mode prevents special treatment of ':' in filenames.
|
||||||
|
.TP
|
||||||
|
\fBmode\fP \fItransfer-mode\fP
|
||||||
|
Specify the mode for transfers;
|
||||||
|
.I transfer-mode
|
||||||
|
may be one of
|
||||||
|
.B ascii
|
||||||
|
(or
|
||||||
|
.BR netascii )
|
||||||
|
or
|
||||||
|
.B binary
|
||||||
|
(or
|
||||||
|
.BR octet .)
|
||||||
|
The default is
|
||||||
|
.BR ascii .
|
||||||
|
.TP
|
||||||
|
\fBput\fP \fIfile\fP
|
||||||
|
.sp -.6l
|
||||||
|
.TP
|
||||||
|
\fBput\fP \fIlocalfile remotefile\fP
|
||||||
|
.sp -.6l
|
||||||
|
.TP
|
||||||
|
\fBput\fP \fIfile1 file2 file3... remote-directory\fP
|
||||||
|
Put a file or set of files to the specified remote file or directory.
|
||||||
|
The destination can be in one of two forms: a filename on the remote
|
||||||
|
host, if the host has already been specified, or a string of the form
|
||||||
|
.I "host:filename"
|
||||||
|
to specify both a host and filename at the same time. If the latter
|
||||||
|
form is used, the hostname specified becomes the default for future
|
||||||
|
transfers. If the remote-directory form is used, the remote host is
|
||||||
|
assumed to be a UNIX system or another system using
|
||||||
|
.B /
|
||||||
|
as directory separator. Enable
|
||||||
|
.B literal
|
||||||
|
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
|
||||||
|
.TP
|
||||||
|
.B quit
|
||||||
|
Exit
|
||||||
|
.BR tftp .
|
||||||
|
End-of-file will also exit.
|
||||||
|
.TP
|
||||||
|
\fBrexmt\fP \fIretransmission-timeout\fP
|
||||||
|
Set the per-packet retransmission timeout, in seconds.
|
||||||
|
.TP
|
||||||
|
.B status
|
||||||
|
Show current status.
|
||||||
|
.TP
|
||||||
|
\fBtimeout\fP \fItotal-transmission-timeout\fP
|
||||||
|
Set the total transmission timeout, in seconds.
|
||||||
|
.TP
|
||||||
|
.B trace
|
||||||
|
Toggle packet tracing (a debugging feature.)
|
||||||
|
.TP
|
||||||
|
.B verbose
|
||||||
|
Toggle verbose mode.
|
||||||
|
.SH "NOTES"
|
||||||
|
The TFTP protocol provides no provisions for authentication or
|
||||||
|
security. Therefore, the remote server will probably implement some
|
||||||
|
kinds of access restriction or firewalling. These access restrictions
|
||||||
|
are likely to be site- and server-specific.
|
||||||
|
.SH "AUTHOR"
|
||||||
|
This version of
|
||||||
|
.B tftp
|
||||||
|
is maintained by H. Peter Anvin <hpa@zytor.com>. It was derived from,
|
||||||
|
but has substantially diverged from, an OpenBSD source base, with
|
||||||
|
added patches by Markus Gutschke and Gero Kulhman.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR tftpd (8).
|
|
@ -0,0 +1,425 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1983, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/tftpsubs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TFTP User Program -- Protocol Machines
|
||||||
|
*/
|
||||||
|
#include "extern.h"
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
static void nak(int, const char *);
|
||||||
|
static int makerequest(int, const char *, struct tftphdr *, const char *);
|
||||||
|
static void printstats(const char *, unsigned long);
|
||||||
|
static void startclock(void);
|
||||||
|
static void stopclock(void);
|
||||||
|
static void timer(int);
|
||||||
|
static void tpacket(const char *, struct tftphdr *, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the requested file.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receive a file.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, &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,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a nak packet (error message).
|
||||||
|
* Error code passed in is one of the
|
||||||
|
* standard TFTP codes, or a UNIX errno
|
||||||
|
* offset by 100.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
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->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 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) {
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval tstart;
|
||||||
|
struct timeval tstop;
|
||||||
|
|
||||||
|
static void startclock(void)
|
||||||
|
{
|
||||||
|
(void)gettimeofday(&tstart, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stopclock(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
(void)gettimeofday(&tstop, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printstats(const char *direction, unsigned long amount)
|
||||||
|
{
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer(int sig)
|
||||||
|
{
|
||||||
|
int save_errno = errno;
|
||||||
|
|
||||||
|
(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);
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
SRCROOT = ..
|
||||||
|
VERSION = $(shell cat ../version)
|
||||||
|
|
||||||
|
-include ../MCONFIG
|
||||||
|
include ../MRULES
|
||||||
|
|
||||||
|
OBJS = tftpd.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS)
|
||||||
|
|
||||||
|
all: tftpd$(X) tftpd.8
|
||||||
|
|
||||||
|
tftpd$(X): $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) $^ $(TFTPD_LIBS) -o $@
|
||||||
|
|
||||||
|
$(OBJS): ../common/tftpsubs.h
|
||||||
|
|
||||||
|
tftpd.8: tftpd.8.in ../version
|
||||||
|
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
|
||||||
|
|
||||||
|
install: all
|
||||||
|
mkdir -p $(INSTALLROOT)$(SBINDIR) $(INSTALLROOT)$(MANDIR)/man8
|
||||||
|
$(INSTALL_PROGRAM) tftpd$(X) $(INSTALLROOT)$(SBINDIR)/in.tftpd
|
||||||
|
$(INSTALL_DATA) tftpd.8 $(INSTALLROOT)$(MANDIR)/man8/in.tftpd.8
|
||||||
|
cd $(INSTALLROOT)$(MANDIR)/man8 && $(LN_S) -f in.tftpd.8 tftpd.8
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.obj *.exe tftpd tftpsubs.c tftpsubs.h tftpd.8
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f *~
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* misc.c
|
||||||
|
*
|
||||||
|
* Minor help routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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().
|
||||||
|
*/
|
||||||
|
void set_signal(int signum, void (*handler) (int), 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* malloc() that syslogs an error message and bails if it fails.
|
||||||
|
*/
|
||||||
|
void *tfmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *p = malloc(size);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
syslog(LOG_ERR, "malloc: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* strdup() that does the equivalent
|
||||||
|
*/
|
||||||
|
char *tfstrdup(const char *str)
|
||||||
|
{
|
||||||
|
char *p = strdup(str);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
syslog(LOG_ERR, "strdup: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
|
@ -0,0 +1,267 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2001-2006 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* recvfrom.c
|
||||||
|
*
|
||||||
|
* Emulate recvfrom() using recvmsg(), but try to capture the local address
|
||||||
|
* since some TFTP clients consider it an error to get the reply from another
|
||||||
|
* IP address than the request was sent to.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
|
||||||
|
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
# ifndef HAVE_STRUCT_IN_PKTINFO
|
||||||
|
# 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;
|
||||||
|
};
|
||||||
|
# else
|
||||||
|
# undef IP_PKTINFO /* No definition, no way to get it */
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CMSG_LEN
|
||||||
|
# define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size))
|
||||||
|
#endif
|
||||||
|
#ifndef CMSG_SPACE
|
||||||
|
# define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if this is a valid local address, meaning that we can
|
||||||
|
* legally bind to it.
|
||||||
|
*/
|
||||||
|
static int address_is_local(const union sock_addr *addr)
|
||||||
|
{
|
||||||
|
union sock_addr sa1, sa2;
|
||||||
|
int sockfd = -1;
|
||||||
|
int e;
|
||||||
|
int rv = 0;
|
||||||
|
socklen_t addrlen;
|
||||||
|
|
||||||
|
memcpy(&sa1, addr, sizeof sa1);
|
||||||
|
|
||||||
|
/* Multicast or universal broadcast address? */
|
||||||
|
if (sa1.sa.sa_family == AF_INET) {
|
||||||
|
if (ntohl(sa1.si.sin_addr.s_addr) >= (224UL << 24))
|
||||||
|
return 0;
|
||||||
|
sa1.si.sin_port = 0; /* Any port */
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (sa1.sa.sa_family == AF_INET6) {
|
||||||
|
if (IN6_IS_ADDR_MULTICAST(&sa1.s6.sin6_addr))
|
||||||
|
return 0;
|
||||||
|
sa1.s6.sin6_port = 0; /* Any port */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sockfd = socket(sa1.sa.sa_family, SOCK_DGRAM, 0);
|
||||||
|
if (sockfd < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (bind(sockfd, &sa1.sa, SOCKLEN(&sa1)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
addrlen = SOCKLEN(addr);
|
||||||
|
if (getsockname(sockfd, (struct sockaddr *)&sa2, &addrlen))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (sa1.sa.sa_family != sa2.sa.sa_family)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (sa2.sa.sa_family == AF_INET)
|
||||||
|
rv = sa1.si.sin_addr.s_addr == sa2.si.sin_addr.s_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (sa2.sa.sa_family == AF_INET6)
|
||||||
|
rv = IN6_ARE_ADDR_EQUAL(&sa1.s6.sin6_addr, &sa2.s6.sin6_addr);
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
e = errno;
|
||||||
|
|
||||||
|
if (sockfd >= 0)
|
||||||
|
close(sockfd);
|
||||||
|
|
||||||
|
errno = e;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
|
struct sockaddr *from, socklen_t * fromlen,
|
||||||
|
union sock_addr *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
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* Try to enable getting the return address */
|
||||||
|
#ifdef IP_RECVDSTADDR
|
||||||
|
if (from->sa_family == AF_INET)
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
|
||||||
|
#endif
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
if (from->sa_family == AF_INET)
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
if (from->sa_family == AF_INET6)
|
||||||
|
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;
|
||||||
|
|
||||||
|
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(*myaddr));
|
||||||
|
myaddr->sa.sa_family = from->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_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_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 &&
|
||||||
|
(cmptr->cmsg_type == IPV6_RECVPKTINFO ||
|
||||||
|
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
|
||||||
|
}
|
||||||
|
/* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* pointless... */
|
||||||
|
|
||||||
|
int
|
||||||
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
|
struct sockaddr *from, socklen_t * fromlen,
|
||||||
|
union sock_addr *myaddr)
|
||||||
|
{
|
||||||
|
/* There is no way we can get the local address, fudge it */
|
||||||
|
|
||||||
|
bzero(myaddr, sizeof(*myaddr));
|
||||||
|
myaddr->sa.sa_family = from->sa_family;
|
||||||
|
sa_set_port(myaddr, htons(IPPORT_TFTP));
|
||||||
|
|
||||||
|
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2001-2006 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* recvfrom.h
|
||||||
|
*
|
||||||
|
* Header for recvfrom substitute
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
|
struct sockaddr *from, socklen_t *fromlen,
|
||||||
|
union sock_addr *myaddr);
|
|
@ -0,0 +1,435 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remap.c
|
||||||
|
*
|
||||||
|
* Perform regular-expression based filename remapping.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Must be included first! */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
|
#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 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 */
|
||||||
|
|
||||||
|
struct rule {
|
||||||
|
struct rule *next;
|
||||||
|
int nrule;
|
||||||
|
int rule_flags;
|
||||||
|
char rule_mode;
|
||||||
|
regex_t rx;
|
||||||
|
const char *pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int xform_null(int c)
|
||||||
|
{
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xform_toupper(int c)
|
||||||
|
{
|
||||||
|
return toupper(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xform_tolower(int c)
|
||||||
|
{
|
||||||
|
return tolower(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do \-substitution. Call with string == NULL to get length only. */
|
||||||
|
static int genmatchstring(char *string, const char *pattern,
|
||||||
|
const char *input, const regmatch_t * pmatch,
|
||||||
|
match_pattern_callback macrosub)
|
||||||
|
{
|
||||||
|
int (*xform) (int) = xform_null;
|
||||||
|
int len = 0;
|
||||||
|
int n, mlen, sublen;
|
||||||
|
int endbytes;
|
||||||
|
|
||||||
|
/* 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy section after match */
|
||||||
|
if (string) {
|
||||||
|
memcpy(string, input + pmatch[0].rm_eo, endbytes);
|
||||||
|
string[endbytes] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract a string terminated by non-escaped whitespace; ignoring
|
||||||
|
* leading whitespace. Consider an unescaped # to be a comment marker,
|
||||||
|
* functionally \n.
|
||||||
|
*/
|
||||||
|
static int readescstring(char *buf, char **str)
|
||||||
|
{
|
||||||
|
char *p = *str;
|
||||||
|
int wasbs = 0, len = 0;
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf = '\0';
|
||||||
|
*str = p;
|
||||||
|
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;
|
||||||
|
|
||||||
|
memset(r, 0, sizeof *r);
|
||||||
|
r->nrule = nrule;
|
||||||
|
|
||||||
|
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 '~':
|
||||||
|
r->rule_flags |= RULE_INVERSE;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
case 'P':
|
||||||
|
r->rule_mode = *p;
|
||||||
|
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_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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
nrule++;
|
||||||
|
return 1; /* Rule found */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a rule file */
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
/* Bail on error, we have already logged an error message */
|
||||||
|
exit(EX_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
return first_rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy a rule file data structure */
|
||||||
|
void freerules(struct rule *r)
|
||||||
|
{
|
||||||
|
struct rule *next;
|
||||||
|
|
||||||
|
while (r) {
|
||||||
|
next = r->next;
|
||||||
|
|
||||||
|
regfree(&r->rx);
|
||||||
|
|
||||||
|
/* "" patterns aren't allocated by malloc() */
|
||||||
|
if (r->pattern && *r->pattern)
|
||||||
|
free((void *)r->pattern);
|
||||||
|
|
||||||
|
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,
|
||||||
|
char mode, 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;
|
||||||
|
|
||||||
|
/* 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_mode && ruleptr->rule_mode != mode)
|
||||||
|
continue; /* Rule not applicable, try next */
|
||||||
|
|
||||||
|
if (!deadman--) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"remap: Breaking loop, input = %s, last = %s", input,
|
||||||
|
current);
|
||||||
|
free(current);
|
||||||
|
return NULL; /* Did not terminate! */
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remap.h
|
||||||
|
*
|
||||||
|
* Prototypes for regular-expression based filename remapping.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TFTPD_REMAP_H
|
||||||
|
#define TFTPD_REMAP_H
|
||||||
|
|
||||||
|
/* Opaque type */
|
||||||
|
struct rule;
|
||||||
|
|
||||||
|
#ifdef WITH_REGEX
|
||||||
|
|
||||||
|
/* This is called when we encounter a substitution like \i. The
|
||||||
|
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 *);
|
||||||
|
|
||||||
|
/* Read a rule file */
|
||||||
|
struct rule *parserulefile(FILE *);
|
||||||
|
|
||||||
|
/* Destroy a rule file data structure */
|
||||||
|
void freerules(struct rule *);
|
||||||
|
|
||||||
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
|
char *rewrite_string(const char *, const struct rule *, char,
|
||||||
|
match_pattern_callback, const char **);
|
||||||
|
|
||||||
|
#endif /* WITH_REGEX */
|
||||||
|
#endif /* TFTPD_REMAP_H */
|
|
@ -0,0 +1,33 @@
|
||||||
|
#
|
||||||
|
# Sample rule file for the -m (remapping option)
|
||||||
|
#
|
||||||
|
# This file has three fields: operation, regex, remapping
|
||||||
|
#
|
||||||
|
# The operation is a combination of the following letters:
|
||||||
|
#
|
||||||
|
# r - rewrite the matched string with the remapping pattern
|
||||||
|
# i - case-insensitive matching
|
||||||
|
# g - repeat until no match (used with "r")
|
||||||
|
# e - exit (with success) if we match this pattern, do not process
|
||||||
|
# subsequent rules
|
||||||
|
# s - start over from the first rule if we match this pattern
|
||||||
|
# a - abort (refuse the request) if we match this rule
|
||||||
|
# G - this rule applies to TFTP GET requests only
|
||||||
|
# P - this rule applies to TFTP PUT requests only
|
||||||
|
#
|
||||||
|
# The regex is a regular expression in the style of egrep(1).
|
||||||
|
#
|
||||||
|
# The remapping is a pattern, all characters are verbatim except \
|
||||||
|
# \0 copies the full string that matched the regex
|
||||||
|
# \1..\9 copies the 9 first (..) expressions in the regex
|
||||||
|
# \\ is an escaped \
|
||||||
|
#
|
||||||
|
# "#" begins a comment, unless \-escaped
|
||||||
|
#
|
||||||
|
ri ^[a-z]: # Remove "drive letters"
|
||||||
|
rg \\ / # Convert backslashes to slashes
|
||||||
|
rg \# @ # Convert hash marks to @ signs
|
||||||
|
rg /../ /..no../ # Convert /../ to /..no../
|
||||||
|
e ^ok/ # These are always ok
|
||||||
|
r ^[^/] /tftpboot/\0 # Convert non-absolute files
|
||||||
|
a \.pvt$ # Reject requests for private files
|
|
@ -0,0 +1,423 @@
|
||||||
|
.\" -*- nroff -*- --------------------------------------------------------- *
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 1990, 1993, 1994
|
||||||
|
.\" The Regents of the University of California. 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
|
||||||
|
.\" are met:
|
||||||
|
.\" 1. Redistributions of source code must retain the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer.
|
||||||
|
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
.\" notice, this list of conditions and the following disclaimer in the
|
||||||
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
|
.\" 3. Neither the name of the University nor the names of its contributors
|
||||||
|
.\" may be used to endorse or promote products derived from this software
|
||||||
|
.\" without specific prior written permission.
|
||||||
|
.\"
|
||||||
|
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
.\" SUCH DAMAGE.
|
||||||
|
.\"
|
||||||
|
.\"----------------------------------------------------------------------- */
|
||||||
|
.TH TFTPD 8 "14 September 2009" "tftp-hpa @@VERSION@@" "System Manager's Manual"
|
||||||
|
.SH NAME
|
||||||
|
.B tftpd
|
||||||
|
\- Trivial File Transfer Protocol server
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B in.tftpd
|
||||||
|
.RI [ options... ]
|
||||||
|
.I directory...
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B tftpd
|
||||||
|
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 ,
|
||||||
|
but can also run standalone.
|
||||||
|
.PP
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\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 \-\-timeout
|
||||||
|
option is ignored, and the
|
||||||
|
.B \-\-address
|
||||||
|
option can be used to specify a specific local address or port to
|
||||||
|
listen to.
|
||||||
|
.TP
|
||||||
|
\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 \-\-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
|
||||||
|
\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 \-\-permissive
|
||||||
|
or
|
||||||
|
.B \-\-umask
|
||||||
|
options are specified.
|
||||||
|
.TP
|
||||||
|
\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 \-\-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\-\-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
|
||||||
|
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\-\-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 \-\-permissive
|
||||||
|
option is not specified, or inherited from the invoking process if
|
||||||
|
.B \-\-permissive
|
||||||
|
is specified.
|
||||||
|
.TP
|
||||||
|
\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 \-\-user
|
||||||
|
option.
|
||||||
|
.TP
|
||||||
|
\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
|
||||||
|
before terminating the server.
|
||||||
|
.B inetd
|
||||||
|
will then respawn the server when another request comes in. The
|
||||||
|
default is 900 (15 minutes.)
|
||||||
|
.TP
|
||||||
|
\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
|
||||||
|
or
|
||||||
|
.B utimeout
|
||||||
|
option is negotiated. The default is 1000000 (1 second.)
|
||||||
|
.TP
|
||||||
|
\fB\-\-mapfile\fP \fIremap-file\fP, \fB\-m\fP \fIremap-file\fP
|
||||||
|
Specify the use of filename remapping. The
|
||||||
|
.I remap-file
|
||||||
|
is a file containing the remapping rules. See the section on filename
|
||||||
|
remapping below. This option may not be compiled in, see the output of
|
||||||
|
.B "in.tftpd \-V"
|
||||||
|
to verify whether or not it is available.
|
||||||
|
.TP
|
||||||
|
\fB\-\-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\-\-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\-\-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;
|
||||||
|
for these clients, it is recommended to set this value to the smallest
|
||||||
|
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\-\-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
|
||||||
|
\fB\-\-version\fP, \fB\-V\fP
|
||||||
|
Print the version number and configuration to standard output, then
|
||||||
|
exit gracefully.
|
||||||
|
.SH "RFC 2347 OPTION NEGOTIATION"
|
||||||
|
This version of
|
||||||
|
.B tftpd
|
||||||
|
supports RFC 2347 option negotation. Currently implemented options
|
||||||
|
are:
|
||||||
|
.TP
|
||||||
|
\fBblksize\fP (RFC 2348)
|
||||||
|
Set the transfer block size to anything less than or equal to the
|
||||||
|
specified option. This version of
|
||||||
|
.B tftpd
|
||||||
|
can support any block size up to the theoretical maximum of 65464
|
||||||
|
bytes.
|
||||||
|
.TP
|
||||||
|
\fBblksize2\fP (nonstandard)
|
||||||
|
Set the transfer block size to anything less than or equal to the
|
||||||
|
specified option, but restrict the possible responses to powers of 2.
|
||||||
|
The maximum is 32768 bytes (the largest power of 2 less than or equal
|
||||||
|
to 65464.)
|
||||||
|
.TP
|
||||||
|
\fBtsize\fP (RFC 2349)
|
||||||
|
Report the size of the file that is about to be transferred. This
|
||||||
|
version of
|
||||||
|
.B tftpd
|
||||||
|
only supports the
|
||||||
|
.B tsize
|
||||||
|
option for binary (octet) mode transfers.
|
||||||
|
.TP
|
||||||
|
\fBtimeout\fP (RFC 2349)
|
||||||
|
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 \-\-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
|
||||||
|
.B blksize
|
||||||
|
option, but crash with an error if they actually get the option
|
||||||
|
accepted by the server.
|
||||||
|
.SH "FILENAME REMAPPING"
|
||||||
|
The
|
||||||
|
.B \-\-mapfile
|
||||||
|
option specifies a file which contains filename remapping rules. Each
|
||||||
|
non-comment line (comments begin with hash marks,
|
||||||
|
.BR # )
|
||||||
|
contains an
|
||||||
|
.IR operation ,
|
||||||
|
specified below; a
|
||||||
|
.IR regex ,
|
||||||
|
a regular expression in the style of
|
||||||
|
.BR egrep ;
|
||||||
|
and optionally a
|
||||||
|
.IR "replacement pattern" .
|
||||||
|
The operation indicated by
|
||||||
|
.I operation
|
||||||
|
is performed if the
|
||||||
|
.I regex
|
||||||
|
matches all or part of the filename. Rules are processed from the top
|
||||||
|
down, and by default, all rules are processed even if there is a
|
||||||
|
match.
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.I operation
|
||||||
|
can be any combination of the following letters:
|
||||||
|
.TP
|
||||||
|
.B r
|
||||||
|
Replace the substring matched by
|
||||||
|
.I regex
|
||||||
|
by the
|
||||||
|
.IR "replacement pattern" .
|
||||||
|
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
|
||||||
|
.BR r .
|
||||||
|
.TP
|
||||||
|
.B i
|
||||||
|
Match the
|
||||||
|
.I regex
|
||||||
|
case-insensitively. By default it is case sensitive.
|
||||||
|
.TP
|
||||||
|
.B e
|
||||||
|
If this rule matches, end rule processing after executing the rule.
|
||||||
|
.TP
|
||||||
|
.B s
|
||||||
|
If this rule matches, start rule processing over from the very first
|
||||||
|
rule after executing this rule.
|
||||||
|
.TP
|
||||||
|
.B a
|
||||||
|
If this rule matches, refuse the request and send an access denied
|
||||||
|
error to the client.
|
||||||
|
.TP
|
||||||
|
.B G
|
||||||
|
This rule applies to GET (RRQ) requests only.
|
||||||
|
.TP
|
||||||
|
.B P
|
||||||
|
This rule applies to PUT (WRQ) requests 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
|
||||||
|
.BR r .
|
||||||
|
.PP
|
||||||
|
The following escape sequences are recognized as part of the
|
||||||
|
.IR "replacement pattern" :
|
||||||
|
.TP
|
||||||
|
\fB\\0\fP
|
||||||
|
The entire string matched by the
|
||||||
|
.IR regex .
|
||||||
|
.TP
|
||||||
|
\fB\\1\fP to \fB\\9\fP
|
||||||
|
The strings matched by each of the first nine parenthesized
|
||||||
|
subexpressions, \\( ... \\), of the
|
||||||
|
.I regex
|
||||||
|
pattern.
|
||||||
|
.TP
|
||||||
|
\fB\\i\fP
|
||||||
|
The IP address of the requesting host, in dotted-quad notation
|
||||||
|
(e.g. 192.0.2.169).
|
||||||
|
.TP
|
||||||
|
\fB\\x\fP
|
||||||
|
The IP address of the requesting host, in hexadecimal notation
|
||||||
|
(e.g. C00002A9).
|
||||||
|
.TP
|
||||||
|
\fB\\\\\fP
|
||||||
|
Literal backslash.
|
||||||
|
.TP
|
||||||
|
\fB\\\fP\fIwhitespace\fP
|
||||||
|
Literal whitespace.
|
||||||
|
.TP
|
||||||
|
\fB\\#\fP
|
||||||
|
Literal hash mark.
|
||||||
|
.TP
|
||||||
|
\fB\\U\fP
|
||||||
|
Turns all subsequent letters to upper case.
|
||||||
|
.TP
|
||||||
|
\fB\\L\fP
|
||||||
|
Turns all subsequent letters to lower case.
|
||||||
|
.TP
|
||||||
|
\fB\\E\fP
|
||||||
|
Cancels the effect of \fB\\U\fP or \fB\\L\fP.
|
||||||
|
.PP
|
||||||
|
If the mapping file is changed, you need to send
|
||||||
|
.B SIGHUP
|
||||||
|
to any outstanding
|
||||||
|
.B tftpd
|
||||||
|
process.
|
||||||
|
.SH "SECURITY"
|
||||||
|
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 \-\-permissive
|
||||||
|
option is specified. Files may be written only if they already exist
|
||||||
|
and are publicly writable, unless the
|
||||||
|
.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 \-\-version" )
|
||||||
|
.B tftpd
|
||||||
|
will query the
|
||||||
|
.BR hosts_access (5)
|
||||||
|
database for access control information. This may be slow; sites
|
||||||
|
requiring maximum performance may want to compile without this option
|
||||||
|
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 \-\-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
|
||||||
|
leaks between applications.
|
||||||
|
.PP
|
||||||
|
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
|
||||||
|
possible, it is recommended that the
|
||||||
|
.B \-\-secure
|
||||||
|
flag is used to set up a chroot() environment for the server to run in
|
||||||
|
once a connection has been set up.
|
||||||
|
.PP
|
||||||
|
Finally, the filename remapping
|
||||||
|
.RB ( \-\-mapfile
|
||||||
|
flag) support can be used to provide a limited amount of additional
|
||||||
|
access control.
|
||||||
|
.SH "CONFORMING TO"
|
||||||
|
RFC 1123,
|
||||||
|
.IR "Requirements for Internet Hosts \- Application and Support" .
|
||||||
|
.br
|
||||||
|
RFC 1350,
|
||||||
|
.IR "The TFTP Protocol (revision 2)" .
|
||||||
|
.br
|
||||||
|
RFC 2347,
|
||||||
|
.IR "TFTP Option Extension" .
|
||||||
|
.br
|
||||||
|
RFC 2348,
|
||||||
|
.IR "TFTP Blocksize Option" .
|
||||||
|
.br
|
||||||
|
RFC 2349,
|
||||||
|
.IR "TFTP Timeout Interval and Transfer Size Options" .
|
||||||
|
.SH "AUTHOR"
|
||||||
|
This version of
|
||||||
|
.B tftpd
|
||||||
|
is maintained by H. Peter Anvin <hpa@zytor.com>. It was derived from,
|
||||||
|
but has substantially diverged from, an OpenBSD source base, with
|
||||||
|
added patches by Markus Gutschke and Gero Kulhman.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.BR tftp (1),
|
||||||
|
.BR egrep (1),
|
||||||
|
.BR umask (2),
|
||||||
|
.BR hosts_access (5),
|
||||||
|
.BR regex (7),
|
||||||
|
.BR inetd (8).
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2001 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/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tftpd.h
|
||||||
|
*
|
||||||
|
* Prototypes for various functions that are part of the tftpd server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TFTPD_TFTPD_H
|
||||||
|
#define TFTPD_TFTPD_H
|
||||||
|
|
||||||
|
void set_signal(int, void (*)(int), int);
|
||||||
|
void *tfmalloc(size_t);
|
||||||
|
char *tfstrdup(const char *);
|
||||||
|
|
||||||
|
extern int verbosity;
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue