WordPress.org

Make WordPress Core

Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#33919 closed defect (bug) (fixed)

ssh2/sftp doesn't work in chrooted environments, FTP_BASE, FTP_CONTENT_DIR, FTP_PLUGIN_DIR not available

Reported by: talatorre Owned by: dd32
Milestone: 4.4 Priority: normal
Severity: major Version: 4.3
Component: Filesystem API Keywords:
Focuses: Cc:
PR Number:

Description

This is a follow-up to #32345.

My server is setup with multiple domains in chrooted environments. Users can connect to the server using rsa keys. Without modification to the system files the SSH2 extension still does not work for me in this environment.

Tested on 4.3.1 here is extra debug from WP_Filesystem_Base::$verbose when attempting an update to a plugin:

Looking for /var/www/user/usersite.com/htdocs/wp-content in /
The update process is starting. This process may take a while on some hosts, so please be patient.

Looking for /var/www/user/usersite.com/htdocs/wp-content in /
Updating Plugin Akismet (1/1)
An error occurred while updating Akismet: Unable to locate WordPress Content directory (wp-content).
Looking for /var/www/user/usersite.com/htdocs in /
All updates have been completed.

The FS Tester plugin returns the following:

Connection Method	ftpext
ABSPATH	/var/www/user/usersite.com/htdocs/
PLUGINDIR	wp-content/plugins
FS Errors	None
FS CWD	/
FS WordPress Locator	Looking for /var/www/user/usersite.com/htdocs in /
FS WordPress Location	
FS0 WordPress Locator (Old code)	Changing to /
FS0 WordPress Location (Old code)	
Tests Stopped; Error: WordPress could not be located	Files in folder

However, if I modify the find_folder( $folder ) function in the file wp-admin/includes/class-wp-filesystem-base.php as outlined by @aberbenni in ticket #32345 then WP recognizes the FTP_BASE, FTP_CONTENT_DIR, and FTP_PLUGIN_DIR and everything works as expected. I am able to update plugins and the system files again. That is until class-wp-filesystem-base.php is overwritten.

I then receive the following output from FS Tester plugin:

Connection Method	ftpext
ABSPATH	/var/www/user/usersite.com/htdocs/
PLUGINDIR	wp-content/plugins
FS Errors	None
FS CWD	/
FS WordPress Locator	
FS WordPress Location	/usersite.com/htdocs/
FS0 WordPress Locator (Old code)	Changing to /
FS0 WordPress Location (Old code)	
NOTICE: WordPress locations different. Which is the correct one?
Please email me at wordpress@dd32.id.au with the output from this page, and mention which is the correct path, Thanks :)
Files in folder	
		
Plugin location:	/var/www/user/usersite.com/htdocs/wp-content/plugins/wp-filesystem-tester.php (Local)
/usersite.com/htdocs/wp-content/plugins/wp-filesystem-tester.php (FTP)
Plugin Locations	
hello.php	/usersite.com/htdocs/wp-content/plugins/	Delete file: /usersite.com/htdocs/wp-content/plugins/hello.php
akismet/akismet.php	/usersite.com/htdocs/wp-content/plugins/akismet/	Delete entire folder: /usersite.com/htdocs/wp-content/plugins/akismet/
File IO Errors	All File IO tests passed.
Created /usersite.com/htdocs/wp-content/plugins/super-long-name-not-to-conflict.php
Verified conents
Deleted /usersite.com/htdocs/wp-content/plugins/super-long-name-not-to-conflict.php
Downloading a zip	Downloading http://downloads.wordpress.org/plugin/akismet.zip... Suceeded
Extracting Zip	Suceeded
Zip Contents	
akismet/	0	ok	binary
akismet/akismet.php	2442	ok	<?php
/**
 * @package Akismet
 */
/*
Plugin Name: ...
akismet/class.akismet-admin.php	38939	ok	<?php

class Akismet_Admin {
	const NONCE = 'akism...
akismet/.htaccess	616	ok	binary
akismet/_inc/	0	ok	binary
akismet/_inc/img/	0	ok	binary
akismet/_inc/img/logo-full-2x.png	4970	ok	binary
akismet/_inc/form.js	700	ok	binary
akismet/_inc/akismet.js	5969	ok	binary
akismet/_inc/akismet.css	6148	ok	binary
akismet/readme.txt	11775	ok	=== Akismet ===
Contributors: matt, ryan, andy, md...
akismet/wrapper.php	6427	ok	<?php

global $wpcom_api_key, $akismet_api_host, $...
akismet/class.akismet.php	42614	ok	<?php

class Akismet {
	const API_HOST = 'rest.aki...
akismet/LICENSE.txt	18092	ok	                    GNU GENERAL PUBLIC LICENSE
   ...
akismet/index.php	26	ok	<?php
# Silence is golden....
akismet/class.akismet-widget.php	2719	ok	<?php
/**
 * @package Akismet
 */
class Akismet_Wi...
akismet/views/	0	ok	binary
akismet/views/notice.php	10572	ok	<?php if ( $type == 'plugin' ) :?>
<div class="upd...
akismet/views/strict.php	830	ok	<tr valign="top">
	<th scope="row"><?php esc_html_...
akismet/views/start.php	6547	ok	<div class="no-key config-wrap"><?php
	if ( $akism...
akismet/views/get.php	595	ok	<form name="akismet_activate" action="https://akis...
akismet/views/config.php	10537	ok	<div class="wrap">

	<h2><?php esc_html_e( 'Akisme...
akismet/views/stats.php	551	ok	<div class="wrap">
	<h2><?php esc_html_e( 'Akismet...

The plugin says to report which path is correct, but the problem is they both are. Apache views the entire folder structure but the user SSH login views the shorter chrooted structure.

Being able to use the FTP_BASE, FTP_CONTENT_DIR, and FTP_PLUGIN_DIR variables, or an analogous SSH_BASE, SSH_CONTENT_DIR, and SSH_PLUGIN_DIR would solve the problem but there may be a better way to address it.

Attachments (2)

33919.diff (8.5 KB) - added by dd32 4 years ago.
class-wp-filesystem-ssh2.php (14.4 KB) - added by dd32 4 years ago.

Download all attachments as: .zip

Change History (10)

#1 @aberbenni
4 years ago

  • Keywords has-patch added
  • Severity changed from normal to major

I'm using the find_folder( $folder ) "patch" too, waiting for a more stable and durable solution.

#2 @atomicjack
4 years ago

  • Keywords has-patch removed

Please only mark as 'has patch' if a suitable patch file has been submitted.

#3 @talatorre
4 years ago

An additional comment on my system configuration:

My system is configured with two folders as follows:

/home/user/website
/var/www/user/website

The users are chrooted to their home folders but I have all of the publicly accessible (web facing) folders for all users located in /var/www/.

I am mounting /var/www/user/website into the home folder so the users can access them as if they were in the same place.

When logging in via an ftp client the user just sees /website, the SSH2 module is seeing /home/user/website, and apache is seeing /var/www/user/website.

#4 @aberbenni
4 years ago

"patch"

use:

public function find_folder( $folder ) {
		if ( isset( $this->cache[ $folder ] ) )
			return $this->cache[ $folder ];

		if ( stripos($this->method, 'ftp') !== false || stripos($this->method, 'ssh2') !== false ) {

isntead of

public function find_folder( $folder ) {
		if ( isset( $this->cache[ $folder ] ) )
			return $this->cache[ $folder ];

		if ( stripos($this->method, 'ftp') !== false ) {

#5 @dd32
4 years ago

  • Milestone changed from Awaiting Review to 4.4

@talatorre gratefully allowed me access to a test account on the server in question, I was able to find one major bug that was preventing it working:

  • The PHP SSH2 extension was failing to be able to access, or list, the contents of the / directory.

This affected two main things:

  • $wp_filesystem->is_dir( '/' ) would return false
  • $wp_filesystem->dirlist( '/' ) would return false

I'm not sure why, but this appears to be something to do with the way the SSH2 wrappers interact with the server. Take the following two examples:

  • dir(ssh2.sftp://Resource id #9/) - Listing the / directory, fails
  • dir(ssh2.sftp://Resource id #9/home/account/) - Listing my accounts home directory succeeds
  • dir(ssh2.sftp://Resource id #9/./) - Listing the /./ directory, which is really / succeeds (you could also use /../)

This has lead me to this PHP bug: https://bugs.php.net/bug.php?id=64169 which actually offers up the same workaround as I've already come up with.

Attached is 33919.diff which implements that workaround and centralises the code. Also attached a full copy of `class-wp-filesystem-ssh2.php` which can be dropped in to test with - @aberbenni can you try that out?

@dd32
4 years ago

#6 @wonderboymusic
4 years ago

  • Owner set to dd32
  • Status changed from new to assigned

#7 @dd32
4 years ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 34738:

Updates: SSH2 Transport: Use a work around to avoid a bug where PHP's SSH2 extension fails to list the contents of the / directory.
This fixes issues where SSH2 with chrooted environments runs into a Unable to locate WordPress Content directory (wp-content). error.

The workaround is to simply list the contents of the /./ directory instead of /.

Fixes #33919

#8 @aberbenni
4 years ago

@dd32 Tested on my server/sites, it works.

Note: See TracTickets for help on using tickets.