* Admin:
- Show last contact date on marketing validation -Fal/FRU
- New page to add users in the database -FRU
+ - New IP based security tool -FRU
* AXLetter:
- New module AXLetter (legal mailer for AX) -FRU
$forlife = str_replace("'","",$forlife);
return $forlife;
}
+
+function check_ip($level)
+{
+ $test = array();
+ switch ($level) {
+ case 'unsafe': $test[] = "state = 'unsafe'";
+ case 'dangerous': $test[] = "state = 'dangerous'";
+ case 'ban': $test[] = "state = 'ban'"; break;
+ default: return false;
+ }
+ $res = XDB::query("SELECT state
+ FROM ip_watch
+ WHERE ip = {?} AND (" . implode(' OR ', $test) . ')',
+ $_SERVER['REMOTE_ADDR']);
+ return $res->numRows();
+}
+
+function send_warning_mail($title)
+{
+ $mailer = new PlMailer();
+ $mailer->setFrom("webmaster@polytechnique.org");
+ $mailer->addTo("florent.bruneau@polytechnique.org");
+ $mailer->setSubject($title);
+ $mailer->setTxtBody("Identifiants de session :\n" . var_export($_SESSION, true) . "\n\n"
+ ."Identifiants de connexion :\n" . var_export($_SERVER, true));
+ $mailer->send();
+}
+
?>
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
***************************************************************************/
+require_once 'xorg.misc.inc.php';
+
class XorgSession
{
// {{{ public static function init
- public static function init() {
+ public static function init()
+ {
S::init();
- if (!S::has('uid')) {
- try_cookie();
+ if (!S::has('uid')) {
+ try_cookie();
+ }
+ if (check_ip('dangerous') && S::has('uid')) {
+ $_SESSION['log']->log("view_page", $_SERVER['REQUEST_URI']);
}
}
// }}}
// {{{ public static function destroy()
- public static function destroy() {
+ public static function destroy()
+ {
S::destroy();
XorgSession::init();
}
if ($logger) {
$logger->log('auth_ok');
}
- start_connexion($uid, true);
+ if (!start_connexion($uid, true)) {
+ return false;
+ }
if (Env::v('remember', 'false') == 'true') {
$cookie = hash_encrypt(S::v('password'));
setcookie('ORGaccess',$cookie,(time()+25920000),'/','',0);
*/
public static function doAuthCookie()
{
- if (S::logged()) {
- return true;
+ if (S::logged()) {
+ return true;
}
- if (Env::has('username') and Env::has('response')) {
- return XorgSession::doAuth();
+ if (Env::has('username') and Env::has('response')) {
+ return XorgSession::doAuth();
}
- if ($r = try_cookie()) {
- return XorgSession::doAuth(($r > 0));
+ if ($r = try_cookie()) {
+ return XorgSession::doAuth(($r > 0));
}
return false;
function try_cookie()
{
if (Cookie::v('ORGaccess') == '' or !Cookie::has('ORGuid')) {
- return -1;
+ return -1;
}
$res = @XDB::query(
Cookie::i('ORGuid'));
if ($res->numRows() != 0) {
- list($uid, $password) = $res->fetchOneRow();
- require_once('secure_hash.inc.php');
- $expected_value = hash_encrypt($password);
- if ($expected_value == Cookie::v('ORGaccess')) {
- start_connexion($uid, false);
- return 0;
- } else {
+ list($uid, $password) = $res->fetchOneRow();
+ require_once('secure_hash.inc.php');
+ $expected_value = hash_encrypt($password);
+ if ($expected_value == Cookie::v('ORGaccess')) {
+ if (!start_connexion($uid, false)) {
+ return -3;
+ }
+ return 0;
+ } else {
return 1;
}
}
FROM auth_user_md5 AS u
INNER JOIN auth_user_quick AS q USING(user_id)
INNER JOIN aliases AS a ON (u.user_id = a.id AND a.type='a_vie')
- INNER JOIN aliases AS a2 ON (u.user_id = a2.id AND FIND_IN_SET('bestalias',a2.flags))
+ INNER JOIN aliases AS a2 ON (u.user_id = a2.id AND FIND_IN_SET('bestalias',a2.flags))
LEFT JOIN logger.sessions AS s ON (s.uid=u.user_id AND s.suid=0)
WHERE u.user_id = {?} AND u.perms IN('admin','user')
ORDER BY s.start DESC
$_SESSION = array_merge($_SESSION, $sess);
$_SESSION['log'] = $logger;
$_SESSION['auth'] = ($identified ? AUTH_MDP : AUTH_COOKIE);
+ if (check_ip('unsafe')) {
+ send_warning_mail("Une IP surveillee a tente de se connecter");
+ if (check_ip('ban')) {
+ $_SESSION = array();
+ global $page;
+ $page->trig("Une erreur est survenue lors de la procédure d'authentification. "
+ ."Merci de contacter au plus vite "
+ ."<a href='mailto:support@polytechnique.org'>support@polytechnique.org</a>");
+ return false;
+ }
+ }
set_skin();
+ return true;
}
// }}}
'admin/validate' => $this->make_hook('validate', AUTH_MDP, 'admin'),
'admin/validate/answers' => $this->make_hook('validate_answers', AUTH_MDP, 'admin'),
'admin/wiki' => $this->make_hook('wiki', AUTH_MDP, 'admin'),
+ 'admin/ipwatch' => $this->make_hook('ipwatch', AUTH_MDP, 'admin'),
);
}
$page->assign('wiki_pages', $wiki_tree);
$page->assign('perms_opts', $perms);
}
+
+ function handler_ipwatch(&$page, $action = 'list', $ip = null)
+ {
+ $page->changeTpl('admin/ipwatcher.tpl');
+
+ $states = array('safe' => 'Ne pas surveiller',
+ 'unsafe' => 'Surveiller les inscription',
+ 'dangerous' => 'Surveiller tous les accès',
+ 'ban' => 'Bannir cette adresse');
+ $page->assign('states', $states);
+
+ switch (Post::v('action')) {
+ case 'create':
+ if (trim(Post::v('ipN')) != '') {
+ Xdb::execute('INSERT IGNORE INTO ip_watch (ip, state, detection, last, uid, description)
+ VALUES ({?}, {?}, CURDATE(), NOW(), {?}, {?})',
+ trim(Post::v('ipN')), Post::v('stateN'), S::i('uid'), Post::v('descriptionN'));
+ };
+ break;
+
+ case 'edit':
+ Xdb::execute('UPDATE ip_watch
+ SET state = {?}, last = NOW(), uid = {?}, description = {?}
+ WHERE ip = {?}', Post::v('stateN'), S::i('uid'), Post::v('descriptionN'), Post::v('ipN'));
+ break;
+
+ default:
+ if ($action == 'delete' && !is_null($ip)) {
+ Xdb::execute('DELETE FROM emails_watch WHERE ip = {?}', $ip);
+ }
+ }
+ if ($action != 'create' && $action != 'edit') {
+ $action = 'list';
+ }
+ $page->assign('action', $action);
+
+ if ($action == 'list') {
+ $sql = "SELECT w.ip, s.host, w.detection, w.state, a.alias AS forlife
+ FROM ip_watch AS w
+ LEFT JOIN logger.sessions AS s USING(ip)
+ LEFT JOIN aliases AS a ON (a.id = s.uid AND a.type = 'a_vie')
+ GROUP BY w.ip, a.alias
+ ORDER BY w.state, w.ip, a.alias";
+ $it = Xdb::iterRow($sql);
+
+ $table = array();
+ $props = array();
+ while (list($ip, $host, $date, $state, $forlife) = $it->next()) {
+ if (count($props) == 0 || $props['ip'] != $ip) {
+ if (count($props) > 0) {
+ $table[] = $props;
+ }
+ $props = array('ip' => $ip,
+ 'host' => $host,
+ 'detection' => $date,
+ 'state' => $state,
+ 'users' => array($forlife));
+ } else {
+ $props['users'][] = $forlife;
+ }
+ }
+ if (count($props) > 0) {
+ $table[] = $props;
+ }
+ $page->assign('table', $table);
+ } elseif ($action == 'edit') {
+ $sql = "SELECT w.detection, w.state, w.last, w.description,
+ a1.alias AS edit, a2.alias AS forlife, s.host
+ FROM ip_watch AS w
+ LEFT JOIN aliases AS a1 ON (a1.id = w.uid AND a1.type = 'a_vie')
+ LEFT JOIN logger.sessions AS s ON (w.ip = s.ip)
+ LEFT JOIN aliases AS a2 ON (a2.id = s.uid AND a2.type = 'a_vie')
+ WHERE w.ip = {?}
+ GROUP BY a2.alias
+ ORDER BY a2.alias";
+ $it = Xdb::iterRow($sql, $ip);
+
+ $props = array();
+ while (list($detection, $state, $last, $description, $edit, $forlife, $host) = $it->next()) {
+ if (count($props) == 0) {
+ $props = array('ip' => $ip,
+ 'host' => $host,
+ 'detection' => $detection,
+ 'state' => $state,
+ 'last' => $last,
+ 'description' => $description,
+ 'edit' => $edit,
+ 'users' => array($forlife));
+ } else {
+ $props['users'][] = $forlife;
+ }
+ }
+ $page->assign('ip', $props);
+ }
+ }
}
?>
function createHash($line, $key)
{
- $hash = implode(time(), $line);
+ $hash = implode(time(), $line) . rand();
$hash = md5($hash);
return $hash;
}
function handler_register(&$page, $hash = null)
{
+ $alert = null;
$sub_state = S::v('sub_state', Array());
if (!isset($sub_state['step'])) {
$sub_state['step'] = 0;
break;
case 3:
- $alert = null;
if (count($_POST)) {
require_once(dirname(__FILE__) . '/register/register.inc.php');
if (!isvalid_email(Post::v('email'))) {
$promo = (int)$sub_state['promo'];
if ($year > $promo - 15 || $year < $promo - 30) {
$err[] = "La 'Date de naissance' n'est pas correcte.";
- $alert = "Date de naissance proposée $birth\n\n";
+ $alert = "Date de naissance incorrecte a l'inscription - ";
}
}
$aliases[] = $alias;
}
if (count($aliases) != 0) {
- $alert .= "Email proposé : " . Post::v('email') . "\n"
- . "Ce mails est connu avec l'état $state :\n"
- . $description . "\n"
- . "Pour les alias :\n* " . join("\n* ", $aliases) . "\n\n";
+ $alert .= "Email surveille propose a l'inscription - ";
+ }
+
+ if (check_ip('unsafe')) {
+ unset($err);
}
if (isset($err)) {
substr($birth,2,2),
substr($birth,0,2));
$sub_state['email'] = Post::v('email');
- $sub_state['step'] = 4;
- finish_ins($sub_state);
- }
- if (!is_null($alert)) {
- send_alert_mail($sub_state, $alert);
+ if (check_ip('unsafe')) {
+ $err = "Une erreur s'est produite lors de l'inscription."
+ . " Merci de contacter <a href='register@polytechnique.org'>register@polytechnique.org</a>"
+ . " pour nous faire part de cette erreur";
+ $alert .= "Tentative d'inscription depuis une IP surveillee";
+ } else {
+ $sub_state['step'] = 4;
+ finish_ins($sub_state);
+ }
}
}
break;
}
$_SESSION['sub_state'] = $sub_state;
+ if ($alert) {
+ send_warning_mail($alert);
+ }
$page->changeTpl('register/step'.intval($sub_state['step']).'.tpl');
if (isset($err)) {
$page->trig($err);
$mymail->assign('prenom', $prenom);
$mymail->send();
- start_connexion($uid,false);
+ if (!start_connexion($uid,false)) {
+ return PL_FORBIDDEN;
+ }
$_SESSION['auth'] = AUTH_MDP;
/***********************************************************/
}
// }}}
-// {{{ function send_alert_mail
-
-function send_alert_mail($state, $body)
-{
- $mailer = new PlMailer();
- $mailer->setFrom("webmaster@polytechnique.org");
- $mailer->addTo("hotliners@staff.polytechnique.org");
- $mailer->setSubject("ALERTE LORS DE L'INSCRIPTION de "
- . $state['prenom'] . ' ' . $state['nom'] . '(' . $promo . ')');
- $mailer->setTxtBody($body
- . "\n\nIndentifiants :\n" . var_export($state, true)
- . "\n\nInformations de connexion :\n" . var_export($_SERVER, true));
- $mailer->send();
-}
-
-// }}}
// {{{ function finish_ins
function finish_ins($sub_state)
<a href="admin/logger/actions">Actions</a>
|
<a href="admin/emails/duplicated">Doublons</a>
+ |
+ <a href="admin/ipwatch">IPs</a>
</td>
</tr>
</table>
--- /dev/null
+{**************************************************************************}
+{* *}
+{* Copyright (C) 2003-2007 Polytechnique.org *}
+{* http://opensource.polytechnique.org/ *}
+{* *}
+{* This program is free software; you can redistribute it and/or modify *}
+{* it under the terms of the GNU General Public License as published by *}
+{* the Free Software Foundation; either version 2 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 General Public License for more details. *}
+{* *}
+{* You should have received a copy of the GNU General Public License *}
+{* along with this program; if not, write to the Free Software *}
+{* Foundation, Inc., *}
+{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *}
+{* *}
+{**************************************************************************}
+
+<h1>Gestion des IPs surveillées</h1>
+
+{if $action eq "list"}
+<table class="bicol">
+ <tr>
+ <th>Adresse</th>
+ <th>Etat</th>
+ <th>Utilisateurs</th>
+ <th></th>
+ </tr>
+ <tr class="impair">
+ <td colspan="2">
+ <strong>Ajouter une entrée</strong>
+ </td>
+ <td colspan="2" class="right">
+ <strong><a href="admin/ipwatch/create">créer{icon name=add}</a></strong>
+ </td>
+ </tr>
+ {foreach from=$table item=ip}
+ <tr class="{cycle values="pair,impair"}">
+ <td>
+ <strong>{$ip.ip}</strong><br />
+ <small>{$ip.host}</small><br />
+ Ajoutée le {$ip.detection|date_format}
+ </td>
+ <td>
+ {$ip.state}
+ </td>
+ <td class="right">
+ {foreach from=$ip.users item=user name=all}
+ {if $user}
+ <a href="profile/{$user}" class="popup2">{$user}</a>
+ <a href="admin/user/{$user}">{icon name=wrench title=Administrer}</a>
+ <a href="admin/logger/user/{$user}">{icon name=information title="Logs"}</a>{if !$smarty.foreach.all.last}<br />{/if}
+ {/if}
+ {/foreach}
+ </td>
+ <td class="right">
+ <a href="admin/ipwatch/edit/{$ip.ip}">{icon name=page_edit title="Editer"}</a>
+ <a href="admin/ipwatch/delete/{$ip.ip}">{icon name=delete title="Supprimer"}</a>
+ </td>
+ </tr>
+ {/foreach}
+</table>
+{elseif $action eq "create" || $action eq "edit"}
+[<a href="admin/ipwatch">Retour à la liste des IPs surveillées</a>]<br /><br />
+<form method="post" action="admin/ipwatch">
+<table class="tinybicol">
+ <tr>
+ <th colspan="2">Commenter une adresse IP</th>
+ </tr>
+ <tr class="impair">
+ {if $action eq "create"}
+ <td class="titre">Adresse IP</td>
+ <td><input type="text" name="ipN" /></td>
+ {else}
+ <td colspan="2">
+ <strong>{$ip.ip}</strong> ({$ip.host})
+ <input type="hidden" name="ipN" value="{$ip.ip}" />
+ </td>
+ </tr>
+ {foreach from=$ip.users key=i name=all item=user}
+ {if $user}
+ {if $i is even}<tr class="impair">{/if}
+ <td>
+ <a href="profile/{$user}" class="popup2">{$user}</a>
+ <a href="admin/user/{$user}">{icon name=wrench title="Administrer}</a>
+ <a href="admin/logger/user/{$user}">{icon name=information title="Logs"}</a>{if !$smarty.foreach.all.last}<br />{/if}
+ </td>
+ {if $i is even && $smarty.foreach.all.last}<td></td>{/if}
+ {if $i is odd || $smarty.foreach.all.last}</tr>{/if}
+ {/if}
+ {/foreach}
+ <tr class="pair">
+ <td class="titre">Date de détection</td>
+ <td>{$ip.detection|date_format}</td>
+ {/if}
+ </tr>
+ <tr class="pair">
+ <td class="titre">Danger</td>
+ <td>
+ <select name="stateN">
+ {foreach from=$states key=state item=text}
+ <option value="{$state}"{if $ip.state eq $state} selected="selected"{/if}>{$text}</option>
+ {/foreach}
+ </select>
+ </td>
+ </tr>
+ <tr class="impair">
+ <td colspan="2" class="titre">Description</td>
+ {if $ip.edit}
+ </tr>
+ <tr class="impair">
+ <td colspan="2">
+ <small>Dernière édition par {$ip.edit} le {$ip.last|date_format}</small>
+ </td>
+ {/if}
+ </tr>
+ <tr class="impair">
+ <td colspan="2" class="center">
+ <textarea cols="50" rows="10" name="descriptionN">{$ip.description}</textarea>
+ </td>
+ </tr>
+ <tr>
+ <th colspan="2">
+ <input type="hidden" name="action" value="{$action}" />
+ <input type="submit" name="valid" value="Valider" />
+ </th>
+ </tr>
+</table>
+</form>
+{/if}
+
+{* vim:set et sw=2 sts=2 sws=2: *}
--- /dev/null
+CREATE TABLE `ip_watch` (
+ `ip` CHAR(16) NOT NULL,
+ `state` ENUM('safe', 'unsafe', 'dangerous', 'ban') NOT NULL DEFAULT 'unsafe',
+ `detection` DATE DEFAULT 0,
+ `last` TIMESTAMP DEFAULT 0,
+ `uid` SMALLINT(5) DEFAULT NULL,
+ `description` TEXT NOT NULL,
+ PRIMARY KEY(`ip`)
+);
+use logger;
+alter table sessions add key(ip);
+insert into actions (text, description) values ('view_page', 'Consultation d\'une page');
+use x4dat;
+
+# vim:set syntax=mysql: