source: extensions/Password_Policy/include/functions.inc.php @ 31805

Last change on this file since 31805 was 30848, checked in by Eric, 9 years ago

Next version is 2.7.5 :
Fixed - Admins and Webmaster accounts were not correctly excluded on login failure protection

File size: 18.2 KB
Line 
1<?php
2
3load_language('plugin.lang', PP_PATH);
4
5/**
6 * Triggered on get_admin_plugin_menu_links
7 *
8 * Plugin's administration menu
9 */
10function PP_admin_menu($menu)
11{
12// +-----------------------------------------------------------------------+
13// |                      Getting plugin name                              |
14// +-----------------------------------------------------------------------+
15  $plugin =  PPInfos(PP_PATH);
16  $name = $plugin['name'];
17 
18  array_push($menu,
19    array(
20                'NAME' => $name,
21                'URL' => get_root_url().'admin.php?page=plugin-'.basename(PP_PATH)
22    )
23  );
24
25  return $menu;
26}
27
28
29/**
30 * Triggered on loc_begin_index
31 *
32 * Perform user logout after registration if account locked and redirection to profile page is password renewal is set
33 */
34function PP_Init()
35{
36  global $conf, $user;
37
38  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
39
40  $conf_PP = unserialize($conf['PasswordPolicy']);
41
42  // Perfoming redirection for locked accounts
43  // -----------------------------------------
44  if (!is_a_guest() and $user['username'] != "16" and $user['username'] != "18")
45  {
46    // Perform user logout if user account is locked
47    if (
48          (isset($conf_PP['LOGFAILBLOCK']) and $conf_PP['LOGFAILBLOCK'] == 'true')
49          and PP_UsrBlock_Verif($user['username'])
50          //and (isset($userlocked) and $userlocked == 'true')
51          and !is_admin()
52          and !is_webmaster())
53    {
54      invalidate_user_cache();
55      logout_user();
56      if ($conf['guest_access'])
57      {
58        redirect(make_index_url().'?PP_msg=locked', 0);
59      }
60      else
61      {
62        redirect(get_root_url().'identification.php?PP_msg=locked' , 0);
63      }
64    }
65  }
66
67  // Performing redirection to profile page for password reset
68  // ---------------------------------------------------------
69  if ((isset($conf_PP['PWDRESET']) and $conf_PP['PWDRESET'] == 'true'))
70  {
71    $query ='
72SELECT user_id, status
73FROM '.USER_INFOS_TABLE.'
74WHERE user_id = '.$user['id'].'
75;';
76    $data = pwg_db_fetch_assoc(pwg_query($query));
77
78    if ($data['status'] <> "webmaster" and $data['status'] <> "generic") // Exclusion of specific accounts
79    {
80      if (PP_check_pwdreset($user['id']))
81      {
82        redirect(PHPWG_ROOT_PATH.'profile.php');
83      }
84    }
85  }
86
87
88}
89
90
91/**
92 * Triggered on init
93 *
94 * Displays messages on index page
95 */
96function PP_InitPage()
97{
98  global $conf, $template, $page, $lang, $errors;
99
100  load_language('plugin.lang', PP_PATH);
101
102  if( isset($_GET['PP_msg']))
103  {
104    PP_DisplayMsg();
105  }
106}
107
108
109/**
110 * Triggered on init
111 *
112 * Display a message according to $_GET['PP_msg']
113 */
114function PP_DisplayMsg()
115{
116  if (isset($_GET['PP_msg']))
117  {
118    global $user, $lang, $conf, $page;
119    $conf_PP = unserialize($conf['PasswordPolicy']);
120
121    // User account locked after x failed attempts
122    if (isset($conf_PP['USRLOCKEDTXT']) and !empty($conf_PP['USRLOCKEDTXT']) and $_GET['PP_msg']=="locked")
123    {
124      if (function_exists('get_user_language_desc'))// Extended Description [lang] feature
125      {
126        $custom_text = get_user_language_desc($conf_PP['USRLOCKEDTXT']);
127      }
128      else $custom_text = l10n($conf_PP['USRLOCKEDTXT']);
129
130      $page["errors"][]=$custom_text;
131    }
132  }
133}
134
135
136/**
137 * Triggered on login_failure in main.inc.php
138 * Count of login failures and lock account after x attempt
139 *
140 */
141function PP_log_fail($username)
142{
143  global $conf, $user;
144
145  include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
146
147  $conf_PP = unserialize($conf['PasswordPolicy']);
148
149  if ((isset($conf_PP['NBLOGFAIL']) and $conf_PP['NBLOGFAIL'] <> 0)
150    and (isset($conf_PP['LOGFAILBLOCK']) and $conf_PP['LOGFAILBLOCK'] == 'true')
151    )
152  {
153    $query ='
154SELECT ui.status
155FROM '.USER_INFOS_TABLE.' AS ui
156  LEFT JOIN '.USERS_TABLE.' AS u
157    ON u.id = ui.user_id
158WHERE(u.username = "'.stripslashes($username).'")
159;';
160    $exclude = pwg_db_fetch_assoc(pwg_query($query));
161
162    // Exclude specific accounts
163    if ($exclude['status'] <> "webmaster" and $exclude['status'] <> "admin" and $exclude['status'] <> "generic")
164    {
165      // If login failure then increments loginfailcount value in database
166      $query = '
167UPDATE '.USERS_TABLE.'
168SET PP_loginfailcount = PP_loginfailcount+1
169WHERE username = "'.stripslashes($username).'"
170LIMIT 1
171;';
172      pwg_query($query);
173
174      $query = '
175SELECT PP_loginfailcount
176FROM '.USERS_TABLE.'
177WHERE username = "'.stripslashes($username).'"
178;';
179
180      $datas = pwg_db_fetch_assoc(pwg_query($query));
181
182      // If number of failed logon exceeds $conf_PP['NBLOGFAIL'], set the account as locked
183      if (isset($datas['PP_loginfailcount']) and $datas['PP_loginfailcount'] >= $conf_PP['NBLOGFAIL'])
184      {
185        $query = '
186UPDATE '.USERS_TABLE.'
187SET PP_lock = "true"
188WHERE username = "'.stripslashes($username).'"
189LIMIT 1
190;';
191        pwg_query($query);
192      }
193    }
194  }
195}
196
197
198/**
199 * PP_user_list_pwdreset
200 * Adds a new feature in user_list to allow password reset for selected users by admin
201 *
202 */
203function PP_user_list_pwdreset($visible_user_list)
204{
205  global $template;
206 
207  load_language('plugin.lang', PP_PATH);
208
209  $user_ids = array();
210
211  foreach ($visible_user_list as $i => $user)
212  {
213    $user_ids[$i] = $user['id'];
214  }
215
216  $user_nums = array_flip($user_ids);
217
218  // Query to get information in database
219  // ------------------------------------
220  if (!empty($user_ids))
221  {
222    $query = '
223SELECT DISTINCT id, PP_pwdreset
224  FROM '.USERS_TABLE.'
225  WHERE id IN ('.implode(',', $user_ids).')
226;';
227    $result = pwg_query($query);
228
229    while ($row = pwg_db_fetch_assoc($result))
230    {
231      if ($row['PP_pwdreset'] == 'false')
232      {
233        $pwdreset = l10n('PP_PwdReset_Done');
234      }
235      else if ($row['PP_pwdreset'] == 'true')
236      {
237        $pwdreset = l10n('PP_PwdReset_Todo');
238      }
239      else $pwdreset = l10n('PP_PwdReset_NA');
240
241                  $visible_user_list[$user_nums[$row['id']]]['plugin_columns'][] = $pwdreset; // Shows users password state in user_list
242    }
243  }
244  return $visible_user_list;
245}
246
247
248/**
249 * PP_user_list_locked
250 * Adds a new feature in user_list to allow user unlocking by admin
251 *
252 */
253function PP_user_list_locked($visible_user_list)
254{
255  global $template;
256 
257  load_language('plugin.lang', PP_PATH);
258
259  $template->append('plugin_user_list_column_titles', l10n('PP_LockedUsers'));
260
261  $user_ids = array();
262
263  foreach ($visible_user_list as $i => $user)
264  {
265    $user_ids[$i] = $user['id'];
266  }
267
268  $user_nums = array_flip($user_ids);
269
270  // Query to get information in database
271  // ------------------------------------
272  if (!empty($user_ids))
273  {
274    $query = '
275SELECT DISTINCT id, PP_lock
276  FROM '.USERS_TABLE.'
277  WHERE id IN ('.implode(',', $user_ids).')
278;';
279    $result = pwg_query($query);
280
281    while ($row = pwg_db_fetch_assoc($result))
282    {
283      if ($row['PP_lock'] == 'false')
284      {
285        $LockedUser = '<img src="'.PP_PATH.'admin/template/icons/nolock.png" title="'.l10n('PP_User Not Locked').'" alt="'.l10n('PP_User Not Locked').'"/>';
286      }
287      else if ($row['PP_lock'] == 'true')
288      {
289        $LockedUser = '<img src="'.PP_PATH.'admin/template/icons/lock.png" title="'.l10n('PP_User Locked').'" alt="'.l10n('PP_User Locked').'"/>';
290      }
291      else $LockedUser = '<img src="'.PP_PATH.'admin/template/icons/nolock.png" title="'.l10n('PP_User Not Locked').'" alt="'.l10n('PP_User Not Locked').'"/>';
292
293                  $visible_user_list[$user_nums[$row['id']]]['plugin_columns'][] = $LockedUser; // Shows users account state in user_list
294    }
295  }
296  return $visible_user_list;
297}
298
299
300/**
301 * Triggered on register_user_check
302 *
303 * Additional controls on user registration check
304 */
305function PP_RegistrationCheck($errors, $user)
306{
307  global $conf;
308
309  // Exclusion of Adult_Content users
310  // --------------------------------
311  if ($user['username'] != "16" and $user['username'] != "18")
312  {
313    load_language('plugin.lang', PP_PATH);
314
315    $PasswordCheck = 0;
316
317    $conf_PP = unserialize($conf['PasswordPolicy']);
318
319    // Password enforcement control
320    // ----------------------------
321    if (isset($conf_PP['PASSWORDENF']) and $conf_PP['PASSWORDENF'] == 'true' and !empty($conf_PP['PASSWORD_SCORE']))
322    {
323      if (!empty($user['password']) and !is_admin())
324      {
325        $PasswordCheck = PP_testpassword($user['password']);
326
327        if ($PasswordCheck < $conf_PP['PASSWORD_SCORE'])
328        {
329          $message = get_l10n_args('PP_Error_Password_Need_Enforcement_%s', $PasswordCheck);
330          $lang['reg_err_pass'] = l10n_args($message).$conf_PP['PASSWORD_SCORE'];
331          array_push($errors, $lang['reg_err_pass']);
332        }
333      }
334      else if (!empty($user['password']) and is_admin() and isset($conf_PP['ADMINPASSWENF']) and $conf_PP['ADMINPASSWENF'] == 'true')
335      {
336        $PasswordCheck = PP_testpassword($user['password']);
337
338        if ($PasswordCheck < $conf_PP['PASSWORD_SCORE'])
339        {
340          $message = get_l10n_args('PP_Error_Password_Need_Enforcement_%s', $PasswordCheck);
341          $lang['reg_err_pass'] = l10n_args($message).$conf_PP['PASSWORD_SCORE'];
342          array_push($errors, $lang['reg_err_pass']);
343        }
344      }
345    }
346    return $errors;
347  }
348}
349
350
351/**
352 * Triggered on loc_begin_profile
353 */
354function PP_Profile_Init()
355{
356  global $conf, $user, $template;
357 
358  load_language('plugin.lang', PP_PATH);
359
360  $conf_PP = unserialize($conf['PasswordPolicy']);
361
362  // Special message display for password reset
363  // ------------------------------------------
364  if ((isset($conf_PP['PWDRESET']) and $conf_PP['PWDRESET'] == 'true'))
365  {
366    if (PP_check_pwdreset($user['id']))
367    {
368      $template->append('errors', l10n('PP_Password_Reset_Msg'));
369    }
370  }
371
372  // Controls on profile page submission
373  // -----------------------------------
374  if (isset($_POST['validate']) and !is_admin())
375  {
376    // Password reset control
377    // ----------------------
378    if (isset($conf_PP['PWDRESET']) and $conf_PP['PWDRESET'] == 'true' and PP_check_pwdreset($user['id']))
379    {
380      // if password not changed then pwdreset field = true else pwdreset field = false
381      // ------------------------------------------------------------------------------
382      if (!empty($_POST['use_new_pwd']))
383      {
384        $query = '
385UPDATE '.USERS_TABLE.'
386SET PP_pwdreset = "false"
387WHERE id = '.$user['id'].'
388LIMIT 1
389;';
390        pwg_query($query);
391      }
392    }
393
394    if (!empty($_POST['use_new_pwd']))
395    {
396      // Password enforcement control
397      // ----------------------------
398      if (isset($conf_PP['PASSWORDENF']) and $conf_PP['PASSWORDENF'] == 'true' and !empty($conf_PP['PASSWORD_SCORE']))
399      {
400        $PasswordCheck = PP_testpassword($_POST['use_new_pwd']);
401
402        if ($PasswordCheck < $conf_PP['PASSWORD_SCORE'])
403        {
404          $message = get_l10n_args('PP_Error_Password_Need_Enforcement_%s', $PasswordCheck);
405          $template->append('errors', l10n_args($message).$conf_PP['PASSWORD_SCORE']);
406          unset($_POST['use_new_pwd']);
407          unset($_POST['validate']);
408        }
409      }
410    }
411  }
412}
413
414
415/**
416 * PP_Set_PwdReset
417 * Action in user_list to set a password reset for a user
418 */
419function PP_Set_PwdReset($uid)
420{
421  $query ='
422UPDATE '.USERS_TABLE.'
423SET PP_pwdreset = "true"
424WHERE id = '.$uid.'
425LIMIT 1
426;';
427
428  pwg_query($query);
429}
430
431
432/**
433 * PP_check_pwdreset
434 * checks if a user id is registered as having already
435 * changed his password.
436 *
437 * @uid        : the user id
438 *
439 * @returns    : true or false whether the users has already changed his password
440 *
441 */
442function PP_check_pwdreset($uid)
443{
444  $query = '
445SELECT PP_pwdreset
446FROM '.USERS_TABLE.'
447WHERE id='.$uid.'
448;';
449
450  $result = pwg_db_fetch_assoc(pwg_query($query));
451
452  if($result['PP_pwdreset'] == 'true')
453  {
454    return true;
455  }
456  else return false; 
457}
458
459
460/**
461 * Returns a password's score for password complexity check
462 *
463 * @param : password filled by user
464 *
465 * @return : Score calculation
466 *
467 * Thanx to MathieuGut from http://m-gut.developpez.com
468 */
469function PP_testpassword($password) // $password given by user
470{
471
472  // Variables initiation
473  // --------------------
474  $points = 0;
475  $point_lowercase = 0;
476  $point_uppercase = 0;
477  $point_numbers = 0;
478  $point_characters = 0;
479
480  // Getting password lengh
481  // ----------------------
482  $length = strlen($password);
483
484  // Loop to read password characters
485  for($i = 0; $i < $length; $i++)
486  {
487    // Select each letters
488    // $i is 0 at first turn
489    // ---------------------
490    $letters = $password[$i];
491
492    if ($letters>='a' && $letters<='z')
493    {
494      // Adding 1 point to score for a lowercase
495      // ---------------------------------------
496                                $points = $points + 1;
497
498      // Adding bonus points for lowercase
499      // ---------------------------------
500                  $point_lowercase = 1;
501    }
502    else if ($letters>='A' && $letters <='Z')
503    {
504      // Adding 2 points to score for uppercase
505      // --------------------------------------
506      $points = $points + 2;
507
508      // Adding bonus points for uppercase
509      // ---------------------------------
510      $point_uppercase = 2;
511    }
512    else if ($letters>='0' && $letters<='9')
513    {
514      // Adding 3 points to score for numbers
515      // ------------------------------------
516      $points = $points + 3;
517
518      // Adding bonus points for numbers
519      // -------------------------------
520      $point_numbers = 3;
521    }
522    else
523    {
524      // Adding 5 points to score for special characters
525      // -----------------------------------------------
526      $points = $points + 5;
527               
528      // Adding bonus points for special characters
529      // ------------------------------------------
530      $point_characters = 5;
531    }
532  }
533
534  // Calculating the coefficient points/length
535  // -----------------------------------------
536  $step1 = $points / $length;
537
538  // Calculation of the diversity of character types...
539  // --------------------------------------------------
540  $step2 = $point_lowercase + $point_uppercase + $point_numbers + $point_characters;
541
542  // Multiplying the coefficient of diversity with that of the length
543  // ----------------------------------------------------------------
544  $score = $step1 * $step2;
545
546  // Multiplying the result by the length of the string
547  // --------------------------------------------------
548  $finalscore = $score * $length;
549
550  return $finalscore;
551}
552
553
554/**
555 * PP_UsrBlock_Verif
556 * Check if the user's account is locked
557 *
558 * @returns : True if account is locked else False
559 */
560function PP_UsrBlock_Verif($username)
561{
562  global $conf;
563
564  $query = '
565SELECT PP_Lock
566FROM '.USERS_TABLE.'
567WHERE username = "'.stripslashes($username).'"
568;';
569
570  $result = pwg_db_fetch_assoc(pwg_query($query));
571
572  if($result['PP_Lock'] == 'true')
573  {
574    return true;
575  }
576  else return false;
577}
578
579
580/**
581 * PP_unlock_user
582 * Action in user_list to unlock a user
583 */
584function PP_unlock_user($uid)
585{
586  // Reset PP_loginfailcount value to 0
587  $query ='
588UPDATE '.USERS_TABLE.'
589SET PP_loginfailcount = 0
590WHERE id = '.$uid.'
591LIMIT 1
592;';
593
594  pwg_query($query);
595 
596  // Set account as unlocked
597  $query ='
598UPDATE '.USERS_TABLE.'
599SET PP_lock = "false"
600WHERE id = '.$uid.'
601LIMIT 1
602;';
603
604  pwg_query($query);
605}
606
607
608/**
609 * Function called from PP_admin.php - Get all users to display the number of days since their last visit
610 *
611 * @return : List of users
612 *
613 */
614function pp_get_user_list()
615{
616  global $conf, $page;
617
618  $users = array();
619
620  // Search users with exclusion of Adult_Content generic users and guest user
621  // -------------------------------------------------------------------------
622  $query = '
623SELECT DISTINCT u.'.$conf['user_fields']['id'].' AS id,
624                u.'.$conf['user_fields']['username'].' AS username,
625                u.'.$conf['user_fields']['email'].' AS email,
626                ui.status
627FROM '.USERS_TABLE.' AS u
628  INNER JOIN '.USER_INFOS_TABLE.' AS ui
629    ON u.'.$conf['user_fields']['id'].' = ui.user_id
630WHERE u.username NOT LIKE "16"
631  AND u.username NOT LIKE "18"
632;';
633
634  $result = pwg_query($query);
635     
636  while ($row = pwg_db_fetch_assoc($result))
637  {
638    $user = $row;
639    array_push($users, $user);
640  }
641
642  $user_ids = array();
643  foreach ($users as $i => $user)
644  {
645    $user_ids[$i] = $user['id'];
646  }
647
648  return $users;
649}
650
651
652/**
653 * Function called from PP_admin.php to get the plugin version and name
654 *
655 * @param : plugin directory
656 *
657 * @return : plugin's version and name
658 *
659 */
660function PPInfos($dir)
661{
662  $path = $dir;
663
664  $plg_data = implode( '', file($path.'main.inc.php') );
665  if ( preg_match("|Plugin Name: (.*)|", $plg_data, $val) )
666  {
667    $plugin['name'] = trim( $val[1] );
668  }
669  if (preg_match("|Version: (.*)|", $plg_data, $val))
670  {
671    $plugin['version'] = trim($val[1]);
672  }
673  if ( preg_match("|Plugin URI: (.*)|", $plg_data, $val) )
674  {
675    $plugin['uri'] = trim($val[1]);
676  }
677  if ($desc = load_language('description.txt', $path.'/', array('return' => true)))
678  {
679    $plugin['description'] = trim($desc);
680  }
681  elseif ( preg_match("|Description: (.*)|", $plg_data, $val) )
682  {
683    $plugin['description'] = trim($val[1]);
684  }
685  if ( preg_match("|Author: (.*)|", $plg_data, $val) )
686  {
687    $plugin['author'] = trim($val[1]);
688  }
689  if ( preg_match("|Author URI: (.*)|", $plg_data, $val) )
690  {
691    $plugin['author uri'] = trim($val[1]);
692  }
693  if (!empty($plugin['uri']) and strpos($plugin['uri'] , 'extension_view.php?eid='))
694  {
695    list( , $extension) = explode('extension_view.php?eid=', $plugin['uri']);
696    if (is_numeric($extension)) $plugin['extension'] = $extension;
697  }
698// IMPORTANT SECURITY !
699// --------------------
700  $plugin = array_map('htmlspecialchars', $plugin);
701
702  return $plugin ;
703}
704
705
706/**
707 * Useful for debugging - 4 vars can be set
708 * Output result to log.txt file
709 *
710 */
711function PPLog($var1, $var2, $var3, $var4)
712{
713   $fo=fopen (PP_PATH.'log.txt','a') ;
714   fwrite($fo,"======================\n") ;
715   fwrite($fo,'le ' . date('D, d M Y H:i:s') . "\r\n");
716   fwrite($fo,$var1 ."\r\n") ;
717   fwrite($fo,$var2 ."\r\n") ;
718   fwrite($fo,$var3 ."\r\n") ;
719   fwrite($fo,$var4 ."\r\n") ;
720   fclose($fo) ;
721}
722?>
Note: See TracBrowser for help on using the repository browser.