added the --safe-links option to disallow symlinks outside the
authorAndrew Tridgell <tridge@samba.org>
Fri, 17 Jul 1998 10:00:48 +0000 (10:00 +0000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 17 Jul 1998 10:00:48 +0000 (10:00 +0000)
destination tree

rsync.yo
util.c

index 36d8590..b6f1d16 100644 (file)
--- a/rsync.yo
+++ b/rsync.yo
@@ -315,11 +315,6 @@ option all symbolic links are skipped.
 dit(bf(-L, --copy-links)) This tells rsync to treat symbolic links just
 like  ordinary files.
 
-dit(bf(--safe-links)) This tells rsync to ignore any symbolic links
-which point outside the destination tree. All absolute symlinks are
-also ignored. Using this option in conjunction with --relative may
-give unexpecetd results. 
-
 dit(bf(-H, --hard-links)) This tells rsync to recreate hard  links  on
 the  remote system  to  be the same as the local system. Without this
 option hard links are treated like regular files.
diff --git a/util.c b/util.c
index 15ab69d..bfa35f1 100644 (file)
--- a/util.c
+++ b/util.c
@@ -710,3 +710,50 @@ void show_progress(OFF_T ofs, OFF_T size)
                }
        }
 }
+
+/* determine if a symlink points outside the current directory tree */
+int unsafe_symlink(char *dest, char *src)
+{
+       char *tok;
+       int depth = 0;
+
+       /* all absolute and null symlinks are unsafe */
+       if (!dest || !(*dest) || (*dest == '/')) return 1;
+
+       src = strdup(src);
+       if (!src) out_of_memory("unsafe_symlink");
+
+       /* find out what our safety margin is */
+       for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) {
+               if (strcmp(tok,"..") == 0) {
+                       depth=0;
+               } else if (strcmp(tok,".") == 0) {
+                       /* nothing */
+               } else {
+                       depth++;
+               }
+       }
+       free(src);
+
+       /* drop by one to account for the filename portion */
+       depth--;
+
+       dest = strdup(dest);
+       if (!dest) out_of_memory("unsafe_symlink");
+
+       for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) {
+               if (strcmp(tok,"..") == 0) {
+                       depth--;
+               } else if (strcmp(tok,".") == 0) {
+                       /* nothing */
+               } else {
+                       depth++;
+               }
+               /* if at any point we go outside the current directory then
+                  stop - it is unsafe */
+               if (depth < 0) break;
+       }
+
+       free(dest);
+       return (depth < 0);
+}