X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/0ecfbf27c3b9e01d498201e90e7d0a89a9d0a47c..e72b18a9bd9f89847e49e87c1159c74d7bf0fbf3:/util.c diff --git a/util.c b/util.c index 00670db4..e5638f05 100644 --- a/util.c +++ b/util.c @@ -301,16 +301,15 @@ int copy_file(char *source, char *dest, mode_t mode) #define MAX_RENAMES 1000 /** - * - Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so - rename to /.rsyncNNN instead. - - Note that successive rsync runs will shuffle the filenames around a - bit as long as the file is still busy; this is because this function - does not know if the unlink call is due to a new file coming in, or - --delete trying to remove old .rsyncNNN files, hence it renames it - each time. -*/ + * Robust unlink: some OS'es (HPUX) refuse to unlink busy files, so + * rename to /.rsyncNNN instead. + * + * Note that successive rsync runs will shuffle the filenames around a + * bit as long as the file is still busy; this is because this function + * does not know if the unlink call is due to a new file coming in, or + * --delete trying to remove old .rsyncNNN files, hence it renames it + * each time. + **/ int robust_unlink(char *fname) { #ifndef ETXTBSY @@ -533,7 +532,8 @@ void glob_expand(char *base1, char **argv, int *argc, int maxargs) void strlower(char *s) { while (*s) { - if (isupper(*s)) *s = tolower(*s); + if (isupper(* (unsigned char *) s)) + *s = tolower(* (unsigned char *) s); s++; } } @@ -590,17 +590,19 @@ 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 (except those allowed by "reldir") - * 3. delete any other "/.." (recursively) + * @li 1. remove leading "/" (or replace with "." if at end) + * + * @li 2. remove leading ".." components (except those allowed by @p reldir) + * + * @li 3. delete any other "/.." (recursively) * * Can only shrink paths, so sanitizes in place. * * While we're at it, remove double slashes and "." components like - * clean_fname does(), but DON'T remove a trailing slash because that + * clean_fname() does, but DON'T remove a trailing slash because that * is sometimes significant on command line arguments. * - * If "reldir" is non-null, it is a sanitized directory that the path will be + * If @p 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. This is used for symbolic link targets. * If reldir is non-null and the path began with "/", to be completely like @@ -699,8 +701,10 @@ void sanitize_path(char *p, char *reldir) static char curr_dir[MAXPATHLEN]; -/** like chdir() but can be reversed with pop_dir() if save is set. It - is also much faster as it remembers where we have been */ +/** + * Like chdir() but can be reversed with pop_dir() if @p save is set. + * It is also much faster as it remembers where we have been. + **/ char *push_dir(char *dir, int save) { char *ret = curr_dir; @@ -731,7 +735,7 @@ char *push_dir(char *dir, int save) return ret; } -/** Reverse a push_dir call */ +/** Reverse a push_dir() call */ int pop_dir(char *dir) { int ret; @@ -771,6 +775,13 @@ int u_strcmp(const char *cs1, const char *cs2) * else's machine it might allow them to establish a symlink to * /etc/passwd, and then read it through a web server. * + * Null symlinks and absolute symlinks are always unsafe. + * + * Basically here we are concerned with symlinks whose target contains + * "..", because this might cause us to walk back up out of the + * transferred directory. We are not allowed to go back up and + * reenter. + * * @param dest Target of the symlink in question. * * @param src Top source directory currently applicable. Basically this @@ -779,57 +790,52 @@ int u_strcmp(const char *cs1, const char *cs2) * * @retval True if unsafe * @retval False is unsafe + * + * @sa t_unsafe.c **/ -int unsafe_symlink(char *dest, char *src) +int unsafe_symlink(const char *dest, const char *src) { - char *tok; + const char *name, *slash; 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"); + if (!dest || !*dest || *dest == '/') return 1; /* find out what our safety margin is */ - for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) { - if (strcmp(tok,"..") == 0) { + for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) { + if (strncmp(name, "../", 3) == 0) { depth=0; - } else if (strcmp(tok,".") == 0) { + } else if (strncmp(name, "./", 2) == 0) { /* nothing */ } else { depth++; } } - free(src); + if (strcmp(name, "..") == 0) + depth = 0; - /* 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) { + for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) { + if (strncmp(name, "../", 3) == 0) { + /* if at any point we go outside the current directory + then stop - it is unsafe */ + if (--depth < 0) + return 1; + } else if (strncmp(name, "./", 2) == 0) { /* nothing */ } else { depth++; } - /* if at any point we go outside the current directory then - stop - it is unsafe */ - if (depth < 0) break; } + if (strcmp(name, "..") == 0) + depth--; - free(dest); return (depth < 0); } /** - Return the date and time as a string -*/ + * Return the date and time as a string + **/ char *timestring(time_t t) { static char TimeBuf[200];