Initial commit.

This commit is contained in:
2026-03-10 21:25:26 +08:00
commit 78739bf725
3089 changed files with 472990 additions and 0 deletions

133
lib/perl5/Selima/ChkPriv.pm Normal file
View File

@@ -0,0 +1,133 @@
# 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;