<?php // File: $Id: security.php,v 1.15 2001/12/07 23:43:11 jgm Exp $
// ----------------------------------------------------------------------
// POST-NUKE Content Management System
// Copyright (C) 2001 by the Post-Nuke Development Team.
// http://www.postnuke.com/
// ----------------------------------------------------------------------
// Based on:
// PHP-NUKE Web Portal System - http://phpnuke.org/
// Thatware - http://thatware.org/
// ----------------------------------------------------------------------
// LICENSE
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License (GPL)
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// To read the license please visit http://www.gnu.org/copyleft/gpl.html
// ----------------------------------------------------------------------
// Original Author of file: Jim McDonald
// Purpose of file: Provide a low-level security access mechanism
// ----------------------------------------------------------------------
/*
* Notes on security system
*
* Special UID and GIDS:
* UID -1 corresponds to 'all users', includes unregistered users
* GID -1 corresponds to 'all groups', includes unregistered users
* UID 0 corresponds to unregistered users
* GID 0 corresponds to unregistered users
*
*/
global $currentlang;
// Language
if (file_exists("language/$currentlang/security.php")) {
include "language/$currentlang/security.php";
} elseif (file_exists("language/eng/security.php")) {
include "language/eng/security.php";
}
/*
* Defines for access levels
*/
define("ACCESS_INVALID", -1);
define("ACCESS_NONE", 0);
define("ACCESS_OVERVIEW", 100);
define("ACCESS_READ", 200);
define("ACCESS_COMMENT", 300);
define("ACCESS_MODERATE", 400);
define("ACCESS_EDIT", 500);
define("ACCESS_ADD", 600);
define("ACCESS_DELETE", 700);
define("ACCESS_ADMIN", 800);
/*
* Arrays for transformations
*/
global $accessnames;
$accessnames = array( 0 => _ACCESS_NONE,
100 => _ACCESS_OVERVIEW,
200 => _ACCESS_READ,
300 => _ACCESS_COMMENT,
400 => _ACCESS_MODERATE,
500 => _ACCESS_EDIT,
600 => _ACCESS_ADD,
700 => _ACCESS_DELETE,
800 => _ACCESS_ADMIN);
// Don't think we need this, but leave it around for the moment
global $accesslevels;
$accesslevels = array(_ACCESS_NONE => 0,
_ACCESS_OVERVIEW => 100,
_ACCESS_READ => 200,
_ACCESS_COMMENT => 300,
_ACCESS_MODERATE => 400,
_ACCESS_EDIT => 500,
_ACCESS_ADD => 600,
_ACCESS_DELETE => 700,
_ACCESS_ADMIN => 800);
/*
* Translation functions - avoids globals in external code
*/
// Translate level -> name
function accesslevelname($level) {
global $accessnames;
//FTO Remove Warning
if (!isset($accessnames[$level])) $accessnames[$level]='';
return $accessnames[$level];
}
// Get all level -> name
function accesslevelnames() {
global $accessnames;
return $accessnames;
}
// Translate name -> level
function accessnamelevel($name) {
global $accesslevels;
return $accesslevels[$name];
}
// Get all name -> levels
function accessnamelevels() {
global $accesslevels;
return $accesslevels;
}
/*
* schemas - holds all component/instance schemas
*/
$schemas = array();
/*
* addinstanceschemainfo - register an instance schema with the security
* system
*
* Takes two parameters:
* - a component
* - an instance schema
*
* Will fail if an attempt is made to overwrite an existing schema
*/
function addinstanceschemainfo($component, $schema) {
global $schemas;
if (!empty($schemas[$component])) {
// Duplicate schema
die("Duplicate schema $component detected");
}
$schemas[$component] = $schema;
}
// Get list of schemas
function getinstanceschemainfo() {
global $schemas;
static $gotmoduleschemas = 0;
if ($gotmoduleschemas == 0) {
getmodulesinstanceschemainfo();
$gotmoduleschemas = 1;
}
return $schemas;
}
// Get instance information from modules
function getmodulesinstanceschemainfo() {
$moddir = opendir('modules/');
while ($modname = readdir($moddir)) {
if (@file_exists("modules/$modname/Version.php")) {
include "modules/$modname/Version.php";
if (!empty($modversion['securityschema'])) {
foreach ($modversion['securityschema'] as $component => $instance) {
addinstanceschemainfo($component, $instance);
}
}
$modversion['securityschema'] = '';
}
}
closedir($moddir);
}
/*
* authorised - see if a user is authorised to view a particular element
* Takes four parameters:
* - the realm
* - the component
* - the instance
* - the level of access required
*
* Returns 1 if authorised, 0 if not
*/
function authorised($testrealm, $testcomponent, $testinstance, $testlevel)
{
static $authinfogathered = 0;
static $userperms, $groupperms;
global $pntable, $dbconn;
if ($authinfogathered == 0) {
// First time here - get auth info
list($userperms, $groupperms) = gatherAuthInfo();
$authinfogathered = 1;
}
// Confirm this is a valid component
// Not yet active, might never be
// if (!authValidComponent($testcomponent)) {
// die("Invalid test component $testcomponent");
// exit;
// }
// Get group access level
$grouplevel = getLevel($groupperms, $testrealm, $testcomponent, $testinstance);
// Get user access level
$userlevel = getLevel($userperms, $testrealm, $testcomponent, $testinstance);
// Assume no access
$retval = 0;
// Group level access, if it exists
if ($grouplevel >= $testlevel) {
$retval = 1;
}
// User access level is over-ride, so return that if it exists
if ($userlevel > ACCESS_INVALID) {
if ($userlevel >= $testlevel) {
$retval = 1;
} else {
$retval = 0;
}
}
return($retval);
}
function gatherAuthInfo()
{
global $pntable, $dbconn, $user;
// Tables we use
$userpermtable = $pntable['user_perms'];
$userpermcolumn = &$pntable['user_perms_column'];
$groupmembershiptable = $pntable['group_membership'];
$groupmembershipcolumn = &$pntable['group_membership_column'];
$grouppermtable = $pntable['group_perms'];
$grouppermcolumn = &$pntable['group_perms_column'];
$realmtable = $pntable['realms'];
$realmcolumn = &$pntable['realms_column'];
// Empty arrays
$userperms = array();
$groupperms = array();
$uids[] = -1;
// Get user ID
if (empty($user)) {
// Unregistered UID
$uids[] = 0;
} else {
if (!is_user($user)) {
return array($userperms, $groupperms);
}
$uinfo = base64_decode($user);
$uinfo = explode(':', $uinfo);
$uids[] = $uinfo[0];
}
$uids = implode(",", $uids);
// ===FTO. USe the PNTABLES defines from the where clause.
// ORACLEDONE
// Get user permissions
$query = "SELECT $userpermcolumn[realm],
$userpermcolumn[component],
$userpermcolumn[instance],
$userpermcolumn[level]
FROM $userpermtable
WHERE $userpermcolumn[uid] IN ($uids)
ORDER by $userpermcolumn[sequence]";
$result = $dbconn->Execute($query);
//FTO : Rewrite the condition loop clearly to test EOF
if (!$result) {
PN_DBMsgError($dbconn, __FILE__, __LINE__, "An error ocurred");
die();
}
while(! $result->EOF) {
list($realm, $component, $instance, $level) = $result->fields;
// Fix component and instance to auto-insert '.*'
$component = preg_replace('/^$/', '.*', $component);
$component = preg_replace('/^:/', '.*:', $component);
$component = preg_replace('/::/', ':.*:', $component);
$component = preg_replace('/:$/', ':.*', $component);
$instance = preg_replace('/^$/', '.*', $instance);
$instance = preg_replace('/^:/', '.*:', $instance);
$instance = preg_replace('/::/', ':.*:', $instance);
$instance = preg_replace('/:$/', ':.*', $instance);
$userperms[] = array("realm" => $realm,
"component" => $component,
"instance" => $instance,
"level" => $level);
$result->MoveNext();
}
// Get all groups that user is in
$query = "SELECT $groupmembershipcolumn[gid]
FROM $groupmembershiptable
WHERE $groupmembershipcolumn[uid] IN ($uids)";
$result = $dbconn->Execute($query);
$usergroups[] = -1;
if (empty($user)) {
// Unregistered GID
$usergroups[] = 0;
}
//FTO : Rewrite the condition loop clearly to test EOF
if (!$result) {
PN_DBMsgError($dbconn, __FILE__, __LINE__, "An error ocurred");
die();
}
while(! $result->EOF ) {
list($gid) = $result->fields;
$usergroups[] = $gid;
$result->MoveNext();
}
$usergroups = implode(",", $usergroups);
//FTO : SOFT CODED GID. USE PNTABLES DEFINES
// Get all group permissions
$query = "SELECT $grouppermcolumn[realm],
$grouppermcolumn[component],
$grouppermcolumn[instance],
$grouppermcolumn[level]
FROM $grouppermtable
WHERE $grouppermcolumn[gid] IN ($usergroups)
ORDER by $grouppermcolumn[sequence]";
$result = $dbconn->Execute($query);
//FTO : Rewrite the condition loop clearly to test EOF
if (!$result) {
PN_DBMsgError($dbconn, __FILE__, __LINE__, "An error ocurred");
die();
}
while(! $result->EOF) {
list($realm, $component, $instance, $level) = $result->fields;
// Fix component and instance to auto-insert '.*' where
// there is nothing there
$component = preg_replace('/^$/', '.*', $component);
$component = preg_replace('/^:/', '.*:', $component);
$component = preg_replace('/::/', ':.*:', $component);
$component = preg_replace('/:$/', ':.*', $component);
$instance = preg_replace('/^$/', '.*', $instance);
$instance = preg_replace('/^:/', '.*:', $instance);
$instance = preg_replace('/::/', ':.*:', $instance);
$instance = preg_replace('/:$/', ':.*', $instance);
$groupperms[] = array("realm" => $realm,
"component" => $component,
"instance" => $instance,
"level" => $level);
$result->MoveNext();
}
return array($userperms, $groupperms);
}
function getLevel($perms, $testrealm, $testcomponent, $testinstance)
{
$level = ACCESS_INVALID;
// If we get a test component or instance purely consisting of ':' signs
// then it counts as blank
$testcomponent = preg_replace('/^:*$/', '', $testcomponent);
$testinstance = preg_replace('/^:*$/', '', $testinstance);
foreach ($perms as $perm) {
// Confirm generic realm, or this particular realm
if (($perm['realm'] != 0) && ($perm['realm'] != $testrealm)) {
continue;
}
if (($testcomponent != '') && ($testinstance != '')) {
// Confirm that component and instance match
if (!((ereg("^$perm[component]$", $testcomponent)) &&
(ereg("^$perm[instance]$", $testinstance)))) {
continue;
}
} elseif (($testcomponent != '') && ($testinstance == '')) {
// Confirm that component matches
if (!ereg("^$perm[component]$", $testcomponent)) {
continue;
}
} elseif (($testcomponent == '') && ($testinstance != '')) {
// Confirm that instance matches
if (!ereg("^$perm[instance]$", $testinstance)) {
continue;
}
}
// We have a match - set the level and quit
$level = $perm['level'];
break;
}
return($level);
}
/*
* Confirm that we have a schema for this component
*/
function authValidComponent($testcomponent)
{
global $schemas;
list($sc1, $sc2, $sc3) = explode(":", $testcomponent);
if (!empty($schemas["$sc1::$sc3"])) {
return 1;
} else {
return 0;
}
}
?>