forked from mirrors/tftp-hpa-google
More error message improvements; work around a suspect Solaris compiler bug
This commit is contained in:
parent
8036d9e857
commit
0f52cd8fa4
2 changed files with 45 additions and 27 deletions
|
@ -57,7 +57,7 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
struct sockaddr_in *myaddr)
|
struct sockaddr_in *myaddr)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov[1];
|
struct iovec iov;
|
||||||
int n;
|
int n;
|
||||||
struct cmsghdr *cmptr;
|
struct cmsghdr *cmptr;
|
||||||
union {
|
union {
|
||||||
|
@ -82,15 +82,16 @@ myrecvfrom(int s, void *buf, int len, unsigned int flags,
|
||||||
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bzero(&msg, sizeof msg); /* Clear possible system-dependent fields */
|
||||||
msg.msg_control = control_un.control;
|
msg.msg_control = control_un.control;
|
||||||
msg.msg_controllen = sizeof(control_un.control);
|
msg.msg_controllen = sizeof(control_un.control);
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
||||||
msg.msg_name = from;
|
msg.msg_name = from;
|
||||||
msg.msg_namelen = *fromlen;
|
msg.msg_namelen = *fromlen;
|
||||||
iov[0].iov_base = buf;
|
iov.iov_base = buf;
|
||||||
iov[0].iov_len = len;
|
iov.iov_len = len;
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = &iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
if ( (n = recvmsg(s, &msg, flags)) < 0 )
|
if ( (n = recvmsg(s, &msg, flags)) < 0 )
|
||||||
|
|
|
@ -458,7 +458,7 @@ main(int argc, char **argv)
|
||||||
exit(EX_OSERR);
|
exit(EX_OSERR);
|
||||||
}
|
}
|
||||||
nfd = open("/dev/null", O_RDWR);
|
nfd = open("/dev/null", O_RDWR);
|
||||||
if ( nfd >= 0 ) {
|
if ( nfd >= 3 ) {
|
||||||
#ifdef HAVE_DUP2
|
#ifdef HAVE_DUP2
|
||||||
dup2(nfd, 0);
|
dup2(nfd, 0);
|
||||||
dup2(nfd, 1);
|
dup2(nfd, 1);
|
||||||
|
@ -469,7 +469,7 @@ main(int argc, char **argv)
|
||||||
close(2); dup(nfd);
|
close(2); dup(nfd);
|
||||||
#endif
|
#endif
|
||||||
close(nfd);
|
close(nfd);
|
||||||
} else {
|
} else if ( nfd < 0 ) {
|
||||||
close(0); close(1); close(2);
|
close(0); close(1); close(2);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_SETSID
|
#ifdef HAVE_SETSID
|
||||||
|
@ -684,14 +684,14 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
char *rewrite_access(char *, int, const char **);
|
char *rewrite_access(char *, int, const char **);
|
||||||
int validate_access(char *, int, struct formats *);
|
int validate_access(char *, int, struct formats *, const char **);
|
||||||
void tftp_sendfile(struct formats *, struct tftphdr *, int);
|
void tftp_sendfile(struct formats *, struct tftphdr *, int);
|
||||||
void tftp_recvfile(struct formats *, struct tftphdr *, int);
|
void tftp_recvfile(struct formats *, struct tftphdr *, int);
|
||||||
|
|
||||||
struct formats {
|
struct formats {
|
||||||
const char *f_mode;
|
const char *f_mode;
|
||||||
char *(*f_rewrite)(char *, int, const char **);
|
char *(*f_rewrite)(char *, int, const char **);
|
||||||
int (*f_validate)(char *, int, struct formats *);
|
int (*f_validate)(char *, int, struct formats *, const char **);
|
||||||
void (*f_send)(struct formats *, struct tftphdr *, int);
|
void (*f_send)(struct formats *, struct tftphdr *, int);
|
||||||
void (*f_recv)(struct formats *, struct tftphdr *, int);
|
void (*f_recv)(struct formats *, struct tftphdr *, int);
|
||||||
int f_convert;
|
int f_convert;
|
||||||
|
@ -707,12 +707,12 @@ struct formats {
|
||||||
int
|
int
|
||||||
tftp(struct tftphdr *tp, int size)
|
tftp(struct tftphdr *tp, int size)
|
||||||
{
|
{
|
||||||
char *cp;
|
char *cp, *end;
|
||||||
int argn, ecode;
|
int argn, ecode;
|
||||||
struct formats *pf = NULL;
|
struct formats *pf = NULL;
|
||||||
char *origfilename;
|
char *origfilename;
|
||||||
char *filename, *mode = NULL;
|
char *filename, *mode = NULL;
|
||||||
const char *maperrmsg;
|
const char *errmsgptr;
|
||||||
|
|
||||||
char *val = NULL, *opt = NULL;
|
char *val = NULL, *opt = NULL;
|
||||||
char *ap = ackbuf + 2;
|
char *ap = ackbuf + 2;
|
||||||
|
@ -722,10 +722,12 @@ tftp(struct tftphdr *tp, int size)
|
||||||
origfilename = cp = (char *) &(tp->th_stuff);
|
origfilename = cp = (char *) &(tp->th_stuff);
|
||||||
argn = 0;
|
argn = 0;
|
||||||
|
|
||||||
while ( cp < buf + size && *cp ) {
|
end = (char *)tp + size;
|
||||||
|
|
||||||
|
while ( cp < end && *cp ) {
|
||||||
do {
|
do {
|
||||||
cp++;
|
cp++;
|
||||||
} while (cp < buf + size && *cp);
|
} while (cp < end && *cp);
|
||||||
|
|
||||||
if ( *cp ) {
|
if ( *cp ) {
|
||||||
nak(EBADOP, "Request not null-terminated");
|
nak(EBADOP, "Request not null-terminated");
|
||||||
|
@ -747,8 +749,8 @@ tftp(struct tftphdr *tp, int size)
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
if ( !(filename =
|
if ( !(filename =
|
||||||
(*pf->f_rewrite)(origfilename, tp->th_opcode, &maperrmsg)) ) {
|
(*pf->f_rewrite)(origfilename, tp->th_opcode, &errmsgptr)) ) {
|
||||||
nak(EACCESS, maperrmsg); /* File denied by mapping rule */
|
nak(EACCESS, errmsgptr); /* File denied by mapping rule */
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
if ( verbosity >= 1 ) {
|
if ( verbosity >= 1 ) {
|
||||||
|
@ -761,9 +763,9 @@ tftp(struct tftphdr *tp, int size)
|
||||||
tp->th_opcode == WRQ ? "WRQ" : "RRQ",
|
tp->th_opcode == WRQ ? "WRQ" : "RRQ",
|
||||||
inet_ntoa(from.sin_addr), origfilename, filename);
|
inet_ntoa(from.sin_addr), origfilename, filename);
|
||||||
}
|
}
|
||||||
ecode = (*pf->f_validate)(filename, tp->th_opcode, pf);
|
ecode = (*pf->f_validate)(filename, tp->th_opcode, pf, &errmsgptr);
|
||||||
if (ecode) {
|
if (ecode) {
|
||||||
nak(ecode, NULL);
|
nak(ecode, errmsgptr);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
opt = ++cp;
|
opt = ++cp;
|
||||||
|
@ -1034,7 +1036,8 @@ FILE *file;
|
||||||
* given as we have no login directory.
|
* given as we have no login directory.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
validate_access(char *filename, int mode, struct formats *pf)
|
validate_access(char *filename, int mode,
|
||||||
|
struct formats *pf, const char **errmsg)
|
||||||
{
|
{
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
int i, len;
|
int i, len;
|
||||||
|
@ -1044,10 +1047,14 @@ validate_access(char *filename, int mode, struct formats *pf)
|
||||||
char stdio_mode[3];
|
char stdio_mode[3];
|
||||||
|
|
||||||
tsize_ok = 0;
|
tsize_ok = 0;
|
||||||
|
*errmsg = NULL;
|
||||||
|
|
||||||
if (!secure) {
|
if (!secure) {
|
||||||
if (*filename != '/')
|
if (*filename != '/') {
|
||||||
|
*errmsg = "Only absolute filenames allowed";
|
||||||
return (EACCESS);
|
return (EACCESS);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prevent tricksters from getting around the directory
|
* prevent tricksters from getting around the directory
|
||||||
* restrictions
|
* restrictions
|
||||||
|
@ -1055,15 +1062,19 @@ validate_access(char *filename, int mode, struct formats *pf)
|
||||||
len = strlen(filename);
|
len = strlen(filename);
|
||||||
for ( i = 1 ; i < len-3 ; i++ ) {
|
for ( i = 1 ; i < len-3 ; i++ ) {
|
||||||
cp = filename + i;
|
cp = filename + i;
|
||||||
if ( *cp == '.' && memcmp(cp-1, "/../", 4) == 0)
|
if ( *cp == '.' && memcmp(cp-1, "/../", 4) == 0 ) {
|
||||||
|
*errmsg = "Reverse path not allowed";
|
||||||
return(EACCESS);
|
return(EACCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (dirp = dirs; *dirp; dirp++)
|
for (dirp = dirs; *dirp; dirp++)
|
||||||
if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
|
if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
|
||||||
break;
|
break;
|
||||||
if (*dirp==0 && dirp!=dirs)
|
if (*dirp==0 && dirp!=dirs) {
|
||||||
|
*errmsg = "Forbidden directory";
|
||||||
return (EACCESS);
|
return (EACCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1088,7 +1099,7 @@ validate_access(char *filename, int mode, struct formats *pf)
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
return EEXISTS;
|
return EEXISTS;
|
||||||
default:
|
default:
|
||||||
return EACCESS;
|
return errno+100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,20 +1107,26 @@ validate_access(char *filename, int mode, struct formats *pf)
|
||||||
exit(EX_OSERR); /* This shouldn't happen */
|
exit(EX_OSERR); /* This shouldn't happen */
|
||||||
|
|
||||||
if (mode == RRQ) {
|
if (mode == RRQ) {
|
||||||
if ( !unixperms && (stbuf.st_mode & (S_IREAD >> 6)) == 0 )
|
if ( !unixperms && (stbuf.st_mode & (S_IREAD >> 6)) == 0 ) {
|
||||||
|
*errmsg = "File must have global read permissions";
|
||||||
return (EACCESS);
|
return (EACCESS);
|
||||||
|
}
|
||||||
tsize = stbuf.st_size;
|
tsize = stbuf.st_size;
|
||||||
/* We don't know the tsize if conversion is needed */
|
/* We don't know the tsize if conversion is needed */
|
||||||
tsize_ok = !pf->f_convert;
|
tsize_ok = !pf->f_convert;
|
||||||
} else {
|
} else {
|
||||||
if ( !unixperms ) {
|
if ( !unixperms ) {
|
||||||
if ( (stbuf.st_mode & (S_IWRITE >> 6)) == 0 )
|
if ( (stbuf.st_mode & (S_IWRITE >> 6)) == 0 ) {
|
||||||
|
*errmsg = "File must have global write permissions";
|
||||||
return (EACCESS);
|
return (EACCESS);
|
||||||
|
}
|
||||||
|
|
||||||
/* We didn't get to truncate the file at open() time */
|
/* We didn't get to truncate the file at open() time */
|
||||||
#ifdef HAVE_FTRUNCATE
|
#ifdef HAVE_FTRUNCATE
|
||||||
if ( ftruncate(fd, (off_t)0) )
|
if ( ftruncate(fd, (off_t)0) ) {
|
||||||
|
*errmsg = "Cannot reset file size";
|
||||||
return(EACCESS);
|
return(EACCESS);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
tsize = 0;
|
tsize = 0;
|
||||||
|
@ -1138,8 +1155,6 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
static u_short block = 1; /* Static to avoid longjmp funnies */
|
static u_short block = 1; /* Static to avoid longjmp funnies */
|
||||||
int size, n;
|
int size, n;
|
||||||
|
|
||||||
ap = (struct tftphdr *)ackbuf;
|
|
||||||
|
|
||||||
if (oap) {
|
if (oap) {
|
||||||
timeout = rexmtval;
|
timeout = rexmtval;
|
||||||
(void)sigsetjmp(timeoutbuf,1);
|
(void)sigsetjmp(timeoutbuf,1);
|
||||||
|
@ -1154,6 +1169,7 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
syslog(LOG_WARNING, "tftpd: read: %m\n");
|
syslog(LOG_WARNING, "tftpd: read: %m\n");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
ap = (struct tftphdr *)ackbuf;
|
||||||
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
||||||
ap->th_block = ntohs((u_short)ap->th_block);
|
ap->th_block = ntohs((u_short)ap->th_block);
|
||||||
|
|
||||||
|
@ -1194,6 +1210,7 @@ tftp_sendfile(struct formats *pf, struct tftphdr *oap, int oacklen)
|
||||||
syslog(LOG_WARNING, "tftpd: read(ack): %m");
|
syslog(LOG_WARNING, "tftpd: read(ack): %m");
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
ap = (struct tftphdr *)ackbuf;
|
||||||
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
ap->th_opcode = ntohs((u_short)ap->th_opcode);
|
||||||
ap->th_block = ntohs((u_short)ap->th_block);
|
ap->th_block = ntohs((u_short)ap->th_block);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue