OSDN Git Service

FIX: PHP5/MySQL5における文法違反コードの修正
[nucleus-jp/nucleus-jp-ancient.git] / nucleus / plugins / NP_SecurityEnforcer.php
1 <?php
2 /**
3  * Attach plugin for Nucleus CMS
4  * Version 0.9.5 (1.0 RC) for PHP5
5  * Written by Cacher, Jan.16, 2011
6  * Original code was written by Frank Truscott, Nov. 01, 2009
7  * 
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 3
11  * of the License, or (at your option) any later version.
12  */
13
14 class NP_SecurityEnforcer extends NucleusPlugin {
15         public function getName()                       { return 'SecurityEnforcer'; }
16         public function getAuthor()             { return 'Frank Truscott + Cacher';     }
17         public function getURL()                        { return 'http://revcetera.com/ftruscot';       }
18         public function getVersion()            { return '1.02JP'; }
19         public function getDescription()        { return _SECURITYENFORCER_DESCRIPTION;}
20         public function getTableList()  { return array(sql_table('plug_securityenforcer')); }
21         public function hasAdminArea()  { return 1; }
22         public function getMinNucleusVersion()  { return 350; }
23         public function supportsFeature($feature)       { return in_array ($feature, array ('SqlTablePrefix', 'SqlApi'));}
24         public function getEventList()  { return array('QuickMenu','PrePasswordSet','CustomLogin','LoginSuccess','LoginFailed','PostRegister','PrePluginOptionsEdit'); }
25         
26         public function install() {
27                 global $CONF;
28                 $this->createOption('quickmenu', '_SECURITYENFORCER_OPT_QUICKMENU', 'yesno', 'yes');
29                 $this->createOption('del_uninstall_data', '_SECURITYENFORCER_OPT_DEL_UNINSTALL_DATA', 'yesno','no');
30                 $this->createOption('enable_security', '_SECURITYENFORCER_OPT_ENABLE', 'yesno','yes');
31                 $this->createOption('pwd_min_length', '_SECURITYENFORCER_OPT_PWD_MIN_LENGTH', 'text','8');
32                 //$this->createOption('pwd_complexity', _SECURITYENFORCER_OPT_PWD_COMPLEXITY, 'select','0',_SECURITYENFORCER_OPT_SELECT_OFF_COMP.'|0|'._SECURITYENFORCER_OPT_SELECT_ONE_COMP.'|1|'._SECURITYENFORCER_OPT_SELECT_TWO_COMP.'|2|'._SECURITYENFORCER_OPT_SELECT_THREE_COMP.'|3|'._SECURITYENFORCER_OPT_SELECT_FOUR_COMP.'|4');
33                 $this->createOption('pwd_complexity', '_SECURITYENFORCER_OPT_PWD_COMPLEXITY', 'select','0','_SECURITYENFORCER_OPT_SELECT');
34                 $this->createOption('max_failed_login', '_SECURITYENFORCER_OPT_MAX_FAILED_LOGIN', 'text', '5');
35                 $this->createOption('login_lockout', '_SECURITYENFORCER_OPT_LOGIN_LOCKOUT', 'text', '15');
36                 
37                 $query = "CREATE TABLE IF NOT EXISTS ". sql_table('plug_securityenforcer').
38                                         " ( 
39                                         `login` varchar(255),
40                                         `fails` int(11) NOT NULL default '0',                                     
41                                         `lastfail` bigint NOT NULL default '0',
42                                         KEY `login` (`login`)) ENGINE=MyISAM";
43                 sql_query($query);
44                 return;
45         }
46         
47         public function unInstall() {
48                 if ($this->getOption('del_uninstall_data') == 'yes')    {
49                         sql_query('DROP TABLE '.sql_table('plug_securityenforcer'));
50                 }
51                 return;
52         }
53         
54         public function init() {
55                 $language = preg_replace( '#\\\\|/#', '', getLanguageName());
56                 if (file_exists($this->getDirectory().$language.'.php')){
57                         include_once($this->getDirectory().$language.'.php');
58                 } else {
59                         include_once($this->getDirectory().'english.php');
60                 }
61                 
62                 $this->enable_security = $this->getOption('enable_security');
63                 $this->pwd_min_length = intval($this->getOption('pwd_min_length'));
64                 $this->pwd_complexity = intval($this->getOption('pwd_complexity'));
65                 $this->max_failed_login = intval($this->getOption('max_failed_login'));
66                 $this->login_lockout = intval($this->getOption('login_lockout'));
67                 return;
68         }
69         
70         public function event_QuickMenu(&$data) {
71                 global $member;
72                 if ($this->getOption('quickmenu') != 'yes' || !$member->isAdmin()) {
73                         return;
74                 }
75                 if (!($member->isLoggedIn())) {
76                         return;
77                 }
78                 array_push($data['options'],
79                 array('title' => 'Security Enforcer',
80                         'url' => $this->getAdminURL(),
81                         'tooltip' => _SECURITYENFORCER_ADMIN_TOOLTIP)
82                 );
83                 return;
84         }
85         
86         public function event_PrePasswordSet(&$data) {
87                 if ($this->enable_security == 'yes') {
88                         $password = $data['password'];
89                         if (postVar('action') == 'changemembersettings'){
90                                 $emptyAllowed = true;
91                         } else {
92                                 $emptyAllowed = false;
93                         }
94                         if ((!$emptyAllowed)||$password) {
95                                 $message = $this->_validate_and_messsage($password,$this->pwd_min_length, $this->pwd_complexity);
96                                 if ($message) {
97                                         $data['errormessage'] = _SECURITYENFORCER_INSUFFICIENT_COMPLEXITY . $message. "<br /><br />\n";
98                                         $data['valid'] = false;
99                                 }
100                         }
101                 }
102                 return;
103         }
104         
105         public function event_PostRegister(&$data) {
106                 if ($this->enable_security == 'yes') {
107                         $password = postVar('password');
108                         if(postVar('action') == 'memberadd'){
109                                 $message = $this->_validate_and_messsage($password,$this->pwd_min_length, $this->pwd_complexity);
110                                 if ($message) {
111                                         $errormessage = _SECURITYENFORCER_ACCOUNT_CREATED. $message. "<br /><br />\n";
112                                         global $admin;
113                                         $admin->error($errormessage);
114                                 }
115                         }
116                 }
117                 return;
118         }
119         
120         public function event_CustomLogin(&$data) {
121                 if ($this->enable_security == 'yes' && $this->max_failed_login > 0) {
122                         global $_SERVER;
123                         $login = $data['login'];
124                         $ip = $_SERVER['REMOTE_ADDR'];
125                         sql_query("DELETE FROM ".sql_table('plug_securityenforcer')." WHERE lastfail < ".(time() - ($this->login_lockout * 60)));
126                         $query = "SELECT fails as result FROM ".sql_table('plug_securityenforcer')." ";
127                         $query .= "WHERE login='".sql_real_escape_string($login)."'";
128                         $flogin = quickQuery($query); 
129                         $query = "SELECT fails as result FROM ".sql_table('plug_securityenforcer')." ";
130                         $query .= "WHERE login='".sql_real_escape_string($ip)."'";
131                         $fip = quickQuery($query); 
132                         if ($flogin >= $this->max_failed_login || $fip >= $this->max_failed_login) {
133                                 $data['success'] = 0;
134                                 $data['allowlocal'] = 0;
135                                 $info = sprintf(_SECURITYENFORCER_LOGIN_DISALLOWED, htmlspecialchars($login), htmlspecialchars($ip));
136                                 ACTIONLOG::add(INFO, $info);
137                         }
138                 }
139                 return;
140         }
141         
142         public function event_LoginSuccess(&$data) {
143                 if ($this->enable_security == 'yes' && $this->max_failed_login > 0) {
144                         global $_SERVER;
145                         $login = $data['username'];
146                         $ip = $_SERVER['REMOTE_ADDR'];
147                         sql_query("DELETE FROM ".sql_table('plug_securityenforcer')." WHERE login='".sql_real_escape_string($login)."'");
148                         sql_query("DELETE FROM ".sql_table('plug_securityenforcer')." WHERE login='".sql_real_escape_string($ip)."'");
149                 }
150                 return;
151         }
152         
153         function event_LoginFailed(&$data) {
154                 if ($this->enable_security == 'yes' && $this->max_failed_login > 0) {
155                         global $_SERVER;
156                         $login = $data['username'];
157                         $ip = $_SERVER['REMOTE_ADDR'];
158                         $lres = sql_query("SELECT * FROM ".sql_table('plug_securityenforcer')." WHERE login='".sql_real_escape_string($login)."'");
159                         if (sql_num_rows($lres)) {
160                                 sql_query("UPDATE ".sql_table('plug_securityenforcer')." SET fails=fails+1, lastfail=".time()." WHERE login='".sql_real_escape_string($login)."'");
161                         }
162                         else {
163                                 sql_query("INSERT INTO ".sql_table('plug_securityenforcer')." (login,fails,lastfail) VALUES ('".sql_real_escape_string($login)."',1,".time().")");
164                         }
165                         $lres = sql_query("SELECT * FROM ".sql_table('plug_securityenforcer')." WHERE login='".sql_real_escape_string($ip)."'");
166                         if (sql_num_rows($lres)) {
167                                 sql_query("UPDATE ".sql_table('plug_securityenforcer')." SET fails=fails+1, lastfail=".time()." WHERE login='".sql_real_escape_string($ip)."'");
168                         }
169                         else {
170                                 sql_query("INSERT INTO ".sql_table('plug_securityenforcer')." (login,fails,lastfail) VALUES ('".sql_real_escape_string($ip)."',1,".time().")");
171                         }
172                 }
173                 return;
174         }
175         
176         public function event_PrePluginOptionsEdit($data) {
177                 if ($data['plugid'] === $this->getID()) {
178                         foreach($data['options'] as $key => $value){
179                                 if (defined($value['description'])) {
180                                         $data['options'][$key]['description'] = constant($value['description']);
181                                 }
182                                 if (!strcmp($value['type'], 'select') && defined($value['typeinfo'])) {
183                                         $data['options'][$key]['typeinfo'] = constant($value['typeinfo']);
184                                 }
185                         }
186                 }
187                 return;
188         }
189         
190         /* Helper Functions */
191         
192         private function _validate_passwd($passwd,$minlength = 6,$complexity = 0) {
193                 $minlength = intval($minlength);
194                 $complexity = intval($complexity);
195                 
196                 if ($minlength < 6 ) {
197                         $minlength = 6;
198                 }
199                 if (strlen($passwd) < $minlength) {
200                         return false;
201                 }
202                 
203                 if ($complexity > 4) $complexity = 4;
204                 $ucchars = "[A-Z]";
205                 $lcchars = "[a-z]";
206                 $numchars = "[0-9]";
207                 $ochars = "[-~!@#$%^&*()_+=,.<>?:;|]";
208                 $chartypes = array($ucchars, $lcchars, $numchars, $ochars);
209                 $tot = array(0,0,0,0);
210                 $i = 0;
211                 foreach ($chartypes as $value) {
212                         $tot[$i] = preg_match("/".$value."/", $passwd);
213                         $i = $i + 1;
214                 }
215
216                 if (array_sum($tot) >= $complexity) {
217                         return true;
218                 }
219                 else return false;
220         }
221         
222         private function _validate_and_messsage($passwd,$minlength = 6,$complexity = 0) {
223                 $minlength = intval($minlength);
224                 $complexity = intval($complexity);
225
226                 if ($minlength < 6 ) {
227                         $minlength = 6;
228                 }
229                 if (strlen($passwd) < $minlength) {
230                         $message = _SECURITYENFORCER_MIN_PWD_LENGTH . $this->pwd_min_length;
231                 }
232
233                 if ($complexity > 4) {
234                         $complexity = 4;
235                 }
236                 $ucchars = "[A-Z]";
237                 $lcchars = "[a-z]";
238                 $numchars = "[0-9]";
239                 $ochars = "[-~!@#$%^&*()_+=,.<>?:;|]";
240                 $chartypes = array($ucchars, $lcchars, $numchars, $ochars);
241                 $tot = array(0,0,0,0);
242                 $i = 0;
243                 foreach ($chartypes as $value) {
244                         $tot[$i] = preg_match("/".$value."/", $passwd);
245                         $i = $i + 1;
246                 }
247
248                 if (array_sum($tot) < $complexity) {
249                         $message .= _SECURITYENFORCER_PWD_COMPLEXITY . $this->pwd_complexity;
250                 }
251                 return $message;
252         }
253 }