user is_auth() is_cert() methods added
[brisk.git] / web / Obj / brisk.phh
index 2323342..6ff2b8e 100644 (file)
@@ -151,10 +151,10 @@ $mlang_brisk = array( 'btn_backstand'=> array( 'it' => 'torna in piedi',
 $G_lng = langtolng($G_lang);
 
 $G_all_points = array( 11,10,4,3,2, 0,0,0,0,0 );
-$G_brisk_version = "4.14.2";
+$G_brisk_version = "4.14.3";
 
 /* MLANG: ALL THE INFO STRINGS IN brisk.phh */
-$root_wellarr = array( 'it' => array ( 'Brisk (Ver. '.$G_brisk_version.'), <b>NOVITA\'</b>: nuovo sistema di registrazione degli utenti, aggiunto reinvio dell\' email di verifica',
+$root_wellarr = array( 'it' => array ( 'Brisk (Ver. '.$G_brisk_version.'), <b>NOVITA\'</b>: nuovo sistema di registrazione degli utenti, aggiunto reinvio dell\' email di verifica, ban con classi di IP',
                                        'Se vuoi iscriverti alla <a target="_blank" href="mailto:ml-briscola+subscribe@milug.org">Mailing List</a>, cliccala!' ),
                        'en' => array ( 'Brisk (Ver. '.$G_brisk_version.'), <b>NEWS</b>: new users subscription system.',
                                        'If you want to subscribe our <a target="_blank" href="ml-briscola+subscribe@milug.org">Mailing List</a>, click it!' ) );
@@ -578,6 +578,33 @@ function xcapemesg($s)
 }
 
 
+class IPClass {
+    var $addr;
+    var $mask;
+
+    function IPClass($ipset)
+    {
+        //split
+        $elem = split("/", $ipset, 2);
+        $addr = $elem[0];
+        $mask = (int)$elem[1];
+
+        //convert mask
+
+        $this->mask = ((1<<($mask))-1) << (32 - $mask);
+        $this->addr = ip2long($addr) & $this->mask;
+
+        fprintf(STDERR, "New ipclass: %x (%x)\n", $this->addr, $this->mask);
+    }
+
+    function match($ip)
+    {
+        fprintf(STDERR, "IP: %x, ADDR: %x, MASK: %x -> (%d)\n",
+                $ip, $this->addr, $this->mask, ((ip2long($ip) & $this->mask) == $this->addr));
+        return (($ip & $this->mask) == $this->addr);
+    }
+}
+
 class Vect {
     function Vect($a)
     {
@@ -595,12 +622,17 @@ class Vect {
     }
 }
 
+define('TABLE_AUTH_TY_PUBL', 0);
+define('TABLE_AUTH_TY_AUTH', 1);
+define('TABLE_AUTH_TY_CERT', 2);
+
+
 class Table {
   var $idx;
   var $player;
   var $player_n;
 
-  var $auth_only;     // se tavolo riservato o libero
+  var $auth_type;     // required authorization to sit down
 
   var $wag_own;
   var $wag_com;
@@ -623,7 +655,13 @@ class Table {
     $thiz->idx       =   $idx;
     $thiz->player    =   array();
     $thiz->player_n  =   0;
-    $thiz->auth_only =   FALSE;
+
+    if ($idx < TABLES_CERT_N)
+        $thiz->auth_type =   TABLE_AUTH_TY_CERT;
+    else if ($idx < TABLES_AUTH_N)
+        $thiz->auth_type =   TABLE_AUTH_TY_AUTH;
+    else
+        $thiz->auth_type =   TABLE_AUTH_TY_PUBL;
 
     $thiz->wag_own   =  -1;
     $thiz->wag_com   =  "";
@@ -647,7 +685,7 @@ class Table {
 
     log_main("PLAYER_N - parent::copy.".$this->player_n);
     
-    $this->auth_only =  $from->auth_only;
+    $this->auth_type =  $from->auth_type;
 
     $this->wag_own   =  $from->wag_own;
     $this->wag_com   =  $from->wag_com;
@@ -680,7 +718,7 @@ class Table {
       $thiz->player[$i] = $i;
     $thiz->player_n = $from->player_n;
 
-    $thiz->auth_only =  $from->auth_only;
+    $thiz->auth_type =  $from->auth_type;
 
     $thiz->wag_own = $from->wag_own;
     $thiz->wag_com = $from->wag_com;
@@ -751,7 +789,7 @@ class Table {
     }
   }
 
-  // function act_content($isstanding, $sitted, $table, $cur_table, $allowed)
+  // Table->act_content - return 'id' of type of output required for table button
   function act_content($user)
   {
     $ret = "";
@@ -763,15 +801,23 @@ class Table {
 
     if ($isstanding) {
       if ($sitted < PLAYERS_N) {
-        if ($this->auth_only) {
-          if ($user->flags & USER_FLAG_AUTH) 
-            $act = "sitreser";
-          else
-            $act = 'reserved';
-        }
-        else {
-          $act = 'sit';
-        }
+          switch ($this->auth_type) {
+          case TABLE_AUTH_TY_CERT:
+              if ($user->is_cert())
+                  $act = "sitcert";
+              else
+                  $act = 'resercert';
+              break;
+          case TABLE_AUTH_TY_AUTH:
+              if ($user->is_auth())
+                  $act = "sitreser";
+              else
+                  $act = 'reserved';
+              break;
+          default:
+              $act = 'sit';
+              break;
+          }
       }
       else {
         $act = 'none';
@@ -945,35 +991,171 @@ class Brisk
     var $step; // current step of the comm array
     var $garbage_timeout;
     var $shm_sz;
-    
+
+    var $ban_list;  // ban list (authized allowed)
+    var $black_list;  // black list (anti-dos, noone allowed)
+
     var $delay_mgr;
 
     public static $sess_cur;
 
-    function Brisk($crystal_filename) {
-        $this->crystal_filename = $crystal_filename;
-        $this->user  = array();
-        $this->table = array();
-        $this->match = array();
-        
+    function Brisk()
+    {
+    }
+
+    // constructor
+    static function create($crystal_filename, $ban_list, $black_list) {
+        if (($brisk_ser = @file_get_contents($crystal_filename)) != FALSE) {
+            if (($brisk = unserialize($brisk_ser)) != FALSE) {
+                fprintf(STDERR, "ROOM FROM FILE\n");
+                rename($crystal_filename, $crystal_filename.".old");
+
+                $brisk->reload($ban_list, $black_list);
+
+                return($brisk);
+            }
+        }
+
+        fprintf(STDERR, "NEW ROOM\n");
+        $thiz = new Brisk();
+
+        $thiz->crystal_filename = $crystal_filename;
+        $thiz->user  = array();
+        $thiz->table = array();
+        $thiz->match = array();
+
+        $thiz->ban_list = NULL;
+        $thiz->black_list = NULL;
+
+        fprintf(STDERR, "PRE IPCLASS_UPDATE (%d, %d)\n", count($ban_list), count($black_list));
+        $thiz->ipclass_update('ban_list', $ban_list);
+        $thiz->ipclass_update('black_list', $black_list);
+        fprintf(STDERR, "POST IPCLASS_UPDATE %d %d\n", count($thiz->ban_list), count($thiz->black_list));
+
         for ($i = 0 ; $i < MAX_PLAYERS ; $i++) {
-            $this->user[$i] = User::create($this, $i, "", "");
+            $thiz->user[$i] = User::create($thiz, $i, "", "");
         }
         
         for ($i = 0 ; $i < TABLES_N ; $i++) {
-            $this->table[$i] = Table::create($i);
-
-            if ($i < TABLES_AUTH_N) 
-                $this->table[$i]->auth_only = TRUE;
-            else
-                $this->table[$i]->auth_only = FALSE;
+            $thiz->table[$i] = Table::create($i);
         }
-        $this->garbage_timeout = 0;
-        $this->shm_sz = SHM_DIMS_MIN;
+        $thiz->garbage_timeout = 0;
+        $thiz->shm_sz = SHM_DIMS_MIN;
 
-        $this->delay_mgr = new Delay_Manager(1.5);
+        $thiz->delay_mgr = new Delay_Manager(1.5);
 
         static::$sess_cur = FALSE;
+
+        return ($thiz);
+    }
+
+    function ipclass_update($ip_out_s, $ip_in)
+    {
+        fprintf(STDERR, "N_IN: %d\n", count($ip_in));
+
+        $ip_out = &$this->$ip_out_s;
+
+        // if already set clean the ban_list property
+        if ($ip_out) {
+            $ct = count($ip_out);
+            for ($i = 0 ; $i < $ct ; $i++) {
+                unset($ip_out[$i]);
+            }
+            unset($ip_out);
+        }
+
+        $ip_out = array();
+        for ($i = 0 ; $i < count($ip_in) ; $i++) {
+            $ip_out[$i] = new IPClass($ip_in[$i]);
+        }
+    }
+
+    function reload($ban_list, $black_list)
+    {
+        fprintf(STDERR, "RELOAD STUFF (%d)(%d)\n", count($ban_list), count($black_list));
+
+        $this->ipclass_update("ban_list", $ban_list);
+        $this->ipclass_update("black_list", $black_list);
+
+        $this->banned_kickoff();
+        $this->garbage_manager(TRUE);
+    }
+
+    function banned_kickoff()
+    {
+        $is_ban = FALSE;
+
+        for ($table_idx = 0 ; $table_idx < TABLES_N ; $table_idx++) {
+            $table_cur = $this->table[$table_idx];
+            // if the table is complete and exists we check users IP
+
+            if ($table_cur->player_n == PLAYERS_N) {
+                if (isset($this->match[$table_idx]) &&
+                    $table_cur->table_token == $bin5->table_token) {
+                    log_main("PLAYERS == N TABLE ".$table_idx);
+
+                    $bin5 = $this->match[$table_idx];
+
+                    $is_ban |= $bin5->banned_kickoff();
+                }
+            }
+        }
+
+        for ($i = 0 ; $i < MAX_PLAYERS ; $i++) {
+            $user_cur = $this->user[$i];
+
+            if ($user_cur->sess == "")
+                continue;
+
+            // check if the IP is blacklisted
+            if ($this->black_check($user_cur->ip)) {
+                $user_cur->lacc = 0;
+                $is_ban = TRUE;
+                continue;
+            }
+
+            // if authorized not check if banlisted
+            if ($user_cur->is_auth()) {
+                continue;
+            }
+
+            if ($this->ban_check($user_cur->ip)) {
+                $user_cur->lacc = 0;
+                $is_ban = TRUE;
+            }
+        }
+
+        return $is_ban;
+    }
+
+    function ban_check($ip_str)
+    {
+        $ip = ip2long($ip_str);
+        fprintf(STDERR, "Brisk::ban_check %d\n", count($this->ban_list));
+        for ($i = 0 ; $i < count($this->ban_list) ; $i++) {
+            fprintf(STDERR, "ban_list[%d] = %x (%x)\n", $i,
+                    $this->ban_list[$i]->addr, $this->ban_list[$i]->mask);
+            if ($this->ban_list[$i]->match($ip)) {
+                fprintf(STDERR, "\n\nMATCHA!\n\n");
+                return(TRUE);
+            }
+        }
+        return (FALSE);
+    }
+
+    function black_check($ip_str)
+    {
+        $ip = ip2long($ip_str);
+        fprintf(STDERR, "Brisk::black_check %d\n", count($this->black_list));
+        for ($i = 0 ; $i < count($this->black_list) ; $i++) {
+            fprintf(STDERR, "black_list[%d] = %x (%x)\n", $i,
+                   $this->black_list[$i]->addr, $this->black_list[$i]->mask);
+            if ($this->black_list[$i]->match($ip)) {
+                fprintf(STDERR, "\n\nMATCHA!\n\n");
+                return(TRUE);
+            }
+        }
+        return (FALSE);
     }
 
   function garbage_manager($force)
@@ -1658,16 +1840,16 @@ class Brisk
       }
     }
     else if (strcmp($msg, "/authreq") == 0) {
-      if ($user->flags & USER_FLAG_AUTH) {
-        $to_user = sprintf('authbox(300,200);');
-      }
-      else {
-        /* MLANG: "<b>Per autenticare qualcuno devi a tua volta essere autenticato.</b>", "Il nickname deve contenere almeno una lettera dell\'alfabeto o una cifra.", "Nickname <b>%s</b> gi&agrave; in uso." */
-        $to_user = sprintf('chatt_sub("%s", [2, "%s"],"%s");', $dt, NICKSERV, $mlang_brisk['authmust'][$G_lang]);
-      }
+        if ($user->is_cert()) {
+            $to_user = sprintf('authbox(300,200);');
+        }
+        else {
+            /* MLANG: "<b>Per autenticare qualcuno devi a tua volta essere autenticato.</b>", "Il nickname deve contenere almeno una lettera dell\'alfabeto o una cifra.", "Nickname <b>%s</b> gi&agrave; in uso." */
+            $to_user = sprintf('chatt_sub("%s", [2, "%s"],"%s");', $dt, NICKSERV, $mlang_brisk['authmust'][$G_lang]);
+        }
     }
     else if (strncmp($msg, "/mesgtoadm", 8) == 0) {
-      if ($user->flags & USER_FLAG_AUTH) {
+        if ($user->is_auth()) {
         $to_user = sprintf('mesgtoadmbox(500,300);');
       }
       else {
@@ -1700,11 +1882,11 @@ class Brisk
         }
         
         /* MLANG: "<b>Non puoi cambiare nick a un tavolo per soli autenticati.</b>", "Il nickname <b>\'%s\'</b> &egrave; gi&agrave; registrato, <b>se il suo proprietario si autentificher&agrave; verrai rinominato d\'ufficio come ghost<i>N</i>.</b>" */
-        if ($user->flags & USER_FLAG_AUTH) {
+        if ($user->is_auth()) {
           if (strcasecmp($user->name,$name_new) != 0) {
              if (( ($user->flags & USER_FLAG_MAP_AUTH) != USER_FLAG_ISOLAUTH) &&
                 ($user->subst == 'standup' || 
-                 ($user->subst != 'standup' && $this->table[$user->table]->auth_only == FALSE)
+                 ($user->subst != 'standup' && $this->table[$user->table]->auth_type == TABLE_AUTH_TY_PUBL)
                  )
                 ) {
               $user->flags &= ~(USER_FLAG_AUTH | USER_FLAG_TY_ALL); // Remove auth if name changed
@@ -1720,7 +1902,7 @@ class Brisk
         }
        $user->name = $name_new; // OK - nick changed
         /* se nome gia' in uso, segnala cosa potrebbe capitare */
-        if (($user->flags & USER_FLAG_AUTH) == 0) {
+        if ( ! $user->is_auth() ) {
             if (($bdb = BriskDB::create()) != FALSE) {
                 $bdb->users_load();
                 /* MLANG: "Il nickname <b>\'%s\'</b> &egrave; gi&agrave; registrato, <b>se il suo proprietario si autentificher&agrave; verrai rinominato d\'ufficio come ghost<i>N</i>.</b>" */
@@ -1873,9 +2055,9 @@ class Brisk
         if ($is_normchat == TRUE) {
           // use MAP_AUTH to check if auth or isolation
           if ($user_cur->flags & USER_FLAG_MAP_AUTH) {
-            if (($user->flags & USER_FLAG_AUTH) == 0) {
-              continue;
-            }
+              if ( ! $user->is_auth() ) {
+                  continue;
+              }
           }
         }
         /*
@@ -2029,7 +2211,7 @@ class Brisk
       if (strcasecmp($this->user[$i]->name, $name_new) == 0) {
           if ($authenticate != FALSE) {
               $ghost = $i;
-              $ghost_auth = ($this->user[$i]->flags & USER_FLAG_AUTH);
+              $ghost_auth = $this->user[$i]->is_auth();
           }
           else {
               $idx = $i;
@@ -2098,7 +2280,6 @@ class Brisk
       $this->user[$idx]->ip = $ip;
 
       $this->user[$idx]->rec = $authenticate;
-      fprintf(STDERR, "MOP: [%s]\n", $authenticate->supp_comp);
       $this->user[$idx]->flags = $user_type;
       $this->user[$idx]->flags |= ($authenticate != FALSE ? USER_FLAG_AUTH : 0x00);
       $this->user[$idx]->flags |= ( ($pass != FALSE && $bdb == FALSE) ? USER_FLAG_DBFAILED : 0x00);
@@ -2202,118 +2383,6 @@ class Brisk
     }
   }
 
-  // Static functions
-  static function create($crystal_filename)
-  {
-      if (($brisk_ser = @file_get_contents($crystal_filename)) == FALSE ||
-          ($brisk = unserialize($brisk_ser)) == FALSE) {
-          fprintf(STDERR, "NEW ROOM\n");
-          $brisk = new Brisk($crystal_filename);
-      }
-      else {
-          fprintf(STDERR, "ROOM FROM FILE\n");
-          rename($crystal_filename, $crystal_filename.".old");
-      }
-
-    return $brisk;
-  }
-  
-  
-  function load_data() 
-  {
-    GLOBAL $sess;
-
-    do {
-      if (($tok = @ftok(FTOK_PATH."/main", "C")) == -1) {
-       log_main("ftok failed");
-       break;
-      }
-    
-      if (($shm_sz = sharedmem_sz($tok)) == -1) {
-       log_main("shmop_open failed");
-      }
-       
-      if ($shm_sz == -1)
-       $shm_sz = SHM_DIMS_MIN;
-
-      if ($shm = shm_attach($tok, $shm_sz)) {
-          $brisk = @shm_get_var($shm, $tok); // CHECKED BELOW
-          
-          log_only("bri ==  ".($brisk == FALSE ?   "FALSE" : "TRUE")."  bri ===  ".($brisk === FALSE ? "FALSE" : "TRUE")."  bri isset ".(isset($brisk) ?   "TRUE" : "FALSE"));
-          if (isset($brisk))
-              log_only("bri count ".count($brisk));
-          
-          if ($brisk == FALSE) {
-              log_only("INIT MAIN DATA");
-              shm_detach($shm);
-              
-              $brisk = Brisk::create();
-              
-              log_shme("Brisk::create");
-
-              if (Brisk::save_data($brisk) == FALSE)
-                  return FALSE;
-
-              return $brisk;
-          }
-          $brisk->shm_sz = $shm_sz;
-          
-          shm_detach($shm);
-
-          for ($i = 0 ; $i < MAX_PLAYERS ; $i++) {
-              if (($brisk->user[$i] = User::load_data($i, FALSE)) == FALSE) {
-                  log_crit("User::load_data failed");
-                  break;
-              }
-          }
-          if ($i < MAX_PLAYERS) {
-              break;
-          }
-      }
-      
-      //  
-      // SHSPLIT: load users from the shared memory
-      //
-      return ($brisk);
-    } while (0);
-    
-    return (FALSE);
-  }
-  
-
-  function save_data_orig($brisk) 
-  {
-    GLOBAL $sess;
-    
-    $shm =   FALSE;
-    
-    // var_dump($brisk);
-    
-    if (($tok = @ftok(FTOK_PATH."/main", "C")) == -1) 
-      return (FALSE);
-    
-    while ($brisk->shm_sz < SHM_DIMS_MAX) {
-      if (($shm = shm_attach($tok, $brisk->shm_sz)) == FALSE)
-       break;
-      
-      // log_only("PUT_VAR DI ".strlen(serialize($brisk)));
-      if (@shm_put_var($shm, $tok, $brisk) != FALSE) {
-       shm_detach($shm);
-       return (TRUE);
-      }
-      if (shm_remove($shm) === FALSE) {
-       log_only("REMOVE FALLITA");
-       break;
-      }
-      shm_detach($shm);
-      $brisk->shm_sz += SHM_DIMS_DLT;
-    } 
-
-    if ($shm)
-      shm_detach($shm);
-    
-    return (FALSE);
-  }
   function dump_data()
   {
       $brisk_ser = serialize($this);
@@ -2325,77 +2394,6 @@ class Brisk
       return (FALSE);
   }
 
-  function save_data($brisk) 
-  {
-      GLOBAL $sess;
-    
-      $ret =   FALSE;
-      $shm =   FALSE;
-    
-      if (($tok = @ftok(FTOK_PATH."/main", "C")) == -1) 
-          return (FALSE);
-    
-      // SHSPLIT: before save the $brisk you must save users, 
-      //          detach from main struct and (then) reattach
-      $user_park = array();
-      for ($i = 0 ; $i < MAX_PLAYERS ; $i++) {
-          $user_park[$i]  = $brisk->user[$i];
-          $brisk->user[$i] = FALSE;
-      }
-
-      while ($brisk->shm_sz < SHM_DIMS_MAX) {
-          if (($shm = shm_attach($tok, $brisk->shm_sz)) == FALSE)
-              break;
-      
-          // log_only("PUT_VAR DI ".strlen(serialize($brisk)));
-          if (@shm_put_var($shm, $tok, $brisk) != FALSE) {
-              log_shme("Brisk::save_data");
-              $ret = TRUE;
-              break;
-          }
-          if (shm_remove($shm) === FALSE) {
-              log_only("REMOVE FALLITA");
-              break;
-          }
-          shm_detach($shm);
-          $brisk->shm_sz += SHM_DIMS_DLT;
-      } 
-
-      if ($shm)
-          shm_detach($shm);
-    
-      // SHSPLIT: reattach users to the room class
-      for ($i = 0 ; $i < MAX_PLAYERS ; $i++) {
-          User::save_data($user_park[$i], $i);
-          $brisk->user[$i] = $user_park[$i];
-      }
-      log_load("FINISH: ".($ret == TRUE ? "TRUE" : "FALSE"));
-
-      return ($ret);
-  }
-
-  static function lock_data($is_exclusive)
-  {
-      if (($res = file_lock(FTOK_PATH."/main", $is_exclusive)) != FALSE) {
-          self::$delta_t = microtime(TRUE);
-          log_lock("LOCK   room         [".self::$delta_t."]");
-          
-          return ($res);
-      }
-
-      return (FALSE);
-  }
-  
-  static function unlock_data($res)
-  {
-    GLOBAL $sess; 
-    
-    log_lock("UNLOCK room         [".(microtime(TRUE) - (self::$delta_t))."]");
-
-    file_unlock($res);
-  }
-
-
   function standup_content($user)
   {
     $ret = "";
@@ -2488,9 +2486,17 @@ class Brisk
 
   function request_mgr(&$s_a_p, $header, &$header_out, &$new_socket, $path, $addr, $get, $post, $cookie)
   {
-      GLOBAL $G_black_list;
+      GLOBAL $G_ban_list, $G_black_list;
 
       printf("NEW_SOCKET (root): %d PATH [%s]\n", intval($new_socket), $path);
+      $remote_addr = addrtoipv4($addr);
+
+          fprintf(STDERR, "\n\n\n PRE_BLACK_CHECK \n\n\n");
+      if ($this->black_check($remote_addr)) {
+          // TODO: waiting async 5 sec before close
+          fprintf(STDERR, "\n\n\n BLACK_CHECK \n\n\n");
+          return (FALSE);
+      }
 
       $enc = get_encoding($header);
       if (isset($header['User-Agent'])) {
@@ -3019,7 +3025,7 @@ function log_legal($curtime, $addr, $user, $where, $mesg)
   if (($fp = @fopen(LEGAL_PATH."/legal.log", 'a')) != FALSE) {
     /* Unix time | session | nickname | IP | where was | mesg */
     fwrite($fp, sprintf("%ld|%s|%s|%s|%s|%s|%s|\n", $curtime, $user->sess,
-                        ($user->flags & USER_FLAG_AUTH ? 'A' : 'N'),
+                        ($user->is_auth() ? 'A' : 'N'),
                         $user->name, $addr, $where , $mesg));
     fclose($fp);
   }