/** * Initializes the logging * * @access public * @return boolean */ public static function Initialize() { global $specialLogUsers; // define some constants for the logging if (!defined('LOGUSERLEVEL')) { define('LOGUSERLEVEL', LOGLEVEL_OFF); } if (!defined('LOGLEVEL')) { define('LOGLEVEL', LOGLEVEL_OFF); } list($user, ) = Utils::SplitDomainUser(Request::GetGETUser()); if (!defined('WBXML_DEBUG') && $user) { // define the WBXML_DEBUG mode on user basis depending on the configurations if (LOGLEVEL >= LOGLEVEL_WBXML || LOGUSERLEVEL >= LOGLEVEL_WBXML && in_array($user, $specialLogUsers)) { define('WBXML_DEBUG', true); } else { define('WBXML_DEBUG', false); } } if ($user) { self::$user = '******' . $user . '] '; } else { self::$user = ''; } // log the device id if the global loglevel is set to log devid or the user is in and has the right log level if (Request::GetDeviceID() != "" && (LOGLEVEL >= LOGLEVEL_DEVICEID || LOGUSERLEVEL >= LOGLEVEL_DEVICEID && in_array($user, $specialLogUsers))) { self::$devid = '[' . Request::GetDeviceID() . '] '; } else { self::$devid = ''; } return true; }
/** * Handles a webservice command * * @param int $commandCode * * @access public * @return boolean * @throws SoapFault */ public function Handle($commandCode) { if (Request::GetDeviceType() !== "webservice" || Request::GetDeviceID() !== "webservice") { throw new FatalException("Invalid device id and type for webservice execution"); } if (Request::GetGETUser() != Request::GetAuthUser()) { ZLog::Write(LOGLEVEL_INFO, sprintf("Webservice::HandleWebservice('%s'): user '%s' executing action for user '%s'", $commandCode, Request::GetAuthUser(), Request::GetGETUser())); } // initialize non-wsdl soap server $this->server = new SoapServer(null, array('uri' => "http://z-push.sf.net/webservice")); // the webservice command is handled by its class if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceDevice service", $commandCode)); include_once 'webservicedevice.php'; $this->server->setClass("WebserviceDevice"); } // the webservice command is handled by its class if ($commandCode == ZPush::COMMAND_WEBSERVICE_USERS) { if (!defined("ALLOW_WEBSERVICE_USERS_ACCESS") || ALLOW_WEBSERVICE_USERS_ACCESS !== true) { throw new HTTPReturnCodeException(sprintf("Access to the WebserviceUsers service is disabled in configuration. Enable setting ALLOW_WEBSERVICE_USERS_ACCESS.", Request::GetAuthUser()), 403); } ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceUsers service", $commandCode)); if (ZPush::GetBackend()->Setup("SYSTEM", true) == false) { throw new AuthenticationRequiredException(sprintf("User '%s' has no admin privileges", Request::GetAuthUser())); } include_once 'webserviceusers.php'; $this->server->setClass("WebserviceUsers"); } $this->server->handle(); ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): sucessfully sent %d bytes", $commandCode, ob_get_length())); return true; }
/** * Authenticates the remote user * The sent HTTP authentication information is used to on Backend->Logon(). * As second step the GET-User verified by Backend->Setup() for permission check * Request::GetGETUser() is usually the same as the Request::GetAuthUser(). * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin * permissions on GETUsers data store. Only then the Setup() will be sucessfull. * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges. * * @access public * @return * @throws AuthenticationRequiredException */ public static function Authenticate() { self::$userIsAuthenticated = false; $backend = ZPush::GetBackend(); if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) { throw new AuthenticationRequiredException("Access denied. Username or password incorrect"); } // mark this request as "authenticated" self::$userIsAuthenticated = true; // check Auth-User's permissions on GETUser's store if ($backend->Setup(Request::GetGETUser(), true) == false) { throw new AuthenticationRequiredException(sprintf("Not enough privileges of '%s' to setup for user '%s': Permission denied", Request::GetAuthUser(), Request::GetGETUser())); } }
/** * Returns a list of folders of the Request::GetGETUser(). * If the user has not enough permissions an empty result is returned. * * @access public * @return array */ public function ListUserFolders() { $user = Request::GetGETUser(); $output = array(); $hasRights = ZPush::GetBackend()->Setup($user); ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceInfo::ListUserFolders(): permissions to open store '%s': %s", $user, Utils::PrintAsString($hasRights))); if ($hasRights) { $folders = ZPush::GetBackend()->GetHierarchy(); ZPush::GetTopCollector()->AnnounceInformation(sprintf("Retrieved details of %d folders", count($folders)), true); foreach ($folders as $folder) { $folder->StripData(); unset($folder->Store, $folder->flags, $folder->content, $folder->NoBackendFolder); $output[] = $folder; } } return $output; }
/** * Handles a webservice command * * @param int $commandCode * * @access public * @return boolean * @throws SoapFault */ public function Handle($commandCode) { if (Request::GetDeviceType() !== "webservice" || Request::GetDeviceID() !== "webservice") { throw new FatalException("Invalid device id and type for webservice execution"); } if (Request::GetGETUser() != Request::GetAuthUser()) { ZLog::Write(LOGLEVEL_INFO, sprintf("Webservice::HandleWebservice('%s'): user '%s' executing action for user '%s'", $commandCode, Request::GetAuthUser(), Request::GetGETUser())); } // initialize non-wsdl soap server $this->server = new SoapServer(null, array('uri' => "http://z-push.sf.net/webservice")); // the webservice command is handled by its class if ($commandCode == ZPush::COMMAND_WEBSERVICE_DEVICE) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): executing WebserviceDevice service", $commandCode)); include_once 'webservicedevice.php'; $this->server->setClass("WebserviceDevice"); } $this->server->handle(); ZLog::Write(LOGLEVEL_DEBUG, sprintf("Webservice::HandleWebservice('%s'): sucessfully sent %d bytes", $commandCode, ob_get_length())); return true; }
/** * Constructor * * @access public */ public function DeviceManager() { $this->statemachine = ZPush::GetStateMachine(); $this->deviceHash = false; $this->devid = Request::GetDeviceID(); $this->windowSize = array(); $this->latestFolder = false; $this->hierarchySyncRequired = false; // only continue if deviceid is set if ($this->devid) { $this->device = new ASDevice($this->devid, Request::GetDeviceType(), Request::GetGETUser(), Request::GetUserAgent()); $this->loadDeviceData(); ZPush::GetTopCollector()->SetUserAgent($this->device->GetDeviceUserAgent()); } else { throw new FatalNotImplementedException("Can not proceed without a device id."); } $this->loopdetection = new LoopDetection(); $this->loopdetection->ProcessLoopDetectionInit(); $this->loopdetection->ProcessLoopDetectionPreviousConnectionFailed(); $this->stateManager = new StateManager(); $this->stateManager->SetDevice($this->device); }
if ($ex instanceof ZPushException) { header('HTTP/1.1 ' . $ex->getHTTPCodeString()); foreach ($ex->getHTTPHeaders() as $h) { header($h); } } else { header('HTTP/1.1 500 Internal Server Error'); } } else { ZLog::Write(LOGLEVEL_FATAL, "Exception: ({$exclass}) - headers were already sent. Message: " . $ex->getMessage()); } if ($ex instanceof AuthenticationRequiredException) { ZPush::PrintZPushLegal($exclass, sprintf('<pre>%s</pre>', $ex->getMessage())); // log the failed login attemt e.g. for fail2ban if (defined('LOGAUTHFAIL') && LOGAUTHFAIL != false) { ZLog::Write(LOGLEVEL_WARN, sprintf("IP: %s failed to authenticate user '%s'", Request::GetRemoteAddr(), Request::GetAuthUser() ? Request::GetAuthUser() : Request::GetGETUser())); } } else { if ($ex instanceof WBXMLException) { ZLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this."); } else { if (!$ex instanceof ZPushException || $ex->showLegalNotice()) { $cmdinfo = Request::GetCommand() ? sprintf(" processing command <i>%s</i>", Request::GetCommand()) : ""; $extrace = $ex->getTrace(); $trace = !empty($extrace) ? "\n\nTrace:\n" . print_r($extrace, 1) : ""; ZPush::PrintZPushLegal($exclass . $cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage() . $trace)); } } } // Announce exception to process loop detection if (ZPush::GetDeviceManager(false)) {
/** * Marks a a device of the Request::GetGETUser() for resynchronization * * @param string $deviceId the device id * * @access public * @return boolean * @throws SoapFault */ public function ResyncDevice($deviceId) { $deviceId = preg_replace("/[^A-Za-z0-9]/", "", $deviceId); ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceDevice::ResyncDevice('%s'): mark device of user '%s' for resynchronization", $deviceId, Request::GetGETUser())); if (!ZPushAdmin::ResyncDevice(Request::GetGETUser(), $deviceId)) { ZPush::GetTopCollector()->AnnounceInformation(ZLog::GetLastMessage(LOGLEVEL_ERROR), true); throw new SoapFault("ERROR", ZLog::GetLastMessage(LOGLEVEL_ERROR)); } ZPush::GetTopCollector()->AnnounceInformation(sprintf("Resync requested - device id '%s'", $deviceId), true); return true; }
/** * Authenticates the remote user * The sent HTTP authentication information is used to on Backend->Logon(). * As second step the GET-User verified by Backend->Setup() for permission check * Request::GetGETUser() is usually the same as the Request::GetAuthUser(). * If the GETUser is different from the AuthUser, the AuthUser MUST HAVE admin * permissions on GETUsers data store. Only then the Setup() will be sucessfull. * This allows the user 'john' to do operations as user 'joe' if he has sufficient privileges. * * @access public * @return * @throws AuthenticationRequiredException */ public static function Authenticate() { self::$userIsAuthenticated = false; // when a certificate is sent, allow authentication only as the certificate owner if (defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser())) { throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER])); } $backend = ZPush::GetBackend(); if ($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) { throw new AuthenticationRequiredException("Access denied. Username or password incorrect"); } // mark this request as "authenticated" self::$userIsAuthenticated = true; // check Auth-User's permissions on GETUser's store if ($backend->Setup(Request::GetGETUser(), true) == false) { throw new AuthenticationRequiredException(sprintf("Not enough privileges of '%s' to setup for user '%s': Permission denied", Request::GetAuthUser(), Request::GetGETUser())); } }
ZPush::PrintZPushLegal($exclass, sprintf('<pre>%s</pre>', $ex->getMessage())); // log the failed login attemt e.g. for fail2ban if (defined('LOGAUTHFAIL') && LOGAUTHFAIL != false) { ZLog::Write(LOGLEVEL_WARN, sprintf("IP: %s failed to authenticate user '%s'", Request::GetRemoteAddr(), Request::GetAuthUser() ? Request::GetAuthUser() : Request::GetGETUser())); } } else { if ($ex instanceof WBXMLException) { ZLog::Write(LOGLEVEL_FATAL, "Request could not be processed correctly due to a WBXMLException. Please report this including the 'WBXML debug data' logged. Be aware that the debug data could contain confidential information."); } else { if (!$ex instanceof ZPushException || $ex->showLegalNotice()) { $cmdinfo = Request::GetCommand() ? sprintf(" processing command <i>%s</i>", Request::GetCommand()) : ""; $extrace = $ex->getTrace(); $trace = !empty($extrace) ? "\n\nTrace:\n" . print_r($extrace, 1) : ""; ZPush::PrintZPushLegal($exclass . $cmdinfo, sprintf('<pre>%s</pre>', $ex->getMessage() . $trace)); } } } // Announce exception to process loop detection if (ZPush::GetDeviceManager(false)) { ZPush::GetDeviceManager()->AnnounceProcessException($ex); } // Announce exception if the TopCollector if available ZPush::GetTopCollector()->AnnounceInformation(get_class($ex), true); } // save device data if the DeviceManager is available if (ZPush::GetDeviceManager(false)) { ZPush::GetDeviceManager()->Save(); } // end gracefully ZLog::Write(LOGLEVEL_INFO, sprintf("cmd='%s' memory='%s/%s' time='%ss' devType='%s' devId='%s' getUser='******' from='%s' version='%s' method='%s' httpcode='%s'", Request::GetCommand(), Utils::FormatBytes(memory_get_peak_usage(false)), Utils::FormatBytes(memory_get_peak_usage(true)), number_format(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"], 2), Request::GetDeviceType(), Request::GetDeviceID(), Request::GetGETUser(), Request::GetRemoteAddr(), @constant('ZPUSH_VERSION'), Request::GetMethod(), http_response_code())); ZLog::Write(LOGLEVEL_DEBUG, "-------- End");
/** * Removes an additional folder from the given device and the Request::GetGETUser(). * * @param string $deviceId device id of where the folder should be removed. * @param string $add_folderid the folder id of the additional folder. * * @access public * @return boolean */ public function AdditionalFolderRemove($deviceId, $add_folderid) { $user = Request::GetGETUser(); $deviceId = preg_replace("/[^A-Za-z0-9]/", "", $deviceId); $add_folderid = preg_replace("/[^A-Za-z0-9]/", "", $add_folderid); $status = ZPushAdmin::AdditionalFolderRemove($user, $deviceId, $add_folderid); if (!$status) { ZPush::GetTopCollector()->AnnounceInformation(ZLog::GetLastMessage(LOGLEVEL_ERROR), true); throw new SoapFault("ERROR", ZLog::GetLastMessage(LOGLEVEL_ERROR)); } ZLog::Write(LOGLEVEL_INFO, sprintf("WebserviceDevice::AdditionalFolderRemove(): removed folder for device '%s' of user '%s': %s", $deviceId, $user, Utils::PrintAsString($status))); ZPush::GetTopCollector()->AnnounceInformation("Removed additional folder", true); return $status; }
/** * Constructor * * @access public */ public function __construct() { $this->statemachine = ZPush::GetStateMachine(); $this->deviceHash = false; $this->devid = Request::GetDeviceID(); $this->saveDevice = true; $this->windowSize = array(); $this->latestFolder = false; $this->hierarchySyncRequired = false; // only continue if deviceid is set if ($this->devid) { $this->device = new ASDevice($this->devid, Request::GetDeviceType(), Request::GetGETUser(), Request::GetUserAgent()); $this->loadDeviceData(); ZPush::GetTopCollector()->SetUserAgent($this->device->GetDeviceUserAgent()); } else { throw new FatalNotImplementedException("Can not proceed without a device id."); } $this->loopdetection = new LoopDetection(); $this->loopdetection->ProcessLoopDetectionInit(); $this->loopdetection->ProcessLoopDetectionPreviousConnectionFailed(); $this->stateManager = new StateManager(); $this->stateManager->SetDevice($this->device); $this->additionalFoldersHash = $this->getAdditionalFoldersHash(); if ($this->IsKoe() && $this->device->GetKoeVersion() !== false) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("KOE: %s / %s / %s", $this->device->GetKoeVersion(), $this->device->GetKoeBuild(), strftime("%Y-%m-%d %H:%M", $this->device->GetKoeBuildDate()))); } }
/** * Returns the logger object. If no logger has been initialized, FileLog will be initialized and returned. * * @access private * @return Log * @throws Exception thrown if the logger class cannot be instantiated. */ private static function getLogger() { if (!self::$logger) { global $specialLogUsers; // This variable comes from the configuration file (config.php) $logger = LOGBACKEND_CLASS; if (!class_exists($logger)) { $errmsg = 'The configured logging class `' . $logger . '` does not exist. Check your configuration.'; error_log($errmsg); throw new \Exception($errmsg); } list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser())); $user = '******' . $user . ']'; self::$logger = new $logger(); self::$logger->SetUser($user); self::$logger->SetAuthUser(Request::GetAuthUser()); self::$logger->SetSpecialLogUsers($specialLogUsers); self::$logger->SetDevid('[' . Request::GetDeviceID() . ']'); self::$logger->SetPidstr('[' . str_pad(@getmypid(), 5, " ", STR_PAD_LEFT) . ']'); self::$logger->AfterInitialize(); } return self::$logger; }