forked from mirrors/tftp-hpa-google
Fork before performing tcpwrappers check.
Don't rely on nonstandard bsd_signal() function, instead require that the platform has sigaction(). This is 2001, after all. This may resolve some potential portability problems. Log a message if memory allocation fails, instead of dying silently. Clean up the main dispatch loop. Use <sysexits.h> for exit codes, if it exists. Reformat tftpd.c to match the other files.
This commit is contained in:
parent
e4650ab86f
commit
81822ea738
10 changed files with 862 additions and 711 deletions
16
README
16
README
|
@ -4,6 +4,22 @@ This is tftp-hpa-0.18; this version was put out by H. Peter Anvin
|
||||||
===> IMPORTANT: SEE THE FILE "README.security" FOR IMPORTANT SECURITY
|
===> IMPORTANT: SEE THE FILE "README.security" FOR IMPORTANT SECURITY
|
||||||
===> CHANGES IN THIS VERSION!!!!!!!!!
|
===> CHANGES IN THIS VERSION!!!!!!!!!
|
||||||
|
|
||||||
|
Changes in 0.19:
|
||||||
|
Fork before performing tcpwrappers check.
|
||||||
|
|
||||||
|
Don't rely on nonstandard bsd_signal() function, instead
|
||||||
|
require that the platform has sigaction(). This is 2001,
|
||||||
|
after all. This may resolve some potential portability
|
||||||
|
problems.
|
||||||
|
|
||||||
|
Log a message if memory allocation fails, instead of dying
|
||||||
|
silently.
|
||||||
|
|
||||||
|
Clean up the main dispatch loop.
|
||||||
|
|
||||||
|
Use <sysexits.h> for exit codes, if it exists.
|
||||||
|
|
||||||
|
|
||||||
Changes in 0.18:
|
Changes in 0.18:
|
||||||
Support (almost) arbitrary filename remappings via regular
|
Support (almost) arbitrary filename remappings via regular
|
||||||
expression-based rulesets.
|
expression-based rulesets.
|
||||||
|
|
|
@ -22,4 +22,5 @@
|
||||||
#undef HAVE_STRUCT_IN_PKTINFO
|
#undef HAVE_STRUCT_IN_PKTINFO
|
||||||
#undef HAVE_SETREUID
|
#undef HAVE_SETREUID
|
||||||
#undef HAVE_SETREGID
|
#undef HAVE_SETREGID
|
||||||
|
#undef HAVE_SYSEXITS_H
|
||||||
#undef WITH_REGEX
|
#undef WITH_REGEX
|
||||||
|
|
|
@ -49,6 +49,8 @@ PA_ADD_CFLAGS(-pipe)
|
||||||
|
|
||||||
PA_SIGSETJMP([AC_DEFINE(HAVE_SIGSETJMP)])
|
PA_SIGSETJMP([AC_DEFINE(HAVE_SIGSETJMP)])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS(sysexits.h)
|
||||||
|
|
||||||
LIBXTRA=false
|
LIBXTRA=false
|
||||||
|
|
||||||
AC_SEARCH_LIBS(xmalloc, iberty, , LIBXTRA=true LIBOBJS="$LIBOBJS xmalloc.o")
|
AC_SEARCH_LIBS(xmalloc, iberty, , LIBXTRA=true LIBOBJS="$LIBOBJS xmalloc.o")
|
||||||
|
|
|
@ -42,6 +42,9 @@
|
||||||
* Prototypes for read-ahead/write-behind subroutines for tftp user and
|
* Prototypes for read-ahead/write-behind subroutines for tftp user and
|
||||||
* server.
|
* server.
|
||||||
*/
|
*/
|
||||||
|
#ifndef TFTPSUBS_H
|
||||||
|
#define TFTPSUBS_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct tftphdr *r_init(void);
|
struct tftphdr *r_init(void);
|
||||||
|
@ -62,3 +65,5 @@ extern int segsize;
|
||||||
*/
|
*/
|
||||||
extern void *xmalloc(size_t);
|
extern void *xmalloc(size_t);
|
||||||
extern char *xstrdup(const char *);
|
extern char *xstrdup(const char *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -3,7 +3,7 @@ all: tftpd
|
||||||
-include ../MCONFIG
|
-include ../MCONFIG
|
||||||
-include ../MRULES
|
-include ../MRULES
|
||||||
|
|
||||||
OBJS = tftpd.o tftpsubs.o recvfrom.o $(TFTPDOBJS)
|
OBJS = tftpd.o tftpsubs.o recvfrom.o misc.o $(TFTPDOBJS)
|
||||||
|
|
||||||
tftpd: $(OBJS)
|
tftpd: $(OBJS)
|
||||||
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
|
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
|
||||||
|
|
71
tftpd/misc.c
Normal file
71
tftpd/misc.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software available under the same license
|
||||||
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
* http://www.openbsd.org/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* misc.c
|
||||||
|
*
|
||||||
|
* Minor help routines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "tftpd.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the signal handler and flags. Basically a user-friendly
|
||||||
|
* wrapper around sigaction().
|
||||||
|
*/
|
||||||
|
void set_signal(int signum, void (*handler)(int), int flags)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof sa);
|
||||||
|
sa.sa_handler = handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = flags;
|
||||||
|
|
||||||
|
if ( sigaction(signum, &sa, NULL) ) {
|
||||||
|
syslog(LOG_ERR, "sigaction: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* malloc() that syslogs an error message and bails if it fails.
|
||||||
|
*/
|
||||||
|
void *tfmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *p = malloc(size);
|
||||||
|
|
||||||
|
if ( !p ) {
|
||||||
|
syslog(LOG_ERR, "malloc: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* strdup() that does the equivalent
|
||||||
|
*/
|
||||||
|
char *tfstrdup(const char *str)
|
||||||
|
{
|
||||||
|
char *p = strdup(str);
|
||||||
|
|
||||||
|
if ( !p ) {
|
||||||
|
syslog(LOG_ERR, "strdup: %m");
|
||||||
|
exit(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
#include "tftpsubs.h"
|
#include "tftpd.h"
|
||||||
#include "remap.h"
|
#include "remap.h"
|
||||||
|
|
||||||
#define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
|
#define DEADMAN_MAX_STEPS 1024 /* Timeout after this many steps */
|
||||||
|
@ -197,7 +197,7 @@ static int parseline(char *line, struct rule *r, int lineno)
|
||||||
|
|
||||||
/* Read the rewrite pattern, if any */
|
/* Read the rewrite pattern, if any */
|
||||||
if ( readescstring(buffer, &line) ) {
|
if ( readescstring(buffer, &line) ) {
|
||||||
r->pattern = xstrdup(buffer);
|
r->pattern = tfstrdup(buffer);
|
||||||
} else {
|
} else {
|
||||||
r->pattern = "";
|
r->pattern = "";
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ struct rule *parserulefile(FILE *f)
|
||||||
char line[LINE_MAX];
|
char line[LINE_MAX];
|
||||||
struct rule *first_rule = NULL;
|
struct rule *first_rule = NULL;
|
||||||
struct rule **last_rule = &first_rule;
|
struct rule **last_rule = &first_rule;
|
||||||
struct rule *this_rule = xmalloc(sizeof(struct rule));
|
struct rule *this_rule = tfmalloc(sizeof(struct rule));
|
||||||
int rv;
|
int rv;
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
@ -224,7 +224,7 @@ struct rule *parserulefile(FILE *f)
|
||||||
if ( rv > 0 ) {
|
if ( rv > 0 ) {
|
||||||
*last_rule = this_rule;
|
*last_rule = this_rule;
|
||||||
last_rule = &this_rule->next;
|
last_rule = &this_rule->next;
|
||||||
this_rule = xmalloc(sizeof(struct rule));
|
this_rule = tfmalloc(sizeof(struct rule));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ struct rule *parserulefile(FILE *f)
|
||||||
|
|
||||||
if ( err ) {
|
if ( err ) {
|
||||||
/* Bail on error, we have already logged an error message */
|
/* Bail on error, we have already logged an error message */
|
||||||
exit(1);
|
exit(EX_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
return first_rule;
|
return first_rule;
|
||||||
|
@ -241,7 +241,7 @@ struct rule *parserulefile(FILE *f)
|
||||||
/* Execute a rule set on a string; returns a malloc'd new string. */
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
char *rewrite_string(const char *input, const struct rule *rules, int is_put)
|
char *rewrite_string(const char *input, const struct rule *rules, int is_put)
|
||||||
{
|
{
|
||||||
char *current = xstrdup(input);
|
char *current = tfstrdup(input);
|
||||||
char *newstr;
|
char *newstr;
|
||||||
const struct rule *ruleptr = rules;
|
const struct rule *ruleptr = rules;
|
||||||
regmatch_t pmatch[10];
|
regmatch_t pmatch[10];
|
||||||
|
@ -272,7 +272,7 @@ char *rewrite_string(const char *input, const struct rule *rules, int is_put)
|
||||||
|
|
||||||
if ( ruleptr->rule_flags & RULE_REWRITE ) {
|
if ( ruleptr->rule_flags & RULE_REWRITE ) {
|
||||||
len = genmatchstring(NULL, ruleptr->pattern, current, pmatch);
|
len = genmatchstring(NULL, ruleptr->pattern, current, pmatch);
|
||||||
newstr = xmalloc(len+1);
|
newstr = tfmalloc(len+1);
|
||||||
genmatchstring(newstr, ruleptr->pattern, current, pmatch);
|
genmatchstring(newstr, ruleptr->pattern, current, pmatch);
|
||||||
free(current);
|
free(current);
|
||||||
current = newstr;
|
current = newstr;
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
* Prototypes for regular-expression based filename remapping.
|
* Prototypes for regular-expression based filename remapping.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef TFTPD_REMAP_H
|
||||||
|
#define TFTPD_REMAP_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
@ -30,4 +33,6 @@ struct rule *parserulefile(FILE *);
|
||||||
/* Execute a rule set on a string; returns a malloc'd new string. */
|
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||||
char *rewrite_string(const char *, const struct rule *, int);
|
char *rewrite_string(const char *, const struct rule *, int);
|
||||||
|
|
||||||
#endif
|
#endif /* WITH_REGEX */
|
||||||
|
#endif /* TFTPD_REMAP_H */
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ static const char *rcsid = "tftp-hpa $Id$";
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#include "../config.h"
|
#include "tftpd.h"
|
||||||
#include "tftpsubs.h"
|
#include "tftpsubs.h"
|
||||||
#include "recvfrom.h"
|
#include "recvfrom.h"
|
||||||
#include "remap.h"
|
#include "remap.h"
|
||||||
|
@ -88,14 +88,6 @@ int allow_severity = -1; /* Don't log at all */
|
||||||
struct request_info wrap_request;
|
struct request_info wrap_request;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void bsd_signal(int, void (*)(int));
|
|
||||||
|
|
||||||
#ifndef HAVE_SIGSETJMP
|
|
||||||
#define sigsetjmp(x,y) setjmp(x)
|
|
||||||
#define siglongjmp(x,y) longjmp(x,y)
|
|
||||||
#define sigjmp_buf jmp_buf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TIMEOUT 5 /* Default timeout (seconds) */
|
#define TIMEOUT 5 /* Default timeout (seconds) */
|
||||||
#define TRIES 4 /* Number of attempts to send each packet */
|
#define TRIES 4 /* Number of attempts to send each packet */
|
||||||
#define TIMEOUT_LIMIT (TRIES*(TRIES+1)/2)
|
#define TIMEOUT_LIMIT (TRIES*(TRIES+1)/2)
|
||||||
|
@ -167,7 +159,7 @@ usage(void)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Usage: %s [-vc][-m mappings][-u user][-t timeout][-r option...] [-s] [directory ...]",
|
syslog(LOG_ERR, "Usage: %s [-vc][-m mappings][-u user][-t timeout][-r option...] [-s] [directory ...]",
|
||||||
__progname);
|
__progname);
|
||||||
exit(1);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -213,7 +205,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
if ( !opt->o_opt ) {
|
if ( !opt->o_opt ) {
|
||||||
syslog(LOG_ERR, "Unknown option: %s", optarg);
|
syslog(LOG_ERR, "Unknown option: %s", optarg);
|
||||||
exit(1);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#ifdef WITH_REGEX
|
#ifdef WITH_REGEX
|
||||||
|
@ -222,12 +214,12 @@ main(int argc, char **argv)
|
||||||
FILE *f;
|
FILE *f;
|
||||||
if ( rewrite_rules ) {
|
if ( rewrite_rules ) {
|
||||||
syslog(LOG_ERR, "Multiple -m options");
|
syslog(LOG_ERR, "Multiple -m options");
|
||||||
exit(1);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
f = fopen(optarg, "rt");
|
f = fopen(optarg, "rt");
|
||||||
if ( !f ) {
|
if ( !f ) {
|
||||||
syslog(LOG_ERR, "Cannot open map file: %s: %m", optarg);
|
syslog(LOG_ERR, "Cannot open map file: %s: %m", optarg);
|
||||||
exit(1);
|
exit(EX_NOINPUT);
|
||||||
}
|
}
|
||||||
rewrite_rules = parserulefile(f);
|
rewrite_rules = parserulefile(f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
@ -249,7 +241,7 @@ main(int argc, char **argv)
|
||||||
dirs = calloc(ndirs+2, sizeof(char *));
|
dirs = calloc(ndirs+2, sizeof(char *));
|
||||||
if (dirs == NULL) {
|
if (dirs == NULL) {
|
||||||
syslog(LOG_ERR, "malloc: %m");
|
syslog(LOG_ERR, "malloc: %m");
|
||||||
exit(1);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
dirs[n++] = argv[optind];
|
dirs[n++] = argv[optind];
|
||||||
dirs[n] = NULL;
|
dirs[n] = NULL;
|
||||||
|
@ -259,38 +251,38 @@ main(int argc, char **argv)
|
||||||
if (secure) {
|
if (secure) {
|
||||||
if (ndirs == 0) {
|
if (ndirs == 0) {
|
||||||
syslog(LOG_ERR, "no -s directory");
|
syslog(LOG_ERR, "no -s directory");
|
||||||
exit(1);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
if (ndirs > 1) {
|
if (ndirs > 1) {
|
||||||
syslog(LOG_ERR, "too many -s directories");
|
syslog(LOG_ERR, "too many -s directories");
|
||||||
exit(1);
|
exit(EX_USAGE);
|
||||||
}
|
}
|
||||||
if (chdir(dirs[0])) {
|
if (chdir(dirs[0])) {
|
||||||
syslog(LOG_ERR, "%s: %m", dirs[0]);
|
syslog(LOG_ERR, "%s: %m", dirs[0]);
|
||||||
exit(1);
|
exit(EX_NOINPUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pw = getpwnam(user);
|
pw = getpwnam(user);
|
||||||
if (!pw) {
|
if (!pw) {
|
||||||
syslog(LOG_ERR, "no user %s: %m", user);
|
syslog(LOG_ERR, "no user %s: %m", user);
|
||||||
exit(1);
|
exit(EX_NOUSER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, FIONBIO, &on) < 0) {
|
if (ioctl(fd, FIONBIO, &on) < 0) {
|
||||||
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
|
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
|
||||||
exit(1);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This means we don't want to wait() for children */
|
/* This means we don't want to wait() for children */
|
||||||
bsd_signal(SIGCHLD, SIG_IGN);
|
set_signal(SIGCHLD, SIG_IGN, SA_NOCLDSTOP);
|
||||||
|
|
||||||
/* Take SIGHUP and use it to set a variable. This
|
/* Take SIGHUP and use it to set a variable. This
|
||||||
is polled synchronously to make sure we don't
|
is polled synchronously to make sure we don't
|
||||||
lose packets as a result. */
|
lose packets as a result. */
|
||||||
bsd_signal(SIGHUP, handle_sighup);
|
set_signal(SIGHUP, handle_sighup, 0);
|
||||||
|
|
||||||
do {
|
while ( 1 ) {
|
||||||
fd_set readset;
|
fd_set readset;
|
||||||
struct timeval tv_timeout;
|
struct timeval tv_timeout;
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -316,9 +308,23 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
syslog(LOG_ERR, "recvfrom: %m");
|
syslog(LOG_ERR, "recvfrom: %m");
|
||||||
exit(1);
|
exit(EX_IOERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we have read the request packet from the UDP
|
||||||
|
* socket, we fork and go back to listening to the socket.
|
||||||
|
*/
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
syslog(LOG_ERR, "fork: %m");
|
||||||
|
exit(EX_OSERR); /* Return to inetd, just in case */
|
||||||
|
} else if ( pid == 0 )
|
||||||
|
break; /* Child exit, parent loop */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Child process: handle the actual request here */
|
||||||
|
|
||||||
#ifdef HAVE_TCPWRAPPERS
|
#ifdef HAVE_TCPWRAPPERS
|
||||||
/* Verify if this was a legal request for us. This has to be
|
/* Verify if this was a legal request for us. This has to be
|
||||||
done before the chroot, while /etc is still accessible. */
|
done before the chroot, while /etc is still accessible. */
|
||||||
|
@ -333,31 +339,18 @@ main(int argc, char **argv)
|
||||||
if ( deny_severity != -1 )
|
if ( deny_severity != -1 )
|
||||||
syslog(deny_severity, "connection refused from %s",
|
syslog(deny_severity, "connection refused from %s",
|
||||||
inet_ntoa(from.sin_addr));
|
inet_ntoa(from.sin_addr));
|
||||||
exit(1); /* Access denied */
|
exit(EX_NOPERM); /* Access denied */
|
||||||
} else if ( allow_severity != -1 ) {
|
} else if ( allow_severity != -1 ) {
|
||||||
syslog(allow_severity, "connect from %s",
|
syslog(allow_severity, "connect from %s",
|
||||||
inet_ntoa(from.sin_addr));
|
inet_ntoa(from.sin_addr));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Now that we have read the request packet from 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 */
|
/* Chroot and drop privileges */
|
||||||
|
|
||||||
if (secure && chroot(".")) {
|
if (secure && chroot(".")) {
|
||||||
syslog(LOG_ERR, "chroot: %m");
|
syslog(LOG_ERR, "chroot: %m");
|
||||||
exit(1);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SETREGID
|
#ifdef HAVE_SETREGID
|
||||||
|
@ -376,31 +369,35 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
if ( setrv ) {
|
if ( setrv ) {
|
||||||
syslog(LOG_ERR, "cannot drop privileges: %m");
|
syslog(LOG_ERR, "cannot drop privileges: %m");
|
||||||
exit(1);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close file descriptors we don't need */
|
/* Ignore SIGHUP */
|
||||||
|
set_signal(SIGHUP, SIG_IGN, 0);
|
||||||
|
|
||||||
from.sin_family = AF_INET;
|
/* Close file descriptors we don't need */
|
||||||
alarm(0);
|
|
||||||
close(fd);
|
close(fd);
|
||||||
close(1);
|
close(1);
|
||||||
|
|
||||||
|
/* Other basic setup */
|
||||||
|
from.sin_family = AF_INET;
|
||||||
|
alarm(0);
|
||||||
|
|
||||||
/* Process the request... */
|
/* Process the request... */
|
||||||
|
|
||||||
peer = socket(AF_INET, SOCK_DGRAM, 0);
|
peer = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (peer < 0) {
|
if (peer < 0) {
|
||||||
syslog(LOG_ERR, "socket: %m");
|
syslog(LOG_ERR, "socket: %m");
|
||||||
exit(1);
|
exit(EX_IOERR);
|
||||||
}
|
}
|
||||||
myaddr.sin_port = htons(0); /* We want a new local port */
|
myaddr.sin_port = htons(0); /* We want a new local port */
|
||||||
if (bind(peer, (struct sockaddr *)&myaddr, sizeof (myaddr)) < 0) {
|
if (bind(peer, (struct sockaddr *)&myaddr, sizeof (myaddr)) < 0) {
|
||||||
syslog(LOG_ERR, "bind: %m");
|
syslog(LOG_ERR, "bind: %m");
|
||||||
exit(1);
|
exit(EX_IOERR);
|
||||||
}
|
}
|
||||||
if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
|
if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
|
||||||
syslog(LOG_ERR, "connect: %m");
|
syslog(LOG_ERR, "connect: %m");
|
||||||
exit(1);
|
exit(EX_IOERR);
|
||||||
}
|
}
|
||||||
tp = (struct tftphdr *)buf;
|
tp = (struct tftphdr *)buf;
|
||||||
tp->th_opcode = ntohs(tp->th_opcode);
|
tp->th_opcode = ntohs(tp->th_opcode);
|
||||||
|
@ -515,7 +512,7 @@ tftp(struct tftphdr *tp, int size)
|
||||||
else
|
else
|
||||||
(*pf->f_send)(pf, NULL, 0);
|
(*pf->f_send)(pf, NULL, 0);
|
||||||
}
|
}
|
||||||
exit(1);
|
exit(EX_SOFTWARE); /* We should never get here */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int blksize_set;
|
static int blksize_set;
|
||||||
|
@ -789,7 +786,7 @@ oack:
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
bsd_signal(SIGALRM, timer);
|
set_signal(SIGALRM, timer, SA_RESTART);
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
n = recv(peer, ackbuf, sizeof(ackbuf), 0);
|
n = recv(peer, ackbuf, sizeof(ackbuf), 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
|
@ -834,7 +831,7 @@ send_data:
|
||||||
}
|
}
|
||||||
read_ahead(file, pf->f_convert);
|
read_ahead(file, pf->f_convert);
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
bsd_signal(SIGALRM, timer);
|
set_signal(SIGALRM, timer, SA_RESTART);
|
||||||
alarm(rexmtval); /* read the ack */
|
alarm(rexmtval); /* read the ack */
|
||||||
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
|
n = recv(peer, ackbuf, sizeof (ackbuf), 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
|
@ -899,7 +896,7 @@ recvfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
}
|
}
|
||||||
block++;
|
block++;
|
||||||
(void) sigsetjmp(timeoutbuf,1);
|
(void) sigsetjmp(timeoutbuf,1);
|
||||||
bsd_signal(SIGALRM, timer);
|
set_signal(SIGALRM, timer, SA_RESTART);
|
||||||
send_ack:
|
send_ack:
|
||||||
if (send(peer, ackbuf, acksize, 0) != acksize) {
|
if (send(peer, ackbuf, acksize, 0) != acksize) {
|
||||||
syslog(LOG_ERR, "tftpd: write(ack): %m");
|
syslog(LOG_ERR, "tftpd: write(ack): %m");
|
||||||
|
@ -907,7 +904,7 @@ send_ack:
|
||||||
}
|
}
|
||||||
write_behind(file, pf->f_convert);
|
write_behind(file, pf->f_convert);
|
||||||
for ( ; ; ) {
|
for ( ; ; ) {
|
||||||
bsd_signal(SIGALRM, timer);
|
set_signal(SIGALRM, timer, SA_RESTART);
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
n = recv(peer, dp, PKTSIZE, 0);
|
n = recv(peer, dp, PKTSIZE, 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
|
@ -944,7 +941,7 @@ send_ack:
|
||||||
ap->th_block = htons((u_short)(block));
|
ap->th_block = htons((u_short)(block));
|
||||||
(void) send(peer, ackbuf, 4, 0);
|
(void) send(peer, ackbuf, 4, 0);
|
||||||
|
|
||||||
bsd_signal(SIGALRM, justquit); /* just quit on timeout */
|
set_signal(SIGALRM, justquit, SA_RESETHAND); /* just quit on timeout */
|
||||||
alarm(rexmtval);
|
alarm(rexmtval);
|
||||||
n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
|
n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
|
||||||
alarm(0);
|
alarm(0);
|
||||||
|
|
54
tftpd/tftpd.h
Normal file
54
tftpd/tftpd.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/* $Id$ */
|
||||||
|
/* ----------------------------------------------------------------------- *
|
||||||
|
*
|
||||||
|
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software available under the same license
|
||||||
|
* as the "OpenBSD" operating system, distributed at
|
||||||
|
* http://www.openbsd.org/.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tftpd.h
|
||||||
|
*
|
||||||
|
* Prototypes for various functions that are part of the tftpd server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TFTPD_TFTPD_H
|
||||||
|
#define TFTPD_TFTPD_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../config.h"
|
||||||
|
#ifdef HAVE_SYSEXITS_H
|
||||||
|
#include <sysexits.h>
|
||||||
|
#else
|
||||||
|
#define EX_USAGE 64 /* command line usage error */
|
||||||
|
#define EX_DATAERR 65 /* data format error */
|
||||||
|
#define EX_NOINPUT 66 /* cannot open input */
|
||||||
|
#define EX_NOUSER 67 /* addressee unknown */
|
||||||
|
#define EX_NOHOST 68 /* host name unknown */
|
||||||
|
#define EX_UNAVAILABLE 69 /* service unavailable */
|
||||||
|
#define EX_SOFTWARE 70 /* internal software error */
|
||||||
|
#define EX_OSERR 71 /* system error (e.g., can't fork) */
|
||||||
|
#define EX_OSFILE 72 /* critical OS file missing */
|
||||||
|
#define EX_CANTCREAT 73 /* can't create (user) output file */
|
||||||
|
#define EX_IOERR 74 /* input/output error */
|
||||||
|
#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
|
||||||
|
#define EX_PROTOCOL 76 /* remote error in protocol */
|
||||||
|
#define EX_NOPERM 77 /* permission denied */
|
||||||
|
#define EX_CONFIG 78 /* configuration error */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_SIGSETJMP
|
||||||
|
#define sigsetjmp(x,y) setjmp(x)
|
||||||
|
#define siglongjmp(x,y) longjmp(x,y)
|
||||||
|
#define sigjmp_buf jmp_buf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void set_signal(int, void (*)(int), int);
|
||||||
|
void *tfmalloc(size_t);
|
||||||
|
char *tfstrdup(const char *);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue