summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clientserver.c8
-rw-r--r--flist.c11
-rw-r--r--util.c90
3 files changed, 75 insertions, 34 deletions
diff --git a/clientserver.c b/clientserver.c
index ace360b4..84252432 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -25,6 +25,7 @@ extern int read_only;
extern int verbose;
extern int rsync_port;
char *auth_user;
+int sanitize_paths = 0;
int start_socket_client(char *host, char *path, int argc, char *argv[])
{
@@ -221,6 +222,7 @@ static int rsync_module(int fd, int i)
io_printf(fd,"@ERROR: chdir failed\n");
return -1;
}
+ sanitize_paths = 1;
}
if (am_root) {
@@ -262,7 +264,7 @@ static int rsync_module(int fd, int i)
request = strdup(p);
start_glob++;
}
- glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
+ glob_expand(name, argv, &argc, MAX_ARGS);
} else {
argc++;
}
@@ -276,7 +278,7 @@ static int rsync_module(int fd, int i)
}
}
- if (!use_chroot) {
+ if (sanitize_paths) {
/*
* Note that this is applied to all parameters, whether or not
* they are filenames, but no other legal parameters contain
@@ -285,7 +287,7 @@ static int rsync_module(int fd, int i)
* and which aren't.
*/
for (i = 1; i < argc; i++) {
- sanitize_path(argv[i]);
+ sanitize_path(argv[i], NULL);
}
}
diff --git a/flist.c b/flist.c
index b8b4c666..861fb2fe 100644
--- a/flist.c
+++ b/flist.c
@@ -45,6 +45,7 @@ extern int copy_links;
extern int copy_unsafe_links;
extern int remote_version;
extern int io_error;
+extern int sanitize_paths;
static char topsrcname[MAXPATHLEN];
@@ -309,6 +310,10 @@ static void receive_file_entry(struct file_struct **fptr,
clean_fname(thisname);
+ if (sanitize_paths) {
+ sanitize_path(thisname, NULL);
+ }
+
if ((p = strrchr(thisname,'/'))) {
static char *lastdir;
*p = 0;
@@ -343,6 +348,9 @@ static void receive_file_entry(struct file_struct **fptr,
file->link = (char *)malloc(l+1);
if (!file->link) out_of_memory("receive_file_entry 2");
read_sbuf(f,file->link,l);
+ if (sanitize_paths) {
+ sanitize_path(file->link, file->dirname);
+ }
}
#if SUPPORT_HARD_LINKS
@@ -414,6 +422,9 @@ static struct file_struct *make_file(int f, char *fname)
strlcpy(cleaned_name, fname, MAXPATHLEN);
cleaned_name[MAXPATHLEN-1] = 0;
clean_fname(cleaned_name);
+ if (sanitize_paths) {
+ sanitize_path(cleaned_name, NULL);
+ }
fname = cleaned_name;
memset(sum,0,SUM_LENGTH);
diff --git a/util.c b/util.c
index 86ee3f0c..974e8651 100644
--- a/util.c
+++ b/util.c
@@ -477,7 +477,7 @@ int lock_range(int fd, int offset, int len)
}
-static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sanitize_paths)
+static void glob_expand_one(char *s, char **argv, int *argc, int maxargs)
{
#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H))
if (!*s) s = ".";
@@ -485,14 +485,16 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sa
(*argc)++;
return;
#else
+ extern int sanitize_paths;
glob_t globbuf;
int i;
if (!*s) s = ".";
- s = strdup(s);
- sanitize_path(s);
- argv[*argc] = s;
+ argv[*argc] = strdup(s);
+ if (sanitize_paths) {
+ sanitize_path(argv[*argc], NULL);
+ }
memset(&globbuf, 0, sizeof(globbuf));
glob(argv[*argc], 0, NULL, &globbuf);
@@ -511,7 +513,7 @@ static void glob_expand_one(char *s, char **argv, int *argc, int maxargs, int sa
#endif
}
-void glob_expand(char *base1, char **argv, int *argc, int maxargs, int sanitize_paths)
+void glob_expand(char *base1, char **argv, int *argc, int maxargs)
{
char *s = argv[*argc];
char *p, *q;
@@ -535,11 +537,11 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs, int sanitize_
while ((p = strstr(q,base)) && ((*argc) < maxargs)) {
/* split it at this point */
*p = 0;
- glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
+ glob_expand_one(q, argv, argc, maxargs);
q = p+strlen(base);
}
- if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs, sanitize_paths);
+ if (*q && (*argc < maxargs)) glob_expand_one(q, argv, argc, maxargs);
free(s);
free(base);
@@ -635,8 +637,11 @@ void clean_fname(char *name)
/*
* Make path appear as if a chroot had occurred:
* 1. remove leading "/" (or replace with "." if at end)
- * 2. remove leading ".." components
+ * 2. remove leading ".." components (except those allowed by "reldir")
* 3. delete any other "<dir>/.." (recursively)
+ * If "reldir" is non-null, it is a sanitized directory that the path will be
+ * relative to, so allow as many ".." at the beginning of the path as
+ * there are components in reldir.
* While we're at it, remove double slashes and "." components like
* clean_fname does(), but DON'T remove a trailing slash because that
* is sometimes significant on command line arguments.
@@ -644,10 +649,20 @@ void clean_fname(char *name)
* Contributed by Dave Dykstra <dwd@bell-labs.com>
*/
-void sanitize_path(char *p)
+void sanitize_path(char *p, char *reldir)
{
char *start, *sanp;
+ int depth = 0;
+ int allowdotdot = 0;
+ if (reldir) {
+ depth++;
+ while (*reldir) {
+ if (*reldir++ == '/') {
+ depth++;
+ }
+ }
+ }
start = p;
sanp = p;
while (*p == '/') {
@@ -665,35 +680,48 @@ void sanitize_path(char *p)
/* skip following slashes */
;
}
- } else if ((*p == '.') && (*(p+1) == '.') &&
+ continue;
+ }
+ allowdotdot = 0;
+ if ((*p == '.') && (*(p+1) == '.') &&
((*(p+2) == '/') || (*(p+2) == '\0'))) {
- /* skip ".." component followed by slash or end */
- p += 2;
- if (*p == '/')
- p++;
- if (sanp != start) {
- /* back up sanp one level */
- --sanp; /* now pointing at slash */
- while ((sanp > start) && (*(sanp - 1) != '/')) {
- /* skip back up to slash */
- sanp--;
+ /* ".." component followed by slash or end */
+ if ((depth > 0) && (sanp == start)) {
+ /* allow depth levels of .. at the beginning */
+ --depth;
+ allowdotdot = 1;
+ } else {
+ p += 2;
+ if (*p == '/')
+ p++;
+ if (sanp != start) {
+ /* back up sanp one level */
+ --sanp; /* now pointing at slash */
+ while ((sanp > start) && (*(sanp - 1) != '/')) {
+ /* skip back up to slash */
+ sanp--;
+ }
}
+ continue;
}
- } else {
- while (1) {
- /* copy one component through next slash */
- *sanp++ = *p++;
- if ((*p == '\0') || (*(p-1) == '/')) {
- while (*p == '/') {
- /* skip multiple slashes */
- p++;
- }
- break;
+ }
+ while (1) {
+ /* copy one component through next slash */
+ *sanp++ = *p++;
+ if ((*p == '\0') || (*(p-1) == '/')) {
+ while (*p == '/') {
+ /* skip multiple slashes */
+ p++;
}
+ break;
}
}
+ if (allowdotdot) {
+ /* move the virtual beginning to leave the .. alone */
+ start = sanp;
+ }
}
- if (sanp == start) {
+ if ((sanp == start) && !allowdotdot) {
/* ended up with nothing, so put in "." component */
*sanp++ = '.';
}