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>.
|
||||
|
||||
The latest version of this collection can be found at:
|
||||
|
@ -18,6 +18,10 @@ improvements.
|
|||
===> IMPORTANT: SEE THE FILE "README.security" FOR IMPORTANT SECURITY
|
||||
===> CHANGES ENACTED IN VERSION 0.17!!!!!!!!!
|
||||
|
||||
Changes in 0.21:
|
||||
Support running in standalone mode, without inetd.
|
||||
|
||||
|
||||
Changes in 0.20:
|
||||
Portability improvements. Now known to compile and run on
|
||||
Solaris 8.
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
.\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91
|
||||
.\" $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
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -46,8 +46,11 @@ IPv4 Trivial File Transfer Protocol server
|
|||
.Nm in.tftpd
|
||||
.Op Fl v
|
||||
.Op Fl c
|
||||
.Op Fl l
|
||||
.Op Fl a Ar [address][:port]
|
||||
.Op Fl m Ar mapfile
|
||||
.Op Fl u Ar userid
|
||||
.Op Fl t Ar timeout
|
||||
.Op Fl r Ar option...
|
||||
.Op Fl s
|
||||
.Op Ar directory
|
||||
|
@ -66,7 +69,8 @@ service description;
|
|||
see
|
||||
.Xr services 5 .
|
||||
The server is normally started by
|
||||
.Xr inetd 8 .
|
||||
.Xr inetd 8 ,
|
||||
but can also run standalone.
|
||||
.Pp
|
||||
The use of
|
||||
.Xr tftp 1
|
||||
|
@ -91,9 +95,20 @@ Access to files may be restricted by invoking
|
|||
.Nm
|
||||
with a list of directories by including pathnames
|
||||
as server program arguments in
|
||||
.Pa /etc/inetd.conf .
|
||||
In this case access is restricted to files whose
|
||||
names are prefixed by the one of the given directories.
|
||||
.Pa /etc/inetd.conf
|
||||
or on the standalone server command line. In this case access is
|
||||
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
|
||||
If the
|
||||
.Fl c
|
||||
|
@ -116,11 +131,15 @@ which do not include a directory name.
|
|||
.Pp
|
||||
The
|
||||
.Fl u
|
||||
flag can be used to specify a user ID which
|
||||
option can be used to specify a user ID which
|
||||
.Nm
|
||||
will run as; the default is ``nobody''.
|
||||
.Pp
|
||||
The
|
||||
.Fl t
|
||||
option specifies the server timeout in inetd mode.
|
||||
.Pp
|
||||
The
|
||||
.Fl m
|
||||
flag specifies a file which contains filename remapping rules.
|
||||
.Pp
|
||||
|
|
157
tftpd/tftpd.c
157
tftpd/tftpd.c
|
@ -166,11 +166,31 @@ static void handle_sighup(int sig)
|
|||
static 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);
|
||||
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
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
@ -178,20 +198,24 @@ main(int argc, char **argv)
|
|||
struct passwd *pw;
|
||||
struct options *opt;
|
||||
struct sockaddr_in myaddr;
|
||||
struct sockaddr_in bindaddr;
|
||||
int n = 0;
|
||||
int on = 1;
|
||||
int fd = 0;
|
||||
int listen = 0; /* Standalone (listen) mode */
|
||||
char *address = NULL; /* Address to listen to */
|
||||
int pid;
|
||||
int c;
|
||||
int setrv;
|
||||
int timeout = 900; /* Default timeout */
|
||||
int timeout = 900; /* Default timeout */
|
||||
char *user = "nobody"; /* Default user */
|
||||
char *rewrite_file = NULL;
|
||||
|
||||
__progname = basename(argv[0]);
|
||||
|
||||
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) {
|
||||
case 'c':
|
||||
cancreate = 1;
|
||||
|
@ -199,6 +223,12 @@ main(int argc, char **argv)
|
|||
case 's':
|
||||
secure = 1;
|
||||
break;
|
||||
case 'l':
|
||||
listen = 1;
|
||||
break;
|
||||
case 'a':
|
||||
address = optarg;
|
||||
break;
|
||||
case 't':
|
||||
timeout = atoi(optarg);
|
||||
break;
|
||||
|
@ -219,20 +249,11 @@ main(int argc, char **argv)
|
|||
break;
|
||||
#ifdef WITH_REGEX
|
||||
case 'm':
|
||||
{
|
||||
FILE *f;
|
||||
if ( rewrite_rules ) {
|
||||
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);
|
||||
if ( rewrite_file ) {
|
||||
syslog(LOG_ERR, "Multiple -m options");
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
rewrite_file = optarg;
|
||||
break;
|
||||
#endif
|
||||
case 'v':
|
||||
|
@ -283,6 +304,73 @@ main(int argc, char **argv)
|
|||
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 */
|
||||
set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP);
|
||||
|
||||
|
@ -296,25 +384,48 @@ main(int argc, char **argv)
|
|||
struct timeval tv_timeout;
|
||||
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_SET(fd, &readset);
|
||||
tv_timeout.tv_sec = timeout;
|
||||
tv_timeout.tv_usec = 0;
|
||||
|
||||
if ( caught_sighup )
|
||||
exit(0); /* Return to inetd for respawn */
|
||||
|
||||
rv = select(fd+1, &readset, NULL, NULL, &tv_timeout);
|
||||
/* Never time out if we're in listen mode */
|
||||
rv = select(fd+1, &readset, NULL, NULL, listen ? NULL : &tv_timeout);
|
||||
if ( rv == -1 && errno == EINTR )
|
||||
continue; /* Signal caught, reloop */
|
||||
if ( rv <= 0 )
|
||||
exit(0); /* Timeout or error, return to inetd */
|
||||
if ( rv == -1 ) {
|
||||
syslog(LOG_ERR, "select loop: %m");
|
||||
exit(EX_OSERR);
|
||||
} else if ( rv == 0 ) {
|
||||
exit(0); /* Timeout, return to inetd */
|
||||
}
|
||||
|
||||
fromlen = sizeof (from);
|
||||
n = myrecvfrom(fd, buf, sizeof (buf), 0,
|
||||
(struct sockaddr *)&from, &fromlen,
|
||||
&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) {
|
||||
syslog(LOG_ERR, "recvfrom: %m");
|
||||
exit(EX_IOERR);
|
||||
|
@ -386,7 +497,9 @@ main(int argc, char **argv)
|
|||
|
||||
/* Close file descriptors we don't need */
|
||||
close(fd);
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
/* Other basic setup */
|
||||
from.sin_family = AF_INET;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue