2015-08-12 17:13:27 -04:00
< ? php
2025-06-30 09:04:05 -04:00
2015-08-12 17:13:27 -04:00
/**
2024-06-06 03:55:47 -04:00
* SPDX - FileCopyrightText : 2018 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - only
2015-08-12 17:13:27 -04:00
*/
2021-10-20 16:39:13 -04:00
2015-08-12 17:13:27 -04:00
namespace OCA\Files_External\Lib\Backend ;
2018-05-28 10:17:19 -04:00
use Icewind\SMB\BasicAuth ;
use Icewind\SMB\KerberosAuth ;
2025-07-10 09:08:22 -04:00
use Icewind\SMB\KerberosTicket ;
2025-05-07 12:48:38 -04:00
use Icewind\SMB\Native\NativeServer ;
use Icewind\SMB\Wrapped\Server ;
2019-11-22 14:52:10 -05:00
use OCA\Files_External\Lib\Auth\AuthMechanism ;
use OCA\Files_External\Lib\Auth\Password\Password ;
2021-10-29 12:27:30 -04:00
use OCA\Files_External\Lib\Auth\SMB\KerberosApacheAuth as KerberosApacheAuthMechanism ;
2019-11-22 14:52:10 -05:00
use OCA\Files_External\Lib\DefinitionParameter ;
2021-10-20 16:39:13 -04:00
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException ;
2025-05-07 12:48:38 -04:00
use OCA\Files_External\Lib\MissingDependency ;
use OCA\Files_External\Lib\Storage\SystemBridge ;
2019-11-22 14:52:10 -05:00
use OCA\Files_External\Lib\StorageConfig ;
use OCP\IL10N ;
2015-08-24 11:32:44 -04:00
use OCP\IUser ;
2015-08-12 17:13:27 -04:00
class SMB extends Backend {
public function __construct ( IL10N $l , Password $legacyAuth ) {
$this
-> setIdentifier ( 'smb' )
2018-05-28 10:17:19 -04:00
-> addIdentifierAlias ( '\OC\Files\Storage\SMB' ) // legacy compat
2016-04-13 18:18:07 -04:00
-> setStorageClass ( '\OCA\Files_External\Lib\Storage\SMB' )
2021-04-22 14:07:39 -04:00
-> setText ( $l -> t ( 'SMB/CIFS' ))
2015-08-12 17:13:27 -04:00
-> addParameters ([
2018-01-26 17:46:40 -05:00
new DefinitionParameter ( 'host' , $l -> t ( 'Host' )),
new DefinitionParameter ( 'share' , $l -> t ( 'Share' )),
2015-08-12 17:13:27 -04:00
( new DefinitionParameter ( 'root' , $l -> t ( 'Remote subfolder' )))
-> setFlag ( DefinitionParameter :: FLAG_OPTIONAL ),
2015-08-21 05:30:42 -04:00
( new DefinitionParameter ( 'domain' , $l -> t ( 'Domain' )))
-> setFlag ( DefinitionParameter :: FLAG_OPTIONAL ),
2019-05-23 15:23:56 -04:00
( new DefinitionParameter ( 'show_hidden' , $l -> t ( 'Show hidden files' )))
-> setType ( DefinitionParameter :: VALUE_BOOLEAN )
-> setFlag ( DefinitionParameter :: FLAG_OPTIONAL ),
2023-10-23 04:15:46 -04:00
( new DefinitionParameter ( 'case_sensitive' , $l -> t ( 'Case sensitive file system' )))
-> setType ( DefinitionParameter :: VALUE_BOOLEAN )
-> setFlag ( DefinitionParameter :: FLAG_OPTIONAL )
-> setDefaultValue ( true )
2023-11-26 05:29:50 -05:00
-> setTooltip ( $l -> t ( 'Disabling it will allow to use a case insensitive file system, but comes with a performance penalty' )),
2020-02-10 10:36:03 -05:00
( new DefinitionParameter ( 'check_acl' , $l -> t ( 'Verify ACL access when listing files' )))
-> setType ( DefinitionParameter :: VALUE_BOOLEAN )
2020-04-10 07:20:20 -04:00
-> setFlag ( DefinitionParameter :: FLAG_OPTIONAL )
2022-09-21 11:44:32 -04:00
-> setTooltip ( $l -> t ( " Check the ACL's of each file or folder inside a directory to filter out items where the account has no read permissions, comes with a performance penalty " )),
2019-09-25 07:30:40 -04:00
( new DefinitionParameter ( 'timeout' , $l -> t ( 'Timeout' )))
2025-05-05 04:52:28 -04:00
-> setType ( DefinitionParameter :: VALUE_TEXT )
-> setFlag ( DefinitionParameter :: FLAG_OPTIONAL )
-> setFlag ( DefinitionParameter :: FLAG_HIDDEN ),
2015-08-12 17:13:27 -04:00
])
-> addAuthScheme ( AuthMechanism :: SCHEME_PASSWORD )
2018-05-28 10:17:19 -04:00
-> addAuthScheme ( AuthMechanism :: SCHEME_SMB )
-> setLegacyAuthMechanism ( $legacyAuth );
2015-08-12 17:13:27 -04:00
}
2025-07-10 09:12:00 -04:00
public function manipulateStorageConfig ( StorageConfig & $storage , ? IUser $user = null ) : void {
2018-05-28 10:17:19 -04:00
$auth = $storage -> getAuthMechanism ();
if ( $auth -> getScheme () === AuthMechanism :: SCHEME_PASSWORD ) {
2021-12-03 08:57:00 -05:00
if ( ! is_string ( $storage -> getBackendOption ( 'user' )) || ! is_string ( $storage -> getBackendOption ( 'password' ))) {
throw new \InvalidArgumentException ( 'user or password is not set' );
}
2018-05-28 10:17:19 -04:00
$smbAuth = new BasicAuth (
$storage -> getBackendOption ( 'user' ),
$storage -> getBackendOption ( 'domain' ),
$storage -> getBackendOption ( 'password' )
);
} else {
switch ( $auth -> getIdentifier ()) {
case 'smb::kerberos' :
$smbAuth = new KerberosAuth ();
2021-10-20 16:39:13 -04:00
break ;
case 'smb::kerberosapache' :
2021-10-29 12:27:30 -04:00
if ( ! $auth instanceof KerberosApacheAuthMechanism ) {
throw new \InvalidArgumentException ( 'invalid authentication backend' );
}
2021-10-20 16:39:13 -04:00
$credentialsStore = $auth -> getCredentialsStore ();
2025-07-10 09:08:22 -04:00
$kerbAuth = new KerberosAuth ();
$kerbAuth -> setTicket ( KerberosTicket :: fromEnv ());
2021-11-04 10:38:42 -04:00
// check if a kerberos ticket is available, else fallback to session credentials
2025-07-10 09:08:22 -04:00
if ( $kerbAuth -> getTicket () ? -> isValid ()) {
2021-11-04 10:38:42 -04:00
$smbAuth = $kerbAuth ;
2021-10-20 16:39:13 -04:00
} else {
try {
$credentials = $credentialsStore -> getLoginCredentials ();
2025-07-10 09:12:00 -04:00
$loginName = $credentials -> getLoginName ();
2021-10-20 16:39:13 -04:00
$pass = $credentials -> getPassword ();
2025-07-10 09:12:00 -04:00
preg_match ( '/(.*)@(.*)/' , $loginName , $matches );
2021-10-29 12:27:30 -04:00
$realm = $storage -> getBackendOption ( 'default_realm' );
if ( empty ( $realm )) {
$realm = 'WORKGROUP' ;
}
if ( count ( $matches ) === 0 ) {
2025-07-10 09:12:00 -04:00
$username = $loginName ;
2021-10-29 12:27:30 -04:00
$workgroup = $realm ;
} else {
2025-07-10 09:12:00 -04:00
[, $username , $workgroup ] = $matches ;
2021-10-20 16:39:13 -04:00
}
$smbAuth = new BasicAuth (
2021-10-29 12:27:30 -04:00
$username ,
$workgroup ,
2021-10-20 16:39:13 -04:00
$pass
);
2025-07-10 09:12:00 -04:00
} catch ( \Exception ) {
2021-10-20 16:39:13 -04:00
throw new InsufficientDataForMeaningfulAnswerException ( 'No session credentials saved' );
}
}
2018-05-28 10:17:19 -04:00
break ;
default :
throw new \InvalidArgumentException ( 'unknown authentication backend' );
}
2015-08-21 05:30:42 -04:00
}
2018-05-28 10:17:19 -04:00
$storage -> setBackendOption ( 'auth' , $smbAuth );
2015-08-21 05:30:42 -04:00
}
2025-05-07 12:48:38 -04:00
2025-07-10 09:12:00 -04:00
public function checkDependencies () : array {
2025-05-07 12:48:38 -04:00
$system = \OCP\Server :: get ( SystemBridge :: class );
if ( NativeServer :: available ( $system )) {
return [];
} elseif ( Server :: available ( $system )) {
$missing = new MissingDependency ( 'php-smbclient' );
$missing -> setOptional ( true );
$missing -> setMessage ( 'The php-smbclient library provides improved compatibility and performance for SMB storages.' );
return [ $missing ];
} else {
$missing = new MissingDependency ( 'php-smbclient' );
$missing -> setMessage ( 'Either the php-smbclient library (preferred) or the smbclient binary is required for SMB storages.' );
return [ $missing , new MissingDependency ( 'smbclient' )];
}
}
2015-08-12 17:13:27 -04:00
}