Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2571985
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/init.php b/lib/init.php
index e41bdca..8a96b68 100644
--- a/lib/init.php
+++ b/lib/init.php
@@ -1,120 +1,121 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
// Roundcube Framework constants
define('RCMAIL_START', microtime(true));
define('RCMAIL_VERSION', '0.9-git');
define('RCMAIL_CHARSET', 'UTF-8');
define('INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/');
define('RCMAIL_CONFIG_DIR', INSTALL_PATH . 'config');
+define('RCMAIL_PLUGINS_DIR', INSTALL_PATH . 'plugins');
// PHP configuration
$config = array(
'error_reporting' => E_ALL &~ (E_NOTICE | E_STRICT),
'mbstring.func_overload' => 0,
// 'suhosin.session.encrypt' => 0,
// 'session.auto_start' => 0,
// 'file_uploads' => 1,
'magic_quotes_runtime' => 0,
'magic_quotes_sybase' => 0,
);
foreach ($config as $optname => $optval) {
if ($optval != ini_get($optname) && @ini_set($optname, $optval) === false) {
die("ERROR: Wrong '$optname' option value!");
}
}
// Define include path
$include_path = INSTALL_PATH . 'lib' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'lib/kolab' . PATH_SEPARATOR;
$include_path .= INSTALL_PATH . 'lib/ext/Roundcube' . PATH_SEPARATOR;
$include_path .= ini_get('include_path');
set_include_path($include_path);
// @TODO: what is a reasonable value for ActiveSync?
@set_time_limit(600);
// set internal encoding for mbstring extension
if (extension_loaded('mbstring')) {
mb_internal_encoding(RCMAIL_CHARSET);
@mb_regex_encoding(RCMAIL_CHARSET);
}
// include global functions from Roundcube Framework
require_once 'rcube_shared.inc';
// Register main autoloader
spl_autoload_register('kolab_sync_autoload');
// set PEAR error handling (will also load the PEAR main class)
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
// Autoloader for Syncroton
//require_once 'Zend/Loader/Autoloader.php';
//$autoloader = Zend_Loader_Autoloader::getInstance();
//$autoloader->setFallbackAutoloader(true);
/**
* Use PHP5 autoload for dynamic class loading
*/
function kolab_sync_autoload($classname)
{
// Roundcube Framework
$filename = preg_replace(
array(
'/Mail_(.+)/',
'/Net_(.+)/',
'/Auth_(.+)/',
'/^html_.+/',
'/^utf8$/',
),
array(
'Mail/\\1',
'Net/\\1',
'Auth/\\1',
'html',
'utf8.class',
),
$classname
);
if ($fp = @fopen("$filename.php", 'r', true)) {
fclose($fp);
include_once "$filename.php";
return true;
}
// Syncroton, replacement for Zend autoloader
$filename = str_replace('_', DIRECTORY_SEPARATOR, $classname);
if ($fp = @fopen("$filename.php", 'r', true)) {
fclose($fp);
include_once "$filename.php";
return true;
}
return false;
}
diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php
index f34df68..ab0e3d5 100644
--- a/lib/kolab_sync.php
+++ b/lib/kolab_sync.php
@@ -1,335 +1,314 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* Main application class (based on Roundcube Framework)
*/
class kolab_sync extends rcube
{
/**
* Application name
*
* @var string
*/
public $app_name = 'ActiveSync for Kolab'; // no double quotes inside
/**
* Current user
*
* @var rcube_user
*/
public $user;
- private $data = array();
-
const CHARSET = 'UTF-8';
- const VERSION = "1.1";
+ const VERSION = "2.0";
/**
* This implements the 'singleton' design pattern
*
* @return kolab_sync The one and only instance
*/
static function get_instance()
{
if (!self::$instance || !is_a(self::$instance, 'kolab_sync')) {
self::$instance = new kolab_sync();
self::$instance->startup(); // init AFTER object was linked with self::$instance
}
return self::$instance;
}
public function startup()
{
// Initialize Syncroton Logger
$debug_mode = $this->config->get('activesync_debug') ? kolab_sync_logger::DEBUG : kolab_sync_logger::WARN;
$this->logger = new kolab_sync_logger($debug_mode);
+
+ // Get list of plugins
+ // WARNING: We can use only plugins that are prepared for this
+ // e.g. are not using output or rcmail objects or
+ // doesn't throw errors when using them
+ $plugins = (array)$this->config->get('activesync_plugins');
+
+ // Initialize/load plugins
+ $this->plugins = kolab_sync_plugin_api::get_instance();
+ $this->plugins->init($this, $this->task);
+ $this->plugins->load_plugins($plugins);
}
/**
* Application execution (authentication and ActiveSync)
*/
public function run()
{
+ $this->plugins->exec_hook('startup', array('task' => 'login'));
+
// when used with (f)cgi no PHP_AUTH* variables are available without defining a special rewrite rule
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// "Basic didhfiefdhfu4fjfjdsa34drsdfterrde..."
if (isset($_SERVER["REMOTE_USER"])) {
$basicAuthData = base64_decode(substr($_SERVER["REMOTE_USER"], 6));
} elseif (isset($_SERVER["REDIRECT_REMOTE_USER"])) {
$basicAuthData = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6));
} elseif (isset($_SERVER["Authorization"])) {
$basicAuthData = base64_decode(substr($_SERVER["Authorization"], 6));
} elseif (isset($_SERVER["HTTP_AUTHORIZATION"])) {
$basicAuthData = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6));
}
if (isset($basicAuthData) && !empty($basicAuthData)) {
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(":", $basicAuthData);
}
}
if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) {
// Convert domain.tld\username into username@domain (?)
$username = explode("\\", $_SERVER['PHP_AUTH_USER']);
if (count($username) == 2) {
$_SERVER['PHP_AUTH_USER'] = $username[1];
if (!strpos($_SERVER['PHP_AUTH_USER'], '@') && !empty($username[0])) {
$_SERVER['PHP_AUTH_USER'] .= '@' . $username[0];
}
}
$userid = $this->authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
}
if (empty($userid)) {
header('WWW-Authenticate: Basic realm="' . $this->app_name .'"');
header('HTTP/1.1 401 Unauthorized');
exit;
}
// Register Syncroton backends
Syncroton_Registry::set('loggerBackend', $this->logger);
Syncroton_Registry::set(Syncroton_Registry::DATABASE, new kolab_sync_db);
Syncroton_Registry::set(Syncroton_Registry::TRANSACTIONMANAGER, kolab_sync_transaction_manager::getInstance());
Syncroton_Registry::set(Syncroton_Registry::DEVICEBACKEND, new kolab_sync_backend_device);
Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND, new kolab_sync_backend_folder);
Syncroton_Registry::set(Syncroton_Registry::SYNCSTATEBACKEND, new kolab_sync_backend_state);
Syncroton_Registry::set(Syncroton_Registry::CONTENTSTATEBACKEND, new kolab_sync_backend_content);
Syncroton_Registry::set(Syncroton_Registry::POLICYBACKEND, new kolab_sync_backend_policy);
Syncroton_Registry::setContactsDataClass('kolab_sync_data_contacts');
Syncroton_Registry::setCalendarDataClass('kolab_sync_data_calendar');
Syncroton_Registry::setEmailDataClass('kolab_sync_data_email');
Syncroton_Registry::setTasksDataClass('kolab_sync_data_tasks');
Syncroton_Registry::setGALDataClass('kolab_sync_data_gal');
// Run Syncroton
$syncroton = new Syncroton_Server($userid);
$syncroton->handle();
}
/**
- * Authenticates a user in LDAP and Roundcube
+ * Authenticates a user
+ *
+ * @param string $username User name
+ * @param string $password User password
+ *
+ * @param int User ID
*/
public function authenticate($username, $password)
{
- // Get IMAP host
- $host = $this->config->get('default_host');
- $host = rcube_utils::parse_host($host);
-
- // Get user
- $user = $this->get_ldap_user($username, $host);
-
- // Get Roundcube user ID
- $userid = $this->get_rcube_user($user, $password, $host);
-
- return $userid;
- }
-
-
- /**
- * Returns user login attribute from LDAP server
- */
- private function get_ldap_user($username, $host)
- {
- @include_once(RCMAIL_CONFIG_DIR . "/kolab_auth.inc.php");
-
- $login_attr = $this->config->get('kolab_auth_login');
- $addressbook = $this->config->get('kolab_auth_addressbook');
- $filter = $this->config->get('kolab_auth_filter');
- $filter = $this->parse_vars($filter, $username, $host);
-
- if (!is_array($addressbook)) {
- $ldap_config = (array)$this->config->get('ldap_public');
- $addressbook = $ldap_config[$addressbook];
- }
-
- if (empty($addressbook)) {
- $this->logger->warn("No address book configured to authenticate the user.");
- return null;
+ $auth = $this->plugins->exec_hook('authenticate', array(
+ 'host' => $this->select_host($username),
+ 'user' => $username,
+ 'pass' => $password,
+ 'valid' => true,
+ ));
+
+ // Authenticate - get Roundcube user ID
+ if ($auth['valid'] && !$auth['abort']
+ && ($userid = $this->login($auth['user'], $auth['pass'], $auth['host']))) {
+ return $userid;
}
- if (empty($login_attr)) {
- $this->logger->warn("No login attribute configured.");
- return null;
- }
-
- $addressbook['filter'] = $filter;
- $addressbook['sizelimit'] = 2;
-
- $this->ldap = new rcube_ldap(
- $addressbook,
- $this->config->get('ldap_debug'),
- $this->config->mail_domain($host)
- );
-
- if (!$this->ldap->ready) {
- return null;
- }
-
- // get record
- $results = $this->ldap->list_records();
-
- if (count($results->records) != 1) {
- return null;
- }
-
- if ($record = $results->records[0]) {
- return is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr];
- }
+ $this->plugins->exec_hook('login_failed', array(
+ 'host' => $auth['host'],
+ 'user' => $auth['user'],
+ ));
}
/**
- * Prepares filter query for LDAP search
+ * Storage host selection
*/
- private function parse_vars($str, $user, $host)
+ private function select_host($username)
{
- $domain = $this->config->get('username_domain');
+ // Get IMAP host
+ $host = $this->config->get('default_host');
+
+ if (is_array($host)) {
+ list($user, $domain) = explode('@', $username);
+
+ // try to select host by mail domain
+ if (!empty($domain)) {
+ foreach ($host as $storage_host => $mail_domains) {
+ if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) {
+ $host = $storage_host;
+ break;
+ }
+ else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) {
+ $host = is_numeric($storage_host) ? $mail_domains : $storage_host;
+ break;
+ }
+ }
+ }
- if (!empty($domain) && strpos($user, '@') === false) {
- if (is_array($domain) && isset($domain[$host]))
- $user .= '@'.rcube_utils::parse_host($domain[$host], $host);
- else if (is_string($domain))
- $user .= '@'.rcube_utils::parse_host($domain, $host);
+ // take the first entry if $host is not found
+ if (is_array($host)) {
+ list($key, $val) = each($default_host);
+ $host = is_numeric($key) ? $val : $key;
+ }
}
- // replace variables in filter
- list($u, $d) = explode('@', $user);
- $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string
- $replaces = array('%dc' => $dc, '%d' => $d, '%fu' => $user, '%u' => $u);
-
- return strtr($str, $replaces);
+ return rcube_utils::parse_host($host);
}
/**
- * Returns Roundcube user ID for specified username and host.
- * Also sets IMAP connection credentials.
+ * Authenticates a user in IMAP and returns Roundcube user ID.
*/
- private function get_rcube_user($username, $password, $host)
+ private function login($username, $password, $host)
{
if (empty($username)) {
return null;
}
$login_lc = $this->config->get('login_lc');
// parse $host
$a_host = parse_url($host);
if ($a_host['host']) {
$host = $a_host['host'];
$ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null;
if (!empty($a_host['port'])) {
$port = $a_host['port'];
}
else if ($ssl && $ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) {
$port = 993;
}
}
if (!$port) {
$port = $this->config->get('default_port');
}
// Convert username to lowercase. If storage backend
// is case-insensitive we need to store always the same username
if ($login_lc) {
if ($login_lc == 2 || $login_lc === true) {
$username = mb_strtolower($username);
}
else if (strpos($username, '@')) {
// lowercase domain name
list($local, $domain) = explode('@', $username);
$username = $local . '@' . mb_strtolower($domain);
}
}
// Here we need IDNA ASCII
// Only rcube_contacts class is using domain names in Unicode
$host = rcube_utils::idn_to_ascii($host);
$username = rcube_utils::idn_to_ascii($username);
// user already registered?
$user = rcube_user::query($username, $host);
if (!is_object($user)) {
// @TODO: log error
return null;
}
// Configure environment
$this->user = $user;
$username = $user->data['username'];
// authenticate user in IMAP
$storage = $this->get_storage();
if (!$storage->connect($host, $username, $password, $port, $ssl)) {
return null;
}
// overwrite config with user preferences
$this->config->set_user_prefs((array)$this->user->get_prefs());
$this->set_storage_prop();
setlocale(LC_ALL, 'en_US.utf8', 'en_US.UTF-8');
// force reloading of mailboxes list/data
//$storage->clear_cache('mailboxes', true);
return $user->ID;
}
/**
* Function to be executed in script shutdown
*/
public function shutdown()
{
parent::shutdown();
- if ($this->ldap) {
- $this->ldap->close();
- }
-
// write performance stats to logs/console
if ($this->config->get('devel_mode')) {
if (function_exists('memory_get_usage'))
$mem = sprintf('%.1f', memory_get_usage() / 1048576);
if (function_exists('memory_get_peak_usage'))
$mem .= '/' . sprintf('%.1f', memory_get_peak_usage() / 1048576);
- $log = $_SERVER['QUERY_STRING'] . ($mem ? " [$mem]" : '');
+ $query = $_SERVER['QUERY_STRING'];
+ $log = $query . ($mem ? ($query ? ' ' : '') . "[$mem]" : '');
+
if (defined('RCMAIL_START'))
self::print_timer(RCMAIL_START, $log);
else
self::console($log);
}
}
}
diff --git a/lib/kolab_sync_plugin_api.php b/lib/kolab_sync_plugin_api.php
new file mode 100644
index 0000000..1b7bac4
--- /dev/null
+++ b/lib/kolab_sync_plugin_api.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ +--------------------------------------------------------------------------+
+ | Kolab Sync (ActiveSync for Kolab) |
+ | |
+ | Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
+ | |
+ | This program is free software: you can redistribute it and/or modify |
+ | it under the terms of the GNU Affero General Public License as published |
+ | by the Free Software Foundation, either version 3 of the License, or |
+ | (at your option) any later version. |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public License |
+ | along with this program. If not, see <http://www.gnu.org/licenses/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak@kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * The plugin loader and global API
+ *
+ * @package PluginAPI
+ */
+class kolab_sync_plugin_api extends rcube_plugin_api
+{
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return rcube_plugin_api The one and only instance if this class
+ */
+ static function get_instance()
+ {
+ if (!self::$instance) {
+ self::$instance = new kolab_sync_plugin_api();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Initialize plugin engine
+ *
+ * This has to be done after rcmail::load_gui() or rcmail::json_init()
+ * was called because plugins need to have access to rcmail->output
+ *
+ * @param object rcube Instance of the rcube base class
+ * @param string Current application task (used for conditional plugin loading)
+ */
+ public function init($app, $task = '')
+ {
+ $this->task = $task;
+ }
+
+
+ /**
+ * Register a handler function for template objects
+ *
+ * @param string $name Object name
+ * @param string $owner Plugin name that registers this action
+ * @param mixed $callback Callback: string with global function name or array($obj, 'methodname')
+ */
+ public function register_handler($name, $owner, $callback)
+ {
+ // empty
+ }
+
+
+ /**
+ * Register this plugin to be responsible for a specific task
+ *
+ * @param string $task Task name (only characters [a-z0-9_.-] are allowed)
+ * @param string $owner Plugin name that registers this action
+ */
+ public function register_task($task, $owner)
+ {
+ $this->tasks[$task] = $owner;
+ }
+
+
+ /**
+ * Include a plugin script file in the current HTML page
+ *
+ * @param string $fn Path to script
+ */
+ public function include_script($fn)
+ {
+ //empty
+ }
+
+
+ /**
+ * Include a plugin stylesheet in the current HTML page
+ *
+ * @param string $fn Path to stylesheet
+ */
+ public function include_stylesheet($fn)
+ {
+ //empty
+ }
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Mar 19, 1:32 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
458661
Default Alt Text
(23 KB)
Attached To
Mode
R4 syncroton
Attached
Detach File
Event Timeline
Log In to Comment