134 lines
4.1 KiB
Perl
134 lines
4.1 KiB
Perl
# Selima Website Content Management System
|
|
# ChkPriv.pm: The privilege checkers.
|
|
|
|
# Copyright (c) 2004-2018 imacat.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# Author: imacat <imacat@mail.imacat.idv.tw>
|
|
# First written: 2004-09-26
|
|
|
|
package Selima::ChkPriv;
|
|
use 5.008;
|
|
use strict;
|
|
use warnings;
|
|
use base qw(Exporter);
|
|
use vars qw(@EXPORT @EXPORT_OK);
|
|
BEGIN {
|
|
@EXPORT = qw(is_admin is_su user_parent_groups);
|
|
@EXPORT_OK = @EXPORT;
|
|
# Prototype declaration
|
|
sub is_admin(;$);
|
|
sub is_su(;$);
|
|
sub user_parent_groups($);
|
|
}
|
|
|
|
use Selima::Array;
|
|
use Selima::Cache qw(:chkpriv);
|
|
use Selima::ChkFunc;
|
|
use Selima::DataVars qw($DBH :groups);
|
|
use Selima::LogIn;
|
|
use Selima::UserName;
|
|
|
|
# is_admin: If the user is an administrator (by user sn)
|
|
sub is_admin(;$) {
|
|
local ($_, %_);
|
|
$_ = $_[0];
|
|
# Default to the current logged-in user
|
|
return is_su || in_array(ADMIN_GROUP, get_login_groups)
|
|
if !defined $_ || (defined get_login_sn && $_ == get_login_sn);
|
|
# Return the cache
|
|
return $ChkPriv_is_admin{$_} if exists $ChkPriv_is_admin{$_};
|
|
# Super user is always an administrator
|
|
return ($ChkPriv_is_admin{$_} = 1) if is_su($_);
|
|
# Check the groups
|
|
return ($ChkPriv_is_admin{$_} =
|
|
in_array(ADMIN_GROUP, user_parent_groups($_)));
|
|
}
|
|
|
|
# is_su: If the user is a super user
|
|
sub is_su(;$) {
|
|
local ($_, %_);
|
|
$_ = $_[0];
|
|
# Default to the current logged-in user
|
|
return in_array(SU_GROUP, get_login_groups)
|
|
if !defined $_ || (defined get_login_sn && $_ == get_login_sn);
|
|
# Return the cache
|
|
return $ChkPriv_is_su{$_} if exists $ChkPriv_is_su{$_};
|
|
# Check the groups
|
|
return ($ChkPriv_is_admin{$_} =
|
|
in_array(SU_GROUP, user_parent_groups($_)));
|
|
}
|
|
|
|
# user_parent_groups: Return the full list of groups a user belongs to
|
|
sub user_parent_groups($) {
|
|
local ($_, %_);
|
|
my ($sn, $sth, $sql, $count, %current, $group);
|
|
$sn = $_[0];
|
|
# Bounce for null
|
|
return if !defined $sn;
|
|
# Return the cache
|
|
return @{$ChkPriv_user_parent_groups{$sn}}
|
|
if exists $ChkPriv_user_parent_groups{$sn};
|
|
# Check the validity of the user first
|
|
if (defined get_login_sn && $sn != get_login_sn) {
|
|
if (!check_sn_in $sn, "users") {
|
|
$ChkPriv_user_parent_groups{$sn} = [];
|
|
return;
|
|
}
|
|
}
|
|
# Find the direct parent groups
|
|
$sql = "SELECT grp FROM usermem"
|
|
. " WHERE member=$sn"
|
|
. " ORDER BY grp;\n";
|
|
$sth = $DBH->prepare($sql);
|
|
$sth->execute;
|
|
$count = $sth->rows;
|
|
# Obtain the direct parent groups
|
|
for ($_ = 0, %current = qw(); $_ < $count; $_++) {
|
|
$current{${$sth->fetch}[0]} = 1;
|
|
}
|
|
# ALLUSERS_GROUP is automatically added to all the valid users
|
|
$current{groupsn(ALLUSERS_GROUP)} = 1;
|
|
# Trace all their ancester groups
|
|
while (1) {
|
|
$sql = "SELECT grp FROM groupmem"
|
|
. " WHERE " . join(" OR ", map "member=$_", keys %current)
|
|
. " GROUP BY grp ORDER BY grp;\n";
|
|
$sth = $DBH->prepare($sql);
|
|
$sth->execute;
|
|
$count = $sth->rows;
|
|
for ($_ = 0, @_ = qw(); $_ < $count; $_++) {
|
|
push @_, ${$sth->fetch}[0];
|
|
}
|
|
@_ = grep !exists $current{$_}, @_;
|
|
last if scalar(@_) == 0;
|
|
$current{$_} = 1 foreach @_;
|
|
}
|
|
# Find their ID
|
|
$sql = "SELECT id FROM groups"
|
|
. " WHERE " . join(" OR ", map "sn=$_", keys %current)
|
|
. " ORDER BY id;\n";
|
|
$sth = $DBH->prepare($sql);
|
|
$sth->execute;
|
|
$count = $sth->rows;
|
|
for ($_ = 0, @_ = qw(); $_ < $count; $_++) {
|
|
push @_, ${$sth->fetch}[0];
|
|
}
|
|
# Cache it
|
|
$ChkPriv_user_parent_groups{$sn} = [@_];
|
|
return @_;
|
|
}
|
|
|
|
return 1;
|