forked from mirrors/tftp-hpa-google
Better error messages.
This commit is contained in:
parent
82eae1bcd6
commit
b3ec0c58e6
5 changed files with 109 additions and 74 deletions
6
CHANGES
6
CHANGES
|
@ -1,5 +1,11 @@
|
|||
$Id$
|
||||
|
||||
Changes in 0.32:
|
||||
Better error messages; including the capability to send a
|
||||
custom error message to the client when hitting an "a" rule in
|
||||
a remapping table.
|
||||
|
||||
|
||||
Changes in 0.31:
|
||||
Put in a check to make sure xinetd (in particular) doesn't
|
||||
pass us an IPv6 socket.
|
||||
|
|
56
tftp/tftp.c
56
tftp/tftp.c
|
@ -65,7 +65,7 @@ int timeout;
|
|||
sigjmp_buf toplevel;
|
||||
sigjmp_buf timeoutbuf;
|
||||
|
||||
static void nak(int);
|
||||
static void nak(int, const char *);
|
||||
static int makerequest(int, const char *, struct tftphdr *, const char *);
|
||||
static void printstats(const char *, unsigned long);
|
||||
static void startclock(void);
|
||||
|
@ -107,7 +107,7 @@ tftp_sendfile(int fd, const char *name, const char *mode)
|
|||
/* size = read(fd, dp->th_data, SEGSIZE); */
|
||||
size = readit(file, &dp, convert);
|
||||
if (size < 0) {
|
||||
nak(errno + 100);
|
||||
nak(errno + 100, NULL);
|
||||
break;
|
||||
}
|
||||
dp->th_opcode = htons((u_short)DATA);
|
||||
|
@ -274,7 +274,7 @@ send_ack:
|
|||
/* size = write(fd, dp->th_data, n - 4); */
|
||||
size = writeit(file, &dp, n - 4, convert);
|
||||
if (size < 0) {
|
||||
nak(errno + 100);
|
||||
nak(errno + 100, NULL);
|
||||
break;
|
||||
}
|
||||
amount += size;
|
||||
|
@ -331,29 +331,37 @@ struct errmsg {
|
|||
* offset by 100.
|
||||
*/
|
||||
static void
|
||||
nak(int error)
|
||||
nak(int error, const char *msg)
|
||||
{
|
||||
struct errmsg *pe;
|
||||
struct tftphdr *tp;
|
||||
int length;
|
||||
|
||||
tp = (struct tftphdr *)ackbuf;
|
||||
tp->th_opcode = htons((u_short)ERROR);
|
||||
tp->th_code = htons((u_short)error);
|
||||
for (pe = errmsgs; pe->e_code >= 0; pe++)
|
||||
if (pe->e_code == error)
|
||||
break;
|
||||
if (pe->e_code < 0) {
|
||||
pe->e_msg = strerror(error - 100);
|
||||
tp->th_code = EUNDEF;
|
||||
struct errmsg *pe;
|
||||
struct tftphdr *tp;
|
||||
int length;
|
||||
|
||||
tp = (struct tftphdr *)ackbuf;
|
||||
tp->th_opcode = htons((u_short)ERROR);
|
||||
tp->th_code = htons((u_short)error);
|
||||
if ( !msg ) {
|
||||
if ( error >= 100 ) {
|
||||
msg = strerror(error - 100);
|
||||
tp->th_code = EUNDEF;
|
||||
} else {
|
||||
for (pe = errmsgs; pe->e_code >= 0; pe++) {
|
||||
if (pe->e_code == error) {
|
||||
msg = pe->e_msg;
|
||||
break;
|
||||
}
|
||||
strcpy(tp->th_msg, pe->e_msg);
|
||||
length = strlen(pe->e_msg) + 4;
|
||||
if (trace)
|
||||
tpacket("sent", tp, length);
|
||||
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
|
||||
sizeof(peeraddr)) != length)
|
||||
perror("nak");
|
||||
}
|
||||
}
|
||||
}
|
||||
length = strlen(msg)+1;
|
||||
memcpy(tp->th_msg, msg, length);
|
||||
length += 4; /* Add space for header */
|
||||
|
||||
if (trace)
|
||||
tpacket("sent", tp, length);
|
||||
if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
|
||||
sizeof(peeraddr)) != length)
|
||||
perror("nak");
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $Id$ */
|
||||
/* ----------------------------------------------------------------------- *
|
||||
*
|
||||
* Copyright 2001 H. Peter Anvin - All Rights Reserved
|
||||
* Copyright 2001-2002 H. Peter Anvin - All Rights Reserved
|
||||
*
|
||||
* This program is free software available under the same license
|
||||
* as the "OpenBSD" operating system, distributed at
|
||||
|
@ -104,8 +104,11 @@ static int genmatchstring(char *string, const char *pattern, const char *input,
|
|||
return len;
|
||||
}
|
||||
|
||||
/* Extract a string terminated by non-escaped whitespace; ignore leading whitespace */
|
||||
/* Consider an unescaped # to be a comment marker, functionally \n */
|
||||
/*
|
||||
* Extract a string terminated by non-escaped whitespace; ignoring
|
||||
* leading whitespace. Consider an unescaped # to be a comment marker,
|
||||
* functionally \n.
|
||||
*/
|
||||
static int readescstring(char *buf, char **str)
|
||||
{
|
||||
char *p = *str;
|
||||
|
@ -268,7 +271,8 @@ void freerules(struct rule *r)
|
|||
|
||||
/* 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, match_pattern_callback macrosub)
|
||||
int is_put, match_pattern_callback macrosub,
|
||||
const char **errmsg)
|
||||
{
|
||||
char *current = tfstrdup(input);
|
||||
char *newstr;
|
||||
|
@ -278,6 +282,9 @@ char *rewrite_string(const char *input, const struct rule *rules,
|
|||
int was_match = 0;
|
||||
int deadman = DEADMAN_MAX_STEPS;
|
||||
|
||||
/* Default error */
|
||||
*errmsg = "Remap table failure";
|
||||
|
||||
if ( verbosity >= 3 ) {
|
||||
syslog(LOG_INFO, "remap: input: %s", current);
|
||||
}
|
||||
|
@ -305,6 +312,17 @@ char *rewrite_string(const char *input, const struct rule *rules,
|
|||
syslog(LOG_INFO, "remap: rule %d: abort: %s",
|
||||
ruleptr->nrule, current);
|
||||
}
|
||||
if ( ruleptr->pattern[0] ) {
|
||||
/* Custom error message */
|
||||
len = genmatchstring(NULL, ruleptr->pattern, current,
|
||||
pmatch, macrosub);
|
||||
newstr = tfmalloc(len+1);
|
||||
genmatchstring(newstr, ruleptr->pattern, current,
|
||||
pmatch, macrosub);
|
||||
*errmsg = newstr;
|
||||
} else {
|
||||
*errmsg = NULL;
|
||||
}
|
||||
free(current);
|
||||
return(NULL);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ void freerules(struct rule *);
|
|||
|
||||
/* Execute a rule set on a string; returns a malloc'd new string. */
|
||||
char *rewrite_string(const char *, const struct rule *, int,
|
||||
match_pattern_callback);
|
||||
match_pattern_callback, const char **);
|
||||
|
||||
#endif /* WITH_REGEX */
|
||||
#endif /* TFTPD_REMAP_H */
|
||||
|
|
|
@ -114,7 +114,7 @@ static struct rule *rewrite_rules = NULL;
|
|||
#endif
|
||||
|
||||
int tftp(struct tftphdr *, int);
|
||||
void nak(int);
|
||||
static void nak(int, const char *);
|
||||
void timer(int);
|
||||
void justquit(int);
|
||||
void do_opt(char *, char *, char **);
|
||||
|
@ -683,14 +683,14 @@ main(int argc, char **argv)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
char *rewrite_access(char *, int);
|
||||
char *rewrite_access(char *, int, const char **);
|
||||
int validate_access(char *, int, struct formats *);
|
||||
void tftp_sendfile(struct formats *, struct tftphdr *, int);
|
||||
void tftp_recvfile(struct formats *, struct tftphdr *, int);
|
||||
|
||||
struct formats {
|
||||
const char *f_mode;
|
||||
char *(*f_rewrite)(char *, int);
|
||||
char *(*f_rewrite)(char *, int, const char **);
|
||||
int (*f_validate)(char *, int, struct formats *);
|
||||
void (*f_send)(struct formats *, struct tftphdr *, int);
|
||||
void (*f_recv)(struct formats *, struct tftphdr *, int);
|
||||
|
@ -712,6 +712,7 @@ tftp(struct tftphdr *tp, int size)
|
|||
struct formats *pf = NULL;
|
||||
char *origfilename;
|
||||
char *filename, *mode = NULL;
|
||||
const char *maperrmsg;
|
||||
|
||||
char *val = NULL, *opt = NULL;
|
||||
char *ap = ackbuf + 2;
|
||||
|
@ -727,7 +728,7 @@ tftp(struct tftphdr *tp, int size)
|
|||
} while (cp < buf + size && *cp);
|
||||
|
||||
if ( *cp ) {
|
||||
nak(EBADOP); /* Corrupt packet - no final NULL */
|
||||
nak(EBADOP, "Request not null-terminated");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -742,11 +743,12 @@ tftp(struct tftphdr *tp, int size)
|
|||
break;
|
||||
}
|
||||
if (!pf->f_mode) {
|
||||
nak(EBADOP);
|
||||
nak(EBADOP, "Unknown mode");
|
||||
exit(0);
|
||||
}
|
||||
if ( !(filename = (*pf->f_rewrite)(origfilename, tp->th_opcode)) ) {
|
||||
nak(EACCESS); /* File denied by mapping rule */
|
||||
if ( !(filename =
|
||||
(*pf->f_rewrite)(origfilename, tp->th_opcode, &maperrmsg)) ) {
|
||||
nak(EACCESS, maperrmsg); /* File denied by mapping rule */
|
||||
exit(0);
|
||||
}
|
||||
if ( verbosity >= 1 ) {
|
||||
|
@ -761,7 +763,7 @@ tftp(struct tftphdr *tp, int size)
|
|||
}
|
||||
ecode = (*pf->f_validate)(filename, tp->th_opcode, pf);
|
||||
if (ecode) {
|
||||
nak(ecode);
|
||||
nak(ecode, NULL);
|
||||
exit(0);
|
||||
}
|
||||
opt = ++cp;
|
||||
|
@ -774,7 +776,7 @@ tftp(struct tftphdr *tp, int size)
|
|||
}
|
||||
|
||||
if (!pf) {
|
||||
nak(EBADOP);
|
||||
nak(EBADOP, "Missing mode");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -946,13 +948,13 @@ do_opt(char *opt, char *val, char **ap)
|
|||
if (po->o_fnc(val, &ret)) {
|
||||
if (*ap + strlen(opt) + strlen(ret) + 2 >=
|
||||
ackbuf + sizeof(ackbuf)) {
|
||||
nak(ENOSPACE); /* EOPTNEG? */
|
||||
nak(EOPTNEG, "Insufficient space for options");
|
||||
exit(0);
|
||||
}
|
||||
*ap = strrchr(strcpy(strrchr(strcpy(*ap, opt),'\0') + 1,
|
||||
ret),'\0') + 1;
|
||||
} else {
|
||||
nak(EOPTNEG);
|
||||
nak(EOPTNEG, "Unsupported option(s) requested");
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
|
@ -999,11 +1001,11 @@ rewrite_macros(char macro, char *output)
|
|||
* Modify the filename, if applicable. If it returns NULL, deny the access.
|
||||
*/
|
||||
char *
|
||||
rewrite_access(char *filename, int mode)
|
||||
rewrite_access(char *filename, int mode, const char **msg)
|
||||
{
|
||||
if ( rewrite_rules ) {
|
||||
char *newname = rewrite_string(filename, rewrite_rules,
|
||||
mode != RRQ, rewrite_macros);
|
||||
char *newname = rewrite_string(filename, rewrite_rules, mode != RRQ,
|
||||
rewrite_macros, msg);
|
||||
filename = newname;
|
||||
}
|
||||
return filename;
|
||||
|
@ -1011,9 +1013,10 @@ rewrite_access(char *filename, int mode)
|
|||
|
||||
#else
|
||||
char *
|
||||
rewrite_access(char *filename, int mode)
|
||||
rewrite_access(char *filename, int mode, const char **msg)
|
||||
{
|
||||
(void)mode; /* Avoid warning */
|
||||
(void)msg;
|
||||
return filename;
|
||||
}
|
||||
#endif
|
||||
|
@ -1172,7 +1175,7 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
|||
do {
|
||||
size = readit(file, &dp, pf->f_convert);
|
||||
if (size < 0) {
|
||||
nak(errno + 100);
|
||||
nak(errno + 100, NULL);
|
||||
goto abort;
|
||||
}
|
||||
dp->th_opcode = htons((u_short)DATA);
|
||||
|
@ -1283,8 +1286,8 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
|||
/* size = write(file, dp->th_data, n - 4); */
|
||||
size = writeit(file, &dp, n - 4, pf->f_convert);
|
||||
if (size != (n-4)) { /* ahem */
|
||||
if (size < 0) nak(errno + 100);
|
||||
else nak(ENOSPACE);
|
||||
if (size < 0) nak(errno + 100, NULL);
|
||||
else nak(ENOSPACE, NULL);
|
||||
goto abort;
|
||||
}
|
||||
} while (size == segsize);
|
||||
|
@ -1308,21 +1311,19 @@ tftp_recvfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
|||
return;
|
||||
}
|
||||
|
||||
struct errmsg {
|
||||
int e_code;
|
||||
const char *e_msg;
|
||||
} errmsgs[] = {
|
||||
{ EUNDEF, "Undefined error code" },
|
||||
{ ENOTFOUND, "File not found" },
|
||||
{ EACCESS, "Access violation" },
|
||||
{ ENOSPACE, "Disk full or allocation exceeded" },
|
||||
{ EBADOP, "Illegal TFTP operation" },
|
||||
{ EBADID, "Unknown transfer ID" },
|
||||
{ EEXISTS, "File already exists" },
|
||||
{ ENOUSER, "No such user" },
|
||||
{ EOPTNEG, "Failure to negotiate RFC2347 options" },
|
||||
{ -1, 0 }
|
||||
static const char * const errmsgs[] =
|
||||
{
|
||||
"Undefined error code", /* 0 - EUNDEF */
|
||||
"File not found", /* 1 - ENOTFOUND */
|
||||
"Access denied", /* 2 - EACCESS */
|
||||
"Disk full or allocation exceeded", /* 3 - ENOSPACE */
|
||||
"Illegal TFTP operation", /* 4 - EBADOP */
|
||||
"Unknown transfer ID", /* 5 - EBADID */
|
||||
"File already exists", /* 6 - EEXISTS */
|
||||
"No such user", /* 7 - ENOUSER */
|
||||
"Failure to negotiate RFC2347 options" /* 8 - EOPTNEG */
|
||||
};
|
||||
#define ERR_CNT (sizeof(errmsgs)/sizeof(const char *))
|
||||
|
||||
/*
|
||||
* Send a nak packet (error message).
|
||||
|
@ -1330,27 +1331,29 @@ struct errmsg {
|
|||
* standard TFTP codes, or a UNIX errno
|
||||
* offset by 100.
|
||||
*/
|
||||
void
|
||||
nak(int error)
|
||||
static void
|
||||
nak(int error, const char *msg)
|
||||
{
|
||||
struct tftphdr *tp;
|
||||
int length;
|
||||
struct errmsg *pe;
|
||||
|
||||
tp = (struct tftphdr *)buf;
|
||||
tp->th_opcode = htons((u_short)ERROR);
|
||||
tp->th_code = htons((u_short)error);
|
||||
for (pe = errmsgs; pe->e_code >= 0; pe++)
|
||||
if (pe->e_code == error)
|
||||
break;
|
||||
if (pe->e_code < 0) {
|
||||
pe->e_msg = strerror(error - 100);
|
||||
tp->th_code = EUNDEF; /* set 'undef' errorcode */
|
||||
if ( !msg ) {
|
||||
if ( error >= 100 ) {
|
||||
/* This is a Unix errno+100 */
|
||||
msg = strerror(error - 100);
|
||||
tp->th_code = EUNDEF;
|
||||
} else {
|
||||
if ( (unsigned)error >= ERR_CNT )
|
||||
tp->th_code = error = EUNDEF;
|
||||
msg = errmsgs[error];
|
||||
}
|
||||
}
|
||||
strcpy(tp->th_msg, pe->e_msg);
|
||||
length = strlen(pe->e_msg);
|
||||
tp->th_msg[length] = '\0';
|
||||
length += 5;
|
||||
length = strlen(msg)+1;
|
||||
memcpy(tp->th_msg, msg, length);
|
||||
length += 4; /* Add space for header */
|
||||
|
||||
if ( verbosity >= 2 ) {
|
||||
syslog(LOG_INFO, "sending NAK (%d, %s) to %s",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue