mirror of
https://github.com/nextcloud/server.git
synced 2025-01-28 13:50:37 +00:00
update icewind/smb to 3.5.1
Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
parent
b391d5714f
commit
a9619c3770
20 changed files with 375 additions and 91 deletions
apps/files_external/3rdparty
2
apps/files_external/3rdparty/.gitignore
vendored
2
apps/files_external/3rdparty/.gitignore
vendored
|
@ -5,6 +5,8 @@ icewind/smb/install_libsmbclient.sh
|
|||
icewind/smb/Makefile
|
||||
icewind/smb/.travis.yml
|
||||
icewind/smb/.scrutinizer.yml
|
||||
icewind/smb/example-apache-kerberos.php
|
||||
icewind/smb/codecov.yml
|
||||
icewind/streams/tests
|
||||
.github
|
||||
.php_cs*
|
||||
|
|
2
apps/files_external/3rdparty/composer.json
vendored
2
apps/files_external/3rdparty/composer.json
vendored
|
@ -9,6 +9,6 @@
|
|||
},
|
||||
"require": {
|
||||
"icewind/streams": "0.7.4",
|
||||
"icewind/smb": "3.4.1"
|
||||
"icewind/smb": "3.5.1"
|
||||
}
|
||||
}
|
||||
|
|
14
apps/files_external/3rdparty/composer.lock
generated
vendored
14
apps/files_external/3rdparty/composer.lock
generated
vendored
|
@ -4,20 +4,20 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "0ffc772b2aaaaffe52decb8d13361976",
|
||||
"content-hash": "ed821b15824934fd2d245faca1f35aad",
|
||||
"packages": [
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v3.4.1",
|
||||
"version": "v3.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3"
|
||||
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
|
||||
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
|
||||
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -49,9 +49,9 @@
|
|||
"description": "php wrapper for smbclient and libsmbclient-php",
|
||||
"support": {
|
||||
"issues": "https://github.com/icewind1991/SMB/issues",
|
||||
"source": "https://github.com/icewind1991/SMB/tree/v3.4.1"
|
||||
"source": "https://github.com/icewind1991/SMB/tree/v3.5.1"
|
||||
},
|
||||
"time": "2021-04-19T13:53:08+00:00"
|
||||
"time": "2021-11-04T14:28:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "icewind/streams",
|
||||
|
|
|
@ -42,30 +42,75 @@ namespace Composer\Autoload;
|
|||
*/
|
||||
class ClassLoader
|
||||
{
|
||||
/** @var ?string */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
/** @var bool */
|
||||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
/** @var bool */
|
||||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
$this->vendorDir = $vendorDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
if (!empty($this->prefixesPsr0)) {
|
||||
|
@ -75,28 +120,47 @@ class ClassLoader
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
return $this->prefixDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
return $this->fallbackDirsPsr0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
return $this->fallbackDirsPsr4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-var array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return $this->classMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $classMap Class to filename map
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addClassMap(array $classMap)
|
||||
{
|
||||
|
@ -111,9 +175,11 @@ class ClassLoader
|
|||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
|
@ -156,11 +222,13 @@ class ClassLoader
|
|||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
|
@ -204,8 +272,10 @@ class ClassLoader
|
|||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param array|string $paths The PSR-0 base directories
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($prefix, $paths)
|
||||
{
|
||||
|
@ -220,10 +290,12 @@ class ClassLoader
|
|||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param array|string $paths The PSR-4 base directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setPsr4($prefix, $paths)
|
||||
{
|
||||
|
@ -243,6 +315,8 @@ class ClassLoader
|
|||
* Turns on searching the include path for class files.
|
||||
*
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUseIncludePath($useIncludePath)
|
||||
{
|
||||
|
@ -265,6 +339,8 @@ class ClassLoader
|
|||
* that have not been registered with the class map.
|
||||
*
|
||||
* @param bool $classMapAuthoritative
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||
{
|
||||
|
@ -285,6 +361,8 @@ class ClassLoader
|
|||
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||
*
|
||||
* @param string|null $apcuPrefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setApcuPrefix($apcuPrefix)
|
||||
{
|
||||
|
@ -305,6 +383,8 @@ class ClassLoader
|
|||
* Registers this instance as an autoloader.
|
||||
*
|
||||
* @param bool $prepend Whether to prepend the autoloader or not
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register($prepend = false)
|
||||
{
|
||||
|
@ -324,6 +404,8 @@ class ClassLoader
|
|||
|
||||
/**
|
||||
* Unregisters this instance as an autoloader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
|
@ -403,6 +485,11 @@ class ClassLoader
|
|||
return self::$registeredLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @param string $ext
|
||||
* @return string|false
|
||||
*/
|
||||
private function findFileWithExtension($class, $ext)
|
||||
{
|
||||
// PSR-4 lookup
|
||||
|
@ -474,6 +561,10 @@ class ClassLoader
|
|||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
* @private
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
|
|
|
@ -20,12 +20,25 @@ use Composer\Semver\VersionParser;
|
|||
*
|
||||
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||
*
|
||||
* To require it's presence, you can require `composer-runtime-api ^2.0`
|
||||
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||
*/
|
||||
class InstalledVersions
|
||||
{
|
||||
/**
|
||||
* @var mixed[]|null
|
||||
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
private static $canGetVendors;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
private static $installedByVendor = array();
|
||||
|
||||
/**
|
||||
|
@ -228,7 +241,7 @@ class InstalledVersions
|
|||
|
||||
/**
|
||||
* @return array
|
||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
|
||||
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
|
||||
*/
|
||||
public static function getRootPackage()
|
||||
{
|
||||
|
@ -242,7 +255,7 @@ class InstalledVersions
|
|||
*
|
||||
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||
* @return array[]
|
||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
|
||||
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
|
||||
*/
|
||||
public static function getRawData()
|
||||
{
|
||||
|
@ -265,7 +278,7 @@ class InstalledVersions
|
|||
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||
*
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
public static function getAllRawData()
|
||||
{
|
||||
|
@ -288,7 +301,7 @@ class InstalledVersions
|
|||
* @param array[] $data A vendor/composer/installed.php data set
|
||||
* @return void
|
||||
*
|
||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
|
||||
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
|
||||
*/
|
||||
public static function reload($data)
|
||||
{
|
||||
|
@ -298,7 +311,7 @@ class InstalledVersions
|
|||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
|
||||
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
|
||||
*/
|
||||
private static function getInstalled()
|
||||
{
|
||||
|
|
|
@ -48,6 +48,7 @@ return array(
|
|||
'Icewind\\SMB\\IShare' => $vendorDir . '/icewind/smb/src/IShare.php',
|
||||
'Icewind\\SMB\\ISystem' => $vendorDir . '/icewind/smb/src/ISystem.php',
|
||||
'Icewind\\SMB\\ITimeZoneProvider' => $vendorDir . '/icewind/smb/src/ITimeZoneProvider.php',
|
||||
'Icewind\\SMB\\KerberosApacheAuth' => $vendorDir . '/icewind/smb/src/KerberosApacheAuth.php',
|
||||
'Icewind\\SMB\\KerberosAuth' => $vendorDir . '/icewind/smb/src/KerberosAuth.php',
|
||||
'Icewind\\SMB\\Native\\NativeFileInfo' => $vendorDir . '/icewind/smb/src/Native/NativeFileInfo.php',
|
||||
'Icewind\\SMB\\Native\\NativeReadStream' => $vendorDir . '/icewind/smb/src/Native/NativeReadStream.php',
|
||||
|
|
|
@ -68,6 +68,7 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3
|
|||
'Icewind\\SMB\\IShare' => __DIR__ . '/..' . '/icewind/smb/src/IShare.php',
|
||||
'Icewind\\SMB\\ISystem' => __DIR__ . '/..' . '/icewind/smb/src/ISystem.php',
|
||||
'Icewind\\SMB\\ITimeZoneProvider' => __DIR__ . '/..' . '/icewind/smb/src/ITimeZoneProvider.php',
|
||||
'Icewind\\SMB\\KerberosApacheAuth' => __DIR__ . '/..' . '/icewind/smb/src/KerberosApacheAuth.php',
|
||||
'Icewind\\SMB\\KerberosAuth' => __DIR__ . '/..' . '/icewind/smb/src/KerberosAuth.php',
|
||||
'Icewind\\SMB\\Native\\NativeFileInfo' => __DIR__ . '/..' . '/icewind/smb/src/Native/NativeFileInfo.php',
|
||||
'Icewind\\SMB\\Native\\NativeReadStream' => __DIR__ . '/..' . '/icewind/smb/src/Native/NativeReadStream.php',
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
"packages": [
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v3.4.1",
|
||||
"version_normalized": "3.4.1.0",
|
||||
"version": "v3.5.1",
|
||||
"version_normalized": "3.5.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3"
|
||||
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
|
||||
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
|
||||
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -25,7 +25,7 @@
|
|||
"phpunit/phpunit": "^8.5|^9.3.8",
|
||||
"psalm/phar": "^4.3"
|
||||
},
|
||||
"time": "2021-04-19T13:53:08+00:00",
|
||||
"time": "2021-11-04T14:28:18+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
@ -46,7 +46,7 @@
|
|||
"description": "php wrapper for smbclient and libsmbclient-php",
|
||||
"support": {
|
||||
"issues": "https://github.com/icewind1991/SMB/issues",
|
||||
"source": "https://github.com/icewind1991/SMB/tree/v3.4.1"
|
||||
"source": "https://github.com/icewind1991/SMB/tree/v3.5.1"
|
||||
},
|
||||
"install-path": "../icewind/smb"
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../',
|
||||
'aliases' => array(),
|
||||
'reference' => '70483a16a3a232758979bb6fa363629b5a16b6a4',
|
||||
'reference' => 'cd72330b8f669e3dc81388be5a92171404f36fec',
|
||||
'name' => 'files_external/3rdparty',
|
||||
'dev' => true,
|
||||
),
|
||||
|
@ -16,16 +16,16 @@
|
|||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../',
|
||||
'aliases' => array(),
|
||||
'reference' => '70483a16a3a232758979bb6fa363629b5a16b6a4',
|
||||
'reference' => 'cd72330b8f669e3dc81388be5a92171404f36fec',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'icewind/smb' => array(
|
||||
'pretty_version' => 'v3.4.1',
|
||||
'version' => '3.4.1.0',
|
||||
'pretty_version' => 'v3.5.1',
|
||||
'version' => '3.5.1.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../icewind/smb',
|
||||
'aliases' => array(),
|
||||
'reference' => '9dba42ab2a3990de29e18cc62b0a8270aceb74e3',
|
||||
'reference' => 'c1ce4fbb2ff1786846d9d0b3850b395ca94cf563',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'icewind/streams' => array(
|
||||
|
|
|
@ -44,13 +44,42 @@ $server = $serverFactory->createServer('localhost', $auth);
|
|||
|
||||
### Using kerberos authentication ###
|
||||
|
||||
There are two ways of using kerberos to authenticate against the smb server:
|
||||
|
||||
- Using a ticket from the php server
|
||||
- Re-using a ticket send by the client
|
||||
|
||||
### Using a server ticket
|
||||
|
||||
Using a server ticket allows the web server to authenticate against the smb server using an existing machine account.
|
||||
|
||||
The ticket needs to be available in the environment of the php process.
|
||||
|
||||
```php
|
||||
$serverFactory = new ServerFactory();
|
||||
$auth = new KerberosAuth();
|
||||
$server = $serverFactory->createServer('localhost', $auth);
|
||||
```
|
||||
|
||||
Note that this requires a valid kerberos ticket to already be available for php
|
||||
### Re-using a client ticket
|
||||
|
||||
By re-using a client ticket you can create a single sign-on setup where the user authenticates against
|
||||
the web service using kerberos. And the web server can forward that ticket to the smb server, allowing it
|
||||
to act on the behalf of the user without requiring the user to enter his passord.
|
||||
|
||||
The setup for such a system is fairly involved and requires roughly the following this
|
||||
|
||||
- The web server is authenticated against kerberos with a machine account
|
||||
- Delegation is enabled for the web server's machine account
|
||||
- Apache is setup to perform kerberos authentication and save the ticket in it's environment
|
||||
- Php has the krb5 extension installed
|
||||
- The client authenticates using a ticket with forwarding enabled
|
||||
|
||||
```php
|
||||
$serverFactory = new ServerFactory();
|
||||
$auth = new KerberosApacheAuth();
|
||||
$server = $serverFactory->createServer('localhost', $auth);
|
||||
```
|
||||
|
||||
### Upload a file ###
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ interface IShare {
|
|||
public function put(string $source, string $target): bool;
|
||||
|
||||
/**
|
||||
* Open a readable stream top a remote file
|
||||
* Open a readable stream to a remote file
|
||||
*
|
||||
* @param string $source
|
||||
* @return resource a read only stream with the contents of the remote file
|
||||
|
|
117
apps/files_external/3rdparty/icewind/smb/src/KerberosApacheAuth.php
vendored
Normal file
117
apps/files_external/3rdparty/icewind/smb/src/KerberosApacheAuth.php
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Icewind\SMB;
|
||||
|
||||
use Icewind\SMB\Exception\DependencyException;
|
||||
use Icewind\SMB\Exception\Exception;
|
||||
|
||||
/**
|
||||
* Use existing kerberos ticket to authenticate and reuse the apache ticket cache (mod_auth_kerb)
|
||||
*/
|
||||
class KerberosApacheAuth extends KerberosAuth implements IAuth {
|
||||
/** @var string */
|
||||
private $ticketPath = "";
|
||||
|
||||
// only working with specific library (mod_auth_kerb, krb5, smbclient) versions
|
||||
/** @var bool */
|
||||
private $saveTicketInMemory = false;
|
||||
|
||||
/** @var bool */
|
||||
private $init = false;
|
||||
|
||||
/**
|
||||
* @param bool $saveTicketInMemory
|
||||
*/
|
||||
public function __construct(bool $saveTicketInMemory = false) {
|
||||
$this->saveTicketInMemory = $saveTicketInMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a valid kerberos ticket is present
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkTicket(): bool {
|
||||
//read apache kerberos ticket cache
|
||||
$cacheFile = getenv("KRB5CCNAME");
|
||||
if (!$cacheFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$krb5 = new \KRB5CCache();
|
||||
$krb5->open($cacheFile);
|
||||
return (bool)$krb5->isValid();
|
||||
}
|
||||
|
||||
private function init(): void {
|
||||
if ($this->init) {
|
||||
return;
|
||||
}
|
||||
$this->init = true;
|
||||
// inspired by https://git.typo3.org/TYPO3CMS/Extensions/fal_cifs.git
|
||||
|
||||
if (!extension_loaded("krb5")) {
|
||||
// https://pecl.php.net/package/krb5
|
||||
throw new DependencyException('Ensure php-krb5 is installed.');
|
||||
}
|
||||
|
||||
//read apache kerberos ticket cache
|
||||
$cacheFile = getenv("KRB5CCNAME");
|
||||
if (!$cacheFile) {
|
||||
throw new Exception('No kerberos ticket cache environment variable (KRB5CCNAME) found.');
|
||||
}
|
||||
|
||||
$krb5 = new \KRB5CCache();
|
||||
$krb5->open($cacheFile);
|
||||
if (!$krb5->isValid()) {
|
||||
throw new Exception('Kerberos ticket cache is not valid.');
|
||||
}
|
||||
|
||||
|
||||
if ($this->saveTicketInMemory) {
|
||||
putenv("KRB5CCNAME=" . (string)$krb5->getName());
|
||||
} else {
|
||||
//workaround: smbclient is not working with the original apache ticket cache.
|
||||
$tmpFilename = tempnam("/tmp", "krb5cc_php_");
|
||||
$tmpCacheFile = "FILE:" . $tmpFilename;
|
||||
$krb5->save($tmpCacheFile);
|
||||
$this->ticketPath = $tmpFilename;
|
||||
putenv("KRB5CCNAME=" . $tmpCacheFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function getExtraCommandLineArguments(): string {
|
||||
$this->init();
|
||||
return parent::getExtraCommandLineArguments();
|
||||
}
|
||||
|
||||
public function setExtraSmbClientOptions($smbClientState): void {
|
||||
$this->init();
|
||||
parent::setExtraSmbClientOptions($smbClientState);
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if (!empty($this->ticketPath) && file_exists($this->ticketPath) && is_file($this->ticketPath)) {
|
||||
unlink($this->ticketPath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -99,7 +99,7 @@ class NativeFileInfo implements IFileInfo {
|
|||
public function isDirectory(): bool {
|
||||
$mode = $this->getMode();
|
||||
if ($mode > 0x1000) {
|
||||
return (bool)($mode & 0x4000); // 0x4000: unix directory flag
|
||||
return ($mode & 0x4000 && !($mode & 0x8000)); // 0x4000: unix directory flag shares bits with 0xC000: socket
|
||||
} else {
|
||||
return (bool)($mode & IFileInfo::MODE_DIRECTORY);
|
||||
}
|
||||
|
|
|
@ -267,14 +267,14 @@ class NativeShare extends AbstractShare {
|
|||
* Open a writeable stream to a remote file
|
||||
* Note: This method will truncate the file to 0bytes first
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @return resource a writeable stream
|
||||
*
|
||||
* @throws NotFoundException
|
||||
* @throws InvalidTypeException
|
||||
*/
|
||||
public function write(string $source) {
|
||||
$url = $this->buildUrl($source);
|
||||
public function write(string $target) {
|
||||
$url = $this->buildUrl($target);
|
||||
$handle = $this->getState()->create($url);
|
||||
return NativeWriteStream::wrap($this->getState(), $handle, 'w', $url);
|
||||
}
|
||||
|
@ -282,14 +282,14 @@ class NativeShare extends AbstractShare {
|
|||
/**
|
||||
* Open a writeable stream and set the cursor to the end of the stream
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @return resource a writeable stream
|
||||
*
|
||||
* @throws NotFoundException
|
||||
* @throws InvalidTypeException
|
||||
*/
|
||||
public function append(string $source) {
|
||||
$url = $this->buildUrl($source);
|
||||
public function append(string $target) {
|
||||
$url = $this->buildUrl($target);
|
||||
$handle = $this->getState()->open($url, "a+");
|
||||
return NativeWriteStream::wrap($this->getState(), $handle, "a", $url);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,14 @@ class NativeState {
|
|||
/** @var bool */
|
||||
protected $connected = false;
|
||||
|
||||
/**
|
||||
* sync the garbage collection cycle
|
||||
* __deconstruct() of KerberosAuth should not called too soon
|
||||
*
|
||||
* @var IAuth|null $auth
|
||||
*/
|
||||
protected $auth = null;
|
||||
|
||||
// see error.h
|
||||
const EXCEPTION_MAP = [
|
||||
1 => ForbiddenException::class,
|
||||
|
@ -107,6 +115,11 @@ class NativeState {
|
|||
}
|
||||
|
||||
$auth->setExtraSmbClientOptions($this->state);
|
||||
|
||||
// sync the garbage collection cycle
|
||||
// __deconstruct() of KerberosAuth should not caled too soon
|
||||
$this->auth = $auth;
|
||||
|
||||
/** @var bool $result */
|
||||
$result = @smbclient_state_init($this->state, $auth->getWorkgroup(), $auth->getUsername(), $auth->getPassword());
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ class System implements ISystem {
|
|||
$result = null;
|
||||
$output = [];
|
||||
exec("which $binary 2>&1", $output, $result);
|
||||
$this->paths[$binary] = $result === 0 ? trim(implode('', $output)) : null;
|
||||
$this->paths[$binary] = $result === 0 && isset($output[0]) ? (string)$output[0] : null;
|
||||
}
|
||||
return $this->paths[$binary];
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class Connection extends RawConnection {
|
|||
public function clearTillPrompt(): void {
|
||||
$this->write('');
|
||||
do {
|
||||
$promptLine = $this->readLine();
|
||||
$promptLine = $this->readTillPrompt();
|
||||
if ($promptLine === false) {
|
||||
break;
|
||||
}
|
||||
|
@ -56,13 +56,12 @@ class Connection extends RawConnection {
|
|||
if ($this->write('') === false) {
|
||||
throw new ConnectionRefusedException();
|
||||
}
|
||||
$this->readLine();
|
||||
$this->readTillPrompt();
|
||||
}
|
||||
|
||||
/**
|
||||
* get all unprocessed output from smbclient until the next prompt
|
||||
*
|
||||
* @param (callable(string):bool)|null $callback (optional) callback to call for every line read
|
||||
* @return string[]
|
||||
* @throws AuthenticationException
|
||||
* @throws ConnectException
|
||||
|
@ -71,42 +70,22 @@ class Connection extends RawConnection {
|
|||
* @throws NoLoginServerException
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
public function read(callable $callback = null): array {
|
||||
public function read(): array {
|
||||
if (!$this->isValid()) {
|
||||
throw new ConnectionException('Connection not valid');
|
||||
}
|
||||
$promptLine = $this->readLine(); //first line is prompt
|
||||
if ($promptLine === false) {
|
||||
$this->unknownError($promptLine);
|
||||
}
|
||||
$this->parser->checkConnectionError($promptLine);
|
||||
|
||||
$output = [];
|
||||
if (!$this->isPrompt($promptLine)) {
|
||||
$line = $promptLine;
|
||||
} else {
|
||||
$line = $this->readLine();
|
||||
}
|
||||
if ($line === false) {
|
||||
$this->unknownError($promptLine);
|
||||
}
|
||||
while ($line !== false && !$this->isPrompt($line)) { //next prompt functions as delimiter
|
||||
if (is_callable($callback)) {
|
||||
$result = $callback($line);
|
||||
if ($result === false) { // allow the callback to close the connection for infinite running commands
|
||||
$this->close(true);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$output[] = $line;
|
||||
}
|
||||
$line = $this->readLine();
|
||||
$output = $this->readTillPrompt();
|
||||
if ($output === false) {
|
||||
$this->unknownError(false);
|
||||
}
|
||||
$output = explode("\n", $output);
|
||||
// last line contains the prompt
|
||||
array_pop($output);
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function isPrompt(string $line): bool {
|
||||
return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER;
|
||||
return substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,6 +111,6 @@ class Connection extends RawConnection {
|
|||
// ignore any errors while trying to send the close command, the process might already be dead
|
||||
@$this->write('close' . PHP_EOL);
|
||||
}
|
||||
parent::close($terminate);
|
||||
$this->close_process($terminate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,16 +65,20 @@ class NotifyHandler implements INotifyHandler {
|
|||
*/
|
||||
public function listen(callable $callback): void {
|
||||
if ($this->listening) {
|
||||
$this->connection->read(function (string $line) use ($callback): bool {
|
||||
while (true) {
|
||||
$line = $this->connection->readLine();
|
||||
if ($line === false) {
|
||||
break;
|
||||
}
|
||||
$this->checkForError($line);
|
||||
$change = $this->parseChangeLine($line);
|
||||
if ($change) {
|
||||
$result = $callback($change);
|
||||
return $result === false ? false : true;
|
||||
} else {
|
||||
return true;
|
||||
if ($result === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ class RawConnection {
|
|||
|
||||
setlocale(LC_ALL, Server::LOCALE);
|
||||
$env = array_merge($this->env, [
|
||||
'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!!
|
||||
'CLI_FORCE_INTERACTIVE' => 'y', // Make sure the prompt is displayed
|
||||
'CLI_NO_READLINE' => 1, // Not all distros build smbclient with readline, disable it to get consistent behaviour
|
||||
'LC_ALL' => Server::LOCALE,
|
||||
'LANG' => Server::LOCALE,
|
||||
'COLUMNS' => 8192 // prevent smbclient from line-wrapping it's output
|
||||
|
@ -91,7 +92,7 @@ class RawConnection {
|
|||
public function isValid(): bool {
|
||||
if (is_resource($this->process)) {
|
||||
$status = proc_get_status($this->process);
|
||||
return (bool)$status['running'];
|
||||
return $status['running'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -109,13 +110,30 @@ class RawConnection {
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* read output till the next prompt
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function readTillPrompt() {
|
||||
$output = "";
|
||||
do {
|
||||
$chunk = $this->readLine('\> ');
|
||||
if ($chunk === false) {
|
||||
return false;
|
||||
}
|
||||
$output .= $chunk;
|
||||
} while (strlen($chunk) == 4096 && strpos($chunk, "smb:") === false);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a line of output
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function readLine() {
|
||||
return stream_get_line($this->getOutputStream(), 4086, "\n");
|
||||
public function readLine(string $end = "\n") {
|
||||
return stream_get_line($this->getOutputStream(), 4096, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,6 +220,14 @@ class RawConnection {
|
|||
* @psalm-assert null $this->process
|
||||
*/
|
||||
public function close(bool $terminate = true): void {
|
||||
$this->close_process($terminate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $terminate
|
||||
* @psalm-assert null $this->process
|
||||
*/
|
||||
protected function close_process(bool $terminate = true): void {
|
||||
if (!is_resource($this->process)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -345,11 +345,17 @@ class Share extends AbstractShare {
|
|||
// since returned stream is closed by the caller we need to create a new instance
|
||||
// since we can't re-use the same file descriptor over multiple calls
|
||||
$connection = $this->getConnection();
|
||||
stream_set_blocking($connection->getOutputStream(), false);
|
||||
|
||||
$connection->write('get ' . $source . ' ' . $this->system->getFD(5));
|
||||
$connection->write('exit');
|
||||
$fh = $connection->getFileOutputStream();
|
||||
stream_context_set_option($fh, 'file', 'connection', $connection);
|
||||
$fh = CallbackWrapper::wrap($fh, function() use ($connection) {
|
||||
$connection->write('');
|
||||
});
|
||||
if (!is_resource($fh)) {
|
||||
throw new Exception("Failed to wrap file output");
|
||||
}
|
||||
return $fh;
|
||||
}
|
||||
|
||||
|
@ -374,7 +380,9 @@ class Share extends AbstractShare {
|
|||
|
||||
// use a close callback to ensure the upload is finished before continuing
|
||||
// this also serves as a way to keep the connection in scope
|
||||
$stream = CallbackWrapper::wrap($fh, null, null, function () use ($connection) {
|
||||
$stream = CallbackWrapper::wrap($fh, function() use ($connection) {
|
||||
$connection->write('');
|
||||
}, null, function () use ($connection) {
|
||||
$connection->close(false); // dont terminate, give the upload some time
|
||||
});
|
||||
if (is_resource($stream)) {
|
||||
|
@ -446,7 +454,7 @@ class Share extends AbstractShare {
|
|||
* @return string[]
|
||||
*/
|
||||
protected function execute(string $command): array {
|
||||
$this->connect()->write($command . PHP_EOL);
|
||||
$this->connect()->write($command);
|
||||
return $this->connect()->read();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue