<?php if(!defined('PmWiki'))exit;
/**
  A passwordless DNS authentication for PmWiki
  Written by (c) Petko Yotov 2011
  Based on a script by (c) Oliver Betz 2008-2010

  This text is written for PmWiki; 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 3 of the License, or
  (at your option) any later version. See pmwiki.php for full details
  and lack of warranty.
*/
$RecipeInfo['AuthDNS']['Version'] = '20110603';

SDVA($HandleActions, array('authdns'=>'HandleAuthDNS'));
SDVA($AuthDNS, array(
  'page' => 'SiteAdmin.AuthDNS',
  'EnableReverseDNS' => 1,
  'CheckAll' => 1,
  'CookieDays' => 30,
  'UrlSuccess' => '$PageUrl',
  'UrlFailure' => '$PageUrl?action=login',
));
SDVA($FmtPV, array('$AuthSessDNS'=>'Keep(pre_r($_SESSION["AuthSessDNS"]))'));# debug

function HandleAuthDNS($pagename) {
  global $AuthDNS, $AuthUser, $IMSCookie;
  
  @session_start();
//   if(! isset($_SESSION['AuthSessDNS'])) { # if the function is called, the check is required, no cache
    $remote_ip = $_SERVER['REMOTE_ADDR'];
    
    $page = ReadPage($AuthDNS['page'], READPAGE_CURRENT); # get IP addresses and host names
    
    if(isset($page['text']) && preg_match_all("/^\\s*([-\\*\\.\\w\\[\\]\\?]+):\\s*(.+)$/m", $page['text'], $matches, PREG_SET_ORDER)) {
      $ips = $names = $authlist = array();
      foreach($matches as $k=>$a) {
        $addr = trim($a[1]); $auth = trim($a[2]);
        if(!preg_match("/[a-z]/i", $addr)) $ips[$addr] = $auth;
        else $names[$addr] = $auth;
      }
      
      ### IP addresses (fast)
      foreach($ips as $addr=>$auth) {
        $test = GlobToPCRE($addr);
        if(preg_match("/{$test[0]}/", $remote_ip)) {
          AuthDNSList($authlist, $auth);
        } # no need for break, ip-check is very fast
      }
      
      ### Suggested by the user (slower)
      if(count($authlist)<1 || $AuthDNS['CheckAll']) {
        $qname = '';
        if(@$_REQUEST['adnshost']>'') $qname = $_REQUEST['adnshost'];
        elseif(@$_COOKIE['adnshost']>'') $qname = $_COOKIE['adnshost']; # PHP 5.3
        if(isset($names[$qname])) {
          if($remote_ip == gethostbyname($qname))
            AuthDNSList($authlist, $names[$qname], $qname);
          unset($names[$qname]); # don't check it again later
        }
      }
      
      ### Reverse DNS of the visitor (slower)
      if(count($authlist)<1 && $AuthDNS['EnableReverseDNS']) {
        $rname = gethostbyaddr($remote_ip);
        if(isset($names[$rname])) { 
          AuthDNSList($authlist, $names[$rname], $rname);
        }
      }
      
      ### Check all hostnames (slowest)
      if(count($authlist)<1 || $AuthDNS['CheckAll']) {
        foreach($names as $name=>$auth) {
          $host_ip = gethostbyname($name);
          if($host_ip != $remote_ip) continue;
          AuthDNSList($authlist, $auth, $name);
          if(!$AuthDNS['CheckAll']) break;
        }
      }
      
      if(count($authlist)) {
        $a = array();
        if(isset($authlist['.'])) {
          $a['authid'] = $authlist['.'];
          unset($authlist['.']);
        }
        $a['authlist'] = $authlist;
        $_SESSION['AuthSessDNS'] = $a;
      }
      else $_SESSION['AuthSessDNS'] = false; # match not found
    }
    else $_SESSION['AuthSessDNS'] = false;   # no addresses in the page
//   }
  if($_SESSION['AuthSessDNS']) {
    SessionAuth($pagename, $_SESSION['AuthSessDNS']);
    if (isset($_COOKIE[$IMSCookie])) setcookie($IMSCookie, '', time()-43200, '/');
    Redirect($pagename, $AuthDNS['UrlSuccess']);
  }
  else Redirect($pagename, $AuthDNS['UrlFailure']);
}

### Populate the $authlist array and optionnally set a helper cookie
function AuthDNSList(&$authlist, $auth, $cookiehost='') {
  if(preg_match_all('/\\bid:(\\w+)\\b/', $auth, $m, PREG_PATTERN_ORDER)) {
    foreach ($m[1] as $u) { $authlist["id:$u"] = 1; $authlist["id:-$u"] = -1; $authlist['.'] = $u; break; }
  }
  if(preg_match_all('/(@\\w+)\\b/', $auth, $n, PREG_PATTERN_ORDER)) {
    foreach ($n[1] as $g) $authlist[$g] = 1;
  }
  if($cookiehost && $AuthDNS['CookieDays']) {
    global $AuthDNS;
    setcookie('adnshost', $cookiehost, time()+60*60*24*$AuthDNS['CookieDays'], '/');
  }
}