diff --git a/htdocs/always.php b/htdocs/always.php
index f3a816bb..2f41cfe7 100644
--- a/htdocs/always.php
+++ b/htdocs/always.php
@@ -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
diff --git a/htdocs/freebusy.php b/htdocs/freebusy.php
index e876d6bb..8be903e2 100644
--- a/htdocs/freebusy.php
+++ b/htdocs/freebusy.php
@@ -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 );
diff --git a/htdocs/tools.php b/htdocs/tools.php
index 39335696..3aaa6307 100644
--- a/htdocs/tools.php
+++ b/htdocs/tools.php
@@ -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);
diff --git a/inc/CalDAVRequest.php b/inc/CalDAVRequest.php
index 84adcb89..22aae37b 100644
--- a/inc/CalDAVRequest.php
+++ b/inc/CalDAVRequest.php
@@ -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;
diff --git a/inc/CalDAVPrincipal.php b/inc/DAVPrincipal.php
similarity index 67%
rename from inc/CalDAVPrincipal.php
rename to inc/DAVPrincipal.php
index 19184546..6cbcc93c 100644
--- a/inc/CalDAVPrincipal.php
+++ b/inc/DAVPrincipal.php
@@ -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.
diff --git a/inc/DAVResource.php b/inc/DAVResource.php
index e116b606..3addb3cd 100644
--- a/inc/DAVResource.php
+++ b/inc/DAVResource.php
@@ -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 = '';
- $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 */
diff --git a/inc/HTTPAuthSession.php b/inc/HTTPAuthSession.php
index 52100659..5350c71e 100644
--- a/inc/HTTPAuthSession.php
+++ b/inc/HTTPAuthSession.php
@@ -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 != "" ) {
diff --git a/inc/Principal.php b/inc/Principal.php
new file mode 100644
index 00000000..36888a55
--- /dev/null
+++ b/inc/Principal.php
@@ -0,0 +1,465 @@
+
+* @copyright Morphoss Ltd
+* @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);
+ }
+}
diff --git a/inc/PublicSession.php b/inc/PublicSession.php
index 36bf6302..560ad9aa 100644
--- a/inc/PublicSession.php
+++ b/inc/PublicSession.php
@@ -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;
diff --git a/inc/always.php.in b/inc/always.php.in
index bb0c9d73..2f41cfe7 100644
--- a/inc/always.php.in
+++ b/inc/always.php.in
@@ -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
diff --git a/inc/auth-functions.php b/inc/auth-functions.php
index cd090051..4715e58d 100644
--- a/inc/auth-functions.php
+++ b/inc/auth-functions.php
@@ -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' => ''
+ );
+ $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' => ''
- );
- $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;
}
}
diff --git a/inc/caldav-ACL.php b/inc/caldav-ACL.php
index 06d78a92..b57a0fd9 100644
--- a/inc/caldav-ACL.php
+++ b/inc/caldav-ACL.php
@@ -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__);
diff --git a/inc/caldav-OPTIONS.php b/inc/caldav-OPTIONS.php
index 10f8da45..1cd3daaf 100644
--- a/inc/caldav-OPTIONS.php
+++ b/inc/caldav-OPTIONS.php
@@ -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.") );
diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php
index 70eba6d5..732cc2fc 100644
--- a/inc/caldav-PUT-functions.php
+++ b/inc/caldav-PUT-functions.php
@@ -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.');
}
diff --git a/inc/drivers_imap_pam.php b/inc/drivers_imap_pam.php
index 7c6daec8..c8b46dae 100644
--- a/inc/drivers_imap_pam.php
+++ b/inc/drivers_imap_pam.php
@@ -5,9 +5,10 @@
* @package davical
* @category Technical
* @subpackage ldap
-* @author Oliver Schulze
+* @author Oliver Schulze ,
+* Andrew McMillan
* @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 );
diff --git a/inc/drivers_ldap.php b/inc/drivers_ldap.php
index 30518175..2f5a6519 100644
--- a/inc/drivers_ldap.php
+++ b/inc/drivers_ldap.php
@@ -5,7 +5,8 @@
* @package davical
* @category Technical
* @subpackage ldap
-* @author Maxime Delorme
+* @author Maxime Delorme ,
+* Andrew McMillan
* @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.'));
}
}
diff --git a/inc/drivers_pwauth_pam.php b/inc/drivers_pwauth_pam.php
index d01fcc15..8564a800 100644
--- a/inc/drivers_pwauth_pam.php
+++ b/inc/drivers_pwauth_pam.php
@@ -6,9 +6,10 @@
* @category Technical
* @subpackage pwauth
* @author Eric Seigne ,
- * Michael B. Trausch
+ * Michael B. Trausch ,
+ * Andrew McMillan
* @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);
diff --git a/inc/drivers_squid_pam.php b/inc/drivers_squid_pam.php
index 41139220..82637616 100644
--- a/inc/drivers_squid_pam.php
+++ b/inc/drivers_squid_pam.php
@@ -5,9 +5,10 @@
* @package davical
* @category Technical
* @subpackage ldap
-* @author Eric Seigne
+* @author Eric Seigne ,
+* Andrew McMillan
* @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 );
diff --git a/inc/ui/collection-edit.php b/inc/ui/collection-edit.php
index 6c66db4a..b1e6dfd3 100644
--- a/inc/ui/collection-edit.php
+++ b/inc/ui/collection-edit.php
@@ -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;