extern unsigned int module_dirlen;
extern mode_t orig_umask;
extern char *partial_dir;
-extern struct filter_list_struct daemon_filter_list;
+extern filter_rule_list daemon_filter_list;
int sanitize_paths = 0;
exit_cleanup(RERR_MALLOC);
}
-int set_modtime(const char *fname, time_t modtime, mode_t mode)
+int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode)
{
-#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES
+#ifndef CAN_SET_SYMLINK_TIMES
if (S_ISLNK(mode))
return 1;
#endif
return 0;
{
-#ifdef HAVE_UTIMES
+#ifdef HAVE_UTIMENSAT
+ struct timespec t[2];
+ t[0].tv_sec = 0;
+ t[0].tv_nsec = UTIME_NOW;
+ t[1].tv_sec = modtime;
+ t[1].tv_nsec = mod_nsec;
+ if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) < 0)
+ return S_ISLNK(mode) && errno == ENOSYS ? 1 : -1;
+ return 0;
+#elif defined HAVE_UTIMES || defined HAVE_LUTIMES
struct timeval t[2];
t[0].tv_sec = time(NULL);
t[0].tv_usec = 0;
t[1].tv_sec = modtime;
- t[1].tv_usec = 0;
+ t[1].tv_usec = mod_nsec / 1000;
# ifdef HAVE_LUTIMES
- if (S_ISLNK(mode)) {
- if (lutimes(fname, t) < 0)
- return errno == ENOSYS ? 1 : -1;
- return 0;
- }
-# endif
+ if (lutimes(fname, t) < 0)
+ return S_ISLNK(mode) && errno == ENOSYS ? 1 : -1;
+ return 0;
+# else
return utimes(fname, t);
+# endif
#elif defined HAVE_STRUCT_UTIMBUF
struct utimbuf tbuf;
tbuf.actime = time(NULL);
}
}
-/** Turn a user name into a uid */
-int name_to_uid(const char *name, uid_t *uid_p)
+/* Parse a user name or (optionally) a number into a uid */
+int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok)
{
struct passwd *pass;
if (!name || !*name)
return 0;
+ if (num_ok && name[strspn(name, "0123456789")] == '\0') {
+ *uid_p = atol(name);
+ return 1;
+ }
if (!(pass = getpwnam(name)))
return 0;
*uid_p = pass->pw_uid;
return 1;
}
-/** Turn a group name into a gid */
-int name_to_gid(const char *name, gid_t *gid_p)
+/* Parse a group name or (optionally) a number into a gid */
+int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok)
{
struct group *grp;
if (!name || !*name)
return 0;
+ if (num_ok && name[strspn(name, "0123456789")] == '\0') {
+ *gid_p = atol(name);
+ return 1;
+ }
if (!(grp = getgrnam(name)))
return 0;
*gid_p = grp->gr_gid;
return 1;
}
+/* Computes the depth of the given path, excluding any basename. This
+ * assumes that the path does not walk through any symlinks.
+ *
+ * For use with unsafe_symlink. */
+int path_depth(const char *path)
+{
+ const char *name, *slash;
+ int depth = 0;
+
+ for (name = path; (slash = strchr(name, '/')) != 0; name = slash+1) {
+ /* ".." segment starts the count over. "." segment is ignored. */
+ if (strncmp(name, "./", 2) == 0)
+ ;
+ else if (strncmp(name, "../", 3) == 0)
+ depth = 0;
+ else
+ depth++;
+ while (slash[1] == '/') slash++; /* just in case path isn't clean */
+ }
+ if (strcmp(name, "..") == 0)
+ depth = 0;
+
+ return depth;
+}
+
/* Determine if a symlink points outside the current directory tree.
* This is considered "unsafe" because e.g. when mirroring somebody
* else's machine it might allow them to establish a symlink to
*
* "dest" is the target of the symlink in question.
*
- * "src" is the top source directory currently applicable at the level
- * of the referenced symlink. This is usually the symlink's full path
- * (including its name), as referenced from the root of the transfer. */
-int unsafe_symlink(const char *dest, const char *src)
+ * "depth" is the depth of the symlink inside the current directory
+ * tree. It can be computed with "path_depth". */
+int unsafe_symlink(const char *dest, int depth)
{
const char *name, *slash;
- int depth = 0;
/* all absolute and null symlinks are unsafe */
if (!dest || !*dest || *dest == '/')
return 1;
- /* find out what our safety margin is */
- for (name = src; (slash = strchr(name, '/')) != 0; name = slash+1) {
- /* ".." segment starts the count over. "." segment is ignored. */
- if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
- if (name[1] == '.')
- depth = 0;
- } else
- depth++;
- while (slash[1] == '/') slash++; /* just in case src isn't clean */
- }
- if (*name == '.' && name[1] == '.' && name[2] == '\0')
- depth = 0;
-
for (name = dest; (slash = strchr(name, '/')) != 0; name = slash+1) {
- if (*name == '.' && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))) {
- if (name[1] == '.') {
- /* if at any point we go outside the current directory
- then stop - it is unsafe */
- if (--depth < 0)
- return 1;
- }
+ if (strncmp(name, "./", 2) == 0)
+ ;
+ else 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
+ /* XXX: We could be walking through another symlink! */
depth++;
while (slash[1] == '/') slash++;
}
- if (*name == '.' && name[1] == '.' && name[2] == '\0')
- depth--;
+ if (strcmp(name, "..") == 0) {
+ if (--depth < 0)
+ return 1;
+ }
- return depth < 0;
+ return 0;
}
/* Return the date and time as a string. Some callers tweak returned buf. */