mirror of
https://gitlab.com/davical-project/davical.git
synced 2026-08-22 17:16:06 +00:00
Refactor fetching of Principal records from database.
This is a significant refactoring, replacing the old getUserBy*() functions with a new Principal class, and replacing the old CalDAVPrincipal class with a new DAVPrincipal class which extends the Principal class. At this point all regression tests pass (again) but there could well be issues for people who use alternative authenticators such as LDAP, although I have endeavoured to resolve those potential issues. Signed-off-by: Andrew McMillan <andrew@morphoss.com>
This commit is contained in:
parent
b35d71e69c
commit
20ee255898
@ -37,7 +37,8 @@ $c->collections_always_exist = false;
|
||||
$c->allow_get_email_visibility = false;
|
||||
$c->permission_scan_depth = 2;
|
||||
$c->expand_pdo_parameters = true;
|
||||
$c->home_calendar_name = 'home';
|
||||
$c->home_calendar_name = 'calendar';
|
||||
$c->home_addressbook_name = 'addresses';
|
||||
$c->enable_row_linking = true;
|
||||
$c->enable_scheduling = false;
|
||||
$c->http_auth_mode = 'Basic';
|
||||
@ -202,92 +203,7 @@ if ( $qry->Exec('always',__LINE__,__FILE__) && $row = $qry->Fetch() ) {
|
||||
if ( isset($_SERVER['HTTP_X_DAVICAL_TESTCASE']) ) $qry->QDo('SET TIMEZONE TO \'Pacific/Auckland\'');
|
||||
}
|
||||
|
||||
|
||||
$_known_users_name = array();
|
||||
$_known_users_id = array();
|
||||
$_known_users_pid = array();
|
||||
$_known_users_email = array();
|
||||
|
||||
function _davical_get_principal_query_cached( $where, $parameter ) {
|
||||
global $c, $session, $_known_users_name, $_known_users_id, $_known_users_pid;
|
||||
|
||||
$sql = 'SELECT *, to_char(updated at time zone \'GMT\',\'Dy, DD Mon IYYY HH24:MI:SS "GMT"\') AS modified, principal.*, ';
|
||||
if ( isset($session->principal_id) ) {
|
||||
$sql .= 'pprivs(:session_principal::int8,principal.principal_id,:scan_depth::int) AS privileges ';
|
||||
$params = array( ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth );
|
||||
}
|
||||
else {
|
||||
$sql .= '0::BIT(24) AS privileges ';
|
||||
$params = array( );
|
||||
}
|
||||
$sql .= 'FROM usr LEFT JOIN principal USING(user_no) WHERE '. $where;
|
||||
$params[':param'] = $parameter;
|
||||
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows() == 1 && $row = $qry->Fetch() ) {
|
||||
if ( isset($session->principal_id) ) {
|
||||
$_known_users_name[$row->username] = $row;
|
||||
$_known_users_id[$row->user_no] = $row;
|
||||
$_known_users_pid[$row->principal_id] = $row;
|
||||
$_known_users_email[$row->email] = $row;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a user record identified by a username, caching it for any subsequent lookup
|
||||
* @param string $username The username of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByName( $username, $use_cache = true ) {
|
||||
global $_known_users_name;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username];
|
||||
return _davical_get_principal_query_cached( 'lower(username) = lower(:param)', $username );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by e-mail address, caching it for any subsequent lookup
|
||||
* @param string $email The email address of the user record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByEMail( $email, $use_cache = true ) {
|
||||
global $_known_users_name;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_email[$email] ) ) return $_known_users_email[$email];
|
||||
return _davical_get_principal_query_cached( 'lower(email) = lower(:param)', $email );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by a user_no, caching it for any subsequent lookup
|
||||
* @param int $user_no The ID of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByID( $user_no, $use_cache = true ) {
|
||||
global $c, $session, $_known_users_id;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no];
|
||||
return _davical_get_principal_query_cached( 'user_no = :param', $user_no );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by a user_no, caching it for any subsequent lookup
|
||||
* @param int $user_no The ID of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getPrincipalByID( $principal_id, $use_cache = true ) {
|
||||
global $c, $session, $_known_users_pid;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_pid[$principal_id] ) ) return $_known_users_pid[$principal_id];
|
||||
return _davical_get_principal_query_cached( 'principal_id = :param', $principal_id );
|
||||
}
|
||||
|
||||
require_once('Principal.php');
|
||||
|
||||
/**
|
||||
* Return the HTTP status code description for a given code. Hopefully
|
||||
|
||||
@ -45,12 +45,12 @@ require_once("CalDAVRequest.php");
|
||||
$request = new CalDAVRequest(array("allow_by_email" => 1));
|
||||
$path_match = '^'.$request->path;
|
||||
if ( preg_match( '{^/(\S+@[a-z0-9][a-z0-9-]*[.][a-z0-9.-]+)/?$}i', $request->path, $matches ) ) {
|
||||
$u = getUserByEMail($matches[1]);
|
||||
$path_match = '^/'.$u->username.'/';
|
||||
$principal = new Principal('email',$matches[1]);
|
||||
$path_match = '^'.$principal->dav_name();
|
||||
}
|
||||
|
||||
if ( isset($fb_format) && $fb_format != 'text/calendar' ) {
|
||||
$request->DoResponse( 406, 'This server only supports the text/calendar format for freebusy URLs' );
|
||||
$request->DoResponse( 406, translate('This server only supports the text/calendar format for freebusy URLs') );
|
||||
}
|
||||
|
||||
if ( ! $request->HavePrivilegeTo('read-free-busy') ) $request->DoResponse( 404 );
|
||||
|
||||
@ -132,14 +132,15 @@ class Tools {
|
||||
if ( $ics != '' ) {
|
||||
include_once('check_UTF8.php');
|
||||
if ( check_string($ics) ) {
|
||||
$path = "/".substr($file,0,-4).$path_ics;
|
||||
$username = substr($file,0,-4);
|
||||
$path = "/".$username.$path_ics;
|
||||
dbg_error_log( "importFromDirectory", "importing to $path");
|
||||
$c->readonly_webdav_collections = false; // Override this setting so we can create collections/events on import.
|
||||
require_once("caldav-PUT-functions.php");
|
||||
if ( $user = getUserByName(substr($file,0,-4),'importFromDirectory',__LINE__,__FILE__)) {
|
||||
$user_no = $user->user_no;
|
||||
if ( $principal = new Principal('username',$username) ) {
|
||||
$user_no = $principal->user_no();
|
||||
}
|
||||
if(controlRequestContainer(substr($file,0,-4),$user_no, $path,false) === -1)
|
||||
if ( controlRequestContainer($username, $user_no, $path, false) === -1)
|
||||
continue;
|
||||
import_collection($ics,$user_no,$path,1);
|
||||
$c->messages[] = sprintf(translate('all events of user %s were deleted and replaced by those from file %s'),substr($file,0,-4),$dir.'/'.$file);
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
require_once("AwlCache.php");
|
||||
require_once("XMLDocument.php");
|
||||
require_once("CalDAVPrincipal.php");
|
||||
require_once("DAVPrincipal.php");
|
||||
include("DAVTicket.php");
|
||||
|
||||
define('DEPTH_INFINITY', 9999);
|
||||
@ -48,7 +48,7 @@ class CalDAVRequest
|
||||
|
||||
/**
|
||||
* The 'principal' (user/resource/...) which this request seeks to access
|
||||
* @var CalDAVPrincipal
|
||||
* @var DAVPrincipal
|
||||
*/
|
||||
var $principal;
|
||||
|
||||
@ -137,7 +137,6 @@ class CalDAVRequest
|
||||
|
||||
$this->options = $options;
|
||||
if ( !isset($this->options['allow_by_email']) ) $this->options['allow_by_email'] = false;
|
||||
$this->principal = (object) array( 'username' => $session->username, 'user_no' => $session->user_no );
|
||||
|
||||
$this->raw_post = file_get_contents ( 'php://input');
|
||||
|
||||
@ -281,14 +280,7 @@ class CalDAVRequest
|
||||
}
|
||||
if ( strstr($this->path,'//') ) $this->path = preg_replace( '#//+#', '/', $this->path);
|
||||
|
||||
$this->user_no = $session->user_no;
|
||||
$this->username = $session->username;
|
||||
if ( $session->user_no > 0 ) {
|
||||
$this->current_user_principal_url = new XMLElement('href', ConstructURL('/'.$session->username.'/') );
|
||||
}
|
||||
else {
|
||||
$this->current_user_principal_url = new XMLElement('unauthenticated' );
|
||||
}
|
||||
$this->principal = new Principal('path',$this->path);
|
||||
|
||||
/**
|
||||
* RFC2518, 5.2: URL pointing to a collection SHOULD end in '/', and if it does not then
|
||||
@ -402,11 +394,11 @@ EOSQL;
|
||||
/**
|
||||
* Extract the user whom we are accessing
|
||||
*/
|
||||
$this->principal = new CalDAVPrincipal( array( "path" => $this->path, "options" => $this->options ) );
|
||||
if ( isset($this->principal->user_no) ) $this->user_no = $this->principal->user_no;
|
||||
if ( isset($this->principal->username)) $this->username = $this->principal->username;
|
||||
if ( isset($this->principal->by_email) && $this->principal->by_email) $this->by_email = true;
|
||||
if ( isset($this->principal->principal_id)) $this->principal_id = $this->principal->principal_id;
|
||||
$this->principal = new DAVPrincipal( array( "path" => $this->path, "options" => $this->options ) );
|
||||
$this->user_no = $this->principal->user_no();
|
||||
$this->username = $this->principal->username();
|
||||
$this->by_email = $this->principal->byEmail();
|
||||
$this->principal_id = $this->principal->principal_id();
|
||||
|
||||
if ( $this->collection_type == 'principal' || $this->collection_type == 'email' || $this->collection_type == 'proxy' ) {
|
||||
$this->collection = $this->principal->AsCollection();
|
||||
@ -562,45 +554,6 @@ EOSQL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work out the user whose calendar we are accessing, based on elements of the path.
|
||||
*/
|
||||
function UserFromPath() {
|
||||
global $session;
|
||||
|
||||
$this->user_no = $session->user_no;
|
||||
$this->username = $session->username;
|
||||
$this->principal_id = $session->principal_id;
|
||||
|
||||
@dbg_error_log( "WARN", "Call to deprecated CalDAVRequest::UserFromPath()" );
|
||||
|
||||
if ( $this->path == '/' || $this->path == '' ) {
|
||||
dbg_error_log( "caldav", "No useful path split possible" );
|
||||
return false;
|
||||
}
|
||||
|
||||
$path_split = explode('/', $this->path );
|
||||
$this->username = $path_split[1];
|
||||
if ( $this->username == 'principals' ) $this->username = $path_split[3];
|
||||
@dbg_error_log( "caldav", "Path split into at least /// %s /// %s /// %s", $path_split[1], $path_split[2], $path_split[3] );
|
||||
if ( isset($this->options['allow_by_email']) && preg_match( '#/(\S+@\S+[.]\S+)/?$#', $this->path, $matches) ) {
|
||||
$this->by_email = $matches[1];
|
||||
$qry = new AwlQuery("SELECT user_no, principal_id, username FROM usr JOIN principal USING (user_no) WHERE email = :email",
|
||||
array(':email' => $this->by_email ) );
|
||||
if ( $qry->Exec('caldav',__LINE__,__FILE__) && $user = $qry->Fetch() ) {
|
||||
$this->user_no = $user->user_no;
|
||||
$this->username = $user->username;
|
||||
$this->principal_id = $user->principal_id;
|
||||
}
|
||||
}
|
||||
elseif( $user = getUserByName($this->username,'caldav',__LINE__,__FILE__)) {
|
||||
$this->principal = $user;
|
||||
$this->user_no = $user->user_no;
|
||||
$this->principal_id = $user->principal_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Permissions are controlled as follows:
|
||||
* 1. if the path is '/', the request has read privileges
|
||||
@ -620,9 +573,9 @@ EOSQL;
|
||||
$this->privileges = privilege_to_bits( array('read','read-free-busy','read-acl'));
|
||||
dbg_error_log( "caldav", "Full read permissions for user accessing /" );
|
||||
}
|
||||
else if ( $session->AllowedTo("Admin") || $session->user_no == $this->user_no ) {
|
||||
else if ( $session->AllowedTo("Admin") || $session->principal->user_no() == $this->user_no ) {
|
||||
$this->privileges = privilege_to_bits('all');
|
||||
dbg_error_log( "caldav", "Full permissions for %s", ( $session->user_no == $this->user_no ? "user accessing their own hierarchy" : "a systems administrator") );
|
||||
dbg_error_log( "caldav", "Full permissions for %s", ( $session->principal->user_no() == $this->user_no ? "user accessing their own hierarchy" : "a systems administrator") );
|
||||
}
|
||||
else {
|
||||
$this->privileges = 0;
|
||||
@ -638,7 +591,7 @@ EOSQL;
|
||||
/**
|
||||
* In other cases we need to query the database for permissions
|
||||
*/
|
||||
$params = array( ':session_principal_id' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth );
|
||||
$params = array( ':session_principal_id' => $session->principal->principal_id(), ':scan_depth' => $c->permission_scan_depth );
|
||||
if ( isset($this->by_email) && $this->by_email ) {
|
||||
$sql ='SELECT pprivs( :session_principal_id::int8, :request_principal_id::int8, :scan_depth::int ) AS perm';
|
||||
$params[':request_principal_id'] = $this->principal_id;
|
||||
@ -1006,7 +959,7 @@ EOSQL;
|
||||
*/
|
||||
function AllowedTo( $activity ) {
|
||||
global $session;
|
||||
dbg_error_log('caldav', 'Checking whether "%s" is allowed to "%s"', $session->username, $activity);
|
||||
dbg_error_log('caldav', 'Checking whether "%s" is allowed to "%s"', $session->principal->username(), $activity);
|
||||
if ( isset($this->permissions['all']) ) return true;
|
||||
switch( $activity ) {
|
||||
case 'all':
|
||||
@ -1209,7 +1162,7 @@ EOSQL;
|
||||
$message = substr( preg_replace("#\s+#m", ' ', $message ), 0, 100) . (strlen($message) > 100 ? "..." : "");
|
||||
}
|
||||
|
||||
dbg_error_log("caldav", "Status: %d, Message: %s, User: %d, Path: %s", $status, $message, $session->user_no, $this->path);
|
||||
dbg_error_log("caldav", "Status: %d, Message: %s, User: %d, Path: %s", $status, $message, $session->principal->user_no(), $this->path);
|
||||
}
|
||||
if ( isset($c->dbg['statistics']) && $c->dbg['statistics'] ) {
|
||||
$script_time = microtime(true) - $c->script_start_time;
|
||||
|
||||
@ -9,30 +9,14 @@
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var $_CalDAVPrincipalCache
|
||||
* A global variable holding a cache of any DAV Principals which are
|
||||
* read from the DB.
|
||||
*/
|
||||
$_CalDAVPrincipalCache = (object) array( 'p' => array(), 'u' => array() );
|
||||
|
||||
|
||||
/**
|
||||
* A class for things to do with a DAV Principal
|
||||
*
|
||||
* @package davical
|
||||
*/
|
||||
class CalDAVPrincipal
|
||||
class DAVPrincipal extends Principal
|
||||
{
|
||||
/**
|
||||
* @var The home URL of the principal
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* @var Identifies whether this principal exists in the DB yet
|
||||
*/
|
||||
private $exists;
|
||||
|
||||
/**
|
||||
* @var RFC4791: Identifies the URL(s) of any WebDAV collections that contain
|
||||
@ -51,23 +35,6 @@ class CalDAVPrincipal
|
||||
*/
|
||||
private $calendar_free_busy_set;
|
||||
|
||||
/**
|
||||
* @var draft-desruisseaux-caldav-sched-03: Identify the URL of the scheduling
|
||||
* Inbox collection owned by the associated principal resource.
|
||||
*/
|
||||
var $schedule_inbox_url;
|
||||
|
||||
/**
|
||||
* @var draft-desruisseaux-caldav-sched-03: Identify the URL of the scheduling
|
||||
* Outbox collection owned by the associated principal resource.
|
||||
*/
|
||||
var $schedule_outbox_url;
|
||||
|
||||
/**
|
||||
* @var Whether or not we are using an e-mail address based URL.
|
||||
*/
|
||||
var $by_email;
|
||||
|
||||
/**
|
||||
* @var RFC3744: The principals that are direct members of this group.
|
||||
*/
|
||||
@ -76,47 +43,43 @@ class CalDAVPrincipal
|
||||
/**
|
||||
* @var RFC3744: The principals that are direct members of this group.
|
||||
*/
|
||||
protected $group_member_set;
|
||||
private $group_member_set;
|
||||
|
||||
/**
|
||||
* @var RFC3744: The groups in which the principal is directly a member.
|
||||
*/
|
||||
protected $group_membership;
|
||||
private $group_membership;
|
||||
|
||||
/**
|
||||
* @var caldav-cu-proxy-02: The principals which this one has read permissions on.
|
||||
*/
|
||||
protected $read_proxy_for;
|
||||
private $read_proxy_for;
|
||||
|
||||
/**
|
||||
* @var caldav-cu-proxy-02: The principals which this one has read-write prmissions for.
|
||||
*/
|
||||
protected $write_proxy_for;
|
||||
private $write_proxy_for;
|
||||
|
||||
/**
|
||||
* @var caldav-cu-proxy-02: The principals which have read permissions on this one.
|
||||
*/
|
||||
protected $read_proxy_group;
|
||||
private $read_proxy_group;
|
||||
|
||||
/**
|
||||
* @var caldav-cu-proxy-02: The principals which have write permissions on this one.
|
||||
*/
|
||||
protected $write_proxy_group;
|
||||
private $write_proxy_group;
|
||||
|
||||
/**
|
||||
* @var CardDAV: The URL to an addressbook entry for this principal
|
||||
*/
|
||||
protected $principal_address;
|
||||
private $principal_address;
|
||||
|
||||
/**
|
||||
* @var The username for this principal
|
||||
* A unique tag which will change if this principal changes
|
||||
* @var string
|
||||
*/
|
||||
protected $username;
|
||||
|
||||
/**
|
||||
* @var The dav_name for this principal - a partial path
|
||||
*/
|
||||
protected $dav_name;
|
||||
private $unique_tag;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -132,60 +95,44 @@ class CalDAVPrincipal
|
||||
global $session, $c;
|
||||
|
||||
$this->exists = null;
|
||||
$this->url = null;
|
||||
|
||||
if ( $parameters == null ) return false;
|
||||
$this->by_email = false;
|
||||
if ( $parameters == null ) return;
|
||||
|
||||
if ( is_object($parameters) ) {
|
||||
dbg_error_log( 'principal', 'Principal: record for %s', $parameters->username );
|
||||
$usr = $parameters;
|
||||
parent::__construct('username',$parameters->username);
|
||||
}
|
||||
else if ( is_int($parameters) ) {
|
||||
dbg_error_log( 'principal', 'Principal: %d', $parameters );
|
||||
$usr = getUserByID($parameters);
|
||||
$this->user_no = $parameters['user_no'];
|
||||
parent::__construct('principal_id',$parameters);
|
||||
}
|
||||
else if ( is_array($parameters) ) {
|
||||
if ( ! isset($parameters['options']['allow_by_email']) ) $parameters['options']['allow_by_email'] = false;
|
||||
if ( isset($parameters['username']) ) {
|
||||
$usr = getUserByName($parameters['username']);
|
||||
$this->username = $parameters['username'];
|
||||
parent::__construct('username',$parameters['username']);
|
||||
}
|
||||
else if ( isset($parameters['user_no']) ) {
|
||||
$usr = getUserByID($parameters['user_no']);
|
||||
$this->user_no = $parameters['user_no'];
|
||||
parent::__construct('user_no',$parameters['user_no']);
|
||||
}
|
||||
else if ( isset($parameters['email']) && $parameters['options']['allow_by_email'] ) {
|
||||
if ( $username = $this->UsernameFromEMail($parameters['email']) ) {
|
||||
$usr = getUserByName($username);
|
||||
$this->username = $username;
|
||||
}
|
||||
else if ( isset($parameters['principal_id']) ) {
|
||||
parent::__construct('principal_id',$parameters['principal_id']);
|
||||
}
|
||||
else if ( isset($parameters['email']) ) {
|
||||
parent::__construct('email',$parameters['email']);
|
||||
}
|
||||
else if ( isset($parameters['path']) ) {
|
||||
dbg_error_log( 'principal', 'Finding Principal from path: "%s", options.allow_by_email: "%s"', $parameters['path'], $parameters['options']['allow_by_email'] );
|
||||
if ( $username = $this->UsernameFromPath($parameters['path'], $parameters['options']) ) {
|
||||
$usr = getUserByName($username);
|
||||
$this->username = $username;
|
||||
}
|
||||
parent::__construct('path',$parameters['path']);
|
||||
}
|
||||
else if ( isset($parameters['principal-property-search']) ) {
|
||||
$usr = $this->PropertySearch($parameters['principal-property-search']);
|
||||
$username = $this->PropertySearch($parameters['principal-property-search']);
|
||||
parent::__construct('username',$username);
|
||||
}
|
||||
}
|
||||
if ( !isset($usr) || !is_object($usr) ) {
|
||||
$this->exists = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->exists = true;
|
||||
$this->InitialiseRecord($usr);
|
||||
if ( ! $this->exists ) return;
|
||||
|
||||
$this->InitialiseRecord();
|
||||
|
||||
if ( is_array($parameters) && !isset($parameters['username']) && !isset($parameters['user_no'])
|
||||
&& isset($parameters['path']) && preg_match('{^/(~|principals/)}', $parameters['path']) ) {
|
||||
// Force it to match
|
||||
$this->url = $parameters['path'];
|
||||
$this->dav_name = $parameters['path'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -193,33 +140,20 @@ class CalDAVPrincipal
|
||||
* Initialise the Principal object from a $usr record from the DB.
|
||||
* @param object $usr The usr record from the DB.
|
||||
*/
|
||||
function InitialiseRecord($usr) {
|
||||
function InitialiseRecord() {
|
||||
global $c;
|
||||
foreach( $usr AS $k => $v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
if ( !isset($this->modified) ) $this->modified = $this->updated;
|
||||
if ( !isset($this->created) ) $this->created = $this->joined;
|
||||
|
||||
$this->dav_etag = md5($this->username . $this->updated);
|
||||
$this->unique_tag = '"'.md5($this->username . $this->modified).'"';
|
||||
$this->_is_group = (isset($this->type_id) && $this->type_id == 3);
|
||||
|
||||
$this->_is_group = (isset($usr->type_id) && $usr->type_id == 3);
|
||||
|
||||
$this->principal_url = ConstructURL( '/'.$this->username.'/', true );
|
||||
$this->url = $this->principal_url;
|
||||
|
||||
$this->principal_address = $this->principal_url . 'principal.vcf';
|
||||
$this->principal_address = $this->url . 'principal.vcf';
|
||||
|
||||
$this->user_address_set = array(
|
||||
'mailto:'.$this->email,
|
||||
ConstructURL( '/'.$this->username.'/', true ),
|
||||
$this->url,
|
||||
// ConstructURL( '/~'.$this->username.'/', true ),
|
||||
// ConstructURL( '/__uuids__/'.$this->username.'/', true ),
|
||||
);
|
||||
$this->schedule_inbox_url = sprintf( '%s.in/', $this->url);
|
||||
$this->schedule_outbox_url = sprintf( '%s.out/', $this->url);
|
||||
$this->dropbox_url = sprintf( '%s.drop/', $this->url);
|
||||
$this->notifications_url = sprintf( '%s.notify/', $this->url);
|
||||
|
||||
if ( isset ( $c->notifications_server ) ) {
|
||||
$this->xmpp_uri = 'xmpp:pubsub.'.$c->notifications_server['host'].'?pubsub;node=/davical-'.$this->principal_id;
|
||||
@ -229,7 +163,7 @@ class CalDAVPrincipal
|
||||
if ( $this->_is_group ) {
|
||||
$this->group_member_set = array();
|
||||
$qry = new AwlQuery('SELECT usr.username FROM group_member JOIN principal ON (principal_id=member_id) JOIN usr USING(user_no) WHERE group_id = :group_id ORDER BY principal.principal_id ', array( ':group_id' => $this->principal_id) );
|
||||
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows() > 0 ) {
|
||||
if ( $qry->Exec('DAVPrincipal') && $qry->rows() > 0 ) {
|
||||
while( $member = $qry->Fetch() ) {
|
||||
$this->group_member_set[] = ConstructURL( '/'. $member->username . '/', true);
|
||||
}
|
||||
@ -238,7 +172,7 @@ class CalDAVPrincipal
|
||||
|
||||
$this->group_membership = array();
|
||||
$qry = new AwlQuery('SELECT usr.username FROM group_member JOIN principal ON (principal_id=group_id) JOIN usr USING(user_no) WHERE member_id = :member_id UNION SELECT usr.username FROM group_member LEFT JOIN grants ON (to_principal=group_id) JOIN principal ON (principal_id=by_principal) JOIN usr USING(user_no) WHERE member_id = :member_id and by_principal != member_id ORDER BY 1', array( ':member_id' => $this->principal_id ) );
|
||||
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows() > 0 ) {
|
||||
if ( $qry->Exec('DAVPrincipal') && $qry->rows() > 0 ) {
|
||||
while( $group = $qry->Fetch() ) {
|
||||
$this->group_membership[] = ConstructURL( '/'. $group->username . '/', true);
|
||||
}
|
||||
@ -249,7 +183,7 @@ class CalDAVPrincipal
|
||||
$this->write_proxy_for = null;
|
||||
$this->read_proxy_for = null;
|
||||
|
||||
dbg_error_log( 'principal', ' User: %s (%d) URL: %s, Home: %s, By Email: %d', $this->username, $this->user_no, $this->url, $this->principal_url, $this->by_email );
|
||||
dbg_error_log( 'principal', ' User: %s (%d) URL: %s, By Email: %d', $this->username, $this->user_no, $this->url, $this->by_email );
|
||||
}
|
||||
|
||||
|
||||
@ -272,7 +206,7 @@ class CalDAVPrincipal
|
||||
$sql = 'SELECT principal_id, username, pprivs(:request_principal::int8,principal_id,:scan_depth::int) FROM principal JOIN usr USING(user_no) WHERE principal_id IN (SELECT * from p_has_proxy_access_to(:request_principal,:scan_depth))';
|
||||
$params = array( ':request_principal' => $this->principal_id, ':scan_depth' => $c->permission_scan_depth );
|
||||
$qry = new AwlQuery($sql, $params);
|
||||
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows() > 0 ) {
|
||||
if ( $qry->Exec('DAVPrincipal') && $qry->rows() > 0 ) {
|
||||
while( $relationship = $qry->Fetch() ) {
|
||||
if ( (bindec($relationship->pprivs) & $write_priv) != 0 ) {
|
||||
$this->write_proxy_for[] = ConstructURL( '/'. $relationship->username . '/', true);
|
||||
@ -287,7 +221,7 @@ class CalDAVPrincipal
|
||||
|
||||
$sql = 'SELECT principal_id, username, pprivs(:request_principal::int8,principal_id,:scan_depth::int) FROM principal JOIN usr USING(user_no) WHERE principal_id IN (SELECT * from grants_proxy_access_from_p(:request_principal,:scan_depth))';
|
||||
$qry = new AwlQuery($sql, $params ); // reuse $params assigned for earlier query
|
||||
if ( $qry->Exec('CalDAVPrincipal') && $qry->rows() > 0 ) {
|
||||
if ( $qry->Exec('DAVPrincipal') && $qry->rows() > 0 ) {
|
||||
while( $relationship = $qry->Fetch() ) {
|
||||
if ( bindec($relationship->pprivs) & $write_priv ) {
|
||||
$this->write_proxy_group[] = ConstructURL( '/'. $relationship->username . '/', true);
|
||||
@ -352,58 +286,6 @@ class CalDAVPrincipal
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work out the username, based on elements of the path.
|
||||
* @param string $path The path to be used.
|
||||
* @param array $options The request options, controlling whether e-mail paths are allowed.
|
||||
*/
|
||||
function UsernameFromPath( $path, $options = null ) {
|
||||
global $session, $c;
|
||||
|
||||
if ( $path == '/' || $path == '' ) {
|
||||
dbg_error_log( 'principal', 'No useful path split possible' );
|
||||
return $session->username;
|
||||
}
|
||||
|
||||
$path_split = explode('/', $path );
|
||||
@dbg_error_log( 'principal', 'Path split into at least /// %s /// %s /// %s', $path_split[1], $path_split[2], $path_split[3] );
|
||||
|
||||
$username = $path_split[1];
|
||||
if ( $path_split[1] == 'principals' && isset($path_split[3]) ) $username = $path_split[3];
|
||||
if ( substr($username,0,1) == '~' ) $username = substr($username,1);
|
||||
|
||||
if ( isset($options['allow_by_email']) && $options['allow_by_email'] && preg_match( '#^(\S+@\S+[.]\S+)$#', $username) ) {
|
||||
$username = $this->UsernameFromEMail($username);
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work out the username, based on the given e-mail
|
||||
* @param string $email The email address to be used.
|
||||
*/
|
||||
function UsernameFromEMail( $email ) {
|
||||
@dbg_error_log( 'principal', 'Retrieving username from e-mail address "%s" ', $email );
|
||||
$qry = new AwlQuery('SELECT username FROM usr WHERE email = :email', array( ':email' => $email ) );
|
||||
if ( $qry->Exec('principal') && $user = $qry->Fetch() ) {
|
||||
$username = $user->username;
|
||||
$this->by_email = true;
|
||||
return $username;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does this principal exist?
|
||||
* @return boolean Whether or not it exists.
|
||||
*/
|
||||
function Exists() {
|
||||
return $this->exists;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is this a group principal?
|
||||
* @return boolean Whether this is a group principal
|
||||
@ -413,28 +295,6 @@ class CalDAVPrincipal
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the username
|
||||
* @return string The username
|
||||
*/
|
||||
function username() {
|
||||
return (isset($this->username)?$this->username:'username not set');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the partial path representing this principal
|
||||
* @return string The dav_name
|
||||
*/
|
||||
function dav_name() {
|
||||
if ( !isset($this->dav_name) ) {
|
||||
if ( !isset($this->username) ) $this->dav_name = '';
|
||||
else $this->dav_name = '/'.$this->username.'/';
|
||||
}
|
||||
return $this->dav_name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an arbitrary property
|
||||
* @return string The name of the arbitrary property
|
||||
@ -457,13 +317,15 @@ class CalDAVPrincipal
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the URL for this principal
|
||||
* @return string The principal-URL, or null if they don't exist
|
||||
* Returns the unique_tag (ETag or getctag) for this resource
|
||||
*/
|
||||
function url() {
|
||||
return ($this->exists ? $this->url : null );
|
||||
public function unique_tag() {
|
||||
if ( isset($this->unique_tag) ) return $this->unique_tag;
|
||||
|
||||
if ( $this->exists !== true ) $this->unique_tag = '"-1"';
|
||||
|
||||
return $this->unique_tag;
|
||||
}
|
||||
|
||||
|
||||
@ -473,17 +335,18 @@ class CalDAVPrincipal
|
||||
function calendar_home_set() {
|
||||
if ( !isset($this->calendar_home_set) ) {
|
||||
$this->calendar_home_set = array();
|
||||
/* $qry = new AwlQuery('SELECT DISTINCT parent_container FROM collection WHERE is_calendar AND user_no = :user_no', array( ':user_no' => $this->user_no));
|
||||
$qry = new AwlQuery('SELECT DISTINCT parent_container FROM collection WHERE is_calendar AND dav_name ~ :dav_name_start',
|
||||
array( ':dav_name_start' => '^'.$this->dav_name));
|
||||
if ( $qry->Exec('principal',__LINE__,__FILE__) ) {
|
||||
if ( $qry->rows() > 0 ) {
|
||||
while( $calendar = $qry->Fetch() ) {
|
||||
$this->calendar_home_set[] = ConstructURL($calendar->parent_container, true);
|
||||
}
|
||||
}
|
||||
else {*/
|
||||
$this->calendar_home_set[] = $this->principal_url;
|
||||
// }
|
||||
// }
|
||||
else {
|
||||
$this->calendar_home_set[] = $this->url;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->calendar_home_set;
|
||||
}
|
||||
@ -494,18 +357,19 @@ class CalDAVPrincipal
|
||||
*/
|
||||
function addressbook_home_set() {
|
||||
if ( !isset($this->addressbook_home_set) ) {
|
||||
$this->addressbook_home_set = array();
|
||||
/* $qry = new AwlQuery('SELECT DISTINCT parent_container FROM collection WHERE is_addressbook AND user_no = :user_no', array( ':user_no' => $this->user_no));
|
||||
$this->addressbook_home_set = array();
|
||||
$qry = new AwlQuery('SELECT DISTINCT parent_container FROM collection WHERE is_addressbook AND dav_name ~ :dav_name_start',
|
||||
array( ':dav_name_start' => '^'.$this->dav_name));
|
||||
if ( $qry->Exec('principal',__LINE__,__FILE__) ) {
|
||||
if ( $qry->rows() > 0 ) {
|
||||
while( $addressbook = $qry->Fetch() ) {
|
||||
$this->addressbook_home_set[] = ConstructURL($addressbook->parent_container, true);
|
||||
}
|
||||
}
|
||||
else {*/
|
||||
$this->addressbook_home_set[] = $this->principal_url;
|
||||
// }
|
||||
// }
|
||||
else {
|
||||
$this->addressbook_home_set[] = $this->url;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->addressbook_home_set;
|
||||
}
|
||||
@ -518,11 +382,11 @@ class CalDAVPrincipal
|
||||
if ( !isset($this->calendar_free_busy_set) ) {
|
||||
/**
|
||||
* calendar-free-busy-set has been dropped from draft 5 of the scheduling extensions for CalDAV
|
||||
* in favour of
|
||||
* in favour of ???
|
||||
*/
|
||||
$this->calendar_free_busy_set = array();
|
||||
$qry = new AwlQuery('SELECT dav_name FROM collection WHERE user_no = :user_no AND is_calendar AND (schedule_transp = \'opaque\' OR schedule_transp IS NULL) ORDER BY user_no, collection_id',
|
||||
array( ':user_no' => $this->user_no) );
|
||||
$qry = new AwlQuery('SELECT dav_name FROM collection WHERE is_calendar AND (schedule_transp = \'opaque\' OR schedule_transp IS NULL) AND dav_name ~ :dav_name_start ORDER BY user_no, collection_id',
|
||||
array( ':dav_name_start' => '^'.$this->dav_name));
|
||||
if ( $qry->Exec('principal',__LINE__,__FILE__) ) {
|
||||
while( $calendar = $qry->Fetch() ) {
|
||||
$this->calendar_free_busy_set[] = ConstructURL($calendar->dav_name, true);
|
||||
@ -532,6 +396,7 @@ class CalDAVPrincipal
|
||||
return $this->calendar_free_busy_set;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the privileges bits for the current session user to this resource
|
||||
*/
|
||||
@ -539,8 +404,10 @@ class CalDAVPrincipal
|
||||
global $session;
|
||||
if ( !isset($this->privileges) ) $this->privileges = 0;
|
||||
if ( is_string($this->privileges) ) $this->privileges = bindec( $this->privileges );
|
||||
if ( $this->_is_group && in_array(ConstructURL('/'.$session->username.'/'), $this->GroupMemberSet()) ) {
|
||||
$this->privileges |= privilege_to_bits( array('DAV::read', 'DAV::read-current-user-privilege-set') );
|
||||
if ( $this->_is_group ) {
|
||||
if ( in_array($session->principal->url(), $this->GroupMemberSet()) ) {
|
||||
$this->privileges |= privilege_to_bits( array('DAV::read', 'DAV::read-current-user-privilege-set') );
|
||||
}
|
||||
}
|
||||
return $this->privileges;
|
||||
}
|
||||
@ -550,26 +417,33 @@ class CalDAVPrincipal
|
||||
* Returns a representation of the principal as a collection
|
||||
*/
|
||||
function AsCollection() {
|
||||
$dav_name = (isset($this->original_request_url) ? DeconstructURL($this->original_request_url) : $this->dav_name());
|
||||
$collection = (object) array(
|
||||
'collection_id' => (isset($this->principal_id) ? $this->principal_id : 0),
|
||||
'collection_id' => ($this->principal_id() ? $this->principal_id() : 0),
|
||||
'is_calendar' => false,
|
||||
'is_addressbook' => false,
|
||||
'is_principal' => true,
|
||||
'type' => 'principal' . (substr($this->dav_name(), 0, 12) == '/principals/'?'_link':''),
|
||||
'user_no' => (isset($this->user_no) ? $this->user_no : 0),
|
||||
'type' => 'principal' . (isset($this->original_request_url) ? '_link' : ''),
|
||||
'user_no' => ($this->user_no() ? $this->user_no() : 0),
|
||||
'username' => $this->username(),
|
||||
'dav_name' => $this->dav_name,
|
||||
'dav_name' => $dav_name,
|
||||
'parent_container' => '/',
|
||||
'email' => (isset($this->email) ? $this->email : ''),
|
||||
'created' => (isset($this->created) ? $this->created : date('Ymd\THis')),
|
||||
'updated' => (isset($this->updated) ? $this->updated : date('Ymd\THis'))
|
||||
'email' => ($this->email()? $this->email() : ''),
|
||||
'created' => $this->created,
|
||||
'updated' => $this->modified,
|
||||
'dav_etag' => substr($this->unique_tag(),1,-1),
|
||||
'resourcetypes' => $this->resourcetypes
|
||||
);
|
||||
$collection->dav_etag = (isset($this->dav_etag) ? $this->dav_etag : md5($collection->username . $collection->updated));
|
||||
$collection->dav_displayname = (isset($this->dav_displayname) ? $this->dav_displayname : (isset($this->fullname) ? $this->fullname : $collection->username));
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
|
||||
function PropertySearch( $parameters ) {
|
||||
throw new Exception("Unimplemented!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns properties which are specific to this principal
|
||||
*/
|
||||
@ -590,7 +464,7 @@ class CalDAVPrincipal
|
||||
break;
|
||||
|
||||
case 'DAV::principal-URL':
|
||||
$prop->NewElement('principal-URL', $reply->href($this->principal_url) );
|
||||
$prop->NewElement('principal-URL', $reply->href($this->url()) );
|
||||
break;
|
||||
|
||||
case 'DAV::getlastmodified':
|
||||
@ -618,15 +492,15 @@ class CalDAVPrincipal
|
||||
break;
|
||||
|
||||
case 'urn:ietf:params:xml:ns:caldav:schedule-inbox-URL':
|
||||
$reply->CalDAVElement($prop, 'schedule-inbox-URL', $reply->href($this->schedule_inbox_url) );
|
||||
$reply->CalDAVElement($prop, 'schedule-inbox-URL', $reply->href($this->url('schedule_inbox')) );
|
||||
break;
|
||||
|
||||
case 'urn:ietf:params:xml:ns:caldav:schedule-outbox-URL':
|
||||
$reply->CalDAVElement($prop, 'schedule-outbox-URL', $reply->href($this->schedule_outbox_url) );
|
||||
$reply->CalDAVElement($prop, 'schedule-outbox-URL', $reply->href($this->url('schedule_outbox')) );
|
||||
break;
|
||||
|
||||
case 'http://calendarserver.org/ns/:dropbox-home-URL':
|
||||
$reply->CalendarserverElement($prop, 'dropbox-home-URL', $reply->href($this->dropbox_url) );
|
||||
$reply->CalendarserverElement($prop, 'dropbox-home-URL', $reply->href($this->url('dropbox')) );
|
||||
break;
|
||||
|
||||
case 'http://calendarserver.org/ns/:xmpp-server':
|
||||
@ -657,7 +531,7 @@ class CalDAVPrincipal
|
||||
|
||||
case 'DAV::owner':
|
||||
// After a careful reading of RFC3744 we see that this must be the principal-URL of the owner
|
||||
$reply->DAVElement( $prop, 'owner', $reply->href( $this->principal_url ) );
|
||||
$reply->DAVElement( $prop, 'owner', $reply->href( $this->url ) );
|
||||
break;
|
||||
|
||||
// Empty tag responses.
|
||||
@ -527,20 +527,19 @@ EOSQL;
|
||||
*/
|
||||
function FetchPrincipal() {
|
||||
if ( isset($this->principal) ) return;
|
||||
$this->principal = new CalDAVPrincipal( array( "path" => $this->bound_from() ) );
|
||||
$this->principal = new DAVPrincipal( array( "path" => $this->bound_from() ) );
|
||||
if ( $this->_is_principal ) {
|
||||
$this->exists = $this->principal->Exists();
|
||||
$this->collection->dav_name = $this->dav_name;
|
||||
$this->collection->dav_name = $this->dav_name();
|
||||
$this->collection->type = 'principal';
|
||||
if ( $this->exists ) {
|
||||
$this->collection = $this->principal->AsCollection();
|
||||
$this->displayname = $this->principal->GetProperty('displayname');
|
||||
$this->unique_tag = '"'.$this->principal->dav_etag.'"';
|
||||
$this->user_no = $this->principal->user_no();
|
||||
$this->resource_id = $this->principal->principal_id();
|
||||
$this->created = $this->principal->created;
|
||||
$this->modified = $this->principal->modified;
|
||||
$this->resourcetypes = '<DAV::collection/><DAV::principal/>';
|
||||
$this->resource_id = $this->principal->principal_id;
|
||||
$this->collection = $this->principal->AsCollection();
|
||||
$this->user_no = $this->principal->user_no;
|
||||
$this->resourcetypes = $this->principal->resourcetypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,20 +617,20 @@ EOQRY;
|
||||
|
||||
if ( $this->dav_name == '/' || $this->dav_name == '' ) {
|
||||
$this->privileges = (1 | 16 | 32); // read + read-acl + read-current-user-privilege-set
|
||||
dbg_error_log( 'DAVResource', 'Read permissions for user accessing /' );
|
||||
dbg_error_log( 'DAVResource', ':FetchPrivileges: Read permissions for user accessing /' );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $session->AllowedTo('Admin') ) {
|
||||
$this->privileges = privilege_to_bits('all');
|
||||
dbg_error_log( 'DAVResource', 'Full permissions for an administrator.' );
|
||||
dbg_error_log( 'DAVResource', ':FetchPrivileges: Full permissions for an administrator.' );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->IsPrincipal() ) {
|
||||
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||
$this->privileges = $this->principal->Privileges();
|
||||
dbg_error_log( 'DAVResource', 'Privileges of "%s" for user accessing principal "%s"', $this->privileges, $this->principal->username() );
|
||||
dbg_error_log( 'DAVResource', ':FetchPrivileges: Privileges of "%s" for user accessing principal "%s"', $this->privileges, $this->principal->username() );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -648,12 +647,12 @@ EOQRY;
|
||||
$this->privileges = $this->collection->path_privs;
|
||||
if ( is_string($this->privileges) ) $this->privileges = bindec( $this->privileges );
|
||||
|
||||
dbg_error_log( 'DAVResource', 'Privileges of "%s" for user "%s" accessing "%s"',
|
||||
dbg_error_log( 'DAVResource', ':FetchPrivileges: Privileges of "%s" for user "%s" accessing "%s"',
|
||||
decbin($this->privileges), $session->username, $this->dav_name() );
|
||||
|
||||
if ( isset($request->ticket) && $request->ticket->MatchesPath($this->bound_from()) ) {
|
||||
$this->privileges |= $request->ticket->privileges();
|
||||
dbg_error_log( 'DAVResource', 'Applying permissions for ticket "%s" now: %s', $request->ticket->id(), decbin($this->privileges) );
|
||||
dbg_error_log( 'DAVResource', ':FetchPrivileges: Applying permissions for ticket "%s" now: %s', $request->ticket->id(), decbin($this->privileges) );
|
||||
}
|
||||
|
||||
if ( isset($this->tickets) ) {
|
||||
@ -661,7 +660,7 @@ EOQRY;
|
||||
foreach( $this->tickets AS $k => $ticket ) {
|
||||
if ( $ticket->MatchesResource($this->resource_id()) || $ticket->MatchesPath($this->bound_from()) ) {
|
||||
$this->privileges |= $ticket->privileges();
|
||||
dbg_error_log( 'DAVResource', 'Applying permissions for ticket "%s" now: %s', $ticket->id(), decbin($this->privileges) );
|
||||
dbg_error_log( 'DAVResource', ':FetchPrivileges: Applying permissions for ticket "%s" now: %s', $ticket->id(), decbin($this->privileges) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1145,7 +1144,10 @@ EOQRY;
|
||||
*/
|
||||
function unique_tag() {
|
||||
if ( isset($this->unique_tag) ) return $this->unique_tag;
|
||||
if ( $this->IsPrincipal() && !isset($this->principal) ) $this->FetchPrincipal();
|
||||
if ( $this->IsPrincipal() && !isset($this->principal) ) {
|
||||
$this->FetchPrincipal();
|
||||
$this->unique_tag = $this->principal->unique_tag();
|
||||
}
|
||||
else if ( !$this->_is_collection && !isset($this->resource) ) $this->FetchResource();
|
||||
|
||||
if ( $this->exists !== true || !isset($this->unique_tag) ) $this->unique_tag = '';
|
||||
@ -1245,7 +1247,8 @@ EOQRY;
|
||||
$acl[] = $this->BuildACE($xmldoc, pow(2,25) - 1, new XMLElement('property', new XMLElement('owner')) );
|
||||
|
||||
$qry = new AwlQuery('SELECT dav_principal.dav_name, grants.* FROM grants JOIN dav_principal ON (to_principal=principal_id) WHERE by_collection = :collection_id OR by_principal = :principal_id ORDER BY by_collection',
|
||||
array( ':collection_id' => $this->collection->collection_id, ':principal_id' => $this->principal->principal_id ) );
|
||||
array( ':collection_id' => $this->collection->collection_id,
|
||||
':principal_id' => $this->principal->principal_id() ) );
|
||||
if ( $qry->Exec('DAVResource') && $qry->rows() > 0 ) {
|
||||
$by_collection = null;
|
||||
while( $grant = $qry->Fetch() ) {
|
||||
@ -1276,7 +1279,12 @@ EOQRY;
|
||||
return $this->collection->collection_id;
|
||||
break;
|
||||
|
||||
case 'resourcetype':
|
||||
case 'principal_id':
|
||||
if ( !isset($this->principal) ) $this->FetchPrincipal();
|
||||
return $this->principal->principal_id();
|
||||
break;
|
||||
|
||||
case 'resourcetype':
|
||||
if ( isset($this->resourcetypes) ) {
|
||||
$this->resourcetypes = preg_replace('{^\s*<(.*)/>\s*$}', '$1', $this->resourcetypes);
|
||||
$type_list = preg_split('{(/>\s*<|\n)}', $this->resourcetypes);
|
||||
@ -1554,7 +1562,7 @@ EOQRY;
|
||||
break;
|
||||
|
||||
case 'DAV::current-user-principal':
|
||||
$prop->NewElement('current-user-principal', $reply->href( $request->principal->principal_url ) );
|
||||
$prop->NewElement('current-user-principal', $reply->href( $request->principal->url() ) );
|
||||
break;
|
||||
|
||||
case 'SOME-DENIED-PROPERTY': /** @todo indicating the style for future expansion */
|
||||
|
||||
@ -128,23 +128,21 @@ class HTTPAuthSession {
|
||||
* Fall through to the normal PHP authentication variables.
|
||||
*/
|
||||
if ( isset($_SERVER['PHP_AUTH_USER']) ) {
|
||||
if ( $u = $this->CheckPassword( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) ) {
|
||||
if ( $p = $this->CheckPassword( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) ) {
|
||||
/**
|
||||
* Maybe some external authentication didn't return false for an inactive
|
||||
* user, so we'll be pedantic here.
|
||||
*/
|
||||
if ( $u->active ) {
|
||||
$this->AssignSessionDetails($u);
|
||||
if ( $p->user_active ) {
|
||||
$this->AssignSessionDetails($p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset($c->allow_unauthenticated) && $c->allow_unauthenticated ) {
|
||||
$this->user_no = -1;
|
||||
$this->username = 'guest';
|
||||
$this->fullname = 'Unauthenticated User';
|
||||
$this->email = 'invalid';
|
||||
$this->AssignSessionDetails('unauthenticated');
|
||||
$this->logged_in = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -247,10 +245,10 @@ class HTTPAuthSession {
|
||||
}
|
||||
}
|
||||
|
||||
if ( $usr = getUserByName($username) ) {
|
||||
dbg_error_log( "BasicAuth", ":CheckPassword: Name:%s, Pass:%s, File:%s, Active:%s", $username, $password, $usr->password, ($usr->active?'Yes':'No') );
|
||||
if ( $usr->active && session_validate_password( $password, $usr->password ) ) {
|
||||
return $usr;
|
||||
if ( $principal = new Principal('username', $username) ) {
|
||||
dbg_error_log( "BasicAuth", ":CheckPassword: Name:%s, Pass:%s, File:%s, Active:%s", $username, $password, $principal->password, ($principal->user_active?'Yes':'No') );
|
||||
if ( $principal->user_active && session_validate_password( $password, $principal->password ) ) {
|
||||
return $principal;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -288,20 +286,26 @@ class HTTPAuthSession {
|
||||
* Internal function used to assign the session details to a user's new session.
|
||||
* @param object $u The user+session object we (probably) read from the database.
|
||||
*/
|
||||
function AssignSessionDetails( $u ) {
|
||||
if ( !isset($u->principal_id) ) {
|
||||
// If they don't have a principal_id set then we should re-read from our local database
|
||||
$qry = new AwlQuery('SELECT * FROM dav_principal WHERE username = :username', array(':username' => $u->username) );
|
||||
if ( $qry->Exec() && $qry->rows() == 1 ) {
|
||||
$u = $qry->Fetch();
|
||||
}
|
||||
function AssignSessionDetails( $principal ) {
|
||||
if ( is_string($principal) ) $principal = new Principal('username',$principal);
|
||||
if ( get_class($principal) != 'Principal' ) {
|
||||
$principal = new Principal('username',$principal->username);
|
||||
}
|
||||
|
||||
// Assign each field in the selected record to the object
|
||||
foreach( $u AS $k => $v ) {
|
||||
foreach( $principal AS $k => $v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
|
||||
if ( !get_class($principal) == 'Principal' ) {
|
||||
throw new Exception('HTTPAuthSession::AssignSessionDetails could not find a Principal object');
|
||||
}
|
||||
$this->username = $principal->username();
|
||||
$this->user_no = $principal->user_no();
|
||||
$this->principal_id = $principal->principal_id();
|
||||
$this->email = $principal->email();
|
||||
$this->dav_name = $principal->dav_name();
|
||||
$this->principal = $principal;
|
||||
|
||||
$this->GetRoles();
|
||||
$this->logged_in = true;
|
||||
if ( function_exists("awl_set_locale") && isset($this->locale) && $this->locale != "" ) {
|
||||
|
||||
465
inc/Principal.php
Normal file
465
inc/Principal.php
Normal file
@ -0,0 +1,465 @@
|
||||
<?php
|
||||
/**
|
||||
* An object representing a 'Principal' read from the database
|
||||
*
|
||||
* @package davical
|
||||
* @subpackage Principal
|
||||
* @author Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Morphoss Ltd <http://www.morhposs.com/>
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
|
||||
require_once('AwlCache.php');
|
||||
|
||||
/**
|
||||
* A class for things to do with a Principal
|
||||
*
|
||||
* @package davical
|
||||
*/
|
||||
class Principal {
|
||||
|
||||
/**
|
||||
* Some control over our DB
|
||||
* @var unknown_type
|
||||
*/
|
||||
private static $db_tablename = 'dav_principal';
|
||||
private static $db_mandatory_fields = array(
|
||||
'username',
|
||||
);
|
||||
public static function updateableFields() {
|
||||
return array(
|
||||
'username', 'email', 'user_active', 'modified', 'password', 'fullname',
|
||||
'email_ok', 'date_format_type', 'locale', 'type_id', 'displayname', 'default_privileges'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* We cache these so if we try and access a row by principal_id/user_no/e_mail that we've
|
||||
* already read we don't read it again.
|
||||
* @var unknown_type
|
||||
*/
|
||||
private static $byUserno = array();
|
||||
private static $byId = array();
|
||||
private static $byEmail = array();
|
||||
|
||||
/**
|
||||
* Columns from the database
|
||||
*/
|
||||
protected $username;
|
||||
protected $user_no;
|
||||
protected $principal_id;
|
||||
protected $email;
|
||||
protected $dav_name;
|
||||
public $user_active;
|
||||
public $created;
|
||||
public $modified;
|
||||
public $password;
|
||||
public $fullname;
|
||||
public $email_ok;
|
||||
public $date_format_type;
|
||||
public $locale;
|
||||
public $type_id;
|
||||
public $displayname;
|
||||
public $default_privileges;
|
||||
public $is_principal;
|
||||
public $is_calendar;
|
||||
public $collection_id;
|
||||
public $is_addressbook;
|
||||
public $resourcetypes;
|
||||
public $privileges;
|
||||
|
||||
/**
|
||||
* Whether this Principal actually exists in the database yet.
|
||||
* @var boolean
|
||||
*/
|
||||
protected $exists;
|
||||
|
||||
/**
|
||||
* @var The home URL of the principal
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* @var The actual requested URL for this principal, when the request was for /principals/... or such
|
||||
*/
|
||||
protected $original_request_url;
|
||||
|
||||
/**
|
||||
* Whether this was retrieved using an e-mail address
|
||||
* @var boolean
|
||||
*/
|
||||
protected $by_email;
|
||||
|
||||
/**
|
||||
* If we're using memcached these is the namespace we'll put stuff in
|
||||
* @var unknown_type
|
||||
*/
|
||||
private $cacheNs;
|
||||
private $cacheKey;
|
||||
|
||||
function __construct( $type, $value, $use_cache=true ) {
|
||||
global $c, $session;
|
||||
|
||||
$this->exists = false;
|
||||
$this->by_email = false;
|
||||
$this->original_request_url = null;
|
||||
switch( $type ) {
|
||||
case 'path':
|
||||
$type = 'username';
|
||||
$value = $this->usernameFromPath($value);
|
||||
break;
|
||||
case 'dav_name':
|
||||
$type = 'username';
|
||||
$value = substr($value, 1, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
$cache = new AwlCache();
|
||||
if ( $use_cache && isset($session->principal_id) ) {
|
||||
switch ( $type ) {
|
||||
case 'user_no':
|
||||
$this->user_no = $value;
|
||||
if ( isset(self::$byUserno[$value]) ) {
|
||||
$type = 'username';
|
||||
$value = self::$byUserno[$value];
|
||||
}
|
||||
break;
|
||||
case 'principal_id':
|
||||
$this->principal_id = $value;
|
||||
if ( isset(self::$byId[$value]) ) {
|
||||
$type = 'username';
|
||||
$value = self::$byId[$value];
|
||||
}
|
||||
break;
|
||||
case 'email':
|
||||
$this->by_email = true;
|
||||
$this->email = $value;
|
||||
if ( isset(self::$byEmail[$value]) ) {
|
||||
$type = 'username';
|
||||
$value = self::$byEmail[$value];
|
||||
}
|
||||
break;
|
||||
case 'username':
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Can only retrieve a Principal by user_no,principal_id,username or email address');
|
||||
}
|
||||
|
||||
if ( $type == 'username' ) {
|
||||
$this->username = $value;
|
||||
$this->dav_name = '/'.$value.'/';
|
||||
$this->url = ConstructURL( $this->dav_name, true );
|
||||
$this->cacheNs = 'principal-/'.$value.'/';
|
||||
$this->cacheKey = 'p-'.$session->principal_id;
|
||||
$row = $cache->get('principal-/'.$value.'/', 'p-'.$session->principal_id );
|
||||
if ( $row !== false ) {
|
||||
self::$byId[$row->principal_id] = $row->username;
|
||||
self::$byUserno[$row->user_no] = $row->username;
|
||||
self::$byEmail[$row->email] = $row->username;
|
||||
$this->assignRowValues($row);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = 'SELECT *, ';
|
||||
if ( isset($session->principal_id) ) {
|
||||
$sql .= 'pprivs(:session_principal::int8,principal_id,:scan_depth::int) AS privileges ';
|
||||
$params = array( ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth );
|
||||
}
|
||||
else {
|
||||
$sql .= '0::BIT(24) AS privileges ';
|
||||
$params = array( );
|
||||
}
|
||||
$sql .= 'FROM dav_principal WHERE ';
|
||||
switch ( $type ) {
|
||||
case 'username':
|
||||
$sql .= 'lower(username)=lower(:param)';
|
||||
break;
|
||||
case 'user_no':
|
||||
$sql .= 'user_no=:param';
|
||||
break;
|
||||
case 'principal_id':
|
||||
$sql .= 'principal_id=:param';
|
||||
break;
|
||||
case 'email':
|
||||
$this->by_email = true;
|
||||
$sql .= 'lower(email)=lower(:param)';
|
||||
break;
|
||||
}
|
||||
$params[':param'] = $value;
|
||||
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec('Principal',__LINE__,__FILE__) && $qry->rows() == 1 && $row = $qry->Fetch() ) {
|
||||
$this->exists = true;
|
||||
if ( isset($session->principal_id) ) {
|
||||
self::$byId[$row->principal_id] = $row->username;
|
||||
self::$byUserno[$row->user_no] = $row->username;
|
||||
self::$byEmail[$row->email] = $row->username;
|
||||
if ( !isset($this->cacheNs) ) {
|
||||
$this->cacheNs = 'principal-'.$row->dav_name;
|
||||
$this->cacheKey = 'p-'.$session->principal_id;
|
||||
}
|
||||
}
|
||||
$this->assignRowValues($row);
|
||||
$this->url = ConstructURL( $this->dav_name, true );
|
||||
$row = $cache->set($this->cacheNs, $this->cacheKey, $row, 864000 );
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ( $type == 'username' && $value == 'unauthenticated' ) {
|
||||
$this->assignGuestValues();
|
||||
}
|
||||
}
|
||||
|
||||
private function assignGuestValues() {
|
||||
$this->user_no = -1;
|
||||
$this->exists = false;
|
||||
$this->username = translate('unauthenticated');
|
||||
$this->fullname = $this->displayname = translate('Unauthenticated User');
|
||||
$this->email = false;
|
||||
$this->is_principal = true;
|
||||
$this->is_calendar = false;
|
||||
$this->principal_id = -1;
|
||||
$this->dav_name = '/';
|
||||
$this->privileges = $this->default_privileges = 0;
|
||||
}
|
||||
|
||||
private function assignRowValues( $db_row ) {
|
||||
foreach( $db_row AS $k => $v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
public function Exists() {
|
||||
return $this->exists;
|
||||
}
|
||||
|
||||
|
||||
public function byEmail() {
|
||||
return $this->by_email;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work out the username, based on elements of the path.
|
||||
* @param string $path The path to be used.
|
||||
* @param array $options The request options, controlling whether e-mail paths are allowed.
|
||||
*/
|
||||
private function usernameFromPath( $path ) {
|
||||
global $session, $c;
|
||||
|
||||
if ( $path == '/' || $path == '' ) {
|
||||
dbg_error_log( 'Principal', 'No useful path split possible' );
|
||||
return $session->username;
|
||||
}
|
||||
|
||||
$path_split = explode('/', $path );
|
||||
@dbg_error_log( 'Principal', 'Path split into at least /// %s /// %s /// %s', $path_split[1], $path_split[2], $path_split[3] );
|
||||
|
||||
$username = $path_split[1];
|
||||
if ( $path_split[1] == 'principals' && isset($path_split[3]) ) {
|
||||
$username = $path_split[3];
|
||||
$this->original_request_url = $path;
|
||||
}
|
||||
if ( substr($username,0,1) == '~' ) {
|
||||
$username = substr($username,1);
|
||||
$this->original_request_url = $path;
|
||||
}
|
||||
|
||||
if ( isset($c->allow_by_email) && $c->allow_by_email && preg_match( '#^(\S+@\S+[.]\S+)$#', $username) ) {
|
||||
// This might seem inefficient, but we cache the result, so the second time will not read from the DB
|
||||
$p = new Principal('email',$username);
|
||||
$username = $p->username;
|
||||
$this->by_email = true;
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the username
|
||||
* @return string The username
|
||||
*/
|
||||
function username() {
|
||||
return (isset($this->username)?$this->username:false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the username - but only if the record does not yet exist!
|
||||
* @return string The username
|
||||
*/
|
||||
function setUsername($new_username) {
|
||||
if ( $this->exists ) return false;
|
||||
$this->username = $new_username;
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the user_no
|
||||
* @return int The user_no
|
||||
*/
|
||||
function user_no() {
|
||||
return (isset($this->user_no)?$this->user_no:false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the principal_id
|
||||
* @return string The principal_id
|
||||
*/
|
||||
function principal_id() {
|
||||
return (isset($this->principal_id)?$this->principal_id:false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the email
|
||||
* @return string The email
|
||||
*/
|
||||
function email() {
|
||||
return (isset($this->email)?$this->email:false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the partial path representing this principal
|
||||
* @return string The dav_name
|
||||
*/
|
||||
function dav_name() {
|
||||
if ( !isset($this->dav_name) ) {
|
||||
if ( !isset($this->username) ) {
|
||||
throw new Exception('Can\'t calculate dav_name for unknown username');
|
||||
}
|
||||
$this->dav_name = '/'.$this->username.'/';
|
||||
}
|
||||
return $this->dav_name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the URL for this principal
|
||||
* @param string $type The type of URL we want (the principal, by default)
|
||||
* @param boolean $internal Whether an internal reference is requested
|
||||
* @return string The principal-URL
|
||||
*/
|
||||
public function url($type = 'principal', $internal=false ) {
|
||||
if ( $internal )
|
||||
$result = $this->dav_name();
|
||||
else {
|
||||
if ( isset($this->original_request_url) && $type == 'principal' )
|
||||
$result = $this->original_request_url;
|
||||
else
|
||||
$result = $this->url;
|
||||
}
|
||||
|
||||
switch( $type ) {
|
||||
case 'schedule_inbox': $result .= '.in/'; break;
|
||||
case 'schedule_outbox': $result .= '.out/'; break;
|
||||
case 'dropbox': $result .= '.drop/'; break;
|
||||
case 'notifications': $result .= '.notify/'; break;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function internal_url($type = 'principal' ) {
|
||||
return $this->url($type,true);
|
||||
}
|
||||
|
||||
|
||||
public function unCache() {
|
||||
if ( !isset($this->cacheNs) ) return;
|
||||
$cache = new AwlCache();
|
||||
$cache->delete($this->cacheNs, null );
|
||||
}
|
||||
|
||||
|
||||
private function Write( $field_values, $inserting=true ) {
|
||||
if ( is_array($field_values) ) $field_values = (object) $field_values;
|
||||
|
||||
if ( !isset($field_values->{'user_active'}) && isset($field_values->{'active'}) )
|
||||
$field_values->{'user_active'} = $field_values->{'active'};
|
||||
if ( !isset($field_values->{'modified'}) && isset($field_values->{'updated'}) )
|
||||
$field_values->{'modified'} = $field_values->{'updated'};
|
||||
|
||||
|
||||
$sql = '';
|
||||
if ( $inserting ) {
|
||||
$insert_fields = array();
|
||||
$param_names = array();
|
||||
}
|
||||
else {
|
||||
$update_list = array();
|
||||
}
|
||||
$sql_params = array();
|
||||
foreach( self::updateableFields() AS $k ) {
|
||||
if ( !isset($field_values->{$k}) && !isset($this->{$k}) ) continue;
|
||||
if ( $inserting ) {
|
||||
$insert_fields[] = $k;
|
||||
$param_names[] = ':'.$k;
|
||||
}
|
||||
else {
|
||||
$update_list[] = $k.'=:'.$k;
|
||||
}
|
||||
$sql_params[':'.$k] = $field_values->{$k};
|
||||
}
|
||||
|
||||
if ( $inserting ) {
|
||||
foreach( $this->db_mandatory_fields AS $k ) {
|
||||
if ( !isset($sql_params[':'.$k]) ) {
|
||||
throw new Exception( get_class($this).'::Create: Mandatory field "'.$k.'" is not set.');
|
||||
}
|
||||
}
|
||||
$sql = 'INSERT INTO '.$this->db_tablename.' ('.implode(',',$insert_fields).') VALUES('.implode(',',$param_names).')';
|
||||
}
|
||||
else {
|
||||
$sql = 'UPDATE '.$this->db_tablename.' SET '.implode(',',$update_list);
|
||||
$sql .= ' WHERE principal_id=:principal_id';
|
||||
$sql_params[':principal_id'] = $this->principal_id;
|
||||
}
|
||||
|
||||
$qry = new AwlQuery($sql, $sql_params);
|
||||
if ( $qry->Exec('Principal',__FILE__,__LINE__) ) {
|
||||
$this->unCache();
|
||||
$new_principal = new Principal('username', $sql_params[':username']);
|
||||
foreach( $new_principal AS $k => $v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function Create( $field_values ) {
|
||||
$this->Write($field_values, true);
|
||||
}
|
||||
|
||||
public function Update( $field_values ) {
|
||||
if ( !$this->Exists() ) {
|
||||
throw new Exception( get_class($this).'::Create: Attempting to update non-existent record.');
|
||||
}
|
||||
$this->Write($field_values, false);
|
||||
}
|
||||
|
||||
static public function cacheFlush( $where, $whereparams=array() ) {
|
||||
$cache = new AwlCache();
|
||||
if ( !$cache->isActive() ) return;
|
||||
$qry = new AwlQuery('SELECT dav_name FROM dav_principal WHERE '.$where, $whereparams );
|
||||
if ( $qry->Exec('Principal',__FILE__,__LINE__) ) {
|
||||
while( $row = $qry->Fetch() ) {
|
||||
$cache->delete('principal-'.$row->dav_name, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public function cacheDelete( $type, $value ) {
|
||||
$cache = new AwlCache();
|
||||
if ( !$cache->isActive() ) return;
|
||||
if ( $type == 'username' ) {
|
||||
$value = '/'.$value.'/';
|
||||
}
|
||||
$cache->delete('principal-'.$value, null);
|
||||
}
|
||||
}
|
||||
@ -56,11 +56,25 @@ class PublicSession {
|
||||
function PublicSession() {
|
||||
global $c;
|
||||
|
||||
$this->user_no = -1;
|
||||
$this->principal_id = -1;
|
||||
$this->email = null;
|
||||
$this->username = 'guest';
|
||||
$this->fullname = 'Anonymous';
|
||||
$principal = new Principal('username','unauthenticated');
|
||||
|
||||
// Assign each field in the selected record to the object
|
||||
foreach( $principal AS $k => $v ) {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
|
||||
$this->username = $principal->username();
|
||||
$this->user_no = $principal->user_no();
|
||||
$this->principal_id = $principal->principal_id();
|
||||
$this->email = $principal->email();
|
||||
$this->dav_name = $principal->dav_name();
|
||||
$this->principal = $principal;
|
||||
|
||||
if ( function_exists("awl_set_locale") && isset($this->locale) && $this->locale != "" ) {
|
||||
awl_set_locale($this->locale);
|
||||
}
|
||||
|
||||
|
||||
$this->groups = ( isset($c->public_groups) ? $c->public_groups : array() );
|
||||
$this->roles = array( 'Public' => true );
|
||||
$this->logged_in = false;
|
||||
|
||||
@ -37,7 +37,8 @@ $c->collections_always_exist = false;
|
||||
$c->allow_get_email_visibility = false;
|
||||
$c->permission_scan_depth = 2;
|
||||
$c->expand_pdo_parameters = true;
|
||||
$c->home_calendar_name = 'home';
|
||||
$c->home_calendar_name = 'calendar';
|
||||
$c->home_addressbook_name = 'addresses';
|
||||
$c->enable_row_linking = true;
|
||||
$c->enable_scheduling = false;
|
||||
$c->http_auth_mode = 'Basic';
|
||||
@ -168,8 +169,8 @@ init_gettext( 'davical', $c->locale_path );
|
||||
*
|
||||
*/
|
||||
$c->code_version = 0;
|
||||
$c->want_awl_version = 0.46; // The actual version # is replaced into that during the build /release process
|
||||
$c->version_string = '0.9.8.3'; // The actual version # is replaced into that during the build /release process
|
||||
$c->want_awl_version = 0.46;
|
||||
$c->version_string = '0.9.9.4'; // The actual version # is replaced into that during the build /release process
|
||||
if ( isset($c->version_string) && preg_match( '/(\d+)\.(\d+)\.(\d+)(.*)/', $c->version_string, $matches) ) {
|
||||
$c->code_major = $matches[1];
|
||||
$c->code_minor = $matches[2];
|
||||
@ -186,7 +187,7 @@ $_SERVER['SERVER_NAME'] = $c->domain_name;
|
||||
|
||||
require_once('AwlQuery.php');
|
||||
|
||||
$c->want_dbversion = array(1,2,8);
|
||||
$c->want_dbversion = array(1,2,9);
|
||||
$c->schema_version = 0;
|
||||
$qry = new AwlQuery( 'SELECT schema_major, schema_minor, schema_patch FROM awl_db_revision ORDER BY schema_id DESC LIMIT 1;' );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $row = $qry->Fetch() ) {
|
||||
@ -202,92 +203,7 @@ if ( $qry->Exec('always',__LINE__,__FILE__) && $row = $qry->Fetch() ) {
|
||||
if ( isset($_SERVER['HTTP_X_DAVICAL_TESTCASE']) ) $qry->QDo('SET TIMEZONE TO \'Pacific/Auckland\'');
|
||||
}
|
||||
|
||||
|
||||
$_known_users_name = array();
|
||||
$_known_users_id = array();
|
||||
$_known_users_pid = array();
|
||||
$_known_users_email = array();
|
||||
|
||||
function _davical_get_principal_query_cached( $where, $parameter ) {
|
||||
global $c, $session, $_known_users_name, $_known_users_id, $_known_users_pid;
|
||||
|
||||
$sql = 'SELECT *, to_char(updated at time zone \'GMT\',\'Dy, DD Mon IYYY HH24:MI:SS "GMT"\') AS modified, principal.*, ';
|
||||
if ( isset($session->principal_id) ) {
|
||||
$sql .= 'pprivs(:session_principal::int8,principal.principal_id,:scan_depth::int) AS privileges ';
|
||||
$params = array( ':session_principal' => $session->principal_id, ':scan_depth' => $c->permission_scan_depth );
|
||||
}
|
||||
else {
|
||||
$sql .= '0::BIT(24) AS privileges ';
|
||||
$params = array( );
|
||||
}
|
||||
$sql .= 'FROM usr LEFT JOIN principal USING(user_no) WHERE '. $where;
|
||||
$params[':param'] = $parameter;
|
||||
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec('always',__LINE__,__FILE__) && $qry->rows() == 1 && $row = $qry->Fetch() ) {
|
||||
if ( isset($session->principal_id) ) {
|
||||
$_known_users_name[$row->username] = $row;
|
||||
$_known_users_id[$row->user_no] = $row;
|
||||
$_known_users_pid[$row->principal_id] = $row;
|
||||
$_known_users_email[$row->email] = $row;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a user record identified by a username, caching it for any subsequent lookup
|
||||
* @param string $username The username of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByName( $username, $use_cache = true ) {
|
||||
global $_known_users_name;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_name[$username] ) ) return $_known_users_name[$username];
|
||||
return _davical_get_principal_query_cached( 'lower(username) = lower(:param)', $username );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by e-mail address, caching it for any subsequent lookup
|
||||
* @param string $email The email address of the user record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByEMail( $email, $use_cache = true ) {
|
||||
global $_known_users_name;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_email[$email] ) ) return $_known_users_email[$email];
|
||||
return _davical_get_principal_query_cached( 'lower(email) = lower(:param)', $email );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by a user_no, caching it for any subsequent lookup
|
||||
* @param int $user_no The ID of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getUserByID( $user_no, $use_cache = true ) {
|
||||
global $c, $session, $_known_users_id;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_id[$user_no] ) ) return $_known_users_id[$user_no];
|
||||
return _davical_get_principal_query_cached( 'user_no = :param', $user_no );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a user record identified by a user_no, caching it for any subsequent lookup
|
||||
* @param int $user_no The ID of the record to retrieve
|
||||
* @param boolean $use_cache Whether or not to use the cache (default: yes)
|
||||
*/
|
||||
function getPrincipalByID( $principal_id, $use_cache = true ) {
|
||||
global $c, $session, $_known_users_pid;
|
||||
|
||||
if ( $use_cache && isset( $_known_users_pid[$principal_id] ) ) return $_known_users_pid[$principal_id];
|
||||
return _davical_get_principal_query_cached( 'principal_id = :param', $principal_id );
|
||||
}
|
||||
|
||||
require_once('Principal.php');
|
||||
|
||||
/**
|
||||
* Return the HTTP status code description for a given code. Hopefully
|
||||
|
||||
@ -27,59 +27,125 @@
|
||||
|
||||
require_once("DataUpdate.php");
|
||||
|
||||
if ( !function_exists('auth_functions_deprecated') ) {
|
||||
function auth_functions_deprecated( $method, $message = null ) {
|
||||
global $c;
|
||||
if ( isset($c->dbg['ALL']) || isset($c->dbg['deprecated']) ) {
|
||||
$stack = debug_backtrace();
|
||||
array_shift($stack);
|
||||
if ( preg_match( '{/inc/auth-functions.php$}', $stack[0]['file'] ) && $stack[0]['line'] > __LINE__ ) return;
|
||||
dbg_error_log("LOG", " auth-functions: Call to deprecated routine '%s'%s", $method, (isset($message)?': '.$message:'') );
|
||||
foreach( $stack AS $k => $v ) {
|
||||
dbg_error_log( 'LOG', ' auth-functions: Deprecated call from line %4d of %s', $v['line'], $v['file']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getUserByName( $username, $use_cache=true ) {
|
||||
auth_functions_deprecated('getUserByName','replaced by Principal class');
|
||||
return new Principal('username', $username, $use_cache);
|
||||
}
|
||||
|
||||
function getUserByEMail( $email, $use_cache = true ) {
|
||||
auth_functions_deprecated('getUserByEMail','replaced by Principal class');
|
||||
return new Principal('email', $email, $use_cache);
|
||||
}
|
||||
|
||||
function getUserByID( $user_no, $use_cache = true ) {
|
||||
auth_functions_deprecated('getUserByID','replaced by Principal class');
|
||||
return new Principal('user_no', $user_no, $use_cache);
|
||||
}
|
||||
|
||||
function getPrincipalByID( $principal_id, $use_cache = true ) {
|
||||
auth_functions_deprecated('getPrincipalByID','replaced by Principal class');
|
||||
return new Principal('principal_id', $principal_id, $use_cache);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a default home calendar for the user.
|
||||
* Creates some default home collections for the user.
|
||||
* @param string $username The username of the user we are creating relationships for.
|
||||
*/
|
||||
function CreateHomeCalendar( $username ) {
|
||||
function CreateHomeCollections( $username ) {
|
||||
global $session, $c;
|
||||
if ( ! isset($c->home_calendar_name) || strlen($c->home_calendar_name) == 0 ) return true;
|
||||
|
||||
$usr = getUserByName( $username );
|
||||
$parent_path = "/".$username."/";
|
||||
$calendar_path = $parent_path . $c->home_calendar_name."/";
|
||||
$dav_etag = md5($usr->user_no . $calendar_path);
|
||||
$qry = new AwlQuery( 'SELECT 1 FROM collection WHERE dav_name = :dav_name', array( ':dav_name' => $calendar_path) );
|
||||
if ( $qry->Exec() ) {
|
||||
if ( $qry->rows() > 0 ) {
|
||||
$c->messages[] = i18n("Home calendar already exists.");
|
||||
return true;
|
||||
$principal = new Principal('username',$username);
|
||||
$params = array( ':collection_path' => $principal->dav_name().$c->home_calendar_name.'/' );
|
||||
$qry = new AwlQuery( 'SELECT 1 FROM collection WHERE dav_name = :collection_path', $params );
|
||||
if ( !$qry->Exec() ) {
|
||||
$c->messages[] = i18n("There was an error reading from the database.");
|
||||
return false;
|
||||
}
|
||||
if ( $qry->rows() > 0 ) {
|
||||
$c->messages[] = i18n("Home calendar already exists.");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
$sql = 'INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, created, modified, resourcetypes) ';
|
||||
$sql .= 'VALUES( :user_no, :parent_container, :collection_path, :dav_etag, :displayname, true, current_timestamp, current_timestamp, :resourcetypes );';
|
||||
$params = array(
|
||||
':user_no' => $principal->user_no(),
|
||||
':parent_container' => $principal->dav_name(),
|
||||
':collection_path' => $principal->dav_name().$c->home_calendar_name.'/',
|
||||
':dav_etag' => '-1',
|
||||
':displayname' => $principal->fullname,
|
||||
':resourcetypes' => '<DAV::collection/><urn:ietf:params:xml:ns:caldav:calendar/>'
|
||||
);
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec() ) {
|
||||
$c->messages[] = i18n("Home calendar added.");
|
||||
dbg_error_log("User",":Write: Created user's home calendar at '%s'", $params[':collection_path'] );
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = 'INSERT INTO collection (user_no, parent_container, dav_name, dav_etag, dav_displayname, is_calendar, created, modified, resourcetypes) ';
|
||||
$sql .= 'VALUES( :user_no, :parent_container, :calendar_path, :dav_etag, :displayname, true, current_timestamp, current_timestamp, :resourcetypes );';
|
||||
$params = array(
|
||||
':user_no' => $usr->user_no,
|
||||
':parent_container' => $parent_path,
|
||||
':calendar_path' => $calendar_path,
|
||||
':dav_etag' => $dav_etag,
|
||||
':displayname' => $usr->fullname,
|
||||
':resourcetypes' => '<DAV::collection/><urn:ietf:params:xml:ns:caldav:calendar/>'
|
||||
);
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec() ) {
|
||||
$c->messages[] = i18n("Home calendar added.");
|
||||
dbg_error_log("User",":Write: Created user's home calendar at '%s'", $calendar_path );
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
if ( !isset($c->home_addressbook_name) ) {
|
||||
$qry = new AwlQuery( 'SELECT 1 FROM collection WHERE dav_name = :dav_name', array( ':dav_name' => $principal->dav_name().$c->home_addressbook_name.'/') );
|
||||
if ( !$qry->Exec() ) {
|
||||
$c->messages[] = i18n("There was an error reading from the database.");
|
||||
return false;
|
||||
}
|
||||
if ( $qry->rows() > 0 ) {
|
||||
$c->messages[] = i18n("Home addressbook already exists.");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
$params[':collection_path'] = $principal->dav_name().$c->home_addressbook_name.'/';
|
||||
$qry = new AwlQuery( $sql, $params );
|
||||
if ( $qry->Exec() ) {
|
||||
$c->messages[] = i18n("Home addressbook added.");
|
||||
dbg_error_log("User",":Write: Created user's home addressbook at '%s'", $params[':collection_path'] );
|
||||
}
|
||||
else {
|
||||
$c->messages[] = i18n("There was an error writing to the database.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward compatibility
|
||||
* @param unknown_type $username
|
||||
*/
|
||||
function CreateHomeCalendar($username) {
|
||||
auth_functions_deprecated('CreateHomeCalendar','renamed to CreateHomeCollections');
|
||||
return CreateHomeCollections($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defunct function for creating default relationships.
|
||||
* @param string $username The username of the user we are creating relationships for.
|
||||
*/
|
||||
function CreateDefaultRelationships( $username ) {
|
||||
auth_functions_deprecated('CreateDefaultRelationships','No longer applicable.');
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -90,6 +156,8 @@ function CreateDefaultRelationships( $username ) {
|
||||
*/
|
||||
function UpdateUserFromExternal( &$usr ) {
|
||||
global $c;
|
||||
|
||||
auth_functions_deprecated('UpdateUserFromExternal','refactor to use the "Principal" class');
|
||||
/**
|
||||
* When we're doing the create we will usually need to generate a user number
|
||||
*/
|
||||
@ -201,19 +269,22 @@ EOERRMSG;
|
||||
if ( $qry->Exec('Login',__LINE__,__FILE__) && $qry->rows() == 1 ) {
|
||||
$usr = $qry->Fetch();
|
||||
if ( session_validate_password( $password, $usr->password ) ) {
|
||||
UpdateUserFromExternal($usr);
|
||||
$principal = new Principal($username);
|
||||
if ( $principal->Exists() ) {
|
||||
if ( $principal->modified <= $usr->updated )
|
||||
$principal->Update($usr);
|
||||
}
|
||||
else {
|
||||
$principal->Create($usr);
|
||||
CreateHomeCollections($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* We disallow login by inactive users _after_ we have updated the local copy
|
||||
*/
|
||||
if ( isset($usr->active) && $usr->active == 'f' ) return false;
|
||||
|
||||
$qry = new AwlQuery('SELECT * FROM dav_principal WHERE username = :username', array(':username' => $usr->username) );
|
||||
if ( $qry->Exec() && $qry->rows() == 1 ) {
|
||||
$principal = $qry->Fetch();
|
||||
return $principal;
|
||||
}
|
||||
return $usr; // Somewhat optimistically
|
||||
return $principal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -94,20 +94,23 @@ $aces = $xmltree->GetPath("/DAV::acl/*");
|
||||
|
||||
$grantor = new DAVResource($request->path);
|
||||
if ( ! $grantor->Exists() ) $request->DoResponse( 404 );
|
||||
$by_principal = null;
|
||||
$by_collection = null;
|
||||
if ( $grantor->IsPrincipal() ) $by_principal = $grantor->GetProperty('principal_id');
|
||||
else if ( $grantor->IsCollection() ) $by_collection = $grantor->GetProperty('collection_id');
|
||||
else $request->PreconditionFailed(403,'not-supported-privilege','ACLs may only be applied to Principals or Collections');
|
||||
if ( ! $grantor->IsCollection() )
|
||||
$request->PreconditionFailed(403,'not-supported-privilege','ACLs are only supported on Principals or Collections');
|
||||
|
||||
$grantor->NeedPrivilege('write-acl');
|
||||
|
||||
$cache_delete_list = array();
|
||||
|
||||
$qry = new AwlQuery('BEGIN');
|
||||
$qry->Exec('ACL',__LINE__,__FILE__);
|
||||
|
||||
foreach( $aces AS $k => $ace ) {
|
||||
function process_ace( $grantor, $by_principal, $by_collection, $ace ) {
|
||||
global $cache_delete_list;
|
||||
|
||||
$elements = $ace->GetContent();
|
||||
$principal = $elements[0];
|
||||
$principal_node = $elements[0];
|
||||
$grant = $elements[1];
|
||||
if ( $principal->GetTag() != 'DAV::principal' ) $request->MalformedRequest('ACL request must contain a principal, not '.$principal->GetTag());
|
||||
if ( $principal_node->GetTag() != 'DAV::principal' ) $request->MalformedRequest('ACL request must contain a principal, not '.$principal->GetTag());
|
||||
$grant_tag = $grant->GetTag();
|
||||
if ( $grant_tag == 'DAV::deny' ) $request->PreconditionFailed(403,'grant-only');
|
||||
if ( $grant_tag == 'DAV::invert' ) $request->PreconditionFailed(403,'no-invert');
|
||||
@ -120,7 +123,7 @@ foreach( $aces AS $k => $ace ) {
|
||||
}
|
||||
$privileges = privilege_to_bits($privilege_names);
|
||||
|
||||
$principal_content = $principal->GetContent();
|
||||
$principal_content = $principal_node->GetContent();
|
||||
if ( count($principal_content) != 1 ) $request->MalformedRequest('ACL request must contain exactly one principal per ACE');
|
||||
$principal_content = $principal_content[0];
|
||||
switch( $principal_content->GetTag() ) {
|
||||
@ -139,10 +142,11 @@ foreach( $aces AS $k => $ace ) {
|
||||
|
||||
case 'DAV::href':
|
||||
$principal_type = 'href';
|
||||
$principal = new DAVResource( DeconstructURL($principal_content->GetContent()) );
|
||||
if ( ! $principal->Exists() || !$principal->IsPrincipal() )
|
||||
$grantee = new DAVResource( DeconstructURL($principal_content->GetContent()) );
|
||||
$grantee_id = $grantee->getProperty('principal_id');
|
||||
if ( !$grantee->Exists() || !$grantee->IsPrincipal() )
|
||||
$request->PreconditionFailed(403,'recognized-principal', 'Principal "' + $principal_content->GetContent() + '" not found.');
|
||||
$sqlparms = array( ':to_principal' => $principal->GetProperty('principal_id') );
|
||||
$sqlparms = array( ':to_principal' => $grantee_id);
|
||||
$where = 'WHERE to_principal=:to_principal AND ';
|
||||
if ( isset($by_principal) ) {
|
||||
$sqlparms[':by_principal'] = $by_principal;
|
||||
@ -163,7 +167,10 @@ foreach( $aces AS $k => $ace ) {
|
||||
}
|
||||
$sqlparms[':privileges'] = $privileges;
|
||||
$qry = new AwlQuery($sql, $sqlparms);
|
||||
$qry->Exec('ACL',__LINE__,__FILE__);
|
||||
if ( $qry->Exec('ACL',__LINE__,__FILE__) ) {
|
||||
Principal::cacheDelete('dav_name',$grantee->dav_name());
|
||||
Principal::cacheFlush('principal_id IN (SELECT member_id FROM group_member WHERE group_id = '.$grantee_id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DAV::authenticated':
|
||||
@ -179,7 +186,12 @@ foreach( $aces AS $k => $ace ) {
|
||||
$sqlparms[':by_principal'] = $by_principal;
|
||||
}
|
||||
$qry = new AwlQuery($sql, $sqlparms);
|
||||
$qry->Exec('ACL',__LINE__,__FILE__);
|
||||
if ( $qry->Exec('ACL',__LINE__,__FILE__) ) {
|
||||
/**
|
||||
* Basically this has changed everyone's permissions now, so...
|
||||
*/
|
||||
Principal::cacheFlush('TRUE');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DAV::all':
|
||||
@ -194,6 +206,13 @@ foreach( $aces AS $k => $ace ) {
|
||||
|
||||
}
|
||||
|
||||
$by_principal = ($grantor->IsPrincipal() ? $grantor->GetProperty('principal_id') : null);
|
||||
$by_collection = ($grantor->IsPrincipal() ? null : $grantor->GetProperty('collection_id'));
|
||||
|
||||
foreach( $aces AS $k => $ace ) {
|
||||
process_ace($grantor, $by_principal, $by_collection, $ace);
|
||||
}
|
||||
|
||||
$qry = new AwlQuery('COMMIT');
|
||||
$qry->Exec('ACL',__LINE__,__FILE__);
|
||||
|
||||
|
||||
@ -13,7 +13,12 @@ dbg_error_log("OPTIONS", "method handler");
|
||||
include_once('DAVResource.php');
|
||||
$resource = new DAVResource($request->path);
|
||||
|
||||
$resource->NeedPrivilege( 'DAV::read', true );
|
||||
/**
|
||||
* The spec calls for this to be controlled by 'read' access, but we expand
|
||||
* that a little to also allow read-current-user-privilege-set since we grant that
|
||||
* more generally and Mozilla attempts this and gets upset...
|
||||
*/
|
||||
$resource->NeedPrivilege( array('DAV::read','DAV::read-current-user-privilege-set'), true );
|
||||
|
||||
if ( !$resource->Exists() ) {
|
||||
$request->DoResponse( 404, translate("No collection found at that location.") );
|
||||
|
||||
@ -184,7 +184,7 @@ function handle_schedule_request( $ical ) {
|
||||
|
||||
foreach( $attendees AS $k => $attendee ) {
|
||||
$attendee_email = preg_replace( '/^mailto:/', '', $attendee->Value() );
|
||||
if ( $attendee_email == $request->principal->email ) {
|
||||
if ( $attendee_email == $request->principal->email() ) {
|
||||
dbg_error_log( "POST", "not delivering to owner" );
|
||||
continue;
|
||||
}
|
||||
@ -195,18 +195,18 @@ function handle_schedule_request( $ical ) {
|
||||
|
||||
dbg_error_log( "POST", "Delivering to %s", $attendee_email );
|
||||
|
||||
$attendee_principal = new CalDAVPrincipal ( array ('email'=>$attendee_email, 'options'=> array ( 'allow_by_email' => true ) ) );
|
||||
$attendee_principal = new DAVPrincipal ( array ('email'=>$attendee_email, 'options'=> array ( 'allow_by_email' => true ) ) );
|
||||
if ( $attendee_principal == false ){
|
||||
$attendee->SetParameterValue ('SCHEDULE-STATUS','3.7;Invalid Calendar User');
|
||||
continue;
|
||||
}
|
||||
$deliver_path = preg_replace ( '/^.*caldav.php/','', $attendee_principal->schedule_inbox_url );
|
||||
$deliver_path = $attendee_principal->internal_url('schedule_inbox');
|
||||
|
||||
$ar = new DAVResource($deliver_path);
|
||||
$priv = $ar->HavePrivilegeTo('schedule-deliver-invite' );
|
||||
if ( ! $ar->HavePrivilegeTo('schedule-deliver-invite' ) ){
|
||||
$reply = new XMLDocument( array('DAV:' => '') );
|
||||
$privnodes = array( $reply->href(ConstructURL($attendee_principal->schedule_inbox_url)), new XMLElement( 'privilege' ) );
|
||||
$privnodes = array( $reply->href($attendee_principal->url('schedule_inbox')), new XMLElement( 'privilege' ) );
|
||||
// RFC3744 specifies that we can only respond with one needed privilege, so we pick the first.
|
||||
$reply->NSElement( $privnodes[1], 'schedule-deliver-invite' );
|
||||
$xml = new XMLElement( 'need-privileges', new XMLElement( 'resource', $privnodes) );
|
||||
@ -222,10 +222,10 @@ function handle_schedule_request( $ical ) {
|
||||
$ncal->AddComponent ( array_merge ( $ical->GetComponents('VEVENT',false) , array ($ic) ));
|
||||
$content = $ncal->Render();
|
||||
$cid = $ar->GetProperty('collection_id');
|
||||
dbg_error_log('DELIVER', 'to user: %s, to path: %s, collection: %s, from user: %s, caldata %s', $attendee_principal->user_no, $deliver_path, $cid, $request->user_no, $content );
|
||||
write_resource( $attendee_principal->user_no, $deliver_path . $etag . '.ics' ,
|
||||
$content , $ar->GetProperty('collection_id'), $request->user_no,
|
||||
md5($content), $ncal, $put_action_type='INSERT', $caldav_context=true, $log_action=true, $etag );
|
||||
dbg_error_log('DELIVER', 'to user: %s, to path: %s, collection: %s, from user: %s, caldata %s', $attendee_principal->user_no(), $deliver_path, $cid, $request->user_no, $content );
|
||||
write_resource( $attendee_principal->user_no(), $deliver_path . $etag . '.ics' ,
|
||||
$content , $ar->GetProperty('collection_id'), $request->user_no,
|
||||
md5($content), $ncal, $put_action_type='INSERT', $caldav_context=true, $log_action=true, $etag );
|
||||
$attendee->SetParameterValue ('SCHEDULE-STATUS','1.2;Scheduling message has been delivered');
|
||||
}
|
||||
// don't write an entry in the out box, ical doesn't delete it or ever read it again
|
||||
@ -234,7 +234,7 @@ function handle_schedule_request( $ical ) {
|
||||
$ncal->AddProperty ( 'METHOD', 'REQUEST' );
|
||||
$ncal->AddComponent ( array_merge ( $ical->GetComponents('VEVENT',false) , array ($ic) ));
|
||||
$content = $ncal->Render();
|
||||
$deliver_path = preg_replace ( '/^.*caldav.php/','', $request->principal->schedule_inbox_url );
|
||||
$deliver_path = $request->principal->internal_url('schedule_inbox');
|
||||
$ar = new DAVResource($deliver_path);
|
||||
write_resource( $request->user_no, $deliver_path . $etag . '.ics' ,
|
||||
$content , $ar->GetProperty('collection_id'), $request->user_no,
|
||||
@ -272,8 +272,8 @@ function handle_schedule_reply ( $ical ) {
|
||||
foreach( $attendees AS $k => $attendee ) {
|
||||
$attendee_email = preg_replace( '/^mailto:/', '', $attendee->Value() );
|
||||
dbg_error_log( "POST", "Delivering to %s", $attendee_email );
|
||||
$attendee_principal = new CalDAVPrincipal ( array ('email'=>$attendee_email, 'options'=> array ( 'allow_by_email' => true ) ) );
|
||||
$deliver_path = preg_replace ( '/^.*caldav.php/','', $attendee_principal->schedule_inbox_url );
|
||||
$attendee_principal = new DAVPrincipal ( array ('email'=>$attendee_email, 'options'=> array ( 'allow_by_email' => true ) ) );
|
||||
$deliver_path = $attendee_principal->internal_url('schedule_inbox');
|
||||
$attendee_email = preg_replace( '/^mailto:/', '', $attendee->Value() );
|
||||
if ( $attendee_email == $request->principal->email ) {
|
||||
dbg_error_log( "POST", "not delivering to owner" );
|
||||
@ -282,7 +282,7 @@ function handle_schedule_reply ( $ical ) {
|
||||
$ar = new DAVResource($deliver_path);
|
||||
if ( ! $ar->HavePrivilegeTo('schedule-deliver-reply' ) ){
|
||||
$reply = new XMLDocument( array('DAV:' => '') );
|
||||
$privnodes = array( $reply->href(ConstructURL($attendee_principal->schedule_inbox_url)), new XMLElement( 'privilege' ) );
|
||||
$privnodes = array( $reply->href($attendee_principal->url('schedule_inbox')), new XMLElement( 'privilege' ) );
|
||||
// RFC3744 specifies that we can only respond with one needed privilege, so we pick the first.
|
||||
$reply->NSElement( $privnodes[1], 'schedule-deliver-reply' );
|
||||
$xml = new XMLElement( 'need-privileges', new XMLElement( 'resource', $privnodes) );
|
||||
@ -296,7 +296,7 @@ function handle_schedule_reply ( $ical ) {
|
||||
$ncal->AddProperty ( 'METHOD', 'REPLY' );
|
||||
$ncal->AddComponent ( array_merge ( $ical->GetComponents('VEVENT',false) , array ($ic) ));
|
||||
$content = $ncal->Render();
|
||||
write_resource( $attendee_principal->user_no, $deliver_path . $etag . '.ics' ,
|
||||
write_resource( $attendee_principal->user_no(), $deliver_path . $etag . '.ics' ,
|
||||
$content , $ar->GetProperty('collection_id'), $request->user_no,
|
||||
md5($content), $ncal, $put_action_type='INSERT', $caldav_context=true, $log_action=true, $etag );
|
||||
}
|
||||
@ -314,9 +314,9 @@ function handle_schedule_reply ( $ical ) {
|
||||
*/
|
||||
function write_scheduling_request( &$resource, $attendee_value, $create_resource ) {
|
||||
$email = preg_replace( '/^mailto:/', '', $attendee_value );
|
||||
$schedule_target = getUserByEmail($email);
|
||||
if ( isset($schedule_target) && is_object($schedule_target) ) {
|
||||
$attendee_inbox = new WritableCollection(array('path' => $schedule_target->dav_name.'.in/'));
|
||||
$schedule_target = new Principal('email',$email);
|
||||
if ( $schedule_target->Exists() ) {
|
||||
$attendee_inbox = new WritableCollection(array('path' => $schedule_target->internal_url('schedule-inbox')));
|
||||
if ( ! $attendee_inbox->HavePrivilegeTo('schedule-deliver-invite') ) {
|
||||
$response = '3.8;'.translate('No authority to deliver invitations to user.');
|
||||
}
|
||||
|
||||
@ -5,9 +5,10 @@
|
||||
* @package davical
|
||||
* @category Technical
|
||||
* @subpackage ldap
|
||||
* @author Oliver Schulze <oliver@samera.com.py>
|
||||
* @author Oliver Schulze <oliver@samera.com.py>,
|
||||
* Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Based on Eric Seigne script drivers_squid_pam.php
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
|
||||
require_once("auth-functions.php");
|
||||
@ -53,54 +54,54 @@ class imapPamDrivers
|
||||
function IMAP_PAM_check($username, $password ){
|
||||
global $c;
|
||||
|
||||
/**
|
||||
* @todo Think of the children! This is a horribly insecure use of unvalidated user input! Probably it should be done with a popen or something, and it seems remarkably dodgy to expect that naively quoted strings will work in any way reliably.
|
||||
* Meanwhile, I've quickly hacked something basic in place to improve the situation. No quotes/backslashes in passwords for YOU!
|
||||
*/
|
||||
$imap_username = $username;
|
||||
if ( function_exists('mb_convert_encoding') ) {
|
||||
$imap_username = mb_convert_encoding($imap_username, "UTF7-IMAP",mb_detect_encoding($imap_username));
|
||||
}
|
||||
else {
|
||||
$imap_username = imap_utf7_encode($imap_username);
|
||||
}
|
||||
|
||||
$username_ori = $username;
|
||||
$username = escapeshellcmd($username);
|
||||
//$password = escapeshellcmd($password);
|
||||
|
||||
//$imap_url = '{localhost:143/imap/notls}';
|
||||
//$imap_url = '{localhost:993/imap/ssl/novalidate-cert}';
|
||||
$imap_url = $c->authenticate_hook['config']['imap_url'];
|
||||
$auth_result = "ERR";
|
||||
|
||||
$imap_stream = @imap_open($imap_url, $username, $password, OP_HALFOPEN);
|
||||
//print_r(imap_errors());
|
||||
if ( $imap_stream ) {
|
||||
// disconnect
|
||||
imap_close($imap_stream);
|
||||
// login ok
|
||||
$auth_result = "OK";
|
||||
}
|
||||
//$imap_url = '{localhost:143/imap/notls}';
|
||||
//$imap_url = '{localhost:993/imap/ssl/novalidate-cert}';
|
||||
$imap_url = $c->authenticate_hook['config']['imap_url'];
|
||||
$auth_result = "ERR";
|
||||
|
||||
$imap_stream = @imap_open($imap_url, $imap_username, $password, OP_HALFOPEN);
|
||||
//print_r(imap_errors());
|
||||
if ( $imap_stream ) {
|
||||
// disconnect
|
||||
imap_close($imap_stream);
|
||||
// login ok
|
||||
$auth_result = "OK";
|
||||
}
|
||||
|
||||
if ( $auth_result == "OK") {
|
||||
if ( $usr = getUserByName($username) ) {
|
||||
return $usr;
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PAM", "user %s doesn't exist in local DB, we need to create it",$username );
|
||||
$principal = new Principal('username',$username);
|
||||
if ( ! $principal->Exists() ) {
|
||||
dbg_error_log( "PAM", "Principal '%s' doesn't exist in local DB, we need to create it",$username );
|
||||
$cmd = "getent passwd '$username'";
|
||||
$getent_res = exec($cmd);
|
||||
$getent_arr = explode(":", $getent_res);
|
||||
$fullname = $getent_arr[4];
|
||||
if(empty($fullname)) {
|
||||
$fullname = $username;
|
||||
}
|
||||
$usr = (object) array(
|
||||
'user_no' => 0,
|
||||
'username' => $username,
|
||||
'active' => 't',
|
||||
'email' => $username . "@" . $c->authenticate_hook['config']['email_base'],
|
||||
'updated' => date(),
|
||||
'fullname' => $fullname
|
||||
);
|
||||
$getent_arr = explode(":", $getent_res);
|
||||
$fullname = $getent_arr[4];
|
||||
if(empty($fullname)) {
|
||||
$fullname = $username;
|
||||
}
|
||||
|
||||
UpdateUserFromExternal( $usr );
|
||||
return $usr;
|
||||
$principal->Create( array(
|
||||
'username' => $username,
|
||||
'user_active' => true,
|
||||
'email' => $username . "@" . $c->authenticate_hook['config']['email_base'],
|
||||
'modified' => date(),
|
||||
'fullname' => $fullname
|
||||
));
|
||||
if ( ! $principal->Exists() ) {
|
||||
dbg_error_log( "PAM", "Unable to create local principal for '%s'", $username );
|
||||
return false;
|
||||
}
|
||||
CreateHomeCalendar($username);
|
||||
}
|
||||
return $principal;
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PAM", "User %s is not a valid username (or password was wrong)", $username );
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
* @package davical
|
||||
* @category Technical
|
||||
* @subpackage ldap
|
||||
* @author Maxime Delorme <mdelorme@tennaxia.net>
|
||||
* @author Maxime Delorme <mdelorme@tennaxia.net>,
|
||||
* Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Maxime Delorme
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
@ -248,7 +249,7 @@ function getStaticLdap() {
|
||||
|
||||
// If the instance is not there, create one
|
||||
if(!isset($instance)) {
|
||||
$ldapDrivers =& new ldapDrivers($c->authenticate_hook['config']);
|
||||
$ldapDrivers = new ldapDrivers($c->authenticate_hook['config']);
|
||||
}
|
||||
return $ldapDrivers;
|
||||
}
|
||||
@ -256,32 +257,36 @@ function getStaticLdap() {
|
||||
|
||||
/**
|
||||
* Synchronise a cached user with one from LDAP
|
||||
* @param object $usr A user record to be updated (or created)
|
||||
* @param object $principal A Principal object to be updated (or created)
|
||||
*/
|
||||
function sync_user_from_LDAP( &$usr, $mapping, $ldap_values ) {
|
||||
function sync_user_from_LDAP( Principal &$principal, $mapping, $ldap_values ) {
|
||||
global $c;
|
||||
|
||||
dbg_error_log( "LDAP", "Going to sync the user from LDAP" );
|
||||
$validUserFields = get_fields('usr');
|
||||
|
||||
$fields_to_set = array();
|
||||
$updateable_fields = Principal::updateableFields();
|
||||
$updateable_fields[] = 'active'; // Backward compatibility: now 'user_exists'
|
||||
$updateable_fields[] = 'updated'; // Backward compatibility: now 'modified'
|
||||
if ( isset($c->authenticate_hook['config']['default_value']) && is_array($c->authenticate_hook['config']['default_value']) ) {
|
||||
foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) {
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$usr->{$field} = $value;
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value );
|
||||
foreach( $updateable_fields AS $field ) {
|
||||
if ( isset($ldap_values[$mapping[$field]]) ) {
|
||||
$fields_to_set[$field] = $ldap_values[$mapping[$field]];
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$mapping[$field]], $mapping[$field] );
|
||||
}
|
||||
else if ( isset($c->authenticate_hook['config']['default_value'][$field] ) ) {
|
||||
$fields_to_set[$field] = $c->authenticate_hook['config']['default_value'][$field];
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $c->authenticate_hook['config']['default_value'][$field] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $mapping as $field => $value ) {
|
||||
dbg_error_log( "LDAP", "Considering copying %s", $field );
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$usr->{$field} = $ldap_values[$value];
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value );
|
||||
}
|
||||
if ( $principal->Exists ) {
|
||||
$principal->Update($fields_to_set);
|
||||
}
|
||||
else {
|
||||
$principal->Create($fields_to_set);
|
||||
CreateHomeCalendar($principal->username());
|
||||
}
|
||||
|
||||
UpdateUserFromExternal( $usr );
|
||||
}
|
||||
|
||||
|
||||
@ -332,24 +337,25 @@ function LDAP_check($username, $password ){
|
||||
$ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S";
|
||||
$valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S";
|
||||
|
||||
if ( $usr = getUserByName($username) ) {
|
||||
$principal = new Principal('username',$username);
|
||||
if ( $principal->Exists() ) {
|
||||
// should we update it ?
|
||||
$db_timestamp = $usr->updated;
|
||||
$db_timestamp = $principal->modified;
|
||||
$db_timestamp = substr(strtr($db_timestamp, array(':' => '',' '=>'','-'=>'')),0,14);
|
||||
if($ldap_timestamp <= $db_timestamp) {
|
||||
return $usr; // no need to update
|
||||
if( $ldap_timestamp <= $db_timestamp ) {
|
||||
return $principal; // no need to update
|
||||
}
|
||||
// we will need to update the user record
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "LDAP", "user %s doesn't exist in local DB, we need to create it",$username );
|
||||
$usr = (object) array( 'user_no' => 0 );
|
||||
$principal->setUsername($username );
|
||||
}
|
||||
|
||||
// The local cached user doesn't exist, or is older, so we create/update their details
|
||||
sync_user_from_LDAP($usr, $mapping, $valid );
|
||||
|
||||
return $usr;
|
||||
sync_user_from_LDAP( $principal, $mapping, $valid );
|
||||
|
||||
return $principal;
|
||||
|
||||
}
|
||||
|
||||
@ -359,117 +365,132 @@ function LDAP_check($username, $password ){
|
||||
function sync_LDAP_groups(){
|
||||
global $c;
|
||||
$ldapDriver = getStaticLdap();
|
||||
if($ldapDriver->valid){
|
||||
$mapping = $c->authenticate_hook['config']['group_mapping_field'];
|
||||
//$attributes = array('cn','modifyTimestamp','memberUid');
|
||||
$attributes = array_values($mapping);
|
||||
$ldap_groups_tmp = $ldapDriver->getAllGroups($attributes);
|
||||
if ( $ldapDriver->valid ) return;
|
||||
|
||||
if ( sizeof($ldap_groups_tmp) == 0 )
|
||||
return;
|
||||
$mapping = $c->authenticate_hook['config']['group_mapping_field'];
|
||||
//$attributes = array('cn','modifyTimestamp','memberUid');
|
||||
$attributes = array_values($mapping);
|
||||
$ldap_groups_tmp = $ldapDriver->getAllGroups($attributes);
|
||||
|
||||
foreach($ldap_groups_tmp as $key => $ldap_group){
|
||||
$ldap_groups_info[$ldap_group[$mapping['username']]] = $ldap_group;
|
||||
if (is_array($ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']])) {
|
||||
unset ( $ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']]['count'] );
|
||||
if ( sizeof($ldap_groups_tmp) == 0 ) return;
|
||||
|
||||
$member_field = $mapping['members'];
|
||||
|
||||
foreach($ldap_groups_tmp as $key => $ldap_group){
|
||||
$group_mapping = $ldap_group[$mapping['username']];
|
||||
$ldap_groups_info[$group_mapping] = $ldap_group;
|
||||
if ( is_array($ldap_groups_info[$group_mapping][$member_field]) ) {
|
||||
unset( $ldap_groups_info[$group_mapping][$member_field]['count'] );
|
||||
}
|
||||
else {
|
||||
$ldap_groups_info[$group_mapping][$member_field] = array($ldap_groups_info[$group_mapping][$member_field]);
|
||||
}
|
||||
unset($ldap_groups_tmp[$key]);
|
||||
}
|
||||
$db_groups = array();
|
||||
$db_group_members = array();
|
||||
$qry = new AwlQuery( "SELECT g.username AS group_name, member.username AS member_name FROM dav_principal g LEFT JOIN group_member ON (g.principal_id=group_member.group_id) LEFT JOIN dav_principal member ON (member.principal_id=group_member.member_id) WHERE g.type_id = 3");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while($db_group = $qry->Fetch()) {
|
||||
$db_groups[$db_group->group_name] = $db_group->group_name;
|
||||
$db_group_members[$db_group->group_name][] = $db_group->member_name;
|
||||
}
|
||||
|
||||
$ldap_groups = array_keys($ldap_groups_info);
|
||||
// users only in ldap
|
||||
$groups_to_create = array_diff($ldap_groups,$db_groups);
|
||||
// users only in db
|
||||
$groups_to_deactivate = array_diff($db_groups,$ldap_groups);
|
||||
// users present in ldap and in the db
|
||||
$groups_to_update = array_intersect($db_groups,$ldap_groups);
|
||||
|
||||
if ( sizeof ( $groups_to_create ) ){
|
||||
$c->messages[] = sprintf(i18n('- creating groups : %s'),join(', ',$groups_to_create));
|
||||
$validUserFields = get_fields('usr');
|
||||
foreach ( $groups_to_create as $k => $group ){
|
||||
$user = (object) array();
|
||||
|
||||
if ( isset($c->authenticate_hook['config']['default_value']) && is_array($c->authenticate_hook['config']['default_value']) ) {
|
||||
foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) {
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$user->{$field} = $value;
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->user_no = 0;
|
||||
$ldap_values = $ldap_groups_info[$group];
|
||||
foreach ( $mapping as $field => $value ) {
|
||||
dbg_error_log( "LDAP", "Considering copying %s", $field );
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$user->{$field} = $ldap_values[$value];
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value );
|
||||
}
|
||||
}
|
||||
if ($user->fullname=="") {
|
||||
$user->fullname = $group;
|
||||
}
|
||||
if ($user->displayname=="") {
|
||||
$user->displayname = $group;
|
||||
}
|
||||
$user->username = $group;
|
||||
$user->updated = "now"; /** @todo Use the 'updated' timestamp from LDAP for groups too */
|
||||
|
||||
$principal = new Principal('username',$group);
|
||||
if ( $principal->Exists() ) {
|
||||
$principal->Update($user);
|
||||
}
|
||||
else {
|
||||
$ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']] = array($ldap_groups_info[$ldap_group[$mapping['username']]][$mapping['members']]);
|
||||
$principal->Create($user);
|
||||
}
|
||||
unset($ldap_groups_tmp[$key]);
|
||||
}
|
||||
$db_groups = array ();
|
||||
$db_group_members = array ();
|
||||
$qry = new AwlQuery( "SELECT g.username AS group_name, member.username AS member_name FROM dav_principal g LEFT JOIN group_member ON (g.principal_id=group_member.group_id) LEFT JOIN dav_principal member ON (member.principal_id=group_member.member_id) WHERE g.type_id = 3");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while($db_group = $qry->Fetch()) {
|
||||
$db_groups[$db_group->group_name] = $db_group->group_name;
|
||||
$db_group_members[$db_group->group_name][] = $db_group->member_name;
|
||||
}
|
||||
|
||||
$ldap_groups = array_keys($ldap_groups_info);
|
||||
// users only in ldap
|
||||
$groups_to_create = array_diff($ldap_groups,$db_groups);
|
||||
// users only in db
|
||||
$groups_to_deactivate = array_diff($db_groups,$ldap_groups);
|
||||
// users present in ldap and in the db
|
||||
$groups_to_update = array_intersect($db_groups,$ldap_groups);
|
||||
|
||||
if ( sizeof ( $groups_to_create ) ){
|
||||
$c->messages[] = sprintf(i18n('- creating groups : %s'),join(', ',$groups_to_create));
|
||||
$validUserFields = get_fields('usr');
|
||||
foreach ( $groups_to_create as $k => $group ){
|
||||
$user = (object) array( 'user_no' => 0, 'username' => '' );
|
||||
|
||||
if ( isset($c->authenticate_hook['config']['default_value']) && is_array($c->authenticate_hook['config']['default_value']) ) {
|
||||
foreach ( $c->authenticate_hook['config']['default_value'] as $field => $value ) {
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$usr->{$field} = $value;
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from configured defaults", $field, $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->user_no = 0;
|
||||
$ldap_values = $ldap_groups_info[$group];
|
||||
foreach ( $mapping as $field => $value ) {
|
||||
dbg_error_log( "LDAP", "Considering copying %s", $field );
|
||||
if ( isset($validUserFields[$field]) ) {
|
||||
$user->{$field} = $ldap_values[$value];
|
||||
dbg_error_log( "LDAP", "Setting usr->%s to %s from LDAP field %s", $field, $ldap_values[$value], $value );
|
||||
}
|
||||
}
|
||||
if ($user->fullname=="") {
|
||||
$user->fullname = $group;
|
||||
}
|
||||
if ($user->displayname=="") {
|
||||
$user->displayname = $group;
|
||||
}
|
||||
$user->username = $group;
|
||||
$user->updated = "now"; /** @todo Use the 'updated' timestamp from LDAP for groups too */
|
||||
|
||||
UpdateUserFromExternal( $user );
|
||||
$qry = new AwlQuery( "UPDATE dav_principal set type_id = 3 WHERE username=:group ",array(':group'=>$group) );
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
$c->messages[] = sprintf(i18n('- adding users %s to group : %s'),join(',',$ldap_groups_info[$group][$mapping['members']]),$group);
|
||||
foreach ( $ldap_groups_info[$group][$mapping['members']] as $member ){
|
||||
$qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member;",array (':group'=>$group,':member'=>$member) );
|
||||
$qry->Exec('sync_LDAP_groups',__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sizeof ( $groups_to_update ) ){
|
||||
$c->messages[] = sprintf(i18n('- updating groups : %s'),join(', ',$groups_to_update));
|
||||
foreach ( $groups_to_update as $group ){
|
||||
$db_members = array_values ( $db_group_members[$group] );
|
||||
$ldap_members = array_values ( $ldap_groups_info[$group][$mapping['members']] );
|
||||
$add_users = array_diff ( $ldap_members, $db_members );
|
||||
if ( sizeof ( $add_users ) ){
|
||||
$c->messages[] = sprintf(i18n('- adding %s to group : %s'),join(', ', $add_users ), $group);
|
||||
foreach ( $add_users as $member ){
|
||||
$qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member",array (':group'=>$group,':member'=>$member) );
|
||||
$qry->Exec('sync_LDAP_groups',__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
$remove_users = array_diff ( $db_members, $ldap_members );
|
||||
if ( sizeof ( $remove_users ) ){
|
||||
$c->messages[] = sprintf(i18n('- removing %s from group : %s'),join(', ', $remove_users ), $group);
|
||||
foreach ( $remove_users as $member ){
|
||||
$qry = new AwlQuery( "DELETE FROM group_member USING dav_principal g,dav_principal m WHERE group_id=g.principal_id AND member_id=m.principal_id AND g.username=:group AND m.username=:member",array (':group'=>$group,':member'=>$member) );
|
||||
$qry->Exec('sync_LDAP_groups',__LINE__,__FILE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sizeof ( $groups_to_deactivate ) ){
|
||||
$c->messages[] = sprintf(i18n('- deactivate groups : %s'),join(', ',$groups_to_deactivate));
|
||||
foreach ( $groups_to_deactivate as $group ){
|
||||
$qry = new AwlQuery( "UPDATE dav_principal set active='f'::bool WHERE username=:group AND type_id = 3",array(':group'=>$group) );
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
$qry = new AwlQuery( "UPDATE dav_principal set type_id = 3 WHERE username=:group ",array(':group'=>$group) );
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
Principal::cacheDelete('username', $group);
|
||||
$c->messages[] = sprintf(i18n('- adding users %s to group : %s'),join(',',$ldap_groups_info[$group][$mapping['members']]),$group);
|
||||
foreach ( $ldap_groups_info[$group][$mapping['members']] as $member ){
|
||||
$qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member;",array (':group'=>$group,':member'=>$member) );
|
||||
$qry->Exec('sync_LDAP_groups',__LINE__,__FILE__);
|
||||
Principal::cacheDelete('username', $member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sizeof ( $groups_to_update ) ){
|
||||
$c->messages[] = sprintf(i18n('- updating groups : %s'),join(', ',$groups_to_update));
|
||||
foreach ( $groups_to_update as $group ){
|
||||
$db_members = array_values ( $db_group_members[$group] );
|
||||
$ldap_members = array_values ( $ldap_groups_info[$group][$member_field] );
|
||||
$add_users = array_diff ( $ldap_members, $db_members );
|
||||
if ( sizeof ( $add_users ) ){
|
||||
$c->messages[] = sprintf(i18n('- adding %s to group : %s'),join(', ', $add_users ), $group);
|
||||
foreach ( $add_users as $member ){
|
||||
$qry = new AwlQuery( "INSERT INTO group_member SELECT g.principal_id AS group_id,u.principal_id AS member_id FROM dav_principal g, dav_principal u WHERE g.username=:group AND u.username=:member",array (':group'=>$group,':member'=>$member) );
|
||||
$qry->Exec('sync_LDAP_groups',__LINE__,__FILE__);
|
||||
Principal::cacheDelete('username', $member);
|
||||
}
|
||||
}
|
||||
$remove_users = array_diff ( $db_members, $ldap_members );
|
||||
if ( sizeof ( $remove_users ) ){
|
||||
$c->messages[] = sprintf(i18n('- removing %s from group : %s'),join(', ', $remove_users ), $group);
|
||||
foreach ( $remove_users as $member ){
|
||||
$qry = new AwlQuery( "DELETE FROM group_member USING dav_principal g,dav_principal m WHERE group_id=g.principal_id AND member_id=m.principal_id AND g.username=:group AND m.username=:member",array (':group'=>$group,':member'=>$member) );
|
||||
$qry->Exec('sync_LDAP_groups',__LINE__,__FILE__);
|
||||
Principal::cacheDelete('username', $member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( sizeof ( $groups_to_deactivate ) ){
|
||||
$c->messages[] = sprintf(i18n('- deactivate groups : %s'),join(', ',$groups_to_deactivate));
|
||||
foreach ( $groups_to_deactivate as $group ){
|
||||
$qry = new AwlQuery( 'UPDATE dav_principal set active=FALSE WHERE username=:group AND type_id = 3',array(':group'=>$group) );
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
Principal::cacheFlush('username=:group AND type_id = 3', array(':group'=>$group) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -478,107 +499,111 @@ function sync_LDAP_groups(){
|
||||
function sync_LDAP(){
|
||||
global $c;
|
||||
$ldapDriver = getStaticLdap();
|
||||
if($ldapDriver->valid){
|
||||
$mapping = $c->authenticate_hook['config']['mapping_field'];
|
||||
$attributes = array_values($mapping);
|
||||
$ldap_users_tmp = $ldapDriver->getAllUsers($attributes);
|
||||
if ( ! $ldapDriver->valid ) return;
|
||||
|
||||
if ( sizeof($ldap_users_tmp) == 0 )
|
||||
return;
|
||||
$mapping = $c->authenticate_hook['config']['mapping_field'];
|
||||
$attributes = array_values($mapping);
|
||||
$ldap_users_tmp = $ldapDriver->getAllUsers($attributes);
|
||||
|
||||
foreach($ldap_users_tmp as $key => $ldap_user){
|
||||
$ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user;
|
||||
unset($ldap_users_tmp[$key]);
|
||||
if ( sizeof($ldap_users_tmp) == 0 ) return;
|
||||
|
||||
foreach($ldap_users_tmp as $key => $ldap_user){
|
||||
$ldap_users_info[$ldap_user[$mapping["username"]]] = $ldap_user;
|
||||
unset($ldap_users_tmp[$key]);
|
||||
}
|
||||
$qry = new AwlQuery( "SELECT username, user_no, modified as updated FROM dav_principal where type_id=1");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while($db_user = $qry->Fetch()) {
|
||||
$db_users[] = $db_user->username;
|
||||
$db_users_info[$db_user->username] = array('user_no' => $db_user->user_no, 'updated' => $db_user->updated);
|
||||
}
|
||||
|
||||
// all users from ldap
|
||||
$ldap_users = array_keys($ldap_users_info);
|
||||
// users only in ldap
|
||||
$users_to_create = array_diff($ldap_users,$db_users);
|
||||
// users only in db
|
||||
$users_to_deactivate = array_diff($db_users,$ldap_users);
|
||||
// users present in ldap and in the db
|
||||
$users_to_update = array_intersect($db_users,$ldap_users);
|
||||
|
||||
// creation of all users;
|
||||
if ( sizeof($users_to_create) ) {
|
||||
$c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create));
|
||||
|
||||
foreach( $users_to_create as $username ) {
|
||||
$principal = new Principal( 'username', $username );
|
||||
$valid = $ldap_users_info[$username];
|
||||
$ldap_timestamp = $valid[$mapping['updated']];
|
||||
|
||||
/**
|
||||
* This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
|
||||
*/
|
||||
foreach($c->authenticate_hook['config']['format_updated'] as $k => $v)
|
||||
$$k = substr($ldap_timestamp,$v[0],$v[1]);
|
||||
$ldap_timestamp = $Y.$m.$d.$H.$M.$S;
|
||||
$valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S";
|
||||
|
||||
sync_user_from_LDAP( $principal, $mapping, $valid );
|
||||
}
|
||||
$qry = new AwlQuery( "SELECT username, user_no, modified as updated FROM dav_principal where type_id=1");
|
||||
}
|
||||
|
||||
// deactivating all users
|
||||
$params = array();
|
||||
$i = 0;
|
||||
foreach( $users_to_deactivate AS $v ) {
|
||||
if ( isset($c->do_not_sync_from_ldap) && isset($c->do_not_sync_from_ldap[$v]) ) continue;
|
||||
$params[':u'.$i++] = strtolower($v);
|
||||
}
|
||||
if ( count($params) > 0 ) {
|
||||
$c->messages[] = sprintf(i18n('- deactivating users : %s'),join(', ',$users_to_deactivate));
|
||||
$qry = new AwlQuery( 'UPDATE usr SET active = FALSE WHERE lower(username) IN ('.implode(',',array_keys($params)).')', $params);
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while($db_user = $qry->Fetch()) {
|
||||
$db_users[] = $db_user->username;
|
||||
$db_users_info[$db_user->username] = array('user_no' => $db_user->user_no, 'updated' => $db_user->updated);
|
||||
}
|
||||
|
||||
$ldap_users = array_keys($ldap_users_info);
|
||||
// users only in ldap
|
||||
$users_to_create = array_diff($ldap_users,$db_users);
|
||||
// users only in db
|
||||
$users_to_deactivate = array_diff($db_users,$ldap_users);
|
||||
// users present in ldap and in the db
|
||||
$users_to_update = array_intersect($db_users,$ldap_users);
|
||||
Principal::cacheFlush('lower(username) IN ('.implode(',',array_keys($params)).')', $params);
|
||||
}
|
||||
|
||||
// creation of all users;
|
||||
if ( sizeof($users_to_create) ) {
|
||||
$c->messages[] = sprintf(i18n('- creating record for users : %s'),join(', ',$users_to_create));
|
||||
// updating all users
|
||||
if ( sizeof($users_to_update) ) {
|
||||
foreach ( $users_to_update as $key=> $username ) {
|
||||
$principal = new Principal( 'username', $username );
|
||||
$valid=$ldap_users_info[$username];
|
||||
$ldap_timestamp = $valid[$mapping['updated']];
|
||||
|
||||
foreach( $users_to_create as $username ) {
|
||||
$user = (object) array( 'user_no' => 0, 'username' => $username );
|
||||
$valid = $ldap_users_info[$username];
|
||||
$ldap_timestamp = $valid[$mapping["updated"]];
|
||||
$valid['user_no'] = $db_users_info[$username]['user_no'];
|
||||
$mapping['user_no'] = 'user_no';
|
||||
|
||||
/**
|
||||
* This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
|
||||
*/
|
||||
foreach($c->authenticate_hook['config']['format_updated'] as $k => $v)
|
||||
$$k = substr($ldap_timestamp,$v[0],$v[1]);
|
||||
$ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S";
|
||||
$valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S";
|
||||
/**
|
||||
* This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
|
||||
*/
|
||||
foreach($c->authenticate_hook['config']['format_updated'] as $k => $v) {
|
||||
$$k = substr($ldap_timestamp,$v[0],$v[1]);
|
||||
}
|
||||
$ldap_timestamp = $Y.$m.$d.$H.$M.$S;
|
||||
$valid[$mapping['updated']] = "$Y-$m-$d $H:$M:$S";
|
||||
|
||||
sync_user_from_LDAP( $user, $mapping, $valid );
|
||||
$db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14);
|
||||
if ( $ldap_timestamp > $db_timestamp ) {
|
||||
sync_user_from_LDAP($principal, $mapping, $valid );
|
||||
}
|
||||
else {
|
||||
unset($users_to_update[$key]);
|
||||
$users_nothing_done[] = $username;
|
||||
}
|
||||
}
|
||||
if ( sizeof($users_to_update) )
|
||||
$c->messages[] = sprintf(i18n('- updating user records : %s'),join(', ',$users_to_update));
|
||||
if ( sizeof($users_nothing_done) )
|
||||
$c->messages[] = sprintf(i18n('- nothing done on : %s'),join(', ', $users_nothing_done));
|
||||
}
|
||||
|
||||
// deactivating all users
|
||||
$params = array();
|
||||
$i = 0;
|
||||
foreach( $users_to_deactivate AS $v ) {
|
||||
if ( isset($c->do_not_sync_from_ldap) && isset($c->do_not_sync_from_ldap[$v]) ) continue;
|
||||
$params[':u'.$i++] = strtolower($v);
|
||||
}
|
||||
if ( count($params) > 0 ) {
|
||||
$c->messages[] = sprintf(i18n('- deactivating users : %s'),join(', ',$users_to_deactivate));
|
||||
$qry = new AwlQuery( 'UPDATE usr SET active = FALSE WHERE lower(username) IN ('.implode(',',array_keys($params)).')', $params);
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
}
|
||||
|
||||
// updating all users
|
||||
if ( sizeof($users_to_update) ) {
|
||||
foreach ( $users_to_update as $key=> $username ) {
|
||||
$valid=$ldap_users_info[$username];
|
||||
$ldap_timestamp = $valid[$mapping["updated"]];
|
||||
|
||||
$valid["user_no"] = $db_users_info[$username]["user_no"];
|
||||
$mapping["user_no"] = "user_no";
|
||||
|
||||
/**
|
||||
* This splits the LDAP timestamp apart and assigns values to $Y $m $d $H $M and $S
|
||||
*/
|
||||
foreach($c->authenticate_hook['config']['format_updated'] as $k => $v)
|
||||
$$k = substr($ldap_timestamp,$v[0],$v[1]);
|
||||
$ldap_timestamp = "$Y"."$m"."$d"."$H"."$M"."$S";
|
||||
$valid[$mapping["updated"]] = "$Y-$m-$d $H:$M:$S";
|
||||
|
||||
$db_timestamp = substr(strtr($db_users_info[$username]['updated'], array(':' => '',' '=>'','-'=>'')),0,14);
|
||||
if ( $ldap_timestamp > $db_timestamp ) {
|
||||
sync_user_from_LDAP($usr, $mapping, $valid );
|
||||
}
|
||||
else {
|
||||
unset($users_to_update[$key]);
|
||||
$users_nothing_done[] = $username;
|
||||
}
|
||||
}
|
||||
if ( sizeof($users_to_update) )
|
||||
$c->messages[] = sprintf(i18n('- updating user records : %s'),join(', ',$users_to_update));
|
||||
if ( sizeof($users_nothing_done) )
|
||||
$c->messages[] = sprintf(i18n('- nothing done on : %s'),join(', ', $users_nothing_done));
|
||||
}
|
||||
|
||||
$admins = 0;
|
||||
$qry = new AwlQuery( "select count(*) as admins from usr join role_member using ( user_no ) join roles using (role_no) where usr.active = true and role_name='Admin'");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while($db_user = $qry->Fetch()) {
|
||||
$admins = $db_user->admins;
|
||||
}
|
||||
if ( $admins == 0 ) {
|
||||
$c->messages[] = sprintf(i18n('Warning: there are no active admin users, you should fix this before logging out.'));
|
||||
}
|
||||
$admins = 0;
|
||||
$qry = new AwlQuery( "SELECT count(*) AS admins FROM usr JOIN role_member USING ( user_no ) JOIN roles USING (role_no) WHERE usr.active=TRUE AND role_name='Admin'");
|
||||
$qry->Exec('sync_LDAP',__LINE__,__FILE__);
|
||||
while ( $db_user = $qry->Fetch() ) {
|
||||
$admins = $db_user->admins;
|
||||
}
|
||||
if ( $admins == 0 ) {
|
||||
$c->messages[] = sprintf(i18n('Warning: there are no active admin users! You should fix this before logging out. Consider using the $c->do_not_sync_from_ldap configuration setting.'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@
|
||||
* @category Technical
|
||||
* @subpackage pwauth
|
||||
* @author Eric Seigne <eric.seigne@ryxeo.com>,
|
||||
* Michael B. Trausch <mike@trausch.us>
|
||||
* Michael B. Trausch <mike@trausch.us>,
|
||||
* Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Eric Seigne
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*
|
||||
* Based on drivers_squid_pam.php
|
||||
*/
|
||||
@ -42,8 +43,7 @@ class pwauthPamDrivers
|
||||
{
|
||||
global $c;
|
||||
if(!file_exists($config)) {
|
||||
$c->messages[] =
|
||||
sprintf(i18n('drivers_pwauth_pam : Unable to find %s file'), $config);
|
||||
$c->messages[] = sprintf(i18n('drivers_pwauth_pam : Unable to find %s file'), $config);
|
||||
$this->valid=false;
|
||||
return ;
|
||||
}
|
||||
@ -62,102 +62,101 @@ function PWAUTH_PAM_check($username, $password) {
|
||||
$pipe = popen(escapeshellarg($program), 'w');
|
||||
$authinfo = sprintf("%s\n%s\n", $username, $password);
|
||||
$written = fwrite($pipe, $authinfo);
|
||||
dbg_error_log('pwauth', 'Bytes written: %d of %d', $written,
|
||||
strlen($authinfo));
|
||||
dbg_error_log('pwauth', 'Bytes written: %d of %d', $written, strlen($authinfo));
|
||||
$return_status = pclose($pipe);
|
||||
|
||||
switch($return_status) {
|
||||
case 0:
|
||||
// STATUS_OK: Authentication succeeded.
|
||||
dbg_error_log('pwauth', 'User %s successfully authenticated', $username);
|
||||
if($user = getUserByName($username)) {
|
||||
return($user);
|
||||
} else {
|
||||
dbg_error_log('pwauth', 'User %s does not exist in local db, creating',
|
||||
$username);
|
||||
$fullname = exec(sprintf('getent passwd %s', escapeshellarg($username)));
|
||||
$fullname = preg_replace('{^[^:]+:[^:]+:\d+:\d+:([^:,]+)(,[^:]*):.*$}',
|
||||
'$1', $fullname);
|
||||
$user = (object) array('user_no' => 0,
|
||||
'username' => $username,
|
||||
'active' => 't',
|
||||
'email' => sprintf('%s@%s', $username,
|
||||
$email_base),
|
||||
'updated' => date('%r'),
|
||||
'fullname' => $fullname);
|
||||
|
||||
UpdateUserFromExternal($user);
|
||||
return($user);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
// STATUS_OK: Authentication succeeded.
|
||||
dbg_error_log('pwauth', 'User %s successfully authenticated', $username);
|
||||
$principal = new Principal('username',$username);
|
||||
if ( !$principal->Exists() ) {
|
||||
dbg_error_log('pwauth', 'User %s does not exist in local db, creating', $username);
|
||||
$pwent = posix_getpwnam($username);
|
||||
$gecos = explode(',',$pwent['gecos']);
|
||||
$fullname = $gecos[0];
|
||||
$principal->Create( array(
|
||||
'username' => $username,
|
||||
'user_active' => 't',
|
||||
'email' => sprintf('%s@%s', $username, $email_base),
|
||||
'fullname' => $fullname
|
||||
));
|
||||
if ( ! $principal->Exists() ) {
|
||||
dbg_error_log( "PAM", "Unable to create local principal for '%s'", $username );
|
||||
return false;
|
||||
}
|
||||
CreateHomeCalendar($username);
|
||||
}
|
||||
return $principal;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Note that for system configurations using PAM instead of
|
||||
* reading the password database directly, if PAM is unable to
|
||||
* read the password database, pwauth will return status 1.
|
||||
*/
|
||||
case 1:
|
||||
case 2:
|
||||
// (1) STATUS_UNKNOWN: Invalid username or password.
|
||||
// (2) STATUS_INVALID: Invalid password.
|
||||
dbg_error_log('pwauth', 'Invalid username or password (username: %s)',
|
||||
$username);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
// (1) STATUS_UNKNOWN: Invalid username or password.
|
||||
// (2) STATUS_INVALID: Invalid password.
|
||||
dbg_error_log('pwauth', 'Invalid username or password (username: %s)', $username);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// STATUS_BLOCKED: UID for username is < pwauth's MIN_UNIX_UID
|
||||
dbg_error_log('pwauth', 'UID for username %s is < pwauth MIN_UNIX_UID',
|
||||
$username);
|
||||
break;
|
||||
case 3:
|
||||
// STATUS_BLOCKED: UID for username is < pwauth's MIN_UNIX_UID
|
||||
dbg_error_log('pwauth', 'UID for username %s is < pwauth MIN_UNIX_UID',
|
||||
$username);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// STATUS_EXPIRED: The user account has expired.
|
||||
dbg_error_log('pwauth', 'The account for %s has expired', $username);
|
||||
break;
|
||||
case 4:
|
||||
// STATUS_EXPIRED: The user account has expired.
|
||||
dbg_error_log('pwauth', 'The account for %s has expired', $username);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// STATUS_PW_EXPIRED: The user account's password has expired.
|
||||
dbg_error_log('pwauth', 'The account password for user %s has expired',
|
||||
$username);
|
||||
break;
|
||||
case 5:
|
||||
// STATUS_PW_EXPIRED: The user account's password has expired.
|
||||
dbg_error_log('pwauth', 'The account password for user %s has expired',
|
||||
$username);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// STATUS_NOLOGIN: Logins to the system are administratively disabled.
|
||||
dbg_error_log('pwauth', 'Logins administratively disabled (%s)', $username);
|
||||
break;
|
||||
case 6:
|
||||
// STATUS_NOLOGIN: Logins to the system are administratively disabled.
|
||||
dbg_error_log('pwauth', 'Logins administratively disabled (%s)', $username);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
// STATUS_MANYFAILS: Too many login failures for user account.
|
||||
dbg_error_log('pwauth', 'Login rejected for %s, too many failures',
|
||||
$username);
|
||||
break;
|
||||
case 7:
|
||||
// STATUS_MANYFAILS: Too many login failures for user account.
|
||||
dbg_error_log('pwauth', 'Login rejected for %s, too many failures',
|
||||
$username);
|
||||
break;
|
||||
|
||||
case 50:
|
||||
// STATUS_INT_USER: Configuration error, Web server cannot use pwauth
|
||||
dbg_error_log('pwauth', 'config error: see pwauth man page (%s)',
|
||||
'STATUS_INT_USER');
|
||||
break;
|
||||
case 50:
|
||||
// STATUS_INT_USER: Configuration error, Web server cannot use pwauth
|
||||
dbg_error_log('pwauth', 'config error: see pwauth man page (%s)',
|
||||
'STATUS_INT_USER');
|
||||
break;
|
||||
|
||||
case 51:
|
||||
// STATUS_INT_ARGS: pwauth received no username/passwd to check
|
||||
dbg_error_log('pwauth', 'error: pwauth received no username/password');
|
||||
break;
|
||||
case 51:
|
||||
// STATUS_INT_ARGS: pwauth received no username/passwd to check
|
||||
dbg_error_log('pwauth', 'error: pwauth received no username/password');
|
||||
break;
|
||||
|
||||
case 52:
|
||||
// STATUS_INT_ERR: unknown error
|
||||
dbg_error_log('pwauth', 'error: see pwauth man page (%s)',
|
||||
'STATUS_INT_ERR');
|
||||
break;
|
||||
case 52:
|
||||
// STATUS_INT_ERR: unknown error
|
||||
dbg_error_log('pwauth', 'error: see pwauth man page (%s)',
|
||||
'STATUS_INT_ERR');
|
||||
break;
|
||||
|
||||
case 53:
|
||||
// STATUS_INT_NOROOT: pwauth could not read the password database
|
||||
dbg_error_log('pwauth', 'config error: cannot read password database (%s)',
|
||||
'STATUS_INT_NOROOT');
|
||||
|
||||
default:
|
||||
// Unknown error code.
|
||||
dbg_error_log('pwauth', 'An unknown error (%d) has occurred',
|
||||
$return_status);
|
||||
case 53:
|
||||
// STATUS_INT_NOROOT: pwauth could not read the password database
|
||||
dbg_error_log('pwauth', 'config error: cannot read password database (%s)',
|
||||
'STATUS_INT_NOROOT');
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown error code.
|
||||
dbg_error_log('pwauth', 'An unknown error (%d) has occurred',
|
||||
$return_status);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
|
||||
@ -5,9 +5,10 @@
|
||||
* @package davical
|
||||
* @category Technical
|
||||
* @subpackage ldap
|
||||
* @author Eric Seigne <eric.seigne@ryxeo.com>
|
||||
* @author Eric Seigne <eric.seigne@ryxeo.com>,
|
||||
* Andrew McMillan <andrew@mcmillan.net.nz>
|
||||
* @copyright Eric Seigne
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
|
||||
* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
|
||||
*/
|
||||
|
||||
require_once("auth-functions.php");
|
||||
@ -53,34 +54,30 @@ class squidPamDrivers
|
||||
function SQUID_PAM_check($username, $password ){
|
||||
global $c;
|
||||
|
||||
/**
|
||||
* @todo Think of the children! This is a horribly insecure use of unvalidated user input! Probably it should be done with a popen or something, and it seems remarkably dodgy to expect that naively quoted strings will work in any way reliably.
|
||||
* Meanwhile, I've quickly hacked something basic in place to improve the situation. No quotes/backslashes in passwords for YOU!
|
||||
*/
|
||||
$username = str_replace("'","",str_replace('"',"",str_replace('\\',"",$username)));
|
||||
$password = str_replace("'","",str_replace('"',"",str_replace('\\',"",$password)));
|
||||
$cmd = "echo '" . $username . "' '" . $password . "' | " . $c->authenticate_hook['config']['script'] . " -n common-auth";
|
||||
$cmd = sprintf( 'echo %s %s | %s -n common-auth', escapeshellarg($username), escapeshellarg($password),
|
||||
$c->authenticate_hook['config']['script']);
|
||||
$auth_result = exec($cmd);
|
||||
if ( $auth_result == "OK") {
|
||||
if ( $usr = getUserByName($username) ) {
|
||||
return $usr;
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PAM", "user %s doesn't exist in local DB, we need to create it",$username );
|
||||
$fullname = exec('getent passwd "'.$username.'"' );
|
||||
$fullname = preg_replace( '{^[^:]+:[^:]+:\d+:\d+:([^:,]+)(,?[^:]*):.*$}', '$1', $fullname );
|
||||
$usr = (object) array(
|
||||
'user_no' => 0,
|
||||
'username' => $username,
|
||||
'active' => 't',
|
||||
'email' => $username . "@" . $c->authenticate_hook['config']['email_base'],
|
||||
'updated' => date(),
|
||||
'fullname' => $fullname
|
||||
);
|
||||
|
||||
UpdateUserFromExternal( $usr );
|
||||
return $usr;
|
||||
dbg_error_log('pwauth', 'User %s successfully authenticated', $username);
|
||||
$principal = new Principal('username',$username);
|
||||
if ( !$principal->Exists() ) {
|
||||
dbg_error_log('pwauth', 'User %s does not exist in local db, creating', $username);
|
||||
$pwent = posix_getpwnam($username);
|
||||
$gecos = explode(',',$pwent['gecos']);
|
||||
$fullname = $gecos[0];
|
||||
$principal->Create( array(
|
||||
'username' => $username,
|
||||
'user_active' => 't',
|
||||
'email' => sprintf('%s@%s', $username, $email_base),
|
||||
'fullname' => $fullname
|
||||
));
|
||||
if ( ! $principal->Exists() ) {
|
||||
dbg_error_log( "PAM", "Unable to create local principal for '%s'", $username );
|
||||
return false;
|
||||
}
|
||||
CreateHomeCalendar($username);
|
||||
}
|
||||
return $principal;
|
||||
}
|
||||
else {
|
||||
dbg_error_log( "PAM", "User %s is not a valid username (or password was wrong)", $username );
|
||||
|
||||
@ -6,8 +6,8 @@ param_to_global('id', 'int', 'old_id', 'collection_id' );
|
||||
param_to_global('user_no', 'int' );
|
||||
param_to_global('principal_id', 'int' );
|
||||
param_to_global('collection_name', '{^.+$}' );
|
||||
if ( isset($user_no) ) $usr = getUserByID($user_no);
|
||||
if ( isset($principal_id) ) $usr = getPrincipalByID($principal_id);
|
||||
if ( isset($user_no) ) $principal = new Principal('user_no',$user_no);
|
||||
if ( isset($principal_id) ) $principal = new Principal('principal_id',$principal_id);
|
||||
$editor->SetLookup( 'timezone', 'SELECT \'\', \'*** Unknown ***\' UNION SELECT tz_id, tz_locn FROM time_zone WHERE tz_id = tz_locn AND length(tz_spec) > 100 ORDER BY 1' );
|
||||
$editor->SetLookup( 'schedule_transp', 'SELECT \'opaque\', \'Opaque\' UNION SELECT \'transp\', \'Transparent\'' );
|
||||
|
||||
@ -39,9 +39,9 @@ $params = array(
|
||||
);
|
||||
$is_update = ( $_POST['_editor_action'][$editor->Id] == 'update' );
|
||||
if ( isset($collection_name) ) $collection_name = trim(str_replace( '/', '', $collection_name));
|
||||
if ( !$is_update && isset($collection_name) && $collection_name != '' && is_object($usr) ) {
|
||||
$_POST['dav_name'] = sprintf('/%s/%s/', $usr->username, $collection_name );
|
||||
$_POST['parent_container'] = sprintf('/%s/', $usr->username );
|
||||
if ( !$is_update && isset($collection_name) && $collection_name != '' && is_object($principal) ) {
|
||||
$_POST['dav_name'] = sprintf('/%s/%s/', $principal->username(), $collection_name );
|
||||
$_POST['parent_container'] = sprintf('/%s/', $principal->username() );
|
||||
$params[':collection_path'] = $_POST['dav_name'];
|
||||
$privsql = 'SELECT path_privs( :session_principal, :collection_path, :scan_depth) AS priv';
|
||||
}
|
||||
@ -137,8 +137,8 @@ else {
|
||||
$c->page_title = $editor->Title(translate('Create New Collection'));
|
||||
$privs = decbin(privilege_to_bits($c->default_privileges));
|
||||
$editor->Assign('default_privileges', $privs);
|
||||
$editor->Assign('username', $usr->username);
|
||||
$editor->Assign('user_no', $usr->user_no);
|
||||
$editor->Assign('username', $principal->username());
|
||||
$editor->Assign('user_no', $principal->user_no());
|
||||
$editor->Assign('is_calendar', 't' );
|
||||
$editor->Assign('use_default_privs', 't');
|
||||
$entries = 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user