use
Socket
qw/inet_aton AF_INET/
;
has
description
=>
''
;
has
error
=>
''
;
has
expires
=> 0;
has
id
=> 0;
has
realm
=>
undef
;
has
realmname
=>
undef
;
has
satisfy
=>
undef
;
has
requirements
=>
sub
{
return
{} };
has
is_cached
=> 0;
has
cached
=> 0;
has
cachekey
=>
''
;
sub
is_valid {
my
$self
=
shift
;
return
1
unless
$self
->id;
unless
(
defined
(
$self
->realmname) &&
length
(
$self
->realmname)) {
$self
->error(
"E1317: Incorrect realmname"
);
return
0;
}
if
(
$self
->expires &&
$self
->expires <
time
) {
$self
->error(
"E1318: The realm data is expired"
);
return
0;
}
return
1;
}
sub
mark {
my
$self
=
shift
;
return
$self
->is_cached(1)->cached(
shift
|| steady_time);
}
sub
_check_by_default {
my
$self
=
shift
;
my
$reqs
=
$self
->requirements->{
'Default'
} // [];
my
$status
= 0;
foreach
my
$r
(
@$reqs
) {
my
$ent
=
lc
(
$r
->{entity});
if
(
$ent
eq
'allow'
) {
$status
++;
}
elsif
(
$ent
eq
'deny'
) {
$status
--;
}
}
return
(
$status
> 0) ? 1 : 0;
}
sub
_check_by_usergroup {
my
$self
=
shift
;
my
$username
=
shift
;
my
$groupnames
=
shift
// [];
$groupnames
= [
$groupnames
]
unless
ref
(
$groupnames
);
my
$reqs
=
$self
->requirements->{
'User/Group'
} // [];
my
$vu
= 0;
my
$status
= 0;
return
-1
unless
scalar
(
@$reqs
);
foreach
my
$r
(
@$reqs
) {
my
$ent
=
lc
(
$r
->{entity});
if
(
$ent
eq
'user'
) {
$status
++
if
_op(
'str'
,
$username
,
$r
->{op},
$r
->{value});
}
elsif
(
$ent
eq
'group'
) {
foreach
my
$g
(
@$groupnames
) {
$status
++
if
_op(
'str'
,
$g
,
$r
->{op},
$r
->{value});
}
}
elsif
(
$ent
eq
'valid-user'
) {
$vu
= 1;
}
}
return
$status
? 1 :
$vu
;
}
sub
_check_by_host {
my
$self
=
shift
;
my
$ip
=
shift
//
''
;
my
$reqs
=
$self
->requirements->{
'Host'
} // [];
my
$status
= 0;
return
-1
unless
scalar
(
@$reqs
);
return
0
unless
length
(
$ip
);
foreach
my
$r
(
@$reqs
) {
my
$ent
=
lc
(
$r
->{entity});
if
(
$ent
eq
'ip'
) {
$status
++
if
_op(
'ip'
,
$ip
,
$r
->{op},
$r
->{value});
}
elsif
(
$ent
eq
'host'
) {
my
$host
=
gethostbyaddr
(inet_aton(
$ip
), AF_INET) //
''
;
next
unless
length
(
$host
);
$status
++
if
_op(
'str'
,
$host
,
$r
->{op},
$r
->{value});
}
}
return
$status
;
}
sub
_check_by_env {
my
$self
=
shift
;
my
$reqs
=
$self
->requirements->{
'Env'
} // [];
my
$status
= 0;
return
-1
unless
scalar
(
@$reqs
);
foreach
my
$r
(
@$reqs
) {
my
$varname
=
uc
(
$r
->{entity});
next
unless
length
(
$varname
);
my
$varval
=
exists
(
$ENV
{
$varname
}) &&
defined
(
$ENV
{
$varname
}) ?
$ENV
{
$varname
} :
''
;
$status
++
if
_op(is_integer(
$varval
) ?
'int'
:
'str'
,
$varval
,
$r
->{op},
$r
->{value});
}
return
$status
;
}
sub
_check_by_header {
my
$self
=
shift
;
my
$cb
=
shift
//
sub
{
undef
};
return
0
unless
ref
(
$cb
) &&
ref
(
$cb
) eq
'CODE'
;
my
$reqs
=
$self
->requirements->{
'Header'
} // [];
my
$status
= 0;
return
-1
unless
scalar
(
@$reqs
);
foreach
my
$r
(
@$reqs
) {
my
$hkey
=
$r
->{entity};
next
unless
length
(
$hkey
);
my
$hval
=
$cb
->(
$hkey
) //
''
;
$status
++
if
_op(is_integer(
$hval
) ?
'int'
:
'str'
,
$hval
,
$r
->{op},
$r
->{value});
}
return
$status
;
}
sub
_op {
my
$rule
=
shift
||
'str'
;
my
$tst
=
shift
;
my
$op
=
shift
||
'eq'
;
my
$val
=
shift
;
my
(
$subnet
,
$ip
);
if
(
$rule
eq
'ip'
) {
$subnet
= Net::IP->new(
$val
) or
warn
(
sprintf
(
"Incorrect Network/CIDR: %s"
, Net::IP::Error()));
$ip
= Net::IP->new(
$tst
) or
warn
(
sprintf
(
"Incorrect client IP: %s"
, Net::IP::Error()));
return
0
unless
defined
(
$subnet
) &&
defined
(
$ip
);
}
if
(
$op
eq
'eq'
) {
if
(
$rule
eq
'str'
) {
return
defined
(
$tst
) &&
defined
(
$val
) &&
$tst
eq
$val
;
}
elsif
(
$rule
eq
'int'
) {
return
is_integer(
$tst
) && is_integer(
$val
) &&
$tst
==
$val
;
}
elsif
(
$rule
eq
'ip'
) {
return
$subnet
->overlaps(
$ip
) ? 1 : 0;
}
}
elsif
(
$op
eq
'ne'
) {
if
(
$rule
eq
'str'
) {
return
defined
(
$tst
) &&
defined
(
$val
) &&
$tst
ne
$val
;
}
elsif
(
$rule
eq
'int'
) {
return
is_integer(
$tst
) && is_integer(
$val
) &&
$tst
!=
$val
;
}
elsif
(
$rule
eq
'ip'
) {
return
$subnet
->overlaps(
$ip
) ? 0 : 1;
}
}
elsif
(
$op
eq
'gt'
) {
if
(
$rule
eq
'str'
) {
return
defined
(
$tst
) &&
defined
(
$val
) &&
$tst
gt
$val
;
}
elsif
(
$rule
eq
'int'
) {
return
is_integer(
$tst
) && is_integer(
$val
) &&
$tst
>
$val
;
}
elsif
(
$rule
eq
'ip'
) {
return
$subnet
->bincomp(
$op
,
$ip
) ? 1 : 0;
}
}
elsif
(
$op
eq
'lt'
) {
if
(
$rule
eq
'str'
) {
return
defined
(
$tst
) &&
defined
(
$val
) &&
$tst
lt
$val
;
}
elsif
(
$rule
eq
'int'
) {
return
is_integer(
$tst
) && is_integer(
$val
) &&
$tst
<
$val
;
}
elsif
(
$rule
eq
'ip'
) {
return
$subnet
->bincomp(
$op
,
$ip
) ? 1 : 0;
}
}
elsif
(
$op
eq
'ge'
) {
if
(
$rule
eq
'str'
) {
return
defined
(
$tst
) &&
defined
(
$val
) &&
$tst
ge
$val
;
}
elsif
(
$rule
eq
'int'
) {
return
is_integer(
$tst
) && is_integer(
$val
) &&
$tst
>=
$val
;
}
elsif
(
$rule
eq
'ip'
) {
return
$subnet
->bincomp(
$op
,
$ip
) ? 1 : 0;
}
}
elsif
(
$op
eq
'le'
) {
if
(
$rule
eq
'str'
) {
return
defined
(
$tst
) &&
defined
(
$val
) &&
$tst
le
$val
;
}
elsif
(
$rule
eq
'int'
) {
return
is_integer(
$tst
) && is_integer(
$val
) &&
$tst
<=
$val
;
}
elsif
(
$rule
eq
'ip'
) {
return
$subnet
->bincomp(
$op
,
$ip
) ? 1 : 0;
}
}
elsif
(
$op
eq
're'
) {
return
0
unless
defined
(
$tst
) &&
length
(
$tst
);
return
0
unless
defined
(
$val
) &&
length
(
$val
);
my
$vre
=
qr/$val/
;
if
(
$rule
eq
'str'
) {
return
$tst
=~
$vre
;
}
elsif
(
$rule
eq
'int'
) {
return
$tst
=~
$vre
;
}
elsif
(
$rule
eq
'ip'
) {
return
$tst
=~
$vre
;
}
}
elsif
(
$op
eq
'rn'
) {
return
0
unless
defined
(
$tst
) &&
length
(
$tst
);
return
0
unless
defined
(
$val
) &&
length
(
$val
);
my
$vre
=
qr/$val/
;
if
(
$rule
eq
'str'
) {
return
$tst
!~
$vre
;
}
elsif
(
$rule
eq
'int'
) {
return
$tst
!~
$vre
;
}
elsif
(
$rule
eq
'ip'
) {
return
$tst
=~
$vre
;
}
}
return
0;
}
1;