/* $OpenBSD: tftpd.c,v 1.13 1999/06/23 17:01:36 deraadt Exp $ */
/*
* Copyright (c) 1983 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 "config.h" /* Must be included first */
#include "tftpd.h"
#ifndef lint
static const char *copyright UNUSED =
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
All rights reserved.\n";
/*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/
/*static char rcsid[] = "$OpenBSD: tftpd.c,v 1.13 1999/06/23 17:01:36 deraadt Exp $: tftpd.c,v 1.6 1997/02/16 23:49:21 deraadt Exp $";*/
static const char *rcsid UNUSED =
"tftp-hpa $Id$";
#endif /* not lint */
/*
* Trivial file transfer protocol server.
*
* This version includes many modifications by Jim Guyton <guyton@rand-unix>
*/
#include <sys/ioctl.h>
#include <signal.h>
#include <netdb.h>
#include <ctype.h>
#include <pwd.h>
#include <limits.h>
#include <syslog.h>
#include "common/tftpsubs.h"
#include "recvfrom.h"
#include "remap.h"
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h> /* Necessary for FIONBIO on Solaris */
#endif
#ifdef HAVE_TCPWRAPPERS
#include <tcpd.h>
int deny_severity = LOG_WARNING;
int allow_severity = -1; /* Don't log at all */
struct request_info wrap_request;
#endif
#define TIMEOUT 1000000 /* Default timeout (us) */
#define TRIES 6 /* Number of attempts to send each packet */
#define TIMEOUT_LIMIT ((1 << TRIES)-1)
const char *__progname;
int peer;
unsigned long timeout = TIMEOUT; /* Current timeout value */
unsigned long rexmtval = TIMEOUT; /* Basic timeout value */
unsigned long maxtimeout = TIMEOUT_LIMIT*TIMEOUT;
int timeout_quit = 0;
sigjmp_buf timeoutbuf;
#define PKTSIZE MAX_SEGSIZE+4
char buf[PKTSIZE];
char ackbuf[PKTSIZE];
unsigned int max_blksize = MAX_SEGSIZE;
struct sockaddr_in from;
socklen_t fromlen;
off_t tsize;
int tsize_ok;
int ndirs;
const char **dirs;
int secure = 0;
int cancreate = 0;
int unixperms = 0;
int portrange = 0;
unsigned int portrange_from, portrange_to;
int verbosity = 0;
struct formats;
#ifdef WITH_REGEX
static struct rule *rewrite_rules = NULL;
#endif
int tftp(struct tftphdr *, int);
static void nak(int, const char *);
void timer(int);
void justquit(int);
void do_opt(char *, char *, char **);
int set_blksize(char *, char **);
int set_blksize2(char *, char **);
int set_tsize(char *, char **);
int set_timeout(char *, char **);
int set_utimeout(char *, char **);
struct options {
const char *o_opt;
int (*o_fnc)(char *, char **);
} options[] = {
{ "blksize", set_blksize },
{ "blksize2", set_blksize2 },
{ "tsize", set_tsize },
{ "timeout", set_timeout },
{ "utimeout", set_utimeout },
{ NULL, NULL }
};
/* Simple handler for SIGHUP */
static volatile sig_atomic_t caught_sighup = 0;
static void handle_sighup(int sig)
{
(void)sig; /* Suppress unused warning */
caught_sighup = 1;
}
/* Handle timeout signal or timeout event */
void
timer(int sig)
{
(void)sig; /* Suppress unused warning */
timeout <<= 1;
if (timeout >= maxtimeout || timeout_quit)
exit(0);
siglongjmp(timeoutbuf, 1);
}
static void
usage(void)
{
syslog(LOG_ERR, "Usage: %s [-vcl][-a address][-m mappings][-u user][-t inetd_timeout][-T pkt_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
static void
set_socket_nonblock(int fd, int flag)
{
int err;
int flags;
#if defined(HAVE_FCNTL) && defined(HAVE_O_NONBLOCK_DEFINITION)
/* Posixly correct */
err = ((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
(fcntl(fd, F_SETFL, flag ? flags|O_NONBLOCK : flags&~O_NONBLOCK) < 0);
#else
flags = flag ? 1 : 0;
err = (ioctl(fd, FIONBIO, &flags) < 0);
#endif
if ( err ) {
syslog(LOG_ERR, "Cannot set nonblock flag on socket: %m");
exit(EX_OSERR);
}
}
static void
pmtu_discovery_off(int fd)
{
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
int pmtu = IP_PMTUDISC_DONT;
setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu));
#endif
}
/*
* Receive packet with synchronous timeout; timeout is adjusted
* to account for time spent waiting.
*/
static int recv_time(int s, void *rbuf, int len, unsigned int flags,
unsigned long *timeout_us_p)
{
fd_set fdset;
struct timeval tmv, t0, t1;
int rv, err;
unsigned long timeout_us = *timeout_us_p;
unsigned long timeout_left, dt;
gettimeofday(&t0, NULL);
timeout_left = timeout_us;
for ( ; ; ) {
FD_ZERO(&fdset);
FD_SET(s, &fdset);
do {
tmv.tv_sec = timeout_left / 1000000;
tmv.tv_usec = timeout_left % 1000000;
rv = select(s+1, &fdset, NULL, NULL, &tmv);
err = errno;
gettimeofday(&t1, NULL);
dt = (t1.tv_sec - t0.tv_sec)*1000000 + (t1.tv_usec - t0.tv_usec);
*timeout_us_p = timeout_left = ( dt >= timeout_us ) ? 1 : (timeout_us - dt);
} while ( rv == -1 && err == EINTR );
if ( rv == 0 ) {
timer(0); /* Should not return */
return -1;
}
set_socket_nonblock(s, 1);
rv = recv(s, rbuf, len, flags);
err = errno;
set_socket_nonblock(s, 0);
if ( rv < 0 ) {
if ( E_WOULD_BLOCK(err) || err == EINTR ) {
continue; /* Once again, with feeling... */
} else {
errno = err;
return rv;
}
} else {
return rv;
}
}
}
int
main(int argc, char **argv)
{
struct tftphdr *tp;
struct passwd *pw;
struct options *opt;
struct sockaddr_in myaddr;
struct sockaddr_in bindaddr;
int n;
int fd = 0;
int standalone = 0; /* Standalone (listen) mode */
int nodaemon = 0; /* Do not detach process */
char *address = NULL; /* Address to listen to */
pid_t pid;
mode_t my_umask = 0;
int spec_umask = 0;
int c;
int setrv;
int waittime = 900; /* Default time to wait for a connect*/
const char *user = "nobody"; /* Default user */
char *p, *ep;
#ifdef WITH_REGEX
char *rewrite_file = NULL;
#en
- 1
- 2
前往页