Merge pull request 'ci' (#135) from forgejo-ci into master

Reviewed-on: https://codeberg.org/icewind/SMB/pulls/135
This commit is contained in:
Robin Appelman 2025-10-25 20:27:25 +02:00
commit 46cbd2cc8f
26 changed files with 252 additions and 159 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

2
.envrc.license Normal file
View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2014 Robin Appelman <robin@icewind.nl>
SPDX-License-Identifier: MIT

View file

@ -1,41 +1,39 @@
# SPDX-FileCopyrightText: 2021 Robin Appelman <robin@icewind.nl> # SPDX-FileCopyrightText: 2021 Robin Appelman <robin@icewind.nl>
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
on: [push, pull_request] on:
pull_request:
push:
branches:
- main
- master
name: CI name: CI
jobs: jobs:
php-cs-fixer: php-cs-fixer:
name: PHP-CS-Fixer name: PHP-CS-Fixer
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: https://github.com/shivammathur/setup-php@v2
with: with:
php-version: '8.0' php-version: '8.2'
extensions: apcu extensions: apcu
- name: Composer
run: composer install
- name: PHP-CS-Fixer - name: PHP-CS-Fixer
uses: OskarStark/php-cs-fixer-ga@2.16.7 run: |
with: composer run cs:check
args: --diff --dry-run --allow-risky yes --stop-on-violation --using-cache=no --path-mode=intersection
php-versions: php-versions:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
name: Unit tests name: Unit tests - PHP ${{ matrix.php-version }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
backend:
- smbclient
- libsmbclient
php-version: php-version:
- "7.2"
- "7.3"
- "7.4"
- "8.0"
- "8.1"
- "8.2" - "8.2"
- "8.3" - "8.3"
- "8.4" - "8.4"
@ -47,17 +45,17 @@ jobs:
ACCOUNT_test: test ACCOUNT_test: test
UID_test: 1000 UID_test: 1000
SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes" SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes"
ports:
- 139:139
- 445:445
steps: steps:
- name: Install packages - name: Install packages
env:
DEBIAN_FRONTEND: noninteractive
run: | run: |
sudo apt-get install smbclient libsmbclient-dev sudo apt-get update
- uses: actions/checkout@v3 sudo apt-get install -y smbclient libsmbclient-dev
- uses: actions/checkout@v4
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: https://github.com/shivammathur/setup-php@v2
with: with:
php-version: "${{ matrix.php-version }}" php-version: "${{ matrix.php-version }}"
extensions: apcu, smbclient extensions: apcu, smbclient
@ -66,23 +64,32 @@ jobs:
run: composer install run: composer install
- name: Config - name: Config
run: | run: |
echo '{"host": "localhost","user": "test","password": "test","share": "test","root": ""}' > tests/config.json echo '{"host": "samba","user": "test","password": "test","share": "test","root": ""}' > tests/config.json
- name: PHPUnit Tests - name: PHPUnit Tests - smbclient
uses: nick-invision/retry@v2 uses: https://github.com/nick-invision/retry@v2
with: with:
timeout_minutes: 2 timeout_minutes: 2
max_attempts: 3 max_attempts: 3
retry_on: timeout retry_on: timeout
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
env: env:
BACKEND: ${{ matrix.backend }} BACKEND: smbclient
- uses: codecov/codecov-action@v3 - name: PHPUnit Tests - libsmbclient
uses: https://github.com/nick-invision/retry@v2
with:
timeout_minutes: 2
max_attempts: 3
retry_on: timeout
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
env:
BACKEND: libsmbclient
- uses: https://github.com/codecov/codecov-action@v3
with: with:
files: ./coverage.xml files: ./coverage.xml
smb-versions: smb-versions:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
name: Unit tests name: Unit tests - Samba ${{ matrix.server-version }} - smbclient ${{ matrix.client-version }}
strategy: strategy:
fail-fast: false fail-fast: false
@ -109,32 +116,32 @@ jobs:
ACCOUNT_test: test ACCOUNT_test: test
UID_test: 1000 UID_test: 1000
SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes" SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes"
ports:
- 139:139
- 445:445
steps: steps:
- name: Setup smbclient - name: Setup smbclient
env:
DEBIAN_FRONTEND: noninteractive
run: | run: |
sudo apt install libjansson4 libcap2 libbsd0 libreadline8 libicu70 sudo apt-get update
sudo apt install -y libjansson4 libcap2 libbsd0 libreadline8 libicu70
sudo mkdir -p /etc/samba /var/lib/samba/private sudo mkdir -p /etc/samba /var/lib/samba/private
echo "[global]\nclient min protocol = SMB2\nclient max protocol = SMB3" | sudo tee /etc/samba/smb.conf echo "[global]\nclient min protocol = SMB2\nclient max protocol = SMB3" | sudo tee /etc/samba/smb.conf
sudo wget "https://github.com/icewind1991/smbclient-builder/releases/download/v0.2.0/smbclient-${{ matrix.client-version }}" -O /usr/local/bin/smbclient sudo wget "https://github.com/icewind1991/smbclient-builder/releases/download/v0.2.0/smbclient-${{ matrix.client-version }}" -O /usr/local/bin/smbclient
sudo chmod +x /usr/local/bin/smbclient sudo chmod +x /usr/local/bin/smbclient
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: https://github.com/shivammathur/setup-php@v2
with: with:
php-version: 8.0 php-version: 8.2
extensions: apcu, smbclient extensions: apcu, smbclient
coverage: pcov coverage: pcov
- name: Composer - name: Composer
run: composer install run: composer install
- name: Config - name: Config
run: | run: |
echo '{"host": "localhost","user": "test","password": "test","share": "test","root": ""}' > tests/config.json echo '{"host": "samba","user": "test","password": "test","share": "test","root": ""}' > tests/config.json
- name: PHPUnit Tests - name: PHPUnit Tests
uses: nick-invision/retry@v2 uses: https://github.com/nick-invision/retry@v2
with: with:
timeout_minutes: 2 timeout_minutes: 2
max_attempts: 3 max_attempts: 3
@ -142,12 +149,12 @@ jobs:
command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
env: env:
BACKEND: smbclient BACKEND: smbclient
- uses: codecov/codecov-action@v3 - uses: https://github.com/codecov/codecov-action@v3
with: with:
files: ./coverage.xml files: ./coverage.xml
alpine-test: alpine-test:
runs-on: ubuntu-22.04 runs-on: alpine-latest
name: Unit tests (alpine) name: Unit tests (alpine)
services: services:
@ -157,83 +164,51 @@ jobs:
ACCOUNT_test: test ACCOUNT_test: test
UID_test: 1000 UID_test: 1000
SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes" SAMBA_VOLUME_CONFIG_test: "[test]; path=/tmp; valid users = test; guest ok = no; read only = no; browseable = yes"
ports:
- 139:139
- 445:445
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup PHP - name: Install dependencies
uses: shivammathur/setup-php@v2 shell: sh
with: run: |
php-version: 8.0 apk add bash sudo git coreutils samba-client php composer php-curl php-iconv php-mbstring php-openssl php-zip php-phar php-tokenizer php-dom php-xml php-xmlwriter
- name: Composer - name: Composer
run: composer install run: composer install
- name: Pull images
run: |
docker pull icewind1991/smbclient-php-alpine
- name: Config - name: Config
run: | run: |
echo '{"host": "localhost","user": "test","password": "test","share": "test","root": ""}' > tests/config.json echo '{"host": "samba","user": "test","password": "test","share": "test","root": ""}' > tests/config.json
- name: PHPUnit Tests - name: PHPUnit Tests - smbclient
run: | uses: https://github.com/nick-invision/retry@v2
docker run --network "host" --rm -v $PWD:/smb icewind1991/smbclient-php-alpine /smb/vendor/bin/phpunit -c /smb/tests/phpunit.xml /smb/tests
kerberos-sso:
runs-on: ubuntu-22.04
name: Kerberos SSO tests
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with: with:
php-version: 8.0 timeout_minutes: 2
- name: Composer max_attempts: 3
run: composer install retry_on: timeout
- name: Pull images command: php ./vendor/bin/phpunit tests -c tests/phpunit.xml --coverage-clover=coverage.xml
run: | env:
docker pull icewind1991/samba-krb-test-dc BACKEND: smbclient
docker pull icewind1991/samba-krb-test-apache
docker pull icewind1991/samba-krb-test-client
- name: Setup AD-DC
run: |
tests/setup-krb.sh
- name: Test kerberos auth
run: |
DC_IP=$(docker inspect dc --format '{{.NetworkSettings.IPAddress}}')
LIST=$(docker run --rm --name client -v /tmp/shared:/shared --dns $DC_IP --hostname client.domain.test icewind1991/samba-krb-test-client \
curl -s --negotiate -u testuser@DOMAIN.TEST: --delegation always http://httpd.domain.test/example-sso-kerberos.php)
echo $LIST
LIST=$(echo $LIST | tr -d '[:space:]')
[[ $LIST == "test.txt" ]]
- name: Apache logs
if: always()
run: |
docker logs apache
static-psalm-analysis: static-psalm-analysis:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
name: Psalm static analysis name: Psalm static analysis - PHP ${{ matrix.php-version }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-version: php-version:
- "7.2"
- "7.3"
- "7.4"
- "8.0"
- "8.1"
- "8.2" - "8.2"
- "8.3" - "8.3"
- "8.4"
steps: steps:
- name: krb5-dev - name: krb5-dev
run: sudo apt-get install -y libkrb5-dev libsmbclient-dev env:
DEBIAN_FRONTEND: noninteractive
run: |
sudo apt-get update
sudo apt-get install -y libkrb5-dev libsmbclient-dev
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Set up php - name: Set up php
uses: shivammathur/setup-php@master uses: https://github.com/shivammathur/setup-php@master
with: with:
php-version: "${{ matrix.php-version }}" php-version: "${{ matrix.php-version }}"
tools: composer:v2 tools: composer:v2
@ -248,16 +223,18 @@ jobs:
phpstan: phpstan:
name: PHPStan Static Analysis name: PHPStan Static Analysis
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
steps: steps:
- name: krb5-dev - name: krb5-dev
run: sudo apt-get install -y libkrb5-dev run: |
- uses: actions/checkout@v3 sudo apt-get update
sudo apt-get install -y libkrb5-dev
- uses: actions/checkout@v4
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@v2 uses: https://github.com/shivammathur/setup-php@v2
with: with:
php-version: '8.0' php-version: 8.3
extensions: apcu, smbclient, krb5 extensions: apcu, smbclient, krb5
env: env:
fail-fast: true fail-fast: true

View file

@ -10,6 +10,6 @@ jobs:
reuse-compliance-check: reuse-compliance-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - uses: https://github.com/actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- name: REUSE Compliance Check - name: REUSE Compliance Check
uses: fsfe/reuse-action@a46482ca367aef4454a87620aa37c2be4b2f8106 # v3.0.0 uses: https://github.com/fsfe/reuse-action@a46482ca367aef4454a87620aa37c2be4b2f8106 # v3.0.0

View file

@ -9,13 +9,16 @@ $finder = PhpCsFixer\Finder::create()
->exclude('vendor') ->exclude('vendor')
->in(__DIR__) ->in(__DIR__)
; ;
return PhpCsFixer\Config::create() return (new PhpCsFixer\Config())
->setRules([ ->setRules([
'@PSR2' => true, '@PSR2' => true,
'curly_braces_position' => [
'classes_opening_brace' => 'same_line',
'functions_opening_brace' => 'same_line',
],
'array_syntax' => ['syntax' => 'short'], 'array_syntax' => ['syntax' => 'short'],
'braces' => ['position_after_functions_and_oop_constructs' => 'same'], 'braces' => ['position_after_functions_and_oop_constructs' => 'same'],
'binary_operator_spaces' => ['align_double_arrow' => true, 'align_equals' => false], 'binary_operator_spaces' => ['operators' => ['=>' => 'align_single_space']],
]) ])
->setIndent("\t") ->setIndent("\t")
->setFinder($finder) ->setFinder($finder);
;

View file

@ -9,14 +9,14 @@
} }
], ],
"require": { "require": {
"php": ">=7.2", "php": ">=8.2",
"icewind/streams": ">=0.7.3" "icewind/streams": ">=0.7.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^8.5|^9.3.8", "phpunit/phpunit": "^8.5|^9.3.8",
"friendsofphp/php-cs-fixer": "^2.16", "friendsofphp/php-cs-fixer": "v3.89.0",
"phpstan/phpstan": "^0.12.57", "phpstan/phpstan": "^0.12.57",
"psalm/phar": "^4.3" "psalm/phar": "6.*"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

47
flake.lock generated Normal file
View file

@ -0,0 +1,47 @@
{
"nodes": {
"flakelight": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1751892651,
"narHash": "sha256-oLNt26YpwTVj+t7BunpmL+iOUHVt5VLvYB1vnJ7Kw28=",
"owner": "nix-community",
"repo": "flakelight",
"rev": "f4604c27e117ad54391160ae207b519694b9f845",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "flakelight",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1751741127,
"narHash": "sha256-t75Shs76NgxjZSgvvZZ9qOmz5zuBE8buUaYD28BMTxg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "29e290002bfff26af1db6f64d070698019460302",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-25.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"flakelight": "flakelight",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

2
flake.lock.license Normal file
View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2014 Robin Appelman <robin@icewind.nl>
SPDX-License-Identifier: MIT

34
flake.nix Normal file
View file

@ -0,0 +1,34 @@
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-25.05";
flakelight = {
url = "github:nix-community/flakelight";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {flakelight, ...}:
flakelight ./. {
formatters = pkgs: {
"*.php" = pkgs.lib.getExe pkgs.php84.packages.php-cs-fixer;
};
devShell.packages = pkgs: let
php_version = "81";
php = pkgs.pkgs."php${php_version}".buildEnv {
extensions = {
enabled,
all,
}:
enabled
++ (with all; [
dom
simplexml
tokenizer
filter
]);
};
in [
php.packages.composer
php
];
};
}

2
flake.nix.license Normal file
View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: 2014 Robin Appelman <robin@icewind.nl>
SPDX-License-Identifier: MIT

View file

@ -5,6 +5,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedCode="false"
> >
<stubs> <stubs>
<file name="tests/krb.phpstub" preloadClasses="true"/> <file name="tests/krb.phpstub" preloadClasses="true"/>

View file

@ -33,7 +33,7 @@ class BasicAuth implements IAuth {
} }
public function getExtraCommandLineArguments(): string { public function getExtraCommandLineArguments(): string {
return ($this->workgroup) ? '-W ' . escapeshellarg($this->workgroup) : ''; return ($this->workgroup !== null) ? '-W ' . escapeshellarg($this->workgroup) : '';
} }
public function setExtraSmbClientOptions($smbClientState): void { public function setExtraSmbClientOptions($smbClientState): void {

View file

@ -23,7 +23,7 @@ class Exception extends \Exception {
*/ */
public static function unknown(?string $path, $error): Exception { public static function unknown(?string $path, $error): Exception {
$message = 'Unknown error (' . (string)$error . ')'; $message = 'Unknown error (' . (string)$error . ')';
if ($path) { if ($path !== null) {
$message .= ' for ' . $path; $message .= ' for ' . $path;
} }

View file

@ -12,6 +12,9 @@ class InvalidRequestException extends Exception {
*/ */
protected $path; protected $path;
/**
* @psalm-suppress ParamNameMismatch
*/
public function __construct(string $path = "", int $code = 0, ?\Throwable $previous = null) { public function __construct(string $path = "", int $code = 0, ?\Throwable $previous = null) {
$class = get_class($this); $class = get_class($this);
$parts = explode('\\', $class); $parts = explode('\\', $class);

View file

@ -9,5 +9,4 @@ declare(strict_types=1);
namespace Icewind\SMB\Exception; namespace Icewind\SMB\Exception;
class InvalidTicket extends Exception { class InvalidTicket extends Exception {
} }

View file

@ -26,7 +26,7 @@ class KerberosTicket {
return $this->cacheName; return $this->cacheName;
} }
public function getName(): string{ public function getName(): string {
return $this->krb5->getName(); return $this->krb5->getName();
} }
@ -47,7 +47,7 @@ class KerberosTicket {
*/ */
public static function fromEnv(): ?KerberosTicket { public static function fromEnv(): ?KerberosTicket {
$ticketName = getenv("KRB5CCNAME"); $ticketName = getenv("KRB5CCNAME");
if (!$ticketName) { if ($ticketName === false) {
return null; return null;
} }
$krb5 = new KRB5CCache(); $krb5 = new KRB5CCache();

View file

@ -129,9 +129,17 @@ class NativeFileInfo implements IFileInfo {
$attribute = $this->share->getAttribute($this->path, 'system.nt_sec_desc.acl.*+'); $attribute = $this->share->getAttribute($this->path, 'system.nt_sec_desc.acl.*+');
foreach (explode(',', $attribute) as $acl) { foreach (explode(',', $attribute) as $acl) {
list($user, $permissions) = explode(':', $acl, 2); $parts = explode(':', $acl, 2);
if (count($parts) !== 2) {
continue;
}
list($user, $permissions) = $parts;
$user = trim($user, '\\'); $user = trim($user, '\\');
list($type, $flags, $mask) = explode('/', $permissions); $parts = explode('/', $permissions);
if (count($parts) < 3) {
continue;
}
list($type, $flags, $mask) = $parts;
$mask = hexdec($mask); $mask = hexdec($mask);
$acls[$user] = new ACL((int)$type, (int)$flags, (int)$mask); $acls[$user] = new ACL((int)$type, (int)$flags, (int)$mask);

View file

@ -322,7 +322,7 @@ class NativeState {
if (!$this->state) { if (!$this->state) {
throw new ConnectionException("Not connected"); throw new ConnectionException("Not connected");
} }
if ($length) { if ($length !== null) {
$result = @smbclient_write($this->state, $file, $data, $length); $result = @smbclient_write($this->state, $file, $data, $length);
} else { } else {
$result = @smbclient_write($this->state, $file, $data); $result = @smbclient_write($this->state, $file, $data);

View file

@ -28,7 +28,7 @@ class TimeZoneProvider implements ITimeZoneProvider {
$timeZone = null; $timeZone = null;
$net = $this->system->getNetPath(); $net = $this->system->getNetPath();
// for local domain names we can assume same timezone // for local domain names we can assume same timezone
if ($net && $host && strpos($host, '.') !== false) { if ($net !== null && $host && strpos($host, '.') !== false) {
$command = sprintf( $command = sprintf(
'%s time zone -S %s', '%s time zone -S %s',
$net, $net,
@ -37,11 +37,12 @@ class TimeZoneProvider implements ITimeZoneProvider {
$timeZone = exec($command); $timeZone = exec($command);
} }
if (!$timeZone) { if (!is_string($timeZone)) {
$date = $this->system->getDatePath(); $date = $this->system->getDatePath();
if ($date) { if ($date !== null) {
$timeZone = exec($date . " +%z"); $timeZone = exec($date . " +%z");
} else { }
if (!is_string($timeZone)) {
$timeZone = date_default_timezone_get(); $timeZone = date_default_timezone_get();
} }
} }

View file

@ -93,11 +93,11 @@ class Connection extends RawConnection {
* @return no-return * @return no-return
*/ */
private function unknownError($promptLine = '') { private function unknownError($promptLine = '') {
if ($promptLine) { //maybe we have some error we missed on the previous line if ($promptLine !== false) { //maybe we have some error we missed on the previous line
throw new ConnectException('Unknown error (' . $promptLine . ')'); throw new ConnectException('Unknown error (' . $promptLine . ')');
} else { } else {
$error = $this->readError(); // maybe something on stderr $error = $this->readError(); // maybe something on stderr
if ($error) { if ($error !== false) {
throw new ConnectException('Unknown error (stderr: ' . $error . ')'); throw new ConnectException('Unknown error (stderr: ' . $error . ')');
} else { } else {
throw new ConnectException('Unknown error'); throw new ConnectException('Unknown error');

View file

@ -78,7 +78,9 @@ class Parser {
* @throws NotFoundException * @throws NotFoundException
*/ */
public function checkForError(array $output, string $path): void { public function checkForError(array $output, string $path): void {
if (strpos($output[0], 'does not exist')) { $error = '';
if (isset($output[0])) {
if (strpos($output[0], 'does not exist') > 0) {
throw new NotFoundException($path); throw new NotFoundException($path);
} }
$error = $this->getErrorCode($output[0]); $error = $this->getErrorCode($output[0]);
@ -87,6 +89,7 @@ class Parser {
$localPath = substr($output[0], strlen(self::MSG_NOT_FOUND)); $localPath = substr($output[0], strlen(self::MSG_NOT_FOUND));
throw new InvalidResourceException('Failed opening local file "' . $localPath . '" for writing'); throw new InvalidResourceException('Failed opening local file "' . $localPath . '" for writing');
} }
}
throw Exception::fromMap(self::EXCEPTION_MAP, $error, $path); throw Exception::fromMap(self::EXCEPTION_MAP, $error, $path);
} }
@ -197,12 +200,12 @@ class Parser {
public function parseListShares(array $output): array { public function parseListShares(array $output): array {
$shareNames = []; $shareNames = [];
foreach ($output as $line) { foreach ($output as $line) {
if (strpos($line, '|')) { if (strpos($line, '|') > 0) {
list($type, $name, $description) = explode('|', $line); list($type, $name, $description) = explode('|', $line);
if (strtolower($type) === 'disk') { if (strtolower($type) === 'disk') {
$shareNames[$name] = $description; $shareNames[$name] = $description;
} }
} elseif (strpos($line, 'Disk')) { } elseif (strpos($line, 'Disk') > 0) {
// new output format // new output format
list($name, $description) = explode('Disk', $line); list($name, $description) = explode('Disk', $line);
$shareNames[trim($name)] = trim($description); $shareNames[trim($name)] = trim($description);
@ -221,12 +224,24 @@ class Parser {
if (strpos($acl, ':') === false) { if (strpos($acl, ':') === false) {
continue; continue;
} }
[$type, $acl] = explode(':', $acl, 2); $parts = explode(':', $acl, 2);
if (count($parts) !== 2) {
continue;
}
[$type, $acl] = $parts;
if ($type !== 'ACL') { if ($type !== 'ACL') {
continue; continue;
} }
[$user, $permissions] = explode(':', $acl, 2); $parts = explode(':', $acl, 2);
[$type, $flags, $mask] = explode('/', $permissions); if (count($parts) !== 2) {
continue;
}
[$user, $permissions] = $parts;
$parts = explode('/', $permissions);
if (count($parts) < 3) {
continue;
}
[$type, $flags, $mask] = $parts;
$type = $type === 'ALLOWED' ? ACL::TYPE_ALLOW : ACL::TYPE_DENY; $type = $type === 'ALLOWED' ? ACL::TYPE_ALLOW : ACL::TYPE_DENY;

View file

@ -28,7 +28,7 @@ class Server extends AbstractServer {
} }
private function getAuthFileArgument(): string { private function getAuthFileArgument(): string {
if ($this->getAuth()->getUsername()) { if ($this->getAuth()->getUsername() !== null) {
return '--authentication-file=' . $this->system->getFD(3); return '--authentication-file=' . $this->system->getFD(3);
} else { } else {
return ''; return '';
@ -54,8 +54,8 @@ class Server extends AbstractServer {
$smbClient, $smbClient,
$this->getAuthFileArgument(), $this->getAuthFileArgument(),
$this->getAuth()->getExtraCommandLineArguments(), $this->getAuth()->getExtraCommandLineArguments(),
$maxProtocol ? "--option='client max protocol=" . $maxProtocol . "'" : "", ($maxProtocol !== null) ? "--option='client max protocol=" . $maxProtocol . "'" : "",
$minProtocol ? "--option='client min protocol=" . $minProtocol . "'" : "", ($minProtocol !== null) ? "--option='client min protocol=" . $minProtocol . "'" : "",
escapeshellarg('//' . $this->getHost()) escapeshellarg('//' . $this->getHost())
); );
$connection = new RawConnection($command); $connection = new RawConnection($command);

View file

@ -76,7 +76,7 @@ class Share extends AbstractShare {
} }
private function getAuthFileArgument(): string { private function getAuthFileArgument(): string {
if ($this->server->getAuth()->getUsername()) { if ($this->server->getAuth()->getUsername() !== null) {
return '--authentication-file=' . $this->system->getFD(3); return '--authentication-file=' . $this->system->getFD(3);
} else { } else {
return ''; return '';
@ -94,13 +94,13 @@ class Share extends AbstractShare {
$command = sprintf( $command = sprintf(
'%s %s%s -t %s %s %s %s %s %s', '%s %s%s -t %s %s %s %s %s %s',
self::EXEC_CMD, self::EXEC_CMD,
$stdBuf ? $stdBuf . ' -o0 ' : '', ($stdBuf !== null) ? $stdBuf . ' -o0 ' : '',
$smbClient, $smbClient,
$this->server->getOptions()->getTimeout(), $this->server->getOptions()->getTimeout(),
$this->getAuthFileArgument(), $this->getAuthFileArgument(),
$this->server->getAuth()->getExtraCommandLineArguments(), $this->server->getAuth()->getExtraCommandLineArguments(),
$maxProtocol ? "--option='client max protocol=" . $maxProtocol . "'" : "", ($maxProtocol !== null) ? "--option='client max protocol=" . $maxProtocol . "'" : "",
$minProtocol ? "--option='client min protocol=" . $minProtocol . "'" : "", ($minProtocol !== null) ? "--option='client min protocol=" . $minProtocol . "'" : "",
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
); );
$connection = new Connection($command, $this->parser); $connection = new Connection($command, $this->parser);
@ -349,7 +349,7 @@ class Share extends AbstractShare {
$connection->write('get ' . $source . ' ' . $this->system->getFD(5)); $connection->write('get ' . $source . ' ' . $this->system->getFD(5));
$connection->write('exit'); $connection->write('exit');
$fh = $connection->getFileOutputStream(); $fh = $connection->getFileOutputStream();
$fh = CallbackWrapper::wrap($fh, function() use ($connection) { $fh = CallbackWrapper::wrap($fh, function () use ($connection) {
$connection->write(''); $connection->write('');
}); });
if (!is_resource($fh)) { if (!is_resource($fh)) {
@ -379,7 +379,7 @@ class Share extends AbstractShare {
// use a close callback to ensure the upload is finished before continuing // use a close callback to ensure the upload is finished before continuing
// this also serves as a way to keep the connection in scope // this also serves as a way to keep the connection in scope
$stream = CallbackWrapper::wrap($fh, function() use ($connection) { $stream = CallbackWrapper::wrap($fh, function () use ($connection) {
$connection->write(''); $connection->write('');
}, null, function () use ($connection) { }, null, function () use ($connection) {
$connection->close(false); // dont terminate, give the upload some time $connection->close(false); // dont terminate, give the upload some time
@ -439,7 +439,7 @@ class Share extends AbstractShare {
* @throws DependencyException * @throws DependencyException
*/ */
public function notify(string $path): INotifyHandler { public function notify(string $path): INotifyHandler {
if (!$this->system->getStdBufPath()) { //stdbuf is required to disable smbclient's output buffering if ($this->system->getStdBufPath() == null) { //stdbuf is required to disable smbclient's output buffering
throw new DependencyException('stdbuf is required for usage of the notify command'); throw new DependencyException('stdbuf is required for usage of the notify command');
} }
$connection = $this->getConnection(); // use a fresh connection since the notify command blocks the process $connection = $this->getConnection(); // use a fresh connection since the notify command blocks the process
@ -519,7 +519,7 @@ class Share extends AbstractShare {
*/ */
protected function getAcls(string $path): array { protected function getAcls(string $path): array {
$commandPath = $this->system->getSmbcAclsPath(); $commandPath = $this->system->getSmbcAclsPath();
if (!$commandPath) { if ($commandPath === null) {
return []; return [];
} }

View file

@ -48,8 +48,6 @@ abstract class AbstractShareTest extends TestCase {
abstract public function getServerClass(): string; abstract public function getServerClass(): string;
public function setUp(): void { public function setUp(): void {
// ob_end_flush();
// var_dump($this->getName());
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json')); $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$options = new Options(); $options = new Options();
$options->setMinProtocol(IOptions::PROTOCOL_SMB2); $options->setMinProtocol(IOptions::PROTOCOL_SMB2);

View file

@ -24,14 +24,14 @@ function waitContainer {
mkdir /tmp/shared mkdir /tmp/shared
# start the dc # start the dc
docker run -dit --name dc -v /tmp/shared:/shared --hostname krb.domain.test --cap-add SYS_ADMIN icewind1991/samba-krb-test-dc docker run -dit --name dc${FORGEJO_RUN_NUMBER} -v /tmp/shared:/shared --hostname krb.domain.test --cap-add SYS_ADMIN icewind1991/samba-krb-test-dc
DC_IP=$(docker inspect dc --format '{{.NetworkSettings.IPAddress}}') DC_IP=$(docker inspect dc${FORGEJO_RUN_NUMBER} --format '{{.NetworkSettings.IPAddress}}')
waitContainer dc waitContainer dc${FORGEJO_RUN_NUMBER}
# start apache # start apache
docker run -d --name apache -v $PWD:/var/www/html -v /tmp/shared:/shared --dns $DC_IP --hostname httpd.domain.test icewind1991/samba-krb-test-apache docker run -d --name apache${FORGEJO_RUN_NUMBER} -v $PWD:/var/www/html -v /tmp/shared:/shared --dns $DC_IP --hostname httpd.domain.test icewind1991/samba-krb-test-apache
APACHE_IP=$(docker inspect apache --format '{{.NetworkSettings.IPAddress}}') APACHE_IP=$(docker inspect apache${FORGEJO_RUN_NUMBER} --format '{{.NetworkSettings.IPAddress}}')
# add the dns record for apache # add the dns record for apache
docker exec dc samba-tool dns add krb.domain.test domain.test httpd A $APACHE_IP -U administrator --password=passwOrd1 docker exec dc${FORGEJO_RUN_NUMBER} samba-tool dns add krb.domain.test domain.test httpd A $APACHE_IP -U administrator --password=passwOrd1