Ejemplo n.º 1
0
 /**
  * Create a new PHPSession object using the provided options (if any)
  *
  * @param   array   $options    An optional array of ini options to set
  *
  * @throws  ConfigurationError
  * @see     http://php.net/manual/en/session.configuration.php
  */
 public function __construct(array $options = null)
 {
     if ($options !== null) {
         $options = array_merge(self::$defaultCookieOptions, $options);
     } else {
         $options = self::$defaultCookieOptions;
     }
     if (array_key_exists('test_session_name', $options)) {
         $this->sessionName = $options['test_session_name'];
         unset($options['test_session_name']);
     }
     foreach ($options as $sessionVar => $value) {
         if (ini_set("session." . $sessionVar, $value) === false) {
             Logger::warning('Could not set php.ini setting %s = %s. This might affect your sessions behaviour.', $sessionVar, $value);
         }
     }
     $sessionSavePath = session_save_path() ?: sys_get_temp_dir();
     if (session_module_name() === 'files' && !is_writable($sessionSavePath)) {
         throw new ConfigurationError("Can't save session, path '{$sessionSavePath}' is not writable.");
     }
     if ($this->exists()) {
         // We do not want to start a new session here if there is not any
         $this->read();
     }
 }
Ejemplo n.º 2
0
 /**
  * Register all custom user backends from all loaded modules
  */
 protected static function registerCustomUserBackends()
 {
     if (static::$customBackends !== null) {
         return;
     }
     static::$customBackends = array();
     $providedBy = array();
     foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
         foreach ($module->getUserBackends() as $identifier => $className) {
             if (array_key_exists($identifier, $providedBy)) {
                 Logger::warning('Cannot register user backend of type "%s" provided by module "%s".' . ' The type is already provided by module "%s"', $identifier, $module->getName(), $providedBy[$identifier]);
             } elseif (in_array($identifier, static::$defaultBackends)) {
                 Logger::warning('Cannot register user backend of type "%s" provided by module "%s".' . ' The type is a default type provided by Icinga Web 2', $identifier, $module->getName());
             } else {
                 $providedBy[$identifier] = $module->getName();
                 static::$customBackends[$identifier] = $className;
             }
         }
     }
 }
Ejemplo n.º 3
0
 /**
  * Run the given LDAP query and return the resulting entries
  *
  * This utilizes paged search requests as defined in RFC 2696.
  *
  * @param   LdapQuery   $query      The query to fetch results with
  * @param   array       $fields     Request these attributes instead of the ones registered in the given query
  * @param   int         $pageSize   The maximum page size, defaults to self::PAGE_SIZE
  *
  * @return  array
  *
  * @throws  LdapException           In case an error occured while fetching the results
  */
 protected function runPagedQuery(LdapQuery $query, array $fields = null, $pageSize = null)
 {
     if ($pageSize === null) {
         $pageSize = static::PAGE_SIZE;
     }
     $limit = $query->getLimit();
     $offset = $query->hasOffset() ? $query->getOffset() : 0;
     if ($fields === null) {
         $fields = $query->getColumns();
     }
     $ds = $this->getConnection();
     $serverSorting = false;
     //$this->getCapabilities()->hasOid(LdapCapabilities::LDAP_SERVER_SORT_OID);
     if (!$serverSorting && $query->hasOrder() && !empty($fields)) {
         foreach ($query->getOrder() as $rule) {
             if (!in_array($rule[0], $fields, true)) {
                 $fields[] = $rule[0];
             }
         }
     }
     $unfoldAttribute = $query->getUnfoldAttribute();
     if ($unfoldAttribute) {
         foreach ($query->getFilter()->listFilteredColumns() as $filterColumn) {
             $fieldKey = array_search($filterColumn, $fields, true);
             if ($fieldKey === false || is_string($fieldKey)) {
                 $fields[] = $filterColumn;
             }
         }
     }
     $count = 0;
     $cookie = '';
     $entries = array();
     do {
         // Do not request the pagination control as a critical extension, as we want the
         // server to return results even if the paged search request cannot be satisfied
         ldap_control_paged_result($ds, $pageSize, false, $cookie);
         if ($serverSorting && $query->hasOrder()) {
             ldap_set_option($ds, LDAP_OPT_SERVER_CONTROLS, array(array('oid' => LdapCapabilities::LDAP_SERVER_SORT_OID, 'value' => $this->encodeSortRules($query->getOrder()))));
         }
         $results = $this->ldapSearch($query, array_values($fields), 0, $serverSorting && $limit ? $offset + $limit : 0);
         if ($results === false) {
             if (ldap_errno($ds) === self::LDAP_NO_SUCH_OBJECT) {
                 break;
             }
             throw new LdapException('LDAP query "%s" (base %s) failed. Error: %s', (string) $query, $query->getBase() ?: $this->getDn(), ldap_error($ds));
         } elseif (ldap_count_entries($ds, $results) === 0) {
             if (in_array(ldap_errno($ds), array(static::LDAP_SIZELIMIT_EXCEEDED, static::LDAP_ADMINLIMIT_EXCEEDED), true)) {
                 Logger::warning('Unable to request more than %u results. Does the server allow paged search requests? (%s)', $count, ldap_error($ds));
             }
             break;
         }
         $entry = ldap_first_entry($ds, $results);
         do {
             if ($unfoldAttribute) {
                 $rows = $this->cleanupAttributes(ldap_get_attributes($ds, $entry), $fields, $unfoldAttribute);
                 if (is_array($rows)) {
                     // TODO: Register the DN the same way as a section name in the ArrayDatasource!
                     foreach ($rows as $row) {
                         if ($query->getFilter()->matches($row)) {
                             $count += 1;
                             if (!$serverSorting || $offset === 0 || $offset < $count) {
                                 $entries[] = $row;
                             }
                             if ($serverSorting && $limit > 0 && $limit === count($entries)) {
                                 break;
                             }
                         }
                     }
                 } else {
                     $count += 1;
                     if (!$serverSorting || $offset === 0 || $offset < $count) {
                         $entries[ldap_get_dn($ds, $entry)] = $rows;
                     }
                 }
             } else {
                 $count += 1;
                 if (!$serverSorting || $offset === 0 || $offset < $count) {
                     $entries[ldap_get_dn($ds, $entry)] = $this->cleanupAttributes(ldap_get_attributes($ds, $entry), $fields);
                 }
             }
         } while ((!$serverSorting || $limit === 0 || $limit !== count($entries)) && ($entry = ldap_next_entry($ds, $entry)));
         if (false === @ldap_control_paged_result_response($ds, $results, $cookie)) {
             // If the page size is greater than or equal to the sizeLimit value, the server should ignore the
             // control as the request can be satisfied in a single page: https://www.ietf.org/rfc/rfc2696.txt
             // This applies no matter whether paged search requests are permitted or not. You're done once you
             // got everything you were out for.
             if ($serverSorting && count($entries) !== $limit) {
                 // The server does not support pagination, but still returned a response by ignoring the
                 // pagedResultsControl. We output a warning to indicate that the pagination control was ignored.
                 Logger::warning('Unable to request paged LDAP results. Does the server allow paged search requests?');
             }
         }
         ldap_free_result($results);
     } while ($cookie && (!$serverSorting || $limit === 0 || count($entries) < $limit));
     if ($cookie) {
         // A sequence of paged search requests is abandoned by the client sending a search request containing a
         // pagedResultsControl with the size set to zero (0) and the cookie set to the last cookie returned by
         // the server: https://www.ietf.org/rfc/rfc2696.txt
         ldap_control_paged_result($ds, 0, false, $cookie);
         // Returns no entries, due to the page size
         ldap_search($ds, $query->getBase() ?: $this->getDn(), (string) $query);
     }
     if (!$serverSorting && $query->hasOrder()) {
         uasort($entries, array($query, 'compare'));
         if ($limit && $count > $limit) {
             $entries = array_splice($entries, $query->hasOffset() ? $query->getOffset() : 0, $limit);
         }
     }
     return $entries;
 }
Ejemplo n.º 4
0
 /**
  * Search for deleted properties and use the editor to delete these entries
  *
  * @param Config    $oldconfig  The config representing the state before the change
  * @param Config    $newconfig  The config representing the state after the change
  * @param Document  $doc
  *
  * @throws ProgrammingError
  */
 protected function diffPropertyDeletions(Config $oldconfig, Config $newconfig, Document $doc)
 {
     // Iterate over all properties in the old configuration file and remove those that don't
     // exist in the new config
     foreach ($oldconfig->toArray() as $section => $directives) {
         if (!is_array($directives)) {
             Logger::warning('Section-less property ' . (string) $directives . ' was ignored.');
             continue;
         }
         if ($newconfig->hasSection($section)) {
             $newSection = $newconfig->getSection($section);
             $oldDomSection = $doc->getSection($section);
             foreach ($directives as $key => $value) {
                 if ($value instanceof ConfigObject) {
                     throw new ProgrammingError('Cannot diff recursive configs');
                 }
                 if (null === $newSection->get($key) && $oldDomSection->hasDirective($key)) {
                     $oldDomSection->removeDirective($key);
                 }
             }
         } else {
             $doc->removeSection($section);
         }
     }
 }
Ejemplo n.º 5
0
 /**
  * Register module
  *
  * @return bool
  */
 public function register()
 {
     if ($this->registered) {
         return true;
     }
     $this->registerAutoloader();
     try {
         $this->launchRunScript();
     } catch (Exception $e) {
         Logger::warning('Launching the run script %s for module %s failed with the following exception: %s', $this->runScript, $this->name, $e->getMessage());
         return false;
     }
     $this->registerWebIntegration();
     $this->registered = true;
     return true;
 }
Ejemplo n.º 6
0
 /**
  * Detect installed modules from every path provided in modulePaths
  *
  * @param   array   $availableDirs      Installed modules location
  *
  * @return $this
  */
 public function detectInstalledModules(array $availableDirs = null)
 {
     $modulePaths = $availableDirs !== null ? $availableDirs : $this->modulePaths;
     foreach ($modulePaths as $basedir) {
         $canonical = realpath($basedir);
         if ($canonical === false) {
             Logger::warning('Module path "%s" does not exist', $basedir);
             continue;
         }
         if (!is_dir($canonical)) {
             Logger::error('Module path "%s" is not a directory', $canonical);
             continue;
         }
         if (!is_readable($canonical)) {
             Logger::error('Module path "%s" is not readable', $canonical);
             continue;
         }
         if (($dh = opendir($canonical)) !== false) {
             while (($file = readdir($dh)) !== false) {
                 if ($file[0] === '.') {
                     continue;
                 }
                 if (is_dir($canonical . '/' . $file)) {
                     if (!array_key_exists($file, $this->installedBaseDirs)) {
                         $this->installedBaseDirs[$file] = $canonical . '/' . $file;
                     } else {
                         Logger::debug('Module "%s" already exists in installation path "%s" and is ignored.', $canonical . '/' . $file, $this->installedBaseDirs[$file]);
                     }
                 }
             }
             closedir($dh);
         }
     }
     ksort($this->installedBaseDirs);
     return $this;
 }
Ejemplo n.º 7
0
 /**
  * Read the ini file contained in a string and return a mutable DOM that can be used
  * to change the content of an INI file.
  *
  * @param $str                  A string containing the whole ini file
  *
  * @return Document             The mutable DOM object.
  * @throws ConfigurationError   In case the file is not parseable
  */
 public static function parseIni($str)
 {
     $doc = new Document();
     $sec = null;
     $dir = null;
     $coms = array();
     $state = self::LINE_START;
     $escaping = null;
     $token = '';
     $line = 0;
     for ($i = 0; $i < strlen($str); $i++) {
         $s = $str[$i];
         switch ($state) {
             case self::LINE_START:
                 if (ctype_space($s)) {
                     continue;
                 }
                 switch ($s) {
                     case '[':
                         $state = self::SECTION;
                         break;
                     case ';':
                         $state = self::COMMENT;
                         break;
                     default:
                         $state = self::DIRECTIVE_KEY;
                         $token = $s;
                         break;
                 }
                 break;
             case self::ESCAPE:
                 $token .= $s;
                 $state = $escaping;
                 $escaping = null;
                 break;
             case self::SECTION:
                 if ($s === "\n") {
                     self::throwParseError('Unterminated SECTION', $line);
                 } elseif ($s === '\\') {
                     $state = self::ESCAPE;
                     $escaping = self::SECTION;
                 } elseif ($s !== ']') {
                     $token .= $s;
                 } else {
                     $sec = new Section($token);
                     $sec->setCommentsPre($coms);
                     $doc->addSection($sec);
                     $dir = null;
                     $coms = array();
                     $state = self::LINE_END;
                     $token = '';
                 }
                 break;
             case self::DIRECTIVE_KEY:
                 if ($s !== '=') {
                     $token .= $s;
                 } else {
                     $dir = new Directive($token);
                     $dir->setCommentsPre($coms);
                     if (isset($sec)) {
                         $sec->addDirective($dir);
                     } else {
                         Logger::warning(sprintf('Ini parser warning: section-less directive "%s" ignored. (l. %d)', $token, $line));
                     }
                     $coms = array();
                     $state = self::DIRECTIVE_VALUE_START;
                     $token = '';
                 }
                 break;
             case self::DIRECTIVE_VALUE_START:
                 if (ctype_space($s)) {
                     continue;
                 } elseif ($s === '"') {
                     $state = self::DIRECTIVE_VALUE_QUOTED;
                 } else {
                     $state = self::DIRECTIVE_VALUE;
                     $token = $s;
                 }
                 break;
             case self::DIRECTIVE_VALUE:
                 /*
                     Escaping non-quoted values is not supported by php_parse_ini, it might
                     be reasonable to include in case we are switching completely our own
                     parser implementation
                 */
                 if ($s === "\n" || $s === ";") {
                     $dir->setValue($token);
                     $token = '';
                     if ($s === "\n") {
                         $state = self::LINE_START;
                         $line++;
                     } elseif ($s === ';') {
                         $state = self::COMMENT;
                     }
                 } else {
                     $token .= $s;
                 }
                 break;
             case self::DIRECTIVE_VALUE_QUOTED:
                 if ($s === '\\') {
                     $state = self::ESCAPE;
                     $escaping = self::DIRECTIVE_VALUE_QUOTED;
                 } elseif ($s !== '"') {
                     $token .= $s;
                 } else {
                     $dir->setValue($token);
                     $token = '';
                     $state = self::LINE_END;
                 }
                 break;
             case self::COMMENT:
             case self::COMMENT_END:
                 if ($s !== "\n") {
                     $token .= $s;
                 } else {
                     $com = new Comment();
                     $com->setContent($token);
                     $token = '';
                     // Comments at the line end belong to the current line's directive or section. Comments
                     // on empty lines belong to the next directive that shows up.
                     if ($state === self::COMMENT_END) {
                         if (isset($dir)) {
                             $dir->setCommentPost($com);
                         } else {
                             $sec->setCommentPost($com);
                         }
                     } else {
                         $coms[] = $com;
                     }
                     $state = self::LINE_START;
                     $line++;
                 }
                 break;
             case self::LINE_END:
                 if ($s === "\n") {
                     $state = self::LINE_START;
                     $line++;
                 } elseif ($s === ';') {
                     $state = self::COMMENT_END;
                 }
                 break;
         }
     }
     // process the last token
     switch ($state) {
         case self::COMMENT:
         case self::COMMENT_END:
             $com = new Comment();
             $com->setContent($token);
             if ($state === self::COMMENT_END) {
                 if (isset($dir)) {
                     $dir->setCommentPost($com);
                 } else {
                     $sec->setCommentPost($com);
                 }
             } else {
                 $coms[] = $com;
             }
             break;
         case self::DIRECTIVE_VALUE:
             $dir->setValue($token);
             $sec->addDirective($dir);
             break;
         case self::ESCAPE:
         case self::DIRECTIVE_VALUE_QUOTED:
         case self::DIRECTIVE_KEY:
         case self::SECTION:
             self::throwParseError('File ended in unterminated state ' . $state, $line);
     }
     if (!empty($coms)) {
         $doc->setCommentsDangling($coms);
     }
     return $doc;
 }
Ejemplo n.º 8
0
 /**
  * Add a notification message
  *
  * @param   string $message
  * @param   string $type
  */
 protected function addMessage($message, $type = self::INFO)
 {
     if ($this->isCli) {
         $msg = sprintf('[%s] %s', $type, $message);
         switch ($type) {
             case self::INFO:
             case self::SUCCESS:
                 Logger::info($msg);
                 break;
             case self::ERROR:
                 Logger::error($msg);
                 break;
             case self::WARNING:
                 Logger::warning($msg);
                 break;
         }
     } else {
         $this->messages[] = (object) array('type' => $type, 'message' => $message);
     }
 }
Ejemplo n.º 9
0
 /**
  * Prepare and establish a connection with the LDAP server
  *
  * @return  resource        A positive LDAP link identifier
  *
  * @throws  LdapException   In case the connection is not possible
  */
 protected function prepareNewConnection()
 {
     if ($this->encryption === static::STARTTLS || $this->encryption === static::LDAPS) {
         $this->prepareTlsEnvironment();
     }
     $hostname = $this->hostname;
     if ($this->encryption === static::LDAPS) {
         $hostname = 'ldaps://' . $hostname;
     }
     $ds = ldap_connect($hostname, $this->port);
     try {
         $this->capabilities = $this->discoverCapabilities($ds);
         $this->discoverySuccess = true;
     } catch (LdapException $e) {
         Logger::debug($e);
         Logger::warning('LADP discovery failed, assuming default LDAP capabilities.');
         $this->capabilities = new Capability();
         // create empty default capabilities
         $this->discoverySuccess = false;
     }
     if ($this->encryption === static::STARTTLS) {
         $force_tls = false;
         if ($this->capabilities->hasStartTls()) {
             if (@ldap_start_tls($ds)) {
                 Logger::debug('LDAP STARTTLS succeeded');
             } else {
                 Logger::error('LDAP STARTTLS failed: %s', ldap_error($ds));
                 throw new LdapException('LDAP STARTTLS failed: %s', ldap_error($ds));
             }
         } elseif ($force_tls) {
             throw new LdapException('STARTTLS is required but not announced by %s', $this->hostname);
         } else {
             Logger::warning('LDAP STARTTLS enabled but not announced');
         }
     }
     // ldap_rename requires LDAPv3:
     if ($this->capabilities->hasLdapV3()) {
         if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3)) {
             throw new LdapException('LDAPv3 is required');
         }
     } else {
         // TODO: remove this -> FORCING v3 for now
         ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
         Logger::warning('No LDAPv3 support detected');
     }
     // Not setting this results in "Operations error" on AD when using the whole domain as search base
     ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
     // ldap_set_option($ds, LDAP_OPT_DEREF, LDAP_DEREF_NEVER);
     return $ds;
 }