Compare commits
10 Commits
11_0_0-19_
...
11_0_0-28_
Author | SHA1 | Date | |
---|---|---|---|
d0b26d9228 | |||
c58758fe43 | |||
f1752e7aa5 | |||
4c64e91235 | |||
74d45e3c8e | |||
507734d114 | |||
0dfb543664 | |||
8c05c61008 | |||
e4b308e422 | |||
5c4bf19137 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
*spec-20*
|
||||
*.tar.xz
|
||||
*.bak
|
||||
*gz
|
||||
|
@@ -0,0 +1 @@
|
||||
enabled
|
@@ -1 +0,0 @@
|
||||
system
|
10
root/etc/e-smith/db/accounts/migrate/10primary
Normal file
10
root/etc/e-smith/db/accounts/migrate/10primary
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
# Delete any pre-existing primary=system record (all lower case)
|
||||
my $p = $DB->get('primary');
|
||||
return unless defined $p;
|
||||
|
||||
my $type = $p->prop('type');
|
||||
return unless defined $type;
|
||||
|
||||
$p->delete if $type eq 'system';
|
||||
}
|
11
root/etc/e-smith/db/configuration/migrate/05pam_faillock
Normal file
11
root/etc/e-smith/db/configuration/migrate/05pam_faillock
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
my $pamtally = $DB->get("pam_tally") or return;
|
||||
|
||||
my $pamfaillock = $DB->get("pam_faillock") ||
|
||||
$DB->new_record("pam_faillock", { type => "service" });
|
||||
|
||||
$pamfaillock->merge_props($pamtally->props);
|
||||
|
||||
$pamtally->delete;
|
||||
}
|
||||
|
@@ -54,7 +54,9 @@ if (!symlink($old_qfn, $new_qfn)) {
|
||||
|
||||
# we let the dedicated systemd command tryin to do what we will do later in this script
|
||||
# as up to systemd 236 it is bugged see:
|
||||
# https://github.com/systemd/systemd/pull/7158 and https://github.com/systemd/systemd/pull/7289
|
||||
# https://github.com/systemd/systemd/pull/7158 : systemctl: respect [Install] section in drop-ins: should be fixed in SME 12 (239)
|
||||
# https://github.com/systemd/systemd/issues/9477 : aliases; open
|
||||
# https://github.com/systemd/systemd/pull/9901 allow instantiated units to be enabled via presets v240
|
||||
system("/usr/bin/systemctl preset-all");
|
||||
# in case preset-all messed up with our default target
|
||||
system("/usr/bin/systemctl set-default sme-server.target");
|
||||
@@ -101,10 +103,11 @@ foreach my $filen (reverse sort keys %files) {
|
||||
my $service=$2;
|
||||
my $stats=$1;
|
||||
# print $_ ."\n";
|
||||
#ignore service that does not exists !
|
||||
# ignore service that does not exists !
|
||||
# here we are searching for service@instance.service type
|
||||
my $multiple = $service;
|
||||
($multiple = $service ) =~ s/([a-zA-Z0-9\-_.]+@)(.*)/$1.service/ if ( $service =~ /@/ );
|
||||
#print "$stats $service $multiple\n";
|
||||
#print "$stats $service $multiple\n" if $service ne $multiple;
|
||||
next unless ( -e "/usr/lib/systemd/system/$service" or -e "/etc/systemd/system/$service" or -e "/usr/lib/systemd/system/$multiple");
|
||||
# eliminate duplicates, this way we keep only the last entry of the lowest file as we do it in reverse order of file,
|
||||
# but from top to bottom of file.
|
||||
@@ -117,7 +120,7 @@ foreach my $filen (reverse sort keys %files) {
|
||||
#print "want $service \n";
|
||||
}
|
||||
else {
|
||||
my $wanted = `grep -P '^WantedBy=.*sme-server.target' /usr/lib/systemd/system/$service* /etc/systemd/system/$service* -rsh` ;
|
||||
my $wanted = `grep -P '^WantedBy=.*sme-server.target' /usr/lib/systemd/system/$service* /etc/systemd/system/$service* /usr/lib/systemd/system/$multiple* /etc/systemd/system/$multiple* -rsh` ;
|
||||
chomp $wanted;
|
||||
$wantedBy{$service}=1 unless ( $wanted eq "");
|
||||
#print "want $service \n" unless ( $wanted eq "") ;
|
||||
|
@@ -1,9 +1,10 @@
|
||||
{
|
||||
my $status = $pam_tally{status} || 'disabled';
|
||||
return unless $status eq 'enabled';
|
||||
$OUT .= "auth required pam_tally.so onerr=fail no_magic_root";
|
||||
}
|
||||
auth required pam_env.so
|
||||
{
|
||||
my $status = $pam_faillock{status} || 'disabled';
|
||||
return unless $status eq 'enabled';
|
||||
# lock out users after three unsuccessful attempts and unlock the user account after 10 minutes (600 seconds)
|
||||
$OUT .= "auth required pam_faillock.so preauth silent audit deny=3 even_deny_root unlock_time=600 root_unlock_time=600";
|
||||
}
|
||||
{
|
||||
my $status = $pam_abl{status} || 'disabled';
|
||||
return unless $status eq 'enabled';
|
||||
@@ -15,5 +16,10 @@ auth sufficient pam_unix.so likeauth nullok
|
||||
return unless $status eq 'enabled';
|
||||
$OUT .= "auth sufficient pam_ldap.so use_first_pass";
|
||||
}
|
||||
{
|
||||
my $status = $pam_faillock{status} || 'disabled';
|
||||
return unless $status eq 'enabled';
|
||||
$OUT .= "auth [default=die] pam_faillock.so authfail audit deny=3 unlock_time=600";
|
||||
}
|
||||
auth required pam_deny.so
|
||||
|
||||
|
@@ -7,7 +7,9 @@ account sufficient pam_succeed_if.so uid < 100 quiet
|
||||
}
|
||||
account required pam_permit.so
|
||||
{
|
||||
my $status = $pam_tally{status} || 'disabled';
|
||||
my $status = $pam_faillock{status} || 'disabled';
|
||||
return unless $status eq 'enabled';
|
||||
$OUT .= "account required pam_tally.so deny=5 reset no_magic_root";
|
||||
# if you drop this call to pam_faillock.so the lock will be done also
|
||||
# on non-consecutive authentication failures
|
||||
$OUT .= "account required pam_faillock.so";
|
||||
}
|
||||
|
@@ -1 +1,2 @@
|
||||
/bin/bash
|
||||
/usr/bin/bash
|
||||
|
@@ -1 +1,2 @@
|
||||
/bin/bash2
|
||||
/usr/bin/bash2
|
||||
|
@@ -1 +1,2 @@
|
||||
/sbin/e-smith/console
|
||||
/usr/sbin/e-smith/console
|
||||
|
@@ -1 +1,2 @@
|
||||
/bin/csh
|
||||
/usr/bin/csh
|
||||
|
@@ -1 +1,2 @@
|
||||
/bin/false
|
||||
/usr/bin/false
|
||||
|
@@ -1 +1,2 @@
|
||||
/bin/sh
|
||||
/usr/bin/sh
|
||||
|
@@ -2,7 +2,7 @@
|
||||
Description=SME server bootstrap-console
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=livesys.service plymouth-quit-wait.service
|
||||
After=livesys.service
|
||||
After=systemd-vconsole-setup.service
|
||||
Before=getty@tty1.service
|
||||
Before=shutdown.target
|
||||
|
@@ -8,6 +8,6 @@ Requires=basic.target
|
||||
Conflicts=rescue.service rescue.target multi-user.target
|
||||
After=basic.target rescue.service rescue.target runit.service
|
||||
AllowIsolate=yes
|
||||
Wants=atd.service auditd.service avahi-daemon.service brandbot.path nfs-client.target remote-fs.target rhel-configure.service
|
||||
Wants=atd.service auditd.service avahi-daemon.service nfs-client.target remote-fs.target
|
||||
Wants=dbus.service plymouth-quit-wait.service plymouth-quit.service systemd-logind.service systemd-update-utmp-runlevel.service systemd-user-sessions.service
|
||||
|
||||
|
@@ -6,18 +6,26 @@ use esmith::ConfigDB;
|
||||
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw( key_exists_good_size cert_exists_good_size cert_is_cert key_is_key related_key_cert);
|
||||
our @EXPORT = qw( key_exists_good_size cert_exists_good_size cert_is_cert key_is_key related_key_cert SSLproto SSLprotoApache SSLprotoComa SSLprotoHyphen SSLprotoMin SSLprotoLDAP SSLprotoQpsmtpd $smeCiphers $smeSSLprotocol %existingSSLprotos);
|
||||
|
||||
my $configdb = esmith::ConfigDB->open_ro or die "Could not open accounts db";
|
||||
our $SystemName = $configdb->get('SystemName')->value;
|
||||
our $DomainName = $configdb->get('DomainName')->value;
|
||||
our $FQDN = "$SystemName.$DomainName";
|
||||
|
||||
# test key size
|
||||
# test key exists
|
||||
#default cipher list
|
||||
our $smeCiphers = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:!ADH:!SSLv2:!ADH:!aNULL:!MD5:!RC4";
|
||||
#default protocol list
|
||||
# 2024 phase out : TLS 1.1 and 1.0 ; insuficient: SSL 3.0, 2.0 and 1.0
|
||||
our $smeSSLprotocol = "TLSv1.2 TLSv1.3";
|
||||
|
||||
# SSLv2 and SSLv3 are not available in el8 openssl-1.1.1, while -ssl3 still in man page
|
||||
# it will throw Option unknown option -ssl3
|
||||
our %existingSSLprotos=%{ {'SSLv3'=>1, 'TLSv1'=>1, 'TLSv1.1'=>1, 'TLSv1.2'=>1, 'TLSv1.3'=>1}};
|
||||
|
||||
=head1 NAME
|
||||
|
||||
esmith::php - A few tools to help with php-fpm installed versions
|
||||
esmith::ssl - A few tools to help with ssl handling
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -42,6 +50,7 @@ returns 0 if key is missing or wrong size
|
||||
returns 1 if key exists and key size is correct
|
||||
|
||||
=cut
|
||||
|
||||
sub key_exists_good_size {
|
||||
my $configdb = esmith::ConfigDB->open_ro or die "Could not open accounts db";
|
||||
my %modSSL = $configdb->as_hash('modSSL');
|
||||
@@ -74,8 +83,8 @@ sub key_exists_good_size {
|
||||
# check cert size Public-Key
|
||||
# openssl rsa -noout -modulus -in domain.key | openssl md5
|
||||
# openssl x509 -noout -modulus -in domain.crt | openssl md5
|
||||
|
||||
=cut
|
||||
|
||||
sub cert_exists_good_size {
|
||||
my $configdb = esmith::ConfigDB->open_ro or die "Could not open accounts db";
|
||||
my %modSSL = $configdb->as_hash('modSSL');
|
||||
@@ -99,6 +108,10 @@ sub cert_exists_good_size {
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 cert_is_cert
|
||||
check if file is really a certificate
|
||||
=cut
|
||||
|
||||
sub cert_is_cert {
|
||||
my $crt = shift || "/home/e-smith/ssl.crt/$FQDN.crt";
|
||||
if ( -f $crt )
|
||||
@@ -115,6 +128,10 @@ sub cert_is_cert {
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 key_is_key
|
||||
check if file is really a key
|
||||
=cut
|
||||
|
||||
sub key_is_key {
|
||||
my $key = shift || "/home/e-smith/ssl.key/$FQDN.key";
|
||||
if ( -f $key )
|
||||
@@ -144,7 +161,8 @@ sub related_key_cert {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
##TODO migrate those actions from
|
||||
|
||||
##TODO write sub and migrate those actions from template fragments
|
||||
# check cert is related to key
|
||||
# => /etc/e-smith/templates/home/e-smith/ssl.crt
|
||||
# check cert domain and alt
|
||||
@@ -152,3 +170,126 @@ sub related_key_cert {
|
||||
# check is valid / expiry date
|
||||
# => /etc/e-smith/templates/home/e-smith/ssl.crt
|
||||
###################################
|
||||
|
||||
=head2 SSLprotoApache
|
||||
output a list of allowed protocols with apache format
|
||||
e.g. -all +TLSv1.2 +TLSv1.3
|
||||
=cut
|
||||
|
||||
sub SSLprotoApache{
|
||||
my $protocols = " -all +".join(" +",split(" ",$smeSSLprotocol)) ." ";
|
||||
my $configdb = esmith::ConfigDB->open_ro or die "Could not open accounts db";
|
||||
my $httpd = $configdb->get('httpd-e-smith');
|
||||
# SSLv2 and SSLv3 are not available in el8 openssl-1.1.1, while -ssl3 still referenced
|
||||
# it will throw Option unknown option -ssl3
|
||||
#$protocols .= " +SSLv3" if ($httpd->{'SSLv3'} || 'disabled') eq 'enabled';
|
||||
# TODO: a loop using existingSSLprotos
|
||||
$protocols .= " +TLSv1" if ($httpd->{'TLSv1'} || 'disabled') eq 'enabled';
|
||||
$protocols .= " +TLSv1.1" if ($httpd->{'TLSv1.1'} || 'disabled') eq 'enabled';
|
||||
# look closely this is to remove what has been added on first line,
|
||||
# hence the minus sign and reverse logic.
|
||||
$protocols .= " -TLSv1.2" unless ($httpd->{'TLSv1.2'} || 'enabled') eq 'enabled';
|
||||
$protocols .= " -TLSv1.3" unless ($httpd->{'TLSv1.3'} || 'enabled') eq 'enabled';
|
||||
return $protocols;
|
||||
}
|
||||
|
||||
=head2 SSLprotoQpsmtpd
|
||||
output an expected IO::Socket::SSL string to enable
|
||||
only the wanted TLS versions
|
||||
SSLv23:!SSLv2:!SSLv3:!TLSv1:!TLSv1_1
|
||||
=cut
|
||||
|
||||
sub SSLprotoQpsmtpd{
|
||||
my $service= shift || 'qpsmtpd';
|
||||
my $configdb = esmith::ConfigDB->open_ro or die "Could not open accounts db";
|
||||
my %qpsmtpd = %{$configdb->get($service)};
|
||||
# SSLv2 and SSLv3 are not available in el8 openssl-1.1.1, while -ssl3 still referenced
|
||||
# it will throw Option unknown option -ssl3
|
||||
my $protocols = "SSLv23:!SSLv2:!SSLv3";
|
||||
# TODO: a loop using existingSSLprotos and SSLprotoHyphen()
|
||||
$protocols .= ':!TLSv1' unless ($qpsmtpd{'TLSv1'} || 'disabled') eq 'enabled';
|
||||
$protocols .= ':!TLSv1_1' unless ($qpsmtpd{'TLSv1.1'} || 'disabled') eq 'enabled';
|
||||
$protocols .= ':!TLSv1_2' unless ($qpsmtpd{'TLSv1.2'} || 'enabled') eq 'enabled';
|
||||
$protocols .= ':!TLSv1_3' unless ($qpsmtpd{'TLSv1.3'} || 'enabled') eq 'enabled';
|
||||
return $protocols;
|
||||
}
|
||||
|
||||
=head2 SSLproto
|
||||
default display of list of protocol. This is how it will be displayed in
|
||||
httpd.conf and proftpd.conf
|
||||
e.g. TLSv1.2 TLSv1.3
|
||||
=cut
|
||||
|
||||
sub SSLproto{
|
||||
return $smeSSLprotocol;
|
||||
}
|
||||
|
||||
=head2 SSLprotoComa
|
||||
way to display protocols in Mariadb as a string list separated by coma
|
||||
e.g. TLSv1.2,TLSv1.3
|
||||
=cut
|
||||
|
||||
sub SSLprotoComa{
|
||||
my $string = shift || $smeSSLprotocol;
|
||||
$string =~ s/[ :]/,/g;
|
||||
return $string;
|
||||
}
|
||||
|
||||
=head2 SSLprotoHyphen
|
||||
convert TLSv1.2 to TLSv1_2
|
||||
This is the format required by perl IO::Socket::SSL; and as the result by
|
||||
qpsmtpd, uqpsmtpd, sqpsmtpd SME Server services
|
||||
=cut
|
||||
|
||||
sub SSLprotoHyphen {
|
||||
my $string = shift || $smeSSLprotocol;
|
||||
$string =~ s/[ ,]/:/g;
|
||||
$string =~ s/\./_/g;
|
||||
return $string;
|
||||
}
|
||||
|
||||
=head2 SSLprotoMin
|
||||
display only the lower protocol, as expected for dovecot
|
||||
ssl_min_protocol = TLSv1.2
|
||||
# limit : will not handle all or sslv23 as input
|
||||
=cut
|
||||
|
||||
sub SSLprotoMin{
|
||||
my @SSLarray = split(" ",shift || $smeSSLprotocol);
|
||||
my %hash ;
|
||||
foreach my $value (@SSLarray) {
|
||||
my $toto = $value =~ s/(.*)(\d{1})+$/$2/r;
|
||||
# hack for TLS > SSL
|
||||
$toto = ($value =~ /^TLS/) ? "2$toto" : "1$toto";
|
||||
$hash{$toto}=$value ;
|
||||
}
|
||||
my @keys_sorted_by_value = sort { $a <=> $b } keys %hash;
|
||||
my $lowest_value = $keys_sorted_by_value[0] ;
|
||||
return $hash{$lowest_value};
|
||||
}
|
||||
|
||||
=head2 SSLprotoLDAP
|
||||
convert min protocol suported to LDAP format
|
||||
TLSProtocolMin 3.3
|
||||
To require TLS 1.x or higher, set this option to 3.(x+1), e.g., TLSProtocolMin 3.2 would require TLS 1.1.
|
||||
from $smeSSLprotocol = "TLSv1.2 TLSv1.3";
|
||||
=cut
|
||||
|
||||
sub SSLprotoLDAP{
|
||||
# convert to array
|
||||
my @SSLarray = split(" ",shift || $smeSSLprotocol);
|
||||
return "3.0" if (grep /^SSLv3$/, @SSLarray);
|
||||
# TLSv1
|
||||
return "3.1" if (grep /^TLSv1$/ , @SSLarray);
|
||||
# keep only digit after .
|
||||
@SSLarray = grep{ $_ =~ s/(.*)(\d{1})+$/$2/ } @SSLarray;
|
||||
# order
|
||||
@SSLarray = sort @SSLarray;
|
||||
# get lower
|
||||
my $num = $SSLarray[0];
|
||||
# sum 3.1 + 0.$x
|
||||
$num = "0.".$num;
|
||||
# return
|
||||
$num = $num +3.1;
|
||||
return $num;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
|
||||
exec \
|
||||
/usr/local/bin/setuidgid smelog \
|
||||
/usr/local/bin/multilog t s5000000 \
|
||||
/usr/bin/setuidgid smelog \
|
||||
/usr/bin/multilog t s5000000 \
|
||||
/var/log/ippp
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#! /bin/sh
|
||||
|
||||
exec \
|
||||
/usr/local/bin/setuidgid smelog \
|
||||
/usr/local/bin/multilog t s5000000 \
|
||||
/usr/bin/setuidgid smelog \
|
||||
/usr/bin/multilog t s5000000 \
|
||||
/var/log/wan
|
||||
|
||||
|
@@ -4,7 +4,7 @@ Summary: smeserver server and gateway - base module
|
||||
%define name smeserver-base
|
||||
Name: %{name}
|
||||
%define version 11.0.0
|
||||
%define release 19
|
||||
%define release 28
|
||||
Version: %{version}
|
||||
Release: %{release}%{?dist}
|
||||
License: GPL
|
||||
@@ -49,6 +49,10 @@ Requires: bash-completion
|
||||
Requires: smeserver-runit >= 2.6.0-7
|
||||
Requires: smeserver-php >= 3.0.0-22
|
||||
Requires: smeserver-yum >= 2.6.0-43
|
||||
# daemontools bins in use
|
||||
Requires: /usr/bin/softlimit
|
||||
Requires: /usr/bin/setuidgid
|
||||
Requires: /usr/bin/multilog
|
||||
Obsoletes: nss_ldap < 254
|
||||
Obsoletes: cpu
|
||||
Obsoletes: rlinetd, e-smith-mod_ssl
|
||||
@@ -65,7 +69,11 @@ BuildRequires: smeserver-devtools >= 1.13.1-03
|
||||
BuildRequires: gettext
|
||||
Requires: gdisk
|
||||
Requires: ppp
|
||||
Requires: rp-pppoe
|
||||
Requires: rp-pppoe
|
||||
# pam autoblock
|
||||
Requires: pam_abl
|
||||
# isdn wan connection (ippp)
|
||||
Requires: isdn4k-utils
|
||||
%define dbfiles accounts configuration domains hosts networks
|
||||
AutoReqProv: no
|
||||
|
||||
@@ -184,6 +192,35 @@ fi
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu Feb 20 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-28.sme
|
||||
- clean sme-server.target [SME: 12931]
|
||||
|
||||
* Sun Feb 16 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-27.sme
|
||||
- fix missing allowed shell for login [SME: 12926]
|
||||
|
||||
* Wed Feb 12 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-26.sme
|
||||
- add pam_abl requirement [SME: 12914]
|
||||
- add isdn4k-utils requirement for ippp isdn connections [SME: 12909]
|
||||
- remove pam_tally as deprecated in favor of pam_faillock [SME: 12913]
|
||||
|
||||
* Tue Feb 04 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-25.sme
|
||||
- fix boot ordering cycle [SME: 12902]
|
||||
|
||||
* Sun Jan 26 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-24.sme
|
||||
- ippp and wan requires daemontools bins [SME: 12566]
|
||||
|
||||
* Sat Jan 18 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-23.sme
|
||||
- handle all ssl ciphers and protocol in one place esmith::ssl [SME: 12827]
|
||||
this will allow to sync all service default protocol and ciphers
|
||||
in one place.
|
||||
|
||||
* Fri Jan 03 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-21.sme
|
||||
- improve support of systemd service with instance service@instance.service [SME: 12859]
|
||||
|
||||
* Thu Jan 02 2025 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-20.sme
|
||||
- Primary default to SSL required and redirect [SME: 12858]
|
||||
- cleanup remove primary=system [SME: 8268]
|
||||
|
||||
* Tue Dec 31 2024 Jean-Philippe Pialasse <jpp@koozali.org> 11.0.0-19.sme
|
||||
- fix www removed from shared on group creation [SME: 12848]
|
||||
|
||||
|
Reference in New Issue
Block a user