mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-28 17:12:32 +00:00
96_allowed.pm: Authorization/Authentication modularized
git-svn-id: https://svn.fhem.de/fhem/trunk@10298 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
a799cabab4
commit
6d26b4c934
10
fhem/CHANGED
10
fhem/CHANGED
@ -1,12 +1,14 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- feature: allowed module added. allowedCommands, basicAuth, password,
|
||||||
|
globalpassword attributes moved to this module.
|
||||||
- bugfix: YAMAHA_AVR: fixing not working volumeStraight set command
|
- bugfix: YAMAHA_AVR: fixing not working volumeStraight set command
|
||||||
- change: FB_CALLLIST: start call processing only when "event:" is triggered
|
- change: FB_CALLLIST: start call processing only when "event:" is triggered
|
||||||
by corresponding FB_CALLMONITOR device.
|
by corresponding FB_CALLMONITOR device.
|
||||||
- change: FB_CALLMONITOR: default value for attr fritzbox-remote-phonebook-via
|
- change: FB_CALLMONITOR: default value for attr
|
||||||
has been changed to "tr064" (previous: "web") to ensure
|
fritzbox-remote-phonebook-via has been changed to "tr064"
|
||||||
no problems with new Fritz!OS web layout.
|
(previous: "web") to ensure no problems with new Fritz!OS web
|
||||||
Besides TR-064 is official supported by AVM.
|
layout. Besides TR-064 is official supported by AVM.
|
||||||
- feature: PHILIPS_AUDIO: Favorite station selection
|
- feature: PHILIPS_AUDIO: Favorite station selection
|
||||||
- feature: YAMAHA_AVR: new set commands and readings for tuner control
|
- feature: YAMAHA_AVR: new set commands and readings for tuner control
|
||||||
- new set commands tunerFrequency,tunerPreset for
|
- new set commands tunerFrequency,tunerPreset for
|
||||||
|
@ -218,10 +218,22 @@ FW_SecurityCheck($$)
|
|||||||
!grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}));
|
!grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}));
|
||||||
my $motd = AttrVal("global", "motd", "");
|
my $motd = AttrVal("global", "motd", "");
|
||||||
if($motd =~ "^SecurityCheck") {
|
if($motd =~ "^SecurityCheck") {
|
||||||
my @list = grep { !AttrVal($_, "basicAuth", undef) }
|
my @list1 = devspec2array("TYPE=FHEMWEB");
|
||||||
devspec2array("TYPE=FHEMWEB");
|
my @list2 = devspec2array("TYPE=allowed");
|
||||||
$motd .= (join(",", sort @list)." has no basicAuth attribute.\n")
|
my @list3;
|
||||||
if(@list);
|
for my $l (@list1) { # This is a hack, as hardcoded to basicAuth
|
||||||
|
next if(!$defs{$l});
|
||||||
|
my $fnd = 0;
|
||||||
|
for my $a (@list2) {
|
||||||
|
next if(!$defs{$a});
|
||||||
|
my $vf = AttrVal($a, "validFor","");
|
||||||
|
$fnd = 1 if((!$vf || $vf =~ m/\b$l\b/) && AttrVal($a, "basicAuth",""));
|
||||||
|
}
|
||||||
|
push @list3, $l if(!$fnd);
|
||||||
|
}
|
||||||
|
$motd .= (join(",", sort @list3).
|
||||||
|
" has no associated allowed device with basicAuth.\n")
|
||||||
|
if(@list3);
|
||||||
$attr{global}{motd} = $motd;
|
$attr{global}{motd} = $motd;
|
||||||
}
|
}
|
||||||
$modules{FHEMWEB}{NotifyFn}= "FW_Notify";
|
$modules{FHEMWEB}{NotifyFn}= "FW_Notify";
|
||||||
@ -362,44 +374,24 @@ FW_Read($$)
|
|||||||
|
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
# BASIC HTTP AUTH
|
# AUTH
|
||||||
my @headerOptions = grep /OPTIONS/, @FW_httpheader; # Need example
|
if(!defined($FW_chash->{Authenticated})) {
|
||||||
my $basicAuth = AttrVal($FW_wname, "basicAuth", undef);
|
my $ret = Authenticate($FW_chash, \%FW_httpheader);
|
||||||
if($basicAuth) {
|
if($ret == 0) {
|
||||||
my $secret = $FW_httpheader{Authorization};
|
$FW_chash->{Authenticated} = 0; # not needed
|
||||||
$secret =~ s/^Basic //i if($secret);
|
|
||||||
my $pwok = ($secret && $secret eq $basicAuth);
|
} elsif($ret == 1) {
|
||||||
if($secret && $basicAuth =~ m/^{.*}$/ || $headerOptions[0]) {
|
$FW_chash->{Authenticated} = 1; # ok
|
||||||
eval "use MIME::Base64";
|
|
||||||
if($@) {
|
|
||||||
Log3 $FW_wname, 1, $@;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
my ($user, $password) = split(":", decode_base64($secret));
|
|
||||||
$pwok = eval $basicAuth;
|
|
||||||
Log3 $FW_wname, 1, "basicAuth expression: $@" if($@);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if($headerOptions[0]) {
|
|
||||||
TcpServer_WriteBlocking($hash,
|
TcpServer_WriteBlocking($hash,
|
||||||
"HTTP/1.1 200 OK\r\n".
|
$FW_chash->{".httpAuthHeader"}.
|
||||||
$FW_headercors.
|
$FW_headercors.
|
||||||
"Content-Length: 0\r\n\r\n");
|
"Content-Length: 0\r\n\r\n");
|
||||||
delete $hash->{CONTENT_LENGTH};
|
delete $hash->{CONTENT_LENGTH};
|
||||||
FW_Read($hash, 1) if($hash->{BUF});
|
FW_Read($hash, 1) if($hash->{BUF});
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
if(!$pwok) {
|
|
||||||
my $msg = AttrVal($FW_wname, "basicAuthMsg", "Fhem: login required");
|
|
||||||
TcpServer_WriteBlocking($hash,
|
|
||||||
"HTTP/1.1 401 Authorization Required\r\n".
|
|
||||||
"WWW-Authenticate: Basic realm=\"$msg\"\r\n".
|
|
||||||
$FW_headercors.
|
|
||||||
"Content-Length: 0\r\n\r\n");
|
|
||||||
delete $hash->{CONTENT_LENGTH};
|
|
||||||
FW_Read($hash, 1) if($hash->{BUF});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
#############################
|
#############################
|
||||||
|
|
||||||
@ -1847,8 +1839,7 @@ FW_style($$)
|
|||||||
my ($cmd, $msg) = @_;
|
my ($cmd, $msg) = @_;
|
||||||
my @a = split(" ", $cmd);
|
my @a = split(" ", $cmd);
|
||||||
|
|
||||||
my $ac = AttrVal($FW_wname,"allowedCommands","");
|
return if(!Authorized($FW_chash, "cmd", $a[0]));
|
||||||
return if($ac && $ac !~ m/\b$a[0]\b/);
|
|
||||||
|
|
||||||
my $start = "<div id=\"content\"><table><tr><td>";
|
my $start = "<div id=\"content\"><table><tr><td>";
|
||||||
my $end = "</td></tr></table></div>";
|
my $end = "</td></tr></table></div>";
|
||||||
@ -2173,11 +2164,9 @@ FW_fC($@)
|
|||||||
my ($cmd, $unique) = @_;
|
my ($cmd, $unique) = @_;
|
||||||
my $ret;
|
my $ret;
|
||||||
if($unique) {
|
if($unique) {
|
||||||
$ret = AnalyzeCommand($FW_chash, $cmd,
|
$ret = AnalyzeCommand($FW_chash, $cmd);
|
||||||
AttrVal($FW_wname,"allowedCommands",undef));
|
|
||||||
} else {
|
} else {
|
||||||
$ret = AnalyzeCommandChain($FW_chash, $cmd,
|
$ret = AnalyzeCommandChain($FW_chash, $cmd);
|
||||||
AttrVal($FW_wname,"allowedCommands",undef));
|
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
@ -2185,52 +2174,65 @@ FW_fC($@)
|
|||||||
sub
|
sub
|
||||||
FW_Attr(@)
|
FW_Attr(@)
|
||||||
{
|
{
|
||||||
my @a = @_;
|
my ($type, $devName, $attrName, @param) = @_;
|
||||||
my $hash = $defs{$a[1]};
|
my $hash = $defs{$devName};
|
||||||
my $name = $hash->{NAME};
|
|
||||||
my $sP = "stylesheetPrefix";
|
my $sP = "stylesheetPrefix";
|
||||||
my $retMsg;
|
my $retMsg;
|
||||||
|
|
||||||
if($a[0] eq "set" && $a[2] eq "HTTPS") {
|
if($type eq "set" && $attrName eq "HTTPS") {
|
||||||
TcpServer_SetSSL($hash);
|
TcpServer_SetSSL($hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($a[0] eq "set") { # Converting styles
|
if($type eq "set") { # Converting styles
|
||||||
if($a[2] eq "smallscreen" || $a[2] eq "touchpad") {
|
if($attrName eq "smallscreen" || $attrName eq "touchpad") {
|
||||||
$attr{$name}{$sP} = $a[2];
|
$attr{$devName}{$sP} = $attrName;
|
||||||
$retMsg="$name: attribute $a[2] deprecated, converted to $sP";
|
$retMsg="$devName: attribute $attrName deprecated, converted to $sP";
|
||||||
$a[3] = $a[2]; $a[2] = $sP;
|
$param[0] = $attrName; $attrName = $sP;
|
||||||
}
|
|
||||||
}
|
|
||||||
if($a[2] eq $sP) {
|
|
||||||
# AttrFn is called too early, we have to set/del the attr here
|
|
||||||
if($a[0] eq "set") {
|
|
||||||
$attr{$name}{$sP} = (defined($a[3]) ? $a[3] : "default");
|
|
||||||
FW_readIcons($attr{$name}{$sP});
|
|
||||||
} else {
|
|
||||||
delete $attr{$name}{$sP};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($a[2] eq "iconPath" && $a[0] eq "set") {
|
if($attrName eq $sP) {
|
||||||
foreach my $pe (split(":", $a[3])) {
|
# AttrFn is called too early, we have to set/del the attr here
|
||||||
|
if($type eq "set") {
|
||||||
|
$attr{$devName}{$sP} = (defined($param[0]) ? $param[0] : "default");
|
||||||
|
FW_readIcons($attr{$devName}{$sP});
|
||||||
|
} else {
|
||||||
|
delete $attr{$devName}{$sP};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($attrName eq "allowedCommands" ||
|
||||||
|
$attrName eq "basicAuth" ||
|
||||||
|
$attrName eq "basicAuthMsg")
|
||||||
|
&& $type eq "set") {
|
||||||
|
my $aName = "allowed_$devName";
|
||||||
|
my $exists = ($defs{$aName} ? 1 : 0);
|
||||||
|
AnalyzeCommand(undef, "defmod $aName allowed");
|
||||||
|
AnalyzeCommand(undef, "attr $aName validFor $devName");
|
||||||
|
AnalyzeCommand(undef, "attr $aName $attrName ".join(" ",@param));
|
||||||
|
return "$devName: ".($exists ? "modifying":"creating").
|
||||||
|
" device $aName for attribute $attrName";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($attrName eq "iconPath" && $type eq "set") {
|
||||||
|
foreach my $pe (split(":", $param[0])) {
|
||||||
$pe =~ s+\.\.++g;
|
$pe =~ s+\.\.++g;
|
||||||
FW_readIcons($pe);
|
FW_readIcons($pe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($a[2] eq "JavaScripts" && $a[0] eq "set") { # create some attributes
|
if($attrName eq "JavaScripts" && $type eq "set") { # create some attributes
|
||||||
my (%a, @add);
|
my (%a, @add);
|
||||||
map { $a{$_} = 1 } split(" ", $modules{FHEMWEB}{AttrList});
|
map { $a{$_} = 1 } split(" ", $modules{FHEMWEB}{AttrList});
|
||||||
map {
|
map {
|
||||||
$_ =~ s+.*/++; $_ =~ s/.js$//; $_ =~ s/fhem_//; $_ .= "Param";
|
$_ =~ s+.*/++; $_ =~ s/.js$//; $_ =~ s/fhem_//; $_ .= "Param";
|
||||||
push @add, $_ if(!$a{$_} && $_ !~ m/^-/);
|
push @add, $_ if(!$a{$_} && $_ !~ m/^-/);
|
||||||
} split(" ", $a[3]);
|
} split(" ", $param[0]);
|
||||||
$modules{FHEMWEB}{AttrList} .= " ".join(" ",@add) if(@add);
|
$modules{FHEMWEB}{AttrList} .= " ".join(" ",@add) if(@add);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($a[2] eq "csrfToken" && $a[0] eq "set") {
|
if($attrName eq "csrfToken" && $type eq "set") {
|
||||||
my $csrf = $a[3];
|
my $csrf = $param[0];
|
||||||
if($csrf eq "random") {
|
if($csrf eq "random") {
|
||||||
my ($x,$y) = gettimeofday();
|
my ($x,$y) = gettimeofday();
|
||||||
$csrf = rand($y)*rand($x);
|
$csrf = rand($y)*rand($x);
|
||||||
@ -2238,7 +2240,7 @@ FW_Attr(@)
|
|||||||
$hash->{CSRFTOKEN} = $csrf;
|
$hash->{CSRFTOKEN} = $csrf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($a[2] eq "csrfToken" && $a[0] eq "del") {
|
if($attrName eq "csrfToken" && $type eq "del") {
|
||||||
delete($hash->{CSRFTOKEN});
|
delete($hash->{CSRFTOKEN});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2937,50 +2939,13 @@ FW_widgetOverride($$)
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="#addStateEvent">addStateEvent</a></li>
|
<li><a href="#addStateEvent">addStateEvent</a></li>
|
||||||
|
|
||||||
<a name="allowedCommands"></a>
|
|
||||||
<li>allowedCommands<br>
|
|
||||||
A comma separated list of commands allowed from this FHEMWEB
|
|
||||||
instance.<br> If set to an empty list <code>, (i.e. comma only)</code>
|
|
||||||
then this FHEMWEB instance will be read-only.<br> If set to
|
|
||||||
<code>get,set</code>, then this FHEMWEB instance will only allow
|
|
||||||
regular usage of the frontend by clicking the icons/buttons/sliders but
|
|
||||||
not changing any configuration.<br>
|
|
||||||
|
|
||||||
|
|
||||||
This attribute intended to be used together with hiddenroom/hiddengroup
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<b>Note:</b>allowedCommands should work as intended, but no guarantee
|
|
||||||
can be given that there is no way to circumvent it. If a command is
|
|
||||||
allowed it can be issued by URL manipulation also for devices that are
|
|
||||||
hidden.</li><br>
|
|
||||||
|
|
||||||
<li><a href="#allowfrom">allowfrom</a></li>
|
<li><a href="#allowfrom">allowfrom</a></li>
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
<a name="basicAuth"></a>
|
<li>allowedCommands, basicAuth, basicAuthMsg<br>
|
||||||
<li>basicAuth, basicAuthMsg<br>
|
Please create these attributes for the corresponding <a
|
||||||
request a username/password authentication for access. You have to set
|
href="#allowed">allowed</a> device, they are deprecated for the FHEMWEB
|
||||||
the basicAuth attribute to the Base64 encoded value of
|
instance from now on.
|
||||||
<user>:<password>, e.g.:<ul>
|
|
||||||
# Calculate first the encoded string with the commandline program<br>
|
|
||||||
$ echo -n fhemuser:secret | base64<br>
|
|
||||||
ZmhlbXVzZXI6c2VjcmV0<br>
|
|
||||||
fhem.cfg:<br>
|
|
||||||
attr WEB basicAuth ZmhlbXVzZXI6c2VjcmV0
|
|
||||||
</ul>
|
|
||||||
You can of course use other means of base64 encoding, e.g. online
|
|
||||||
Base64 encoders. If basicAuthMsg is set, it will be displayed in the
|
|
||||||
popup window when requesting the username/password.<br>
|
|
||||||
<br>
|
|
||||||
If the argument of basicAuth is enclosed in {}, then it will be
|
|
||||||
evaluated, and the $user and $password variable will be set to the
|
|
||||||
values entered. If the return value is true, then the password will be
|
|
||||||
accepted.
|
|
||||||
Example:<br>
|
|
||||||
<code>
|
|
||||||
attr WEB basicAuth { "$user:$password" eq "admin:secret" }<br>
|
|
||||||
</code>
|
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
<a name="closeConn"></a>
|
<a name="closeConn"></a>
|
||||||
@ -3647,52 +3612,13 @@ FW_widgetOverride($$)
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="#addStateEvent">addStateEvent</a></li>
|
<li><a href="#addStateEvent">addStateEvent</a></li>
|
||||||
|
|
||||||
<a name="allowedCommands"></a>
|
|
||||||
<li>allowedCommands<br>
|
|
||||||
Eine Komma getrennte Liste der erlaubten Befehle. Bei einer leeren
|
|
||||||
Liste (, dh. nur ein Komma) wird dieser FHEMWEB-Instanz "read-only".
|
|
||||||
<br> Falls es auf <code>get,set</code> gesetzt ist, dann sind in dieser
|
|
||||||
FHEMWEB Instanz keine Konfigurationsänderungen möglich, nur
|
|
||||||
"normale" Bedienung der Schalter/etc.<br>
|
|
||||||
|
|
||||||
Dieses Attribut sollte zusammen mit dem hiddenroom/hiddengroup
|
|
||||||
Attributen verwendet werden. <br>
|
|
||||||
|
|
||||||
<b>Achtung:</b> allowedCommands sollte wie hier beschrieben
|
|
||||||
funktionieren, allerdings können wir keine Garantie geben,
|
|
||||||
daß man sie nicht überlisten, und Schaden anrichten kann.
|
|
||||||
</li><br>
|
|
||||||
|
|
||||||
<li><a href="#allowfrom">allowfrom</a>
|
<li><a href="#allowfrom">allowfrom</a>
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
<a name="basicAuth"></a>
|
<li>allowedCommands, basicAuth, basicAuthMsg<br>
|
||||||
<li>basicAuth, basicAuthMsg<br>
|
Diese Attribute müssen ab sofort bei dem passenden <a
|
||||||
Fragt username/password zur Autentifizierung ab. Es gibt mehrere
|
href="#allowed">allowed</a> Gerät angelegt werden, und sind
|
||||||
Varianten:
|
für eine FHEMWEB Instanz unerwünscht.
|
||||||
<ul>
|
|
||||||
<li>falls das Argument <b>nicht</b> in {} eingeschlossen ist, dann wird
|
|
||||||
es als base64 kodiertes benutzername:passwort interpretiert.
|
|
||||||
Um sowas zu erzeugen kann man entweder einen der zahlreichen
|
|
||||||
Webdienste verwenden, oder das base64 Programm. Beispiel:
|
|
||||||
<ul><code>
|
|
||||||
$ echo -n fhemuser:secret | base64<br>
|
|
||||||
ZmhlbXVzZXI6c2VjcmV0<br>
|
|
||||||
fhem.cfg:<br>
|
|
||||||
attr WEB basicAuth ZmhlbXVzZXI6c2VjcmV0
|
|
||||||
</code></ul>
|
|
||||||
</li>
|
|
||||||
<li>Werden die Argumente in {} angegeben, wird es als perl-Ausdruck
|
|
||||||
ausgewertet, die Variablen $user and $password werden auf die
|
|
||||||
eingegebenen Werte gesetzt. Falls der Rückgabewert wahr ist,
|
|
||||||
wird die Anmeldung akzeptiert.
|
|
||||||
|
|
||||||
Beispiel:<br>
|
|
||||||
<code>
|
|
||||||
attr WEB basicAuth { "$user:$password" eq "admin:secret" }<br>
|
|
||||||
</code>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
<a name="closeConn"></a>
|
<a name="closeConn"></a>
|
||||||
|
446
fhem/FHEM/96_allowed.pm
Executable file
446
fhem/FHEM/96_allowed.pm
Executable file
@ -0,0 +1,446 @@
|
|||||||
|
##############################################
|
||||||
|
# $Id$
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
allowed_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
$hash->{DefFn} = "allowed_Define";
|
||||||
|
$hash->{AuthorizeFn} = "allowed_Authorize";
|
||||||
|
$hash->{AuthenticateFn} = "allowed_Authenticate";
|
||||||
|
$hash->{AttrFn} = "allowed_Attr";
|
||||||
|
$hash->{AttrList} = "disable:0,1 validFor allowedCommands allowedDevices ".
|
||||||
|
"basicAuth basicAuthMsg password globalpassword";
|
||||||
|
$hash->{UndefFn} = "allowed_Undef";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
sub
|
||||||
|
allowed_Define($$)
|
||||||
|
{
|
||||||
|
my ($hash, $def) = @_;
|
||||||
|
my @l = split(" ", $def);
|
||||||
|
|
||||||
|
if(@l > 2) {
|
||||||
|
my %list;
|
||||||
|
for(my $i=2; $i<@l; $i++) {
|
||||||
|
$list{$l[$i]} = 1;
|
||||||
|
}
|
||||||
|
$hash->{devices} = \%list;
|
||||||
|
}
|
||||||
|
$auth_refresh = 1;
|
||||||
|
readingsSingleUpdate($hash, "state", "active", 0);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
allowed_Undef($$)
|
||||||
|
{
|
||||||
|
$auth_refresh = 1;
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# Return 0 for don't care, 1 for Allowed, 2 for forbidden.
|
||||||
|
sub
|
||||||
|
allowed_Authorize($$$$)
|
||||||
|
{
|
||||||
|
my ($me, $cl, $type, $arg) = @_;
|
||||||
|
|
||||||
|
return 0 if($me->{disabled});
|
||||||
|
return 0 if($me->{validFor} && $me->{validFor} !~ m/\b$cl->{SNAME}\b/);
|
||||||
|
|
||||||
|
if($type eq "cmd") {
|
||||||
|
return 0 if(!$me->{allowedCommands});
|
||||||
|
return ($me->{allowedCommands} =~ m/\b$arg\b/) ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($type eq "devicename") {
|
||||||
|
return 0 if(!$me->{allowedDevices});
|
||||||
|
return ($me->{allowedDevices} =~ m/\b$arg\b/) ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
# Return 0 for authentication not needed, 1 for auth-ok, 2 for wrong password
|
||||||
|
sub
|
||||||
|
allowed_Authenticate($$$$)
|
||||||
|
{
|
||||||
|
my ($me, $cl, $param) = @_;
|
||||||
|
|
||||||
|
return 0 if($me->{disabled});
|
||||||
|
return 0 if($me->{validFor} && $me->{validFor} !~ m/\b$cl->{SNAME}\b/);
|
||||||
|
my $aName = $me->{NAME};
|
||||||
|
|
||||||
|
if($cl->{TYPE} eq "FHEMWEB") {
|
||||||
|
my $basicAuth = AttrVal($aName, "basicAuth", undef);
|
||||||
|
return 0 if(!$basicAuth);
|
||||||
|
|
||||||
|
my $FW_httpheader = $param;
|
||||||
|
my $secret = $FW_httpheader->{Authorization};
|
||||||
|
$secret =~ s/^Basic //i if($secret);
|
||||||
|
my $pwok = ($secret && $secret eq $basicAuth); # Base64
|
||||||
|
if($secret && $basicAuth =~ m/^{.*}$/) {
|
||||||
|
eval "use MIME::Base64";
|
||||||
|
if($@) {
|
||||||
|
Log3 $aName, 1, $@;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
my ($user, $password) = split(":", decode_base64($secret));
|
||||||
|
$pwok = eval $basicAuth;
|
||||||
|
Log3 $aName, 1, "basicAuth expression: $@" if($@);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1 if($pwok);
|
||||||
|
|
||||||
|
my $msg = AttrVal($aName, "basicAuthMsg", "FHEM: login required");
|
||||||
|
$cl->{".httpAuthHeader"} = "HTTP/1.1 401 Authorization Required\r\n".
|
||||||
|
"WWW-Authenticate: Basic realm=\"$msg\"\r\n";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($cl->{TYPE} eq "telnet") {
|
||||||
|
my $pw = AttrVal($aName, "password", undef);
|
||||||
|
if(!$pw) {
|
||||||
|
$pw = AttrVal($aName, "globalpassword", undef);
|
||||||
|
$pw = undef if($pw && $cl->{NAME} !~ m/^telnet:127.0.0.1/);
|
||||||
|
}
|
||||||
|
return 0 if(!$pw);
|
||||||
|
return 2 if(!defined($param));
|
||||||
|
if($pw =~ m/^{.*}$/) {
|
||||||
|
my $password = $param;
|
||||||
|
my $ret = eval $pw;
|
||||||
|
Log3 $aName, 1, "password expression: $@" if($@);
|
||||||
|
return ($ret ? 1 : 2);
|
||||||
|
}
|
||||||
|
return ($pw eq $param) ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub
|
||||||
|
allowed_Attr(@)
|
||||||
|
{
|
||||||
|
my ($type, $devName, $attrName, @param) = @_;
|
||||||
|
my $hash = $defs{$devName};
|
||||||
|
|
||||||
|
my $set = ($type eq "del" ? 0 : (!defined($param[0]) || $param[0]) ? 1 : 0);
|
||||||
|
|
||||||
|
if($attrName eq "disable") {
|
||||||
|
readingsSingleUpdate($hash, "state", $set ? "disabled" : "active", 1);
|
||||||
|
if($set) {
|
||||||
|
$hash->{disable} = 1;
|
||||||
|
} else {
|
||||||
|
delete($hash->{disable});
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif($attrName eq "allowedCommands" || # hoping for some speedup
|
||||||
|
$attrName eq "allowedDevices" ||
|
||||||
|
$attrName eq "validFor") {
|
||||||
|
if($set) {
|
||||||
|
$hash->{$attrName} = join(" ", @param);
|
||||||
|
} else {
|
||||||
|
delete($hash->{$attrName});
|
||||||
|
}
|
||||||
|
|
||||||
|
} elsif(($attrName eq "basicAuth" ||
|
||||||
|
$attrName eq "password" || $attrName eq "globalpassword") &&
|
||||||
|
$type eq "set") {
|
||||||
|
foreach my $d (devspec2array("TYPE=(FHEMWEB|telnet)")) {
|
||||||
|
delete $defs{$d}{Authenticated} if($defs{$d});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<a name="allowed"></a>
|
||||||
|
<h3>allowed</h3>
|
||||||
|
<ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="alloweddefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> allowed <deviceList></code>
|
||||||
|
<br><br>
|
||||||
|
Authorize execution of commands and modification of devices based on the
|
||||||
|
frontend used.<br>
|
||||||
|
<b>Note:</b> this module should work as intended, but no guarantee
|
||||||
|
can be given that there is no way to circumvent it.<br><br>
|
||||||
|
Examples:
|
||||||
|
<ul><code>
|
||||||
|
define allowedWEB allowed<br>
|
||||||
|
attr allowedWEB validFor WEB,WEBphone,WEBtablet<br>
|
||||||
|
attr allowedWEB basicAuth { "$user:$password" eq "admin:secret" }<br>
|
||||||
|
attr allowedWEB allowedCommands set,get<br><br>
|
||||||
|
|
||||||
|
define allowedTelnet allowed<br>
|
||||||
|
attr allowedTelnet validFor telnetPort<br>
|
||||||
|
attr allowedTelnet password secret<br>
|
||||||
|
</code></ul>
|
||||||
|
<br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a name="allowedset"></a>
|
||||||
|
<b>Set:</b> <ul>N/A</ul><br>
|
||||||
|
|
||||||
|
<a name="allowedget"></a>
|
||||||
|
<b>Get</b> <ul>N/A</ul><br>
|
||||||
|
|
||||||
|
<a name="allowedattr"></a>
|
||||||
|
<b>Attributes</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#disable">disable</a></li><br>
|
||||||
|
|
||||||
|
<a name="allowedCommands"></a>
|
||||||
|
<li>allowedCommands<br>
|
||||||
|
A comma separated list of commands allowed from the matching frontend
|
||||||
|
(see validFor).<br>
|
||||||
|
If set to an empty list <code>, (i.e. comma only)</code>
|
||||||
|
then no comands are allowed. If set to <code>get,set</code>, then only
|
||||||
|
a "regular" usage is allowed via set and get, but changing any
|
||||||
|
configuration is forbidden.<br>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="allowedDevices"></a>
|
||||||
|
<li>allowedDevices<br>
|
||||||
|
A comma separated list of device names which can be manipulated via the
|
||||||
|
matching frontend (see validFor).
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="basicAuth"></a>
|
||||||
|
<li>basicAuth, basicAuthMsg<br>
|
||||||
|
request a username/password authentication for FHEMWEB access. You have
|
||||||
|
to set the basicAuth attribute to the Base64 encoded value of
|
||||||
|
<user>:<password>, e.g.:<ul>
|
||||||
|
# Calculate first the encoded string with the commandline program<br>
|
||||||
|
$ echo -n fhemuser:secret | base64<br>
|
||||||
|
ZmhlbXVzZXI6c2VjcmV0<br>
|
||||||
|
# Set the FHEM attribute<br>
|
||||||
|
attr allowed_WEB basicAuth ZmhlbXVzZXI6c2VjcmV0
|
||||||
|
</ul>
|
||||||
|
You can of course use other means of base64 encoding, e.g. online
|
||||||
|
Base64 encoders.<br>
|
||||||
|
|
||||||
|
If the argument of basicAuth is enclosed in { }, then it will be
|
||||||
|
evaluated, and the $user and $password variable will be set to the
|
||||||
|
values entered. If the return value is true, then the password will be
|
||||||
|
accepted.<br>
|
||||||
|
|
||||||
|
If basicAuthMsg is set, it will be displayed in the
|
||||||
|
popup window when requesting the username/password.<br>
|
||||||
|
|
||||||
|
Example:<br>
|
||||||
|
<ul><code>
|
||||||
|
attr allowedWEB basicAuth { "$user:$password" eq "admin:secret" }<br>
|
||||||
|
</code></ul>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="password"></a>
|
||||||
|
<li>password<br>
|
||||||
|
Specify a password for telnet instances, which has to be entered as the
|
||||||
|
very first string after the connection is established. If the argument
|
||||||
|
is enclosed in {}, then it will be evaluated, and the $password
|
||||||
|
variable will be set to the password entered. If the return value is
|
||||||
|
true, then the password will be accepted. If this parameter is
|
||||||
|
specified, FHEM sends telnet IAC requests to supress echo while
|
||||||
|
entering the password. Also all returned lines are terminated with
|
||||||
|
\r\n.
|
||||||
|
Example:<br>
|
||||||
|
<ul>
|
||||||
|
<code>
|
||||||
|
attr allowed_tPort password secret<br>
|
||||||
|
attr allowed_tPort password {"$password" eq "secret"}
|
||||||
|
</code>
|
||||||
|
</ul>
|
||||||
|
Note: if this attribute is set, you have to specify a password as the
|
||||||
|
first argument when using fhem.pl in client mode:
|
||||||
|
<ul>
|
||||||
|
perl fhem.pl localhost:7072 secret "set lamp on"
|
||||||
|
</ul>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="globalpassword"></a>
|
||||||
|
<li>globalpassword<br>
|
||||||
|
Just like the attribute password, but a password will only required for
|
||||||
|
non-local connections.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="validFor"></a>
|
||||||
|
<li>validFor<br>
|
||||||
|
A comma separated list of frontend names. Currently supported frontends
|
||||||
|
are all devices connected through the FHEM TCP/IP library, e.g. telnet
|
||||||
|
and FHEMWEB. If set, the rules specified via the other attributes will
|
||||||
|
only apply to the frontends in the list. If not set, the rules apply to
|
||||||
|
all frontends.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
=end html
|
||||||
|
|
||||||
|
=begin html_DE
|
||||||
|
|
||||||
|
<a name="allowed"></a>
|
||||||
|
<h3>allowed</h3>
|
||||||
|
<ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="alloweddefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> allowed <deviceList></code>
|
||||||
|
<br><br>
|
||||||
|
Authorisiert das Ausführen von Kommandos oder das Ändern von
|
||||||
|
Geräten abhängig vom verwendeten Frontend.<br>
|
||||||
|
|
||||||
|
<b>Achtung:</b> das Modul sollte wie hier beschrieben funktionieren,
|
||||||
|
allerdings können wir keine Garantie geben, daß man sie nicht
|
||||||
|
überlisten, und Schaden anrichten kann.
|
||||||
|
<br>
|
||||||
|
Beispiele:
|
||||||
|
<ul><code>
|
||||||
|
define allowedWEB allowed<br>
|
||||||
|
attr allowedWEB validFor WEB,WEBphone,WEBtablet<br>
|
||||||
|
attr allowedWEB basicAuth { "$user:$password" eq "admin:secret" }<br>
|
||||||
|
attr allowedWEB allowedCommands set,get<br><br>
|
||||||
|
|
||||||
|
define allowedTelnet allowed<br>
|
||||||
|
attr allowedTelnet validFor telnetPort<br>
|
||||||
|
attr allowedTelnet password secret<br>
|
||||||
|
</code></ul>
|
||||||
|
<br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a name="allowedset"></a>
|
||||||
|
<b>Set:</b> <ul>N/A</ul><br>
|
||||||
|
|
||||||
|
<a name="allowedget"></a>
|
||||||
|
<b>Get</b> <ul>N/A</ul><br>
|
||||||
|
|
||||||
|
<a name="allowedattr"></a>
|
||||||
|
<b>Attribute</b>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#disable">disable</a>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="allowedCommands"></a>
|
||||||
|
<li>allowedCommands<br>
|
||||||
|
Eine Komma getrennte Liste der erlaubten Befehle des passenden
|
||||||
|
Frontends (siehe validFor). Bei einer leeren Liste (, dh. nur ein
|
||||||
|
Komma) wird dieser Frontend "read-only".
|
||||||
|
Falls es auf <code>get,set</code> gesetzt ist, dann sind in dieser
|
||||||
|
Frontend keine Konfigurationsänderungen möglich, nur
|
||||||
|
"normale" Bedienung der Schalter/etc.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="allowedDevices"></a>
|
||||||
|
<li>allowedDevices<br>
|
||||||
|
Komma getrennte Liste von Gerätenamen, die mit dem passenden
|
||||||
|
Frontend (siehe validFor) geändert werden können.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="basicAuth"></a>
|
||||||
|
<li>basicAuth, basicAuthMsg<br>
|
||||||
|
Betrifft nur FHEMWEB Instanzen (siehe validFor): Fragt username /
|
||||||
|
password zur Autentifizierung ab. Es gibt mehrere Varianten:
|
||||||
|
<ul>
|
||||||
|
<li>falls das Argument <b>nicht</b> in { } eingeschlossen ist, dann wird
|
||||||
|
es als base64 kodiertes benutzername:passwort interpretiert.
|
||||||
|
Um sowas zu erzeugen kann man entweder einen der zahlreichen
|
||||||
|
Webdienste verwenden, oder das base64 Programm. Beispiel:
|
||||||
|
<ul><code>
|
||||||
|
$ echo -n fhemuser:secret | base64<br>
|
||||||
|
ZmhlbXVzZXI6c2VjcmV0<br>
|
||||||
|
fhem.cfg:<br>
|
||||||
|
attr WEB basicAuth ZmhlbXVzZXI6c2VjcmV0
|
||||||
|
</code></ul>
|
||||||
|
</li>
|
||||||
|
<li>Werden die Argumente in { } angegeben, wird es als perl-Ausdruck
|
||||||
|
ausgewertet, die Variablen $user and $password werden auf die
|
||||||
|
eingegebenen Werte gesetzt. Falls der Rückgabewert wahr ist,
|
||||||
|
wird die Anmeldung akzeptiert.
|
||||||
|
|
||||||
|
Beispiel:<br>
|
||||||
|
<ul><code>
|
||||||
|
attr allwedWEB basicAuth { "$user:$password" eq "admin:secret" }<br>
|
||||||
|
</code></ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="password"></a>
|
||||||
|
<li>password<br>
|
||||||
|
Betrifft nur telnet Instanzen (siehe validFor): Bezeichnet ein
|
||||||
|
Passwort, welches als allererster String eingegeben werden muss,
|
||||||
|
nachdem die Verbindung aufgebaut wurde. Wenn das Argument in { }
|
||||||
|
eingebettet ist, dann wird es als Perl-Ausdruck ausgewertet, und die
|
||||||
|
Variable $password mit dem eingegebenen Passwort verglichen. Ist der
|
||||||
|
zurückgegebene Wert wahr (true), wird das Passwort akzeptiert.
|
||||||
|
Falls dieser Parameter gesetzt wird, sendet FHEM telnet IAC Requests,
|
||||||
|
um ein Echo während der Passworteingabe zu unterdrücken.
|
||||||
|
Ebenso werden alle zurückgegebenen Zeilen mit \r\n abgeschlossen.
|
||||||
|
|
||||||
|
Beispiel:<br>
|
||||||
|
<ul>
|
||||||
|
<code>
|
||||||
|
attr allowed_tPort password secret<br>
|
||||||
|
attr allowed_tPort password {"$password" eq "secret"}
|
||||||
|
</code>
|
||||||
|
</ul>
|
||||||
|
Hinweis: Falls dieses Attribut gesetzt wird, muss als erstes Argument
|
||||||
|
ein Passwort angegeben werden, wenn fhem.pl im Client-mode betrieben
|
||||||
|
wird:
|
||||||
|
<ul>
|
||||||
|
<code>
|
||||||
|
perl fhem.pl localhost:7072 secret "set lamp on"
|
||||||
|
</code>
|
||||||
|
</ul>
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="globalpassword"></a>
|
||||||
|
<li>globalpassword<br>
|
||||||
|
Betrifft nur telnet Instanzen (siehe validFor): Entspricht dem
|
||||||
|
Attribut password; ein Passwort wird aber ausschließlich für
|
||||||
|
nicht-lokale Verbindungen verlangt.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="validFor"></a>
|
||||||
|
<li>validFor<br>
|
||||||
|
Komma separierte Liste von Forntend-Instanznamen. Aktuell werden nur
|
||||||
|
Frontends unterstützt, die das FHEM TCP/IP Bibliothek verwenden.
|
||||||
|
Falls gesetzt, dann gelten die mit den anderen Attributen
|
||||||
|
spezifizierten Regeln nur für diese Instanzen. Falls nicht
|
||||||
|
gesetzt, dann sind alle Frontends betroffen.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
=end html_DE
|
||||||
|
|
||||||
|
=cut
|
@ -31,6 +31,7 @@ telnet_Initialize($)
|
|||||||
Hlp=>"[utf8|latin1],query and set the character encoding for the current telnet session" );
|
Hlp=>"[utf8|latin1],query and set the character encoding for the current telnet session" );
|
||||||
$cmds{encoding} = \%lhash;
|
$cmds{encoding} = \%lhash;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
CommandTelnetEncoding($$)
|
CommandTelnetEncoding($$)
|
||||||
{
|
{
|
||||||
@ -60,16 +61,29 @@ telnet_SecurityCheck($$)
|
|||||||
!grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}));
|
!grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}));
|
||||||
my $motd = AttrVal("global", "motd", "");
|
my $motd = AttrVal("global", "motd", "");
|
||||||
if($motd =~ "^SecurityCheck") {
|
if($motd =~ "^SecurityCheck") {
|
||||||
my @list = grep { !(AttrVal($_, "password", undef) ||
|
my @list1 = devspec2array("TYPE=telnet");
|
||||||
AttrVal($_, "globalpassword", undef)) }
|
my @list2 = devspec2array("TYPE=allowed");
|
||||||
devspec2array("TYPE=telnet");
|
my @list3;
|
||||||
$motd .= (join(",", sort @list).
|
for my $l (@list1) { # This is a hack, as hardcoded to basicAuth
|
||||||
" has no password/globalpassword attribute.\n")
|
next if(!$defs{$l});
|
||||||
if(@list);
|
my $fnd = 0;
|
||||||
|
for my $a (@list2) {
|
||||||
|
next if(!$defs{$a});
|
||||||
|
my $vf = AttrVal($a, "validFor","");
|
||||||
|
$fnd = 1 if((!$vf || $vf =~ m/\b$l\b/) &&
|
||||||
|
(AttrVal($a, "password","") ||
|
||||||
|
AttrVal($a, "globalpassword","")));
|
||||||
|
}
|
||||||
|
push @list3, $l if(!$fnd);
|
||||||
|
}
|
||||||
|
$motd .= (join(",", sort @list3).
|
||||||
|
" has no associated allowed device with password/globalpassword.\n")
|
||||||
|
if(@list3);
|
||||||
$attr{global}{motd} = $motd;
|
$attr{global}{motd} = $motd;
|
||||||
}
|
}
|
||||||
delete $modules{telnet}{NotifyFn};
|
delete $modules{telnet}{NotifyFn};
|
||||||
return;
|
return;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
@ -165,19 +179,6 @@ telnet_Define($$$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
|
||||||
telnet_pw($$)
|
|
||||||
{
|
|
||||||
my ($sname, $cname) = @_;
|
|
||||||
my $pw = $attr{$sname}{password};
|
|
||||||
return $pw if($pw);
|
|
||||||
|
|
||||||
$pw = $attr{$sname}{globalpassword};
|
|
||||||
return $pw if($pw && $cname !~ m/^telnet:127.0.0.1/);
|
|
||||||
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
sub
|
sub
|
||||||
telnet_Read($)
|
telnet_Read($)
|
||||||
@ -193,8 +194,10 @@ telnet_Read($)
|
|||||||
syswrite($chash->{CD}, sprintf("%c%c%c", 255, 253, 0) )
|
syswrite($chash->{CD}, sprintf("%c%c%c", 255, 253, 0) )
|
||||||
if( AttrVal($name, "encoding", "") ); #DO BINARY
|
if( AttrVal($name, "encoding", "") ); #DO BINARY
|
||||||
$chash->{CD}->flush();
|
$chash->{CD}->flush();
|
||||||
|
my $auth = Authenticate($chash, undef);
|
||||||
syswrite($chash->{CD}, sprintf("%c%c%cPassword: ", 255, 251, 1)) # WILL ECHO
|
syswrite($chash->{CD}, sprintf("%c%c%cPassword: ", 255, 251, 1)) # WILL ECHO
|
||||||
if(telnet_pw($name, $chash->{NAME}));
|
if($auth);
|
||||||
|
$chash->{Authenticated} = 0 if(!$auth);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,8 +220,7 @@ telnet_Read($)
|
|||||||
|
|
||||||
$buf =~ s/\r//g;
|
$buf =~ s/\r//g;
|
||||||
my $sname = ($hash->{isClient} ? $name : $hash->{SNAME});
|
my $sname = ($hash->{isClient} ? $name : $hash->{SNAME});
|
||||||
my $pw = telnet_pw($sname, $name);
|
if(!defined($hash->{Authenticated}) || $hash->{Authenticated}) {
|
||||||
if($pw) {
|
|
||||||
$buf =~ s/\xff..//g; # Telnet IAC stuff
|
$buf =~ s/\xff..//g; # Telnet IAC stuff
|
||||||
$buf =~ s/\xfd(.)//; # Telnet Do ?
|
$buf =~ s/\xfd(.)//; # Telnet Do ?
|
||||||
syswrite($hash->{CD}, sprintf("%c%c%c", 0xff, 0xfc, ord($1)))
|
syswrite($hash->{CD}, sprintf("%c%c%c", 0xff, 0xfc, ord($1)))
|
||||||
@ -232,19 +234,11 @@ telnet_Read($)
|
|||||||
my ($cmd, $rest) = split("\n", $hash->{BUF}, 2);
|
my ($cmd, $rest) = split("\n", $hash->{BUF}, 2);
|
||||||
$hash->{BUF} = $rest;
|
$hash->{BUF} = $rest;
|
||||||
|
|
||||||
if(!$hash->{pwEntered}) {
|
if(!defined($hash->{Authenticated})) {
|
||||||
if($pw) {
|
|
||||||
syswrite($hash->{CD}, sprintf("%c%c%c\r\n", 255, 252, 1)); # WONT ECHO
|
syswrite($hash->{CD}, sprintf("%c%c%c\r\n", 255, 252, 1)); # WONT ECHO
|
||||||
|
|
||||||
$ret = ($pw eq $cmd);
|
if(Authenticate($hash, $cmd) == 1) {
|
||||||
if($pw =~ m/^{.*}$/) { # Expression as pw
|
$hash->{Authenticated} = 1;
|
||||||
my $password = $cmd;
|
|
||||||
$ret = eval $pw;
|
|
||||||
Log3 $name, 1, "password expression: $@" if($@);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($ret) {
|
|
||||||
$hash->{pwEntered} = 1;
|
|
||||||
next;
|
next;
|
||||||
} else {
|
} else {
|
||||||
if($hash->{isClient}) {
|
if($hash->{isClient}) {
|
||||||
@ -256,7 +250,7 @@ telnet_Read($)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$gotCmd = 1;
|
$gotCmd = 1;
|
||||||
if($cmd) {
|
if($cmd) {
|
||||||
if($cmd =~ m/\\ *$/) { # Multi-line
|
if($cmd =~ m/\\ *$/) { # Multi-line
|
||||||
@ -268,8 +262,7 @@ telnet_Read($)
|
|||||||
undef($hash->{prevlines});
|
undef($hash->{prevlines});
|
||||||
}
|
}
|
||||||
$cmd = latin1ToUtf8($cmd) if( $hash->{encoding} eq "latin1" );
|
$cmd = latin1ToUtf8($cmd) if( $hash->{encoding} eq "latin1" );
|
||||||
$ret = AnalyzeCommandChain($hash, $cmd,
|
$ret = AnalyzeCommandChain($hash, $cmd);
|
||||||
AttrVal($sname,"allowedCommands",undef));
|
|
||||||
push @ret, $ret if(defined($ret));
|
push @ret, $ret if(defined($ret));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -288,7 +281,7 @@ telnet_Read($)
|
|||||||
$ret .= ($hash->{prevlines} ? "> " : $hash->{prompt}." ")
|
$ret .= ($hash->{prevlines} ? "> " : $hash->{prompt}." ")
|
||||||
if($gotCmd && $hash->{showPrompt} && !$hash->{rcvdQuit});
|
if($gotCmd && $hash->{showPrompt} && !$hash->{rcvdQuit});
|
||||||
|
|
||||||
$ret =~ s/\n/\r\n/g if($pw); # only for DOS telnet
|
$ret =~ s/\n/\r\n/g if($hash->{Authenticated}); # only for DOS telnet
|
||||||
telnet_Output($hash,$ret);
|
telnet_Output($hash,$ret);
|
||||||
|
|
||||||
if($hash->{rcvdQuit}) {
|
if($hash->{rcvdQuit}) {
|
||||||
@ -323,16 +316,30 @@ telnet_Output($$)
|
|||||||
sub
|
sub
|
||||||
telnet_Attr(@)
|
telnet_Attr(@)
|
||||||
{
|
{
|
||||||
|
my ($type, $devName, $attrName, @param) = @_;
|
||||||
my @a = @_;
|
my @a = @_;
|
||||||
my $hash = $defs{$a[1]};
|
my $hash = $defs{$devName};
|
||||||
|
|
||||||
if($a[0] eq "set" && $a[2] eq "SSL") {
|
if($type eq "set" && $attrName eq "SSL") {
|
||||||
TcpServer_SetSSL($hash);
|
TcpServer_SetSSL($hash);
|
||||||
if($hash->{CD}) {
|
if($hash->{CD}) {
|
||||||
my $ret = IO::Socket::SSL->start_SSL($hash->{CD});
|
my $ret = IO::Socket::SSL->start_SSL($hash->{CD});
|
||||||
Log3 $a[1], 1, "$hash->{NAME} start_SSL: $ret" if($ret);
|
Log3 $devName, 1, "$hash->{NAME} start_SSL: $ret" if($ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(($attrName eq "allowedCommands" ||
|
||||||
|
$attrName eq "password" ||
|
||||||
|
$attrName eq "globalpassword" ) && $type eq "set") {
|
||||||
|
my $aName = "allowed_$devName";
|
||||||
|
my $exists = ($defs{$aName} ? 1 : 0);
|
||||||
|
AnalyzeCommand(undef, "defmod $aName allowed");
|
||||||
|
AnalyzeCommand(undef, "attr $aName validFor $devName");
|
||||||
|
AnalyzeCommand(undef, "attr $aName $attrName ".join(" ",@param));
|
||||||
|
return "$devName: ".($exists ? "modifying":"creating").
|
||||||
|
" device $aName for attribute $attrName";
|
||||||
|
}
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,8 +394,10 @@ telnet_ActivateInform($;$)
|
|||||||
Examples:
|
Examples:
|
||||||
<ul>
|
<ul>
|
||||||
<code>define tPort telnet 7072 global</code><br>
|
<code>define tPort telnet 7072 global</code><br>
|
||||||
<code>attr tPort globalpassword mySecret</code><br>
|
|
||||||
<code>attr tPort SSL</code><br>
|
<code>attr tPort SSL</code><br>
|
||||||
|
<code>attr allowed_tPort allowed</code><br>
|
||||||
|
<code>attr allowed_tPort validFor tPort</code><br>
|
||||||
|
<code>attr allowed_tPort globalpassword mySecret</code><br>
|
||||||
</ul>
|
</ul>
|
||||||
Note: The old global attribute port is automatically converted to a
|
Note: The old global attribute port is automatically converted to a
|
||||||
telnet instance with the name telnetPort. The global allowfrom attibute is
|
telnet instance with the name telnetPort. The global allowfrom attibute is
|
||||||
@ -424,37 +433,6 @@ telnet_ActivateInform($;$)
|
|||||||
<a name="telnetattr"></a>
|
<a name="telnetattr"></a>
|
||||||
<b>Attributes:</b>
|
<b>Attributes:</b>
|
||||||
<ul>
|
<ul>
|
||||||
<a href="#allowedCommands">allowedCommands</a><br>
|
|
||||||
|
|
||||||
<a name="password"></a>
|
|
||||||
<li>password<br>
|
|
||||||
Specify a password, which has to be entered as the very first string
|
|
||||||
after the connection is established. If the argument is enclosed in {},
|
|
||||||
then it will be evaluated, and the $password variable will be set to
|
|
||||||
the password entered. If the return value is true, then the password
|
|
||||||
will be accepted. If thies parameter is specified, fhem sends telnet
|
|
||||||
IAC requests to supress echo while entering the password.
|
|
||||||
Also all returned lines are terminated with \r\n.
|
|
||||||
Example:<br>
|
|
||||||
<ul>
|
|
||||||
<code>
|
|
||||||
attr tPort password secret<br>
|
|
||||||
attr tPort password {"$password" eq "secret"}
|
|
||||||
</code>
|
|
||||||
</ul>
|
|
||||||
Note: if this attribute is set, you have to specify a password as the
|
|
||||||
first argument when using fhem.pl in client mode:
|
|
||||||
<ul>
|
|
||||||
perl fhem.pl localhost:7072 secret "set lamp on"
|
|
||||||
</ul>
|
|
||||||
</li><br>
|
|
||||||
|
|
||||||
<a name="globalpassword"></a>
|
|
||||||
<li>globalpassword<br>
|
|
||||||
Just like the attribute password, but a password will only required for
|
|
||||||
non-local connections.
|
|
||||||
</li><br>
|
|
||||||
|
|
||||||
<a name="prompt"></a>
|
<a name="prompt"></a>
|
||||||
<li>prompt<br>
|
<li>prompt<br>
|
||||||
Sets the string for the telnet prompt, the default is fhem>
|
Sets the string for the telnet prompt, the default is fhem>
|
||||||
@ -538,8 +516,10 @@ telnet_ActivateInform($;$)
|
|||||||
Beispiele:
|
Beispiele:
|
||||||
<ul>
|
<ul>
|
||||||
<code>define tPort telnet 7072 global</code><br>
|
<code>define tPort telnet 7072 global</code><br>
|
||||||
<code>attr tPort globalpassword mySecret</code><br>
|
|
||||||
<code>attr tPort SSL</code><br>
|
<code>attr tPort SSL</code><br>
|
||||||
|
<code>attr allowed_tPort allowed</code><br>
|
||||||
|
<code>attr allowed_tPort validFor tPort</code><br>
|
||||||
|
<code>attr allowed_tPort globalpassword mySecret</code><br>
|
||||||
</ul>
|
</ul>
|
||||||
Hinweis: Das alte (pre 5.3) "global attribute port" wird automatisch in
|
Hinweis: Das alte (pre 5.3) "global attribute port" wird automatisch in
|
||||||
eine telnet-Instanz mit dem Namen telnetPort umgewandelt. Im Rahmen dieser
|
eine telnet-Instanz mit dem Namen telnetPort umgewandelt. Im Rahmen dieser
|
||||||
@ -579,43 +559,6 @@ telnet_ActivateInform($;$)
|
|||||||
<a name="telnetattr"></a>
|
<a name="telnetattr"></a>
|
||||||
<b>Attribute</b>
|
<b>Attribute</b>
|
||||||
<ul>
|
<ul>
|
||||||
<a href="#allowedCommands">allowedCommands</a><br>
|
|
||||||
|
|
||||||
<a name="password"></a>
|
|
||||||
<li>password<br>
|
|
||||||
Bezeichnet ein Passwort, welches als allererster String eingegeben
|
|
||||||
werden muss, nachdem die Verbindung aufgebaut wurde. Wenn das Argument
|
|
||||||
in {} eingebettet ist, dann wird es als Perl-Ausdruck ausgewertet, und
|
|
||||||
die Variable $password mit dem eingegebenen Passwort verglichen. Ist
|
|
||||||
der zurückgegebene Wert wahr (true), wurde das Passwort
|
|
||||||
akzeptiert. Falls dieser Parameter gesetzt wird, sendet fhem
|
|
||||||
telnet IAC Requests, um ein Echo während der Passworteingabe zu
|
|
||||||
unterdrücken. Ebenso werden alle zurückgegebenen Zeilen mit
|
|
||||||
\r\n abgeschlossen.
|
|
||||||
|
|
||||||
Beispiel:<br>
|
|
||||||
<ul>
|
|
||||||
<code>
|
|
||||||
attr tPort password secret<br>
|
|
||||||
attr tPort password {"$password" eq "secret"}
|
|
||||||
</code>
|
|
||||||
</ul>
|
|
||||||
Hinweis: Falls dieses Attribut gesetzt wird, muss als erstes Argument
|
|
||||||
ein Passwort angegeben werden, wenn fhem.pl im Client-mode betrieben
|
|
||||||
wird:
|
|
||||||
<ul>
|
|
||||||
<code>
|
|
||||||
perl fhem.pl localhost:7072 secret "set lamp on"
|
|
||||||
</code>
|
|
||||||
</ul>
|
|
||||||
</li><br>
|
|
||||||
|
|
||||||
<a name="globalpassword"></a>
|
|
||||||
<li>globalpassword<br>
|
|
||||||
Entspricht dem Attribut password; ein Passwort wird aber
|
|
||||||
ausschließlich für nicht-lokale Verbindungen verlangt.
|
|
||||||
</li><br>
|
|
||||||
|
|
||||||
<a name="prompt"></a>
|
<a name="prompt"></a>
|
||||||
<li>prompt<br>
|
<li>prompt<br>
|
||||||
Gibt die Zeichenkette an, welche in der Telnet-Sitzung als
|
Gibt die Zeichenkette an, welche in der Telnet-Sitzung als
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
<b>Helper modules</b>
|
<b>Helper modules</b>
|
||||||
<ul>
|
<ul>
|
||||||
<a href="#at">at</a>
|
<a href="#at">at</a>
|
||||||
|
<a href="#allowed">at</a>
|
||||||
<a href="#autocreate">autocreate</a>
|
<a href="#autocreate">autocreate</a>
|
||||||
<a href="#average">average</a>
|
<a href="#average">average</a>
|
||||||
<a href="#Calendar">Calendar</a>
|
<a href="#Calendar">Calendar</a>
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
<b>Hilfs (Erweiterungs-) Module</b>
|
<b>Hilfs (Erweiterungs-) Module</b>
|
||||||
<ul>
|
<ul>
|
||||||
<a href="#at">at</a>
|
<a href="#at">at</a>
|
||||||
|
<a href="#allowed">at</a>
|
||||||
<a href="#autocreate">autocreate</a>
|
<a href="#autocreate">autocreate</a>
|
||||||
<a href="#average">average</a>
|
<a href="#average">average</a>
|
||||||
<a href="#Calendar">Calendar</a>
|
<a href="#Calendar">Calendar</a>
|
||||||
|
81
fhem/fhem.pl
81
fhem/fhem.pl
@ -81,6 +81,7 @@ sub PrintHash($$);
|
|||||||
sub ReadingsNum($$$);
|
sub ReadingsNum($$$);
|
||||||
sub ReadingsTimestamp($$$);
|
sub ReadingsTimestamp($$$);
|
||||||
sub ReadingsVal($$$);
|
sub ReadingsVal($$$);
|
||||||
|
sub RefreshAuthList();
|
||||||
sub RemoveInternalTimer($);
|
sub RemoveInternalTimer($);
|
||||||
sub ReplaceEventMap($$$);
|
sub ReplaceEventMap($$$);
|
||||||
sub ResolveDateWildcards($@);
|
sub ResolveDateWildcards($@);
|
||||||
@ -224,6 +225,9 @@ use vars qw($lastDefChange); # number of last def/attr change
|
|||||||
use vars qw(@structChangeHist); # Contains the last 10 structural changes
|
use vars qw(@structChangeHist); # Contains the last 10 structural changes
|
||||||
use vars qw($cmdFromAnalyze); # used by the warnings-sub
|
use vars qw($cmdFromAnalyze); # used by the warnings-sub
|
||||||
use vars qw($featurelevel);
|
use vars qw($featurelevel);
|
||||||
|
use vars qw(@authorize); # List of authorization devices
|
||||||
|
use vars qw(@authenticate); # List of authentication devices
|
||||||
|
use vars qw($auth_refresh);
|
||||||
|
|
||||||
my $AttrList = "verbose:0,1,2,3,4,5 room group comment:textField-long alias ".
|
my $AttrList = "verbose:0,1,2,3,4,5 room group comment:textField-long alias ".
|
||||||
"eventMap userReadings:textField-long";
|
"eventMap userReadings:textField-long";
|
||||||
@ -231,7 +235,7 @@ my $currcfgfile=""; # current config/include file
|
|||||||
my $currlogfile; # logfile, without wildcards
|
my $currlogfile; # logfile, without wildcards
|
||||||
my $cvsid = '$Id$';
|
my $cvsid = '$Id$';
|
||||||
my $duplidx=0; # helper for the above pool
|
my $duplidx=0; # helper for the above pool
|
||||||
my $evalSpecials; # Used by EvalSpecials->AnalyzeCommand parameter passing
|
my $evalSpecials; # Used by EvalSpecials->AnalyzeCommand
|
||||||
my $intAtCnt=0;
|
my $intAtCnt=0;
|
||||||
my $logopened = 0; # logfile opened or using stdout
|
my $logopened = 0; # logfile opened or using stdout
|
||||||
my $namedef = "where <name> is a single device name, a list separated by komma (,) or a regexp. See the devspec section in the commandref.html for details.\n";
|
my $namedef = "where <name> is a single device name, a list separated by komma (,) or a regexp. See the devspec section in the commandref.html for details.\n";
|
||||||
@ -910,7 +914,7 @@ CommandIOWrite($$)
|
|||||||
sub
|
sub
|
||||||
AnalyzeCommandChain($$;$)
|
AnalyzeCommandChain($$;$)
|
||||||
{
|
{
|
||||||
my ($c, $cmd, $allowed) = @_;
|
my ($c, $cmd) = @_;
|
||||||
my @ret;
|
my @ret;
|
||||||
|
|
||||||
if($cmd =~ m/^[ \t]*(#.*)?$/) { # Save comments
|
if($cmd =~ m/^[ \t]*(#.*)?$/) { # Save comments
|
||||||
@ -933,7 +937,7 @@ AnalyzeCommandChain($$;$)
|
|||||||
my $subcmd;
|
my $subcmd;
|
||||||
while(defined($subcmd = shift @cmdList)) {
|
while(defined($subcmd = shift @cmdList)) {
|
||||||
$subcmd =~ s/SeMiCoLoN/;/g;
|
$subcmd =~ s/SeMiCoLoN/;/g;
|
||||||
my $lret = AnalyzeCommand($c, $subcmd, $allowed);
|
my $lret = AnalyzeCommand($c, $subcmd);
|
||||||
push(@ret, $lret) if(defined($lret));
|
push(@ret, $lret) if(defined($lret));
|
||||||
}
|
}
|
||||||
@cmdList = @saveCmdList;
|
@cmdList = @saveCmdList;
|
||||||
@ -946,15 +950,15 @@ AnalyzeCommandChain($$;$)
|
|||||||
sub
|
sub
|
||||||
AnalyzePerlCommand($$;$)
|
AnalyzePerlCommand($$;$)
|
||||||
{
|
{
|
||||||
my ($cl, $cmd, $calledFromChain) = @_;
|
my ($cl, $cmd, $calledFromChain) = @_; # third parmeter is deprecated
|
||||||
|
|
||||||
|
return "Forbidden command $cmd." if($cl && !Authorized($cl, "cmd", "perl"));
|
||||||
|
|
||||||
return "Forbidden command $cmd."
|
|
||||||
if($cl && $cl->{".allowed"} && $cl->{".allowed"} !~ m/\bperl\b/);
|
|
||||||
$cmd =~ s/\\ *\n/ /g; # Multi-line. Probably not needed anymore
|
$cmd =~ s/\\ *\n/ /g; # Multi-line. Probably not needed anymore
|
||||||
|
|
||||||
# Make life easier for oneliners:
|
# Make life easier for oneliners:
|
||||||
%value = ();
|
|
||||||
if($featurelevel <= 5.6) {
|
if($featurelevel <= 5.6) {
|
||||||
|
%value = ();
|
||||||
foreach my $d (keys %defs) {
|
foreach my $d (keys %defs) {
|
||||||
$value{$d} = $defs{$d}{STATE}
|
$value{$d} = $defs{$d}{STATE}
|
||||||
}
|
}
|
||||||
@ -994,9 +998,8 @@ AnalyzePerlCommand($$;$)
|
|||||||
sub
|
sub
|
||||||
AnalyzeCommand($$;$)
|
AnalyzeCommand($$;$)
|
||||||
{
|
{
|
||||||
my ($cl, $cmd, $allowed) = @_;
|
my ($cl, $cmd) = @_; # third parmeter is deprecated
|
||||||
|
|
||||||
$cl->{".allowed"} = $allowed if($cl); # Forum #38276
|
|
||||||
$cmd = "" if(!defined($cmd)); # Forum #29963
|
$cmd = "" if(!defined($cmd)); # Forum #29963
|
||||||
$cmd =~ s/^(\n|[ \t])*//;# Strip space or \n at the begginning
|
$cmd =~ s/^(\n|[ \t])*//;# Strip space or \n at the begginning
|
||||||
$cmd =~ s/[ \t]*$//;
|
$cmd =~ s/[ \t]*$//;
|
||||||
@ -1009,7 +1012,7 @@ AnalyzeCommand($$;$)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($cmd =~ m/^"(.*)"$/s) { # Shell code in bg, to be able to call us from it
|
if($cmd =~ m/^"(.*)"$/s) { # Shell code in bg, to be able to call us from it
|
||||||
return "Forbidden command $cmd." if($allowed && $allowed !~ m/\bshell\b/);
|
return "Forbidden command $cmd." if($cl || !Authorized($cl,"cmd","shell"));
|
||||||
if($evalSpecials) {
|
if($evalSpecials) {
|
||||||
map { $ENV{substr($_,1)} = $evalSpecials->{$_}; } keys %{$evalSpecials};
|
map { $ENV{substr($_,1)} = $evalSpecials->{$_}; } keys %{$evalSpecials};
|
||||||
}
|
}
|
||||||
@ -1041,7 +1044,7 @@ AnalyzeCommand($$;$)
|
|||||||
$fn = $cmds{$fn}{ReplacedBy}
|
$fn = $cmds{$fn}{ReplacedBy}
|
||||||
if(defined($cmds{$fn}) && defined($cmds{$fn}{ReplacedBy}));
|
if(defined($cmds{$fn}) && defined($cmds{$fn}{ReplacedBy}));
|
||||||
|
|
||||||
return "Forbidden command $fn." if($allowed && $allowed !~ m/\b$fn\b/);
|
return "Forbidden command $fn." if($cl && !Authorized($cl,"cmd",$fn));
|
||||||
|
|
||||||
#############
|
#############
|
||||||
# autoload commands.
|
# autoload commands.
|
||||||
@ -1077,6 +1080,11 @@ devspec2array($;$)
|
|||||||
|
|
||||||
return "" if(!defined($name));
|
return "" if(!defined($name));
|
||||||
if(defined($defs{$name})) {
|
if(defined($defs{$name})) {
|
||||||
|
if($cl && !Authorized($cl, "devicename", $name)) {
|
||||||
|
Log 4, "Forbidden device $name";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
# FHEM2FHEM LOG mode fake device, avoid local set/attr/etc operations on it
|
# FHEM2FHEM LOG mode fake device, avoid local set/attr/etc operations on it
|
||||||
return "FHEM2FHEM_FAKE_$name" if($defs{$name}{FAKEDEVICE});
|
return "FHEM2FHEM_FAKE_$name" if($defs{$name}{FAKEDEVICE});
|
||||||
return $name;
|
return $name;
|
||||||
@ -1156,6 +1164,7 @@ devspec2array($;$)
|
|||||||
push @ret,@res;
|
push @ret,@res;
|
||||||
}
|
}
|
||||||
return $name if(!@ret && !$isAttr);
|
return $name if(!@ret && !$isAttr);
|
||||||
|
@ret = grep { Authorized($cl, "devicename", $_) } @ret if($cl);
|
||||||
return @ret;
|
return @ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4526,4 +4535,54 @@ Each($$;$) # can be used e.g. in at, Forum #40022
|
|||||||
return $arr[$idx];
|
return $arr[$idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##################
|
||||||
|
# Return 1 if Authorized, else 0
|
||||||
|
sub
|
||||||
|
Authorized($$$)
|
||||||
|
{
|
||||||
|
my ($cl, $type, $arg) = @_;
|
||||||
|
|
||||||
|
return 1 if(!$init_done || !$cl || !$cl->{SNAME}); # Safeguarding
|
||||||
|
RefreshAuthList() if($auth_refresh);
|
||||||
|
|
||||||
|
foreach my $a (@authorize) {
|
||||||
|
my $r = CallFn($a, "AuthorizeFn", $defs{$a}, $cl, $type, $arg);
|
||||||
|
return 1 if($r == 1);
|
||||||
|
return 0 if($r == 2);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
##################
|
||||||
|
# Return 0 if not needed, 1 if authenticated, 2 if authentication failed
|
||||||
|
sub
|
||||||
|
Authenticate($$)
|
||||||
|
{
|
||||||
|
my ($cl, $arg) = @_;
|
||||||
|
|
||||||
|
return 1 if(!$init_done || !$cl || !$cl->{SNAME}); # Safeguarding
|
||||||
|
RefreshAuthList() if($auth_refresh);
|
||||||
|
|
||||||
|
foreach my $a (@authenticate) {
|
||||||
|
my $r = CallFn($a, "AuthenticateFn", $defs{$a}, $cl, $arg);
|
||||||
|
return $r if($r);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
RefreshAuthList()
|
||||||
|
{
|
||||||
|
@authorize = ();
|
||||||
|
@authenticate = ();
|
||||||
|
|
||||||
|
foreach my $d (sort keys %defs) {
|
||||||
|
my $h = $defs{$d};
|
||||||
|
next if(!$h->{TYPE} || !$modules{$h->{TYPE}});
|
||||||
|
push @authorize, $d if($modules{$h->{TYPE}}{AuthorizeFn});
|
||||||
|
push @authenticate, $d if($modules{$h->{TYPE}}{AuthenticateFn});
|
||||||
|
}
|
||||||
|
$auth_refresh = 0;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user