# 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 # 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;