summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2004-06-21 08:01:16 +0000
committerbrian <brian@FreeBSD.org>2004-06-21 08:01:16 +0000
commit86ff38aa6a16b0d64c479830cee246b451837992 (patch)
treeb23d0d3ee239998bb689eb262cc2b53c953a4434
parent05c25483b4784c8f5df796f4494e20e8c408d1d6 (diff)
downloadFreeBSD-src-86ff38aa6a16b0d64c479830cee246b451837992.zip
FreeBSD-src-86ff38aa6a16b0d64c479830cee246b451837992.tar.gz
o Reduce path names in RRQ and WRQ packets by:
Reducing "/+./" strings to "/" Reducing "/[^/]+/../" to "/" o Don't send an OACK when the result of the [RW]RQ is an error. These changes allow tftpd to interact with pxelinux.bin from the syslinux package. Whilst the path reducing code doesn't properly handle situations where the path component before the "/../" is a symlink to (say) ".", I would suggest that it does the right thing in terms of the clients perception of what their path string actually represents. This seems better than using realpath() and breaking environments where symlinks point outside of the directory hierarchy that tftpd is configured to allow.
-rw-r--r--libexec/tftpd/tftpd.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
index 7eadc9f..0067287 100644
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -329,6 +329,37 @@ main(int argc, char *argv[])
exit(1);
}
+static void
+reduce_path(char *fn)
+{
+ char *slash, *ptr;
+
+ /* Reduce all "/+./" to "/" (just in case we've got "/./../" later */
+ while ((slash = strstr(fn, "/./")) != NULL) {
+ for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
+ ;
+ slash += 2;
+ while (*slash)
+ *++ptr = *++slash;
+ }
+
+ /* Now reduce all "/something/+../" to "/" */
+ while ((slash = strstr(fn, "/../")) != NULL) {
+ if (slash == fn)
+ break;
+ for (ptr = slash; ptr > fn && ptr[-1] == '/'; ptr--)
+ ;
+ for (ptr--; ptr >= fn; ptr--)
+ if (*ptr == '/')
+ break;
+ if (ptr < fn)
+ break;
+ slash += 3;
+ while (*slash)
+ *++ptr = *++slash;
+ }
+}
+
struct formats;
int validate_access(char **, int);
void xmitfile(struct formats *);
@@ -374,7 +405,7 @@ tftp(struct tftphdr *tp, int size)
int i, first = 1, has_options = 0, ecode;
struct formats *pf;
char *filename, *mode, *option, *ccp;
- char fnbuf[MAXPATHLEN];
+ char fnbuf[PATH_MAX], resolved_fnbuf[PATH_MAX];
cp = tp->th_stuff;
again:
@@ -394,6 +425,7 @@ again:
}
memcpy(fnbuf, tp->th_stuff, i);
fnbuf[i] = '\0';
+ reduce_path(fnbuf);
filename = fnbuf;
if (first) {
mode = ++cp;
@@ -449,7 +481,7 @@ option_fail:
}
ecode = (*pf->f_validate)(&filename, tp->th_opcode);
- if (has_options)
+ if (has_options && ecode == 0)
oack();
if (logging) {
char hbuf[NI_MAXHOST];
OpenPOWER on IntegriCloud