Skip to content
Permalink
Browse files

Backporting recursive handling of DefaultRoot path, when AllowChrootS…

…ymlinks

is off, to 1.3.5 branch.
  • Loading branch information...
Castaglia committed Mar 6, 2017
1 parent 5a2ca0f commit ecff21e0d0e84f35c299ef91d7fda088e516d4ed
Showing with 65 additions and 18 deletions.
  1. +65 −18 modules/mod_auth.c
@@ -2,7 +2,7 @@
* ProFTPD - FTP server daemon
* Copyright (c) 1997, 1998 Public Flood Software
* Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver@tos.net>
* Copyright (c) 2001-2016 The ProFTPD Project team
* Copyright (c) 2001-2017 The ProFTPD Project team
*
* 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
@@ -688,9 +688,66 @@ static char *get_default_chdir(pool *p, xaset_t *conf) {
return dir;
}

/* Determine if the user (non-anon) needs a default root dir other than /.
*/
static int is_symlink_path(pool *p, const char *path, size_t pathlen) {
int res, xerrno = 0;
struct stat st;
char *ptr;

if (pathlen == 0) {
return 0;
}

pr_fs_clear_cache();
res = pr_fsio_lstat(path, &st);
if (res < 0) {
xerrno = errno;

pr_log_pri(PR_LOG_WARNING, "error: unable to check %s: %s", path,
strerror(xerrno));

errno = xerrno;
return -1;
}

if (S_ISLNK(st.st_mode)) {
errno = EPERM;
return -1;
}

/* To handle the case where a component further up the path might be a
* symlink (which lstat(2) will NOT handle), we walk the path backwards,
* calling ourselves recursively.
*/

ptr = strrchr(path, '/');
if (ptr != NULL) {
char *new_path;
size_t new_pathlen;

pr_signals_handle();

new_pathlen = ptr - path;

/* Make sure our pointer actually changed position. */
if (new_pathlen == pathlen) {
return 0;
}

new_path = pstrndup(p, path, new_pathlen);

pr_log_debug(DEBUG10,
"AllowChrootSymlink: path '%s' not a symlink, checking '%s'", path,
new_path);
res = is_symlink_path(p, new_path, new_pathlen);
if (res < 0) {
return -1;
}
}

return 0;
}

/* Determine if the user (non-anon) needs a default root dir other than /. */
static int get_default_root(pool *p, int allow_symlinks, char **root) {
config_rec *c = NULL;
char *dir = NULL;
@@ -733,7 +790,6 @@ static int get_default_root(pool *p, int allow_symlinks, char **root) {

if (allow_symlinks == FALSE) {
char *path, target_path[PR_TUNABLE_PATH_MAX + 1];
struct stat st;
size_t pathlen;

/* First, deal with any possible interpolation. dir_realpath() will
@@ -764,22 +820,13 @@ static int get_default_root(pool *p, int allow_symlinks, char **root) {
path[pathlen-1] = '\0';
}

pr_fs_clear_cache();
res = pr_fsio_lstat(path, &st);
res = is_symlink_path(p, path, pathlen);
if (res < 0) {
xerrno = errno;

pr_log_pri(PR_LOG_WARNING, "error: unable to check %s: %s", path,
strerror(xerrno));

errno = xerrno;
return -1;
}
if (errno == EPERM) {
pr_log_pri(PR_LOG_WARNING, "error: DefaultRoot %s is a symlink "
"(denied by AllowChrootSymlinks config)", path);
}

if (S_ISLNK(st.st_mode)) {
pr_log_pri(PR_LOG_WARNING,
"error: DefaultRoot %s is a symlink (denied by AllowChrootSymlinks "
"config)", path);
errno = EPERM;
return -1;
}

2 comments on commit ecff21e

@pghmcfc

This comment has been minimized.

Copy link

replied Apr 19, 2017

Somehow this seems to be breaking virtual users - see https://bugzilla.redhat.com/show_bug.cgi?id=1443507

I tried raising a bug from work but the company proxy blocked me from posting form data to bugs.proftpd.org; I can try again from home at a later time.

@pghmcfc

This comment has been minimized.

Copy link

replied Apr 19, 2017

Please sign in to comment.
You can’t perform that action at this time.