Commit b0775280 authored by Robin McCorkell's avatar Robin McCorkell
Browse files

Perform proper checking for share availability

To check for shares, the code attempts to connect anonymously to the share.
In most cases this will fail with NT_STATUS_ACCESS_DENIED, so the regex array
used for parsing the output of smbclient in smb4php has been overridden to
treat such output as success.

The 'test' method for storage classes can now take a single parameter,
$isPersonal, which allows the storage to adjust the tests performed based on
if they are being configured as personal shares or as system shares.
parent cac4aaa8
......@@ -8,6 +8,8 @@
# Homepage: http://www.phpclasses.org/smb4php
#
# Copyright (c) 2007 Victor M. Varela <vmvarela@gmail.com>
# Copyright (c) 2012 Frank Karlitschek <frank@owncloud.org>
# Copyright (c) 2014 Robin McCorkell <rmccorkell@karoshi.org.uk>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
......@@ -19,8 +21,6 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Addition 17/12/2012 Frank Karlitschek (frank@owncloud.org)
# Addition 17/03/2014 Robin McCorkell (rmccorkell@karoshi.org.uk)
# On the official website http://www.phpclasses.org/smb4php the
# license is listed as LGPL so we assume that this is
# dual-licensed GPL/LGPL
......@@ -44,6 +44,42 @@ $GLOBALS['__smb_cache'] = array ('stat' => array (), 'dir' => array ());
class smb {
private static $regexp = array (
'^added interface ip=(.*) bcast=(.*) nmask=(.*)$' => 'skip',
'Anonymous login successful' => 'skip',
'^Domain=\[(.*)\] OS=\[(.*)\] Server=\[(.*)\]$' => 'skip',
'^\tSharename[ ]+Type[ ]+Comment$' => 'shares',
'^\t---------[ ]+----[ ]+-------$' => 'skip',
'^\tServer [ ]+Comment$' => 'servers',
'^\t---------[ ]+-------$' => 'skip',
'^\tWorkgroup[ ]+Master$' => 'workg',
'^\t(.*)[ ]+(Disk|IPC)[ ]+IPC.*$' => 'skip',
'^\tIPC\\\$(.*)[ ]+IPC' => 'skip',
'^\t(.*)[ ]+(Disk)[ ]+(.*)$' => 'share',
'^\t(.*)[ ]+(Printer)[ ]+(.*)$' => 'skip',
'([0-9]+) blocks of size ([0-9]+)\. ([0-9]+) blocks available' => 'skip',
'Got a positive name query response from ' => 'skip',
'^(session setup failed): (.*)$' => 'error',
'^(.*): ERRSRV - ERRbadpw' => 'error',
'^Error returning browse list: (.*)$' => 'error',
'^tree connect failed: (.*)$' => 'error',
'^(Connection to .* failed)(.*)$' => 'error-connect',
'^NT_STATUS_(.*) ' => 'error',
'^NT_STATUS_(.*)\$' => 'error',
'ERRDOS - ERRbadpath \((.*).\)' => 'error',
'cd (.*): (.*)$' => 'error',
'^cd (.*): NT_STATUS_(.*)' => 'error',
'^\t(.*)$' => 'srvorwg',
'^([0-9]+)[ ]+([0-9]+)[ ]+(.*)$' => 'skip',
'^Job ([0-9]+) cancelled' => 'skip',
'^[ ]+(.*)[ ]+([0-9]+)[ ]+(Mon|Tue|Wed|Thu|Fri|Sat|Sun)[ ](Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+([0-9]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]([0-9]{4})$' => 'files',
'^message start: ERRSRV - (ERRmsgoff)' => 'error'
);
function getRegexp() {
return self::$regexp;
}
function parse_url ($url) {
$pu = parse_url (trim($url));
foreach (array ('domain', 'user', 'pass', 'host', 'port', 'path') as $i) {
......@@ -75,46 +111,16 @@ class smb {
}
function execute ($command, $purl) {
function execute ($command, $purl, $regexp = NULL) {
return smb::client ('-d 0 '
. escapeshellarg ('//' . $purl['host'] . '/' . $purl['share'])
. ' -c ' . escapeshellarg ($command), $purl
. ' -c ' . escapeshellarg ($command), $purl, $regexp
);
}
function client ($params, $purl) {
static $regexp = array (
'^added interface ip=(.*) bcast=(.*) nmask=(.*)$' => 'skip',
'Anonymous login successful' => 'skip',
'^Domain=\[(.*)\] OS=\[(.*)\] Server=\[(.*)\]$' => 'skip',
'^\tSharename[ ]+Type[ ]+Comment$' => 'shares',
'^\t---------[ ]+----[ ]+-------$' => 'skip',
'^\tServer [ ]+Comment$' => 'servers',
'^\t---------[ ]+-------$' => 'skip',
'^\tWorkgroup[ ]+Master$' => 'workg',
'^\t(.*)[ ]+(Disk|IPC)[ ]+IPC.*$' => 'skip',
'^\tIPC\\\$(.*)[ ]+IPC' => 'skip',
'^\t(.*)[ ]+(Disk)[ ]+(.*)$' => 'share',
'^\t(.*)[ ]+(Printer)[ ]+(.*)$' => 'skip',
'([0-9]+) blocks of size ([0-9]+)\. ([0-9]+) blocks available' => 'skip',
'Got a positive name query response from ' => 'skip',
'^(session setup failed): (.*)$' => 'error',
'^(.*): ERRSRV - ERRbadpw' => 'error',
'^Error returning browse list: (.*)$' => 'error',
'^tree connect failed: (.*)$' => 'error',
'^(Connection to .* failed)(.*)$' => 'error-connect',
'^NT_STATUS_(.*) ' => 'error',
'^NT_STATUS_(.*)\$' => 'error',
'ERRDOS - ERRbadpath \((.*).\)' => 'error',
'cd (.*): (.*)$' => 'error',
'^cd (.*): NT_STATUS_(.*)' => 'error',
'^\t(.*)$' => 'srvorwg',
'^([0-9]+)[ ]+([0-9]+)[ ]+(.*)$' => 'skip',
'^Job ([0-9]+) cancelled' => 'skip',
'^[ ]+(.*)[ ]+([0-9]+)[ ]+(Mon|Tue|Wed|Thu|Fri|Sat|Sun)[ ](Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+([0-9]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]([0-9]{4})$' => 'files',
'^message start: ERRSRV - (ERRmsgoff)' => 'error'
);
function client ($params, $purl, $regexp = NULL) {
if ($regexp === NULL) $regexp = smb::$regexp;
if (SMB4PHP_AUTHMODE == 'env') {
putenv("USER={$purl['user']}%{$purl['pass']}");
......
......@@ -319,7 +319,7 @@ class OC_Mount_Config {
'backend' => $backends[$mount['class']]['backend'],
'options' => $mount['options'],
'applicable' => array('groups' => array($group), 'users' => array()),
'status' => self::getBackendStatus($mount['class'], $mount['options'])
'status' => self::getBackendStatus($mount['class'], $mount['options'], false)
);
$hash = self::makeConfigHash($config);
// If an existing config exists (with same class, mountpoint and options)
......@@ -349,7 +349,7 @@ class OC_Mount_Config {
'backend' => $backends[$mount['class']]['backend'],
'options' => $mount['options'],
'applicable' => array('groups' => array(), 'users' => array($user)),
'status' => self::getBackendStatus($mount['class'], $mount['options'])
'status' => self::getBackendStatus($mount['class'], $mount['options'], true)
);
$hash = self::makeConfigHash($config);
// If an existing config exists (with same class, mountpoint and options)
......@@ -389,7 +389,7 @@ class OC_Mount_Config {
'mountpoint' => substr($mountPoint, strlen($uid) + 8),
'backend' => $backends[$mount['class']]['backend'],
'options' => $mount['options'],
'status' => self::getBackendStatus($mount['class'], $mount['options'])
'status' => self::getBackendStatus($mount['class'], $mount['options'], true)
);
}
}
......@@ -402,7 +402,7 @@ class OC_Mount_Config {
* @param array $options backend configuration options
* @return bool true if the connection succeeded, false otherwise
*/
private static function getBackendStatus($class, $options) {
private static function getBackendStatus($class, $options, $isPersonal) {
if (self::$skipTest) {
return true;
}
......@@ -412,7 +412,7 @@ class OC_Mount_Config {
if (class_exists($class)) {
try {
$storage = new $class($options);
return $storage->test();
return $storage->test($isPersonal);
} catch (Exception $exception) {
\OCP\Util::logException('files_external', $exception);
return false;
......@@ -479,7 +479,7 @@ class OC_Mount_Config {
$mountPoints[$mountType] = $mount;
}
self::writeData($isPersonal, $mountPoints);
return self::getBackendStatus($class, $classOptions);
return self::getBackendStatus($class, $classOptions, $isPersonal);
}
/**
......
......@@ -8,11 +8,15 @@
namespace OC\Files\Storage;
require_once __DIR__ . '/../3rdparty/smb4php/smb.php';
class SMB_OC extends \OC\Files\Storage\SMB {
private $username_as_share;
public function __construct($params) {
if (isset($params['host']) && \OC::$session->exists('smb-credentials')) {
$host=$params['host'];
$username_as_share = ($params['username_as_share'] === 'true');
$this->username_as_share = ($params['username_as_share'] === 'true');
$params_auth = \OC::$session->get('smb-credentials');
$user = \OC::$session->get('loginname');
......@@ -21,7 +25,7 @@ class SMB_OC extends \OC\Files\Storage\SMB {
$root=isset($params['root'])?$params['root']:'/';
$share = '';
if ($username_as_share) {
if ($this->username_as_share) {
$share = '/'.$user;
} elseif (isset($params['share'])) {
$share = $params['share'];
......@@ -47,4 +51,39 @@ class SMB_OC extends \OC\Files\Storage\SMB {
public function isSharable($path) {
return false;
}
public function test($isPersonal = true) {
if ($isPersonal) {
if ($this->stat(''))
return true;
return false;
} else {
$smb = new \smb();
$pu = $smb->parse_url($this->constructUrl(''));
// Attempt to connect anonymously
$pu['user'] = '';
$pu['pass'] = '';
// Share cannot be checked if dynamic
if ($this->username_as_share) {
if ($smb->look($pu))
return true;
else
return false;
}
if (!$pu['share'])
return false;
// The following error messages are expected due to anonymous login
$regexp = array(
'(NT_STATUS_ACCESS_DENIED)' => 'skip'
) + $smb->getRegexp();
if ($smb->client("-d 0 " . escapeshellarg('//' . $pu['host'] . '/' . $pu['share']) . " -c exit", $pu, $regexp))
return true;
else
return false;
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment