WARNS?=1. merge lite-2.
This commit is contained in:
parent
7bcd5087e9
commit
60cef5019e
|
@ -1,9 +1,10 @@
|
|||
# from: @(#)Makefile 5.10 (Berkeley) 5/11/90
|
||||
# $Id: Makefile,v 1.3 1994/12/22 10:28:22 cgd Exp $
|
||||
# $NetBSD: Makefile,v 1.4 1997/10/07 09:46:45 mrg Exp $
|
||||
# from: @(#)Makefile 8.1 (Berkeley) 6/4/93
|
||||
|
||||
PROG= tftpd
|
||||
SRCS= tftpd.c tftpsubs.c
|
||||
MAN= tftpd.8
|
||||
CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp
|
||||
.PATH: ${.CURDIR}/../../usr.bin/tftp
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
.\" Copyright (c) 1983, 1991 The Regents of the University of California.
|
||||
.\" All rights reserved.
|
||||
.\" $NetBSD: tftpd.8,v 1.4 1997/10/07 09:46:46 mrg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1983, 1991, 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
|
||||
|
@ -29,23 +31,22 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" from: @(#)tftpd.8 6.7 (Berkeley) 5/13/91
|
||||
.\" $Id: tftpd.8,v 1.3 1994/01/10 16:29:46 mycroft Exp $
|
||||
.\"
|
||||
.Dd May 13, 1991
|
||||
.\" from: @(#)tftpd.8 8.1 (Berkeley) 6/4/93
|
||||
.\"
|
||||
.Dd June 4, 1993
|
||||
.Dt TFTPD 8
|
||||
.Os BSD 4.2
|
||||
.Sh NAME
|
||||
.Nm tftpd
|
||||
.Nd
|
||||
.Tn DARPA
|
||||
Trivial File Transfer Protocol server
|
||||
Internet Trivial File Transfer Protocol server
|
||||
.Sh SYNOPSIS
|
||||
.Nm tftpd
|
||||
.Op Fl s Ar directory
|
||||
.Op Fl l
|
||||
.Op Fl n
|
||||
.Op Ar directory ...
|
||||
.Nm tftpd
|
||||
.Fl s
|
||||
.Op Ar directory
|
||||
.Sh DESCRIPTION
|
||||
.Nm Tftpd
|
||||
is a server which supports the
|
||||
|
@ -70,6 +71,7 @@ Due to the lack of authentication information,
|
|||
.Nm tftpd
|
||||
will allow only publicly readable files to be
|
||||
accessed.
|
||||
Files containing the string ``/\|\fB.\|.\fP\|/'' are not allowed.
|
||||
Files may be written only if they already exist and are publicly writable.
|
||||
Note that this extends the concept of
|
||||
.Dq public
|
||||
|
@ -81,19 +83,31 @@ The server should have the user ID with the lowest possible privilege.
|
|||
.Pp
|
||||
Access to files may be restricted by invoking
|
||||
.Nm tftpd
|
||||
with a list of directories by including pathnames
|
||||
with a list of directories by including up to 20 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.
|
||||
The given directories are also treated as a search path for
|
||||
relative filename requests.
|
||||
.Pp
|
||||
When using the
|
||||
.Fl s
|
||||
flag with a directory name, tftpd will
|
||||
The options are:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl l
|
||||
Logs all requests using
|
||||
.Xr syslog 3 .
|
||||
.It Fl n
|
||||
Suppresses negative acknowledgement of requests for nonexistent
|
||||
relative filenames.
|
||||
.It Fl s
|
||||
.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.
|
||||
.El
|
||||
.Pp
|
||||
.Sh SEE ALSO
|
||||
.Xr tftp 1 ,
|
||||
.Xr inetd 8
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* $NetBSD: tftpd.c,v 1.9 1997/10/07 09:46:47 mrg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* 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
|
||||
|
@ -31,41 +33,49 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
char copyright[] =
|
||||
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
|
||||
All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
/*static char sccsid[] = "from: @(#)tftpd.c 5.13 (Berkeley) 2/26/91";*/
|
||||
static char rcsid[] = "$Id: tftpd.c,v 1.8 1997/04/22 10:33:07 mrg Exp $";
|
||||
__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n");
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: tftpd.c,v 1.9 1997/10/07 09:46:47 mrg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Trivial file transfer protocol server.
|
||||
*
|
||||
* This version includes many modifications by Jim Guyton <guyton@rand-unix>
|
||||
* This version includes many modifications by Jim Guyton
|
||||
* <guyton@rand-unix>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/tftp.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tftpsubs.h"
|
||||
|
||||
/* XXX svr4 defines UID_NOBODY and GID_NOBODY constants in <sys/param.h> */
|
||||
#define UID_NOBODY 32767
|
||||
|
@ -73,9 +83,7 @@ static char rcsid[] = "$Id: tftpd.c,v 1.8 1997/04/22 10:33:07 mrg Exp $";
|
|||
|
||||
#define TIMEOUT 5
|
||||
|
||||
extern int errno;
|
||||
extern char *__progname;
|
||||
struct sockaddr_in s_in = { AF_INET };
|
||||
int peer;
|
||||
int rexmtval = TIMEOUT;
|
||||
int maxtimeout = 5*TIMEOUT;
|
||||
|
@ -86,10 +94,51 @@ char ackbuf[PKTSIZE];
|
|||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
|
||||
#define MAXARG 4
|
||||
char *dirs[MAXARG+1];
|
||||
/*
|
||||
* Null-terminated directory prefix list for absolute pathname requests and
|
||||
* search list for relative pathname requests.
|
||||
*
|
||||
* MAXDIRS should be at least as large as the number of arguments that
|
||||
* inetd allows (currently 20).
|
||||
*/
|
||||
#define MAXDIRS 20
|
||||
static struct dirlist {
|
||||
char *name;
|
||||
int len;
|
||||
} dirs[MAXDIRS+1];
|
||||
static int suppress_naks;
|
||||
static int logging;
|
||||
static int secure;
|
||||
static char *securedir;
|
||||
|
||||
int secure = 0;
|
||||
struct formats;
|
||||
|
||||
static void tftp __P((struct tftphdr *, int));
|
||||
static char *errtomsg __P((int));
|
||||
static void nak __P((int));
|
||||
static char *verifyhost __P((struct sockaddr_in *));
|
||||
static void usage __P((void));
|
||||
void timer __P((int));
|
||||
void sendfile __P((struct formats *));
|
||||
void recvfile __P((struct formats *));
|
||||
void justquit __P((int));
|
||||
int validate_access __P((char **, int));
|
||||
int main __P((int, char **));
|
||||
|
||||
struct formats {
|
||||
char *f_mode;
|
||||
int (*f_validate) __P((char **, int));
|
||||
void (*f_send) __P((struct formats *));
|
||||
void (*f_recv) __P((struct formats *));
|
||||
int f_convert;
|
||||
} formats[] = {
|
||||
{ "netascii", validate_access, sendfile, recvfile, 1 },
|
||||
{ "octet", validate_access, sendfile, recvfile, 0 },
|
||||
#ifdef notdef
|
||||
{ "mail", validate_user, sendmail, recvmail, 1 },
|
||||
#endif
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
usage()
|
||||
|
@ -98,22 +147,32 @@ usage()
|
|||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register struct tftphdr *tp;
|
||||
register int n = 0;
|
||||
int on = 1;
|
||||
int ch, on;
|
||||
int fd = 0;
|
||||
int c;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
openlog("tftpd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
while ((c = getopt(argc, argv, "s")) != -1)
|
||||
switch (c) {
|
||||
while ((ch = getopt(argc, argv, "lns:")) != -1)
|
||||
switch (ch) {
|
||||
case 'l':
|
||||
logging = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
suppress_naks = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
secure = 1;
|
||||
securedir = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -121,23 +180,29 @@ main(argc, argv)
|
|||
break;
|
||||
}
|
||||
|
||||
for (; optind != argc; optind++) {
|
||||
if (!secure) {
|
||||
if (n >= MAXARG) {
|
||||
syslog(LOG_ERR, "too many directories\n");
|
||||
exit(1);
|
||||
} else
|
||||
dirs[n++] = argv[optind];
|
||||
}
|
||||
if (chdir(argv[optind])) {
|
||||
syslog(LOG_ERR, "%s: %m\n", argv[optind]);
|
||||
exit(1);
|
||||
if (optind < argc) {
|
||||
struct dirlist *dirp;
|
||||
|
||||
/* Get list of directory prefixes. Skip relative pathnames. */
|
||||
for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
|
||||
optind++) {
|
||||
if (argv[optind][0] == '/') {
|
||||
dirp->name = argv[optind];
|
||||
dirp->len = strlen(dirp->name);
|
||||
dirp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (secure && chroot(".")) {
|
||||
syslog(LOG_ERR, "chroot: %m\n");
|
||||
exit(1);
|
||||
if (secure) {
|
||||
if (chdir(securedir) < 0) {
|
||||
syslog(LOG_ERR, "chdir %s: %m", securedir);
|
||||
exit(1);
|
||||
}
|
||||
if (chroot(".")) {
|
||||
syslog(LOG_ERR, "chroot: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (setgid(GID_NOBODY)) {
|
||||
|
@ -155,6 +220,7 @@ main(argc, argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
on = 1;
|
||||
if (ioctl(fd, FIONBIO, &on) < 0) {
|
||||
syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
|
||||
exit(1);
|
||||
|
@ -226,7 +292,9 @@ main(argc, argv)
|
|||
syslog(LOG_ERR, "socket: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
if (bind(peer, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
|
||||
syslog(LOG_ERR, "bind: %m\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -241,27 +309,10 @@ main(argc, argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
int validate_access();
|
||||
int sendfile(), recvfile();
|
||||
|
||||
struct formats {
|
||||
char *f_mode;
|
||||
int (*f_validate)();
|
||||
int (*f_send)();
|
||||
int (*f_recv)();
|
||||
int f_convert;
|
||||
} formats[] = {
|
||||
{ "netascii", validate_access, sendfile, recvfile, 1 },
|
||||
{ "octet", validate_access, sendfile, recvfile, 0 },
|
||||
#ifdef notdef
|
||||
{ "mail", validate_user, sendmail, recvmail, 1 },
|
||||
#endif
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Handle initial connection protocol.
|
||||
*/
|
||||
static void
|
||||
tftp(tp, size)
|
||||
struct tftphdr *tp;
|
||||
int size;
|
||||
|
@ -269,7 +320,7 @@ tftp(tp, size)
|
|||
register char *cp;
|
||||
int first = 1, ecode;
|
||||
register struct formats *pf;
|
||||
char *filename, *mode;
|
||||
char *filename, *mode = NULL; /* XXX gcc */
|
||||
|
||||
filename = cp = tp->th_stuff;
|
||||
again:
|
||||
|
@ -297,8 +348,20 @@ again:
|
|||
nak(EBADOP);
|
||||
exit(1);
|
||||
}
|
||||
ecode = (*pf->f_validate)(filename, tp->th_opcode);
|
||||
ecode = (*pf->f_validate)(&filename, tp->th_opcode);
|
||||
if (logging) {
|
||||
syslog(LOG_INFO, "%s: %s request for %s: %s",
|
||||
verifyhost(&from),
|
||||
tp->th_opcode == WRQ ? "write" : "read",
|
||||
filename, errtomsg(ecode));
|
||||
}
|
||||
if (ecode) {
|
||||
/*
|
||||
* Avoid storms of naks to a RRQ broadcast for a relative
|
||||
* bootfile pathname from a diskless Sun.
|
||||
*/
|
||||
if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
|
||||
exit(0);
|
||||
nak(ecode);
|
||||
exit(1);
|
||||
}
|
||||
|
@ -323,38 +386,84 @@ FILE *file;
|
|||
* Note also, full path name must be
|
||||
* given as we have no login directory.
|
||||
*/
|
||||
validate_access(filename, mode)
|
||||
char *filename;
|
||||
int
|
||||
validate_access(filep, mode)
|
||||
char **filep;
|
||||
int mode;
|
||||
{
|
||||
struct stat stbuf;
|
||||
int fd;
|
||||
char *cp, **dirp;
|
||||
struct dirlist *dirp;
|
||||
static char pathname[MAXPATHLEN];
|
||||
char *filename = *filep;
|
||||
|
||||
if (!secure) {
|
||||
if (*filename != '/')
|
||||
return (EACCESS);
|
||||
/*
|
||||
* Prevent tricksters from getting around the directory restrictions
|
||||
*/
|
||||
if (strstr(filename, "/../"))
|
||||
return (EACCESS);
|
||||
|
||||
if (*filename == '/') {
|
||||
/*
|
||||
* prevent tricksters from getting around the directory
|
||||
* restrictions
|
||||
* Allow the request if it's in one of the approved locations.
|
||||
* Special case: check the null prefix ("/") by looking
|
||||
* for length = 1 and relying on the arg. processing that
|
||||
* it's a /.
|
||||
*/
|
||||
for (cp = filename + 1; *cp; cp++)
|
||||
if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)
|
||||
return(EACCESS);
|
||||
for (dirp = dirs; *dirp; dirp++)
|
||||
if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
|
||||
break;
|
||||
if (*dirp==0 && dirp!=dirs)
|
||||
return (EACCESS);
|
||||
}
|
||||
if (stat(filename, &stbuf) < 0)
|
||||
return (errno == ENOENT ? ENOTFOUND : EACCESS);
|
||||
if (mode == RRQ) {
|
||||
if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
|
||||
for (dirp = dirs; dirp->name != NULL; dirp++) {
|
||||
if (dirp->len == 1 ||
|
||||
(!strncmp(filename, dirp->name, dirp->len) &&
|
||||
filename[dirp->len] == '/'))
|
||||
break;
|
||||
}
|
||||
/* If directory list is empty, allow access to any file */
|
||||
if (dirp->name == NULL && dirp != dirs)
|
||||
return (EACCESS);
|
||||
if (stat(filename, &stbuf) < 0)
|
||||
return (errno == ENOENT ? ENOTFOUND : EACCESS);
|
||||
if ((stbuf.st_mode & S_IFMT) != S_IFREG)
|
||||
return (ENOTFOUND);
|
||||
if (mode == RRQ) {
|
||||
if ((stbuf.st_mode & S_IROTH) == 0)
|
||||
return (EACCESS);
|
||||
} else {
|
||||
if ((stbuf.st_mode & S_IWOTH) == 0)
|
||||
return (EACCESS);
|
||||
}
|
||||
} else {
|
||||
if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Relative file name: search the approved locations for it.
|
||||
* Don't allow write requests or ones that avoid directory
|
||||
* restrictions.
|
||||
*/
|
||||
|
||||
if (mode != RRQ || !strncmp(filename, "../", 3))
|
||||
return (EACCESS);
|
||||
|
||||
/*
|
||||
* If the file exists in one of the directories and isn't
|
||||
* readable, continue looking. However, change the error code
|
||||
* to give an indication that the file exists.
|
||||
*/
|
||||
err = ENOTFOUND;
|
||||
if (dirs[0].name != NULL) {
|
||||
for (dirp = dirs; dirp->name != NULL; dirp++) {
|
||||
snprintf(pathname, sizeof pathname, "%s/%s",
|
||||
dirp->name, filename);
|
||||
if (stat(pathname, &stbuf) == 0 &&
|
||||
(stbuf.st_mode & S_IFMT) == S_IFREG) {
|
||||
if ((stbuf.st_mode & S_IROTH) != 0)
|
||||
break;
|
||||
err = EACCESS;
|
||||
}
|
||||
}
|
||||
if (dirp->name == NULL)
|
||||
return (err);
|
||||
*filep = filename = pathname;
|
||||
} else
|
||||
*filep = filename;
|
||||
}
|
||||
fd = open(filename, mode == RRQ ? 0 : 1);
|
||||
if (fd < 0)
|
||||
|
@ -370,7 +479,8 @@ int timeout;
|
|||
jmp_buf timeoutbuf;
|
||||
|
||||
void
|
||||
timer()
|
||||
timer(dummy)
|
||||
int dummy;
|
||||
{
|
||||
|
||||
timeout += rexmtval;
|
||||
|
@ -382,16 +492,19 @@ timer()
|
|||
/*
|
||||
* Send the requested file.
|
||||
*/
|
||||
void
|
||||
sendfile(pf)
|
||||
struct formats *pf;
|
||||
{
|
||||
struct tftphdr *dp, *r_init();
|
||||
struct tftphdr *dp;
|
||||
register struct tftphdr *ap; /* ack packet */
|
||||
register int block = 1, size, n;
|
||||
register int size, n;
|
||||
volatile int block;
|
||||
|
||||
signal(SIGALRM, timer);
|
||||
dp = r_init();
|
||||
ap = (struct tftphdr *)ackbuf;
|
||||
block = 1;
|
||||
do {
|
||||
size = readit(file, &dp, pf->f_convert);
|
||||
if (size < 0) {
|
||||
|
@ -401,7 +514,7 @@ sendfile(pf)
|
|||
dp->th_opcode = htons((u_short)DATA);
|
||||
dp->th_block = htons((u_short)block);
|
||||
timeout = 0;
|
||||
(void) setjmp(timeoutbuf);
|
||||
(void)setjmp(timeoutbuf);
|
||||
|
||||
send_data:
|
||||
if (send(peer, dp, size + 4, 0) != size + 4) {
|
||||
|
@ -422,16 +535,14 @@ send_data:
|
|||
|
||||
if (ap->th_opcode == ERROR)
|
||||
goto abort;
|
||||
|
||||
|
||||
if (ap->th_opcode == ACK) {
|
||||
if (ap->th_block == block) {
|
||||
if (ap->th_block == block)
|
||||
break;
|
||||
}
|
||||
/* Re-synchronize with the other side */
|
||||
(void) synchnet(peer);
|
||||
if (ap->th_block == (block -1)) {
|
||||
if (ap->th_block == (block -1))
|
||||
goto send_data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -442,25 +553,28 @@ abort:
|
|||
}
|
||||
|
||||
void
|
||||
justquit()
|
||||
justquit(dummy)
|
||||
int dummy;
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Receive a file.
|
||||
*/
|
||||
void
|
||||
recvfile(pf)
|
||||
struct formats *pf;
|
||||
{
|
||||
struct tftphdr *dp, *w_init();
|
||||
struct tftphdr *dp;
|
||||
register struct tftphdr *ap; /* ack buffer */
|
||||
register int block = 0, n, size;
|
||||
register int n, size;
|
||||
volatile int block;
|
||||
|
||||
signal(SIGALRM, timer);
|
||||
dp = w_init();
|
||||
ap = (struct tftphdr *)ackbuf;
|
||||
block = 0;
|
||||
do {
|
||||
timeout = 0;
|
||||
ap->th_opcode = htons((u_short)ACK);
|
||||
|
@ -538,12 +652,29 @@ struct errmsg {
|
|||
{ -1, 0 }
|
||||
};
|
||||
|
||||
static char *
|
||||
errtomsg(error)
|
||||
int error;
|
||||
{
|
||||
static char buf[20];
|
||||
register struct errmsg *pe;
|
||||
|
||||
if (error == 0)
|
||||
return "success";
|
||||
for (pe = errmsgs; pe->e_code >= 0; pe++)
|
||||
if (pe->e_code == error)
|
||||
return pe->e_msg;
|
||||
sprintf(buf, "error %d", error);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a nak packet (error message).
|
||||
* Error code passed in is one of the
|
||||
* standard TFTP codes, or a UNIX errno
|
||||
* offset by 100.
|
||||
*/
|
||||
static void
|
||||
nak(error)
|
||||
int error;
|
||||
{
|
||||
|
@ -568,3 +699,17 @@ nak(error)
|
|||
if (send(peer, buf, length, 0) != length)
|
||||
syslog(LOG_ERR, "nak: %m\n");
|
||||
}
|
||||
|
||||
static char *
|
||||
verifyhost(fromp)
|
||||
struct sockaddr_in *fromp;
|
||||
{
|
||||
struct hostent *hp;
|
||||
|
||||
hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (fromp->sin_addr),
|
||||
fromp->sin_family);
|
||||
if (hp)
|
||||
return hp->h_name;
|
||||
else
|
||||
return inet_ntoa(fromp->sin_addr);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue