aboutsummaryrefslogtreecommitdiff
path: root/libexec/tftpd
diff options
context:
space:
mode:
authorBrian Somers <brian@FreeBSD.org>2004-06-21 08:01:16 +0000
committerBrian Somers <brian@FreeBSD.org>2004-06-21 08:01:16 +0000
commit7bc7e0c85e9a52a347fb79e4af0f31879355d3ce (patch)
treeb23d0d3ee239998bb689eb262cc2b53c953a4434 /libexec/tftpd
parentf46519d1c1446cd5863857a7217c7f6a4025c372 (diff)
downloadsrc-7bc7e0c85e9a52a347fb79e4af0f31879355d3ce.tar.gz
src-7bc7e0c85e9a52a347fb79e4af0f31879355d3ce.zip
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.
Notes
Notes: svn path=/head/; revision=130834
Diffstat (limited to 'libexec/tftpd')
-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 7eadc9f59c2e..00672872bb99 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];