Matt McCutchen's Web Site
/
rsync
/
rsync.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Die if we sent --max-delete=0 to a receiving side that is too old.
[rsync/rsync.git]
/
util.c
diff --git
a/util.c
b/util.c
index
42e0238
..
540fdf5
100644
(file)
--- a/
util.c
+++ b/
util.c
@@
-29,18
+29,23
@@
extern int module_id;
extern int modify_window;
extern int relative_paths;
extern int human_readable;
extern int modify_window;
extern int relative_paths;
extern int human_readable;
+extern unsigned int module_dirlen;
extern mode_t orig_umask;
extern char *partial_dir;
extern struct filter_list_struct server_filter_list;
int sanitize_paths = 0;
extern mode_t orig_umask;
extern char *partial_dir;
extern struct filter_list_struct server_filter_list;
int sanitize_paths = 0;
+char curr_dir[MAXPATHLEN];
+unsigned int curr_dir_len;
+int curr_dir_depth; /* This is only set for a sanitizing daemon. */
+
/* Set a fd into nonblocking mode. */
void set_nonblocking(int fd)
{
int val;
/* Set a fd into nonblocking mode. */
void set_nonblocking(int fd)
{
int val;
- if ((val = fcntl(fd, F_GETFL
, 0
)) == -1)
+ if ((val = fcntl(fd, F_GETFL)) == -1)
return;
if (!(val & NONBLOCK_FLAG)) {
val |= NONBLOCK_FLAG;
return;
if (!(val & NONBLOCK_FLAG)) {
val |= NONBLOCK_FLAG;
@@
-53,7
+58,7
@@
void set_blocking(int fd)
{
int val;
{
int val;
- if ((val = fcntl(fd, F_GETFL
, 0
)) == -1)
+ if ((val = fcntl(fd, F_GETFL)) == -1)
return;
if (val & NONBLOCK_FLAG) {
val &= ~NONBLOCK_FLAG;
return;
if (val & NONBLOCK_FLAG) {
val &= ~NONBLOCK_FLAG;
@@
-87,7
+92,7
@@
int fd_pair(int fd[2])
void print_child_argv(char **cmd)
{
void print_child_argv(char **cmd)
{
- rprintf(F
INFO
, "opening connection using ");
+ rprintf(F
CLIENT
, "opening connection using ");
for (; *cmd; cmd++) {
/* Look for characters that ought to be quoted. This
* is not a great quoting algorithm, but it's
for (; *cmd; cmd++) {
/* Look for characters that ought to be quoted. This
* is not a great quoting algorithm, but it's
@@
-96,23
+101,23
@@
void print_child_argv(char **cmd)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
",.-_=+@/") != strlen(*cmd)) {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
",.-_=+@/") != strlen(*cmd)) {
- rprintf(F
INFO
, "\"%s\" ", *cmd);
+ rprintf(F
CLIENT
, "\"%s\" ", *cmd);
} else {
} else {
- rprintf(F
INFO
, "%s ", *cmd);
+ rprintf(F
CLIENT
, "%s ", *cmd);
}
}
}
}
- rprintf(F
INFO
, "\n");
+ rprintf(F
CLIENT
, "\n");
}
}
-void out_of_memory(char *str)
+
NORETURN
void out_of_memory(char *str)
{
{
- rprintf(FERROR, "ERROR: out of memory in %s
\n", str
);
+ rprintf(FERROR, "ERROR: out of memory in %s
[%s]\n", str, who_am_i()
);
exit_cleanup(RERR_MALLOC);
}
exit_cleanup(RERR_MALLOC);
}
-void overflow_exit(char *str)
+
NORETURN
void overflow_exit(char *str)
{
{
- rprintf(FERROR, "ERROR: buffer overflow in %s
\n", str
);
+ rprintf(FERROR, "ERROR: buffer overflow in %s
[%s]\n", str, who_am_i()
);
exit_cleanup(RERR_MALLOC);
}
exit_cleanup(RERR_MALLOC);
}
@@
-354,7
+359,7
@@
int robust_unlink(const char *fname)
/* start where the last one left off to reduce chance of clashes */
start = counter;
do {
/* start where the last one left off to reduce chance of clashes */
start = counter;
do {
- s
printf(&path[pos]
, "%03d", counter);
+ s
nprintf(&path[pos], MAX_RENAMES_DIGITS+1
, "%03d", counter);
if (++counter >= MAX_RENAMES)
counter = 1;
} while ((rc = access(path, 0)) == 0 && counter != start);
if (++counter >= MAX_RENAMES)
counter = 1;
} while ((rc = access(path, 0)) == 0 && counter != start);
@@
-539,7
+544,7
@@
static void glob_expand_one(char *s, char ***argv_ptr, int *argc_ptr,
s = ".";
if (sanitize_paths)
s = ".";
if (sanitize_paths)
- s = sanitize_path(NULL, s, "", 0);
+ s = sanitize_path(NULL, s, "", 0
, NULL
);
else
s = strdup(s);
else
s = strdup(s);
@@
-607,8
+612,8
@@
void glob_expand(char *base1, char ***argv_ptr, int *argc_ptr, int *maxargs_ptr)
void strlower(char *s)
{
while (*s) {
void strlower(char *s)
{
while (*s) {
- if (is
upper(*(unsigned char *)
s))
- *s = to
lower(*(unsigned char *)
s);
+ if (is
Upper(
s))
+ *s = to
Lower(
s);
s++;
}
}
s++;
}
}
@@
-670,7
+675,7
@@
int count_dir_elements(const char *p)
int cnt = 0, new_component = 1;
while (*p) {
if (*p++ == '/')
int cnt = 0, new_component = 1;
while (*p) {
if (*p++ == '/')
- new_component =
1
;
+ new_component =
(*p != '.' || (p[1] != '/' && p[1] != '\0'))
;
else if (new_component) {
new_component = 0;
cnt++;
else if (new_component) {
new_component = 0;
cnt++;
@@
-745,8
+750,9
@@
unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
* The rootdir string contains a value to use in place of a leading slash.
* Specify NULL to get the default of lp_path(module_id).
*
* The rootdir string contains a value to use in place of a leading slash.
* Specify NULL to get the default of lp_path(module_id).
*
- * If depth is >= 0, it is a count of how many '..'s to allow at the start
- * of the path. Use -1 to allow unlimited depth.
+ * The depth var is a count of how many '..'s to allow at the start of the
+ * path. If symlink is set, combine its value with the "p" value to get
+ * the target path, and **return NULL if any '..'s try to escape**.
*
* We also clean the path in a manner similar to clean_fname() but with a
* few differences:
*
* We also clean the path in a manner similar to clean_fname() but with a
* few differences:
@@
-756,11
+762,17
@@
unsigned int clean_fname(char *name, BOOL collapse_dot_dot)
* ALWAYS collapses ".." elements (except for those at the start of the
* string up to "depth" deep). If the resulting name would be empty,
* change it into a ".". */
* ALWAYS collapses ".." elements (except for those at the start of the
* string up to "depth" deep). If the resulting name would be empty,
* change it into a ".". */
-char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
+char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth,
+ const char *symlink)
{
{
- char *start, *sanp;
+ char *start, *sanp
, *save_dest = dest
;
int rlen = 0, leave_one_dotdir = relative_paths;
int rlen = 0, leave_one_dotdir = relative_paths;
+ if (symlink && *symlink == '/') {
+ p = symlink;
+ symlink = "";
+ }
+
if (dest != p) {
int plen = strlen(p);
if (*p == '/') {
if (dest != p) {
int plen = strlen(p);
if (*p == '/') {
@@
-783,7
+795,18
@@
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
}
start = sanp = dest + rlen;
}
start = sanp = dest + rlen;
- while (*p != '\0') {
+ while (1) {
+ if (*p == '\0') {
+ if (!symlink || !*symlink)
+ break;
+ while (sanp != start && sanp[-1] != '/') {
+ /* strip last element */
+ sanp--;
+ }
+ /* Append a relative symlink */
+ p = symlink;
+ symlink = "";
+ }
/* discard leading or extra slashes */
if (*p == '/') {
p++;
/* discard leading or extra slashes */
if (*p == '/') {
p++;
@@
-805,6
+828,11
@@
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
/* ".." component followed by slash or end */
if (depth <= 0 || sanp != start) {
if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
/* ".." component followed by slash or end */
if (depth <= 0 || sanp != start) {
+ if (symlink && sanp == start) {
+ if (!save_dest)
+ free(dest);
+ return NULL;
+ }
p += 2;
if (sanp != start) {
/* back up sanp one level */
p += 2;
if (sanp != start) {
/* back up sanp one level */
@@
-833,15
+861,10
@@
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth)
return dest;
}
return dest;
}
-char curr_dir[MAXPATHLEN];
-unsigned int curr_dir_len;
-
-/**
- * Like chdir(), but it keeps track of the current directory (in the
+/* Like chdir(), but it keeps track of the current directory (in the
* global "curr_dir"), and ensures that the path size doesn't overflow.
* global "curr_dir"), and ensures that the path size doesn't overflow.
- * Also cleans the path using the clean_fname() function.
- **/
-int push_dir(char *dir)
+ * Also cleans the path using the clean_fname() function. */
+int push_dir(char *dir, int set_path_only)
{
static int initialised;
unsigned int len;
{
static int initialised;
unsigned int len;
@@
-862,7
+885,7
@@
int push_dir(char *dir)
if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
return 0;
if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir)
return 0;
- if (chdir(dir))
+ if (
!set_path_only &&
chdir(dir))
return 0;
if (*dir == '/') {
return 0;
if (*dir == '/') {
@@
-875,6
+898,11
@@
int push_dir(char *dir)
}
curr_dir_len = clean_fname(curr_dir, 1);
}
curr_dir_len = clean_fname(curr_dir, 1);
+ if (sanitize_paths) {
+ if (module_dirlen > curr_dir_len)
+ module_dirlen = curr_dir_len;
+ curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
+ }
return 1;
}
return 1;
}
@@
-891,6
+919,8
@@
int pop_dir(char *dir)
curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
if (curr_dir_len >= sizeof curr_dir)
curr_dir_len = sizeof curr_dir - 1;
curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
if (curr_dir_len >= sizeof curr_dir)
curr_dir_len = sizeof curr_dir - 1;
+ if (sanitize_paths)
+ curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
return 1;
}
return 1;
}
@@
-912,7
+942,7
@@
char *full_fname(const char *fn)
if (*fn == '/')
p1 = p2 = "";
else {
if (*fn == '/')
p1 = p2 = "";
else {
- p1 = curr_dir;
+ p1 = curr_dir
+ module_dirlen
;
for (p2 = p1; *p2 == '/'; p2++) {}
if (*p2)
p2 = "/";
for (p2 = p1; *p2 == '/'; p2++) {}
if (*p2)
p2 = "/";
@@
-921,17
+951,11
@@
char *full_fname(const char *fn)
m1 = " (in ";
m2 = lp_name(module_id);
m3 = ")";
m1 = " (in ";
m2 = lp_name(module_id);
m3 = ")";
- if (p1 == curr_dir) {
- if (!lp_use_chroot(module_id)) {
- char *p = lp_path(module_id);
- if (*p != '/' || p[1])
- p1 += strlen(p);
- }
- }
} else
m1 = m2 = m3 = "";
} else
m1 = m2 = m3 = "";
- asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3);
+ if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) <= 0)
+ out_of_memory("full_fname");
return result;
}
return result;
}
@@
-957,13
+981,11
@@
char *partial_dir_fname(const char *fname)
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
return NULL;
if (server_filter_list.head) {
if ((int)pathjoin(t, sz, partial_dir, fn) >= sz)
return NULL;
if (server_filter_list.head) {
- static int len;
- if (!len)
- len = strlen(partial_dir);
- t[len] = '\0';
+ t = strrchr(partial_fname, '/');
+ *t = '\0';
if (check_filter(&server_filter_list, partial_fname, 1) < 0)
return NULL;
if (check_filter(&server_filter_list, partial_fname, 1) < 0)
return NULL;
-
t[len]
= '/';
+
*t
= '/';
if (check_filter(&server_filter_list, partial_fname, 0) < 0)
return NULL;
}
if (check_filter(&server_filter_list, partial_fname, 0) < 0)
return NULL;
}
@@
-1093,7
+1115,7
@@
char *human_num(int64 num)
units = 'K';
}
if (units) {
units = 'K';
}
if (units) {
- s
printf(bufs[n
], "%.2f%c", dnum, units);
+ s
nprintf(bufs[n], sizeof bufs[0
], "%.2f%c", dnum, units);
return bufs[n];
}
}
return bufs[n];
}
}
@@
-1117,7
+1139,7
@@
char *human_dnum(double dnum, int decimal_digits)
{
char *buf = human_num(dnum);
int len = strlen(buf);
{
char *buf = human_num(dnum);
int len = strlen(buf);
- if (is
digit(*(uchar*)(buf+len-1)
)) {
+ if (is
Digit(buf + len - 1
)) {
/* There's extra room in buf prior to the start of the num. */
buf -= decimal_digits + 1;
snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
/* There's extra room in buf prior to the start of the num. */
buf -= decimal_digits + 1;
snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
@@
-1285,7
+1307,7
@@
const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
if (strcmp(s+1, "orig") == 0)
continue;
} else if (s_len > 2 && had_tilde
if (strcmp(s+1, "orig") == 0)
continue;
} else if (s_len > 2 && had_tilde
- && s[1] == '~' && is
digit(*(uchar*)(s+2)
))
+ && s[1] == '~' && is
Digit(s + 2
))
continue;
*len_ptr = s_len;
suf = s;
continue;
*len_ptr = s_len;
suf = s;
@@
-1293,7
+1315,7
@@
const char *find_filename_suffix(const char *fn, int fn_len, int *len_ptr)
break;
/* Determine if the suffix is all digits. */
for (s++, s_len--; s_len > 0; s++, s_len--) {
break;
/* Determine if the suffix is all digits. */
for (s++, s_len--; s_len > 0; s++, s_len--) {
- if (!is
digit(*(uchar*)
s))
+ if (!is
Digit(
s))
return suf;
}
/* An all-digit suffix may not be that signficant. */
return suf;
}
/* An all-digit suffix may not be that signficant. */