forked from mirrors/tftp-hpa-google
Compare commits
144 commits
tftp-hpa-0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 1dd16bc0df | |||
| 37ac880897 | |||
|
|
2c86ff58dc | ||
|
|
33ec23c0dc | ||
|
|
9a92dec1dc | ||
|
|
ac7f98e4d8 | ||
|
|
74c5d8a020 | ||
|
|
cb619257ed | ||
|
|
fefaa2cc5c | ||
|
|
33051a296c | ||
|
|
e52af4207a | ||
|
|
5e8d5c24b2 | ||
|
|
99112f0206 | ||
|
|
416046e2ad | ||
|
|
b9f2335e88 | ||
|
|
351907e3f0 | ||
|
|
6f96fcd1b6 | ||
|
|
1dc6d55811 | ||
|
|
15c4f369ee | ||
|
|
aaaa76e8e7 | ||
|
|
1f4b33a1f7 | ||
|
|
9c0908a778 | ||
|
|
e83d71d394 | ||
|
|
b2b34cecc8 | ||
|
|
7678ae7f14 | ||
|
|
ff819b108a | ||
|
|
3ee2b27809 | ||
|
|
18ac1e26f7 | ||
|
|
8ddf0d87d7 | ||
|
|
2ac12abbc9 | ||
|
|
18ee96a03f | ||
|
|
c89a63a441 | ||
|
|
128e6a3905 | ||
|
|
b9708e2201 | ||
|
|
f08a34ede1 | ||
|
|
c6d2c36b1a | ||
|
|
badf05140d | ||
|
|
f6a1282fec | ||
|
|
464be3090b | ||
|
|
bd250a597f | ||
|
|
f3035c45bc | ||
|
|
2864d83fea | ||
|
|
05ffcecaa8 | ||
|
|
ad5aab9281 | ||
|
|
0b5732e263 | ||
|
|
915f62f5c7 | ||
|
|
aeb1c31bae | ||
|
|
a63534e6e6 | ||
|
|
e7a7b19483 | ||
|
|
ab382980ae | ||
|
|
c86f82532e | ||
|
|
5a27e30ec2 | ||
|
|
85029077c8 | ||
|
|
3f2bc9833d | ||
|
|
44c98cf8b6 | ||
|
|
338648870e | ||
|
|
9ba4e118d2 | ||
|
|
2f3a775f85 | ||
|
|
e7a5fc2d68 | ||
|
|
878b024bcd | ||
|
|
acf818880c | ||
|
|
932277c9a5 | ||
|
|
fcdd859a75 | ||
|
|
b0a2a17864 | ||
|
|
12996491c2 | ||
|
|
dd50e8b75c | ||
|
|
920b99dfee | ||
|
|
4f715da294 | ||
|
|
ac5f0ab996 | ||
|
|
a1dfd6baf8 | ||
|
|
740871b0f5 | ||
|
|
544abd789e | ||
|
|
18fd18bd5c | ||
|
|
bdb90cf176 | ||
|
|
e4d3083006 | ||
|
|
77fbfeebee | ||
|
|
0c6f7f86d3 | ||
|
|
7670c83e5a | ||
|
|
cfb85d4dec | ||
|
|
c3a5c712e2 | ||
|
|
4bdac0b536 | ||
|
|
28f22b6591 | ||
|
|
7fe0fb941c | ||
|
|
57ca281980 | ||
|
|
40e20cc4a5 | ||
|
|
3e7043c50f | ||
|
|
50f22a7ad2 | ||
|
|
9f83475779 | ||
|
|
cd22c6ea31 | ||
|
|
22accddda0 | ||
|
|
62533e7441 | ||
|
|
bbb17208a9 | ||
|
|
80f86e5a04 | ||
|
|
1f57b0edd5 | ||
|
|
0eacf8823f | ||
|
|
c7ecc59f86 | ||
|
|
077eac1fd6 | ||
|
|
ecf79bc97f | ||
|
|
d15a61abe6 | ||
|
|
d9938a7d83 | ||
|
|
059de7ce20 | ||
|
|
6124dcbe2d | ||
|
|
0db17eedd3 | ||
|
|
625002c097 | ||
|
|
2b36598746 | ||
|
|
4d02d827fb | ||
|
|
982c1f2697 | ||
|
|
ab12c128ff | ||
|
|
df877df452 | ||
|
|
899b7d500b | ||
|
|
e031e3bc9a | ||
|
|
7390c7ceca | ||
|
|
1cb44ce918 | ||
|
|
ad475989a5 | ||
|
|
ec5973ac5f | ||
|
|
5f64014add | ||
|
|
14993bc916 | ||
|
|
f3beb3a119 | ||
|
|
40133b212b | ||
|
|
a548569a3e | ||
|
|
9b969ddd0e | ||
|
|
0b821ec893 | ||
|
|
ebeb6a63f3 | ||
|
|
293301fb2c | ||
|
|
22e2fe6dc6 | ||
|
|
b3892e801f | ||
|
|
8890d206f4 | ||
|
|
30d10d7e22 | ||
|
|
5336233982 | ||
|
|
ccb6289984 | ||
|
|
4187af0e6f | ||
|
|
ae1305e2d5 | ||
|
|
25d63c415a | ||
|
|
7976458c8b | ||
|
|
4cee9cc9ee | ||
|
|
a3af5d93a3 | ||
|
|
b52fe85017 | ||
|
|
8a2f696097 | ||
|
|
cbf26dca81 | ||
|
|
759ff9e29b | ||
|
|
547d611d53 | ||
|
|
d1f0406637 | ||
|
|
d86d06e131 | ||
|
|
9630aae006 |
67 changed files with 5489 additions and 3555 deletions
11
.editorconfig
Normal file
11
.editorconfig
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[{*.c,*.h}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
tab_width = 8
|
||||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/config/MCONFIG
|
||||||
|
/config/config.h
|
||||||
|
/config/config.h.in
|
||||||
|
/autoconf/aclocal.m4
|
||||||
|
/autoconf/clean.sh
|
||||||
|
/autoconf/helpers/
|
||||||
|
/autom4te.cache
|
||||||
|
/config.log
|
||||||
|
/config.status
|
||||||
|
/configure
|
||||||
|
/version.h
|
||||||
|
/tftp/tftp
|
||||||
|
/tftpd/tftpd
|
||||||
|
*.1
|
||||||
|
*.8
|
||||||
|
*.a
|
||||||
|
*.o
|
||||||
|
*.i
|
||||||
|
*.s
|
||||||
|
*~
|
||||||
|
\#*
|
||||||
100
CHANGES
100
CHANGES
|
|
@ -1,4 +1,102 @@
|
||||||
$Id$
|
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:
|
Changes in 0.39:
|
||||||
Support Perl-style \U...\E and \L...\E, as well as allow
|
Support Perl-style \U...\E and \L...\E, as well as allow
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
$Id$
|
|
||||||
|
|
||||||
Specific installation instructions
|
Specific installation instructions
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
|
|
||||||
40
Makefile
40
Makefile
|
|
@ -1,12 +1,12 @@
|
||||||
# You can do "make SUB=blah" to make only a few, or edit here, or both
|
# You can do "make SUB=blah" to make only a few, or edit here, or both
|
||||||
# You can also run make directly in the subdirs you want.
|
# You can also run make directly in the subdirs you want.
|
||||||
|
|
||||||
SUB = lib tftp tftpd
|
SUB = lib common tftp tftpd
|
||||||
|
|
||||||
%.build: MCONFIG aconfig.h version.h
|
%.build: config/MCONFIG config/config.h version.h
|
||||||
$(MAKE) -C $(patsubst %.build, %, $@)
|
$(MAKE) -C $(patsubst %.build, %, $@)
|
||||||
|
|
||||||
%.install: MCONFIG aconfig.h version.h
|
%.install: config/MCONFIG config/config.h version.h
|
||||||
$(MAKE) -C $(patsubst %.install, %, $@) install
|
$(MAKE) -C $(patsubst %.install, %, $@) install
|
||||||
|
|
||||||
%.clean:
|
%.clean:
|
||||||
|
|
@ -15,12 +15,12 @@ SUB = lib tftp tftpd
|
||||||
%.distclean:
|
%.distclean:
|
||||||
$(MAKE) -C $(patsubst %.distclean, %, $@) distclean
|
$(MAKE) -C $(patsubst %.distclean, %, $@) distclean
|
||||||
|
|
||||||
all: MCONFIG $(patsubst %, %.build, $(SUB))
|
all: config/MCONFIG $(patsubst %, %.build, $(SUB))
|
||||||
|
|
||||||
tftp.build: lib.build
|
tftp.build: lib.build common.build
|
||||||
tftpd.build: lib.build
|
tftpd.build: lib.build common.build
|
||||||
|
|
||||||
install: MCONFIG $(patsubst %, %.install, $(SUB))
|
install: config/MCONFIG $(patsubst %, %.install, $(SUB))
|
||||||
|
|
||||||
clean: localclean $(patsubst %, %.clean, $(SUB))
|
clean: localclean $(patsubst %, %.clean, $(SUB))
|
||||||
|
|
||||||
|
|
@ -30,46 +30,40 @@ localclean:
|
||||||
distclean: localdistclean $(patsubst %, %.distclean, $(SUB))
|
distclean: localdistclean $(patsubst %, %.distclean, $(SUB))
|
||||||
|
|
||||||
localdistclean: localclean
|
localdistclean: localclean
|
||||||
rm -f MCONFIG config.status config.log aconfig.h *~ \#*
|
rm -f config/config/MCONFIG config.status config.log config/config.h *~ \#*
|
||||||
rm -rf *.cache
|
rm -rf *.cache
|
||||||
find . -type f \( -name \*.orig -o -name \*.rej \) | xargs rm -f
|
find . -type f \( -name \*.orig -o -name \*.rej \) | xargs rm -f
|
||||||
|
|
||||||
spotless: distclean
|
spotless: distclean
|
||||||
rm -f configure aconfig.h.in tftp.spec
|
rm -f configure config/config.h.in tftp.spec
|
||||||
|
|
||||||
autoconf: configure aconfig.h.in
|
autoconf: configure config/config.h.in
|
||||||
|
|
||||||
config: MCONFIG aconfig.h
|
config: config/MCONFIG config/config.h
|
||||||
|
|
||||||
release:
|
release:
|
||||||
$(MAKE) autoconf
|
$(MAKE) autoconf
|
||||||
$(MAKE) tftp.spec
|
$(MAKE) tftp.spec
|
||||||
$(MAKE) distclean
|
$(MAKE) distclean
|
||||||
|
|
||||||
MCONFIG: configure MCONFIG.in aconfig.h.in
|
config/MCONFIG: configure config/MCONFIG.in config/config.h.in
|
||||||
if test -x config.status; then \
|
if test -x config.status; then \
|
||||||
./config.status --recheck && ./config.status ; \
|
./config.status --recheck && ./config.status ; \
|
||||||
else \
|
else \
|
||||||
./configure ; \
|
./configure ; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
aconfig.h: MCONFIG
|
config/config.h: config/MCONFIG
|
||||||
: Generated by side effect
|
: Generated by side effect
|
||||||
|
|
||||||
# Adding "configure" to the dependencies serializes this with running
|
configure: configure.ac
|
||||||
# autoconf, because there are apparently race conditions between
|
sh autogen.sh
|
||||||
# autoconf and autoheader.
|
|
||||||
aconfig.h.in: configure.in configure aclocal.m4
|
|
||||||
rm -f aconfig.h.in aconfig.h
|
|
||||||
autoheader
|
|
||||||
|
|
||||||
configure: configure.in aclocal.m4
|
config/config.h.in: configure
|
||||||
rm -rf MCONFIG configure config.log aconfig.h *.cache
|
: Generated by side effect
|
||||||
autoconf
|
|
||||||
|
|
||||||
version.h: version
|
version.h: version
|
||||||
echo \#define VERSION \"tftp-hpa `cat version`\" > version.h
|
echo \#define VERSION \"tftp-hpa `cat version`\" > version.h
|
||||||
|
|
||||||
tftp.spec: tftp.spec.in version
|
tftp.spec: tftp.spec.in version
|
||||||
sed -e "s/@@VERSION@@/`cat version`/g" < $< > $@ || rm -f $@
|
sed -e "s/@@VERSION@@/`cat version`/g" < $< > $@ || rm -f $@
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,3 @@
|
||||||
$Id$
|
|
||||||
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
Starting in version 0.27, tftp-hpa has the option of a "use Unix
|
Starting in version 0.27, tftp-hpa has the option of a "use Unix
|
||||||
permissions" mode. In this mode, tftpd can access any file accessible
|
permissions" mode. In this mode, tftpd can access any file accessible
|
||||||
by the tftpd effective user, specified via the -u option. This means
|
by the tftpd effective user, specified via the -u option. This means
|
||||||
|
|
|
||||||
206
aclocal.m4
vendored
206
aclocal.m4
vendored
|
|
@ -1,206 +0,0 @@
|
||||||
dnl $Id$
|
|
||||||
dnl -----------------------------------------------------------------------
|
|
||||||
dnl
|
|
||||||
dnl Copyright 1999-2002 H. Peter Anvin - All Rights Reserved
|
|
||||||
dnl
|
|
||||||
dnl This program is free software; you can redistribute it and/or modify
|
|
||||||
dnl it under the terms of the GNU General Public License as published by
|
|
||||||
dnl the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
|
||||||
dnl Bostom MA 02111-1307, USA; either version 2 of the License, or
|
|
||||||
dnl (at your option) any later version; incorporated herein by reference.
|
|
||||||
dnl
|
|
||||||
dnl -----------------------------------------------------------------------
|
|
||||||
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
dnl PA_ADD_CFLAGS()
|
|
||||||
dnl
|
|
||||||
dnl Attempt to add the given option to CFLAGS, if it doesn't break compilation
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
AC_DEFUN(PA_ADD_CFLAGS,
|
|
||||||
[AC_MSG_CHECKING([if $CC accepts $1])
|
|
||||||
pa_add_cflags__old_cflags="$CFLAGS"
|
|
||||||
CFLAGS="$CFLAGS $1"
|
|
||||||
AC_TRY_LINK([#include <stdio.h>],
|
|
||||||
[printf("Hello, World!\n");],
|
|
||||||
AC_MSG_RESULT([yes]),
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
CFLAGS="$pa_add_cflags__old_cflags")])
|
|
||||||
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
dnl PA_SIGSETJMP
|
|
||||||
dnl
|
|
||||||
dnl Do we have sigsetjmp/siglongjmp? (AC_CHECK_FUNCS doesn't seem to work
|
|
||||||
dnl for these particular functions.)
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
AC_DEFUN(PA_SIGSETJMP,
|
|
||||||
[AC_MSG_CHECKING([for sigsetjmp])
|
|
||||||
AC_TRY_LINK([
|
|
||||||
#ifdef HAVE_SETJMP_H
|
|
||||||
#include <setjmp.h>
|
|
||||||
#endif],
|
|
||||||
[sigjmp_buf buf;
|
|
||||||
sigsetjmp(buf,1);
|
|
||||||
siglongjmp(buf,2);],
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
$1,
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
$2)])
|
|
||||||
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
dnl PA_MSGHDR_MSG_CONTROL
|
|
||||||
dnl
|
|
||||||
dnl Does struct msghdr have the msg_control field?
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
AH_TEMPLATE([HAVE_MSGHDR_MSG_CONTROL],
|
|
||||||
[Define if struct msghdr has the msg_control field.])
|
|
||||||
|
|
||||||
AC_DEFUN(PA_MSGHDR_MSG_CONTROL,
|
|
||||||
[AC_CHECK_MEMBER(struct msghdr.msg_control,
|
|
||||||
[AC_DEFINE(HAVE_MSGHDR_MSG_CONTROL)],
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
])])
|
|
||||||
|
|
||||||
dnl ------------------------------------------------------------------------
|
|
||||||
dnl PA_STRUCT_IN_PKTINFO
|
|
||||||
dnl
|
|
||||||
dnl Look for definition of struct in_pktinfo, which at least has an
|
|
||||||
dnl ipi_addr member. Some versions of glibc lack struct in_pktinfo;
|
|
||||||
dnl if so we need to include the definition ourselves -- but we only
|
|
||||||
dnl want to do that if absolutely necessary!
|
|
||||||
dnl
|
|
||||||
dnl We don't use AC_CHECK_MEMBER() here, since at least in autoconf 2.52
|
|
||||||
dnl this is broken for a member of structure type.
|
|
||||||
dnl ------------------------------------------------------------------------
|
|
||||||
AH_TEMPLATE([HAVE_STRUCT_IN_PKTINFO],
|
|
||||||
[Define if struct in_pktinfo is defined.])
|
|
||||||
|
|
||||||
AC_DEFUN(PA_STRUCT_IN_PKTINFO,
|
|
||||||
[AC_MSG_CHECKING([for definition of struct in_pktinfo])
|
|
||||||
AC_TRY_COMPILE(
|
|
||||||
[
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/uio.h>
|
|
||||||
],
|
|
||||||
[
|
|
||||||
struct in_pktinfo pktinfo;
|
|
||||||
int foo = sizeof(struct in_pktinfo);
|
|
||||||
void *quux = (void *)(&pktinfo.ipi_addr);
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_DEFINE(HAVE_STRUCT_IN_PKTINFO)
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
])])
|
|
||||||
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
dnl PA_HAVE_TCPWRAPPERS
|
|
||||||
dnl
|
|
||||||
dnl Do we have the tcpwrappers -lwrap? This can't be done using AC_CHECK_LIBS
|
|
||||||
dnl due to the need to provide "allow_severity" and "deny_severity" variables
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
AH_TEMPLATE([HAVE_TCPWRAPPERS],
|
|
||||||
[Define if we have tcpwrappers (-lwrap) and <tcpd.h>.])
|
|
||||||
|
|
||||||
AC_DEFUN(PA_HAVE_TCPWRAPPERS,
|
|
||||||
[AC_CHECK_LIB([wrap], [main])
|
|
||||||
AC_MSG_CHECKING([for tcpwrappers])
|
|
||||||
AC_TRY_LINK(
|
|
||||||
[
|
|
||||||
#include <tcpd.h>
|
|
||||||
int allow_severity = 0;
|
|
||||||
int deny_severity = 0;
|
|
||||||
],
|
|
||||||
[
|
|
||||||
hosts_ctl("sample_daemon", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN);
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_DEFINE(HAVE_TCPWRAPPERS)
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT([no])
|
|
||||||
])])
|
|
||||||
|
|
||||||
dnl ------------------------------------------------------------------------
|
|
||||||
dnl PA_CHECK_INTTYPES_H_SANE
|
|
||||||
dnl
|
|
||||||
dnl At least some versions of AIX 4 have <inttypes.h> macros which are
|
|
||||||
dnl completely broken. Try to detect those.
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
AH_TEMPLATE([INTTYPES_H_IS_SANE],
|
|
||||||
[Define if the macros in <inttypes.h> are usable])
|
|
||||||
|
|
||||||
AC_DEFUN(PA_CHECK_INTTYPES_H_SANE,
|
|
||||||
[AC_CHECK_HEADERS(inttypes.h,
|
|
||||||
[
|
|
||||||
AC_MSG_CHECKING([if inttypes.h is sane])
|
|
||||||
AC_TRY_LINK(
|
|
||||||
[
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
],
|
|
||||||
[uintmax_t max = UINTMAX_C(0);
|
|
||||||
printf("%"PRIuMAX"\n", max);],
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
AC_DEFINE(INTTYPES_H_IS_SANE),
|
|
||||||
AC_MSG_RESULT([no (AIX, eh?)]))
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl ------------------------------------------------------------------------
|
|
||||||
dnl PA_WITH_BOOL
|
|
||||||
dnl
|
|
||||||
dnl PA_WITH_BOOL(option, default, help, enable, disable)
|
|
||||||
dnl
|
|
||||||
dnl Provides a more convenient way to specify --with-option and
|
|
||||||
dnl --without-option, with a default. default should be either 0 or 1.
|
|
||||||
dnl ------------------------------------------------------------------------
|
|
||||||
AC_DEFUN(PA_WITH_BOOL,
|
|
||||||
[AC_ARG_WITH([$1], [$3],
|
|
||||||
if test ["$withval"] != no; then
|
|
||||||
[$4]
|
|
||||||
else
|
|
||||||
[$5]
|
|
||||||
fi,
|
|
||||||
if test [$2] -ne 0; then
|
|
||||||
[$4]
|
|
||||||
else
|
|
||||||
[$5]
|
|
||||||
fi)])
|
|
||||||
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
dnl PA_HEADER_DEFINES
|
|
||||||
dnl
|
|
||||||
dnl PA_HEADER_DEFINES(header, type, value)
|
|
||||||
dnl --------------------------------------------------------------------------
|
|
||||||
AC_DEFUN(PA_HEADER_DEFINES,
|
|
||||||
[AC_MSG_CHECKING([if $1 defines $3])
|
|
||||||
AH_TEMPLATE([HAVE_$3_DEFINITION], [Define if $1 defines $3])
|
|
||||||
AC_TRY_COMPILE([
|
|
||||||
#include <$1>
|
|
||||||
],
|
|
||||||
[
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
$2 dummy = $3;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[
|
|
||||||
pa_header_define=`echo HAVE_$3_DEFINITION | tr '[a-z]' '[A-Z]'`
|
|
||||||
AC_DEFINE_UNQUOTED($pa_header_define)
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
],
|
|
||||||
[
|
|
||||||
AC_MSG_RESULT(no)
|
|
||||||
])])
|
|
||||||
9
autoconf/m4/pa_add_cflags.m4
Normal file
9
autoconf/m4/pa_add_cflags.m4
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ADD_CFLAGS(variable, flag [,actual_flag [,success [,failure]]]])
|
||||||
|
dnl
|
||||||
|
dnl Attempt to add the given option to xFLAGS, if it doesn't break
|
||||||
|
dnl compilation. If the option to be tested is different than the
|
||||||
|
dnl option that should actually be added, add the option to be
|
||||||
|
dnl actually added as a second argument.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_ADD_CFLAGS], [PA_ADD_FLAGS(CFLAGS, [$1], [$2], [$3], [$4])])
|
||||||
39
autoconf/m4/pa_add_flags.m4
Normal file
39
autoconf/m4/pa_add_flags.m4
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ADD_FLAGS(flagvar, flags)
|
||||||
|
dnl
|
||||||
|
dnl Add [flags] to the variable [flagvar] if and only if it is accepted
|
||||||
|
dnl by all languages affected by [flagvar], if those languages have
|
||||||
|
dnl been previously seen in the script.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_ADD_FLAGS],
|
||||||
|
[
|
||||||
|
AS_VAR_PUSHDEF([old], [_$0_$1_orig])
|
||||||
|
AS_VAR_PUSHDEF([ok], [_$0_$1_ok])
|
||||||
|
AS_VAR_PUSHDEF([flags], [$1])
|
||||||
|
|
||||||
|
AS_VAR_COPY([old], [flags])
|
||||||
|
AS_VAR_SET([flags], ["$flags $2"])
|
||||||
|
AS_VAR_SET([ok], [yes])
|
||||||
|
|
||||||
|
PA_LANG_FOREACH(PA_FLAGS_LANGLIST($1),
|
||||||
|
[AS_VAR_IF([ok], [yes],
|
||||||
|
[AC_MSG_CHECKING([if $]_AC_CC[ accepts $2])
|
||||||
|
PA_BUILD_IFELSE([],
|
||||||
|
[AC_MSG_RESULT([yes])],
|
||||||
|
[AC_MSG_RESULT([no])
|
||||||
|
AS_VAR_SET([ok], [no])])])
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_VAR_IF([ok], [yes],
|
||||||
|
[m4_ifnblank([$3],[AS_VAR_SET([flags], ["$old $3"])])
|
||||||
|
m4_foreach_w([_pa_add_flags_flag], [m4_ifblank([$3],[$2],[$3])],
|
||||||
|
[AC_DEFINE(PA_SYM([$1_]_pa_add_flags_flag), 1,
|
||||||
|
[Define to 1 if compiled with the ]_pa_add_flags_flag[ compiler flag])])
|
||||||
|
$4],
|
||||||
|
[AS_VAR_SET([flags], ["$old"])
|
||||||
|
$5])
|
||||||
|
|
||||||
|
AS_VAR_POPDEF([flags])
|
||||||
|
AS_VAR_POPDEF([ok])
|
||||||
|
AS_VAR_POPDEF([old])
|
||||||
|
])
|
||||||
13
autoconf/m4/pa_add_headers.m4
Normal file
13
autoconf/m4/pa_add_headers.m4
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ADD_HEADERS(headers...)
|
||||||
|
dnl
|
||||||
|
dnl Call AC_CHECK_HEADERS(), and add to ac_includes_default if found
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([_PA_ADD_HEADER],
|
||||||
|
[AC_CHECK_HEADERS([$1],[ac_includes_default="$ac_includes_default
|
||||||
|
#include <$1>"
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([PA_ADD_HEADERS],
|
||||||
|
[m4_map_args_w([$1],[_PA_ADD_HEADER(],[)])])
|
||||||
27
autoconf/m4/pa_add_langflags.m4
Normal file
27
autoconf/m4/pa_add_langflags.m4
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ADD_LANGFLAGS(flag...)
|
||||||
|
dnl
|
||||||
|
dnl Attempt to add the option in the given list to each compiler flags
|
||||||
|
dnl (CFLAGS, CXXFLAGS, ...), if it doesn't break compilation.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
m4_defun([_PA_LANGFLAG_VAR],
|
||||||
|
[m4_case([$1],
|
||||||
|
[C], [CFLAGS],
|
||||||
|
[C++], [CXXFLAGS],
|
||||||
|
[Fortran 77], [FFLAGS],
|
||||||
|
[Fortran], [FCFLAGS],
|
||||||
|
[Erlang], [ERLCFLAGS],
|
||||||
|
[Objective C], [OBJCFLAGS],
|
||||||
|
[Objective C++], [OBJCXXFLAGS],
|
||||||
|
[Go], [GOFLAGS],
|
||||||
|
[m4_fatal([PA_ADD_LANGFLAGS: Unknown language: $1])])])
|
||||||
|
|
||||||
|
AC_DEFUN([PA_ADD_LANGFLAGS],
|
||||||
|
[m4_pushdef([_pa_langflags],m4_dquote($1))dnl
|
||||||
|
m4_set_foreach(_PA_LANG_SEEN_SET,[_pa_lang],dnl
|
||||||
|
[_pa_flag_found=no
|
||||||
|
m4_foreach_w([_pa_flag], _pa_langflags,
|
||||||
|
[AS_IF([test $_pa_flag_found = no],
|
||||||
|
[PA_ADD_FLAGS(_PA_LANGFLAG_VAR(_pa_lang),_pa_flag,[],[_pa_flag_found=yes])])
|
||||||
|
])])
|
||||||
|
m4_popdef([_pa_langflags])])
|
||||||
19
autoconf/m4/pa_arg_bool.m4
Normal file
19
autoconf/m4/pa_arg_bool.m4
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ARG_BOOL(option,helptext,default,enabled_action,disabled_action)
|
||||||
|
dnl
|
||||||
|
dnl The last three arguments are optional; default can be yes or no.
|
||||||
|
dnl
|
||||||
|
dnl Simpler-to-use versions of AC_ARG_ENABLED, that include the
|
||||||
|
dnl test for $enableval and the AS_HELP_STRING definition. This is only
|
||||||
|
dnl to be used for boolean options.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_ARG_BOOL],
|
||||||
|
[m4_pushdef([pa_default],m4_default(m4_normalize([$3]),[no]))
|
||||||
|
m4_pushdef([pa_option],m4_case(pa_default,[yes],[disable],[enable]))
|
||||||
|
AC_ARG_ENABLE([$1],
|
||||||
|
[AS_HELP_STRING([--]m4_defn([pa_option])[-$1],[$2])],
|
||||||
|
[pa_arg_bool_enableval="$enableval"],
|
||||||
|
[pa_arg_bool_enableval="]m4_defn([pa_default])["])
|
||||||
|
m4_popdef([pa_option], [pa_default])
|
||||||
|
AS_IF([test x"$pa_arg_bool_enableval" != xno], [$4], [$5])
|
||||||
|
])
|
||||||
4
autoconf/m4/pa_arg_disabled.m4
Normal file
4
autoconf/m4/pa_arg_disabled.m4
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ARG_DISABLED(option,helptext,disabled_action,enabled_action)
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_ARG_DISABLED],[PA_ARG_BOOL([$1],[$2],yes,[$4],[$3])])
|
||||||
4
autoconf/m4/pa_arg_enabled.m4
Normal file
4
autoconf/m4/pa_arg_enabled.m4
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_ARG_ENABLED(option,helptext,enabled_action,disabled_action)
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_ARG_ENABLED],[PA_ARG_BOOL([$1],[$2],no,[$3],[$4])])
|
||||||
16
autoconf/m4/pa_build_ifelse.m4
Normal file
16
autoconf/m4/pa_build_ifelse.m4
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_BUILD_IFELSE(input [,success [,failure]])
|
||||||
|
dnl
|
||||||
|
dnl Same as AC_LINK_IFELSE for languages where linking is applicable,
|
||||||
|
dnl otherwise AC_COMPILE_IFELSE.
|
||||||
|
dnl
|
||||||
|
dnl If the first argument is empty, use _AC_LANG_IO_PROGRAM.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
m4_defun([_PA_BUILD_IFELSE],
|
||||||
|
[m4_case(_AC_LANG,
|
||||||
|
[Erlang], [AC_COMPILE_IFELSE($@)],
|
||||||
|
[AC_LINK_IFELSE($@)])])
|
||||||
|
|
||||||
|
AC_DEFUN([PA_BUILD_IFELSE],
|
||||||
|
[_PA_BUILD_IFELSE([m4_ifblank([$1],[AC_LANG_SOURCE(_AC_LANG_IO_PROGRAM)],
|
||||||
|
[$1])],[$2],[$3])])
|
||||||
32
autoconf/m4/pa_c_typeof.m4
Normal file
32
autoconf/m4/pa_c_typeof.m4
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_C_TYPEOF
|
||||||
|
dnl
|
||||||
|
dnl Find if typeof() exists, or an equivalent (__typeof__, decltype,
|
||||||
|
dnl __decltype__)
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_C_TYPEOF],
|
||||||
|
[AC_CACHE_CHECK([if $CC supports typeof], [pa_cv_typeof],
|
||||||
|
[pa_cv_typeof=no
|
||||||
|
for pa_typeof_try in typeof __typeof __typeof__ decltype __decltype __decltype__ _Decltype
|
||||||
|
do
|
||||||
|
AS_IF([test $pa_cv_typeof = no],
|
||||||
|
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||||
|
AC_INCLUDES_DEFAULT
|
||||||
|
int testme(int x);
|
||||||
|
int testme(int x)
|
||||||
|
{
|
||||||
|
$pa_typeof_try(x) y = x*x;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
])],
|
||||||
|
[pa_cv_typeof=$pa_typeof_try])])
|
||||||
|
done
|
||||||
|
])
|
||||||
|
AS_IF([test $pa_cv_typeof = no],
|
||||||
|
[],
|
||||||
|
[AC_DEFINE([HAVE_TYPEOF], 1,
|
||||||
|
[Define to 1 if you have some version of the typeof operator.])
|
||||||
|
AS_IF([test $pa_cv_typeof = typeof],
|
||||||
|
[],
|
||||||
|
[AC_DEFINE_UNQUOTED([typeof], [$pa_cv_typeof],
|
||||||
|
[Define if your typeof operator is not named `typeof'.])])])])
|
||||||
26
autoconf/m4/pa_check_bad_stdc_inline.m4
Normal file
26
autoconf/m4/pa_check_bad_stdc_inline.m4
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_CHECK_BAD_STDC_INLINE
|
||||||
|
dnl
|
||||||
|
dnl Some versions of gcc seem to apply -Wmissing-prototypes to C99
|
||||||
|
dnl inline functions, which means we need to use GNU inline syntax
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_CHECK_BAD_STDC_INLINE],
|
||||||
|
[AC_MSG_CHECKING([if $CC supports C99 external inlines])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||||
|
AC_INCLUDES_DEFAULT
|
||||||
|
|
||||||
|
/* Don't mistake GNU inlines for c99 */
|
||||||
|
#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
|
||||||
|
# error "Using gnu inline standard"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline int foo(int x)
|
||||||
|
{
|
||||||
|
return x+1;
|
||||||
|
}
|
||||||
|
])],
|
||||||
|
[AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE([HAVE_STDC_INLINE], 1,
|
||||||
|
[Define to 1 if your compiler supports C99 extern inline])],
|
||||||
|
[AC_MSG_RESULT([no])
|
||||||
|
PA_ADD_CFLAGS([-fgnu89-inline])])])
|
||||||
17
autoconf/m4/pa_check_inttypes_h_sane.m4
Normal file
17
autoconf/m4/pa_check_inttypes_h_sane.m4
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
dnl ------------------------------------------------------------------------
|
||||||
|
dnl PA_CHECK_INTTYPES_H_SANE
|
||||||
|
dnl
|
||||||
|
dnl At least some versions of AIX 4 have <inttypes.h> macros which are
|
||||||
|
dnl completely broken. Try to detect those.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_CHECK_INTTYPES_H_SANE],
|
||||||
|
[AC_CHECK_HEADERS_ONCE(inttypes.h)
|
||||||
|
AS_IF([test "x$ac_cv_header_inttypes_h" = xyes],[
|
||||||
|
AC_MSG_CHECKING([if inttypes.h is sane])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
|
||||||
|
[uintmax_t max = UINTMAX_C(0);
|
||||||
|
printf("%"PRIuMAX"\n", max);])],
|
||||||
|
[AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE(INTTYPES_H_IS_SANE, 1,
|
||||||
|
[Define if the macros in <inttypes.h> are usable])],
|
||||||
|
[AC_MSG_RESULT([no (AIX, eh?)])])])])
|
||||||
41
autoconf/m4/pa_cross_compile.m4
Normal file
41
autoconf/m4/pa_cross_compile.m4
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_CROSS_COMPILE
|
||||||
|
dnl
|
||||||
|
dnl Get the canonical name for the build and host (runtime) systems;
|
||||||
|
dnl then figure out if this is cross-compilation. Specifically, this
|
||||||
|
dnl disables invoking WINE on non-Windows systems which are configured
|
||||||
|
dnl to run WINE automatically.
|
||||||
|
dnl
|
||||||
|
dnl Use PA_CROSS_COMPILE_TOOL if the target system (output of a code-
|
||||||
|
dnl generation tool) is applicable.
|
||||||
|
dnl
|
||||||
|
dnl This doesn't explicitly print any messages as that is automatically
|
||||||
|
dnl done elsewhere.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN_ONCE([PA_CROSS_COMPILE],
|
||||||
|
[
|
||||||
|
AC_BEFORE([$0], [AC_LANG_COMPILER])
|
||||||
|
AC_BEFORE([$0], [AC_LANG])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_CC])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_CPP])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_CXX])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_CXXCPP])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_OBJC])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_OBJCPP])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_OBJCXX])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_OBJCXXCPP])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_F77])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_FC])
|
||||||
|
AC_BEFORE([$0], [AC_PROG_GO])
|
||||||
|
|
||||||
|
# Disable WINE
|
||||||
|
WINELOADER=/dev/null
|
||||||
|
export WINELOADER
|
||||||
|
WINESERVER=/dev/null
|
||||||
|
export WINESERVER
|
||||||
|
WINEPREFIX=/dev/null
|
||||||
|
export WINEPREFIX
|
||||||
|
|
||||||
|
AC_CANONICAL_BUILD
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
])
|
||||||
19
autoconf/m4/pa_flags_langlist.m4
Normal file
19
autoconf/m4/pa_flags_langlist.m4
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_FLAGS_LANGLIST(flagvar)
|
||||||
|
dnl
|
||||||
|
dnl Return a list of languages affected by the variable flagvar.
|
||||||
|
dnl If flagvar is unknown, assume it affects the current language.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_FLAGS_LANGLIST],
|
||||||
|
[m4_dquote(m4_case([$1],
|
||||||
|
[CPPFLAGS], [[C],[C++],[Objective C],[Objective C++]],
|
||||||
|
[CFLAGS], [[C]],
|
||||||
|
[CXXFLAGS], [[C++]],
|
||||||
|
[FFLAGS], [[Fortran 77]],
|
||||||
|
[FCFLAGS], [[Fortran]],
|
||||||
|
[ERLCFLAGS], [[Erlang]],
|
||||||
|
[OBJCFLAGS], [[Objective C]],
|
||||||
|
[OBJCXXFLAGS], [[Objective C++]],
|
||||||
|
[GOFLAGS], [[Go]],
|
||||||
|
[LDFLAGS], [[C],[C++],[Fortran 77],[Fortran],[Objective C],[Objective C++],[Go]],
|
||||||
|
m4_dquote(_AC_LANG)))])
|
||||||
26
autoconf/m4/pa_have_tcpwrappers.m4
Normal file
26
autoconf/m4/pa_have_tcpwrappers.m4
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_HAVE_TCPWRAPPERS
|
||||||
|
dnl
|
||||||
|
dnl Do we have the tcpwrappers -lwrap? This can't be done using AC_CHECK_LIBS
|
||||||
|
dnl due to the need to provide "allow_severity" and "deny_severity" variables
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_HAVE_TCPWRAPPERS],
|
||||||
|
[AC_CHECK_LIB([wrap], [main])
|
||||||
|
AC_MSG_CHECKING([for tcpwrappers])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||||
|
[[
|
||||||
|
#include <tcpd.h>
|
||||||
|
int allow_severity = 0;
|
||||||
|
int deny_severity = 0;
|
||||||
|
]],
|
||||||
|
[[
|
||||||
|
hosts_ctl("sample_daemon", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN);
|
||||||
|
]])],
|
||||||
|
[
|
||||||
|
AC_DEFINE(HAVE_TCPWRAPPERS, 1,
|
||||||
|
[Define if we have tcpwrappers (-lwrap) and <tcpd.h>.])
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
],
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
])])
|
||||||
15
autoconf/m4/pa_lang_foreach.m4
Normal file
15
autoconf/m4/pa_lang_foreach.m4
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_LANG_FOREACH(subset, body)
|
||||||
|
dnl
|
||||||
|
dnl Expand [body] for each language encountered in the configure script also
|
||||||
|
dnl present in [subset], or all if [subset] is empty
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([_PA_LANG_DO],dnl
|
||||||
|
[AC_LANG([$2])dnl
|
||||||
|
$1])
|
||||||
|
|
||||||
|
AC_DEFUN([PA_LANG_FOREACH],dnl
|
||||||
|
[m4_pushdef([_pa_lang_foreach_current],[_AC_LANG])dnl
|
||||||
|
m4_map_args([m4_curry([_PA_LANG_DO],[$2])],m4_unquote(PA_LANG_SEEN_LIST($1)))dnl
|
||||||
|
AC_LANG(_pa_lang_foreach_current)dnl
|
||||||
|
m4_popdef([_pa_lang_foreach_current])])
|
||||||
20
autoconf/m4/pa_lang_seen_list.m4
Normal file
20
autoconf/m4/pa_lang_seen_list.m4
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_LANG_SEEN_LIST(subset)
|
||||||
|
dnl
|
||||||
|
dnl List of the language lang has been used in the configuration
|
||||||
|
dnl script so far, possibly subset by [subset].
|
||||||
|
dnl
|
||||||
|
dnl This relies on overriding _AC_LANG_SET(from, to),
|
||||||
|
dnl the internal implementation of _AC_LANG.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
m4_ifndef([_PA_LANG_SET],
|
||||||
|
[m4_rename([_AC_LANG_SET], [_PA_LANG_SET])dnl
|
||||||
|
m4_defun([_AC_LANG_SET], [m4_set_add([_PA_LANG_SEEN_SET],[$2])dnl
|
||||||
|
_PA_LANG_SET($@)])])
|
||||||
|
|
||||||
|
AC_DEFUN([PA_LANG_SEEN_LIST],
|
||||||
|
[m4_set_delete([_pa_lang_seen_subset])dnl
|
||||||
|
m4_pushdef([_pa_lang_seen_subset_list],m4_ifnblank([$1],[$1],m4_dquote(m4_set_list([_PA_LANG_SEEN_SET]))))dnl
|
||||||
|
m4_set_add_all([_pa_lang_seen_subset],_pa_lang_seen_subset_list)dnl
|
||||||
|
m4_cdr(m4_set_intersection([_pa_lang_seen_subset],[_PA_LANG_SEEN_SET]))dnl
|
||||||
|
m4_popdef([_pa_lang_seen_subset_list])])
|
||||||
13
autoconf/m4/pa_option_debug.m4
Normal file
13
autoconf/m4/pa_option_debug.m4
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_OPTION_DEBUG(with_debug, without_debug)
|
||||||
|
dnl
|
||||||
|
dnl Set debug flags and optimization flags depending on if
|
||||||
|
dnl --enable-debug is set or not. Some flags are set regardless...
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_OPTION_DEBUG],
|
||||||
|
[PA_ARG_DISABLED([gdb], [disable gdb debug extensions],
|
||||||
|
[PA_ADD_LANGFLAGS([-g3])], [PA_ADD_LANGFLAGS([-ggdb3 -g3])])
|
||||||
|
PA_ARG_ENABLED([debug], [optimize for debugging],
|
||||||
|
[PA_ADD_LANGFLAGS([-Og -O0])
|
||||||
|
$1],
|
||||||
|
[$2])])
|
||||||
8
autoconf/m4/pa_option_profiling.m4
Normal file
8
autoconf/m4/pa_option_profiling.m4
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_OPTION_PROFILING(with_profiling, without_profiling)
|
||||||
|
dnl
|
||||||
|
dnl Try to enable profiling if --enable-profiling is set.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_OPTION_PROFILING],
|
||||||
|
[PA_ARG_ENABLED([profiling], [compile with profiling (-pg option)],
|
||||||
|
[PA_ADD_LANGFLAGS([-pg])])])
|
||||||
13
autoconf/m4/pa_prog_cc.m4
Normal file
13
autoconf/m4/pa_prog_cc.m4
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_PROG_CC()
|
||||||
|
dnl
|
||||||
|
dnl Similar to AC_PROG_CC, but add a prototype for main() to
|
||||||
|
dnl AC_INCLUDES_DEFAULT to avoid -Werror from breaking compilation.
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_PROG_CC],
|
||||||
|
[AC_PROG_CC
|
||||||
|
AS_IF([test x$ac_cv_prog != xno],
|
||||||
|
[ac_includes_default="$ac_includes_default
|
||||||
|
#ifndef __cplusplus
|
||||||
|
extern int main(void);
|
||||||
|
#endif"])])
|
||||||
22
autoconf/m4/pa_search_libs_and_add.m4
Normal file
22
autoconf/m4/pa_search_libs_and_add.m4
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_SEARCH_LIBS_AND_ADD
|
||||||
|
dnl
|
||||||
|
dnl PA_SEARCH_LIBS_AND_ADD(function, libraries [,function to add])
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_SEARCH_LIBS_AND_ADD],
|
||||||
|
[
|
||||||
|
AH_TEMPLATE(AS_TR_CPP(HAVE_$1), [Define if $1 function was found])
|
||||||
|
AC_SEARCH_LIBS($1, $2,
|
||||||
|
[
|
||||||
|
AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1))
|
||||||
|
pa_add_$1=false;
|
||||||
|
],
|
||||||
|
[
|
||||||
|
XTRA=true;
|
||||||
|
if test $# -eq 3; then
|
||||||
|
AC_LIBOBJ($3)
|
||||||
|
else
|
||||||
|
AC_LIBOBJ($1)
|
||||||
|
fi
|
||||||
|
pa_add_$1=true;
|
||||||
|
])])
|
||||||
25
autoconf/m4/pa_sigsetjmp.m4
Normal file
25
autoconf/m4/pa_sigsetjmp.m4
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_SIGSETJMP
|
||||||
|
dnl
|
||||||
|
dnl Do we have sigsetjmp/siglongjmp? (AC_CHECK_FUNCS doesn't seem to work
|
||||||
|
dnl for these particular functions.)
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_SIGSETJMP],
|
||||||
|
[AC_MSG_CHECKING([for sigsetjmp])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_SOURCE(
|
||||||
|
[
|
||||||
|
AC_INCLUDES_DEFAULT
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
sigjmp_buf buf;
|
||||||
|
if (sigsetjmp(buf,1))
|
||||||
|
return 0;
|
||||||
|
siglongjmp(buf,2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
])],
|
||||||
|
[AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE([HAVE_SIGSETJMP], 1,
|
||||||
|
[Define to 1 if your system has sigsetjmp/siglongjmp])],
|
||||||
|
[AC_MSG_RESULT([no])])])
|
||||||
11
autoconf/m4/pa_sym.m4
Normal file
11
autoconf/m4/pa_sym.m4
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
dnl PA_SYM(prefix, string)
|
||||||
|
dnl
|
||||||
|
dnl Convert a (semi-) arbitrary string to a CPP symbol
|
||||||
|
dnl Compact underscores and convert non-C characters to underscore,
|
||||||
|
dnl except + which is converted to X (so C++ -> CXX).
|
||||||
|
dnl --------------------------------------------------------------------------
|
||||||
|
AC_DEFUN([PA_SYM],
|
||||||
|
[m4_bpatsubsts(m4_quote(m4_toupper([$*])),
|
||||||
|
[,],[],[\+],[X],[[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]+],[_],dnl
|
||||||
|
[^._?\(.*\)_.$],[[\1]])])
|
||||||
83
autogen.sh
Executable file
83
autogen.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#!/bin/sh -x
|
||||||
|
#
|
||||||
|
# Run this script to regenerate autoconf files
|
||||||
|
#
|
||||||
|
recheck=false
|
||||||
|
for arg; do
|
||||||
|
case x"$arg" in
|
||||||
|
x--recheck)
|
||||||
|
recheck=true
|
||||||
|
config=$(sh config.status --config 2>/dev/null)
|
||||||
|
;;
|
||||||
|
x--clearenv)
|
||||||
|
unset AUTOCONF AUTOMAKE ACLOCAL AUTOHEADER ACLOCAL_PATH
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "$0: unknown option: $arg" 1>&2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This allows for overriding the default autoconf programs
|
||||||
|
AUTOCONF="${AUTOCONF:-${AUTOTOOLS_PREFIX}autoconf}"
|
||||||
|
AUTOMAKE="${AUTOMAKE:-${AUTOTOOLS_PREFIX}automake}"
|
||||||
|
ACLOCAL="${ACLOCAL:-${AUTOTOOLS_PREFIX}aclocal}"
|
||||||
|
AUTOHEADER="${AUTOHEADER:-${AUTOTOOLS_PREFIX}autoheader}"
|
||||||
|
|
||||||
|
mkdir -p autoconf autoconf/helpers config
|
||||||
|
autolib="`"$AUTOMAKE" --print-libdir`"
|
||||||
|
if test ! x"$autolib" = x; then
|
||||||
|
for prg in install-sh compile config.guess config.sub; do
|
||||||
|
# Update autoconf helpers if and only if newer ones are available
|
||||||
|
if test -f "$autolib"/"$prg" && \
|
||||||
|
( set -e ; \
|
||||||
|
test -f autoconf/helpers/"$prg" && sed -n \
|
||||||
|
-e 's/^scriptver=/scriptversion=/' \
|
||||||
|
-e 's/^timestamp=/scriptversion=/' \
|
||||||
|
-e 's/^scriptversion=['\''"]?\([^'\''"]*\).*$/\1/p' \
|
||||||
|
"$autolib"/"$prg" autoconf/helpers/"$prg" | \
|
||||||
|
sort -c 2>/dev/null ; \
|
||||||
|
test $? -ne 0 )
|
||||||
|
then
|
||||||
|
cp -f "$autolib"/"$prg" autoconf/helpers
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
mv -f autoconf/aclocal.m4 autoconf/aclocal.m4.old
|
||||||
|
mkdir -p autoconf/m4.old autoconf/m4
|
||||||
|
mv -f autoconf/m4/*.m4 autoconf/m4.old/ 2>/dev/null || true
|
||||||
|
ACLOCAL_PATH="${ACLOCAL_PATH}${ACLOCAL_PATH:+:}`pwd`/autoconf/m4.old"
|
||||||
|
export ACLOCAL_PATH
|
||||||
|
"$ACLOCAL" --install --output=autoconf/aclocal.m4 -I autoconf/m4
|
||||||
|
if test ! -f autoconf/aclocal.m4; then
|
||||||
|
# aclocal failed, revert to previous files
|
||||||
|
mv -f autoconf/m4.old/*.m4 autoconf/m4/
|
||||||
|
mv -f autoconf/aclocal.m4.old autoconf/aclocal.m4
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -rf autoconf/*m4.old
|
||||||
|
"$AUTOHEADER" -B autoconf
|
||||||
|
"$AUTOCONF" -B autoconf
|
||||||
|
(
|
||||||
|
echo '#!/bin/sh'
|
||||||
|
"$AUTOCONF" -B autoconf \
|
||||||
|
-t AC_CONFIG_HEADERS:'rm -f $*' \
|
||||||
|
-t AC_CONFIG_FILES:'rm -f $*'
|
||||||
|
echo 'rm -f config.log config.status'
|
||||||
|
echo 'rm -rf autom4te.cache'
|
||||||
|
) > autoconf/clean.sh
|
||||||
|
chmod +x autoconf/clean.sh
|
||||||
|
sh autoconf/clean.sh
|
||||||
|
|
||||||
|
rm -f configure~ || true
|
||||||
|
|
||||||
|
# Try to regenerate unconfig.h if Perl is available and unconfig.pl
|
||||||
|
# is present in the autoconf directory.
|
||||||
|
if [ -n "$(which perl)" -a -f autoconf/unconfig.pl ]; then
|
||||||
|
perl autoconf/unconfig.pl . config/config.h.in config/unconfig.h
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $recheck; then
|
||||||
|
# This bizarre statement has to do with how config.status quotes its output
|
||||||
|
echo exec sh configure $config | sh -
|
||||||
|
fi
|
||||||
25
common/Makefile
Normal file
25
common/Makefile
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
SRCROOT = ..
|
||||||
|
VERSION = $(shell cat ../version)
|
||||||
|
|
||||||
|
-include ../config/MCONFIG
|
||||||
|
include ../MRULES
|
||||||
|
|
||||||
|
OBJS = tftpsubs.$(O) signal.$(O)
|
||||||
|
LIB = libcommon.a
|
||||||
|
|
||||||
|
all: $(LIB)
|
||||||
|
|
||||||
|
$(LIB): $(OBJS)
|
||||||
|
-rm -f $(LIB)
|
||||||
|
$(AR) $(LIB) $(OBJS)
|
||||||
|
$(RANLIB) $(LIB)
|
||||||
|
|
||||||
|
$(OBJS): tftpsubs.h
|
||||||
|
|
||||||
|
install:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.obj *.exe $(LIB)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f *~
|
||||||
19
common/signal.c
Normal file
19
common/signal.c
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* signal.c
|
||||||
|
*
|
||||||
|
* User-friendly wrapper around sigaction().
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int tftp_signal(int signum, sighandler_t handler, int flags)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof sa);
|
||||||
|
sa.sa_handler = handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = flags;
|
||||||
|
|
||||||
|
return sigaction(signum, &sa, NULL);
|
||||||
|
}
|
||||||
406
common/tftpsubs.c
Normal file
406
common/tftpsubs.c
Normal file
|
|
@ -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
|
||||||
|
|
@ -1,8 +1,3 @@
|
||||||
/* $Id$ */
|
|
||||||
|
|
||||||
/* $OpenBSD: tftpsubs.h,v 1.2 1996/06/26 05:40:37 deraadt Exp $ */
|
|
||||||
/* $NetBSD: tftpsubs.h,v 1.2 1994/12/08 09:51:32 jtc Exp $ */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1993
|
* Copyright (c) 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
|
@ -34,8 +29,6 @@
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
|
||||||
* @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -47,30 +40,82 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
union sock_addr {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_in si;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
struct sockaddr_in6 s6;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SOCKLEN(sock) \
|
||||||
|
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
|
||||||
|
(sizeof(struct sockaddr_in)) : \
|
||||||
|
(sizeof(union sock_addr)))
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#define SOCKPORT(sock) \
|
||||||
|
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
|
||||||
|
((union sock_addr*)sock)->si.sin_port : \
|
||||||
|
((union sock_addr*)sock)->s6.sin6_port)
|
||||||
|
#else
|
||||||
|
#define SOCKPORT(sock) \
|
||||||
|
(((union sock_addr*)sock)->si.sin_port)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#define SOCKADDR_P(sock) \
|
||||||
|
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
|
||||||
|
(void *)&((union sock_addr*)sock)->si.sin_addr : \
|
||||||
|
(void *)&((union sock_addr*)sock)->s6.sin6_addr)
|
||||||
|
#else
|
||||||
|
#define SOCKADDR_P(sock) \
|
||||||
|
(void *)&((union sock_addr*)sock)->si.sin_addr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_numeric_ipv6(const char *);
|
||||||
|
char *strip_address(char *);
|
||||||
|
#else
|
||||||
|
#define is_numeric_ipv6(a) 0
|
||||||
|
#define strip_address(a) (a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int sa_set_port(union sock_addr *s, u_short port)
|
||||||
|
{
|
||||||
|
switch (s->sa.sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
s->si.sin_port = port;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case AF_INET6:
|
||||||
|
s->s6.sin6_port = port;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_sock_addr(char *, union sock_addr *, char **);
|
||||||
|
|
||||||
struct tftphdr;
|
struct tftphdr;
|
||||||
|
|
||||||
struct tftphdr *r_init(void);
|
struct tftphdr *r_init(void);
|
||||||
void read_ahead(FILE *, int);
|
void read_ahead(FILE *, int);
|
||||||
int readit(FILE *, struct tftphdr **, int);
|
int readit(FILE *, struct tftphdr **, int);
|
||||||
|
|
||||||
int synchnet(int);
|
int synchnet(int);
|
||||||
|
|
||||||
struct tftphdr *w_init(void);
|
struct tftphdr *w_init(void);
|
||||||
int write_behind(FILE *, int);
|
int write_behind(FILE *, int);
|
||||||
int writeit(FILE *, struct tftphdr **, int, int);
|
int writeit(FILE *, struct tftphdr **, int, int);
|
||||||
|
|
||||||
extern int segsize;
|
extern int segsize;
|
||||||
#define MAX_SEGSIZE 65464
|
#define MAX_SEGSIZE 65464
|
||||||
|
|
||||||
/*
|
int pick_port_bind(int sockfd, union sock_addr *myaddr,
|
||||||
* Prototype for xmalloc/xstrdup
|
unsigned int from, unsigned int to);
|
||||||
*/
|
|
||||||
extern void *xmalloc(size_t);
|
|
||||||
extern char *xstrdup(const char *);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Signal-related stuff
|
|
||||||
*/
|
|
||||||
void (*bsd_signal(int, void (*)(int)))(int);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
134
config.h
134
config.h
|
|
@ -1,13 +1,12 @@
|
||||||
/* -*- c -*- ------------------------------------------------------------- *
|
/* -*- c -*- ------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2024 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
* http://www.openbsd.org/.
|
* http://www.openbsd.org/.
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------- */
|
||||||
/* $Id$ */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* config.h
|
* config.h
|
||||||
|
|
@ -18,12 +17,23 @@
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H 1
|
#define CONFIG_H 1
|
||||||
|
|
||||||
|
/* Feature enables for specific environments */
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1070
|
||||||
|
#define __APPLE_USE_RFC_3542 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Must be included before we include any system headers! */
|
/* Must be included before we include any system headers! */
|
||||||
#include "aconfig.h" /* autogenerated configuration header */
|
#include "config/config.h" /* autogenerated configuration header */
|
||||||
|
|
||||||
/* Standard includes */
|
/* Standard includes */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
@ -33,28 +43,13 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef STDC_HEADERS
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#else
|
|
||||||
#ifdef HAVE_STDLIB_H
|
|
||||||
#include <stdlib.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_MEMORY_H
|
|
||||||
#ifndef STDC_HEADERS
|
|
||||||
#include <memory.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_STRING_H
|
#ifdef HAVE_STRING_H
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STRINGS_H
|
#ifdef HAVE_STRINGS_H
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_INTTYPES_H
|
#ifdef HAVE_INTTYPES_H
|
||||||
#ifdef INTTYPES_H_IS_SANE
|
#ifdef INTTYPES_H_IS_SANE
|
||||||
|
|
@ -74,15 +69,8 @@
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TIME_WITH_SYS_TIME
|
#ifdef HAVE_SYS_TIME_H
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
|
||||||
#else
|
|
||||||
#if HAVE_SYS_TIME_H
|
|
||||||
#include <sys/time.h>
|
|
||||||
#else
|
|
||||||
#include <time.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GRP_H
|
#ifdef HAVE_GRP_H
|
||||||
|
|
@ -93,9 +81,6 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_SOCKET_H
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#else
|
#else
|
||||||
|
|
@ -107,12 +92,14 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_NETDB_H
|
||||||
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_LONG
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#else
|
#else
|
||||||
extern char *optarg;
|
#include "lib/getopt.h"
|
||||||
extern int optind, opterr, optopt;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Test for EAGAIN/EWOULDBLOCK */
|
/* Test for EAGAIN/EWOULDBLOCK */
|
||||||
|
|
@ -128,10 +115,10 @@ extern int optind, opterr, optopt;
|
||||||
|
|
||||||
/* Some broken systems care about text versus binary, but
|
/* Some broken systems care about text versus binary, but
|
||||||
real Unix systems don't... */
|
real Unix systems don't... */
|
||||||
#ifndef HAVE_O_TEXT_DEFINITION
|
#if !HAVE_DECL_O_TEXT
|
||||||
#define O_TEXT 0
|
#define O_TEXT 0
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_O_BINARY_DEFINITION
|
#if !HAVE_DECL_O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -217,6 +204,11 @@ typedef unsigned long u_long;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* socklen_t */
|
||||||
|
#ifndef HAVE_SOCKLEN_T
|
||||||
|
typedef int socklen_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* sysexits.h */
|
/* sysexits.h */
|
||||||
|
|
||||||
#ifdef HAVE_SYSEXITS_H
|
#ifdef HAVE_SYSEXITS_H
|
||||||
|
|
@ -261,11 +253,9 @@ typedef unsigned long u_long;
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#ifndef HAVE_IPPORT_TFTP_DEFINITION
|
#if !HAVE_DECL_IPPORT_TFTP && !defined(IPPORT_TFTP)
|
||||||
#ifndef IPPORT_TFTP
|
|
||||||
#define IPPORT_TFTP 69
|
#define IPPORT_TFTP 69
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
/* arpa/{inet,tftp}.h, and possible missing pieces */
|
/* arpa/{inet,tftp}.h, and possible missing pieces */
|
||||||
|
|
||||||
|
|
@ -282,6 +272,72 @@ typedef unsigned long u_long;
|
||||||
#define EOPTNEG 8
|
#define EOPTNEG 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Prototypes for libxtra functions */
|
||||||
|
|
||||||
|
void *xmalloc(size_t);
|
||||||
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
|
#ifndef HAVE_SIGHANDLER_T
|
||||||
|
typedef void (*sighandler_t)(int);
|
||||||
|
#endif
|
||||||
|
int tftp_signal(int, sighandler_t, int);
|
||||||
|
|
||||||
|
#ifndef HAVE_DUP2
|
||||||
|
int dup2(int, int);
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_DAEMON
|
||||||
|
int daemon(int, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_GETADDRINFO
|
||||||
|
#ifndef HAVE_STRUCT_ADDRINFO
|
||||||
|
struct addrinfo {
|
||||||
|
int ai_flags;
|
||||||
|
int ai_family;
|
||||||
|
int ai_socktype;
|
||||||
|
int ai_protocol;
|
||||||
|
size_t ai_addrlen;
|
||||||
|
struct sockaddr *ai_addr;
|
||||||
|
char *ai_canonname;
|
||||||
|
struct addrinfo *ai_next;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
int getaddrinfo(const char *, const char *, const struct addrinfo *,
|
||||||
|
struct addrinfo **);
|
||||||
|
void freeaddrinfo(struct addrinfo *);
|
||||||
|
const char *gai_strerror(int);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef EAI_NONAME
|
||||||
|
#define EAI_NONAME -2 /* NAME or SERVICE is unknown. */
|
||||||
|
#endif
|
||||||
|
#ifndef EAI_ADDRFAMILY
|
||||||
|
#define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */
|
||||||
|
#endif
|
||||||
|
#ifndef EAI_MEMORY
|
||||||
|
#define EAI_MEMORY -10 /* Memory allocation failure. */
|
||||||
|
#endif
|
||||||
|
#ifndef EAI_SYSTEM
|
||||||
|
#define EAI_SYSTEM -11 /* System error returned in `errno'. */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef AI_CANONNAME
|
||||||
|
#define AI_CANONNAME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef AI_ADDRCONFIG
|
||||||
|
#define AI_ADDRCONFIG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INET6_ADDRSTRLEN
|
||||||
|
#define INET6_ADDRSTRLEN 46
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_INET_NTOP
|
||||||
|
const char *inet_ntop(int, const void *, char *, socklen_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* tftp-hpa version and configuration strings */
|
/* tftp-hpa version and configuration strings */
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
## -*- makefile -*- ------------------------------------------------------
|
## -*- makefile -*- ------------------------------------------------------
|
||||||
##
|
##
|
||||||
## Copyright 2001 H. Peter Anvin - All Rights Reserved
|
## Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
|
||||||
##
|
##
|
||||||
## This program is free software available under the same license
|
## This program is free software available under the same license
|
||||||
## as the "OpenBSD" operating system, distributed at
|
## as the "OpenBSD" operating system, distributed at
|
||||||
## http://www.openbsd.org/.
|
## http://www.openbsd.org/.
|
||||||
##
|
##
|
||||||
## -----------------------------------------------------------------------
|
## -----------------------------------------------------------------------
|
||||||
## $Id$
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## MCONFIG.in
|
## MCONFIG.in
|
||||||
|
|
@ -32,6 +31,9 @@ MANDIR = @mandir@
|
||||||
# System binaries
|
# System binaries
|
||||||
SBINDIR = @sbindir@
|
SBINDIR = @sbindir@
|
||||||
|
|
||||||
|
# Data root directory
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
|
||||||
# Binary suffixes
|
# Binary suffixes
|
||||||
O = @OBJEXT@
|
O = @OBJEXT@
|
||||||
X = @EXEEXT@
|
X = @EXEEXT@
|
||||||
|
|
@ -55,8 +57,8 @@ CFLAGS = @CFLAGS@ -I$(SRCROOT)
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
# Libraries (client and server)
|
# Libraries (client and server)
|
||||||
TFTP_LIBS = @TFTP_LIBS@
|
TFTP_LIBS = ../common/libcommon.a @TFTP_LIBS@
|
||||||
TFTPD_LIBS = @TFTPD_LIBS@
|
TFTPD_LIBS = ../common/libcommon.a @TFTPD_LIBS@
|
||||||
|
|
||||||
# Additional library we need to build
|
# Additional library we need to build
|
||||||
LIBOBJS = @LIBOBJS@
|
LIBOBJS = @LIBOBJS@
|
||||||
283
configure.ac
Normal file
283
configure.ac
Normal file
|
|
@ -0,0 +1,283 @@
|
||||||
|
dnl Process this file with autoconf 2.71 or later to produce
|
||||||
|
dnl a configure script.
|
||||||
|
AC_PREREQ([2.71])
|
||||||
|
AC_INIT
|
||||||
|
AC_CONFIG_SRCDIR([MRULES])
|
||||||
|
AC_PREFIX_DEFAULT([/usr])
|
||||||
|
AC_CONFIG_AUX_DIR([autoconf/helpers])
|
||||||
|
|
||||||
|
dnl This prevents us from running Wine and thinking we are not
|
||||||
|
dnl cross-compiling when in fact we are; running Wine here is at
|
||||||
|
dnl the best very slow and doesn't buy us a single thing at all.
|
||||||
|
PA_CROSS_COMPILE
|
||||||
|
|
||||||
|
dnl Enable any available C extensions
|
||||||
|
PA_PROG_CC
|
||||||
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
|
|
||||||
|
dnl Options for debugging and profiling
|
||||||
|
PA_OPTION_DEBUG
|
||||||
|
PA_OPTION_PROFILING
|
||||||
|
|
||||||
|
dnl LLVM doesn't error out on invalid -W options unless this option is
|
||||||
|
dnl specified first. Enable this so this script can actually discover
|
||||||
|
dnl which -W options are possible for this compiler.
|
||||||
|
PA_ADD_CFLAGS([-Werror=unknown-warning-option])
|
||||||
|
|
||||||
|
dnl Force gcc and gcc-compatible compilers treat signed integers
|
||||||
|
dnl as 2's complement
|
||||||
|
PA_ADD_CFLAGS([-fwrapv])
|
||||||
|
|
||||||
|
dnl Force clang to behave in a predictable manner, in order to make bugs
|
||||||
|
dnl possible to track down. gcc appears to have this behavior by default.
|
||||||
|
PA_ADD_CFLAGS([-ftrivial-auto-var-init=zero])
|
||||||
|
|
||||||
|
dnl Some environments abuse __STRICT_ANSI__ to disable some
|
||||||
|
dnl function declarations
|
||||||
|
PA_ADD_CFLAGS([-U__STRICT_ANSI__])
|
||||||
|
|
||||||
|
dnl Don't put things in common if we can avoid it. We don't want to
|
||||||
|
dnl assume all compilers support common, and this will help find those
|
||||||
|
dnl problems. This also works around an OSX linker problem.
|
||||||
|
PA_ADD_CFLAGS([-fno-common])
|
||||||
|
|
||||||
|
dnl Tests which may trigger warnings on some compilers
|
||||||
|
AC_C_CONST
|
||||||
|
AC_C_INLINE
|
||||||
|
AC_C_RESTRICT
|
||||||
|
|
||||||
|
dnl Checks for header files.
|
||||||
|
AC_CHECK_INCLUDES_DEFAULT
|
||||||
|
|
||||||
|
dnl See if we need extra libraries
|
||||||
|
XTRA=false
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS([strerror],[cposix])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS_ONCE(inttypes.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(stdint.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(grp.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(libgen.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(setjmp.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(strings.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(sysexits.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(unistd.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(sys/filio.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(sys/stat.h)
|
||||||
|
AC_CHECK_HEADERS_ONCE(sys/time.h)
|
||||||
|
PA_CHECK_INTTYPES_H_SANE
|
||||||
|
|
||||||
|
dnl This is needed on some versions of FreeBSD...
|
||||||
|
AC_CHECK_HEADERS_ONCE(machine/param.h)
|
||||||
|
|
||||||
|
dnl Windows...
|
||||||
|
PA_ADD_HEADERS(windows.h)
|
||||||
|
PA_ADD_HEADERS(winsock2.h)
|
||||||
|
AS_IF([test "x$ac_cv_header_winsock2_h" != xyes],
|
||||||
|
[PA_ADD_HEADERS(winsock.h)])
|
||||||
|
|
||||||
|
PA_ADD_HEADERS(fcntl.h)
|
||||||
|
PA_ADD_HEADERS(sys/types.h)
|
||||||
|
PA_ADD_HEADERS(arpa/inet.h)
|
||||||
|
PA_ADD_HEADERS(sys/socket.h)
|
||||||
|
PA_ADD_HEADERS(sys/file.h)
|
||||||
|
PA_ADD_HEADERS(netinet/in.h)
|
||||||
|
PA_ADD_HEADERS(sys/uio.h)
|
||||||
|
PA_ADD_HEADERS(netdb.h)
|
||||||
|
|
||||||
|
AC_TYPE_OFF_T
|
||||||
|
AC_TYPE_PID_T
|
||||||
|
AC_TYPE_MODE_T
|
||||||
|
AC_TYPE_SIZE_T
|
||||||
|
AC_CHECK_TYPES(intmax_t)
|
||||||
|
AC_CHECK_TYPES(long long)
|
||||||
|
AC_CHECK_TYPES(uint16_t)
|
||||||
|
AC_CHECK_TYPES(uint32_t)
|
||||||
|
AC_CHECK_TYPES(u_short)
|
||||||
|
AC_CHECK_TYPES(u_long)
|
||||||
|
|
||||||
|
AC_CHECK_TYPES(socklen_t)
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], ,
|
||||||
|
[AC_MSG_ERROR(socket library not found)])
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS(fcntl)
|
||||||
|
AC_CHECK_FUNCS(flock)
|
||||||
|
AC_CHECK_FUNCS(setsid)
|
||||||
|
AC_CHECK_FUNCS(recvmsg)
|
||||||
|
AC_CHECK_FUNCS(ftruncate)
|
||||||
|
AC_CHECK_FUNCS(setresuid)
|
||||||
|
AC_CHECK_FUNCS(setreuid)
|
||||||
|
AC_CHECK_FUNCS(setresgid)
|
||||||
|
AC_CHECK_FUNCS(setregid)
|
||||||
|
AC_CHECK_FUNCS(initgroups)
|
||||||
|
AC_CHECK_FUNCS(setgroups)
|
||||||
|
AC_CHECK_TYPES(sighandler_t)
|
||||||
|
|
||||||
|
dnl Solaris 8 has [u]intmax_t but not strtoumax(). How utterly braindamaged.
|
||||||
|
AC_CHECK_FUNCS(strtoumax)
|
||||||
|
AC_CHECK_FUNCS(strtoull)
|
||||||
|
|
||||||
|
AC_CHECK_MEMBERS(struct msghdr.msg_control)
|
||||||
|
AC_CHECK_MEMBERS(struct in_pktinfo.ipi_addr)
|
||||||
|
AC_CHECK_MEMBERS(struct addrinfo.ai_addr)
|
||||||
|
|
||||||
|
AC_CHECK_DECLS([O_NONBLOCK, O_BINARY, O_TEXT])
|
||||||
|
AC_CHECK_DECLS([F_SETLK])
|
||||||
|
AC_CHECK_DECLS([LOCK_SH, LOCK_EX])
|
||||||
|
|
||||||
|
PA_SIGSETJMP
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Get common paths
|
||||||
|
dnl
|
||||||
|
SRCROOT=`cd $srcdir && pwd`
|
||||||
|
OBJROOT=`pwd`
|
||||||
|
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(xmalloc, iberty)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(xstrdup, iberty)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(getopt_long, getopt, getopt_long)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(getaddrinfo, [nsl resolv])
|
||||||
|
AS_IF([$pa_add_getaddrinfo],
|
||||||
|
[AC_SEARCH_LIBS(gethostbyname, [nsl resolv],
|
||||||
|
[AC_SEARCH_LIBS(herror, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(herror not found)])],
|
||||||
|
[AC_MSG_ERROR(gethostbyname not found)])],
|
||||||
|
[AC_SEARCH_LIBS(freeaddrinfo, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(getaddrinfo but not freeaddrinfo found)])
|
||||||
|
AC_SEARCH_LIBS(gai_strerror, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(getaddrinfo but not gai_strerror found)])])
|
||||||
|
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(inet_ntop, [nsl resolv])
|
||||||
|
AS_IF([$pa_add_inet_ntop],
|
||||||
|
[AC_SEARCH_LIBS(inet_ntoa, [nsl resolv], ,
|
||||||
|
[AC_MSG_ERROR(inet_ntoa not found)])])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(inet_aton, [nsl resolv], ,[AC_MSG_ERROR(inet_aton not found)])
|
||||||
|
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(daemon)
|
||||||
|
PA_SEARCH_LIBS_AND_ADD(dup2)
|
||||||
|
|
||||||
|
AS_IF([$XTRA], [XTRALIBS="$OBJROOT/lib/libxtra.a $XTRALIBS"])
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl These libraries apply to the server only
|
||||||
|
dnl
|
||||||
|
|
||||||
|
common_libs="$LIBS"
|
||||||
|
|
||||||
|
AC_CHECK_DECLS(IPPORT_TFTP)
|
||||||
|
|
||||||
|
PA_ARG_DISABLED([tcpwrappers],
|
||||||
|
[disable tcpwrapper permissions checking], [],
|
||||||
|
[
|
||||||
|
AC_SEARCH_LIBS(yp_get_default_domain, [nsl resolv])
|
||||||
|
PA_HAVE_TCPWRAPPERS
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS_ONCE([regex.h])
|
||||||
|
PA_ARG_DISABLED([remap],
|
||||||
|
[disable regex-based filename remapping], [],
|
||||||
|
[AS_IF([test x"$ac_cv_header_regex_h" = xyes],
|
||||||
|
[AC_SEARCH_LIBS(regcomp, [regex rx],
|
||||||
|
[AC_DEFINE([WITH_REGEX], 1,
|
||||||
|
[Define if we are compiling with regex filename remapping.])
|
||||||
|
TFTPDOBJS="remap.\$(O) $TFTPOBJS"])])])
|
||||||
|
|
||||||
|
TFTPD_LIBS="$LIBS $XTRALIBS"
|
||||||
|
LIBS="$common_libs"
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl These libraries apply to the client only
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AH_TEMPLATE([WITH_READLINE],
|
||||||
|
[Define if we are compiling with readline/editline command-line editing.])
|
||||||
|
|
||||||
|
PA_ARG_DISABLED([readline],
|
||||||
|
[disable the use of readline command-line editing], [],
|
||||||
|
[
|
||||||
|
AC_CHECK_HEADER([readline/readline.h],
|
||||||
|
[
|
||||||
|
dnl readline may need libtermcap or somesuch...
|
||||||
|
AC_SEARCH_LIBS(tputs, [termcap terminfo])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(readline, [readline history],
|
||||||
|
[AC_DEFINE(WITH_READLINE)])
|
||||||
|
AC_CHECK_HEADERS(readline/history.h)
|
||||||
|
],
|
||||||
|
[AC_CHECK_HEADER([editline/readline.h],
|
||||||
|
[
|
||||||
|
dnl editline may need libtermcap or somesuch...
|
||||||
|
AC_SEARCH_LIBS(tputs, [termcap terminfo])
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS(editline, [edit],
|
||||||
|
[AC_DEFINE(WITH_READLINE)])
|
||||||
|
])])
|
||||||
|
],:)
|
||||||
|
|
||||||
|
TFTP_LIBS="$LIBS $XTRALIBS"
|
||||||
|
LIBS="$common_libs"
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Check for IPV6 and disable-ipv6
|
||||||
|
dnl
|
||||||
|
|
||||||
|
AC_CHECK_MEMBERS(struct sockaddr_in6.sin6_addr)
|
||||||
|
AC_MSG_CHECKING([for IPv6 support])
|
||||||
|
PA_ARG_DISABLED([ipv6],
|
||||||
|
[disable support for IPv6],
|
||||||
|
[AC_MSG_RESULT(disabled)],
|
||||||
|
[AS_IF([test x"$ac_cv_member_struct_sockaddr_in6_sin6_addr$ac_cv_member_struct_addrinfo_ai_addr" = xyesyes],
|
||||||
|
[AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_IPV6, 1, [define if IPv6 support is enabled])],
|
||||||
|
[AC_MSG_RESULT(no)
|
||||||
|
AC_MSG_WARN([*** we do not have required IPv6 structs - IPv6 will be disabled])])])
|
||||||
|
|
||||||
|
AC_SUBST(SRCROOT)
|
||||||
|
AC_SUBST(OBJROOT)
|
||||||
|
|
||||||
|
AC_SUBST(TFTP_LIBS)
|
||||||
|
AC_SUBST(TFTPD_LIBS)
|
||||||
|
AC_SUBST(TFTPDOBJS)
|
||||||
|
|
||||||
|
AC_PROG_LN_S
|
||||||
|
AC_PROG_RANLIB
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Make sure the install program has an absolute path if it
|
||||||
|
dnl has a path at all. autoconf doesn't do this "in order
|
||||||
|
dnl to not pollute the cache." Sigh.
|
||||||
|
dnl Note: the $ needs to be double-quoted for reasons unknown.
|
||||||
|
dnl
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
[if echo "$INSTALL" | grep '^[^/].*/' > /dev/null 2>&1; then
|
||||||
|
INSTALL='\${SRCROOT}'/"$INSTALL"
|
||||||
|
fi]
|
||||||
|
|
||||||
|
PA_ADD_CFLAGS(-W)
|
||||||
|
PA_ADD_CFLAGS(-Wall)
|
||||||
|
PA_ADD_CFLAGS(-Wpointer-arith)
|
||||||
|
PA_ADD_CFLAGS(-Wbad-function-cast)
|
||||||
|
PA_ADD_CFLAGS(-Wcast-equal)
|
||||||
|
PA_ADD_CFLAGS(-Wstrict-prototypes)
|
||||||
|
PA_ADD_CFLAGS(-Wmissing-prototypes)
|
||||||
|
PA_ADD_CFLAGS(-Wmissing-declarations)
|
||||||
|
PA_ADD_CFLAGS(-Wnested-externs)
|
||||||
|
PA_ADD_CFLAGS(-Winline)
|
||||||
|
PA_ADD_CFLAGS(-Wwrite-strings)
|
||||||
|
PA_ADD_CFLAGS(-Wundef)
|
||||||
|
PA_ADD_CFLAGS(-Wshadow)
|
||||||
|
PA_ADD_CFLAGS(-Wsign-compare)
|
||||||
|
PA_ADD_CFLAGS(-fno-strict-aliasing)
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl Test compiler features. On some compilers, this can be affected
|
||||||
|
dnl by -Werror options, so run this *after* those options are added.
|
||||||
|
dnl
|
||||||
|
PA_CHECK_BAD_STDC_INLINE
|
||||||
|
PA_C_TYPEOF
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS([config/config.h])
|
||||||
|
AC_CONFIG_FILES([config/MCONFIG])
|
||||||
|
AC_OUTPUT
|
||||||
222
configure.in
222
configure.in
|
|
@ -1,222 +0,0 @@
|
||||||
dnl
|
|
||||||
dnl autoconf input file to generate MCONFIG
|
|
||||||
dnl
|
|
||||||
|
|
||||||
AC_PREREQ(2.52)
|
|
||||||
AC_REVISION([$Id$])
|
|
||||||
AC_INIT(MCONFIG.in)
|
|
||||||
AC_PREFIX_DEFAULT(/usr)
|
|
||||||
|
|
||||||
AC_ISC_POSIX
|
|
||||||
AC_AIX
|
|
||||||
AC_MINIX
|
|
||||||
AC_PROG_CC
|
|
||||||
|
|
||||||
dnl
|
|
||||||
dnl Feature-test macros. These need to be set in CFLAGS, rather in
|
|
||||||
dnl aconfig.h, or "configure" will run in a different environment than
|
|
||||||
dnl we eventually we build in.
|
|
||||||
dnl
|
|
||||||
|
|
||||||
dnl Needed on Solaris/cc or Solaris/gcc
|
|
||||||
CFLAGS="$CFLAGS -D_XPG4_2"
|
|
||||||
CFLAGS="$CFLAGS -D_XOPEN_SOURCE"
|
|
||||||
CFLAGS="$CFLAGS -D__EXTENSIONS__"
|
|
||||||
|
|
||||||
dnl Needed on some glibc systems
|
|
||||||
CFLAGS="$CFLAGS -D_BSD_SOURCE"
|
|
||||||
CFLAGS="$CFLAGS -D_ISO9X_SOURCE"
|
|
||||||
|
|
||||||
dnl Needed on Digital Unix
|
|
||||||
CFLAGS="$CFLAGS -D_OSF_SOURCE"
|
|
||||||
CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED"
|
|
||||||
|
|
||||||
AC_C_CONST
|
|
||||||
AC_C_INLINE
|
|
||||||
|
|
||||||
AC_SYS_LARGEFILE
|
|
||||||
|
|
||||||
PA_ADD_CFLAGS(-W)
|
|
||||||
PA_ADD_CFLAGS(-Wall)
|
|
||||||
PA_ADD_CFLAGS(-Wpointer-arith)
|
|
||||||
PA_ADD_CFLAGS(-Wbad-function-cast)
|
|
||||||
PA_ADD_CFLAGS(-Wcast-equal)
|
|
||||||
PA_ADD_CFLAGS(-Wstrict-prototypes)
|
|
||||||
PA_ADD_CFLAGS(-Wmissing-prototypes)
|
|
||||||
PA_ADD_CFLAGS(-Wmissing-declarations)
|
|
||||||
PA_ADD_CFLAGS(-Wnested-externs)
|
|
||||||
PA_ADD_CFLAGS(-Winline)
|
|
||||||
PA_ADD_CFLAGS(-Wwrite-strings)
|
|
||||||
PA_ADD_CFLAGS(-Wundef)
|
|
||||||
PA_ADD_CFLAGS(-Wshadow)
|
|
||||||
PA_ADD_CFLAGS(-Wsign-compare)
|
|
||||||
PA_ADD_CFLAGS(-pipe)
|
|
||||||
PA_ADD_CFLAGS(-fno-strict-aliasing)
|
|
||||||
|
|
||||||
AC_HEADER_STDC
|
|
||||||
AC_CHECK_HEADERS(inttypes.h)
|
|
||||||
AC_CHECK_HEADERS(stdint.h)
|
|
||||||
PA_CHECK_INTTYPES_H_SANE
|
|
||||||
AC_CHECK_HEADERS(fcntl.h)
|
|
||||||
AC_CHECK_HEADERS(getopt.h)
|
|
||||||
AC_CHECK_HEADERS(grp.h)
|
|
||||||
AC_CHECK_HEADERS(libgen.h)
|
|
||||||
AC_CHECK_HEADERS(memory.h)
|
|
||||||
AC_CHECK_HEADERS(setjmp.h)
|
|
||||||
AC_CHECK_HEADERS(stddef.h)
|
|
||||||
AC_CHECK_HEADERS(stdlib.h)
|
|
||||||
AC_CHECK_HEADERS(string.h)
|
|
||||||
AC_CHECK_HEADERS(strings.h)
|
|
||||||
AC_CHECK_HEADERS(sysexits.h)
|
|
||||||
AC_CHECK_HEADERS(time.h)
|
|
||||||
AC_CHECK_HEADERS(unistd.h)
|
|
||||||
AC_CHECK_HEADERS(sys/filio.h)
|
|
||||||
AC_CHECK_HEADERS(sys/stat.h)
|
|
||||||
AC_CHECK_HEADERS(sys/time.h)
|
|
||||||
AC_CHECK_HEADERS(sys/types.h)
|
|
||||||
AC_CHECK_HEADERS(arpa/inet.h)
|
|
||||||
AC_HEADER_TIME
|
|
||||||
dnl This is needed on some versions of FreeBSD...
|
|
||||||
AC_CHECK_HEADERS(machine/param.h)
|
|
||||||
AC_CHECK_HEADERS(sys/socket.h)
|
|
||||||
AC_CHECK_HEADERS(winsock2.h)
|
|
||||||
AC_CHECK_HEADERS(winsock.h)
|
|
||||||
|
|
||||||
AC_CHECK_TYPES(intmax_t)
|
|
||||||
AC_CHECK_TYPES(long long)
|
|
||||||
AC_CHECK_TYPES(uint16_t)
|
|
||||||
AC_CHECK_TYPES(uint32_t)
|
|
||||||
AC_CHECK_TYPES(u_short)
|
|
||||||
AC_CHECK_TYPES(u_long)
|
|
||||||
AC_TYPE_OFF_T
|
|
||||||
AC_TYPE_PID_T
|
|
||||||
AC_TYPE_MODE_T
|
|
||||||
AC_TYPE_SIZE_T
|
|
||||||
|
|
||||||
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], , [AC_MSG_ERROR(socket library not found)])
|
|
||||||
AC_SEARCH_LIBS(gethostbyname, [nsl resolv], , [AC_MSG_ERROR(gethostbyname not found)])
|
|
||||||
AC_SEARCH_LIBS(inet_aton, [nsl resolv], , [AC_MSG_ERROR(inet_aton not found)])
|
|
||||||
AC_SEARCH_LIBS(herror, [nsl resolv], , [AC_MSG_ERROR(herror not found)])
|
|
||||||
|
|
||||||
AC_CHECK_FUNCS(dup2)
|
|
||||||
AC_CHECK_FUNCS(fcntl)
|
|
||||||
AC_CHECK_FUNCS(setsid)
|
|
||||||
AC_CHECK_FUNCS(recvmsg)
|
|
||||||
AC_CHECK_FUNCS(ftruncate)
|
|
||||||
AC_CHECK_FUNCS(setreuid)
|
|
||||||
AC_CHECK_FUNCS(setregid)
|
|
||||||
AC_CHECK_FUNCS(initgroups)
|
|
||||||
AC_CHECK_FUNCS(setgroups)
|
|
||||||
|
|
||||||
dnl Solaris 8 has [u]intmax_t but not strtoumax(). How utterly braindamaged.
|
|
||||||
AC_CHECK_FUNCS(strtoumax)
|
|
||||||
AC_CHECK_FUNCS(strtoull)
|
|
||||||
|
|
||||||
PA_MSGHDR_MSG_CONTROL
|
|
||||||
PA_STRUCT_IN_PKTINFO
|
|
||||||
|
|
||||||
PA_HEADER_DEFINES(fcntl.h, int, O_NONBLOCK)
|
|
||||||
PA_HEADER_DEFINES(fcntl.h, int, O_BINARY)
|
|
||||||
PA_HEADER_DEFINES(fcntl.h, int, O_TEXT)
|
|
||||||
|
|
||||||
AH_TEMPLATE([HAVE_SIGSETJMP],
|
|
||||||
[Define if we have sigsetjmp, siglongjmp and sigjmp_buf.])
|
|
||||||
PA_SIGSETJMP([AC_DEFINE(HAVE_SIGSETJMP)])
|
|
||||||
|
|
||||||
dnl
|
|
||||||
dnl Get common paths
|
|
||||||
dnl
|
|
||||||
SRCROOT=`cd $srcdir && pwd`
|
|
||||||
OBJROOT=`pwd`
|
|
||||||
|
|
||||||
AC_SEARCH_LIBS(xmalloc, iberty, , [AC_LIBOBJ(xmalloc)])
|
|
||||||
AC_SEARCH_LIBS(xstrdup, iberty, , [AC_LIBOBJ(xstrdup)])
|
|
||||||
AC_SEARCH_LIBS(bsd_signal, bsd, , [AC_LIBOBJ(bsdsignal)])
|
|
||||||
XTRALIBS="$OBJROOT/lib/libxtra.a $XTRALIBS"
|
|
||||||
|
|
||||||
dnl
|
|
||||||
dnl These libraries apply to the server only
|
|
||||||
dnl
|
|
||||||
|
|
||||||
common_libs="$LIBS"
|
|
||||||
|
|
||||||
PA_HEADER_DEFINES(netinet/in.h, int, IPPORT_TFTP)
|
|
||||||
|
|
||||||
PA_WITH_BOOL(tcpwrappers, 1,
|
|
||||||
[ --without-tcpwrappers disable tcpwrapper permissions checking],
|
|
||||||
[
|
|
||||||
AC_SEARCH_LIBS(yp_get_default_domain, [nsl resolv])
|
|
||||||
PA_HAVE_TCPWRAPPERS
|
|
||||||
],:)
|
|
||||||
|
|
||||||
|
|
||||||
AH_TEMPLATE([WITH_REGEX],
|
|
||||||
[Define if we are compiling with regex filename remapping.])
|
|
||||||
|
|
||||||
PA_WITH_BOOL(remap, 1,
|
|
||||||
[ --without-remap disable regex-based filename remapping],
|
|
||||||
[
|
|
||||||
AC_CHECK_HEADER(regex.h,
|
|
||||||
[
|
|
||||||
AC_SEARCH_LIBS(regcomp, [regex rx],
|
|
||||||
[
|
|
||||||
AC_DEFINE(WITH_REGEX)
|
|
||||||
TFTPDOBJS="remap.${OBJEXT} $TFTPDOBJS"
|
|
||||||
])
|
|
||||||
])
|
|
||||||
],:)
|
|
||||||
|
|
||||||
TFTPD_LIBS="$LIBS $XTRALIBS"
|
|
||||||
LIBS="$common_libs"
|
|
||||||
|
|
||||||
dnl
|
|
||||||
dnl These libraries apply to the client only
|
|
||||||
dnl
|
|
||||||
|
|
||||||
AH_TEMPLATE([WITH_READLINE],
|
|
||||||
[Define if we are compiling with readline command-line editing.])
|
|
||||||
|
|
||||||
PA_WITH_BOOL(readline, 1,
|
|
||||||
[ --without-readline disable the use of readline command-line editing],
|
|
||||||
[
|
|
||||||
AC_CHECK_HEADER(readline/readline.h,
|
|
||||||
[
|
|
||||||
dnl readline may need libtermcap or somesuch...
|
|
||||||
AC_SEARCH_LIBS(tputs, [termcap terminfo])
|
|
||||||
|
|
||||||
AC_SEARCH_LIBS(readline, [readline history],
|
|
||||||
[
|
|
||||||
AC_DEFINE(WITH_READLINE)
|
|
||||||
],
|
|
||||||
[],
|
|
||||||
[-ltermcap])
|
|
||||||
AC_CHECK_HEADERS(readline/history.h)
|
|
||||||
])
|
|
||||||
],:)
|
|
||||||
|
|
||||||
TFTP_LIBS="$LIBS $XTRALIBS"
|
|
||||||
LIBS="$common_libs"
|
|
||||||
|
|
||||||
AC_SUBST(SRCROOT)
|
|
||||||
AC_SUBST(OBJROOT)
|
|
||||||
|
|
||||||
AC_SUBST(TFTP_LIBS)
|
|
||||||
AC_SUBST(TFTPD_LIBS)
|
|
||||||
AC_SUBST(TFTPDOBJS)
|
|
||||||
|
|
||||||
AC_PROG_LN_S
|
|
||||||
AC_PROG_RANLIB
|
|
||||||
|
|
||||||
dnl
|
|
||||||
dnl Make sure the install program has an absolute path if it
|
|
||||||
dnl has a path at all. autoconf doesn't do this "in order
|
|
||||||
dnl to not pollute the cache." Sigh.
|
|
||||||
dnl Note: the $ needs to be double-quoted for reasons unknown.
|
|
||||||
dnl
|
|
||||||
AC_PROG_INSTALL
|
|
||||||
[if echo "$INSTALL" | grep '^[^/].*/' > /dev/null 2>&1; then
|
|
||||||
INSTALL='\${SRCROOT}'/"$INSTALL"
|
|
||||||
fi]
|
|
||||||
|
|
||||||
AC_CONFIG_HEADERS(aconfig.h)
|
|
||||||
AC_OUTPUT(MCONFIG)
|
|
||||||
|
|
@ -4,10 +4,14 @@
|
||||||
|
|
||||||
SRCROOT = ..
|
SRCROOT = ..
|
||||||
|
|
||||||
-include ../MCONFIG
|
-include ../config/MCONFIG
|
||||||
include ../MRULES
|
include ../MRULES
|
||||||
|
|
||||||
|
ifeq ($(LIBOBJS),)
|
||||||
|
all:
|
||||||
|
else
|
||||||
all: libxtra.a
|
all: libxtra.a
|
||||||
|
endif
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
|
||||||
|
|
@ -21,5 +25,3 @@ libxtra.a: $(LIBOBJS)
|
||||||
-rm -f libxtra.a
|
-rm -f libxtra.a
|
||||||
$(AR) libxtra.a $(LIBOBJS)
|
$(AR) libxtra.a $(LIBOBJS)
|
||||||
$(RANLIB) libxtra.a
|
$(RANLIB) libxtra.a
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* bsdsignal.c
|
|
||||||
*
|
|
||||||
* Use sigaction() to simulate BSD signal()
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
void (*bsd_signal(int, void (*)(int)))(int);
|
|
||||||
|
|
||||||
void (*bsd_signal(int signum, void (*handler)(int)))(int)
|
|
||||||
{
|
|
||||||
struct sigaction action, oldaction;
|
|
||||||
|
|
||||||
memset(&action, 0, sizeof action);
|
|
||||||
action.sa_handler = handler;
|
|
||||||
sigemptyset(&action.sa_mask);
|
|
||||||
sigaddset(&action.sa_mask, signum);
|
|
||||||
action.sa_flags = SA_RESTART;
|
|
||||||
|
|
||||||
if (sigaction(signum, &action, &oldaction) == -1) {
|
|
||||||
#ifdef SIG_ERR
|
|
||||||
return SIG_ERR;
|
|
||||||
#else
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldaction.sa_handler;
|
|
||||||
}
|
|
||||||
36
lib/daemon.c
Normal file
36
lib/daemon.c
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* daemon.c - "daemonize" a process
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int daemon(int nochdir, int noclose)
|
||||||
|
{
|
||||||
|
int nullfd;
|
||||||
|
pid_t f;
|
||||||
|
|
||||||
|
if (!nochdir) {
|
||||||
|
if (chdir("/"))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noclose) {
|
||||||
|
if ((nullfd = open("/dev/null", O_RDWR)) < 0 ||
|
||||||
|
dup2(nullfd, 0) < 0 ||
|
||||||
|
dup2(nullfd, 1) < 0 || dup2(nullfd, 2) < 0)
|
||||||
|
return -1;
|
||||||
|
close(nullfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fork();
|
||||||
|
if (f < 0)
|
||||||
|
return -1;
|
||||||
|
else if (f > 0)
|
||||||
|
_exit(0);
|
||||||
|
|
||||||
|
#ifdef HAVE_SETSID
|
||||||
|
return setsid();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
23
lib/dup2.c
Normal file
23
lib/dup2.c
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* dup2.c
|
||||||
|
*
|
||||||
|
* Ersatz dup2() for really ancient systems
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int dup2(int oldfd, int newfd)
|
||||||
|
{
|
||||||
|
int rv, nfd;
|
||||||
|
|
||||||
|
close(newfd);
|
||||||
|
|
||||||
|
nfd = rv = dup(oldfd);
|
||||||
|
|
||||||
|
if (rv >= 0 && rv != newfd) {
|
||||||
|
rv = dup2(oldfd, newfd);
|
||||||
|
close(nfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
121
lib/getaddrinfo.c
Normal file
121
lib/getaddrinfo.c
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* getaddrinfo.c
|
||||||
|
*
|
||||||
|
* Simple version of getaddrinfo()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
extern int errno;
|
||||||
|
extern int h_errno;
|
||||||
|
|
||||||
|
void freeaddrinfo(struct addrinfo *res)
|
||||||
|
{
|
||||||
|
if (!res)
|
||||||
|
return;
|
||||||
|
if (res->ai_next)
|
||||||
|
freeaddrinfo(res->ai_next);
|
||||||
|
if (res->ai_addr)
|
||||||
|
free(res->ai_addr);
|
||||||
|
if (res->ai_canonname)
|
||||||
|
free(res->ai_canonname);
|
||||||
|
free(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res)
|
||||||
|
{
|
||||||
|
struct hostent *host;
|
||||||
|
struct sockaddr *sa;
|
||||||
|
int err, size = 0;
|
||||||
|
|
||||||
|
if ((!node) || (!res)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return EAI_SYSTEM;
|
||||||
|
}
|
||||||
|
*res = NULL;
|
||||||
|
/* we do not support service in this version */
|
||||||
|
if (service) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return EAI_SYSTEM;
|
||||||
|
}
|
||||||
|
host = gethostbyname(node);
|
||||||
|
if (!host)
|
||||||
|
return EAI_NONAME;
|
||||||
|
if (hints) {
|
||||||
|
if (hints->ai_family != AF_UNSPEC) {
|
||||||
|
if (hints->ai_family != host->h_addrtype)
|
||||||
|
return EAI_ADDRFAMILY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*res = malloc(sizeof(struct addrinfo));
|
||||||
|
if (!*res) {
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
memset(*res, 0, sizeof(struct addrinfo));
|
||||||
|
(*res)->ai_family = host->h_addrtype;
|
||||||
|
if (host->h_length) {
|
||||||
|
if (host->h_addrtype == AF_INET)
|
||||||
|
size = sizeof(struct sockaddr_in);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (host->h_addrtype == AF_INET6)
|
||||||
|
size = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
free(*res);
|
||||||
|
*res = NULL;
|
||||||
|
return EAI_ADDRFAMILY;
|
||||||
|
}
|
||||||
|
sa = malloc(size);
|
||||||
|
if (!sa) {
|
||||||
|
free(*res);
|
||||||
|
*res = NULL;
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
memset(sa, 0, size);
|
||||||
|
(*res)->ai_addr = sa;
|
||||||
|
(*res)->ai_addrlen = size;
|
||||||
|
sa->sa_family = host->h_addrtype;
|
||||||
|
if (host->h_addrtype == AF_INET)
|
||||||
|
memcpy(&((struct sockaddr_in *)sa)->sin_addr, host->h_addr, host->h_length);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, host->h_addr, host->h_length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (host->h_name)
|
||||||
|
(*res)->ai_canonname = strdup(host->h_name);
|
||||||
|
|
||||||
|
/* we only handle the first address entry and do not build a list now */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *gai_strerror(int errcode)
|
||||||
|
{
|
||||||
|
const char *s = NULL;
|
||||||
|
|
||||||
|
switch(errcode) {
|
||||||
|
case 0:
|
||||||
|
s = "no error";
|
||||||
|
break;
|
||||||
|
case EAI_MEMORY:
|
||||||
|
s = "no memory";
|
||||||
|
break;
|
||||||
|
case EAI_SYSTEM:
|
||||||
|
s = strerror(errno);
|
||||||
|
break;
|
||||||
|
case EAI_NONAME:
|
||||||
|
s = hstrerror(h_errno);
|
||||||
|
break;
|
||||||
|
case EAI_ADDRFAMILY:
|
||||||
|
s = "address does not match address family";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "unknown error code";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
23
lib/getopt.h
Normal file
23
lib/getopt.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef LIB_GETOPT_H
|
||||||
|
#define LIB_GETOPT_H
|
||||||
|
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind, opterr, optopt;
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
const char *name;
|
||||||
|
int has_arg;
|
||||||
|
int *flag;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
no_argument = 0,
|
||||||
|
required_argument = 1,
|
||||||
|
optional_argument = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
int getopt_long(int, char *const *, const char *,
|
||||||
|
const struct option *, int *);
|
||||||
|
|
||||||
|
#endif /* LIB_GETOPT_H */
|
||||||
150
lib/getopt_long.c
Normal file
150
lib/getopt_long.c
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* getopt_long.c
|
||||||
|
*
|
||||||
|
* getopt_long(), or at least a common subset thereof:
|
||||||
|
*
|
||||||
|
* - Option reordering is not supported
|
||||||
|
* - -W foo is not supported
|
||||||
|
* - First optstring character "-" not supported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
char *optarg;
|
||||||
|
int optind, opterr, optopt;
|
||||||
|
|
||||||
|
static struct getopt_private_state {
|
||||||
|
const char *optptr;
|
||||||
|
const char *last_optstring;
|
||||||
|
char *const *last_argv;
|
||||||
|
} pvt;
|
||||||
|
|
||||||
|
static inline const char *option_matches(const char *arg_str,
|
||||||
|
const char *opt_name)
|
||||||
|
{
|
||||||
|
while (*arg_str != '\0' && *arg_str != '=') {
|
||||||
|
if (*arg_str++ != *opt_name++)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*opt_name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return arg_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getopt_long(int argc, char *const *argv, const char *optstring,
|
||||||
|
const struct option *longopts, int *longindex)
|
||||||
|
{
|
||||||
|
const char *carg;
|
||||||
|
const char *osptr;
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
/* getopt() relies on a number of different global state
|
||||||
|
variables, which can make this really confusing if there is
|
||||||
|
more than one use of getopt() in the same program. This
|
||||||
|
attempts to detect that situation by detecting if the
|
||||||
|
"optstring" or "argv" argument have changed since last time
|
||||||
|
we were called; if so, reinitialize the query state. */
|
||||||
|
|
||||||
|
if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
|
||||||
|
optind < 1 || optind > argc) {
|
||||||
|
/* optind doesn't match the current query */
|
||||||
|
pvt.last_optstring = optstring;
|
||||||
|
pvt.last_argv = argv;
|
||||||
|
optind = 1;
|
||||||
|
pvt.optptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
carg = argv[optind];
|
||||||
|
|
||||||
|
/* First, eliminate all non-option cases */
|
||||||
|
|
||||||
|
if (!carg || carg[0] != '-' || !carg[1])
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (carg[1] == '-') {
|
||||||
|
const struct option *lo;
|
||||||
|
const char *opt_end = NULL;
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
/* Either it's a long option, or it's -- */
|
||||||
|
if (!carg[2]) {
|
||||||
|
/* It's -- */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (lo = longopts; lo->name; lo++) {
|
||||||
|
if ((opt_end = option_matches(carg+2, lo->name)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!opt_end)
|
||||||
|
return '?';
|
||||||
|
|
||||||
|
if (longindex)
|
||||||
|
*longindex = lo-longopts;
|
||||||
|
|
||||||
|
if (*opt_end == '=') {
|
||||||
|
if (lo->has_arg)
|
||||||
|
optarg = (char *)opt_end+1;
|
||||||
|
else
|
||||||
|
return '?';
|
||||||
|
} else if (lo->has_arg == 1) {
|
||||||
|
if (!(optarg = argv[optind]))
|
||||||
|
return '?';
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lo->flag) {
|
||||||
|
*lo->flag = lo->val;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return lo->val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
|
||||||
|
/* Someone frobbed optind, change to new opt. */
|
||||||
|
pvt.optptr = carg + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = *pvt.optptr++;
|
||||||
|
|
||||||
|
if (opt != ':' && (osptr = strchr(optstring, opt))) {
|
||||||
|
if (osptr[1] == ':') {
|
||||||
|
if (*pvt.optptr) {
|
||||||
|
/* Argument-taking option with attached
|
||||||
|
argument */
|
||||||
|
optarg = (char *)pvt.optptr;
|
||||||
|
optind++;
|
||||||
|
} else {
|
||||||
|
/* Argument-taking option with non-attached
|
||||||
|
argument */
|
||||||
|
if (argv[optind + 1]) {
|
||||||
|
optarg = (char *)argv[optind+1];
|
||||||
|
optind += 2;
|
||||||
|
} else {
|
||||||
|
/* Missing argument */
|
||||||
|
optind++;
|
||||||
|
return (optstring[0] == ':')
|
||||||
|
? ':' : '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opt;
|
||||||
|
} else {
|
||||||
|
/* Non-argument-taking option */
|
||||||
|
/* pvt.optptr will remember the exact position to
|
||||||
|
resume at */
|
||||||
|
if (!*pvt.optptr)
|
||||||
|
optind++;
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Unknown option */
|
||||||
|
optopt = opt;
|
||||||
|
if (!*pvt.optptr)
|
||||||
|
optind++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
52
lib/inet_ntop.c
Normal file
52
lib/inet_ntop.c
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* inet_ntop.c
|
||||||
|
*
|
||||||
|
* Simple version of inet_ntop()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
extern int errno;
|
||||||
|
|
||||||
|
const char *inet_ntop(int af, const void *src,
|
||||||
|
char *dst, socklen_t cnt)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
switch(af) {
|
||||||
|
case AF_INET:
|
||||||
|
p = inet_ntoa(*((struct in_addr *)src));
|
||||||
|
if (p) {
|
||||||
|
if (cnt <= strlen(p)) {
|
||||||
|
errno = ENOSPC;
|
||||||
|
dst = NULL;
|
||||||
|
} else
|
||||||
|
strcpy(dst, p);
|
||||||
|
} else
|
||||||
|
dst = NULL;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
case AF_INET6:
|
||||||
|
if (cnt < 40) {
|
||||||
|
errno = ENOSPC;
|
||||||
|
dst = NULL;
|
||||||
|
} else {
|
||||||
|
struct in6_addr *a = src;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
p = (char *)dst;
|
||||||
|
/* we do not compress :0: to :: */
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
p += sprintf(p, "%x:", ntohs(a->s6_addr16[i]));
|
||||||
|
p--;
|
||||||
|
*p = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
errno = EAFNOSUPPORT;
|
||||||
|
dst = NULL;
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
@ -5,17 +5,16 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include "config.h"
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void *xmalloc(size_t size)
|
void *xmalloc(size_t size)
|
||||||
{
|
{
|
||||||
void *p = malloc(size);
|
void *p = malloc(size);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
exit(128);
|
exit(128);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,16 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include "config.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
char *xstrdup(const char *s)
|
char *xstrdup(const char *s)
|
||||||
{
|
{
|
||||||
char *p = strdup(s);
|
char *p = strdup(s);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
fprintf(stderr, "Out of memory!\n");
|
fprintf(stderr, "Out of memory!\n");
|
||||||
exit(128);
|
exit(128);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
38
release.sh
38
release.sh
|
|
@ -1,11 +1,8 @@
|
||||||
#!/bin/sh -x
|
#!/bin/sh -xe
|
||||||
# $Id$
|
|
||||||
#
|
#
|
||||||
# Script for generating a release
|
# Script for generating a release
|
||||||
#
|
#
|
||||||
|
|
||||||
CVS='cvs-real -d hpa@terminus.zytor.com:/home/hpa/cvsroot'
|
|
||||||
MODULE=tftp
|
|
||||||
PACKAGE=tftp-hpa
|
PACKAGE=tftp-hpa
|
||||||
|
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
|
|
@ -14,22 +11,41 @@ if [ -z "$1" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
release="$1"
|
release="$1"
|
||||||
cvsrelease=$PACKAGE-`echo "$release" | tr '.' '_'`
|
releasetag=$PACKAGE-$release
|
||||||
releasedir=$PACKAGE-$release
|
releasedir=$PACKAGE-$release
|
||||||
|
|
||||||
echo $release > version
|
GIT_DIR=`cd "${GIT_DIR-.git}" && pwd`
|
||||||
$CVS commit -m 'Update version for release' version
|
export GIT_DIR
|
||||||
|
|
||||||
$CVS tag -F $cvsrelease
|
if [ `git diff --cached | wc -l` -ne 0 ]; then
|
||||||
|
echo "$0: index not clean" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$release" = x'test' ]; then
|
||||||
|
release=`cat version`
|
||||||
|
releasetag=HEAD
|
||||||
|
releasedir=$PACKAGE-$release
|
||||||
|
else
|
||||||
|
echo $release > version
|
||||||
|
if [ `git diff version | wc -l` -ne 0 ]; then
|
||||||
|
git add version
|
||||||
|
git commit -m "Update version for release $release" version
|
||||||
|
else
|
||||||
|
git checkout version
|
||||||
|
fi
|
||||||
|
rm -f "$GIT_DIR"/refs/tags/$releasetag
|
||||||
|
git tag -a -m "$releasetag" -f "$releasetag"
|
||||||
|
fi
|
||||||
|
|
||||||
here=`pwd`
|
here=`pwd`
|
||||||
|
|
||||||
tmpdir=/var/tmp/release.$$
|
tmpdir=/var/tmp/release.$$
|
||||||
rm -rf $tmpdir
|
rm -rf $tmpdir
|
||||||
mkdir $tmpdir
|
mkdir -p $tmpdir
|
||||||
cd $tmpdir
|
cd $tmpdir
|
||||||
$CVS export -r $cvsrelease $MODULE
|
mkdir -p $releasedir
|
||||||
mv $MODULE $releasedir
|
git archive --format=tar $releasetag | tar -xf - -C $releasedir
|
||||||
cd $releasedir
|
cd $releasedir
|
||||||
make release
|
make release
|
||||||
rm -f release.sh
|
rm -f release.sh
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ Summary: The client for the Trivial File Transfer Protocol (TFTP).
|
||||||
Name: tftp
|
Name: tftp
|
||||||
Version: @@VERSION@@
|
Version: @@VERSION@@
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: BSD
|
License: BSD
|
||||||
Group: Applications/Internet
|
Group: Applications/Internet
|
||||||
Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{version}.tar.gz
|
Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa-%{version}.tar.gz
|
||||||
BuildPreReq: tcp_wrappers
|
BuildRequires: tcp_wrappers-devel
|
||||||
BuildRoot: %{_tmppath}/%{name}-root
|
BuildRoot: %{_tmppath}/%{name}-root
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
SRCROOT = ..
|
SRCROOT = ..
|
||||||
VERSION = $(shell cat ../version)
|
VERSION = $(shell cat ../version)
|
||||||
|
|
||||||
-include ../MCONFIG
|
-include ../config/MCONFIG
|
||||||
include ../MRULES
|
include ../MRULES
|
||||||
|
|
||||||
OBJS = tftp.$(O) main.$(O) tftpsubs.$(O)
|
OBJS = tftp.$(O) main.$(O)
|
||||||
|
|
||||||
all: tftp$(X) tftp.1
|
all: tftp$(X) tftp.1
|
||||||
|
|
||||||
tftp$(X): $(OBJS)
|
tftp$(X): $(OBJS)
|
||||||
$(CC) $(LDFLAGS) $^ $(TFTP_LIBS) -o $@
|
$(CC) $(LDFLAGS) $^ $(TFTP_LIBS) -o $@
|
||||||
|
|
||||||
$(OBJS): tftpsubs.h
|
$(OBJS): ../common/tftpsubs.h
|
||||||
|
|
||||||
tftp.1: tftp.1.in ../version
|
tftp.1: tftp.1.in ../version
|
||||||
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
|
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,3 @@
|
||||||
/* $Id$ */
|
|
||||||
|
|
||||||
/* $OpenBSD: extern.h,v 1.2 1996/06/26 05:40:33 deraadt Exp $ */
|
|
||||||
/* $NetBSD: extern.h,v 1.2 1994/12/08 09:51:24 jtc Exp $ */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1993
|
* Copyright (c) 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
|
@ -34,14 +29,15 @@
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
|
||||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RECVFILE_H
|
#ifndef EXTERN_H
|
||||||
#define RECVFILE_H
|
#define EXTERN_H
|
||||||
|
|
||||||
void tftp_recvfile (int, const char *, const char *);
|
#include "config.h"
|
||||||
void tftp_sendfile (int, const char *, const char *);
|
|
||||||
|
void tftp_recvfile(int, const char *, const char *);
|
||||||
|
void tftp_sendfile(int, const char *, const char *);
|
||||||
|
extern sigjmp_buf toplevel;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
1395
tftp/main.c
1395
tftp/main.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,4 @@
|
||||||
.\" -*- nroff -*- --------------------------------------------------------- *
|
.\" -*- nroff -*- --------------------------------------------------------- *
|
||||||
.\" $Id$
|
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1990, 1993, 1994
|
.\" Copyright (c) 1990, 1993, 1994
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
|
|
@ -31,7 +30,7 @@
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\"----------------------------------------------------------------------- */
|
.\"----------------------------------------------------------------------- */
|
||||||
.TH TFTP 1 "2 February 2003" "tftp-hpa @@VERSION@@" "User's Manual"
|
.TH TFTP 1 "23 July 2008" "tftp-hpa @@VERSION@@" "User's Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.B tftp
|
.B tftp
|
||||||
\- IPv4 Trivial File Transfer Protocol client
|
\- IPv4 Trivial File Transfer Protocol client
|
||||||
|
|
@ -43,7 +42,7 @@
|
||||||
.br
|
.br
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.B tftp
|
.B tftp
|
||||||
is a client for the IPv4 Trivial file Transfer Protocol, which can be
|
is a client for the Trivial file Transfer Protocol, which can be
|
||||||
used to transfer files to and from remote machines, including some
|
used to transfer files to and from remote machines, including some
|
||||||
very minimalistic, usually embedded, systems. The remote
|
very minimalistic, usually embedded, systems. The remote
|
||||||
.I host
|
.I host
|
||||||
|
|
@ -56,13 +55,27 @@ as the default host for future transfers (see the
|
||||||
command below.)
|
command below.)
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
.B \-4
|
||||||
|
Connect with IPv4 only, even if IPv6 support was compiled in.
|
||||||
|
.TP
|
||||||
|
.B \-6
|
||||||
|
Connect with IPv6 only, if compiled in.
|
||||||
|
.TP
|
||||||
\fB\-c\fP \fIcommand\fP
|
\fB\-c\fP \fIcommand\fP
|
||||||
Execute \fIcommand\fP as if it had been entered on the tftp prompt.
|
Execute \fIcommand\fP as if it had been entered on the tftp prompt.
|
||||||
Must be specified last on the command line.
|
Must be specified last on the command line.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-l
|
||||||
|
Default to literal mode. Used to avoid special processing of ':' in a
|
||||||
|
file name.
|
||||||
|
.TP
|
||||||
\fB\-m\fP \fImode\fP
|
\fB\-m\fP \fImode\fP
|
||||||
Set the default transfer mode to \fImode\fP. This is usually used with \-c.
|
Set the default transfer mode to \fImode\fP. This is usually used with \-c.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-R\fP \fIport:port\fP
|
||||||
|
Force the originating port number to be in the specified range of port
|
||||||
|
numbers.
|
||||||
|
.TP
|
||||||
.B \-v
|
.B \-v
|
||||||
Default to verbose mode.
|
Default to verbose mode.
|
||||||
.TP
|
.TP
|
||||||
|
|
@ -119,7 +132,12 @@ host, if the host has already been specified, or a string of the form
|
||||||
.I "host:filename"
|
.I "host:filename"
|
||||||
to specify both a host and filename at the same time. If the latter
|
to specify both a host and filename at the same time. If the latter
|
||||||
form is used, the last hostname specified becomes the default for
|
form is used, the last hostname specified becomes the default for
|
||||||
future transfers.
|
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
|
.TP
|
||||||
\fBmode\fP \fItransfer-mode\fP
|
\fBmode\fP \fItransfer-mode\fP
|
||||||
Specify the mode for transfers;
|
Specify the mode for transfers;
|
||||||
|
|
@ -151,7 +169,9 @@ form is used, the hostname specified becomes the default for future
|
||||||
transfers. If the remote-directory form is used, the remote host is
|
transfers. If the remote-directory form is used, the remote host is
|
||||||
assumed to be a UNIX system or another system using
|
assumed to be a UNIX system or another system using
|
||||||
.B /
|
.B /
|
||||||
as directory separator.
|
as directory separator. Enable
|
||||||
|
.B literal
|
||||||
|
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
|
||||||
.TP
|
.TP
|
||||||
.B quit
|
.B quit
|
||||||
Exit
|
Exit
|
||||||
|
|
|
||||||
640
tftp/tftp.c
640
tftp/tftp.c
|
|
@ -1,8 +1,3 @@
|
||||||
/* $Id$ */
|
|
||||||
|
|
||||||
/* $OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $ */
|
|
||||||
/* $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $ */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1983, 1993
|
* Copyright (c) 1983, 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
|
@ -36,34 +31,24 @@
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tftpsubs.h"
|
#include "common/tftpsubs.h"
|
||||||
|
|
||||||
#ifndef lint
|
|
||||||
/* static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; */
|
|
||||||
/* static char rcsid[] = "$OpenBSD: tftp.c,v 1.4 1997/08/06 06:43:45 deraadt Exp $"; */
|
|
||||||
static const char *rcsid UNUSED =
|
|
||||||
"tftp-hpa $Id$";
|
|
||||||
#endif /* not lint */
|
|
||||||
|
|
||||||
/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TFTP User Program -- Protocol Machines
|
* TFTP User Program -- Protocol Machines
|
||||||
*/
|
*/
|
||||||
#include "extern.h"
|
#include "extern.h"
|
||||||
|
|
||||||
extern struct sockaddr_in peeraddr; /* filled in by main */
|
extern union sock_addr peeraddr; /* filled in by main */
|
||||||
extern int f; /* the opened socket */
|
extern int f; /* the opened socket */
|
||||||
extern int trace;
|
extern int trace;
|
||||||
extern int verbose;
|
extern int verbose;
|
||||||
extern int rexmtval;
|
extern int rexmtval;
|
||||||
extern int maxtimeout;
|
extern int maxtimeout;
|
||||||
|
|
||||||
#define PKTSIZE SEGSIZE+4
|
#define PKTSIZE SEGSIZE+4
|
||||||
char ackbuf[PKTSIZE];
|
char ackbuf[PKTSIZE];
|
||||||
int timeout;
|
int timeout;
|
||||||
sigjmp_buf toplevel;
|
static sigjmp_buf timeoutbuf;
|
||||||
sigjmp_buf timeoutbuf;
|
|
||||||
|
|
||||||
static void nak(int, const char *);
|
static void nak(int, const char *);
|
||||||
static int makerequest(int, const char *, struct tftphdr *, const char *);
|
static int makerequest(int, const char *, struct tftphdr *, const char *);
|
||||||
|
|
@ -76,251 +61,248 @@ static void tpacket(const char *, struct tftphdr *, int);
|
||||||
/*
|
/*
|
||||||
* Send the requested file.
|
* Send the requested file.
|
||||||
*/
|
*/
|
||||||
void
|
void tftp_sendfile(int fd, const char *name, const char *mode)
|
||||||
tftp_sendfile(int fd, const char *name, const char *mode)
|
|
||||||
{
|
{
|
||||||
struct tftphdr *ap; /* data and ack packets */
|
struct tftphdr *ap; /* data and ack packets */
|
||||||
struct tftphdr *dp;
|
struct tftphdr *dp;
|
||||||
int n;
|
int n;
|
||||||
volatile int is_request;
|
volatile int is_request;
|
||||||
volatile u_short block;
|
volatile u_short block;
|
||||||
volatile int size, convert;
|
volatile int size, convert;
|
||||||
volatile off_t amount;
|
volatile off_t amount;
|
||||||
struct sockaddr_in from;
|
union sock_addr from;
|
||||||
int fromlen;
|
socklen_t fromlen;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
u_short ap_opcode, ap_block;
|
u_short ap_opcode, ap_block;
|
||||||
|
|
||||||
startclock(); /* start stat's clock */
|
startclock(); /* start stat's clock */
|
||||||
dp = r_init(); /* reset fillbuf/read-ahead code */
|
dp = r_init(); /* reset fillbuf/read-ahead code */
|
||||||
ap = (struct tftphdr *)ackbuf;
|
ap = (struct tftphdr *)ackbuf;
|
||||||
convert = !strcmp(mode, "netascii");
|
convert = !strcmp(mode, "netascii");
|
||||||
file = fdopen(fd, convert ? "rt" : "rb");
|
file = fdopen(fd, convert ? "rt" : "rb");
|
||||||
block = 0;
|
block = 0;
|
||||||
is_request = 1; /* First packet is the actual WRQ */
|
is_request = 1; /* First packet is the actual WRQ */
|
||||||
amount = 0;
|
amount = 0;
|
||||||
|
|
||||||
bsd_signal(SIGALRM, timer);
|
tftp_signal(SIGALRM, timer, 0);
|
||||||
do {
|
do {
|
||||||
if (is_request) {
|
if (is_request) {
|
||||||
size = makerequest(WRQ, name, dp, mode) - 4;
|
size = makerequest(WRQ, name, dp, mode) - 4;
|
||||||
} else {
|
} else {
|
||||||
/* size = read(fd, dp->th_data, SEGSIZE); */
|
/* size = read(fd, dp->th_data, SEGSIZE); */
|
||||||
size = readit(file, &dp, convert);
|
size = readit(file, &dp, convert);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
nak(errno + 100, NULL);
|
nak(errno + 100, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dp->th_opcode = htons((u_short)DATA);
|
dp->th_opcode = htons((u_short) DATA);
|
||||||
dp->th_block = htons((u_short)block);
|
dp->th_block = htons((u_short) block);
|
||||||
}
|
}
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf, 1);
|
||||||
|
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("sent", dp, size + 4);
|
tpacket("sent", dp, size + 4);
|
||||||
n = sendto(f, dp, size + 4, 0,
|
n = sendto(f, dp, size + 4, 0,
|
||||||
(struct sockaddr *)&peeraddr, sizeof(peeraddr));
|
&peeraddr.sa, SOCKLEN(&peeraddr));
|
||||||
if (n != size + 4) {
|
if (n != size + 4) {
|
||||||
perror("tftp: sendto");
|
perror("tftp: sendto");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
read_ahead(file, convert);
|
read_ahead(file, convert);
|
||||||
for ( ; ; ) {
|
for (;;) {
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
do {
|
do {
|
||||||
fromlen = sizeof(from);
|
fromlen = sizeof(from);
|
||||||
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
|
n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
|
||||||
(struct sockaddr *)&from, &fromlen);
|
&from.sa, &fromlen);
|
||||||
} while (n <= 0);
|
} while (n <= 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
perror("tftp: recvfrom");
|
perror("tftp: recvfrom");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
peeraddr.sin_port = from.sin_port; /* added */
|
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("received", ap, n);
|
tpacket("received", ap, n);
|
||||||
/* should verify packet came from server */
|
/* should verify packet came from server */
|
||||||
ap_opcode = ntohs((u_short)ap->th_opcode);
|
ap_opcode = ntohs((u_short) ap->th_opcode);
|
||||||
ap_block = ntohs((u_short)ap->th_block);
|
ap_block = ntohs((u_short) ap->th_block);
|
||||||
if (ap_opcode == ERROR) {
|
if (ap_opcode == ERROR) {
|
||||||
printf("Error code %d: %s\n", ap_block,
|
printf("Error code %d: %s\n", ap_block, ap->th_msg);
|
||||||
ap->th_msg);
|
goto abort;
|
||||||
goto abort;
|
}
|
||||||
}
|
if (ap_opcode == ACK) {
|
||||||
if (ap_opcode == ACK) {
|
int j;
|
||||||
int j;
|
|
||||||
|
|
||||||
if (ap_block == block) {
|
if (ap_block == block) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* On an error, try to synchronize
|
/* On an error, try to synchronize
|
||||||
* both sides.
|
* both sides.
|
||||||
*/
|
*/
|
||||||
j = synchnet(f);
|
j = synchnet(f);
|
||||||
if (j && trace) {
|
if (j && trace) {
|
||||||
printf("discarded %d packets\n",
|
printf("discarded %d packets\n", j);
|
||||||
j);
|
}
|
||||||
}
|
/*
|
||||||
/*
|
* RFC1129/RFC1350: We MUST NOT re-send the DATA
|
||||||
* RFC1129/RFC1350: We MUST NOT re-send the DATA
|
* packet in response to an invalid ACK. Doing so
|
||||||
* packet in response to an invalid ACK. Doing so
|
* would cause the Sorcerer's Apprentice bug.
|
||||||
* would cause the Sorcerer's Apprentice bug.
|
*/
|
||||||
*/
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!is_request)
|
||||||
if ( !is_request )
|
amount += size;
|
||||||
amount += size;
|
is_request = 0;
|
||||||
is_request = 0;
|
block++;
|
||||||
block++;
|
} while (size == SEGSIZE || block == 1);
|
||||||
} while (size == SEGSIZE || block == 1);
|
abort:
|
||||||
abort:
|
fclose(file);
|
||||||
fclose(file);
|
stopclock();
|
||||||
stopclock();
|
if (amount > 0)
|
||||||
if (amount > 0)
|
printstats("Sent", amount);
|
||||||
printstats("Sent", amount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Receive a file.
|
* Receive a file.
|
||||||
*/
|
*/
|
||||||
void
|
void tftp_recvfile(int fd, const char *name, const char *mode)
|
||||||
tftp_recvfile(int fd, const char *name, const char *mode)
|
|
||||||
{
|
{
|
||||||
struct tftphdr *ap;
|
struct tftphdr *ap;
|
||||||
struct tftphdr *dp;
|
struct tftphdr *dp;
|
||||||
int n;
|
int n;
|
||||||
volatile u_short block;
|
volatile u_short block;
|
||||||
volatile int size, firsttrip;
|
volatile int size, firsttrip;
|
||||||
volatile unsigned long amount;
|
volatile unsigned long amount;
|
||||||
struct sockaddr_in from;
|
union sock_addr from;
|
||||||
int fromlen;
|
socklen_t fromlen;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
volatile int convert; /* true if converting crlf -> lf */
|
volatile int convert; /* true if converting crlf -> lf */
|
||||||
u_short dp_opcode, dp_block;
|
u_short dp_opcode, dp_block;
|
||||||
|
|
||||||
startclock();
|
startclock();
|
||||||
dp = w_init();
|
dp = w_init();
|
||||||
ap = (struct tftphdr *)ackbuf;
|
ap = (struct tftphdr *)ackbuf;
|
||||||
convert = !strcmp(mode, "netascii");
|
convert = !strcmp(mode, "netascii");
|
||||||
file = fdopen(fd, convert ?"wt":"wb");
|
file = fdopen(fd, convert ? "wt" : "wb");
|
||||||
block = 1;
|
block = 1;
|
||||||
firsttrip = 1;
|
firsttrip = 1;
|
||||||
amount = 0;
|
amount = 0;
|
||||||
|
|
||||||
bsd_signal(SIGALRM, timer);
|
tftp_signal(SIGALRM, timer, 0);
|
||||||
do {
|
do {
|
||||||
if (firsttrip) {
|
if (firsttrip) {
|
||||||
size = makerequest(RRQ, name, ap, mode);
|
size = makerequest(RRQ, name, ap, mode);
|
||||||
firsttrip = 0;
|
firsttrip = 0;
|
||||||
} else {
|
} else {
|
||||||
ap->th_opcode = htons((u_short)ACK);
|
ap->th_opcode = htons((u_short) ACK);
|
||||||
ap->th_block = htons((u_short)block);
|
ap->th_block = htons((u_short) block);
|
||||||
size = 4;
|
size = 4;
|
||||||
block++;
|
block++;
|
||||||
}
|
}
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf, 1);
|
||||||
send_ack:
|
send_ack:
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("sent", ap, size);
|
tpacket("sent", ap, size);
|
||||||
if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peeraddr,
|
if (sendto(f, ackbuf, size, 0, &peeraddr.sa,
|
||||||
sizeof(peeraddr)) != size) {
|
SOCKLEN(&peeraddr)) != size) {
|
||||||
alarm(0);
|
alarm(0);
|
||||||
perror("tftp: sendto");
|
perror("tftp: sendto");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
write_behind(file, convert);
|
write_behind(file, convert);
|
||||||
for ( ; ; ) {
|
for (;;) {
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
do {
|
do {
|
||||||
fromlen = sizeof(from);
|
fromlen = sizeof(from);
|
||||||
n = recvfrom(f, dp, PKTSIZE, 0,
|
n = recvfrom(f, dp, PKTSIZE, 0,
|
||||||
(struct sockaddr *)&from, &fromlen);
|
&from.sa, &fromlen);
|
||||||
} while (n <= 0);
|
} while (n <= 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
perror("tftp: recvfrom");
|
perror("tftp: recvfrom");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
peeraddr.sin_port = from.sin_port; /* added */
|
sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */
|
||||||
if (trace)
|
if (trace)
|
||||||
tpacket("received", dp, n);
|
tpacket("received", dp, n);
|
||||||
/* should verify client address */
|
/* should verify client address */
|
||||||
dp_opcode = ntohs((u_short)dp->th_opcode);
|
dp_opcode = ntohs((u_short) dp->th_opcode);
|
||||||
dp_block = ntohs((u_short)dp->th_block);
|
dp_block = ntohs((u_short) dp->th_block);
|
||||||
if (dp_opcode == ERROR) {
|
if (dp_opcode == ERROR) {
|
||||||
printf("Error code %d: %s\n", dp_block, dp->th_msg);
|
printf("Error code %d: %s\n", dp_block, dp->th_msg);
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
if (dp_opcode == DATA) {
|
if (dp_opcode == DATA) {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
if (dp_block == block) {
|
if (dp_block == block) {
|
||||||
break; /* have next packet */
|
break; /* have next packet */
|
||||||
}
|
}
|
||||||
/* On an error, try to synchronize
|
/* On an error, try to synchronize
|
||||||
* both sides.
|
* both sides.
|
||||||
*/
|
*/
|
||||||
j = synchnet(f);
|
j = synchnet(f);
|
||||||
if (j && trace) {
|
if (j && trace) {
|
||||||
printf("discarded %d packets\n", j);
|
printf("discarded %d packets\n", j);
|
||||||
}
|
}
|
||||||
if (dp_block == (block-1)) {
|
if (dp_block == (block - 1)) {
|
||||||
goto send_ack; /* resend ack */
|
goto send_ack; /* resend ack */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* size = write(fd, dp->th_data, n - 4); */
|
/* size = write(fd, dp->th_data, n - 4); */
|
||||||
size = writeit(file, &dp, n - 4, convert);
|
size = writeit(file, &dp, n - 4, convert);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
nak(errno + 100, NULL);
|
nak(errno + 100, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
amount += size;
|
amount += size;
|
||||||
} while (size == SEGSIZE);
|
} while (size == SEGSIZE);
|
||||||
abort: /* ok to ack, since user */
|
abort: /* ok to ack, since user */
|
||||||
ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
|
ap->th_opcode = htons((u_short) ACK); /* has seen err msg */
|
||||||
ap->th_block = htons((u_short)block);
|
ap->th_block = htons((u_short) block);
|
||||||
(void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
|
(void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
|
||||||
sizeof(peeraddr));
|
SOCKLEN(&peeraddr));
|
||||||
write_behind(file, convert); /* flush last buffer */
|
write_behind(file, convert); /* flush last buffer */
|
||||||
fclose(file);
|
fclose(file);
|
||||||
stopclock();
|
stopclock();
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
printstats("Received", amount);
|
printstats("Received", amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
makerequest(int request, const char *name,
|
makerequest(int request, const char *name,
|
||||||
struct tftphdr *tp, const char *mode)
|
struct tftphdr *tp, const char *mode)
|
||||||
{
|
{
|
||||||
char *cp;
|
char *cp;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
tp->th_opcode = htons((u_short)request);
|
tp->th_opcode = htons((u_short) request);
|
||||||
cp = (char *) &(tp->th_stuff);
|
cp = (char *)&(tp->th_stuff);
|
||||||
strcpy(cp, name);
|
len = strlen(name) + 1;
|
||||||
cp += strlen(name);
|
memcpy(cp, name, len);
|
||||||
*cp++ = '\0';
|
cp += len;
|
||||||
strcpy(cp, mode);
|
len = strlen(mode) + 1;
|
||||||
cp += strlen(mode);
|
memcpy(cp, mode, len);
|
||||||
*cp++ = '\0';
|
cp += len;
|
||||||
return (cp - (char *)tp);
|
return (cp - (char *)tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const errmsgs[] =
|
static const char *const errmsgs[] = {
|
||||||
{
|
"Undefined error code", /* 0 - EUNDEF */
|
||||||
"Undefined error code", /* 0 - EUNDEF */
|
"File not found", /* 1 - ENOTFOUND */
|
||||||
"File not found", /* 1 - ENOTFOUND */
|
"Access denied", /* 2 - EACCESS */
|
||||||
"Access denied", /* 2 - EACCESS */
|
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
|
||||||
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
|
"Illegal TFTP operation", /* 4 - EBADOP */
|
||||||
"Illegal TFTP operation", /* 4 - EBADOP */
|
"Unknown transfer ID", /* 5 - EBADID */
|
||||||
"Unknown transfer ID", /* 5 - EBADID */
|
"File already exists", /* 6 - EEXISTS */
|
||||||
"File already exists", /* 6 - EEXISTS */
|
"No such user", /* 7 - ENOUSER */
|
||||||
"No such user", /* 7 - ENOUSER */
|
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
|
||||||
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
|
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -329,121 +311,115 @@ static const char * const errmsgs[] =
|
||||||
* standard TFTP codes, or a UNIX errno
|
* standard TFTP codes, or a UNIX errno
|
||||||
* offset by 100.
|
* offset by 100.
|
||||||
*/
|
*/
|
||||||
static void
|
static void nak(int error, const char *msg)
|
||||||
nak(int error, const char *msg)
|
|
||||||
{
|
{
|
||||||
struct tftphdr *tp;
|
struct tftphdr *tp;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
tp = (struct tftphdr *)ackbuf;
|
|
||||||
tp->th_opcode = htons((u_short)ERROR);
|
|
||||||
tp->th_code = htons((u_short)error);
|
|
||||||
|
|
||||||
if ( error >= 100 ) {
|
tp = (struct tftphdr *)ackbuf;
|
||||||
/* This is a Unix errno+100 */
|
tp->th_opcode = htons((u_short) ERROR);
|
||||||
if ( !msg )
|
tp->th_code = htons((u_short) error);
|
||||||
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);
|
if (error >= 100) {
|
||||||
|
/* This is a Unix errno+100 */
|
||||||
|
if (!msg)
|
||||||
|
msg = strerror(error - 100);
|
||||||
|
error = EUNDEF;
|
||||||
|
} else {
|
||||||
|
if ((unsigned)error >= ERR_CNT)
|
||||||
|
error = EUNDEF;
|
||||||
|
|
||||||
length = strlen(msg)+1;
|
if (!msg)
|
||||||
memcpy(tp->th_msg, msg, length);
|
msg = errmsgs[error];
|
||||||
length += 4; /* Add space for header */
|
}
|
||||||
|
|
||||||
if (trace)
|
tp->th_code = htons((u_short) error);
|
||||||
tpacket("sent", tp, length);
|
|
||||||
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
|
length = strlen(msg) + 1;
|
||||||
sizeof(peeraddr)) != length)
|
memcpy(tp->th_msg, msg, length);
|
||||||
perror("nak");
|
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
|
static void tpacket(const char *s, struct tftphdr *tp, int n)
|
||||||
tpacket(const char *s, struct tftphdr *tp, int n)
|
|
||||||
{
|
{
|
||||||
static const char *opcodes[] =
|
static const char *opcodes[] =
|
||||||
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
|
{ "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
|
||||||
char *cp, *file;
|
char *cp, *file;
|
||||||
u_short op = ntohs((u_short)tp->th_opcode);
|
u_short op = ntohs((u_short) tp->th_opcode);
|
||||||
|
|
||||||
if (op < RRQ || op > ERROR)
|
if (op < RRQ || op > ERROR)
|
||||||
printf("%s opcode=%x ", s, op);
|
printf("%s opcode=%x ", s, op);
|
||||||
else
|
else
|
||||||
printf("%s %s ", s, opcodes[op]);
|
printf("%s %s ", s, opcodes[op]);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|
||||||
case RRQ:
|
case RRQ:
|
||||||
case WRQ:
|
case WRQ:
|
||||||
n -= 2;
|
n -= 2;
|
||||||
file = cp = (char *) &(tp->th_stuff);
|
file = cp = (char *)&(tp->th_stuff);
|
||||||
cp = strchr(cp, '\0');
|
cp = strchr(cp, '\0');
|
||||||
printf("<file=%s, mode=%s>\n", file, cp + 1);
|
printf("<file=%s, mode=%s>\n", file, cp + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DATA:
|
case DATA:
|
||||||
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
|
printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACK:
|
case ACK:
|
||||||
printf("<block=%d>\n", ntohs(tp->th_block));
|
printf("<block=%d>\n", ntohs(tp->th_block));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
|
printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timeval tstart;
|
struct timeval tstart;
|
||||||
struct timeval tstop;
|
struct timeval tstop;
|
||||||
|
|
||||||
static void
|
static void startclock(void)
|
||||||
startclock(void)
|
|
||||||
{
|
{
|
||||||
(void)gettimeofday(&tstart, NULL);
|
(void)gettimeofday(&tstart, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void stopclock(void)
|
||||||
stopclock(void)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
(void)gettimeofday(&tstop, NULL);
|
(void)gettimeofday(&tstop, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void printstats(const char *direction, unsigned long amount)
|
||||||
printstats(const char *direction, unsigned long amount)
|
|
||||||
{
|
{
|
||||||
double delta;
|
double delta;
|
||||||
|
|
||||||
delta = (tstop.tv_sec+(tstop.tv_usec/100000.0)) -
|
delta = (tstop.tv_sec + (tstop.tv_usec / 100000.0)) -
|
||||||
(tstart.tv_sec+(tstart.tv_usec/100000.0));
|
(tstart.tv_sec + (tstart.tv_usec / 100000.0));
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
|
printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
|
||||||
printf(" [%.0f bit/s]", (amount*8.)/delta);
|
printf(" [%.0f bit/s]", (amount * 8.) / delta);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void timer(int sig)
|
||||||
timer(int sig)
|
|
||||||
{
|
{
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
|
|
||||||
(void)sig; /* Shut up unused warning */
|
(void)sig; /* Shut up unused warning */
|
||||||
|
|
||||||
timeout += rexmtval;
|
timeout += rexmtval;
|
||||||
if (timeout >= maxtimeout) {
|
if (timeout >= maxtimeout) {
|
||||||
printf("Transfer timed out.\n");
|
printf("Transfer timed out.\n");
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
siglongjmp(toplevel, -1);
|
siglongjmp(toplevel, -1);
|
||||||
}
|
}
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
siglongjmp(timeoutbuf, 1);
|
siglongjmp(timeoutbuf, 1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
274
tftp/tftpsubs.c
274
tftp/tftpsubs.c
|
|
@ -1,274 +0,0 @@
|
||||||
/* tftp-hpa: $Id$ */
|
|
||||||
|
|
||||||
/* $OpenBSD: tftpsubs.c,v 1.2 1996/06/26 05:40:36 deraadt Exp $ */
|
|
||||||
/* $NetBSD: tftpsubs.c,v 1.3 1994/12/08 09:51:31 jtc Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 1983, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. All advertising materials mentioning features or use of this software
|
|
||||||
* must display the following acknowledgement:
|
|
||||||
* This product includes software developed by the University of
|
|
||||||
* California, Berkeley and its contributors.
|
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tftpsubs.h"
|
|
||||||
|
|
||||||
#ifndef lint
|
|
||||||
/* static char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93"; */
|
|
||||||
/* static char rcsid[] = "$OpenBSD: tftpsubs.c,v 1.2 1996/06/26 05:40:36 deraadt Exp $"; */
|
|
||||||
static const char *rcsid UNUSED =
|
|
||||||
"tftp-hpa: $Id$";
|
|
||||||
#endif /* not lint */
|
|
||||||
|
|
||||||
/* Simple minded read-ahead/write-behind subroutines for tftp user and
|
|
||||||
server. Written originally with multiple buffers in mind, but current
|
|
||||||
implementation has two buffer logic wired in.
|
|
||||||
|
|
||||||
Todo: add some sort of final error check so when the write-buffer
|
|
||||||
is finally flushed, the caller can detect if the disk filled up
|
|
||||||
(or had an i/o error) and return a nak to the other side.
|
|
||||||
|
|
||||||
Jim Guyton 10/85
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
|
|
||||||
#define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
|
|
||||||
|
|
||||||
int segsize = SEGSIZE; /* Default segsize */
|
|
||||||
|
|
||||||
struct bf {
|
|
||||||
int counter; /* size of data in buffer, or flag */
|
|
||||||
char buf[PKTSIZE]; /* room for data packet */
|
|
||||||
} bfs[2];
|
|
||||||
|
|
||||||
/* Values for bf.counter */
|
|
||||||
#define BF_ALLOC -3 /* alloc'd but not yet filled */
|
|
||||||
#define BF_FREE -2 /* free */
|
|
||||||
/* [-1 .. segsize] = size of data in the data buffer */
|
|
||||||
|
|
||||||
static int nextone; /* index of next buffer to use */
|
|
||||||
static int current; /* index of buffer in use */
|
|
||||||
|
|
||||||
/* control flags for crlf conversions */
|
|
||||||
int newline = 0; /* fillbuf: in middle of newline expansion */
|
|
||||||
int prevchar = -1; /* putbuf: previous char (cr check) */
|
|
||||||
|
|
||||||
static struct tftphdr *rw_init(int);
|
|
||||||
|
|
||||||
struct tftphdr *w_init() { return rw_init(0); } /* write-behind */
|
|
||||||
struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */
|
|
||||||
|
|
||||||
/* init for either read-ahead or write-behind */
|
|
||||||
/* x == zero for write-behind, one for read-head */
|
|
||||||
static struct tftphdr *
|
|
||||||
rw_init(int x)
|
|
||||||
{
|
|
||||||
newline = 0; /* init crlf flag */
|
|
||||||
prevchar = -1;
|
|
||||||
bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
|
|
||||||
current = 0;
|
|
||||||
bfs[1].counter = BF_FREE;
|
|
||||||
nextone = x; /* ahead or behind? */
|
|
||||||
return (struct tftphdr *)bfs[0].buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Have emptied current buffer by sending to net and getting ack.
|
|
||||||
Free it and return next buffer filled with data.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
readit(FILE *file, struct tftphdr **dpp, int convert)
|
|
||||||
{
|
|
||||||
struct bf *b;
|
|
||||||
|
|
||||||
bfs[current].counter = BF_FREE; /* free old one */
|
|
||||||
current = !current; /* "incr" current */
|
|
||||||
|
|
||||||
b = &bfs[current]; /* look at new buffer */
|
|
||||||
if (b->counter == BF_FREE) /* if it's empty */
|
|
||||||
read_ahead(file, convert); /* fill it */
|
|
||||||
/* assert(b->counter != BF_FREE);*//* check */
|
|
||||||
*dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
|
|
||||||
return b->counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fill the input buffer, doing ascii conversions if requested
|
|
||||||
* conversions are lf -> cr,lf and cr -> cr, nul
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
read_ahead(FILE *file, int convert)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *p;
|
|
||||||
int c;
|
|
||||||
struct bf *b;
|
|
||||||
struct tftphdr *dp;
|
|
||||||
|
|
||||||
b = &bfs[nextone]; /* look at "next" buffer */
|
|
||||||
if (b->counter != BF_FREE) /* nop if not free */
|
|
||||||
return;
|
|
||||||
nextone = !nextone; /* "incr" next buffer ptr */
|
|
||||||
|
|
||||||
dp = (struct tftphdr *)b->buf;
|
|
||||||
|
|
||||||
if (convert == 0) {
|
|
||||||
b->counter = read(fileno(file), dp->th_data, segsize);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = dp->th_data;
|
|
||||||
for (i = 0 ; i < segsize; i++) {
|
|
||||||
if (newline) {
|
|
||||||
if (prevchar == '\n')
|
|
||||||
c = '\n'; /* lf to cr,lf */
|
|
||||||
else c = '\0'; /* cr to cr,nul */
|
|
||||||
newline = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c = getc(file);
|
|
||||||
if (c == EOF) break;
|
|
||||||
if (c == '\n' || c == '\r') {
|
|
||||||
prevchar = c;
|
|
||||||
c = '\r';
|
|
||||||
newline = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
b->counter = (int)(p - dp->th_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update count associated with the buffer, get new buffer
|
|
||||||
from the queue. Calls write_behind only if next buffer not
|
|
||||||
available.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
|
|
||||||
{
|
|
||||||
bfs[current].counter = ct; /* set size of data to write */
|
|
||||||
current = !current; /* switch to other buffer */
|
|
||||||
if (bfs[current].counter != BF_FREE) /* if not free */
|
|
||||||
(void)write_behind(file, convert); /* flush it */
|
|
||||||
bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
|
|
||||||
*dpp = (struct tftphdr *)bfs[current].buf;
|
|
||||||
return ct; /* this is a lie of course */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Output a buffer to a file, converting from netascii if requested.
|
|
||||||
* CR,NUL -> CR and CR,LF => LF.
|
|
||||||
* Note spec is undefined if we get CR as last byte of file or a
|
|
||||||
* CR followed by anything else. In this case we leave it alone.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
write_behind(FILE *file, int convert)
|
|
||||||
{
|
|
||||||
char *buf;
|
|
||||||
int count;
|
|
||||||
int ct;
|
|
||||||
char *p;
|
|
||||||
int c; /* current character */
|
|
||||||
struct bf *b;
|
|
||||||
struct tftphdr *dp;
|
|
||||||
|
|
||||||
b = &bfs[nextone];
|
|
||||||
if (b->counter < -1) /* anything to flush? */
|
|
||||||
return 0; /* just nop if nothing to do */
|
|
||||||
|
|
||||||
count = b->counter; /* remember byte count */
|
|
||||||
b->counter = BF_FREE; /* reset flag */
|
|
||||||
dp = (struct tftphdr *)b->buf;
|
|
||||||
nextone = !nextone; /* incr for next time */
|
|
||||||
buf = dp->th_data;
|
|
||||||
|
|
||||||
if (count <= 0) return -1; /* nak logic? */
|
|
||||||
|
|
||||||
if (convert == 0)
|
|
||||||
return write(fileno(file), buf, count);
|
|
||||||
|
|
||||||
p = buf;
|
|
||||||
ct = count;
|
|
||||||
while (ct--) { /* loop over the buffer */
|
|
||||||
c = *p++; /* pick up a character */
|
|
||||||
if (prevchar == '\r') { /* if prev char was cr */
|
|
||||||
if (c == '\n') /* if have cr,lf then just */
|
|
||||||
fseek(file, -1, 1); /* smash lf on top of the cr */
|
|
||||||
else
|
|
||||||
if (c == '\0') /* if have cr,nul then */
|
|
||||||
goto skipit; /* just skip over the putc */
|
|
||||||
/* else just fall through and allow it */
|
|
||||||
}
|
|
||||||
putc(c, file);
|
|
||||||
skipit:
|
|
||||||
prevchar = c;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* When an error has occurred, it is possible that the two sides
|
|
||||||
* are out of synch. Ie: that what I think is the other side's
|
|
||||||
* response to packet N is really their response to packet N-1.
|
|
||||||
*
|
|
||||||
* So, to try to prevent that, we flush all the input queued up
|
|
||||||
* for us on the network connection on our host.
|
|
||||||
*
|
|
||||||
* We return the number of packets we flushed (mostly for reporting
|
|
||||||
* when trace is active).
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
synchnet(int f) /* socket to flush */
|
|
||||||
{
|
|
||||||
int pktcount = 0;
|
|
||||||
char rbuf[PKTSIZE];
|
|
||||||
struct sockaddr_in from;
|
|
||||||
int fromlen;
|
|
||||||
fd_set socketset;
|
|
||||||
struct timeval notime;
|
|
||||||
|
|
||||||
while ( 1 ) {
|
|
||||||
notime.tv_sec = notime.tv_usec = 0;
|
|
||||||
|
|
||||||
FD_ZERO(&socketset);
|
|
||||||
FD_SET(f, &socketset);
|
|
||||||
|
|
||||||
if ( select(f, &socketset, NULL, NULL, ¬ime) <= 0 )
|
|
||||||
break; /* Nothing to read */
|
|
||||||
|
|
||||||
/* Otherwise drain the packet */
|
|
||||||
pktcount++;
|
|
||||||
fromlen = sizeof from;
|
|
||||||
(void) recvfrom(f, rbuf, sizeof (rbuf), 0,
|
|
||||||
(struct sockaddr *)&from, &fromlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pktcount; /* Return packets drained */
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +1,17 @@
|
||||||
SRCROOT = ..
|
SRCROOT = ..
|
||||||
VERSION = $(shell cat ../version)
|
VERSION = $(shell cat ../version)
|
||||||
|
|
||||||
-include ../MCONFIG
|
-include ../config/MCONFIG
|
||||||
include ../MRULES
|
include ../MRULES
|
||||||
|
|
||||||
OBJS = tftpd.$(O) tftpsubs.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS)
|
OBJS = tftpd.$(O) recvfrom.$(O) misc.$(O) $(TFTPDOBJS)
|
||||||
|
|
||||||
all: tftpd$(X) tftpd.8
|
all: tftpd$(X) tftpd.8
|
||||||
|
|
||||||
tftpd$(X): $(OBJS)
|
tftpd$(X): $(OBJS)
|
||||||
$(CC) $(LDFLAGS) $^ $(TFTPD_LIBS) -o $@
|
$(CC) $(LDFLAGS) $^ $(TFTPD_LIBS) -o $@
|
||||||
|
|
||||||
tftpsubs.c:
|
$(OBJS): ../common/tftpsubs.h
|
||||||
$(LN_S) -f ../tftp/tftpsubs.c .
|
|
||||||
|
|
||||||
tftpsubs.h:
|
|
||||||
$(LN_S) -f ../tftp/tftpsubs.h .
|
|
||||||
|
|
||||||
$(OBJS): tftpsubs.h
|
|
||||||
|
|
||||||
tftpd.8: tftpd.8.in ../version
|
tftpd.8: tftpd.8.in ../version
|
||||||
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
|
sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
|
||||||
|
|
|
||||||
52
tftpd/misc.c
52
tftpd/misc.c
|
|
@ -1,7 +1,6 @@
|
||||||
/* $Id$ */
|
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
|
@ -15,27 +14,19 @@
|
||||||
* Minor help routines.
|
* Minor help routines.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h" /* Must be included first! */
|
#include "config.h" /* Must be included first! */
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include "tftpd.h"
|
#include "tftpd.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the signal handler and flags. Basically a user-friendly
|
* Set the signal handler and flags, and error out on failure.
|
||||||
* wrapper around sigaction().
|
|
||||||
*/
|
*/
|
||||||
void set_signal(int signum, void (*handler)(int), int flags)
|
void set_signal(int signum, sighandler_t handler, int flags)
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
if (tftp_signal(signum, handler, flags)) {
|
||||||
|
syslog(LOG_ERR, "sigaction: %m");
|
||||||
memset(&sa, 0, sizeof sa);
|
exit(EX_OSERR);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -43,14 +34,14 @@ void set_signal(int signum, void (*handler)(int), int flags)
|
||||||
*/
|
*/
|
||||||
void *tfmalloc(size_t size)
|
void *tfmalloc(size_t size)
|
||||||
{
|
{
|
||||||
void *p = malloc(size);
|
void *p = malloc(size);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
syslog(LOG_ERR, "malloc: %m");
|
syslog(LOG_ERR, "malloc: %m");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -58,13 +49,12 @@ void *tfmalloc(size_t size)
|
||||||
*/
|
*/
|
||||||
char *tfstrdup(const char *str)
|
char *tfstrdup(const char *str)
|
||||||
{
|
{
|
||||||
char *p = strdup(str);
|
char *p = strdup(str);
|
||||||
|
|
||||||
if ( !p ) {
|
if (!p) {
|
||||||
syslog(LOG_ERR, "strdup: %m");
|
syslog(LOG_ERR, "strdup: %m");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
334
tftpd/recvfrom.c
334
tftpd/recvfrom.c
|
|
@ -1,7 +1,6 @@
|
||||||
/* $Id$ */
|
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
|
@ -18,28 +17,30 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h" /* Must be included first! */
|
#include "config.h" /* Must be included first! */
|
||||||
|
#include "common/tftpsubs.h"
|
||||||
#include "recvfrom.h"
|
#include "recvfrom.h"
|
||||||
#include "tftpsubs.h"
|
|
||||||
#ifdef HAVE_MACHINE_PARAM_H
|
#ifdef HAVE_MACHINE_PARAM_H
|
||||||
#include <machine/param.h> /* Needed on some versions of FreeBSD */
|
#include <machine/param.h> /* Needed on some versions of FreeBSD */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
|
#if defined(HAVE_RECVMSG) && defined(HAVE_MSGHDR_MSG_CONTROL)
|
||||||
|
|
||||||
#include <sys/uio.h>
|
#ifdef HAVE_SYS_UIO_H
|
||||||
|
# include <sys/uio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef IP_PKTINFO
|
#ifdef IP_PKTINFO
|
||||||
# ifndef HAVE_STRUCT_IN_PKTINFO
|
# ifndef HAVE_STRUCT_IN_PKTINFO_IPI_ADDR
|
||||||
# ifdef __linux__
|
# ifdef __linux__
|
||||||
/* Assume this version of glibc simply lacks the definition */
|
/* Assume this version of glibc simply lacks the definition */
|
||||||
struct in_pktinfo {
|
struct in_pktinfo {
|
||||||
int ipi_ifindex;
|
int ipi_ifindex;
|
||||||
struct in_addr ipi_spec_dst;
|
struct in_addr ipi_spec_dst;
|
||||||
struct in_addr ipi_addr;
|
struct in_addr ipi_addr;
|
||||||
};
|
};
|
||||||
# else
|
# else
|
||||||
# undef IP_PKTINFO /* No definition, no way to get it */
|
# undef IP_PKTINFO /* No definition, no way to get it */
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -51,103 +52,246 @@ struct in_pktinfo {
|
||||||
# define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
|
# define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
/*
|
||||||
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
* Check to see if this is a valid local address, meaning that we can
|
||||||
struct sockaddr *from, int *fromlen,
|
* legally bind to it.
|
||||||
struct sockaddr_in *myaddr)
|
*/
|
||||||
|
static int address_is_local(const union sock_addr *addr)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
union sock_addr sa1, sa2;
|
||||||
struct iovec iov;
|
int sockfd = -1;
|
||||||
int n;
|
int e;
|
||||||
struct cmsghdr *cmptr;
|
int rv = 0;
|
||||||
union {
|
socklen_t addrlen;
|
||||||
struct cmsghdr cm;
|
|
||||||
#ifdef IP_PKTINFO
|
|
||||||
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
|
||||||
CMSG_SPACE(sizeof(struct in_pktinfo))];
|
|
||||||
#else
|
|
||||||
char control[CMSG_SPACE(sizeof(struct in_addr))];
|
|
||||||
#endif
|
|
||||||
} control_un;
|
|
||||||
int on = 1;
|
|
||||||
#ifdef IP_PKTINFO
|
|
||||||
struct in_pktinfo pktinfo;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Try to enable getting the return address */
|
memcpy(&sa1, addr, sizeof sa1);
|
||||||
#ifdef IP_RECVDSTADDR
|
|
||||||
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
|
|
||||||
#endif
|
|
||||||
#ifdef IP_PKTINFO
|
|
||||||
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
|
|
||||||
msg.msg_control = control_un.control;
|
|
||||||
msg.msg_controllen = sizeof(control_un.control);
|
|
||||||
msg.msg_flags = 0;
|
|
||||||
|
|
||||||
msg.msg_name = from;
|
|
||||||
msg.msg_namelen = *fromlen;
|
|
||||||
iov.iov_base = buf;
|
|
||||||
iov.iov_len = len;
|
|
||||||
msg.msg_iov = &iov;
|
|
||||||
msg.msg_iovlen = 1;
|
|
||||||
|
|
||||||
if ( (n = recvmsg(s, &msg, flags)) < 0 )
|
|
||||||
return n; /* Error */
|
|
||||||
|
|
||||||
*fromlen = msg.msg_namelen;
|
|
||||||
|
|
||||||
if ( myaddr ) {
|
|
||||||
bzero(myaddr, sizeof(struct sockaddr_in));
|
|
||||||
myaddr->sin_family = AF_INET;
|
|
||||||
|
|
||||||
if ( msg.msg_controllen < sizeof(struct cmsghdr) ||
|
|
||||||
(msg.msg_flags & MSG_CTRUNC) )
|
|
||||||
return n; /* No information available */
|
|
||||||
|
|
||||||
for ( cmptr = CMSG_FIRSTHDR(&msg) ; cmptr != NULL ;
|
|
||||||
cmptr = CMSG_NXTHDR(&msg, cmptr) ) {
|
|
||||||
|
|
||||||
#ifdef IP_RECVSTDADDR
|
|
||||||
if ( cmptr->cmsg_level == IPPROTO_IP &&
|
|
||||||
cmptr->cmsg_type == IP_RECVDSTADDR ) {
|
|
||||||
memcpy(&myaddr->sin_addr, CMSG_DATA(cmptr),
|
|
||||||
sizeof(struct in_addr));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef IP_PKTINFO
|
|
||||||
if ( cmptr->cmsg_level == IPPROTO_IP &&
|
|
||||||
cmptr->cmsg_type == IP_PKTINFO ) {
|
|
||||||
memcpy(&pktinfo, CMSG_DATA(cmptr), sizeof(struct in_pktinfo));
|
|
||||||
memcpy(&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof(struct in_addr));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
return n;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* pointless... */
|
static void normalize_ip6_compat(union sock_addr *myaddr)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
static const uint8_t ip6_compat_prefix[12] =
|
||||||
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
|
||||||
|
struct sockaddr_in in;
|
||||||
|
|
||||||
|
if (myaddr->sa.sa_family == AF_INET6 &&
|
||||||
|
!memcmp(&myaddr->s6.sin6_addr, ip6_compat_prefix,
|
||||||
|
sizeof ip6_compat_prefix)) {
|
||||||
|
bzero(&in, sizeof in);
|
||||||
|
in.sin_family = AF_INET;
|
||||||
|
in.sin_port = myaddr->s6.sin6_port;
|
||||||
|
memcpy(&in.sin_addr, (const char *)&myaddr->s6.sin6_addr +
|
||||||
|
sizeof ip6_compat_prefix, sizeof in.sin_addr);
|
||||||
|
memcpy(&myaddr->si, &in, sizeof in);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)myaddr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
struct sockaddr *from, int *fromlen,
|
union sock_addr *from, union sock_addr *myaddr)
|
||||||
struct sockaddr_in *myaddr)
|
|
||||||
{
|
{
|
||||||
/* There is no way we can get the local address, fudge it */
|
struct msghdr msg;
|
||||||
|
struct iovec iov;
|
||||||
|
int n;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
union {
|
||||||
|
struct cmsghdr cm;
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
||||||
|
CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||||
|
#else
|
||||||
|
char control[CMSG_SPACE(sizeof(struct in_addr))];
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#ifdef HAVE_STRUCT_IN6_PKTINFO
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_addr)) +
|
||||||
|
CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
#else
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_addr))];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} control_un;
|
||||||
|
int on = 1;
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
struct in_pktinfo pktinfo;
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_STRUCT_IN6_PKTINFO
|
||||||
|
struct in6_pktinfo pktinfo6;
|
||||||
|
#endif
|
||||||
|
|
||||||
bzero(myaddr, sizeof(struct sockaddr_in));
|
/* Try to enable getting the return address */
|
||||||
myaddr->sin_family = AF_INET;
|
#ifdef IP_RECVDSTADDR
|
||||||
|
if (from->sa.sa_family == AF_INET)
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
|
||||||
|
#endif
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
if (from->sa.sa_family == AF_INET)
|
||||||
|
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
if (from->sa.sa_family == AF_INET6)
|
||||||
|
setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
|
||||||
|
msg.msg_control = control_un.control;
|
||||||
|
msg.msg_controllen = sizeof(control_un);
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
myaddr->sin_port = htons(IPPORT_TFTP);
|
msg.msg_name = &from->sa;
|
||||||
bzero(&myaddr->sin_addr, sizeof(myaddr->sin_addr));
|
msg.msg_namelen = sizeof(*from);
|
||||||
|
iov.iov_base = buf;
|
||||||
|
iov.iov_len = len;
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
return recvfrom(s,buf,len,flags,from,fromlen);
|
if ((n = recvmsg(s, &msg, flags)) < 0)
|
||||||
|
return n; /* Error */
|
||||||
|
|
||||||
|
if (myaddr) {
|
||||||
|
bzero(myaddr, sizeof(*myaddr));
|
||||||
|
myaddr->sa.sa_family = from->sa.sa_family;
|
||||||
|
|
||||||
|
if (msg.msg_controllen < sizeof(struct cmsghdr) ||
|
||||||
|
(msg.msg_flags & MSG_CTRUNC))
|
||||||
|
return n; /* No information available */
|
||||||
|
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
|
||||||
|
cmptr = CMSG_NXTHDR(&msg, cmptr)) {
|
||||||
|
|
||||||
|
if (from->sa.sa_family == AF_INET) {
|
||||||
|
myaddr->sa.sa_family = AF_INET;
|
||||||
|
#ifdef IP_RECVDSTADDR
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||||
|
cmptr->cmsg_type == IP_RECVDSTADDR) {
|
||||||
|
memcpy(&myaddr->si.sin_addr, CMSG_DATA(cmptr),
|
||||||
|
sizeof(struct in_addr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IP &&
|
||||||
|
cmptr->cmsg_type == IP_PKTINFO) {
|
||||||
|
memcpy(&pktinfo, CMSG_DATA(cmptr),
|
||||||
|
sizeof(struct in_pktinfo));
|
||||||
|
memcpy(&myaddr->si.sin_addr, &pktinfo.ipi_addr,
|
||||||
|
sizeof(struct in_addr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (from->sa.sa_family == AF_INET6) {
|
||||||
|
myaddr->sa.sa_family = AF_INET6;
|
||||||
|
#ifdef IP6_RECVDSTADDR
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
|
||||||
|
cmptr->cmsg_type == IPV6_RECVDSTADDR )
|
||||||
|
memcpy(&myaddr->s6.sin6_addr, CMSG_DATA(cmptr),
|
||||||
|
sizeof(struct in6_addr));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_STRUCT_IN6_PKTINFO
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IPV6 &&
|
||||||
|
(
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
cmptr->cmsg_type == IPV6_RECVPKTINFO ||
|
||||||
|
#endif
|
||||||
|
cmptr->cmsg_type == IPV6_PKTINFO)) {
|
||||||
|
memcpy(&pktinfo6, CMSG_DATA(cmptr),
|
||||||
|
sizeof(struct in6_pktinfo));
|
||||||
|
memcpy(&myaddr->s6.sin6_addr, &pktinfo6.ipi6_addr,
|
||||||
|
sizeof(struct in6_addr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_ip6_compat(myaddr);
|
||||||
|
|
||||||
|
/* If the address is not a valid local address,
|
||||||
|
* then bind to any address...
|
||||||
|
*/
|
||||||
|
if (address_is_local(myaddr) != 1) {
|
||||||
|
if (myaddr->sa.sa_family == AF_INET)
|
||||||
|
((struct sockaddr_in *)myaddr)->sin_addr.s_addr = INADDR_ANY;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (myaddr->sa.sa_family == AF_INET6)
|
||||||
|
memset(&myaddr->s6.sin6_addr, 0, sizeof(struct in6_addr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_ip6_compat(from);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* pointless... */
|
||||||
|
|
||||||
|
int
|
||||||
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
|
union sock_addr *from, union sock_addr *myaddr)
|
||||||
|
{
|
||||||
|
/* There is no way we can get the local address, fudge it */
|
||||||
|
socklen_t fromlen = sizeof(*from);
|
||||||
|
|
||||||
|
bzero(myaddr, sizeof(*myaddr));
|
||||||
|
myaddr->sa.sa_family = from->sa.sa_family;
|
||||||
|
sa_set_port(myaddr, htons(IPPORT_TFTP));
|
||||||
|
|
||||||
|
return recvfrom(s, buf, len, flags, &from->sa, &fromlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/* $Id$ */
|
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2006 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
|
@ -20,5 +19,4 @@
|
||||||
|
|
||||||
int
|
int
|
||||||
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
struct sockaddr *from, int *fromlen,
|
union sock_addr *from, union sock_addr *myaddr);
|
||||||
struct sockaddr_in *myaddr);
|
|
||||||
|
|
|
||||||
767
tftpd/remap.c
767
tftpd/remap.c
|
|
@ -1,7 +1,6 @@
|
||||||
/* $Id$ */
|
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001-2004 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2024 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
|
@ -15,7 +14,7 @@
|
||||||
* Perform regular-expression based filename remapping.
|
* Perform regular-expression based filename remapping.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h" /* Must be included first! */
|
#include "config.h" /* Must be included first! */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
@ -23,123 +22,172 @@
|
||||||
#include "tftpd.h"
|
#include "tftpd.h"
|
||||||
#include "remap.h"
|
#include "remap.h"
|
||||||
|
|
||||||
#define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
|
#define DEADMAN_MAX_STEPS 4096 /* Timeout after this many steps */
|
||||||
#define MAXLINE 16384 /* Truncate a line at this many bytes */
|
#define MAXLINE 16384 /* Truncate a line at this many bytes */
|
||||||
|
|
||||||
#define RULE_REWRITE 0x01 /* This is a rewrite rule */
|
#define RULE_REWRITE 0x01 /* This is a rewrite rule */
|
||||||
#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */
|
#define RULE_GLOBAL 0x02 /* Global rule (repeat until no match) */
|
||||||
#define RULE_EXIT 0x04 /* Exit after matching this rule */
|
#define RULE_EXIT 0x04 /* Exit after matching this rule */
|
||||||
#define RULE_RESTART 0x08 /* Restart at the top after matching this rule */
|
#define RULE_RESTART 0x08 /* Restart at the top after matching this rule */
|
||||||
#define RULE_ABORT 0x10 /* Terminate processing with an error */
|
#define RULE_ABORT 0x10 /* Terminate processing with an error */
|
||||||
#define RULE_GETONLY 0x20 /* Applicable to GET only */
|
#define RULE_INVERSE 0x20 /* Execute if regex *doesn't* match */
|
||||||
#define RULE_PUTONLY 0x40 /* Applicable to PUT only */
|
#define RULE_IPV4 0x40 /* IPv4 only */
|
||||||
#define RULE_INVERSE 0x80 /* Execute if regex *doesn't* match */
|
#define RULE_IPV6 0x80 /* IPv6 only */
|
||||||
|
|
||||||
|
#define RULE_HASFILE 0x100 /* Valid if rule results in a valid filename */
|
||||||
|
#define RULE_RRQ 0x200 /* Get (read) only */
|
||||||
|
#define RULE_WRQ 0x400 /* Put (write) only */
|
||||||
|
#define RULE_SEDG 0x800 /* sed-style global */
|
||||||
|
|
||||||
|
int deadman_max_steps = DEADMAN_MAX_STEPS;
|
||||||
|
|
||||||
struct rule {
|
struct rule {
|
||||||
struct rule *next;
|
struct rule *next;
|
||||||
int nrule;
|
int nrule;
|
||||||
int rule_flags;
|
unsigned int rule_flags;
|
||||||
regex_t rx;
|
regex_t rx;
|
||||||
const char *pattern;
|
const char *pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int xform_null(int c)
|
static int xform_null(int c)
|
||||||
{
|
{
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xform_toupper(int c)
|
static int xform_toupper(int c)
|
||||||
{
|
{
|
||||||
return toupper(c);
|
return toupper(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xform_tolower(int c)
|
static int xform_tolower(int c)
|
||||||
{
|
{
|
||||||
return tolower(c);
|
return tolower(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do \-substitution. Call with string == NULL to get length only. */
|
/*
|
||||||
static int genmatchstring(char *string, const char *pattern, const char *input,
|
* Do \-substitution. Call with string == NULL to get length only.
|
||||||
const regmatch_t *pmatch, match_pattern_callback macrosub)
|
* "start" indicates an offset into the input buffer where the pattern
|
||||||
|
* match was started.
|
||||||
|
*/
|
||||||
|
static int do_genmatchstring(char *string, const char *pattern,
|
||||||
|
const char *ibuf,
|
||||||
|
const regmatch_t * pmatch,
|
||||||
|
match_pattern_callback macrosub,
|
||||||
|
int start, int *nextp)
|
||||||
{
|
{
|
||||||
int (*xform)(int) = xform_null;
|
int (*xform) (int) = xform_null;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int n, mlen, sublen;
|
int n, mlen, sublen;
|
||||||
int endbytes;
|
int endbytes;
|
||||||
|
const char *input = ibuf + start;
|
||||||
|
|
||||||
/* Get section before match; note pmatch[0] is the whole match */
|
/* Get section before match; note pmatch[0] is the whole match */
|
||||||
endbytes = strlen(input) - pmatch[0].rm_eo;
|
endbytes = strlen(input) - pmatch[0].rm_eo;
|
||||||
len = pmatch[0].rm_so + endbytes;
|
len = start + pmatch[0].rm_so;
|
||||||
if ( string ) {
|
if (string) {
|
||||||
memcpy(string, input, pmatch[0].rm_so);
|
/* Copy the prefix before "start" as well! */
|
||||||
string += pmatch[0].rm_so;
|
memcpy(string, ibuf, start + pmatch[0].rm_so);
|
||||||
}
|
string += start + 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 ) {
|
|
||||||
memcpy(string, input+pmatch[n].rm_so, mlen);
|
|
||||||
string += mlen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 */
|
/* Transform matched section */
|
||||||
if ( string ) {
|
while (*pattern) {
|
||||||
memcpy(string, input+pmatch[0].rm_eo, endbytes);
|
mlen = 0;
|
||||||
string[endbytes] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
if (*pattern == '\\' && pattern[1] != '\0') {
|
||||||
|
char macro = pattern[1];
|
||||||
|
switch (macro) {
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
n = pattern[1] - '0';
|
||||||
|
|
||||||
|
if (pmatch[n].rm_so != -1) {
|
||||||
|
mlen = pmatch[n].rm_eo - pmatch[n].rm_so;
|
||||||
|
len += mlen;
|
||||||
|
if (string) {
|
||||||
|
const char *p = input + start + pmatch[n].rm_so;
|
||||||
|
while (mlen--)
|
||||||
|
*string++ = xform(*p++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'L':
|
||||||
|
xform = xform_tolower;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
xform = xform_toupper;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
xform = xform_null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (macrosub && (sublen = macrosub(macro, string)) >= 0) {
|
||||||
|
while (sublen--) {
|
||||||
|
len++;
|
||||||
|
if (string) {
|
||||||
|
*string = xform(*string);
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len++;
|
||||||
|
if (string)
|
||||||
|
*string++ = xform(pattern[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pattern += 2;
|
||||||
|
} else {
|
||||||
|
len++;
|
||||||
|
if (string)
|
||||||
|
*string++ = xform(*pattern);
|
||||||
|
pattern++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pointer to post-substitution tail */
|
||||||
|
if (nextp)
|
||||||
|
*nextp = len;
|
||||||
|
|
||||||
|
/* Copy section after match */
|
||||||
|
len += endbytes;
|
||||||
|
if (string) {
|
||||||
|
memcpy(string, input + pmatch[0].rm_eo, endbytes);
|
||||||
|
string[endbytes] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ditto, but allocate the string in a new buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int genmatchstring(char **string, const char *pattern,
|
||||||
|
const char *ibuf,
|
||||||
|
const regmatch_t * pmatch,
|
||||||
|
match_pattern_callback macrosub,
|
||||||
|
int start, int *nextp)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
len = do_genmatchstring(NULL, pattern, ibuf, pmatch,
|
||||||
|
macrosub, start, NULL);
|
||||||
|
*string = buf = tfmalloc(len + 1);
|
||||||
|
return do_genmatchstring(buf, pattern, ibuf, pmatch,
|
||||||
|
macrosub, start, nextp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -149,276 +197,349 @@ static int genmatchstring(char *string, const char *pattern, const char *input,
|
||||||
*/
|
*/
|
||||||
static int readescstring(char *buf, char **str)
|
static int readescstring(char *buf, char **str)
|
||||||
{
|
{
|
||||||
char *p = *str;
|
char *p = *str;
|
||||||
int wasbs = 0, len = 0;
|
int wasbs = 0, len = 0;
|
||||||
|
|
||||||
while ( *p && isspace(*p) )
|
while (*p && isspace(*p))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
|
if (!*p) {
|
||||||
|
*buf = '\0';
|
||||||
|
*str = p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
|
if (!wasbs && (isspace(*p) || *p == '#')) {
|
||||||
|
*buf = '\0';
|
||||||
|
*str = p;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
/* Important: two backslashes leave us in the !wasbs state! */
|
||||||
|
wasbs = !wasbs && (*p == '\\');
|
||||||
|
*buf++ = *p++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! *p ) {
|
|
||||||
*buf = '\0';
|
*buf = '\0';
|
||||||
*str = p;
|
*str = p;
|
||||||
return 0;
|
return len;
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
/* Parse a line into a set of instructions */
|
||||||
static int parseline(char *line, struct rule *r, int lineno)
|
static int parseline(char *line, struct rule *r, int lineno)
|
||||||
{
|
{
|
||||||
char buffer[MAXLINE];
|
char buffer[MAXLINE];
|
||||||
char *p;
|
char *p;
|
||||||
int rv;
|
int rv;
|
||||||
int rxflags = REG_EXTENDED;
|
int rxflags = REG_EXTENDED;
|
||||||
static int nrule;
|
static int nrule;
|
||||||
|
|
||||||
memset(r, 0, sizeof *r);
|
memset(r, 0, sizeof *r);
|
||||||
r->nrule = nrule;
|
r->nrule = nrule;
|
||||||
|
|
||||||
if ( !readescstring(buffer, &line) )
|
if (!readescstring(buffer, &line))
|
||||||
return 0; /* No rule found */
|
return 0; /* No rule found */
|
||||||
|
|
||||||
for ( p = buffer ; *p ; p++ ) {
|
for (p = buffer; *p; p++) {
|
||||||
switch(*p) {
|
switch (*p) {
|
||||||
case 'r':
|
case 'r':
|
||||||
r->rule_flags |= RULE_REWRITE;
|
r->rule_flags |= RULE_REWRITE;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
r->rule_flags |= RULE_GLOBAL;
|
if (r->rule_flags & RULE_GLOBAL)
|
||||||
break;
|
r->rule_flags |= RULE_SEDG;
|
||||||
case 'e':
|
else
|
||||||
r->rule_flags |= RULE_EXIT;
|
r->rule_flags |= RULE_GLOBAL;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 'e':
|
||||||
r->rule_flags |= RULE_RESTART;
|
r->rule_flags |= RULE_EXIT;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'E':
|
||||||
r->rule_flags |= RULE_ABORT;
|
r->rule_flags |= RULE_HASFILE;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 's':
|
||||||
rxflags |= REG_ICASE;
|
r->rule_flags |= RULE_RESTART;
|
||||||
break;
|
break;
|
||||||
case 'G':
|
case 'a':
|
||||||
r->rule_flags |= RULE_GETONLY;
|
r->rule_flags |= RULE_ABORT;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'i':
|
||||||
r->rule_flags |= RULE_PUTONLY;
|
rxflags |= REG_ICASE;
|
||||||
break;
|
break;
|
||||||
case '~':
|
case '~':
|
||||||
r->rule_flags |= RULE_INVERSE;
|
r->rule_flags |= RULE_INVERSE;
|
||||||
break;
|
break;
|
||||||
default:
|
case '4':
|
||||||
syslog(LOG_ERR, "Remap command \"%s\" on line %d contains invalid char \"%c\"",
|
r->rule_flags |= RULE_IPV4;
|
||||||
buffer, lineno, *p);
|
break;
|
||||||
return -1; /* Error */
|
case '6':
|
||||||
break;
|
r->rule_flags |= RULE_IPV6;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
r->rule_flags |= RULE_RRQ;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
r->rule_flags |= RULE_WRQ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"Remap command \"%s\" on line %d contains invalid char \"%c\"",
|
||||||
|
buffer, lineno, *p);
|
||||||
|
return -1; /* Error */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* RULE_GLOBAL only applies when RULE_REWRITE specified */
|
if (r->rule_flags & RULE_REWRITE) {
|
||||||
if ( !(r->rule_flags & RULE_REWRITE) )
|
if (r->rule_flags & RULE_INVERSE) {
|
||||||
r->rule_flags &= ~RULE_GLOBAL;
|
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n",
|
||||||
|
lineno, line);
|
||||||
|
return -1; /* Error */
|
||||||
|
}
|
||||||
|
if ((r->rule_flags & (RULE_GLOBAL|RULE_SEDG|RULE_HASFILE))
|
||||||
|
== (RULE_GLOBAL|RULE_HASFILE)) {
|
||||||
|
syslog(LOG_ERR, "E rules cannot be combined with g (but gg is OK), line %d: %s\n",
|
||||||
|
lineno, line);
|
||||||
|
return -1; /* Error */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* RULE_GLOBAL and RULE_SEDG are meaningless without RULE_REWRITE */
|
||||||
|
r->rule_flags &= ~(RULE_GLOBAL|RULE_SEDG);
|
||||||
|
}
|
||||||
|
|
||||||
if ( r->rule_flags & (RULE_INVERSE|RULE_REWRITE) ) {
|
/* Read and compile the regex */
|
||||||
syslog(LOG_ERR, "r rules cannot be inverted, line %d: %s\n", lineno, line);
|
if (!readescstring(buffer, &line)) {
|
||||||
return -1; /* Error */
|
syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);
|
||||||
}
|
return -1; /* Error */
|
||||||
|
}
|
||||||
|
|
||||||
/* Read and compile the regex */
|
if ((rv = regcomp(&r->rx, buffer, rxflags)) != 0) {
|
||||||
if ( !readescstring(buffer, &line) ) {
|
char errbuf[BUFSIZ];
|
||||||
syslog(LOG_ERR, "No regex on remap line %d: %s\n", lineno, line);
|
regerror(rv, &r->rx, errbuf, BUFSIZ);
|
||||||
return -1; /* Error */
|
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno,
|
||||||
}
|
errbuf);
|
||||||
|
return -1; /* Error */
|
||||||
|
}
|
||||||
|
|
||||||
if ( (rv = regcomp(&r->rx, buffer, rxflags)) != 0 ) {
|
/* Read the rewrite pattern, if any */
|
||||||
char errbuf[BUFSIZ];
|
if (readescstring(buffer, &line)) {
|
||||||
regerror(rv, &r->rx, errbuf, BUFSIZ);
|
r->pattern = tfstrdup(buffer);
|
||||||
syslog(LOG_ERR, "Bad regex in remap line %d: %s\n", lineno, errbuf);
|
} else {
|
||||||
return -1; /* Error */
|
r->pattern = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the rewrite pattern, if any */
|
nrule++;
|
||||||
if ( readescstring(buffer, &line) ) {
|
return 1; /* Rule found */
|
||||||
r->pattern = tfstrdup(buffer);
|
|
||||||
} else {
|
|
||||||
r->pattern = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
nrule++;
|
|
||||||
return 1; /* Rule found */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a rule file */
|
/* Read a rule file */
|
||||||
struct rule *parserulefile(FILE *f)
|
struct rule *parserulefile(FILE * f)
|
||||||
{
|
{
|
||||||
char line[MAXLINE];
|
char line[MAXLINE];
|
||||||
struct rule *first_rule = NULL;
|
struct rule *first_rule = NULL;
|
||||||
struct rule **last_rule = &first_rule;
|
struct rule **last_rule = &first_rule;
|
||||||
struct rule *this_rule = tfmalloc(sizeof(struct rule));
|
struct rule *this_rule = tfmalloc(sizeof(struct rule));
|
||||||
int rv;
|
int rv;
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
while ( lineno++, fgets(line, MAXLINE, f) ) {
|
while (lineno++, fgets(line, MAXLINE, f)) {
|
||||||
rv = parseline(line, this_rule, lineno);
|
rv = parseline(line, this_rule, lineno);
|
||||||
if ( rv < 0 )
|
if (rv < 0)
|
||||||
err = 1;
|
err = 1;
|
||||||
if ( rv > 0 ) {
|
if (rv > 0) {
|
||||||
*last_rule = this_rule;
|
*last_rule = this_rule;
|
||||||
last_rule = &this_rule->next;
|
last_rule = &this_rule->next;
|
||||||
this_rule = tfmalloc(sizeof(struct rule));
|
this_rule = tfmalloc(sizeof(struct rule));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
free(this_rule); /* Last one is always unused */
|
free(this_rule); /* Last one is always unused */
|
||||||
|
|
||||||
if ( err ) {
|
if (err) {
|
||||||
/* Bail on error, we have already logged an error message */
|
/* Bail on error, we have already logged an error message */
|
||||||
exit(EX_CONFIG);
|
exit(EX_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
return first_rule;
|
return first_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy a rule file data structure */
|
/* Destroy a rule file data structure */
|
||||||
void freerules(struct rule *r)
|
void freerules(struct rule *r)
|
||||||
{
|
{
|
||||||
struct rule *next;
|
struct rule *next;
|
||||||
|
|
||||||
while ( r ) {
|
while (r) {
|
||||||
next = r->next;
|
next = r->next;
|
||||||
|
|
||||||
regfree(&r->rx);
|
regfree(&r->rx);
|
||||||
|
|
||||||
/* "" patterns aren't allocated by malloc() */
|
/* "" patterns aren't allocated by malloc() */
|
||||||
if ( r->pattern && *r->pattern )
|
if (r->pattern && *r->pattern)
|
||||||
free((void *)r->pattern);
|
free((void *)r->pattern);
|
||||||
|
|
||||||
free(r);
|
|
||||||
|
|
||||||
r = next;
|
free(r);
|
||||||
}
|
|
||||||
|
r = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute a rule set on a string; returns a malloc'd new string. */
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
char *rewrite_string(const char *input, const struct rule *rules,
|
char *rewrite_string(const struct formats *pf,
|
||||||
int is_put, match_pattern_callback macrosub,
|
const char *input, const struct rule *rules,
|
||||||
const char **errmsg)
|
int mode, int af, match_pattern_callback macrosub,
|
||||||
|
const char **errmsg)
|
||||||
{
|
{
|
||||||
char *current = tfstrdup(input);
|
char *current = tfstrdup(input);
|
||||||
char *newstr;
|
char *newstr, *newerstr;
|
||||||
const struct rule *ruleptr = rules;
|
const char *accerr;
|
||||||
regmatch_t pmatch[10];
|
const struct rule *ruleptr = rules;
|
||||||
int len;
|
regmatch_t pmatch[10];
|
||||||
int was_match = 0;
|
int i;
|
||||||
int deadman = DEADMAN_MAX_STEPS;
|
int len;
|
||||||
|
int was_match = 0;
|
||||||
|
int deadman = deadman_max_steps;
|
||||||
|
int matchsense;
|
||||||
|
int pmatches;
|
||||||
|
unsigned int bad_flags;
|
||||||
|
int ggoffset;
|
||||||
|
|
||||||
/* Default error */
|
/* Default error */
|
||||||
*errmsg = "Remap table failure";
|
*errmsg = "Remap table failure";
|
||||||
|
|
||||||
if ( verbosity >= 3 ) {
|
if (verbosity >= 3) {
|
||||||
syslog(LOG_INFO, "remap: input: %s", current);
|
syslog(LOG_INFO, "remap: input: %s", current);
|
||||||
}
|
|
||||||
|
|
||||||
for ( ruleptr = rules ; ruleptr ; ruleptr = ruleptr->next ) {
|
|
||||||
if ( ((ruleptr->rule_flags & RULE_GETONLY) && is_put) ||
|
|
||||||
((ruleptr->rule_flags & RULE_PUTONLY) && !is_put) ) {
|
|
||||||
continue; /* Rule not applicable, try next */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! deadman-- ) {
|
bad_flags = 0;
|
||||||
syslog(LOG_WARNING, "remap: Breaking loop, input = %s, last = %s",
|
if (mode != RRQ) bad_flags |= RULE_RRQ;
|
||||||
input, current);
|
if (mode != WRQ) bad_flags |= RULE_WRQ;
|
||||||
free(current);
|
if (af != AF_INET) bad_flags |= RULE_IPV4;
|
||||||
return NULL; /* Did not terminate! */
|
if (af != AF_INET6) bad_flags |= RULE_IPV6;
|
||||||
|
|
||||||
|
for (ruleptr = rules; ruleptr; ruleptr = ruleptr->next) {
|
||||||
|
if (ruleptr->rule_flags & bad_flags)
|
||||||
|
continue; /* This rule is excluded by flags */
|
||||||
|
|
||||||
|
matchsense = ruleptr->rule_flags & RULE_INVERSE ? REG_NOMATCH : 0;
|
||||||
|
pmatches = ruleptr->rule_flags & RULE_INVERSE ? 0 : 10;
|
||||||
|
|
||||||
|
/* Clear the pmatch[] array */
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
pmatch[i].rm_so = pmatch[i].rm_eo = -1;
|
||||||
|
|
||||||
|
was_match = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (!deadman--)
|
||||||
|
goto dead;
|
||||||
|
|
||||||
|
if (regexec(&ruleptr->rx, current, pmatches, pmatch, 0)
|
||||||
|
!= matchsense)
|
||||||
|
break; /* No match, break out of do loop */
|
||||||
|
|
||||||
|
/* Match on this rule */
|
||||||
|
was_match = 1;
|
||||||
|
|
||||||
|
if (ruleptr->rule_flags & RULE_ABORT) {
|
||||||
|
if (verbosity >= 3) {
|
||||||
|
syslog(LOG_INFO, "remap: rule %d: abort: %s",
|
||||||
|
ruleptr->nrule, current);
|
||||||
|
}
|
||||||
|
if (ruleptr->pattern[0]) {
|
||||||
|
/* Custom error message */
|
||||||
|
genmatchstring(&newstr, ruleptr->pattern, current,
|
||||||
|
pmatch, macrosub, 0, NULL);
|
||||||
|
*errmsg = newstr;
|
||||||
|
} else {
|
||||||
|
*errmsg = NULL;
|
||||||
|
}
|
||||||
|
free(current);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ruleptr->rule_flags & RULE_REWRITE) {
|
||||||
|
len = genmatchstring(&newstr, ruleptr->pattern, current,
|
||||||
|
pmatch, macrosub, 0, &ggoffset);
|
||||||
|
|
||||||
|
if (ruleptr->rule_flags & RULE_SEDG) {
|
||||||
|
/* sed-style partial-matching global */
|
||||||
|
while (ggoffset < len &&
|
||||||
|
regexec(&ruleptr->rx, newstr + ggoffset,
|
||||||
|
pmatches, pmatch,
|
||||||
|
ggoffset ? REG_NOTBOL : 0)
|
||||||
|
== matchsense) {
|
||||||
|
if (!deadman--) {
|
||||||
|
free(current);
|
||||||
|
current = newstr;
|
||||||
|
goto dead;
|
||||||
|
}
|
||||||
|
len = genmatchstring(&newerstr, ruleptr->pattern,
|
||||||
|
newstr, pmatch, macrosub,
|
||||||
|
ggoffset, &ggoffset);
|
||||||
|
free(newstr);
|
||||||
|
newstr = newerstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ruleptr->rule_flags & RULE_HASFILE) &&
|
||||||
|
pf->f_validate(newstr, mode, pf, &accerr)) {
|
||||||
|
if (verbosity >= 3) {
|
||||||
|
syslog(LOG_INFO, "remap: rule %d: ignored rewrite (%s): %s",
|
||||||
|
ruleptr->nrule, accerr, newstr);
|
||||||
|
}
|
||||||
|
free(newstr);
|
||||||
|
was_match = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(current);
|
||||||
|
current = newstr;
|
||||||
|
if (verbosity >= 3) {
|
||||||
|
syslog(LOG_INFO, "remap: rule %d: rewrite: %s",
|
||||||
|
ruleptr->nrule, current);
|
||||||
|
}
|
||||||
|
} else if (ruleptr->rule_flags & RULE_HASFILE) {
|
||||||
|
if (pf->f_validate(current, mode, pf, &accerr)) {
|
||||||
|
if (verbosity >= 3) {
|
||||||
|
syslog(LOG_INFO, "remap: rule %d: not exiting (%s)\n",
|
||||||
|
ruleptr->nrule, accerr);
|
||||||
|
}
|
||||||
|
was_match = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If the rule is (old-style) global, keep going until no match */
|
||||||
|
} while ((ruleptr->rule_flags & (RULE_GLOBAL|RULE_SEDG)) == RULE_GLOBAL);
|
||||||
|
|
||||||
|
if (!was_match)
|
||||||
|
continue; /* Next rule */
|
||||||
|
|
||||||
|
if (ruleptr->rule_flags & (RULE_EXIT|RULE_HASFILE)) {
|
||||||
|
if (verbosity >= 3) {
|
||||||
|
syslog(LOG_INFO, "remap: rule %d: exit",
|
||||||
|
ruleptr->nrule);
|
||||||
|
}
|
||||||
|
return current; /* Exit here, we're done */
|
||||||
|
} else if (ruleptr->rule_flags & RULE_RESTART) {
|
||||||
|
ruleptr = rules; /* Start from the top */
|
||||||
|
if (verbosity >= 3) {
|
||||||
|
syslog(LOG_INFO, "remap: rule %d: restart",
|
||||||
|
ruleptr->nrule);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
if (verbosity >= 3) {
|
||||||
if ( regexec(&ruleptr->rx, current, 10, pmatch, 0) ==
|
syslog(LOG_INFO, "remap: done");
|
||||||
(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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return current;
|
||||||
|
|
||||||
if ( verbosity >= 3 ) {
|
dead: /* Deadman expired */
|
||||||
syslog(LOG_INFO, "remap: done");
|
syslog(LOG_ERR,
|
||||||
}
|
"remap: Breaking loop after %d steps, input = %s, last = %s",
|
||||||
return current;
|
deadman_max_steps, input, current);
|
||||||
|
free(current);
|
||||||
|
return NULL; /* Did not terminate! */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/* $Id$ */
|
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001-2007 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
* as the "OpenBSD" operating system, distributed at
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
|
@ -27,7 +26,7 @@ struct rule;
|
||||||
macro character is passed as the first argument; the output buffer,
|
macro character is passed as the first argument; the output buffer,
|
||||||
if any, is passed as the second argument. The function should return
|
if any, is passed as the second argument. The function should return
|
||||||
the number of characters output, or -1 on failure. */
|
the number of characters output, or -1 on failure. */
|
||||||
typedef int (*match_pattern_callback)(char, char *);
|
typedef int (*match_pattern_callback) (char, char *);
|
||||||
|
|
||||||
/* Read a rule file */
|
/* Read a rule file */
|
||||||
struct rule *parserulefile(FILE *);
|
struct rule *parserulefile(FILE *);
|
||||||
|
|
@ -36,9 +35,13 @@ struct rule *parserulefile(FILE *);
|
||||||
void freerules(struct rule *);
|
void freerules(struct rule *);
|
||||||
|
|
||||||
/* Execute a rule set on a string; returns a malloc'd new string. */
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
char *rewrite_string(const char *, const struct rule *, int,
|
struct formats;
|
||||||
match_pattern_callback, const char **);
|
char *rewrite_string(const struct formats *, const char *,
|
||||||
|
const struct rule *, int, int,
|
||||||
|
match_pattern_callback, const char **);
|
||||||
|
|
||||||
#endif /* WITH_REGEX */
|
/* Remapping deadman counter */
|
||||||
#endif /* TFTPD_REMAP_H */
|
extern int deadman_max_steps;
|
||||||
|
|
||||||
|
#endif /* WITH_REGEX */
|
||||||
|
#endif /* TFTPD_REMAP_H */
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
# $Id$
|
|
||||||
#
|
#
|
||||||
# Sample rule file for the -m (remapping option)
|
# Sample rule file for the -m (remapping option)
|
||||||
#
|
#
|
||||||
|
|
|
||||||
157
tftpd/tftpd.8.in
157
tftpd/tftpd.8.in
|
|
@ -1,10 +1,9 @@
|
||||||
.\" -*- nroff -*- --------------------------------------------------------- *
|
.\" -*- nroff -*- --------------------------------------------------------- *
|
||||||
.\" $Id$
|
.\"
|
||||||
.\"
|
|
||||||
.\" Copyright (c) 1990, 1993, 1994
|
.\" Copyright (c) 1990, 1993, 1994
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright 2001 H. Peter Anvin - All Rights Reserved
|
.\" Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
|
||||||
.\"
|
.\"
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
.\" modification, are permitted provided that the following conditions
|
.\" modification, are permitted provided that the following conditions
|
||||||
|
|
@ -31,17 +30,17 @@
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\"----------------------------------------------------------------------- */
|
.\"----------------------------------------------------------------------- */
|
||||||
.TH TFTPD 8 "3 September 2004" "tftp-hpa @@VERSION@@" "System Manager's Manual"
|
.TH TFTPD 8 "7 June 2014" "tftp-hpa @@VERSION@@" "System Manager's Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
.B tftpd
|
.B tftpd
|
||||||
\- IPv4 Trivial File Transfer Protocol server
|
\- Trivial File Transfer Protocol server
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B in.tftpd
|
.B in.tftpd
|
||||||
.RI [ options... ]
|
.RI [ options... ]
|
||||||
.I directory...
|
.I directory...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.B tftpd
|
.B tftpd
|
||||||
is a server for the IPv4 Trivial File Transfer Protocol. The TFTP
|
is a server for the Trivial File Transfer Protocol. The TFTP
|
||||||
protocol is extensively used to support remote booting of diskless
|
protocol is extensively used to support remote booting of diskless
|
||||||
devices. The server is normally started by
|
devices. The server is normally started by
|
||||||
.BR inetd ,
|
.BR inetd ,
|
||||||
|
|
@ -49,52 +48,70 @@ but can also run standalone.
|
||||||
.PP
|
.PP
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
.B \-l
|
\fB\-\-ipv4\fP, \fB\-4\fP
|
||||||
|
Connect with IPv4 only, even if IPv6 support was compiled in.
|
||||||
|
.TP
|
||||||
|
\fB\-\-ipv6\fP, \fB\-6\fP
|
||||||
|
Connect with IPv6 only, if compiled in.
|
||||||
|
.TP
|
||||||
|
\fB\-l\fP, \fB\-\-listen\fP
|
||||||
Run the server in standalone (listen) mode, rather than run from
|
Run the server in standalone (listen) mode, rather than run from
|
||||||
.BR inetd .
|
.BR inetd .
|
||||||
In listen mode, the
|
In listen mode, the
|
||||||
.B \-t
|
.B \-\-timeout
|
||||||
option is ignored, and the
|
option is ignored, and the
|
||||||
.B \-a
|
.B \-\-address
|
||||||
option can be used to specify a specific local address or port to
|
option can be used to specify a specific local address or port to
|
||||||
listen to.
|
listen to.
|
||||||
.TP
|
.TP
|
||||||
\fB\-a\fP \fI[address][:port]\fP
|
\fB\-\-foreground\fP, \fB\-L\fP
|
||||||
|
Similar to
|
||||||
|
.B \-\-listen
|
||||||
|
but do not detach from the foreground process. Implies
|
||||||
|
.BR \-\-listen .
|
||||||
|
.TP
|
||||||
|
\fB\-\-address\fP \fI[address][:port]\fP, \fB\-a\fP \fI[address][:port]\fP
|
||||||
Specify a specific
|
Specify a specific
|
||||||
.I address
|
.I address
|
||||||
and
|
and
|
||||||
.I port
|
.I port
|
||||||
to listen to when called with the
|
to listen to when called with the
|
||||||
.B \-l
|
.B \-\-listen
|
||||||
|
or
|
||||||
|
.B \-\-foreground
|
||||||
option. The default is to listen to the
|
option. The default is to listen to the
|
||||||
.I tftp
|
.I tftp
|
||||||
port specified in
|
port specified in
|
||||||
.I /etc/services
|
.I /etc/services
|
||||||
on all local addresses.
|
on all local addresses.
|
||||||
|
|
||||||
|
.B Please note:
|
||||||
|
Numeric IPv6 adresses must be enclosed in square brackets
|
||||||
|
to avoid ambiguity with the optional port information.
|
||||||
.TP
|
.TP
|
||||||
.B \-c
|
\fB\-\-create\fP, \fB\-c\fP
|
||||||
Allow new files to be created. By default,
|
Allow new files to be created. By default,
|
||||||
.B tftpd
|
.B tftpd
|
||||||
will only allow upload of files that already exist. Files are created
|
will only allow upload of files that already exist. Files are created
|
||||||
with default permissions allowing anyone to read or write them, unless
|
with default permissions allowing anyone to read or write them, unless
|
||||||
the
|
the
|
||||||
.B \-p
|
.B \-\-permissive
|
||||||
or
|
or
|
||||||
.B \-U
|
.B \-\-umask
|
||||||
options are specified.
|
options are specified.
|
||||||
.TP
|
.TP
|
||||||
.B \-s
|
\fB\-\-secure\fP, \fB\-s\fP
|
||||||
Change root directory on startup. This means the remote host does not
|
Change root directory on startup. This means the remote host does not
|
||||||
need to pass along the directory as part of the transfer, and may add
|
need to pass along the directory as part of the transfer, and may add
|
||||||
security. When
|
security. When
|
||||||
.B \-s
|
.B \-\-secure
|
||||||
is specified, exactly one
|
is specified, exactly one
|
||||||
.I directory
|
.I directory
|
||||||
should be specified on the command line. The use of this option is
|
should be specified on the command line. The use of this option is
|
||||||
recommended for security as well as compatibility with some boot ROMs
|
recommended for security as well as compatibility with some boot ROMs
|
||||||
which cannot be easily made to include a directory name in its request.
|
which cannot be easily made to include a directory name in its request.
|
||||||
.TP
|
.TP
|
||||||
\fB\-u\fP \fIusername\fP
|
\fB\-\-user\fP \fIusername\fP, \fB\-u\fP \fIusername\fP
|
||||||
Specify the username which
|
Specify the username which
|
||||||
.B tftpd
|
.B tftpd
|
||||||
will run as; the default is "nobody". The user ID, group ID, and (if
|
will run as; the default is "nobody". The user ID, group ID, and (if
|
||||||
|
|
@ -102,21 +119,26 @@ possible on the platform) the supplementary group IDs will be set to
|
||||||
the ones specified in the system permission database for this
|
the ones specified in the system permission database for this
|
||||||
username.
|
username.
|
||||||
.TP
|
.TP
|
||||||
\fB\-U\fP \fIumask\fP
|
\fB\-\-umask\fP \fIumask\fP, \fB\-U\fP \fIumask\fP
|
||||||
Sets the \fIumask\fP for newly created files to the specified value.
|
Sets the \fIumask\fP for newly created files to the specified value.
|
||||||
The default is zero (anyone can read or write) if the
|
The default is zero (anyone can read or write) if the
|
||||||
.B \-p
|
.B \-\-permissive
|
||||||
option is not specified, or inherited from the invoking process if
|
option is not specified, or inherited from the invoking process if
|
||||||
.B \-p
|
.B \-\-permissive
|
||||||
is specified.
|
is specified.
|
||||||
.TP
|
.TP
|
||||||
.B \-p
|
\fB\-\-permissive\fP, \fB\-p\fP
|
||||||
Perform no additional permissions checks above the normal
|
Perform no additional permissions checks above the normal
|
||||||
system-provided access controls for the user specified via the
|
system-provided access controls for the user specified via the
|
||||||
.B \-u
|
.B \-\-user
|
||||||
option.
|
option.
|
||||||
.TP
|
.TP
|
||||||
\fB\-t\fP \fItimeout\fP
|
\fB\-\-pidfile\fP \fIpidfile\fP, \fB\-P\fP \fIpidfile\fP
|
||||||
|
When run in standalone mode, write the process ID of the listening
|
||||||
|
server into \fIpidfile\fP. On normal termination (SIGTERM or SIGINT)
|
||||||
|
the pid file is automatically removed.
|
||||||
|
.TP
|
||||||
|
\fB\-\-timeout\fP \fItimeout\fP, \fB\-t\fP \fItimeout\fP
|
||||||
When run from
|
When run from
|
||||||
.B inetd
|
.B inetd
|
||||||
this specifies how long, in seconds, to wait for a second connection
|
this specifies how long, in seconds, to wait for a second connection
|
||||||
|
|
@ -125,7 +147,7 @@ before terminating the server.
|
||||||
will then respawn the server when another request comes in. The
|
will then respawn the server when another request comes in. The
|
||||||
default is 900 (15 minutes.)
|
default is 900 (15 minutes.)
|
||||||
.TP
|
.TP
|
||||||
\fB\-T\fP \fItimeout\fP
|
\fB\-\-retransmit\fP \fItimeout, \fP\fB\-T\fP \fItimeout\fP
|
||||||
Determine the default timeout, in microseconds, before the first
|
Determine the default timeout, in microseconds, before the first
|
||||||
packet is retransmitted. This can be modified by the client if the
|
packet is retransmitted. This can be modified by the client if the
|
||||||
.B timeout
|
.B timeout
|
||||||
|
|
@ -133,7 +155,7 @@ or
|
||||||
.B utimeout
|
.B utimeout
|
||||||
option is negotiated. The default is 1000000 (1 second.)
|
option is negotiated. The default is 1000000 (1 second.)
|
||||||
.TP
|
.TP
|
||||||
\fB\-m\fP \fIremap-file\fP
|
\fB\-\-map-file\fP \fIremap-file\fP, \fB\-m\fP \fIremap-file\fP
|
||||||
Specify the use of filename remapping. The
|
Specify the use of filename remapping. The
|
||||||
.I remap-file
|
.I remap-file
|
||||||
is a file containing the remapping rules. See the section on filename
|
is a file containing the remapping rules. See the section on filename
|
||||||
|
|
@ -141,16 +163,23 @@ remapping below. This option may not be compiled in, see the output of
|
||||||
.B "in.tftpd \-V"
|
.B "in.tftpd \-V"
|
||||||
to verify whether or not it is available.
|
to verify whether or not it is available.
|
||||||
.TP
|
.TP
|
||||||
.B \-v
|
.\fB\-\-map-steps\fP \fIsteps\fP
|
||||||
|
Specify the number of remapping rules that may be executed before the
|
||||||
|
filename mapping fails. The default is 4096.
|
||||||
|
.TP
|
||||||
|
\fB\-\-verbose\fP, \fB\-v\fP
|
||||||
Increase the logging verbosity of
|
Increase the logging verbosity of
|
||||||
.BR tftpd .
|
.BR tftpd .
|
||||||
This flag can be specified multiple times for even higher verbosity.
|
This flag can be specified multiple times for even higher verbosity.
|
||||||
.TP
|
.TP
|
||||||
\fB\-r\fP \fItftp-option\fP
|
\fB\-\-verbosity\fP \fIvalue\fP
|
||||||
|
Set the verbosity value to \fIvalue\fP.
|
||||||
|
.TP
|
||||||
|
\fB\-\-refuse\fP \fItftp-option\fP, \fB\-r\fP \fItftp-option\fP
|
||||||
Indicate that a specific RFC 2347 TFTP option should never be
|
Indicate that a specific RFC 2347 TFTP option should never be
|
||||||
accepted.
|
accepted.
|
||||||
.TP
|
.TP
|
||||||
\fB\-B\fP \fImax-block-size\fP
|
\fB\-\-blocksize\fP \fImax-block-size\fP, \fB\-B\fP \fImax-block-size\fP
|
||||||
Specifies the maximum permitted block size. The permitted range for
|
Specifies the maximum permitted block size. The permitted range for
|
||||||
this parameter is from 512 to 65464. Some embedded clients request
|
this parameter is from 512 to 65464. Some embedded clients request
|
||||||
large block sizes and yet do not handle fragmented packets correctly;
|
large block sizes and yet do not handle fragmented packets correctly;
|
||||||
|
|
@ -159,7 +188,11 @@ MTU on your network minus 32 bytes (20 bytes for IP, 8 for UDP, and 4
|
||||||
for TFTP; less if you use IP options on your network.) For example,
|
for TFTP; less if you use IP options on your network.) For example,
|
||||||
on a standard Ethernet (MTU 1500) a value of 1468 is reasonable.
|
on a standard Ethernet (MTU 1500) a value of 1468 is reasonable.
|
||||||
.TP
|
.TP
|
||||||
.B \-V
|
\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
|
Print the version number and configuration to standard output, then
|
||||||
exit gracefully.
|
exit gracefully.
|
||||||
.SH "RFC 2347 OPTION NEGOTIATION"
|
.SH "RFC 2347 OPTION NEGOTIATION"
|
||||||
|
|
@ -194,9 +227,13 @@ Set the time before the server retransmits a packet, in seconds.
|
||||||
.TP
|
.TP
|
||||||
\fButimeout\fP (nonstandard)
|
\fButimeout\fP (nonstandard)
|
||||||
Set the time before the server retransmits a packet, in microseconds.
|
Set the time before the server retransmits a packet, in microseconds.
|
||||||
|
.TP
|
||||||
|
\fBrollover\fP (nonstandard)
|
||||||
|
Set the block number to resume at after a block number rollover. The
|
||||||
|
default and recommended value is zero.
|
||||||
.PP
|
.PP
|
||||||
The
|
The
|
||||||
.B \-r
|
.B \-\-refuse
|
||||||
option can be used to disable specific options; this may be necessary
|
option can be used to disable specific options; this may be necessary
|
||||||
to work around bugs in specific TFTP client implementations. For
|
to work around bugs in specific TFTP client implementations. For
|
||||||
example, some TFTP clients have been found to request the
|
example, some TFTP clients have been found to request the
|
||||||
|
|
@ -205,7 +242,7 @@ option, but crash with an error if they actually get the option
|
||||||
accepted by the server.
|
accepted by the server.
|
||||||
.SH "FILENAME REMAPPING"
|
.SH "FILENAME REMAPPING"
|
||||||
The
|
The
|
||||||
.B \-m
|
.B \-\-map-file
|
||||||
option specifies a file which contains filename remapping rules. Each
|
option specifies a file which contains filename remapping rules. Each
|
||||||
non-comment line (comments begin with hash marks,
|
non-comment line (comments begin with hash marks,
|
||||||
.BR # )
|
.BR # )
|
||||||
|
|
@ -237,7 +274,18 @@ by the
|
||||||
The replacement pattern may contain escape sequences; see below.
|
The replacement pattern may contain escape sequences; see below.
|
||||||
.TP
|
.TP
|
||||||
.B g
|
.B g
|
||||||
Repeat this rule until it no longer matches. This is always used with
|
Repeat this rule until it no longer matches. This is always used with
|
||||||
|
.BR r .
|
||||||
|
.TP
|
||||||
|
.B gg
|
||||||
|
Repeat this rule until it no longer matches, but only on the portion
|
||||||
|
of the string that has not yet been matched, similar to how the
|
||||||
|
.B s
|
||||||
|
command with the
|
||||||
|
.B g
|
||||||
|
option works in
|
||||||
|
.BR sed (1).
|
||||||
|
This is always used with
|
||||||
.BR r .
|
.BR r .
|
||||||
.TP
|
.TP
|
||||||
.B i
|
.B i
|
||||||
|
|
@ -248,6 +296,17 @@ case-insensitively. By default it is case sensitive.
|
||||||
.B e
|
.B e
|
||||||
If this rule matches, end rule processing after executing the rule.
|
If this rule matches, end rule processing after executing the rule.
|
||||||
.TP
|
.TP
|
||||||
|
.B E
|
||||||
|
If this rule matches,
|
||||||
|
\fIand the result matches a filename that can be transferred\fP,
|
||||||
|
end rule processing after executing the rule. If this is combined with
|
||||||
|
.BR r ,
|
||||||
|
then if the substitution does \fInot\fP result in a valid filename,
|
||||||
|
the substitution is undone. This cannot be combined with
|
||||||
|
.BR g ,
|
||||||
|
but \fIcan\fP be combined with
|
||||||
|
.BR gg .
|
||||||
|
.TP
|
||||||
.B s
|
.B s
|
||||||
If this rule matches, start rule processing over from the very first
|
If this rule matches, start rule processing over from the very first
|
||||||
rule after executing this rule.
|
rule after executing this rule.
|
||||||
|
|
@ -262,16 +321,22 @@ This rule applies to GET (RRQ) requests only.
|
||||||
.B P
|
.B P
|
||||||
This rule applies to PUT (WRQ) requests only.
|
This rule applies to PUT (WRQ) requests only.
|
||||||
.TP
|
.TP
|
||||||
|
.B 4
|
||||||
|
This rule applies to IPv4 sessions only.
|
||||||
|
.TP
|
||||||
|
.B 6
|
||||||
|
This rule applies to IPv6 sessions only.
|
||||||
|
.TP
|
||||||
.B ~
|
.B ~
|
||||||
Inverse the sense of this rule, i.e. execute the
|
Inverse the sense of this rule, i.e. execute the
|
||||||
.I operation
|
.I operation
|
||||||
only if the
|
only if the
|
||||||
.I regex
|
.I regex
|
||||||
.I doesn't
|
.I doesn't
|
||||||
match. Cannot used together with
|
match. Cannot used together with
|
||||||
.BR r .
|
.BR r .
|
||||||
.PP
|
.PP
|
||||||
The following escape sequences are recognized as part of the
|
The following escape sequences are recognized as part of a
|
||||||
.IR "replacement pattern" :
|
.IR "replacement pattern" :
|
||||||
.TP
|
.TP
|
||||||
\fB\\0\fP
|
\fB\\0\fP
|
||||||
|
|
@ -285,12 +350,14 @@ subexpressions, \\( ... \\), of the
|
||||||
pattern.
|
pattern.
|
||||||
.TP
|
.TP
|
||||||
\fB\\i\fP
|
\fB\\i\fP
|
||||||
The IP address of the requesting host, in dotted-quad notation
|
The IP address of the requesting host, in dotted-quad notation for
|
||||||
(e.g. 192.0.2.169).
|
IPv4 (e.g. 192.0.2.169) or conventional colon form for IPv6
|
||||||
|
(e.g. 2001:db8::1).
|
||||||
.TP
|
.TP
|
||||||
\fB\\x\fP
|
\fB\\x\fP
|
||||||
The IP address of the requesting host, in hexadecimal notation
|
The IP address of the requesting host, in expanded hexadecimal
|
||||||
(e.g. C00002A9).
|
notation (e.g. C00002A9 for IPv4, or 20010DB8000000000000000000000001
|
||||||
|
for IPv6).
|
||||||
.TP
|
.TP
|
||||||
\fB\\\\\fP
|
\fB\\\\\fP
|
||||||
Literal backslash.
|
Literal backslash.
|
||||||
|
|
@ -320,17 +387,17 @@ The use of TFTP services does not require an account or password on
|
||||||
the server system. Due to the lack of authentication information,
|
the server system. Due to the lack of authentication information,
|
||||||
.B tftpd
|
.B tftpd
|
||||||
will allow only publicly readable files (o+r) to be accessed, unless the
|
will allow only publicly readable files (o+r) to be accessed, unless the
|
||||||
.B \-p
|
.B \-\-permissive
|
||||||
option is specified. Files may be written only if they already exist
|
option is specified. Files may be written only if they already exist
|
||||||
and are publicly writable, unless the
|
and are publicly writable, unless the
|
||||||
.B \-c
|
.B \-\-create
|
||||||
option is specified. Note that this extends the concept of ``public''
|
option is specified. Note that this extends the concept of ``public''
|
||||||
to include all users on all hosts that can be reached through the
|
to include all users on all hosts that can be reached through the
|
||||||
network; this may not be appropriate on all systems, and its
|
network; this may not be appropriate on all systems, and its
|
||||||
implications should be considered before enabling TFTP service.
|
implications should be considered before enabling TFTP service.
|
||||||
Typically, some kind of firewall or packet-filter solution should be
|
Typically, some kind of firewall or packet-filter solution should be
|
||||||
employed. If appropriately compiled (see the output of
|
employed. If appropriately compiled (see the output of
|
||||||
.BR "in.tftpd \-V" )
|
.BR "in.tftpd \-\-version" )
|
||||||
.B tftpd
|
.B tftpd
|
||||||
will query the
|
will query the
|
||||||
.BR hosts_access (5)
|
.BR hosts_access (5)
|
||||||
|
|
@ -340,7 +407,7 @@ and rely on firewalling or kernel-based packet filters instead.
|
||||||
.PP
|
.PP
|
||||||
The server should be set to run as the user with the lowest possible
|
The server should be set to run as the user with the lowest possible
|
||||||
privilege; please see the
|
privilege; please see the
|
||||||
.B \-u
|
.B \-\-user
|
||||||
flag. It is probably a good idea to set up a specific user account for
|
flag. It is probably a good idea to set up a specific user account for
|
||||||
.BR tftpd ,
|
.BR tftpd ,
|
||||||
rather than letting it run as "nobody", to guard against privilege
|
rather than letting it run as "nobody", to guard against privilege
|
||||||
|
|
@ -350,14 +417,14 @@ Access to files can, and should, be restricted by invoking
|
||||||
.B tftpd
|
.B tftpd
|
||||||
with a list of directories by including pathnames as server program
|
with a list of directories by including pathnames as server program
|
||||||
arguments on the command line. In this case access is restricted to
|
arguments on the command line. In this case access is restricted to
|
||||||
files whole names are prefixed by one of the given directories. If
|
files whose names are prefixed by one of the given directories. If
|
||||||
possible, it is recommended that the
|
possible, it is recommended that the
|
||||||
.B \-s
|
.B \-\-secure
|
||||||
flag is used to set up a chroot() environment for the server to run in
|
flag is used to set up a chroot() environment for the server to run in
|
||||||
once a connection has been set up.
|
once a connection has been set up.
|
||||||
.PP
|
.PP
|
||||||
Finally, the filename remapping
|
Finally, the filename remapping
|
||||||
.RB ( \-m
|
.RB ( \-\-map-file
|
||||||
flag) support can be used to provide a limited amount of additional
|
flag) support can be used to provide a limited amount of additional
|
||||||
access control.
|
access control.
|
||||||
.SH "CONFORMING TO"
|
.SH "CONFORMING TO"
|
||||||
|
|
|
||||||
2725
tftpd/tftpd.c
2725
tftpd/tftpd.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,5 @@
|
||||||
/* $Id$ */
|
|
||||||
/* ----------------------------------------------------------------------- *
|
/* ----------------------------------------------------------------------- *
|
||||||
*
|
*
|
||||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software available under the same license
|
* This program is free software available under the same license
|
||||||
|
|
@ -24,4 +23,13 @@ char *tfstrdup(const char *);
|
||||||
|
|
||||||
extern int verbosity;
|
extern int verbosity;
|
||||||
|
|
||||||
|
struct formats {
|
||||||
|
const char *f_mode;
|
||||||
|
char *(*f_rewrite) (const struct formats *, char *, int, int, const char **);
|
||||||
|
int (*f_validate) (char *, int, const struct formats *, const char **);
|
||||||
|
void (*f_send) (const struct formats *, struct tftphdr *, int);
|
||||||
|
void (*f_recv) (const struct formats *, struct tftphdr *, int);
|
||||||
|
int f_convert;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
2
version
2
version
|
|
@ -1 +1 @@
|
||||||
0.39
|
5.3
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue