- * Copyright (C) 1996-2000 by Andrew Tridgell
- * Copyright (C) Paul Mackerras 1996
- * Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
+ * Copyright (C) 1996-2000 Andrew Tridgell
+ * Copyright (C) 1996 Paul Mackerras
+ * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
+ * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
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 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;
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
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
",.-_=+@/") != strlen(*cmd)) {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
",.-_=+@/") != strlen(*cmd)) {
- rprintf(FERROR, "ERROR: out of memory in %s\n", str);
+ rprintf(FERROR, "ERROR: out of memory in %s [%s]\n", str, who_am_i());
- rprintf(FERROR, "ERROR: buffer overflow in %s\n", str);
+ rprintf(FERROR, "ERROR: buffer overflow in %s [%s]\n", str, who_am_i());
- sprintf(&path[pos], "%03d", counter);
+ snprintf(&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);
* across filesystems, -2 if copy_file() failed, and -1 on other errors.
* If partialptr is not NULL and we need to do a copy, copy the file into
* the active partial-dir instead of over the destination file. */
* across filesystems, -2 if copy_file() failed, and -1 on other errors.
* If partialptr is not NULL and we need to do a copy, copy the file into
* the active partial-dir instead of over the destination file. */
-int robust_rename(char *from, char *to, char *partialptr,
+int robust_rename(const char *from, const char *to, const char *partialptr,
- s = sanitize_path(NULL, s, "", 0);
+ s = sanitize_path(NULL, s, "", 0, NULL);
* 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**.
*
* Turns multiple adjacent slashes into a single slash, gets rid of "." dir
* elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
* 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 ".". */
*
* Turns multiple adjacent slashes into a single slash, gets rid of "." dir
* elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and
* 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)
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) {
-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
* Reverse a push_dir() call. You must pass in an absolute path
* that was copied from a prior value of "curr_dir".
**/
* Reverse a push_dir() call. You must pass in an absolute path
* that was copied from a prior value of "curr_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;
- 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");
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) {
- sprintf(bufs[n], "%.2f%c", dnum, units);
+ snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units);
/* 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);
if (!ptr)
return malloc(size * num);
return realloc(ptr, size * num);
if (!ptr)
return malloc(size * num);
return realloc(ptr, size * num);
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
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--) {