mirror of
https://github.com/webmin/webmin.git
synced 2026-09-20 04:20:39 +01:00
Added support for SHA512 format passwords, created common function to validate a password
This commit is contained in:
@@ -15,9 +15,7 @@ $user || &error($passwd::text{'passwd_euser'});
|
||||
# Validate inputs
|
||||
if ($access{'old'} == 1 ||
|
||||
$access{'old'} == 2 && $user->{'user'} ne $remote_user) {
|
||||
&unix_crypt($in{'old'}, $user->{'pass'}) eq $user->{'pass'} ||
|
||||
&useradmin::encrypt_password($in{'old'}, $user->{'pass'}) eq
|
||||
$user->{'pass'} ||
|
||||
&useradmin::validate_password($in{'old'}, $user->{'pass'}) ||
|
||||
&error($passwd::text{'passwd_eold'});
|
||||
}
|
||||
if ($access{'repeat'}) {
|
||||
|
||||
@@ -60,17 +60,8 @@ else {
|
||||
# Validate inputs
|
||||
if ($access{'old'} == 1 ||
|
||||
$access{'old'} == 2 && $user->{'user'} ne $remote_user) {
|
||||
$chash = undef;
|
||||
eval {
|
||||
# May fail if crypt is broken
|
||||
local $main::error_must_die = 1;
|
||||
$chash = &unix_crypt($in{'old'},
|
||||
$user->{'pass'});
|
||||
};
|
||||
$md5hash = &useradmin::encrypt_password(
|
||||
$in{'old'}, $user->{'pass'});
|
||||
$chash eq $user->{'pass'} ||
|
||||
$md5hash eq $user->{'pass'} ||
|
||||
&useradmin::validate_password(
|
||||
$in{'old'}, $user->{'pass'}) ||
|
||||
&error($text{'passwd_eold'});
|
||||
}
|
||||
if ($access{'repeat'}) {
|
||||
|
||||
@@ -62,3 +62,5 @@ Fixed the hashing format for Blowfish passwords, to put $2a$ at the start instea
|
||||
On Linux systems with SElinux enabled, the context user_u:object_r:user_home_dir_t is set on new home directories by default.
|
||||
---- Changes since 1.510 ----
|
||||
When deleting a user's personal group and user deletion in other modules is enabled, delete the group in other modules too.
|
||||
---- Changes since 1.530 ----
|
||||
Added support for SHA512 format passwords.
|
||||
|
||||
@@ -15,7 +15,7 @@ uid_calc=UID Calculation Method,4,0-Berkeley cksum,1-Custom mkuid program
|
||||
gid_calc=GID Calculation Method,4,0-Berkeley cksum,1-Custom mkgid program
|
||||
new_user_group=Create new group for new users?,1,1-Yes,0-No
|
||||
new_user_gid=Assign same ID to new user and group?,1,1-Yes,0-No
|
||||
md5=Password encryption method,1,2-MD5,1-Determine automatically,0-DES crypt,3-Blowfish
|
||||
md5=Password encryption method,1,1-Determine automatically,0-DES crypt,2-MD5,3-Blowfish,4-SHA512
|
||||
alias_check=Check for sendmail alias clashes?,1,1-Yes,0-No
|
||||
delete_only=Only delete files owned by user?,1,1-Yes,0-No
|
||||
max_length=Maximum user and group name length,3,Unlimited
|
||||
|
||||
@@ -15,7 +15,7 @@ uid_calc=M
|
||||
gid_calc=Mètode de càlcul del GID,4,0-Suma de comprovació Berkeley,1-Programa mkgid personalitzat
|
||||
new_user_group=Crea un grup nou per als usuaris nous,1,1-Sí,0-No
|
||||
new_user_gid=Assigna el mateix al nou usuari i al grup,1,1-Sí,0-No
|
||||
md5=Mètode de xifratge de contrasenyes,1,2-MD5,1-Determinat automàticament,0-DES crypt,3-Blowfish
|
||||
md5=Mètode de xifratge de contrasenyes,1,1-Determinat automàticament,0-DES crypt,2-MD5,3-Blowfish
|
||||
alias_check=Comprova duplicats amb els àlies de sendmail,1,1-Sí,0-No
|
||||
delete_only=Esborra només els fitxers propietat de l'usuari,1,1-Sí,0-No
|
||||
max_length=Llargària màxima dels noms d'usuaris i grups,3,Il·limitada
|
||||
|
||||
@@ -13,7 +13,7 @@ uid_calc=Metoda v
|
||||
gid_calc=Metoda výpočtu GID,4,0-Berkeley cksum,1-Náhodný program mkgid
|
||||
new_user_group=Vytvořit novou skupinu pro nové uživatele?,1,1-ano,0-ne
|
||||
new_user_gid=Přidělit stejné ID pro nového uživatele i skupinu?,1,1-ano,0-ne
|
||||
md5=Metoda kryptování hesla,1,2-MD5,1-Automatické zjištění,0-DES crypt
|
||||
md5=Metoda kryptování hesla,1,1-Automatické zjištění,0-DES crypt,2-MD5
|
||||
alias_check=Kontrolovat kolize v sendmail aliasech?,1,1-ano,0-ne
|
||||
delete_only=Smazat pouze soubory vlastněné uživatelem?,1,1-ano,0-ne
|
||||
max_length=Maximální délka jmen uživatele a skupiny,3,Neomezeno
|
||||
|
||||
@@ -16,7 +16,7 @@ uid_calc=UID beregningsmetode,4,0-Berkeley cksum,1-Brugerdefineret mkuid program
|
||||
gid_calc=GID beregningsmetode,4,0-Berkelet cksum,1-Brugerdefineret mkgid program
|
||||
new_user_group=Opret ny gruppe for ny brugere,1,1-Ja,0-Nej
|
||||
new_user_gid=Tildel samme ID til ny bruger og gruppe?,1,1-Ja,0-Nej
|
||||
md5=Adgangskode krypteringsmetode,1,2-MD5,1-Bestem automatisk,0-DES crypt
|
||||
md5=Adgangskode krypteringsmetode,1,1-Bestem automatisk,0-DES crypt,2-MD5
|
||||
alias_check=Tjek for sendmail alias konflikter?,1,1-Ja,0-Nej
|
||||
delete_only=Slet kun filer ejet af bruger?,1,1-Ja,0-Nej
|
||||
max_length=Maksimum bruger og gurppe navnelængde,3,Ubegrænset
|
||||
|
||||
@@ -15,7 +15,7 @@ uid_calc=User-ID Errechnungsmethode,4,0-Berkeley chksum,1-Benutzerdefiniertes mk
|
||||
gid_calc=Gruppen-ID Errechnungsmethode,4,0-Berkeley chksum,1-Benutzerdefiniertes mkgid Programm
|
||||
new_user_group=Eine Gruppe für neue Benutzer anlegen?,1,1-Ja,0-Nein
|
||||
new_user_gid=Gleiche ID für Benutzer und Gruppe?,1,1-Ja,0-Nein
|
||||
md5=Passwortverschlüsselungsmethode,1,2-MD5,1-Automatisch ermitteln,0-DES crypt
|
||||
md5=Passwortverschlüsselungsmethode,1,1-Automatisch ermitteln,0-DES crypt,2-MD5
|
||||
alias_check=Überprüfe auf vorhandene Sendmail-Aliase?,1,1-Ja,0-Nein
|
||||
delete_only=Nur Dateien löschen<code>,</code> die dem Benutzer gehören?,1,1-Ja,0-Nein
|
||||
max_length=Maximale Länge von Benutzer- und Gruppennamen,3,Unbegrenzt
|
||||
|
||||
@@ -16,7 +16,7 @@ uid_calc=Método de cálculo de UID,4,0-Cksum de Berkeley,1-Programa per
|
||||
gid_calc=Método de cálculo de GID,4,0-Cksum de Berkeley,1-Programa mkgid personalizado
|
||||
new_user_group=¿Crear nuevo grupo para nuevos usuarios?,1,1-Sí,0-No
|
||||
new_user_gid=¿Asignar el mismo ID a nuevo usuario y grupo?,1,1-Sí,0-No
|
||||
md5=Método de encriptación de contraseña,1,2-MD5,1-Determinar automáticamente,0-Encriptación DES
|
||||
md5=Método de encriptación de contraseña,1,1-Determinar automáticamente,0-Encriptación DES,2-MD5
|
||||
alias_check=¿Revisar para evitar choques de alias de sendmail?,1,1-Sí,0-No
|
||||
delete_only=¿Sólo borrar archivos pertenecientes al usuario?,1,1-Sí,0-No
|
||||
max_length=Tamaño máximo de nombre de usuario y grupo,3,Ilimitada
|
||||
|
||||
@@ -18,7 +18,7 @@ uid_calc=روش محاسبه شناسه کاربر,4,0-Berkeley cksum,1-برنا
|
||||
gid_calc=روش محاسبه شناسه گروه,4,0-Berkeley cksum,1-برنامه سفارشي mkgid
|
||||
new_user_group=آيا براي کاربران جديد گروه جديدي ايجاد شود؟,1,1-بله,0-خير
|
||||
new_user_gid=آيا به کاربر و گروه جديد شناسه يکسان اختصاص يابد؟,1,1-بله,0-خير
|
||||
md5=روش رمزگذاري اسمرمز,1,2-MD5,1-بهطور خودکار انتخاب شود,0-DES crypt
|
||||
md5=روش رمزگذاري اسمرمز,1,1-بهطور خودکار انتخاب شود,0-DES crypt,2-MD5
|
||||
alias_check=آيا يکسان بودن با اسم مستعار sendmail بررسي شود؟,1,1-بله,0-خير
|
||||
delete_only=آيا فقط پروندههاي ايجاد شده توسط کاربر حذف شوند؟,1,1-بله,0-خير
|
||||
max_length=بيشينه طول اسمکاربر و گروه,3,نامحدود
|
||||
|
||||
Binary file not shown.
@@ -14,7 +14,7 @@ uid_calc=UID計算方法,4,0-バークレイ cksum,1-カスタムmkuidプログ
|
||||
gid_calc=GID計算方法,4,0-バークレイ cksum,1-カスタムmkgidプログラム
|
||||
new_user_group=新しいユーザ用に新しいグループを作成しますか?,1,1-はい,0-いいえ
|
||||
new_user_gid=新しいユーザとグループに同じIDを割り当てますか?,1,1-はい,0-いいえ
|
||||
md5=パスワードの暗号化方法,1,2-MD5,1-自動選択,0-DES暗号
|
||||
md5=パスワードの暗号化方法,1,1-自動選択,0-DES暗号,2-MD5
|
||||
alias_check=sendmailのエイリアスと重複するかどうかをチェックしますか?,1,1-はい,0-いいえ
|
||||
delete_only=ユーザが所有するファイルだけを削除しますか?,1,1-はい,0-いいえ
|
||||
max_length=ユーザ及びグループ名の最大長,3,無制限
|
||||
|
||||
@@ -14,7 +14,7 @@ uid_calc=UID
|
||||
gid_calc=GID計算方法,4,0-バークレイ cksum,1-カスタムmkgidプログラム
|
||||
new_user_group=新しいユーザ用に新しいグループを作成しますか?,1,1-はい,0-いいえ
|
||||
new_user_gid=新しいユーザとグループに同じIDを割り当てますか?,1,1-はい,0-いいえ
|
||||
md5=パスワードの暗号化方法,1,2-MD5,1-自動選択,0-DES暗号
|
||||
md5=パスワードの暗号化方法,1,1-自動選択,0-DES暗号,2-MD5
|
||||
alias_check=sendmailのエイリアスと重複するかどうかをチェックしますか?,1,1-はい,0-いいえ
|
||||
delete_only=ユーザが所有するファイルだけを削除しますか?,1,1-はい,0-いいえ
|
||||
max_length=ユーザ及びグループ名の最大長,3,無制限
|
||||
|
||||
@@ -14,7 +14,7 @@ uid_calc=UID bereken methoden,4,0-Berkeley cksum,1-Eigen mkuid programma
|
||||
gid_calc=GID bereken methoden,4,0-Berkeley cksum,1-Eigen mkgid programma
|
||||
new_user_group=Maak nieuwe groep voor nieuwe gebruikers?,1,1-Ja,0-Nee
|
||||
new_user_gid=Zelfde ID toewijzen aan nieuwe gebruiker en groep?,1,1-Ja,0-Nee
|
||||
md5=Wachtwoord versleutel methoden,1,2-MD5,1-Bepaal automatisch,0-DES crypt,3-Blowfish
|
||||
md5=Wachtwoord versleutel methoden,1,1-Bepaal automatisch,0-DES crypt,2-MD5,3-Blowfish
|
||||
alias_check=Controleer op conflict met Sendmail alias,1,1-Ja,0-Nee
|
||||
delete_only=Alleen bestanden verwijderen die van de gebruiker zijn?,1,1-Ja,0-Nee
|
||||
max_length=Maximum gebruiker en groepen naam lengte,3,Ongelimiteerd
|
||||
|
||||
@@ -34,7 +34,7 @@ gid_mode=M
|
||||
uid_calc=Método de cálculo de UID,4,0-Berkeley cksum,1-Programa mkuid personalizado
|
||||
gid_calc=Método de cálculo de GID,4,0-Berkeley cksum,1-Programa mkuid personalizado
|
||||
new_user_gid=Atribuir a mesma ID a novo usuário e grupo?,1,1-Sim,0-Não
|
||||
md5=Método de criptografia da senha,1,2-MD5,1-Determinado automaticamente,0-DES crypt,3-Blowfish
|
||||
md5=Método de criptografia da senha,1,1-Determinado automaticamente,0-DES crypt,2-MD5,3-Blowfish
|
||||
max_length=Tamanho máximo de nome de usuário e grupo,3,Ilimitado
|
||||
username_re=Expressão regular Perl para verificar o nome de usuário,3,Nenhuma
|
||||
shells=Gerar lista de shells baseado em,2,fixed-Lista incluida,passwd-Usuários existentes,shells-/etc/shells
|
||||
|
||||
@@ -15,7 +15,7 @@ uid_calc=UID Hesaplama Metodu,4,0-Berkeley cksum,1-
|
||||
gid_calc=GID Hesaplama Metodu,4,0-Berkeley cksum,1-Özel mkgid programı
|
||||
new_user_group=Yeni kullanıcılar için yeni grup oluşturulsun mu?,1,1-Evet,0-Hayır
|
||||
new_user_gid=Aynı ID kullanıcı ve gruba atansın mı?,1,1-Evet,0-Hayır
|
||||
md5=Parola şifreleme metodu,1,2-MD5,1-Otomatik olarak bul,0-DES crypt
|
||||
md5=Parola şifreleme metodu,1,1-Otomatik olarak bul,0-DES crypt,2-MD5
|
||||
delete_only=Sadece kullanıcının sahibi olduğu dosyalar silinsin?,1,1-Evet,0-Hayır
|
||||
max_length=Maksimum kullanıcı ve grup adı uzunluğu,3,Limitsiz
|
||||
username_re=Kullanıcı adlarının kontrol edileceği Perl düzenli ifades,3,Yok
|
||||
|
||||
@@ -201,7 +201,7 @@ print &ui_table_row(&hlink($text{'pass'}, "pass"),
|
||||
( [ 2, $text{'nochange'},
|
||||
&ui_hidden("encpass", $pass) ] ) :
|
||||
( [ 2, $text{'encrypted'},
|
||||
&ui_textbox("encpass", $passmode == 2 ? $pass : "", 40) ] )
|
||||
&ui_textbox("encpass", $passmode == 2 ? $pass : "", 60) ] )
|
||||
]).
|
||||
($can_disable ? " ".&ui_checkbox("disable", 1,
|
||||
$text{'uedit_disabled'}, $disabled) : "")
|
||||
|
||||
@@ -169,6 +169,7 @@ usave_eworkph=Work phone cannot contain a : character
|
||||
usave_ehomeph=Home phone cannot contain a : character
|
||||
usave_edigestmd5=Your system has MD5 passwords enabled, but the Perl <tt>$3</tt> module is not installed.<p>To force the use of normal encrypted passwords, adjust your <a href='$1'>module configuration</a>.<p>Or have Webmin <a href='$2'>download and install</a> the <tt>$3</tt> module for you.
|
||||
usave_edigestblowfish=Your system has Blowfish passwords enabled, but the Perl <tt>$3</tt> module is not installed.<p>To force the use of normal encrypted passwords, adjust your <a href='$1'>module configuration</a>.<p>Or have Webmin <a href='$2'>download and install</a> the <tt>$3</tt> module for you.
|
||||
usave_edigestsha512=Your system has Blowfish passwords enabled, but the <tt>crypt</tt> function does not support this format.
|
||||
usave_emaking=Before update command failed : $1
|
||||
usave_epasswd_min=Password must be at least $1 letters long
|
||||
usave_epasswd_re=Password does not match regexp $1
|
||||
|
||||
@@ -60,7 +60,7 @@ return @rv;
|
||||
}
|
||||
|
||||
# use_md5()
|
||||
# Returns 1 if pam is set up to use MD5 encryption
|
||||
# Returns 1 if pam is set up to use MD5 encryption, 2 for blowfish, 3 for SHA512
|
||||
sub use_md5
|
||||
{
|
||||
if (defined($use_md5_cache)) {
|
||||
@@ -79,6 +79,12 @@ if (&foreign_check("pam")) {
|
||||
if ($m->{'args'} =~ /md5/) {
|
||||
$md5 = 1;
|
||||
}
|
||||
elsif ($m->{'args'} =~ /sha512/) {
|
||||
$md5 = 3;
|
||||
}
|
||||
elsif ($m->{'args'} =~ /blowfish/) {
|
||||
$md5 = 2;
|
||||
}
|
||||
elsif ($m->{'module'} =~ /pam_stack\.so/ &&
|
||||
$m->{'args'} =~ /service=(\S+)/) {
|
||||
# Referred to another service!
|
||||
@@ -102,11 +108,24 @@ if (&foreign_check("pam")) {
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif (&open_readfile(PAM, "/etc/pam.d/passwd")) {
|
||||
if (!$md5 && &open_readfile(PAM, "/etc/pam.d/passwd")) {
|
||||
# Otherwise try to check the PAM file directly
|
||||
while(<PAM>) {
|
||||
s/#.*$//g;
|
||||
$md5 = 1 if (/^password.*md5/);
|
||||
if (/^password.*md5/) { $md5 = 1; }
|
||||
elsif (/^password.*blowfish/) { $md5 = 2; }
|
||||
elsif (/^password.*sha512/) { $md5 = 3; }
|
||||
}
|
||||
close(PAM);
|
||||
}
|
||||
if (!$md5 && (&open_readfile(PAM, "/etc/pam.d/common-password") ||
|
||||
&open_readfile(PAM, "/etc/pam.d/system-auth"))) {
|
||||
# Then try reading common password config file
|
||||
while(<PAM>) {
|
||||
s/#.*$//g;
|
||||
if (/^password.*md5/) { $md5 = 1; }
|
||||
elsif (/^password.*blowfish/) { $md5 = 2; }
|
||||
elsif (/^password.*sha512/) { $md5 = 3; }
|
||||
}
|
||||
close(PAM);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ $salt ||= substr(time(), -8);
|
||||
|
||||
# Use built-in crypt support for MD5, if we can
|
||||
if (&unix_crypt_supports_md5()) {
|
||||
return &unix_crypt($passwd, $magic.$salt.'$xxxxxxxxxxxxxxxxxxxxxx');
|
||||
return crypt($passwd, $magic.$salt.'$xxxxxxxxxxxxxxxxxxxxxx');
|
||||
}
|
||||
|
||||
# Add the password, magic and salt
|
||||
@@ -113,8 +113,9 @@ return $rv;
|
||||
# Returns 1 if the built-in crypt() function can already do MD5
|
||||
sub unix_crypt_supports_md5
|
||||
{
|
||||
return &unix_crypt('test', '$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/') eq
|
||||
'$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/';
|
||||
my $hash = '$1$A9wB3O18$zaZgqrEmb9VNltWTL454R/';
|
||||
my $newhash = eval { crypt('test', $hash) };
|
||||
return $newhash eq $hash;
|
||||
}
|
||||
|
||||
@itoa64 = split(//, "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
@@ -184,5 +185,30 @@ if (!$salt) {
|
||||
return Crypt::Eksblowfish::Bcrypt::bcrypt($passwd, $salt);
|
||||
}
|
||||
|
||||
# unix_crypt_supports_sha512()
|
||||
# Returns 1 if the built-in crypt() function can already do SHA512
|
||||
sub unix_crypt_supports_sha512
|
||||
{
|
||||
my $hash = '$6$Tk5o/GEE$zjvXhYf/dr5M7/jan3pgunkNrAsKmQO9r5O8sr/Cr1hFOLkWmsH4iE9hhqdmHwXd5Pzm4ubBWTEjtMeC.h5qv1';
|
||||
my $newhash = eval { crypt('test', $hash) };
|
||||
return $newhash eq $hash;
|
||||
}
|
||||
|
||||
# check_sha512()
|
||||
# Returns undef if SHA512 hashing is supported, or an error message if not
|
||||
sub check_sha512
|
||||
{
|
||||
return &unix_crypt_supports_sha512() ? undef : 'Crypt::SHA';
|
||||
}
|
||||
|
||||
# encrypt_sha512(password, [salt])
|
||||
# Hashes a password, possibly with the give salt, with SHA512
|
||||
sub encrypt_sha512
|
||||
{
|
||||
local ($passwd, $salt) = @_;
|
||||
$salt ||= '$6$'.substr(time(), -8).'$';
|
||||
return crypt($passwd, $salt);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
@@ -1769,6 +1769,10 @@ elsif ($config{'md5'} == 3) {
|
||||
# Always use blowfish
|
||||
$format = 2;
|
||||
}
|
||||
elsif ($config{'md5'} == 4) {
|
||||
# Always use SHA512
|
||||
$format = 3;
|
||||
}
|
||||
elsif ($config{'md5'} == 1 && !$config{'skip_md5'}) {
|
||||
# Up to system
|
||||
$format = &use_md5() if (defined(&use_md5));
|
||||
@@ -1798,6 +1802,14 @@ elsif ($format == 2) {
|
||||
}
|
||||
return &encrypt_blowfish($pass, $salt);
|
||||
}
|
||||
elsif ($format == 3) {
|
||||
# SHA512 is selected .. use it
|
||||
local $err = &check_sha512();
|
||||
if ($err) {
|
||||
&error($text{'usave_edigestsha512'});
|
||||
}
|
||||
return &encrypt_sha512($pass, $salt);
|
||||
}
|
||||
else {
|
||||
# Just do old-style crypt() DES encryption
|
||||
if ($salt !~ /^[a-z0-9]{2}/i) {
|
||||
@@ -1809,6 +1821,45 @@ else {
|
||||
}
|
||||
}
|
||||
|
||||
# validate_password(password, hash)
|
||||
# Compares a password with a hash to see if they match, returns 1 if so,
|
||||
# 0 otherwise. Tries all supported hashing schemes.
|
||||
sub validate_password
|
||||
{
|
||||
local ($passwd, $hash) = @_;
|
||||
|
||||
# Classic Unix crypt
|
||||
local $chash = eval {
|
||||
local $main::error_must_die = 1;
|
||||
&unix_crypt($passwd, $hash);
|
||||
};
|
||||
return 1 if ($chash eq $hash);
|
||||
|
||||
# MD5
|
||||
if (!&check_md5()) {
|
||||
local $mhash = &encrypt_md5($passwd, $hash);
|
||||
return 1 if ($mhash eq $hash);
|
||||
}
|
||||
|
||||
# Blowfish
|
||||
if (!&check_blowfish()) {
|
||||
local $mhash = &encrypt_blowfish($passwd, $hash);
|
||||
return 1 if ($mhash eq $hash);
|
||||
}
|
||||
|
||||
# SHA1
|
||||
if (!&check_sha512()) {
|
||||
local $shash = &encrypt_sha512($passwd, $hash);
|
||||
return 1 if ($shash eq $hash);
|
||||
}
|
||||
|
||||
# Some other hashing, maybe supported by crypt
|
||||
local $ohash = eval { crypt($passwd, $hash) };
|
||||
return 1 if ($ohash eq $hash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
=head2 build_user_used([&uid-hash], [&shell-list], [&username-hash])
|
||||
|
||||
Fills in hashes with used UIDs, shells and usernames, based on existing users.
|
||||
|
||||
Reference in New Issue
Block a user