Document new options and new configuration setup.

This commit is contained in:
hpa 2001-04-23 22:50:47 +00:00
parent c9f28745f5
commit 4d0dd611ae
4 changed files with 136 additions and 79 deletions

View file

@ -1,3 +1,4 @@
.\" tftp-hpa: $Id$
.\" $OpenBSD: tftpd.8,v 1.7 1999/07/09 13:35:51 aaron Exp $
.\"
.\" Copyright (c) 1983, 1991 The Regents of the University of California.
@ -34,18 +35,19 @@
.\" 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 9, 2000
.Dd Apr 23, 2001
.Dt TFTPD 8
.Os
.Sh NAME
.Nm tftpd
.Nd
.Tn DARPA
Trivial File Transfer Protocol server
IPv4 Trivial File Transfer Protocol server
.Sh SYNOPSIS
.Nm tftpd
.Op Fl cs
.Nm in.tftpd
.Op Fl c
.Op Fl u Ar userid
.Op Fl r Ar option...
.Op Fl s
.Op Ar directory
.Sh DESCRIPTION
.Nm
@ -78,7 +80,10 @@ to include
all users on all hosts that can be reached through the network;
this may not be appropriate on all systems, and its implications
should be considered before enabling tftp service.
The server should have the user ID with the lowest possible privilege.
The server should have the user ID with the lowest possible privilege
(see the
.Fl u
flag below.)
.Pp
Access to files may be restricted by invoking
.Nm
@ -102,9 +107,16 @@ flag with a directory name,
.Nm
will
.Xr chroot 2
on startup; therefore the remote host is not expected to pass the directory
as part of the file name to transfer. This option is intended primarily for
compatibility with SunOS boot ROMs which do not include a directory name.
on startup; therefore the remote host is not expected to pass the
directory as part of the file name to transfer. This option is
recommended for security, as well as compatibility with boot ROMs
which do not include a directory name.
.Pp
The
.Fl u
flag can be used to specify a user ID which
.Nm
will run as; the default is ``nobody''.
.Pp
This version of
.Nm
@ -139,3 +151,7 @@ The
.Fl r
flag and RFC 2347 options were added by H. Peter Anvin based on
patches by Markus Gutschke and Gero Kulhman.
.Pp
The
.Fl u
flag was added by H. Peter Anvin.

View file

@ -53,6 +53,7 @@ static const char *rcsid = "tftp-hpa $Id$";
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
@ -154,7 +155,7 @@ struct options {
static void
usage(void)
{
syslog(LOG_ERR, "Usage: %s [-c] [-u user] [-r option...] [-s] [directory ...]",
syslog(LOG_ERR, "Usage: %s [-c] [-u user] [-t timeout] [-r option...] [-s] [directory ...]",
__progname);
exit(1);
}
@ -170,16 +171,16 @@ main(int argc, char **argv)
int on = 1;
int fd = 0;
int pid;
int i, j;
int c;
int setrv;
int timeout = 900; /* Default timeout */
char *user = "nobody"; /* Default user */
__progname = basename(argv[0]);
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
while ((c = getopt(argc, argv, "csu:r:")) != -1)
while ((c = getopt(argc, argv, "csu:r:t:")) != -1)
switch (c) {
case 'c':
cancreate = 1;
@ -187,6 +188,9 @@ main(int argc, char **argv)
case 's':
secure = 1;
break;
case 't':
timeout = atoi(optarg);
break;
case 'u':
user = optarg;
break;
@ -248,37 +252,69 @@ main(int argc, char **argv)
exit(1);
}
fromlen = sizeof (from);
n = myrecvfrom(fd, buf, sizeof (buf), 0,
(struct sockaddr *)&from, &fromlen,
&myaddr);
if (n < 0) {
syslog(LOG_ERR, "recvfrom: %m");
exit(1);
}
/* This means we don't want to wait() for children */
bsd_signal(SIGCHLD, SIG_IGN);
do {
fd_set readset;
struct timeval tv_timeout;
FD_ZERO(&readset);
FD_SET(fd, &readset);
tv_timeout.tv_sec = timeout;
tv_timeout.tv_usec = 0;
if ( select(fd+1, &readset, NULL, NULL, &tv_timeout) == 0 )
exit(0); /* Timeout, return to inetd */
fromlen = sizeof (from);
n = myrecvfrom(fd, buf, sizeof (buf), 0,
(struct sockaddr *)&from, &fromlen,
&myaddr);
if (n < 0) {
syslog(LOG_ERR, "recvfrom: %m");
exit(1);
}
#ifdef HAVE_TCPWRAPPERS
/* Verify if this was a legal request for us. This has to be
done before the chroot, while /etc is still accessible. */
request_init(&wrap_request,
RQ_DAEMON, __progname,
RQ_FILE, fd,
RQ_CLIENT_SIN, &from,
RQ_SERVER_SIN, &myaddr,
0);
sock_methods(&wrap_request);
if ( hosts_access(&wrap_request) == 0 ) {
if ( deny_severity != -1 )
syslog(deny_severity, "connection refused from %s",
request_init(&wrap_request,
RQ_DAEMON, __progname,
RQ_FILE, fd,
RQ_CLIENT_SIN, &from,
RQ_SERVER_SIN, &myaddr,
0);
sock_methods(&wrap_request);
if ( hosts_access(&wrap_request) == 0 ) {
if ( deny_severity != -1 )
syslog(deny_severity, "connection refused from %s",
inet_ntoa(from.sin_addr));
exit(1); /* Access denied */
} else if ( allow_severity != -1 ) {
syslog(allow_severity, "connect from %s",
inet_ntoa(from.sin_addr));
exit(1); /* Access denied */
} else if ( allow_severity != -1 ) {
syslog(allow_severity, "connect from %s",
inet_ntoa(from.sin_addr));
}
}
#endif
/* Drop privileges */
/*
* Now that we have read the message out of the UDP
* socket, we fork and go back to listening to the
* socket.
*/
pid = fork();
if (pid < 0) {
syslog(LOG_ERR, "fork: %m");
exit(1); /* Return to inetd, just in case */
}
} while ( pid > 0 ); /* Parent process continues... */
/* Child process: handle the actual request here */
/* Chroot and drop privileges */
if (secure && chroot(".")) {
syslog(LOG_ERR, "chroot: %m");
exit(1);
@ -303,55 +339,15 @@ main(int argc, char **argv)
exit(1);
}
/*
* Now that we have read the message out of the UDP
* socket, we fork and exit. Thus, inetd will go back
* to listening to the tftp port, and the next request
* to come in will start up a new instance of tftpd.
*
* We do this so that inetd can run tftpd in "wait" mode.
* The problem with tftpd running in "nowait" mode is that
* inetd may get one or more successful "selects" on the
* tftp port before we do our receive, so more than one
* instance of tftpd may be started up. Worse, if tftpd
* break before doing the above "recvfrom", inetd would
* spawn endless instances, clogging the system.
*/
for (i = 1; i < 20; i++) {
pid = fork();
if (pid < 0) {
sleep(i);
/*
* flush out to most recently sent request.
*
* This may drop some request, but those
* will be resent by the clients when
* they timeout. The positive effect of
* this flush is to (try to) prevent more
* than one tftpd being started up to service
* a single request from a single client.
*/
j = sizeof from;
i = myrecvfrom(fd, buf, sizeof (buf), 0,
(struct sockaddr *)&from, &j, &myaddr);
if (i > 0) {
n = i;
fromlen = j;
}
} else
break;
}
if (pid < 0) {
syslog(LOG_ERR, "fork: %m");
exit(1);
} else if (pid != 0)
exit(0);
/* Close file descriptors we don't need */
from.sin_family = AF_INET;
alarm(0);
close(fd);
close(1);
/* Process the request... */
peer = socket(AF_INET, SOCK_DGRAM, 0);
if (peer < 0) {
syslog(LOG_ERR, "socket: %m");