Merge pull request #7875 from Xenopathic/files_external_smb_auto

SMB/CIFS mounts using ownCloud login, fixes #7843
This commit is contained in:
Vincent Petry 2014-03-27 12:18:51 +01:00
commit 1f6259d9c2
4 changed files with 155 additions and 45 deletions

View File

@ -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) {
function client ($params, $purl, $regexp = NULL) {
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'
);
if ($regexp === NULL) $regexp = smb::$regexp;
if (SMB4PHP_AUTHMODE == 'env') {
putenv("USER={$purl['user']}%{$purl['pass']}");

View File

@ -1,6 +1,7 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* Copyright (c) 2014 Robin McCorkell <rmccorkell@karoshi.org.uk>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
@ -13,6 +14,7 @@ OC::$CLASSPATH['OC\Files\Storage\OwnCloud'] = 'files_external/lib/owncloud.php';
OC::$CLASSPATH['OC\Files\Storage\Google'] = 'files_external/lib/google.php';
OC::$CLASSPATH['OC\Files\Storage\Swift'] = 'files_external/lib/swift.php';
OC::$CLASSPATH['OC\Files\Storage\SMB'] = 'files_external/lib/smb.php';
OC::$CLASSPATH['OC\Files\Storage\SMB_OC'] = 'files_external/lib/smb_oc.php';
OC::$CLASSPATH['OC\Files\Storage\AmazonS3'] = 'files_external/lib/amazons3.php';
OC::$CLASSPATH['OC\Files\Storage\Dropbox'] = 'files_external/lib/dropbox.php';
OC::$CLASSPATH['OC\Files\Storage\SFTP'] = 'files_external/lib/sftp.php';
@ -27,4 +29,5 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == '
// connecting hooks
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login');
OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login');

View File

@ -5,6 +5,7 @@
* @author Michael Gapczynski
* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
* @copyright 2014 Robin McCorkell <rmccorkell@karoshi.org.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@ -122,11 +123,18 @@ class OC_Mount_Config {
'password' => '*Password',
'share' => 'Share',
'root' => '&Root'));
$backends['\OC\Files\Storage\SMB_OC'] = array(
'backend' => 'SMB / CIFS using OC login',
'configuration' => array(
'host' => 'URL',
'username_as_share' => '!Username as share',
'share' => '&Share',
'root' => '&Root'));
}
}
if(OC_Mount_Config::checkcurl()){
$backends['\OC\Files\Storage\DAV']=array(
$backends['\OC\Files\Storage\DAV']=array(
'backend' => 'WebDAV',
'configuration' => array(
'host' => 'URL',
@ -134,7 +142,7 @@ class OC_Mount_Config {
'password' => '*Password',
'root' => '&Root',
'secure' => '!Secure https://'));
$backends['\OC\Files\Storage\OwnCloud']=array(
$backends['\OC\Files\Storage\OwnCloud']=array(
'backend' => 'ownCloud',
'configuration' => array(
'host' => 'URL',
@ -185,7 +193,7 @@ class OC_Mount_Config {
* @return array of mount point string as key, mountpoint config as value
*/
public static function getAbsoluteMountPoints($user) {
$mountPoints = array();
$mountPoints = array();
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
$mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json");
@ -311,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)
@ -341,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'], false)
);
$hash = self::makeConfigHash($config);
// If an existing config exists (with same class, mountpoint and options)
@ -381,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)
);
}
}
@ -394,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;
}
@ -404,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;
@ -471,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);
}
/**

View File

@ -0,0 +1,93 @@
<?php
/**
* Copyright (c) 2014 Robin McCorkell <rmccorkell@karoshi.org.uk>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
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'];
$this->username_as_share = ($params['username_as_share'] === 'true');
$params_auth = \OC::$session->get('smb-credentials');
$user = \OC::$session->get('loginname');
$password = $params_auth['password'];
$root=isset($params['root'])?$params['root']:'/';
$share = '';
if ($this->username_as_share) {
$share = '/'.$user;
} elseif (isset($params['share'])) {
$share = $params['share'];
} else {
throw new \Exception();
}
parent::__construct(array(
"user" => $user,
"password" => $password,
"host" => $host,
"share" => $share,
"root" => $root
));
} else {
throw new \Exception();
}
}
public static function login( $params ) {
\OC::$session->set('smb-credentials', $params);
}
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;
}
}
}
}