forked from mirrors/tftp-hpa-google
Support running without inetd.
This commit is contained in:
parent
5ed924bce2
commit
8c3d63fba8
3 changed files with 167 additions and 31 deletions
6
README
6
README
|
@ -1,4 +1,4 @@
|
||||||
This is tftp-hpa-0.19; this version was put out by H. Peter Anvin
|
This is tftp-hpa-0.21; this version was put out by H. Peter Anvin
|
||||||
<hpa@zytor.com>.
|
<hpa@zytor.com>.
|
||||||
|
|
||||||
The latest version of this collection can be found at:
|
The latest version of this collection can be found at:
|
||||||
|
@ -18,6 +18,10 @@ improvements.
|
||||||
===> IMPORTANT: SEE THE FILE "README.security" FOR IMPORTANT SECURITY
|
===> IMPORTANT: SEE THE FILE "README.security" FOR IMPORTANT SECURITY
|
||||||
===> CHANGES ENACTED IN VERSION 0.17!!!!!!!!!
|
===> CHANGES ENACTED IN VERSION 0.17!!!!!!!!!
|
||||||
|
|
||||||
|
Changes in 0.21:
|
||||||
|
Support running in standalone mode, without inetd.
|
||||||
|
|
||||||
|
|
||||||
Changes in 0.20:
|
Changes in 0.20:
|
||||||
Portability improvements. Now known to compile and run on
|
Portability improvements. Now known to compile and run on
|
||||||
Solaris 8.
|
Solaris 8.
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
.\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91
|
.\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91
|
||||||
.\" $OpenBSD: tftpd.8,v 1.7 1999/07/09 13:35:51 aaron Exp $
|
.\" $OpenBSD: tftpd.8,v 1.7 1999/07/09 13:35:51 aaron Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd July 10, 2001
|
.Dd August 6, 2001
|
||||||
.Dt TFTPD 8
|
.Dt TFTPD 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -46,8 +46,11 @@ IPv4 Trivial File Transfer Protocol server
|
||||||
.Nm in.tftpd
|
.Nm in.tftpd
|
||||||
.Op Fl v
|
.Op Fl v
|
||||||
.Op Fl c
|
.Op Fl c
|
||||||
|
.Op Fl l
|
||||||
|
.Op Fl a Ar [address][:port]
|
||||||
.Op Fl m Ar mapfile
|
.Op Fl m Ar mapfile
|
||||||
.Op Fl u Ar userid
|
.Op Fl u Ar userid
|
||||||
|
.Op Fl t Ar timeout
|
||||||
.Op Fl r Ar option...
|
.Op Fl r Ar option...
|
||||||
.Op Fl s
|
.Op Fl s
|
||||||
.Op Ar directory
|
.Op Ar directory
|
||||||
|
@ -66,7 +69,8 @@ service description;
|
||||||
see
|
see
|
||||||
.Xr services 5 .
|
.Xr services 5 .
|
||||||
The server is normally started by
|
The server is normally started by
|
||||||
.Xr inetd 8 .
|
.Xr inetd 8 ,
|
||||||
|
but can also run standalone.
|
||||||
.Pp
|
.Pp
|
||||||
The use of
|
The use of
|
||||||
.Xr tftp 1
|
.Xr tftp 1
|
||||||
|
@ -91,9 +95,20 @@ Access to files may be restricted by invoking
|
||||||
.Nm
|
.Nm
|
||||||
with a list of directories by including pathnames
|
with a list of directories by including pathnames
|
||||||
as server program arguments in
|
as server program arguments in
|
||||||
.Pa /etc/inetd.conf .
|
.Pa /etc/inetd.conf
|
||||||
In this case access is restricted to files whose
|
or on the standalone server command line. In this case access is
|
||||||
names are prefixed by the one of the given directories.
|
restricted to files whose names are prefixed by the one of the given
|
||||||
|
directories.
|
||||||
|
.Pp
|
||||||
|
If the
|
||||||
|
.Fl l
|
||||||
|
flag is used, the server runs in standalone (listen) mode. In listen
|
||||||
|
mode, the
|
||||||
|
.Fl t
|
||||||
|
option is ignored, and the
|
||||||
|
.Fl a
|
||||||
|
option can be used to specify a specific local address or port to
|
||||||
|
listen to.
|
||||||
.Pp
|
.Pp
|
||||||
If the
|
If the
|
||||||
.Fl c
|
.Fl c
|
||||||
|
@ -116,11 +131,15 @@ which do not include a directory name.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fl u
|
.Fl u
|
||||||
flag can be used to specify a user ID which
|
option can be used to specify a user ID which
|
||||||
.Nm
|
.Nm
|
||||||
will run as; the default is ``nobody''.
|
will run as; the default is ``nobody''.
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
|
.Fl t
|
||||||
|
option specifies the server timeout in inetd mode.
|
||||||
|
.Pp
|
||||||
|
The
|
||||||
.Fl m
|
.Fl m
|
||||||
flag specifies a file which contains filename remapping rules.
|
flag specifies a file which contains filename remapping rules.
|
||||||
.Pp
|
.Pp
|
||||||
|
|
161
tftpd/tftpd.c
161
tftpd/tftpd.c
|
@ -166,11 +166,31 @@ static void handle_sighup(int sig)
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Usage: %s [-vc][-m mappings][-u user][-t timeout][-r option...] [-s] [directory ...]",
|
syslog(LOG_ERR, "Usage: %s [-vcl][-a address][-m mappings][-u user][-t timeout][-r option...] [-s] [directory ...]",
|
||||||
__progname);
|
__progname);
|
||||||
exit(EX_USAGE);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_REGEX
|
||||||
|
static struct rule *
|
||||||
|
read_remap_rules(const char *file)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
struct rule *rulep;
|
||||||
|
|
||||||
|
f = fopen(file, "rt");
|
||||||
|
if ( !f ) {
|
||||||
|
syslog(LOG_ERR, "Cannot open map file: %s: %m", file);
|
||||||
|
exit(EX_NOINPUT);
|
||||||
|
}
|
||||||
|
rulep = parserulefile(f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return rulep;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -178,20 +198,24 @@ main(int argc, char **argv)
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
struct options *opt;
|
struct options *opt;
|
||||||
struct sockaddr_in myaddr;
|
struct sockaddr_in myaddr;
|
||||||
|
struct sockaddr_in bindaddr;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
int fd = 0;
|
int fd = 0;
|
||||||
|
int listen = 0; /* Standalone (listen) mode */
|
||||||
|
char *address = NULL; /* Address to listen to */
|
||||||
int pid;
|
int pid;
|
||||||
int c;
|
int c;
|
||||||
int setrv;
|
int setrv;
|
||||||
int timeout = 900; /* Default timeout */
|
int timeout = 900; /* Default timeout */
|
||||||
char *user = "nobody"; /* Default user */
|
char *user = "nobody"; /* Default user */
|
||||||
|
char *rewrite_file = NULL;
|
||||||
|
|
||||||
__progname = basename(argv[0]);
|
__progname = basename(argv[0]);
|
||||||
|
|
||||||
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "csvu:r:t:m:")) != -1)
|
while ((c = getopt(argc, argv, "csvla:u:r:t:m:")) != -1)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'c':
|
case 'c':
|
||||||
cancreate = 1;
|
cancreate = 1;
|
||||||
|
@ -199,6 +223,12 @@ main(int argc, char **argv)
|
||||||
case 's':
|
case 's':
|
||||||
secure = 1;
|
secure = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
listen = 1;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
address = optarg;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
timeout = atoi(optarg);
|
timeout = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -219,20 +249,11 @@ main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
#ifdef WITH_REGEX
|
#ifdef WITH_REGEX
|
||||||
case 'm':
|
case 'm':
|
||||||
{
|
if ( rewrite_file ) {
|
||||||
FILE *f;
|
syslog(LOG_ERR, "Multiple -m options");
|
||||||
if ( rewrite_rules ) {
|
exit(EX_USAGE);
|
||||||
syslog(LOG_ERR, "Multiple -m options");
|
|
||||||
exit(EX_USAGE);
|
|
||||||
}
|
|
||||||
f = fopen(optarg, "rt");
|
|
||||||
if ( !f ) {
|
|
||||||
syslog(LOG_ERR, "Cannot open map file: %s: %m", optarg);
|
|
||||||
exit(EX_NOINPUT);
|
|
||||||
}
|
|
||||||
rewrite_rules = parserulefile(f);
|
|
||||||
fclose(f);
|
|
||||||
}
|
}
|
||||||
|
rewrite_file = optarg;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -282,7 +303,74 @@ main(int argc, char **argv)
|
||||||
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
|
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( rewrite_file )
|
||||||
|
rewrite_rules = read_remap_rules(rewrite_file);
|
||||||
|
|
||||||
|
/* If we're running standalone, set up the input port */
|
||||||
|
if ( listen ) {
|
||||||
|
fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
memset(&bindaddr, 0, sizeof bindaddr);
|
||||||
|
bindaddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
bindaddr.sin_port = htons(IPPORT_TFTP);
|
||||||
|
|
||||||
|
if ( address ) {
|
||||||
|
char *portptr, *eportptr;
|
||||||
|
struct hostent *hostent;
|
||||||
|
struct servent *servent;
|
||||||
|
unsigned long port;
|
||||||
|
|
||||||
|
address = tfstrdup(address);
|
||||||
|
portptr = strrchr(address, ':');
|
||||||
|
if ( portptr )
|
||||||
|
*portptr++ = '\0';
|
||||||
|
|
||||||
|
if ( *address ) {
|
||||||
|
hostent = gethostbyname(address);
|
||||||
|
if ( !hostent || hostent->h_addrtype != AF_INET ) {
|
||||||
|
syslog(LOG_ERR, "cannot resolve local bind address: %s", address);
|
||||||
|
exit(EX_NOINPUT);
|
||||||
|
}
|
||||||
|
memcpy(&bindaddr.sin_addr, hostent->h_addr, hostent->h_length);
|
||||||
|
} else {
|
||||||
|
/* Default to using INADDR_ANY */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( portptr && *portptr ) {
|
||||||
|
servent = getservbyname(portptr, "udp");
|
||||||
|
if ( servent ) {
|
||||||
|
bindaddr.sin_port = servent->s_port;
|
||||||
|
} else if ( (port = strtoul(portptr, &eportptr, 0)) && !*eportptr ) {
|
||||||
|
bindaddr.sin_port = htons(port);
|
||||||
|
} else if ( !strcmp(portptr, "tftp") ) {
|
||||||
|
/* It's TFTP, we're OK */
|
||||||
|
} else {
|
||||||
|
syslog(LOG_ERR, "cannot resolve local bind port: %s", portptr);
|
||||||
|
exit(EX_NOINPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bind(fd, &bindaddr, sizeof bindaddr) ) {
|
||||||
|
syslog(LOG_ERR, "cannot bind to local socket: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Daemonize this process */
|
||||||
|
{
|
||||||
|
int f = fork();
|
||||||
|
if ( f > 0 )
|
||||||
|
exit(0);
|
||||||
|
if ( f < 0 ) {
|
||||||
|
syslog(LOG_ERR, "cannot fork: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
close(0); close(1); close(2);
|
||||||
|
setsid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* This means we don't want to wait() for children */
|
/* This means we don't want to wait() for children */
|
||||||
set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP);
|
set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP);
|
||||||
|
|
||||||
|
@ -296,25 +384,48 @@ main(int argc, char **argv)
|
||||||
struct timeval tv_timeout;
|
struct timeval tv_timeout;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
if ( caught_sighup ) {
|
||||||
|
caught_sighup = 0;
|
||||||
|
if ( listen ) {
|
||||||
|
#ifdef HAVE_REGEX
|
||||||
|
/* This is unfortunately a memory leak. Hopefully
|
||||||
|
SIGHUPs aren't too common. */
|
||||||
|
if ( rewrite_file )
|
||||||
|
rewrite_rules = read_remap_rules(rewrite_file);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
/* Return to inetd for respawn */
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FD_ZERO(&readset);
|
FD_ZERO(&readset);
|
||||||
FD_SET(fd, &readset);
|
FD_SET(fd, &readset);
|
||||||
tv_timeout.tv_sec = timeout;
|
tv_timeout.tv_sec = timeout;
|
||||||
tv_timeout.tv_usec = 0;
|
tv_timeout.tv_usec = 0;
|
||||||
|
|
||||||
if ( caught_sighup )
|
/* Never time out if we're in listen mode */
|
||||||
exit(0); /* Return to inetd for respawn */
|
rv = select(fd+1, &readset, NULL, NULL, listen ? NULL : &tv_timeout);
|
||||||
|
|
||||||
rv = select(fd+1, &readset, NULL, NULL, &tv_timeout);
|
|
||||||
if ( rv == -1 && errno == EINTR )
|
if ( rv == -1 && errno == EINTR )
|
||||||
continue; /* Signal caught, reloop */
|
continue; /* Signal caught, reloop */
|
||||||
if ( rv <= 0 )
|
if ( rv == -1 ) {
|
||||||
exit(0); /* Timeout or error, return to inetd */
|
syslog(LOG_ERR, "select loop: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
} else if ( rv == 0 ) {
|
||||||
|
exit(0); /* Timeout, return to inetd */
|
||||||
|
}
|
||||||
|
|
||||||
fromlen = sizeof (from);
|
fromlen = sizeof (from);
|
||||||
n = myrecvfrom(fd, buf, sizeof (buf), 0,
|
n = myrecvfrom(fd, buf, sizeof (buf), 0,
|
||||||
(struct sockaddr *)&from, &fromlen,
|
(struct sockaddr *)&from, &fromlen,
|
||||||
&myaddr);
|
&myaddr);
|
||||||
|
|
||||||
|
if ( listen && myaddr.sin_addr.s_addr == INADDR_ANY ) {
|
||||||
|
/* myrecvfrom() didn't capture the source address; but we might
|
||||||
|
have bound to a specific address, if so we should use it */
|
||||||
|
memcpy(&myaddr.sin_addr, &bindaddr.sin_addr, sizeof bindaddr.sin_addr);
|
||||||
|
}
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
syslog(LOG_ERR, "recvfrom: %m");
|
syslog(LOG_ERR, "recvfrom: %m");
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR);
|
||||||
|
@ -386,7 +497,9 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
/* Close file descriptors we don't need */
|
/* Close file descriptors we don't need */
|
||||||
close(fd);
|
close(fd);
|
||||||
|
close(0);
|
||||||
close(1);
|
close(1);
|
||||||
|
close(2);
|
||||||
|
|
||||||
/* Other basic setup */
|
/* Other basic setup */
|
||||||
from.sin_family = AF_INET;
|
from.sin_family = AF_INET;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue