/** * Create a new MailManager and set all the relevant header flags for * sending a message from $sender to $pers->getEmail * * @param $pers Person A person object containing recipient information * @param $sender string The sender, as to be defined in the mail's * envelope * @param $senderName string The name that should appear in the sender * field * @param $sendHeader string The sender, as to be defined in the mail's * header */ public function __construct($pers, $sender, $senderName, $sendHeader, $alternateAddress = null) { if (!$pers instanceof Person) { throw new ConfusaGenException("Error: First argument to the " . "MailManager constructor is not a " . "valid person object!"); } $this->mailer = new PHPMailer(); if (is_null($this->mailer)) { Framework::error_output("Could not create mailer. Aborting"); return; } $this->mailer->CharSet = "UTF-8"; $this->mailer->Mailer = "sendmail"; /* set the envelope "from" address using the sendmail option -f, and * the return-path header */ $this->mailer->Sender = $sender; /* set the header "from" address */ $this->mailer->From = $sendHeader; $this->mailer->FromName = $senderName; $this->mailer->WordWrap = 80; $this->toAddr = $pers->getEmail(); if (!is_null($alternateAddress)) { $this->toAddr = $alternateAddress; } $this->mailer->AddAddress($this->toAddr, $pers->getName()); $help_desk = $pers->getSubscriber()->getHelpEmail(); /* add a reply-to to the helpdesk, if a helpdesk is defined */ if (isset($help_desk)) { $support_name = $pers->getSubscriber()->getOrgName() . " support"; $this->mailer->AddReplyTo($help_desk, $support_name); } }
private function handleMaintText() { if (array_key_exists("nren_maint_msg", $_POST)) { if ($this->person->getNREN()->setMaintMsg($this->person, $_POST['nren_maint_msg'])) { Framework::success_output($this->translateTag("l10n_nren_maint_msg_success", 'portal_config')); } else { Framework::error_output($this->translateTag("l10n_nren_maint_msg_failure", 'portal_config')); } } }
function process() { if (CS::getSessionKey('hasAcceptedAUP') !== true) { Framework::error_output($this->translateTag("l10n_err_aupagreement", "processcsr")); return; } $user_cert_enabled = $this->person->testEntitlementAttribute(Config::get_config('entitlement_user')); $this->tpl->assign('email_status', $this->person->getNREN()->getEnableEmail()); $this->tpl->assign('user_cert_enabled', $user_cert_enabled); $this->tpl->assign('content', $this->tpl->fetch('select_email.tpl')); }
public function pre_process($person) { parent::pre_process($person); $script = file_get_contents('../include/fetch_attr.js'); $this->tpl->assign('rawScript', $script); if (!$person->isNRENAdmin() && !$person->isSubscriberAdmin()) { return; } if (isset($_POST['attributes_operation'])) { switch ($_POST['attributes_operation']) { case 'update_map': $cn = Input::sanitizeText($_POST['cn']); $mail = Input::sanitizeText($_POST['mail']); /* only NREN-admin can change the mapping for * - organization-identifier * - entitlement */ if ($this->person->isNRENAdmin()) { $epodn = Input::sanitizeText($_POST['epodn']); $entitlement = Input::sanitizeText($_POST['entitlement']); if ($this->person->getNREN()->saveMap($this->person->getEPPNKey(), $epodn, $cn, $mail, $entitlement)) { Framework::success_output($this->translateTag('l10n_suc_updmap', 'attributes')); } } else { if ($this->person->isSubscriberAdmin()) { try { $result = $this->person->getSubscriber()->saveMap($this->person->getEPPNKey(), $cn, $mail); } catch (DBQueryException $dbqe) { Framework::error_output($this->translateTag('l10n_err_updmap1', 'attributes') . "<br />" . $this->translateTag('l10n_label_cn', 'attributes') . ": " . htmlentities($cn) . "<br />" . $this->translateTag('l10n_label_mail', 'attributes') . ": " . htmlentities($mail) . "<br />" . $this->translateMessageTag('err_servsaid') . " " . htmlentities($dbqe->getMessage())); Logger::log_event(LOG_NOTICE, __FILE__ . ", " . __LINE__ . ": " . $dbqe->getMessage()); } catch (DBStatementException $dbse) { Framework::error_output("Could not update the subscriber-mapping, probably due to a " . "problem with the server-configuration. Server said: " . htmlentities($dbse->getMessage())); Logger::log_event(LOG_NOTICE, __FILE__ . ", " . __LINE__ . ": " . $dbse->getMessage()); } if ($result === true) { Framework::success_output($this->translateTag('l10n_suc_updmap', 'attributes')); } } } break; default: Framework::error_output("Unknown operation chosen on attributes mask!"); break; } } }
/** * Display CSR generation choices. Fail if user has not accepted AUP * or number of registered e-mail addresses does not match the number * mandated by the NREN. * @see Content_Page::process() */ function process() { if (CS::getSessionKey('hasAcceptedAUP') !== true) { Framework::error_output($this->translateTag("l10n_err_aupagreement", "processcsr")); return; } $numberRequiredEmails = $this->person->getNREN()->getEnableEmail(); switch ($numberRequiredEmails) { case 'n': case '0': break; case '1': case 'm': $numberEmails = count($this->person->getRegCertEmails()); if ($numberEmails < 1) { Framework::error_output($this->translateTag('l10n_err_emailmissing', 'processcsr')); $this->tpl->assign('disable_next_button', true); } break; default: break; } if (isset($_GET['show'])) { switch ($_GET['show']) { case 'upload_csr': /* FIXME: constants */ $this->tpl->assign('nextScript', 'upload_csr.php'); $this->tpl->assign('upload_csr', true); break; case 'paste_csr': $this->tpl->assign('nextScript', 'upload_csr.php'); $this->tpl->assign('paste_csr', true); break; default: $this->tpl->assign('nextScript', 'browser_csr.php'); $this->tpl->assign('browser_csr', true); break; } } else { $this->tpl->assign('nextScript', 'browser_csr.php'); $this->tpl->assign('browser_csr', true); } $user_cert_enabled = $this->person->testEntitlementAttribute(Config::get_config('entitlement_user')); $this->tpl->assign('user_cert_enabled', $user_cert_enabled); $this->tpl->assign('content', $this->tpl->fetch('receive_csr.tpl')); }
/** * Decorate the about::confusa template with the information from the * VERSION file */ private function assignVersionVariables() { try { $confusaVersion = MetaInfo::getConfusaVersion(); } catch (ConfusaGenException $cge) { Framework::error_output("Could not determine the version of Confusa! " . "Please contact an administrator about that!"); } $version_path = Config::get_config('install_path') . "VERSION"; $version_file = file_get_contents($version_path); $this->tpl->assign('cVersion', $confusaVersion); $cdn_line_start = strpos($version_file, "NAME="); $cdn_line_end = strpos($version_file, "\n", $cdn_line_start); if ($cdn_line_start === false || $cdn_line_end === false) { Framework::error_output("Could not determine the version codename of " . "Confusa! Please contact an administrator about " . "that!"); } $cdn_line_start += 5; $versionCodename = substr($version_file, $cdn_line_start, $cdn_line_end - $cdn_line_start); $this->tpl->assign('cCodename', $versionCodename); }
function confusaErrorHandler($errno, $errstr, $errfile, $errline) { $msg = ""; $display_errors = ini_get('display_errors') == true || ini_get('display_errors') == "stdout"; switch ($errno) { case E_ERROR: case E_USER_ERROR: $msg = "PHP Fatal Error: {$errstr} in {$errfile} on line {$errline}"; if ($display_errors) { Framework::error_output($msg); } break; case E_WARNING: case E_USER_WARNING: $msg = "PHP Warning: {$errstr} in {$errfile} on line {$errline}"; if ($display_errors) { Framework::warning_output($msg); } break; case E_NOTICE: case E_USER_NOTICE: $msg = "PHP Notice: {$errstr} in {$errfile} on line {$errline}"; if ($display_errors) { Framework::message_output($msg); } break; case E_STRICT: $msg = "PHP Strict: {$errstr} in {$errfile} on line {$errline}"; break; default: $msg = "PHP Unknown: {$errstr} in {$errfile} on line {$errline}"; if ($display_errors) { Framework::message_output($msg); } break; } /* if logging is turned on, log the errors to the respective PHP log */ if (ini_get('log_errors') && error_reporting() & $errno) { error_log($msg); } return true; }
public function deleteCertFromDB($key) { Framework::error_output(__FILE__ . ":" . __LINE__ . " This function (deleteCertFromDB) should not be called in online-mode!"); return false; }
/** * getAboutText * Get the about-text for a certain NREN, so it can be displayed in Confusa's * about-section * * @param Person $person the current person for tag-replacement */ public function getAboutText($person) { $query = "SELECT about FROM nrens WHERE nren_id = ? AND about IS NOT NULL"; try { $res = MDB2Wrapper::execute($query, array('text'), array($this->getID())); } catch (DBStatementException $dbse) { Framework::error_output($this->translateMessageTag('abt_err_dbstat') . " " . htmlentities($dbse->getMessage())); Logger::log_event(LOG_INFO, "Could not retrive about-text for NREN {$nren} " . "due to an error with the statement. " . "Server said: " . $dbse->getMessage()); return null; } catch (DBQueryException $dbqe) { Framework::error_output($this->translateMessageTag('abt_err_dbquery') . " " . htmlentities($nren)); Logger::log_event(LOG_INFO, "Could not retrieve about-text for NREN {$nren} " . "due to an error in the statement. Server said: " . $dbqe->getMessage()); return null; } if (count($res) > 0) { $at = $res[0]['about']; $at = stripslashes($at); $at = Input::br2nl($at); $textile = new Textile(); return $this->replaceTags($textile->TextileRestricted($at, 0), $person); } return null; }
/** getCountriesIdP() return all countries and IdP present in the database * * @params void * @return array list of available countries with corresponding IdP(s) * @access private */ private function getCountriesIdP() { if (isset($this->cidp)) { return $this->cidp; } try { $res = MDB2Wrapper::execute("SELECT idp_url, country, name FROM nrens n " . "LEFT JOIN idp_map im ON n.nren_id = im.nren_id", NULL, NULL); } catch (ConfusaGenException $cge) { Logger::log_event(LOG_WARNING, "Could not get IdP-URLs from the database, " . "make sure DB-connection is properly configured\n"); Framework::error_output($this->translateTag('l10n_err_db_select', 'disco')); return array(); } $this->cidp = array(); foreach ($res as $key => $value) { if (!isset($this->cidp[$value['country']])) { $this->cidp[$value['country']] = array(); } $this->cidp[$value['country']][] = $value['idp_url']; } return $res; }
/** * Sign the CSR with the passed authToken. If signing succeeds, the class * member authKey is set to the orderNumber/certHash. If not, an error is * displayer * @param $authToken pubkey hash of the CSR that is to be signed */ private function signCSR($authToken) { $csr = CSR::getFromDB($this->person->getX509ValidCN(), $authToken); if (!isset($csr) || !$csr) { $errorTag = PW::create(); Framework::error_output("[{$errorTag}] Did not find CSR with auth_token " . htmlentities($auth_token)); $msg = "User " . $this->person->getEPPN() . " "; $msg .= "tried to delete CSR with auth_token " . $authToken . " but was unsuccessful"; Logger::logEvent(LOG_NOTICE, "Process_CSR", "approveCSR({$authToken})", $msg, __LINE__, $errorTag); return false; } try { if (!isset($this->ca)) { Framework::error_output($this->translateTag('l10n_err_noca', 'processcsr')); return false; } $permission = $this->person->mayRequestCertificate(); if ($permission->isPermissionGranted() === false) { Framework::error_output($this->translateTag('l10n_err_noperm1', 'processcsr') . "<br /><br />" . $permission->getFormattedReasons() . "<br />" . $this->translateTag('l10n_err_noperm2', 'processcsr')); return; } $this->authKey = $this->ca->signKey($csr); } catch (CGE_ComodoAPIException $capie) { Framework::error_output($this->translateTag('l10n_sign_error', 'processcsr') . htmlentities($capie)); return false; } catch (ConfusaGenException $e) { $msg = $this->translateTag('l10n_sign_error', 'processcsr') . "<br /><br /><i>" . htmlentities($e->getMessage()) . "</i><br />"; Framework::error_output($msg); return false; } catch (KeySigningException $kse) { Framework::error_output($this->translateTag('l10n_sign_error', 'processcsr') . htmlentites($kse->getMessage())); return false; } CSR::deleteFromDB($this->person, $authToken); }
/** * Update the contact information for a subscriber to a new value * * @param $contact_email string A general subscriber-mail address * @param $contact_phone string The (main) phone number of the subscriber * @param $resp_name string The name of a responsible person at the subscr. * @param $resp_email string e-mail address of a responsible person * @param $help_url string URL of the subscriber's helpdesk * @param $help_email string e-mail address of the subscriber's helpdesk * @param $language string the language code for the subscriber's preferred * language */ private function updateSubscriberContact($language) { $subscriber = $this->person->getSubscriber(); $subscriber->setEmail($contact_email); $subscriber->setPhone($contact_phone); $subscriber->setRespName($resp_name); $subscriber->setRespEmail($resp_email); $subscriber->setHelpURL($help_url); $subscriber->setHelpEmail($help_email); $subscriber->setLanguage($language); try { $subscriber->save(); } catch (ConfusaGenException $cge) { Framework::error_output($this->translateTag('l10n_err_updatesubscr', 'contactinfo') . " " . htmlentities($cge->getMessage())); Logger::log_event(LOG_INFO, "[sadm] Could not update " . "contact of subscriber {$subscriber}: " . $cge->getMessage()); } Framework::success_output($this->translateTag('l10n_suc_updatesubscr', 'contactinfo') . " " . htmlentities($subscriber->getIdPName()) . "."); Logger::log_event(LOG_DEBUG, "[sadm] Updated contact for subscriber {$subscriber}."); }
/** * retrieveMap() return the map for the subscriber * * @param void * @return Array|null the array for the subscriber or null if not set * @access private */ private function retrieveMap() { if (is_null($this->nren->getID())) { throw new ConfusaGenException("Cannot find map for subscriber when NREN-ID is not set!"); } if (is_null($this->db_id)) { throw new ConfusaGenException("Cannot find map for subscriber when Subscriber-ID is not set!"); } $this->hasMap = false; $query = "SELECT * FROM attribute_mapping WHERE subscriber_id=? AND nren_id=?"; $params = array('text', 'text'); $data = array($this->db_id, $this->nren->getID()); try { $res = MDB2Wrapper::execute($query, $params, $data); switch (count($res)) { case 0: $this->hasMap = false; return false; case 1: $this->hasMap = true; $this->map = $res[0]; return true; default: $this->hasMap = false; $msg = "Too many hits (" . count($res) . ") were found in the database. "; $msg .= __CLASS__ . __FUNCTION__ . " gets confused. Aborting."; Logger::log_event(LOG_NOTICE, $msg); Framework::error_output($msg); return false; } } catch (ConfusaGenException $e) { /* FIXME */ Framework::error_output($e->getMessage()); return false; } }
/** * Show an error (in the framework) about an invalid character found * during sanitation. * * @param $original The original string, e.g. as it was received via the * POST array * @param $sanitized The string as it appeared after sanitizing it * @param $dictEntry The dictionary entry to look up from the dictionary * when referring to the input element that cause the * sanitation. * @param $dictionary The dictionary from which the entry should be looked * up. If this is NULL, the current page's dictionary * will be used by default. */ protected function displayInvalidCharError($original, $sanitized, $dictEntry = NULL, $dictionary = NULL) { $invalidChars = Input::findSanitizedCharacters($original, $sanitized); $errorMsg = ""; if (empty($dictionary)) { $dictionary = $this->dictionary; } if (isset($dictEntry)) { $errorMsg .= $this->translateTag($dictEntry, $this->dictionary); } $errorMsg .= " "; $errorMsg .= $this->translateTag('l10n_err_sanitation', 'messages'); $errorMsg .= " {$invalidChars}"; Framework::error_output($errorMsg); }
/** * Revoke a list of certificates possibly belonging to more than one end-entity * based on an array of auth_keys stored in the session. Based on the number of * certificates that are going to be revoked, this may take some time. * * @param string $reason The reason for revocation (as in RFC 3280) * */ private function revoke_list($reason) { if (Config::get_config('ca_mode') === CA_COMODO && Config::get_config('capi_test') === true) { Framework::message_output($this->translateTag('l10n_msg_revsim1', 'revocation')); } $auth_keys = CS::getSessionKey('auth_keys'); CS::deleteSessionKey('auth_keys'); if (is_null($auth_keys)) { Framework::error_output("Lost session! Please log-out of Confusa, " . "log-in again and try again!\n"); return; } $num_certs = count($auth_keys); $num_certs_revoked = 0; Logger::log_event(LOG_INFO, "Trying to revoke {$num_certs} certificates." . "Administrator contacted us from " . $_SERVER['REMOTE_ADDR'] . " in a bulk (list) revocation request."); foreach ($auth_keys as $auth_key) { try { if (!$this->ca->revokeCert($auth_key, $reason)) { Framework::error_output("Could not revoke certificate " . htmlentities($auth_key) . "."); } else { $num_certs_revoked = $num_certs_revoked + 1; } } catch (ConfusaGenException $cge) { Framework::error_output($cge->getMessage()); } } Logger::log_event(LOG_INFO, "Successfully revoked {$num_certs_revoked} certificates out of {$num_certs}. " . "Administrator contacted us from " . $_SERVER['REMOTE_ADDR'] . " in a bulk (list) revocation request."); Framework::message_output($this->translateTag('l10n_suc_revoke1', 'revocation') . " " . $num_certs_revoked . " " . $this->translateTag('l10n_suc_revoke2', 'revocation') . " " . $num_certs); }
/** * Check if the person that called "revoke" on auth_key may revoke the respective * certificate, i.e. whether the certificate is issued to the person herself. * * @param $auth_key mixed The auth_key for which to check * @return boolean true, if revocation of the passed key is permitted */ private function checkRevocationPermissions($auth_key) { try { $info = $this->ca->getCertInformation($auth_key); if (is_null($info)) { Framework::error_output($this->translateTag('l10n_err_ordnum_notfound', 'download')); return false; } $cn = $this->person->getX509ValidCN(); $subscriber = $this->person->getSubscriber()->getOrgName(); if (stripslashes($info['cert_owner']) === stripslashes($cn) && $info['organization'] === $subscriber) { return true; } } catch (ConfusaGenException $cge) { Framework::error_output($this->translateTag('l10n_err_retrieval_fail', 'download') . ' ' . htmlentities($cge->getMessage())); Logger::log_event(LOG_INFO, "[norm] Revoking certificate " . "with key {$auth_key} failed, because permissions could not be " . "determined!"); } return false; }
function match_dn($subject, $expectedSubj) { $composed_dn = $subject; if (is_array($subject)) { /* Compose the DN in the 'correct' order, only use the fields set in * the subject */ $composed_dn = ""; if (isset($subject['C'])) { $composed_dn .= "/C=" . $subject['C']; } if (isset($subject['O'])) { $composed_dn .= "/O=" . $subject['O']; } if (isset($subject['OU'])) { $composed_dn .= "/OU=" . $subject['OU']; } if (isset($subject['C'])) { $composed_dn .= "/CN=" . $subject['CN']; } } $res = $expectedSubj === $composed_dn; if (!$res) { Framework::error_output("Supplied (" . htmlentities($composed_dn) . ") and required subject (" . htmlentities($expectedSubj) . ") differs!"); } return $res; }
/** * signCSR() * * The function ships a CSR generated in the browser for * signing. * * @param SPKAC * @return Ordernumber|false * @access private */ private function signCSR($csr) { $permission = $this->person->mayRequestCertificate(); if ($permission->isPermissionGranted() === false) { Framework::error_output($this->translateTag('l10n_err_noperm1', 'processcsr') . "<br /><br />" . $permission->getFormattedReasons() . "<br />" . $this->translateTag('l10n_err_noperm2', 'processcsr')); return false; } $order_number = $this->ca->signKey($csr); return $order_number; }
/** * no operation * * @param $logout_loc The location to which the user is redirected */ public function deAuthenticate($logout_loc = 'logout.php') { Framework::error_output("Cannot log out, you're in bypass-mode!"); }
/** * decoratePerson - get the supplied attributes and add to the correct * fields in person * * This function is a bit fragile. The reason for this, is that it needs * to 'bootstrap' the map for person-identifier (e.g. ePPN) * through various encodings. * * One way would be to add a specific mapping for all known NRENs, but * we'd rather add a generic approach and just try the known encodings * and see if we find something there. * * If, for some reason, a new NREN/IdP fails to correctly decorate the * person-object, the problem most likely starts here. * * @author Henrik Austad <*****@*****.**> * @author Thomas Zangerl <*****@*****.**> * * @throws CGE_CriticalAttributeException If an attribute without which Confusa * really can not work is not found * @throws MapNotFoundException If the NREN-map is not found * * @param array $attributes * @param String $idp * @throws MapNotFoundException */ protected function decoratePerson($attributes, $idp) { $cnPrefix = ""; $oPrefix = ""; if (Config::get_config('capi_test')) { $cnPrefix = ConfusaConstants::$CAPI_TEST_CN_PREFIX; $oPrefix = ConfusaConstants::$CAPI_TEST_O_PREFIX; } if (is_null($idp)) { throw new CGE_CriticalAttributeException("Need the URL of the IdP in order to create an NREN-object!"); } if (is_null($attributes)) { throw new CGE_CriticalAttributeException("Cannot find <b>any</b> attributes!"); } /* From the IdP, find the NREN-details */ $this->person->setNREN(new NREN($idp)); if (is_null($this->person->getNREN()) || !$this->person->getNREN()->isValid()) { $msg = "Could not map from the identity provider to the NREN. "; $msg .= "Probably the idp_map in the database is not configured for your idp ({$idp}) "; $msg .= "Please tell an administrator about that problem!"; throw new CGE_CriticalAttributeException($msg); } $nren_id = $this->person->getNREN()->getID(); Logger::logEvent(LOG_INFO, "Confusa_Auth", "decoratePerson(..., {$idp})", "Decorating person with map from NREN {$nren_id}."); $map = $this->person->getMap(); /* Normal mapping, this is what we want. */ if ($this->mapSanityCheck($map)) { /* Now that we have the NREN-map, reiterate getMap() in * case we can find the subscriber-map. */ $this->person->setSubscriber(new Subscriber($attributes[$map['epodn']][0], $this->person->getNREN())); $new_map = $this->person->getMap(); if ($this->mapSanityCheck($new_map)) { $map = $new_map; } $eppn = Input::sanitizeEPPN($attributes[$map['eppn']][0]); $this->person->setEPPN($eppn); if (!is_null($map['eppn'])) { $this->person->setEPPNKey($map['eppn']); } if (!is_null($map['cn'])) { if (array_key_exists($map['cn'], $attributes)) { $cn = mysql_real_escape_string($attributes[$map['cn']][0]); $this->person->setName($cnPrefix . $cn); } } /* end map has cn */ if (!is_null($map['mail'])) { if (array_key_exists($map['mail'], $attributes)) { $mail = Input::sanitizeEmail($attributes[$map['mail']]); $this->person->setEmail($mail); } } /* go through and add the relevant entitlement-parts. * TODO: cleanup this and move to person::setEntitlement() */ if (!is_null($map['entitlement'])) { if (array_key_exists($map['entitlement'], $attributes)) { $entitlements = $attributes[$map['entitlement']]; } } if (isset($entitlements)) { $namespace = Config::get_config('entitlement_namespace'); foreach ($entitlements as $key => $entitlementValue) { $pos = strpos($entitlementValue, $namespace); /* Note: we *must* check for both false *and* * type, as we want pos to be 0 */ if ($pos === false || (int) $pos != 0) { continue; } else { $val = explode(":", $entitlementValue); if (count($val) !== count(explode(":", $namespace)) + 1) { Framework::error_output("Error with namespace, too many objects in namespace (" . count($val) . ")"); continue; } /* only set the part *after* * entitlement-namespace */ $entitlement = Input::sanitizeEntitlement($val[count($val) - 1]); /* is the entitlement a valid entitlement? */ if ($entitlement == Config::get_config('entitlement_user') || $entitlement == Config::get_config('entitlement_admin')) { $this->person->setEntitlement($entitlement); } } } } } else { /* At this point we're on shaky ground as we have to * 'see if we can find anything' * * no map is set, can we find the ePPN in there? */ $eppnKey = $this->findEPPN($attributes); if (!is_null($eppnKey)) { $eppn = Input::sanitizeEPPN($eppnKey['value']); $this->person->setEPPN($eppn); $this->person->setEPPNKey($eppnKey['key']); } /* is ePPN registred as NREN admin (from bootstrap) */ if ($this->person->isNRENAdmin()) { if (is_array($map)) { Logger::log_event(LOG_WARNING, "Map for NREN {$nren_id} ({$idp}) corrupted. " . "Contains empty fields, consider dropping the map."); } $msg = "No NREN map found!"; if (Config::get_config('debug')) { $msg .= "Raw-dump of supplied attributes:<br />\n"; $msg .= "<br /><pre>\n"; foreach ($attributes as $key => $val) { $tabs = "\t"; if (strlen($key) < 8) { $tabs .= "\t\t"; } else { if (strlen($key) < 16) { $tabs .= "\t"; } } $msg .= htmlentities("{$key}{$tabs}{$val[0]}") . "\n"; } $msg .= "</pre><br />\n"; } throw new MapNotFoundException($msg); } } }
static function log_event($pri, $message) { /* add this after the pri-test, as we don't want to */ if ($pri <= Config::get_config('syslog_min')) { openlog("confusa: ", LOG_PID | LOG_PERROR, LOG_LOCAL0); syslog((int) $pri, $message); closelog(); } /* open local logfile */ $fd = @fopen(Config::get_config('default_log'), 'a'); if (!$fd) { openlog("confusa: ", LOG_PID | LOG_PERROR, LOG_LOCAL0); syslog(LOG_EMERG, "Confusa: cannot open secondary logfile (" . Config::get_config('default_log') . ")"); closelog(); return; } /* log to normal file if within level. highest level is 0, increasing number * is lower pri */ if ($pri > Config::get_config('loglevel_min')) { fclose($fd); return; } /* The prefix for the log-messages that will be place in syslog * and confusa.log */ $header = ""; switch ($pri) { case LOG_DEBUG: $header .= ConfusaConstants::$LOG_HEADER_DEBUG; break; case LOG_INFO: $header .= ConfusaConstants::$LOG_HEADER_INFO; break; case LOG_NOTICE: $header .= ConfusaConstants::$LOG_HEADER_NOTICE; break; case LOG_WARNING: $header .= ConfusaConstants::$LOG_HEADER_WARNING; break; case LOG_ERR: $header .= ConfusaConstants::$LOG_HEADER_ERR; break; case LOG_CRIT: $header .= ConfusaConstants::$LOG_HEADER_CRIT; break; case LOG_ALERT: $header .= ConfusaConstants::$LOG_HEADER_ALERT; break; case LOG_EMERG: $header .= ConfusaConstants::$LOG_HEADER_EMERG; break; default: /* don't log things when you don't know how (un)important it is */ Framework::error_output("Don't know this loglevel ({$pri}). Please contact sys.developer"); return; break; } /* assemble line and enter into local log */ $timestamp = Logger::get_timestamp(); $log_body = " (Confusa) " . $header . " " . $message; $log_line = $timestamp . $log_body . "\n"; fputs($fd, $log_line); @fclose($fd); /* insert a critical error into the DB, if possible */ if ($pri <= Config::get_config('loglevel_fail')) { Logger::insertCriticalErrorIntoDB($pri, $log_body); } }
/** * downloadArchive() pack the RI-library in a zip-file and present it as * a file to download. * * @param : void * @return : Boolean True if no errors were encountered. */ private function downloadArchive() { require_once 'file_download.php'; $confusa_client = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/Confusa_Client.py"); $parser = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/Parser.py"); $https_client = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/HTTPSClient.py"); $timeout = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/Timeout.py"); $readme = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/README"); $license = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/LICENSE"); $gplv3 = file_get_contents(Config::get_config('install_path') . "/COPYING"); $init = file_get_contents(Config::get_config('install_path') . "/extlibs/XML_Client/__init__.py"); $zip = new ZipArchive(); $name = tempnam($ZIP_CACHE, "XML_Cli_"); $zip->open($name, ZipArchive::OVERWRITE); $zip->addFromString("XML_Client/Confusa_Client.py", $confusa_client); $zip->addFromString("XML_Client/Parser.py", $parser); $zip->addFromString("XML_Client/HTTPSClient.py", $https_client); $zip->addFromString("XML_Client/Timeout.py", $timeout); $zip->addFromString("XML_Client/README", $readme); $zip->addFromString("XML_Client/LICENSE", $license); $zip->addFromString("XML_Client/COPYING", $gplv3); $zip->addFromString("XML_Client/__init__.py", $init); if ($zip->numFiles != 8) { Logger::log_event(LOG_NOTICE, " Could not add all RI-library files to ZIP-archive."); Framework::error_output("Error creating archive. Cannot send"); return False; } if ($zip->close()) { $contents = file_get_contents($name); download_zip($contents, "XML_Client.zip"); } unlink($name); Logger::log_event(LOG_NOTICE, "Sending XML_Client.zip to " . $this->person->getEPPN()); return True; }
/** * getSubscribers - get an array with subscriber and state * * Find all subscribers for the current NREN and return an array containing * - subscriber name * - subscriber state (subscribed | unsubscribed | suspended) * */ private function getSubscribers() { try { return $this->person->getNREN()->getSubscriberList(); } catch (DBStatementException $dbse) { $errorTag = PW::create(); $msg = "Error in query-syntax. Verify that the query matches the database!"; Logger::logEvent(LOG_NOTICE, "NRENAdmin", "getSubscribers()", $msg, __LINE__, $errorTag); $msg .= "<br />Server said: " . htmlentities($dbse->getMessage()); Framework::error_output("[{$errorTag}]" . $msg); return; } catch (DBQueryException $dbqe) { $errorTag = PW::create(); $msg = "Possible constraint-violation in query. Compare query to db-schema"; Logger::logEvent(LOG_NOTICE, "NRENAdmin", "getSubscribers()", $msg, __LINE__, $errorTag); $msg .= "<br />Server said: " . htmlentities($dbse->getMessage()); Framework::error_output("[{$errorTag}]" . $msg); } }
public function start() { /* From OWASP (prevent clickjacking): * * This new (nonstandard) X-FRAME-OPTIONS header is used to mark * responses that shouldn't be framed. There are two options with * X-FRAME-OPTIONS. The first is DENY, which prevents everyone from * framing the content. * * This can also be done by apache itself: * a2enmod headers * Add to the Virtualhost, directory that hosts confusa: * Header set X-Frame-Options "DENY" */ header('X-Frame-Options: DENY'); /* * Strict-Transport-Security (RFC 6797) * Once page has been accessed over HTTPS and this header was present, * confirmant browsers will force subsequent requests over HTTPS aswell. */ header('Strict-Transport-Security: max-age=31536000'); /* Set tpl object to content page */ $this->contentPage->setTpl($this->tpl); /* check the authentication-thing, catch the login-hook * This is done via confusa_auth */ try { $this->authenticate(); } catch (CGE_CriticalAttributeException $cae) { $msg = "<b>" . $this->contentPage->translateMessageTag('fw_error_critical_attribute1') . "</b><br /><br />"; $msg .= htmlentities($cae->getMessage()) . "<br /><br />"; $msg .= $this->contentPage->translateMessageTag('fw_error_critical_attribute2'); Framework::error_output($msg); $this->renderError = true; } catch (MapNotFoundException $mnfe) { $msg = $this->contentPage->translateMessageTag('fw_error_map_notfound'); /* if user is admin */ if ($this->person->isNRENAdmin()) { $msg .= "<br /><br />"; $msg .= "<a href=\"attributes.php?mode=admin&anticsrf=" . Framework::getAntiCSRF() . "\">"; $msg .= $this->contentPage->translateMessageTag('fw_error_map_updatemap'); $msg .= "</>\n"; } Framework::error_output($msg); $this->renderError = true; } catch (ConfusaGenException $cge) { Framework::error_output($this->contentPage->translateMessageTag('fw_error_auth') . htmlentities($cge->getMessage())); $this->renderError = true; } if ($this->isCSRFAttempt()) { Framework::error_output($this->contentPage->translateMessageTag('fw_anticsrf_msg')); $this->tpl->assign('instance', Config::get_config('system_name')); $this->tpl->assign('errors', self::$errors); $this->tpl->display('site.tpl'); exit(0); } /* Create a new anti CSRF token and export to the template engine */ $this->current_anticsrf = self::getAntiCSRF(); $this->tpl->assign('ganticsrf', 'anticsrf=' . $this->current_anticsrf); $this->tpl->assign('panticsrf', '<input type="hidden" name="anticsrf" value="' . $this->current_anticsrf . '" />'); /* * Try to run the pre-processing */ try { $res = $this->contentPage->pre_process($this->person); if ($res) { $this->tpl->assign('extraHeader'); } } catch (CGE_RemoteCredentialException $rce) { $msg = $this->contentPage->translateMessageTag('fw_error_remote_credential1'); $msg .= "<i>" . htmlentities($rce->getMessage()) . "</i><br /><br />"; if ($this->person->isNRENAdmin()) { $msg .= "<div style=\"text-align: center\">"; $msg .= self::translateMessageTag('fw_error_remote_credential2') . "</div>"; } else { $msg .= Framework::error_output($this->contentPage->translateMessageTag('fw_error_remote_credential3')); $this->renderError = true; } Framework::warning_output($msg); } catch (KeyNotFoundException $knfe) { $this->renderError = true; $errorTag = PW::create(8); $msg = "[{$errorTag}] " . $this->contentPage->translateMessageTag('fw_keynotfound1'); Logger::logEvent(LOG_NOTICE, "Framework", "start()", "Config-file not properly configured: " . $knfe->getMessage(), __LINE__, $errorTag); $msg .= htmlentities($knfe->getMessage()); $msg .= "<br />" . $this->contentPage->translateMessageTag('fw_keynotfound2'); Framework::error_output($msg); } catch (Exception $e) { Framework::error_output($this->contentPage->translateMessageTag('fw_unhandledexp1') . "<br />" . htmlentities($e->getMessage())); $this->renderError = true; } /* ---------------------------------------------------------------- * Admin messages, trigger on missing elements */ if ($this->person->isNRENAdmin()) { $this->triggerAdminIssues(); } /* Mode-hook, to catch mode-change regardless of target-page (not only * index) */ if (isset($_GET['mode'])) { $new_mode = NORMAL_MODE; if (htmlentities($_GET['mode']) == 'admin') { $new_mode = ADMIN_MODE; } $this->person->setMode($new_mode); } $this->tpl->assign('title_logo', $this->contentPage->translateMessageTag('l10n_title_logo')); $this->tpl->assign('person', $this->person); $this->tpl->assign('subscriber', $this->person->getSubscriber()); $this->tpl->assign('nren', $this->person->getNREN()); $this->tpl->assign('is_online', Config::get_config('ca_mode') === CA_COMODO); /* If we have a renderError, do not allow the user-page to * render, otherwise, run it, and catch all unhandled exception * * The general idea, is that the process() should be * self-contained wrt to exceptions. * * A NREN admin is supposed to be able to "fix stuff" such as for instance * CGE_CriticalAttributeExceptions and should hence see the pages also if * renderError is set. */ if (!$this->renderError || $this->person->isNRENAdmin()) { try { $this->applyNRENBranding(); $this->contentPage->process($this->person); } catch (KeyNotFoundException $knfe) { $errorTag = PW::create(8); $msg = "[{$errorTag}] " . $this->contentPage->translateMessageTag('fw_keynotfound1'); Logger::logEvent(LOG_NOTICE, "Framework", "start()", "Config-file not properly configured: " . $knfe->getMessage(), __LINE__, $errorTag); $msg .= htmlentities($knfe->getMessage()); $msg .= "<br />" . $this->contentPage->translateMessageTag('fw_keynotfound2'); Framework::error_output($msg); } catch (Exception $e) { Logger::logEvent(LOG_INFO, "Framework", "start()", "Unhandleded exception when running contentPage->process()", __LINE__); Framework::error_output($this->contentPage->translateMessageTag('fw_unhandledexp1') . "<br />\n" . htmlentities($e->getMessage())); } } else { $nren = $this->person->getNREN(); if (isset($nren)) { /* if all else fails, at least give the user some recovery information */ Framework::message_output($this->contentPage->translateMessageTag('fw_unrecoverable_nren') . htmlentities($this->person->getEPPN())); } else { $errorTag = PW::create(); Framework::error_output("[{$errorTag}] " . $this->contentPage->translateMessageTag('fw_unrecoverable_nonren')); Logger::logEvent(LOG_WARNING, "Framework", "start()", "User contacting us from " . $_SERVER['REMOTE_ADDR'] . " tried to login from IdP that appears to have no NREN-mapping!", __LINE__, $errorTag); } } $this->tpl->assign('logoutUrl', 'logout.php'); // see render_menu($this->person) $this->tpl->assign('menu', $this->tpl->fetch('menu.tpl')); $this->tpl->assign('errors', self::$errors); $this->tpl->assign('messages', self::$messages); $this->tpl->assign('successes', self::$successes); $this->tpl->assign('warnings', self::$warnings); if (Config::get_config('debug')) { $db_debug_res = ""; $db_debug_res .= "<address>\n"; $db_debug_res .= "During this session, we had "; $db_debug_res .= MDB2Wrapper::getConnCounter() . " individual DB-connections.<br />\n"; $db_debug_res .= "</address>\n"; $this->tpl->assign('db_debug', $db_debug_res); } $this->tpl->display('site.tpl'); if (!$this->renderError) { $this->contentPage->post_process($this->person); } }
/** * verifyCSR() * * This function will test the CSR against several fields. * It will test the subject against the person-attributes (which in turn are * gathered from simplesamlphp-attributes (Feide, surfnet etc). * * @param String The CSR in base64 PEM format * @return Boolean True if valid CSR */ private function verifyCSR($csr) { /* by default, the CSR is valid, we then try to prove that it's invalid * * A better approach could be to distrust all CSRs and try to prove that * they are OK, however this leads to messy code (as the tests becomes * somewhat more involved) and I'm not convinced that it will be any safer. */ if (!isset($csr)) { Framework::error_output(__FILE__ . ":" . __LINE__ . " CSR not provided by caller1"); return false; } $subject = openssl_csr_get_subject($csr); /* check fields of CSR to predefined values and user-specific values * Make sure that the emailAddress is not set, as this is * non-compatible with ARC. */ if (isset($subject['emailAddress'])) { Framework::error_output("will not accept email in DN of certificate. Download latest version of script."); return false; } else { if (!match_dn($subject, $this->getFullDN())) { $msg = ""; $msg .= "Error in subject! <BR/>\n"; $msg .= "The fields in your CSR was not set properly.<BR>\n"; $msg .= "To try again, please download a new version of the script, "; $msg .= "generate a new key and upload again.<BR>\n"; Framework::error_output($msg); return false; } } return true; }
/** * Delete the NREN logo for the given position within Confusa. This will * really delete the physical file containing the logo. * * @param $position string a position from * ConfusaConstants::$ALLOWED_IMG_POSITIONS * @param $nren string the name of the NREN, whose custom-logo should be * removed * @return void */ private function deleteLogo($position, $nren) { $basepath = Config::get_config('custom_logo') . $nren . "/custom_"; $basepath .= $position . "."; $result = FALSE; foreach (ConfusaConstants::$ALLOWED_IMG_SUFFIXES as $sfx) { $logoName = $basepath . $sfx; if (file_exists($logoName)) { $result = unlink($logoName); break; } } if ($result === FALSE) { Framework::error_output($this->translateTag('l10n_error_delete_logo', 'stylist')); Logger::log_event(LOG_INFO, "[nadm] Error when trying to delete " . "NREN logo {$logoName}, for NREN {$nren}."); } else { Framework::success_output($this->translateTag('l10n_success_delete_logo', 'stylist')); } }
private function deleteAdmin($admin, $level) { /* does the current user have the rights? */ try { $query = "SELECT a.* FROM admins a LEFT JOIN nrens n on n.nren_id = a.nren"; $query .= " WHERE (a.admin=? OR a.admin=?) AND n.name=?"; $res = MDB2Wrapper::execute($query, array('text', 'text', 'text'), array($admin, $this->person->getEPPN(), $this->person->getNREN())); switch (count($res)) { case 0: Framework::error_output("Did not find neither the admin to delete or the current admin in the database. Cannot continue."); return; case 1: if ($res[0]['admin'] != $admin) { Framework::error_output("Cannot find the admin to delete in the admins-table. Cannot continue."); return; } break; case 2: $id = 0; if ($res[1]['admin'] == $admin) { $id = 1; } $nrenID = $res[$id]['nren']; $subscriberID = $res[$id]['subscriber']; break; default: Framework::error_output("Too many hits in the database. Cannot decide where to go from here."); return; } } catch (DBStatementException $dbse) { $msg = "Cannot find id-values in the database due to server problems. Server said: " . htmlentities($dbse->getMessage()); Framework::error_output($msg); return; } catch (DBQueryException $dbqe) { $msg = "Cannot find id-values due to data inconsistency. Server said: " . htmlentities($dbqe->getMessage()); Framework::error_output($msg); return; } /* Find the admin-level of both admins and make sure that the * enforcer (the admin performing the deletion) has the rights * to do so. */ if ($res[0]['admin'] == $admin) { $targetLevel = (int) $res[0]['admin_level']; $enforcerLevel = (int) $res[1]['admin_level']; } else { $targetLevel = (int) $res[1]['admin_level']; $enforcerLevel = (int) $res[0]['admin_level']; } if ($enforcerLevel < $targetLevel) { Framework::error_output("Cannot delete admin with higher admin-level."); return; } if ($targetLevel == NREN_ADMIN) { $query = "DELETE FROM admins WHERE admin=? AND nren=?"; $params = array('text', 'text'); $data = array($admin, $nrenID); } else { $query = "DELETE FROM admins WHERE admin=? AND nren=? AND subscriber=?"; $params = array('text', 'text', 'text'); $data = array($admin, $nrenID, $subscriberID); } try { MDB2Wrapper::update($query, $params, $data); Logger::log_event(LOG_INFO, "Successfully deleted admin {$admin} with level {$targetLevel}"); } catch (DBStatementException $dbse) { Framework::error_output("Could not delete the admin because the statement was bad " . "Please contact an administrator. Server said " . htmlentities($dbse->getMessage())); Logger::log_event(LOG_NOTICE, __FILE__ . ":" . __LINE__ . ": Problem occured when trying to delete " . "admin {$admin} with level {$level}: " . $dbse->getMessage()); } catch (DBQueryException $dbqe) { Framework::error_output("Could not delete the admin because of problems with the " . "received data. Server said " . htmlentities($dbqe->getMessage())); Logger::log_event(LOG_INFO, __FILE__ . ":" . __LINE__ . ": Problem occured when tyring to delete " . "admin {$admin} with level {$level}: " . $dbqe->getMessage()); } Framework::success_output($this->translateTag('l10n_suc_deleteadm1', 'admin') . " " . htmlentities($admin)); }
/** * getAdminStatus() get the admin-level from the database * * This function assumes isAuth() has been verified. * * @param void * @return Integer value indication the admin-level */ private function getAdminStatus() { if (isset($this->adminStatus)) { return $this->adminStatus; } $adminRes = NORMAL_USER; if (!$this->isAuth()) { $this->adminStatus = NORMAL_USER; return NORMAL_USER; } /* if the database is riddled with errors, do not run through the * test once more, just bail */ if ($this->adminDBError) { $this->adminStatus = NORMAL_USER; return NORMAL_USER; } require_once 'MDB2Wrapper.php'; $errorCode = PW::create(8); $query = "SELECT * FROM admins WHERE admin=:admin AND nren=:nren_id AND "; $query .= "((admin_level='2' AND (idp_url='' OR ISNULL(idp_url) OR idp_url=:idp_url)) OR "; $query .= "((admin_level='1' OR admin_level='0') AND subscriber=:subscriber_id))"; $params = array(); $params['admin'] = $this->eppn; $params['nren_id'] = $this->nren->getID(); $params['idp_url'] = $this->nren->getIdP(); $params['subscriber_id'] = -1; if (!is_null($this->getSubscriber())) { $params['subscriber_id'] = $this->getSubscriber()->getDBID(); } $res = MDB2Wrapper::execute($query, null, $params); $size = count($res); if ($size == 1) { $adminRes = $res[0]['admin_level']; if ($this->getName(false) != $res[0]['admin_name'] || $this->getEmail(false) != $res[0]['admin_email']) { try { MDB2Wrapper::update("UPDATE admins SET admin_name=?, admin_email=? WHERE admin_id=?", array('text', 'text', 'text'), array($this->getName(false), $this->getEmail(false), $res[0]['admin_id'])); } catch (DBStatementException $dbse) { $msg = "[{$errorCode}] Database not properly set. Missing fields in the admins-table."; Logger::log_event(LOG_ALERT, __FILE__ . ":" . __LINE__ . $msg); Framework::error_output($msg . "<br />Server said: " . $dbse->getMessage()); $this->adminDBError = true; } catch (DBQueryException $dbqe) { Logger::log_event(LOG_INFO, "[{$errorCode}] Could not update data for admin." . $dbqe->getMessage()); Framework::error_output("[{$errorCode}] Could not update data for admin. Problems with keys. Server said: " . $dbqe->getMessage()); $this->adminDBError = true; } catch (Exception $e) { $msg = "Could not update admin-data. Unknown error. Server said: " . $e->getMessage(); Framework::error_output($msg); Logger::Log_event(LOG_INFO, $msg); $this->adminDBError = true; } } } $this->adminStatus = $adminRes; return $adminRes; }
public function pre_process($person) { $res = true; $this->setPerson($person); $this->account = NRENAccount::get($this->person); /* If the caller is not a nren-admin or Confusa is not in online mode, we stop here */ if (!$this->person->isNRENAdmin() || Config::get_config('ca_mode') != CA_COMODO) { return false; } $login_name = false; $password = false; $ap_name = false; if (isset($_POST['account']) && $_POST['account'] === 'edit') { /* We must use POST as we may pass along a password and * we do not want to set that statically in the subject-line. */ if (isset($_POST['login_name'])) { $ln = $_POST['login_name']; $login_name = Input::sanitizeText(htmlspecialchars($ln)); if ($ln === $login_name) { $this->account->setLoginName($login_name); $res = false; } else { /* FIXME: l10n */ Framework::error_output("The new login_name contains illegal characters, dropping new login!"); } } /* Do not sanitize password, we should allow special characters and * stuff, we should url-encode it. If Comodo does not sanitize * their password, it's their business, not ours. */ if (isset($_POST['password']) && $_POST['password'] !== "") { $this->account->setPassword($_POST['password']); } if (isset($_POST['ap_name'])) { $ap = $_POST['ap_name']; $ap_name = Input::sanitizeText(htmlspecialchars($ap)); if ($ap === $ap_name) { $this->account->setAPName($ap_name); } else { /* FIXME: l10n */ Framework::error_output("Cleaned ap-name and it contains illegal characters, dropping new name!"); $res = false; } } /* should we validate? */ try { $validate = false; if (isset($_POST['verify_ca_cred']) && $_POST['verify_ca_cred'] === "yes") { $validate = true; } if ($this->account->save($validate)) { /* FIXME: l10n */ Framework::success_output("CA Account details successfully updated!"); } else { Framework::message_output("No changes to account-details, not updating."); } } catch (ConfusaGenException $cge) { /* FIXME: l10n */ Framework::error_output("Could not update account-data: " . $cge->getMessage()); } } parent::pre_process($person); return $res; }
public function process() { if (isset($_GET['show_root_cert'])) { try { $this->makeCertAvailable(); $cdata = file_get_contents($this->cert_path); $cert = new Certificate($cdata); $this->tpl->assign('ca_dump', $cert->getPEMContent(false)); } catch (ConfusaGenException $cge) { Framework::error_output($this->translateTag('l10n_cacert_fetch_error', 'rootcert')); } } if (isset($_GET['show_crl'])) { try { $this->makeCRLAvailable(); $crl = new CRL(file_get_contents($this->crl_path)); $this->tpl->assign('crl_dump', $crl->getPEMContent(false)); } catch (ConfusaGenException $cge) { Framework::error_output($this->translateTag('l10n_crl_fetch_error', 'rootcert')); } } $this->tpl->assign('ca_download_link', $this->cert_url); $this->tpl->assign('crl_download_link', $this->crl_url); $this->tpl->assign('content', $this->tpl->fetch('root_cert.tpl')); }