Alternc  latest
Alternc logiel libre pour l'hébergement
m_admin.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  ----------------------------------------------------------------------
5  LICENSE
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License (GPL)
9  as published by the Free Software Foundation; either version 2
10  of the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  To read the license please visit http://www.gnu.org/copyleft/gpl.html
18  ----------------------------------------------------------------------
19 */
20 
21 /**
22  * Manage the AlternC's account administration (create/edit/delete)
23  *
24  * @copyright AlternC-Team 2000-2017 https://alternc.com/
25  */
26 class m_admin {
27 
28 
29  /**
30  * $enabled tells if the logged user is super-admin or not
31  */
32  var $enabled = 0;
33 
34 
35  /** List of the controls made for each TLD
36  *
37  * $tldmode is used by the administration panel, while choosing
38  * the authorized TLDs. It's an array of strings explaining the current state of the TLD.
39  */
40  public $tldmode = array();
41  var $archive = '';
42 
43 
44  /**
45  * Constructor
46  *
47  * @global type $db
48  * @global type $cuid
49  */
50  function __construct() {
51  global $db, $cuid;
52  $db->query("SELECT su FROM membres WHERE uid=?;", array($cuid));
53  $db->next_record();
54  $this->enabled = $db->f("su");
55 
56  $this->tldmode = array(
57  0 => _("This TLD is forbidden"),
58  1 => _("primary DNS is checked in WHOIS db"),
59  2 => _("primary & secondary DNS are checked in WHOIS db"),
60  3 => _("Domain must exist, but don't do any DNS check"),
61  4 => _("Domain can be installed, no check at all"),
62  5 => _("Domain can be installed, force NO DNS hosting"),
63  );
64  $this->archive = variable_get('archive_del_data', '', 'If folder specified html folder of deleted user is archived, else it is deleted. ');
65  }
66 
67 
68  /**
69  * Hook function called by the menu class to add menu to the left panel.
70  * @global type $mem
71  * @global type $cuid
72  * @global type $debug_alternc
73  * @global type $L_INOTIFY_UPDATE_DOMAIN
74  * @return boolean|string
75  */
76  function hook_menu() {
77  global $mem, $cuid, $debug_alternc, $L_INOTIFY_UPDATE_DOMAIN;
78  if (!$mem->checkRight()) {
79  return false;
80  }
81  $obj = array(
82  'title' => _("Administration"),
83  'link' => 'toggle',
84  'class' => 'adminmenu',
85  'pos' => 10,
86  'links' =>
87  array(
88  array(
89  'txt' => _("Manage AlternC accounts"),
90  'url' => 'adm_list.php',
91  'class' => 'adminmenu'
92  ),
93  array(
94  'txt' => _("User Quotas"),
95  'url' => 'quotas_users.php?mode=4',
96  'class' => 'adminmenu'
97  ),
98  )
99  );
100 
101  if ($cuid == 2000) { // only ADMIN, not available to subadmins
102  $obj['links'][] = array(
103  'txt' => _("Admin Control Panel"),
104  'url' => 'adm_panel.php',
105  'class' => 'adminmenu'
106  );
107  $obj['links'][] = array(
108  'txt' => _("PhpMyAdmin"),
109  'url' => 'sql_pma_sso.php',
110  'class' => 'adminmenu',
111  'target' => '_blank',
112  );
113  $obj['links'][] = array(
114  'txt' => ($debug_alternc->status) ? _("Switch debug Off") : _("Switch debug On"),
115  'url' => "alternc_debugme.php?enable=" . ($debug_alternc->status ? "0" : "1"),
116  'class' => 'adminmenu'
117  );
118  if (empty($L_INOTIFY_UPDATE_DOMAIN) || file_exists("$L_INOTIFY_UPDATE_DOMAIN")) {
119  $obj['links'][] = array(
120  'txt' => _("Applying..."),
121  'url' => 'javascript:alert(\'' . _("Domain changes are already applying") . '\');',
122  'class' => 'adminmenu',
123  );
124  } else {
125  $obj['links'][] = array(
126  'txt' => _("Apply changes"),
127  'url' => 'adm_update_domains.php',
128  'class' => 'adminmenu',
129  'onclick' => 'return confirm("' . addslashes(_("Server configuration changes are applied every 5 minutes. Do you want to do it right now?")) . '");',
130  );
131  } // L_INOTIFY_UPDATE_DOMAIN
132  } // cuid == 2000
133 
134 
135  return $obj;
136  }
137 
138 
139  /**
140  * Password kind used in this class (hook for admin class)
141  *
142  * @return array
143  */
144  function alternc_password_policy() {
145  return array("adm" => "Administration section");
146  }
147 
148 
149  /**
150  *
151  */
152  function stop_if_jobs_locked() {
153  if (file_exists(ALTERNC_LOCK_JOBS)) {
154  echo "There is a file " . ALTERNC_LOCK_JOBS . "\n";
155  echo "So no jobs are allowed\n";
156  echo "Did you launch alternc.install ?\n";
157  die();
158  }
159  }
160 
161 
162  /**
163  * return the uid of an alternc account
164  *
165  * @global type $db
166  * @param type $login
167  * @return null
168  */
169  function get_uid_by_login($login) {
170  global $db;
171  $db->query("SELECT uid FROM membres WHERE login= ?;", array($login));
172  if (!$db->next_record()) {
173  return null;
174  }
175  return $db->f('uid');
176  }
177 
178 
179  /**
180  * return the name of an alternc account
181  *
182  * @global type $db
183  * @param type $uid
184  * @return null if missing
185  */
186  function get_login_by_uid($uid) {
187  global $db;
188  $db->query("SELECT login FROM membres WHERE uid= ?;", array($uid));
189  if (!$db->next_record()) {
190  return null;
191  }
192  return $db->f('login');
193  }
194 
195 
196  /**
197  * Returns the known information about a hosted account
198  *
199  * Returns all what we know about an account (contents of the tables
200  * <code>membres</code> et <code>local</code>)
201  * Ckecks if the account is super-admin
202  *
203  * @global type $msg
204  * @global type $db
205  * @global string $lst_users_properties
206  * @param int $uid a unique integer identifying the account
207  * @param boolean $recheck
208  * @return array|boolean an associative array containing all the fields of the
209  * table <code>membres</code> and <code>local</code> of the corresponding account.
210  * Returns FALSE if an error occurs.
211  */
212  function get($uid, $recheck = false) {
213  global $msg, $db, $lst_users_properties;
214  $msg->debug("admin","get",$uid);
215  if (!$this->enabled) {
216  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
217  return false;
218  }
219 
220  if (!isset($lst_users_properties) || empty($lst_users_properties) || !is_array($lst_users_properties) || $recheck) {
221  $lst_users_properties = array();
222  $db->query("
223  SELECT
224  m.uid as muid,
225  l.*,
226  m.*,
227  parent.login as parentlogin,
228  dbs.name as db_server_name,
229  m.renewed + INTERVAL m.duration MONTH as expiry,
230  CASE
231  WHEN m.duration IS NULL THEN 0
232  WHEN m.renewed + INTERVAL m.duration MONTH <= NOW() THEN 3
233  WHEN m.renewed <= NOW() THEN 2
234  ELSE 1 END 'status'
235 
236  FROM membres as m
237  LEFT JOIN membres as parent ON (parent.uid = m.creator)
238  LEFT JOIN db_servers as dbs ON (m.db_server_id = dbs.id)
239  LEFT JOIN local as l ON (m.uid = l.uid) ;");
240  while ($db->next_record()) {
241  $lst_users_properties[$db->f('muid')] = $db->Record;
242  }
243  }
244 
245  if (!isset($lst_users_properties[$uid])) {
246  if (!$recheck) {
247  // don't exist, but is not a forced check. Do a forced check
248  return $this->get($uid, true);
249  }
250  $msg->raise("ERROR", "admin", _("Account not found"));
251  return false;
252  }
253 
254  return $lst_users_properties[$uid];
255  }
256 
257 
258  /**
259  * Returns the known information about a specific hosted account
260  *
261  * Similar to get_list() but for creators/resellers.
262  *
263  * @global type $msg
264  * @global type $db
265  * @param int $uid
266  * @return boolean
267  */
268  function get_creator($uid) {
269  global $msg, $db;
270  $msg->debug("admin","get_creator",$uid);
271  if (!$this->enabled) {
272  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
273  return false;
274  }
275 
276  $db->query("SELECT m.*, parent.login as parentlogin FROM membres as m LEFT JOIN membres as parent ON (parent.uid = m.creator) WHERE m.uid= ?;", array($uid));
277 
278  if ($db->num_rows()) {
279  $db->next_record();
280  $c = $db->Record;
281  } else {
282  $msg->raise("ERROR", "admin", _("Account not found"));
283  return false;
284  }
285 
286  $db->query("SELECT * FROM local WHERE uid= ?;", array($uid));
287  if ($db->num_rows()) {
288  $db->next_record();
289  reset($db->Record);
290  while (list($key, $val) = each($db->Record)) {
291  $c[$key] = $val;
292  }
293  }
294 
295  $db->query("SELECT count(*) as nbcreated FROM membres WHERE creator= ?;", array($uid));
296  if ($db->num_rows()) {
297  $db->next_record();
298  reset($db->Record);
299  while (list($key, $val) = each($db->Record)) {
300  $c[$key] = $val;
301  }
302  }
303 
304  return $c;
305  }
306 
307 
308  /**
309  *
310  * @global type $db
311  * @return boolean TRUE if there is only one admin account
312  * (allow the program to prevent the destruction of the last admin account)
313  */
314  function onesu() {
315  global $db;
316  $db->query("SELECT COUNT(*) AS cnt FROM membres WHERE su=1");
317  $db->next_record();
318  return ($db->f("cnt") == 1);
319  }
320 
321 
322  /**
323  * @TODO :EM: those request should have been escaped
324  * Returns the list of the hosted accounts
325  *
326  * Returns all what we know about ALL the accounts (contents of the tables
327  * <code>membres</code> et <code>local</code>)
328  * Check for super-admin accounts
329  * @param
330  * @return
331  *
332  * @global type $msg
333  * @global type $mem
334  * @global type $cuid
335  * @param integer $all
336  * @param integer $creator
337  * @param string $pattern
338  * @param string $pattern_type
339  * @return boolean | array an associative array containing all the fields of the
340  * table <code>membres</code> and <code>local</code> of all the accounts.
341  * Returns FALSE if an error occurs.
342  */
343  function get_list($all = 0, $creator = 0, $pattern = FALSE, $pattern_type = FALSE) {
344  global $msg, $mem, $cuid;
345  $msg->debug("admin", "get_list");
346  if (!$this->enabled) {
347  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
348  return false;
349  }
350  $db = new DB_System();
351 
352 
353  if ($pattern) {
354 
355  if ($pattern_type === 'domaine') {
356 
357  $request = 'SELECT compte AS uid FROM domaines WHERE 1';
358 
359  if ($pattern && preg_match('/[.a-zA-Z0-9]+/', $pattern)) {
360  $request .= sprintf(' AND domaine LIKE "%%%s%%"', $pattern);
361  }
362  if ($creator) {
363  $request .= sprintf(' AND compte in (select uid from membres where creator = "%s" ) ', $creator);
364  }
365  if ($mem->user['uid'] != 2000 && !$all) {
366  $request .= sprintf(' AND compte in (select uid from membres where creator = "%s") ', $cuid);
367  }
368 
369  $request .= ' GROUP BY uid';
370  } elseif ($pattern_type === 'login') {
371 
372  $request = 'SELECT uid FROM membres WHERE 1';
373 
374  if ($pattern && preg_match('/[a-zA-Z0-9]+/', $pattern)) {
375  $request .= sprintf(' AND login LIKE "%%%s%%"', $pattern);
376  }
377  if ($creator) {
378  $request .= sprintf(' AND creator = "%s"', $creator);
379  }
380  if ($mem->user['uid'] != 2000 && !$all) {
381  $request .= sprintf(' AND creator = "%s"', $cuid);
382  }
383  $request .= ' ORDER BY login;';
384  } else {
385  $msg->raise("ERROR", "admin", _("Invalid pattern type provided. Are you even performing a legitimate action?"));
386  return FALSE;
387  }
388  } else {
389  if ($creator) {
390  // Limit listing to a specific reseller
391  $request = "SELECT uid FROM membres WHERE creator='" . $creator . "' ORDER BY login;";
392  } elseif ($mem->user['uid'] == 2000 || $all) {
393  $request = "SELECT uid FROM membres ORDER BY login;";
394  } else {
395  $request = "SELECT uid FROM membres WHERE creator='" . $cuid . "' ORDER BY login;";
396  }
397  }
398 
399  $db->query($request);
400 
401  if ($db->num_rows()) {
402  $c = array();
403  while ($db->next_record()) {
404  $c[$db->f("uid")] = $this->get($db->f("uid"));
405  }
406  return $c;
407  } else {
408  return false;
409  }
410  }
411 
412 
413  /**
414  * Send an email to all AlternC's accounts
415  *
416  * @global type $msg
417  * @global type $mem
418  * @global type $cuid
419  * @global type $db
420  * @param string $subject Subject of the email to send
421  * @param string $message Message to send
422  * @param string $from Expeditor of that email
423  * @return boolean
424  */
425  function mailallmembers($subject, $message, $from) {
426  global $msg, $db;
427  $msg->log("admin", "mailallmembers");
428  if (!$this->enabled) {
429  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
430  return false;
431  }
432  $subject = trim($subject);
433  $message = trim($message);
434  $from = trim($from);
435 
436  if (empty($subject) || empty($message) || empty($from)) {
437  $msg->raise("ERROR", "admin", _("Subject, message and sender are mandatory"));
438  return false;
439  }
440  //@todo remove cf functions.php
441  if (checkmail($from) != 0) {
442  $msg->raise("ERROR", "admin", _("Sender is syntaxically incorrect"));
443  return false;
444  }
445 
446  @set_time_limit(1200);
447  $db->query("SELECT DISTINCT mail FROM membres WHERE mail!='';");
448  while ($db->next_record()) {
449  // Can't do BCC due to postfix limitation
450  // FIXME: use phpmailer, far better for mass-mailing than sendmail (reply-to issue among others)
451  mail($db->f('mail'), $subject, $message, null, "-f$from");
452  }
453  return true;
454  }
455 
456 
457  /**
458  * Returns an array with the known information about resellers (uid, login, number of accounts)
459  * Does not include account 2000 in the list.
460  * May only be called by the admin account (2000)
461  * If there are no reseller accounts, returns an empty array.
462  *
463  * @global type $msg
464  * @global type $mem
465  * @global type $cuid
466  * @return boolean
467  */
468  function get_creator_list() {
469  global $msg, $cuid;
470 
471  $creators = array();
472 
473  $msg->debug("admin", "get_creator_list");
474  if (!$this->enabled) {
475  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
476  return false;
477  }
478 
479  $db = new DB_System();
480  $db->query("SELECT DISTINCT creator FROM membres WHERE creator <> 0 ORDER BY creator ASC;");
481  if ($db->num_rows()) {
482  while ($db->next_record()) {
483  $creators[] = $this->get_creator($db->f("creator"));
484  }
485  }
486  $creators2 = array();
487  foreach ($creators as $cc) {
488  $creators2[$cc['uid']] = $cc;
489  }
490  return $creators2;
491  }
492 
493 
494  /**
495  * Check if I am the creator of the member $uid
496  *
497  * @global type $msg
498  * @global type $mem
499  * @global type $db
500  * @global type $cuid
501  * @param int $uid a unique integer identifying the account
502  * @return boolean TRUE if I am the creator of that account. FALSE else.
503  */
504  function checkcreator($uid) {
505  global $msg, $db, $cuid;
506  if ($cuid == 2000) {
507  return true;
508  }
509  $db->query("SELECT creator FROM membres WHERE uid= ?;", array($uid));
510  $db->next_record();
511  if ($db->Record["creator"] != $cuid) {
512  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
513  return false;
514  }
515  return true;
516  }
517 
518 
519  /**
520  * When the admin want to delegate a subdomain to an account
521  *
522  * @global m_mysql $db
523  * @global m_messages $msg
524  * @global m_dom $dom
525  * @global m_mem $mem
526  * @global int $cuid
527  * @param string $u
528  * @param string $domain_name
529  * @return boolean
530  */
531  function add_shared_domain($u, $domain_name) {
532  global $msg, $dom, $mem;
533  $msg->log("admin", "add_shared_domain", $u . "/" . $domain_name);
534 
535  if (!$mem->checkright()) {
536  $msg->raise("ERROR", "admin", _("-- Only administrators can do that! --"));
537  return false;
538  }
539 
540  // Check if this domain exist on this admin account
541  if ((!in_array($domain_name, $dom->enum_domains()))&&($domain_name!=variable_get("hosting_tld"))) {
542  $msg->raise("ERROR", "admin", _("You don't seem to be allowed to delegate this domain"));
543  $msg->log("admin", "add_shared_domain", "domain not allowed");
544  return false;
545  }
546 
547  // Clean the domain_name
548  $domain_name = preg_replace("/^\.\.*/", "", $domain_name);
549 
550  $mem->su($u);
551  $dom->lock();
552  // option : 1=hébergement dns, 1=noerase, empeche de modifier, 1=force
553  // we do not allow DNS modification for hosting_tld
554  $dns=($domain_name==variable_get("hosting_tld")) ? 0 : 1;
555  $dom->add_domain($mem->user['login'] . "." . $domain_name, $dns, 1, 1);
556  $dom->unlock();
557  $mem->unsu();
558  return true;
559  }
560 
561 
562  /** Creates a new hosted account
563  *
564  * Creates a new hosted account (in the tables <code>membres</code>
565  * and <code>local</code>). Prevents any manipulation of the account if
566  * the account $mid is not super-admin.
567  *
568  *
569  * @global m_messages $msg
570  * @global m_quota $quota
571  * @global array $classes
572  * @global int $cuid
573  * @global m_mem $mem
574  * @global string $L_MYSQL_DATABASE
575  * @global string $L_MYSQL_LOGIN
576  * @global m_hooks $hooks
577  * @global m_action $action
578  * @param string $login Login name like [a-z][a-z0-9]*
579  * @param string $pass Password (max. 64 characters)
580  * @param string $nom Name of the account owner
581  * @param string $prenom First name of the account owner
582  * @param string $mail Email address of the account owner, useful to get
583  * one's lost password
584  * @param integer $canpass
585  * @param string $type Account type for quotas
586  * @param int $duration
587  * @param string $notes
588  * @param integer $force
589  * @param string $create_dom
590  * @param int $db_server_id
591  * @return boolean Returns FALSE if an error occurs, TRUE if not.
592  */
593  function add_mem($login, $pass, $nom, $prenom, $mail, $canpass = 1, $type = 'default', $duration = 0, $notes = "", $force = 0, $create_dom = '', $db_server_id) {
594  global $msg, $cuid, $mem, $L_MYSQL_DATABASE, $L_MYSQL_LOGIN, $hooks, $action;
595  $msg->log("admin", "add_mem", $login . "/" . $mail);
596  if (!$this->enabled) {
597  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
598  return false;
599  }
600  if (empty($db_server_id)) {
601  $msg->raise("ERROR", "admin", _("Missing db_server field"));
602  return false;
603  }
604  if (($login == "") || ($pass == "")) {
605  $msg->raise("ERROR", "admin", _("Please fill all mandatory fields"));
606  return false;
607  }
608  if (!$force) {
609  if ($mail == "") {
610  $msg->raise("ERROR", "admin", _("Please fill all mandatory fields"));
611  return false;
612  }
613  //@todo remove cf functions.php
614  if (checkmail($mail) != 0) {
615  $msg->raise("ERROR", "admin", _("Please enter a valid email address"));
616  return false;
617  }
618  }
619  $login = strtolower($login);
620  if (!preg_match("#^[a-z0-9]+$#", $login)) { //$
621  $msg->raise("ERROR", "admin", _("Login can only contains characters a-z and 0-9"));
622  return false;
623  }
624  if (strlen($login) > 14) {
625  // Not an arbitrary value : MySQL user names can be up to 16 characters long
626  // If we want to allow people to create a few mysql_user (and we want to!)
627  // we have to limit the login lenght
628  $msg->raise("ERROR", "admin", _("The login is too long (14 chars max)"));
629  return false;
630  }
631  // Some login are not allowed...
632  if ($login == $L_MYSQL_DATABASE || $login == $L_MYSQL_LOGIN || $login == "mysql" || $login == "root") {
633  $msg->raise("ERROR", "admin", _("Login can only contains characters a-z, 0-9 and -"));
634  return false;
635  }
636  $pass = password_hash($pass, PASSWORD_BCRYPT);
637  $db = new DB_System();
638  // Already exist?
639  $db->query("SELECT count(*) AS cnt FROM membres WHERE login= ?;", array($login));
640  $db->next_record();
641  if (!$db->f("cnt")) {
642  $db->query("SELECT max(m.uid)+1 as nextid FROM membres m");
643  if (!$db->next_record()) {
644  $uid = 2000;
645  } else {
646  $uid = $db->Record["nextid"];
647  if ($uid <= 2000) {
648  $uid = 2000;
649  }
650  }
651  $db->query("INSERT INTO membres (uid,login,pass,mail,creator,canpass,type,created,notes,db_server_id) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), ?, ?);", array($uid, $login, $pass, $mail, $cuid, $canpass, $type, $notes, $db_server_id));
652  $db->query("INSERT INTO local(uid,nom,prenom) VALUES(?, ?, ?);", array($uid, $nom, $prenom));
653  $this->renew_update($uid, $duration);
654  $action->create_dir(getuserpath("$login"));
655  $action->fix_user($uid);
656 
657  // Triggering hooks
658  $mem->su($uid);
659 
660  $hooks->invoke("alternc_add_member");
661  // New hook way
662  $hooks->invoke("hook_admin_add_member", array(), array('quota')); // First !!! The quota !!! Eitherway, we can't be sure to be able to create all
663  $hooks->invoke("hook_admin_add_member");
664  $mem->unsu();
665 
666  if (!empty($create_dom)) {
667  $this->add_shared_domain($uid, $create_dom);
668  }
669 
670  return $uid;
671  } else {
672  $msg->raise("ERROR", "admin", _("This login already exists"));
673  return false;
674  }
675  }
676 
677 
678  /**
679  * AlternC's standard function called when a user is created
680  * This sends an email if configured through the interface.
681  *
682  * @global m_messages $msg
683  * @global int $cuid
684  * @global string $L_FQDN
685  * @global string $L_HOSTING
686  * @return boolean
687  */
689  global $msg, $cuid, $L_FQDN, $L_HOSTING;
690  $dest = variable_get('new_email', '0', 'An email will be sent to this address when new accounts are created if set.', array('desc' => 'Enabled', 'type' => 'boolean'));
691  if (!$dest) {
692  return false;
693  }
694  $db = new DB_System();
695  if (!$db->query("SELECT m.*, parent.login as parentlogin FROM membres m LEFT JOIN membres parent ON parent.uid=m.creator WHERE m.uid= ?", array($cuid))) {
696  $msg->raise("ERROR", "admin", sprintf(_("query failed: %s "), $db->Error));
697  return false;
698  }
699  if ($db->next_record()) {
700  // TODO: put that string into gettext !
701  $mail = '
702  A new AlternC account was created on %fqdn by %creator.
703 
704  Account details
705  ---------------
706 
707  login: %login (%uid)
708  email: %mail
709  createor: %creator (%cuid)
710  can change password: %canpass
711  type: %type
712  notes: %notes
713  ';
714  $mail = strtr($mail, array('%fqdn' => $L_FQDN,
715  '%creator' => $db->Record['parentlogin'],
716  '%uid' => $db->Record['uid'],
717  '%login' => $db->Record['login'],
718  '%mail' => $db->Record['mail'],
719  '%cuid' => $db->Record['creator'],
720  '%canpass' => $db->Record['canpass'],
721  '%type' => $db->Record['type'],
722  '%notes' => $db->Record['notes']));
723  $subject = sprintf(_("New account %s from %s on %s"), $db->Record['login'], $db->Record['parentlogin'], $L_HOSTING);
724  if (mail($dest, $subject, $mail, "From: postmaster@$L_FQDN")) {
725  //sprintf(_("Email successfully sent to %s"), $dest);
726  return true;
727  } else {
728  $msg->raise("ERROR", "admin", sprintf(_("Cannot send email to %s"), $dest));
729  return false;
730  }
731  } else {
732  $msg->raise("ERROR", "admin", sprintf(_("Query failed: %s"), $db->Error));
733  return false;
734  }
735  }
736 
737 
738  /**
739  * Edit an account
740  *
741  * Change an account (in the tables <code>membres</code>
742  * and <code>local</code>). Prevents any manipulation of the account if
743  * the account $mid is not super-admin.
744  *
745  * @global m_messages $msg
746  * @global m_mysql $db
747  * @global int $cuid
748  * @global m_quota $quota
749  * @param int $uid The uid number of the account we want to modify
750  * @param string $mail New email address of the account owner
751  * @param string $nom New name of the account owner
752  * @param string $prenom New first name of the account owner
753  * @param string $pass New password (max. 64 characters)
754  * @param string $enabled (value: 0 or 1) activates or desactivates the
755  * @param boolean $canpass
756  * @param int $type New type of account
757  * @param int $duration
758  * @param string $notes
759  * @param boolean $reset_quotas
760  * @return boolean Returns FALSE if an error occurs, TRUE if not
761  */
762  function update_mem($uid, $mail, $nom, $prenom, $pass, $enabled, $canpass, $type = 'default', $duration = 0, $notes = "", $reset_quotas = false) {
763  global $msg, $db, $quota;
764 
765  $msg->log("admin", "update_mem", $uid);
766 
767  if (!$this->enabled) {
768  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
769  return false;
770  }
771  $db = new DB_System();
772 
773  if ($pass) {
774  $pass = password_hash($pass, PASSWORD_BCRYPT);
775  $second_query = "UPDATE membres SET mail= ?, canpass= ?, enabled= ?, `type`= ?, notes= ? , pass = ? WHERE uid= ?;";
776  $second_query_args = array($mail, $canpass, $enabled, $type, $notes, $pass, $uid);
777  } else {
778  $second_query = "UPDATE membres SET mail= ?, canpass= ?, enabled= ?, `type`= ?, notes= ? WHERE uid= ?;";
779  $second_query_args = array($mail, $canpass, $enabled, $type, $notes, $uid);
780  }
781 
782  $old_mem = $this->get($uid);
783 
784  if(
785  ($db->query("UPDATE local SET nom= ?, prenom= ? WHERE uid=?;", array($nom, $prenom, $uid))) &&
786  ($db->query($second_query, $second_query_args))
787  ){
788  if ($reset_quotas == "on" || $type != $old_mem['type']) {
789  $quota->addquotas();
790  $quota->synchronise_user_profile();
791  }
792  $this->renew_update($uid, $duration);
793  return true;
794  } else {
795  $msg->raise("ERROR", "admin", _("Account not found"));
796  return false;
797  }
798  }
799 
800 
801  /**
802  * Lock an account
803  *
804  * Lock an account and prevent the user to access its account.
805  *
806  * @global m_messages $msg
807  * @global m_mysql $db
808  * @param int $uid The uid number of the account
809  * @return boolean Returns FALSE if an error occurs, TRUE if not.
810  */
811  function lock_mem($uid) {
812  global $msg, $db;
813  $msg->log("admin", "lock_mem", $uid);
814  if (!$this->enabled) {
815  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
816  return false;
817  }
818  $db = new DB_System();
819  if ($db->query("UPDATE membres SET enabled='0' WHERE uid= ?;", array($uid))) {
820  return true;
821  } else {
822  $msg->raise("ERROR", "admin", _("Account not found"));
823  return false;
824  }
825  }
826 
827 
828  /**
829  * UnLock an account
830  *
831  * UnLock an account and prevent the user to access its account.
832  *
833  *
834  * @global m_messages $msg
835  * @global m_mysql $db
836  * @param int $uid The uid number of the account
837  * @return boolean Returns FALSE if an error occurs, TRUE if not.
838  */
839  function unlock_mem($uid) {
840  global $msg, $db;
841  $msg->log("admin", "unlock_mem", $uid);
842  if (!$this->enabled) {
843  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
844  return false;
845  }
846  $db = new DB_System();
847  if ($db->query("UPDATE membres SET enabled='1' WHERE uid= ?;", array($uid))) {
848  return true;
849  } else {
850  $msg->raise("ERROR", "admin", _("Account not found"));
851  return false;
852  }
853  }
854 
855 
856  /** Deletes an account
857  * Deletes the specified account. Prevents any manipulation of the account if
858  * the account $mid is not super-admin.
859  *
860  * @global m_messages $msg
861  * @global m_quota $quota
862  * @global array $classes
863  * @global int $cuid
864  * @global m_mem $mem
865  * @global m_dom $dom
866  * @global m_hooks $hooks
867  * @global m_action $action
868  * @param int $uid The uid number of the account
869  * @return boolean Returns FALSE if an error occurs, TRUE if not.
870  */
871  function del_mem($uid) {
872  global $msg, $mem, $dom, $hooks, $action;
873  $msg->log("admin", "del_mem", $uid);
874 
875  if (!$this->enabled) {
876  $msg->raise("ERROR", "admin", _("-- Only administrators can access this page! --"));
877  return false;
878  }
879  $db = new DB_System();
880  $tt = $this->get($uid);
881 
882  $mem->su($uid);
883  // This script may take a long time on big accounts, let's give us some time ... Fixes 1132
884  @set_time_limit(0);
885  // WE MUST call m_dom before all others because of conflicts ...
886  $dom->admin_del_member();
887 
888  # New way of deleting or backup delted user html folders using action class
889  $path = getuserpath($tt['login']);
890  $action->archive($path);
891 
892  $hooks->invoke("alternc_del_member");
893  $hooks->invoke("hook_admin_del_member");
894 
895  if (($db->query("DELETE FROM membres WHERE uid= ?;", array($uid))) &&
896  ($db->query("DELETE FROM local WHERE uid= ?;", array($uid)))) {
897  $mem->unsu();
898  // If this user was (one day) an administrator one, he may have a list of his own accounts. Let's associate those accounts to nobody as a creator.
899  $db->query("UPDATE membres SET creator=2000 WHERE creator= ?;", array($uid));
900  return true;
901  } else {
902  $msg->raise("ERROR", "admin", _("Account not found"));
903  $mem->unsu();
904  return false;
905  }
906  }
907 
908 
909  /**
910  * Renew an account
911  *
912  * Renew an account for its duration
913  *
914  * @global m_messages $msg
915  * @global m_mysql $db
916  * @param int $uid The uid number of the account
917  * @param int $periods The new duration, in months, of the account
918  * @return boolean Returns FALSE if an error occurs, TRUE if not.
919  */
920  function renew_mem($uid, $periods = 1) {
921  global $msg, $db;
922 
923  $periods = intval($periods);
924  if ($periods == 0) {
925  return false;
926  }
927  if ($db->query("UPDATE membres SET renewed = renewed + INTERVAL (duration * ?) MONTH WHERE uid= ?;", array($periods, $uid))) {
928  return true;
929  } else {
930  $msg->raise("ERROR", "admin", _("Account not found"));
931  return false;
932  }
933  }
934 
935 
936  /**
937  * Update the duration information for an account
938  *
939  * @global m_messages $msg
940  * @global m_mysql $db
941  * @param int $uid The uid number of the account
942  * @param int $duration The new duration, in months, of the account
943  * @return boolean Returns FALSE if an error occurs, TRUE if not.
944  */
945  function renew_update($uid, $duration) {
946  global $msg, $db;
947 
948  if ($duration == 0) {
949  if ($db->query("UPDATE membres SET duration = NULL, renewed = NULL WHERE uid= ?;", array($uid))) {
950  return true;
951  }
952  } else {
953  if ($db->query("UPDATE membres SET duration = ? WHERE uid= ?", array($duration, $uid)) &&
954  $db->query("UPDATE membres SET renewed = NOW() WHERE uid= ? and renewed is null;", array($uid))) {
955  return true;
956  }
957  }
958 
959  $msg->raise("ERROR", "admin", _("Account not found"));
960  return false;
961  }
962 
963 
964  /**
965  * Get the expiry date for an account
966  *
967  * @param int $uid The uid number of the account
968  * @return string The expiry date, a string as printed by MySQL
969  */
970  function renew_get_expiry($uid) {
971  $jj = $this->get($uid);
972  if (isset($jj) && isset($jj['expiry']) && !empty($jj['expiry'])) {
973  return $jj['expiry'];
974  }
975  return '';
976  }
977 
978 
979  /**
980  * Get the expiry status for an account
981  *
982  * @param int $uid The uid number of the account
983  * @return integer The expiry status:
984  * 0: account does not expire
985  * 1: expires in more than duration,
986  * 2: expires within the duration
987  * 3: has expired past the duration
988  */
989  function renew_get_status($uid) {
990  $jj = $this->get($uid);
991 
992  if (isset($jj) && isset($jj['status']) && !empty($jj['status'])) {
993  return $jj['status'];
994  }
995 
996  return 0;
997  }
998 
999 
1000  /**
1001  * Get the expired/about to expire accounts.
1002  *
1003  * @global m_mysql $db
1004  * @return array The recordset of the corresponding accounts
1005  */
1007  global $db;
1008 
1009  if (!$db->query("SELECT *, m.renewed + INTERVAL duration MONTH 'expiry'," .
1010  " CASE WHEN m.duration IS NULL THEN 0" .
1011  " WHEN m.renewed + INTERVAL m.duration MONTH <= NOW() THEN 3" .
1012  " WHEN m.renewed <= NOW() THEN 2" .
1013  " ELSE 1 END 'status' FROM membres m, local l" .
1014  " WHERE m.uid = l.uid" .
1015  " HAVING status=2 or status=3 ORDER BY status DESC, expiry;")) {
1016  return false;
1017  } else {
1018  $res = array();
1019  while ($db->next_record()) {
1020  $res[] = $db->Record;
1021  }
1022  return $res;
1023  }
1024  }
1025 
1026 
1027  /**
1028  * Turns a common account into a super-admin account
1029  *
1030  * @global m_messages $msg
1031  * @global m_mysql $db
1032  * @param int $uid The uid number of the account
1033  * @return boolean
1034  */
1035  function normal2su($uid) {
1036  global $msg, $db;
1037  $db->query("SELECT su FROM membres WHERE uid= ?;", array($uid));
1038  if (!$db->next_record()) {
1039  $msg->raise("ERROR", "admin", _("Account not found"));
1040  return false;
1041  }
1042  if ($db->Record["su"] != 0) {
1043  $msg->raise("ERROR", "admin", _("This account is ALREADY an administrator account"));
1044  return false;
1045  }
1046  $db->query("UPDATE membres SET su=1 WHERE uid= ?;", array($uid));
1047  return true;
1048  }
1049 
1050 
1051  /**
1052  * Turns a super-admin account into a common account
1053  *
1054  * @global m_messages $msg
1055  * @global m_mysql $db
1056  * @param int $uid The uid number of the account
1057  * @return boolean Returns FALSE if an error occurs, TRUE if not.
1058  */
1059  function su2normal($uid) {
1060  global $msg, $db;
1061  $db->query("SELECT su FROM membres WHERE uid= ?;", array($uid));
1062  if (!$db->next_record()) {
1063  $msg->raise("ERROR", "admin", _("Account not found"));
1064  return false;
1065  }
1066  if ($db->Record["su"] != 1) {
1067  $msg->raise("ERROR", "admin", _("This account is NOT an administrator account!"));
1068  return false;
1069  }
1070  $db->query("UPDATE membres SET su=0 WHERE uid= ?;", array($uid));
1071  return true;
1072  }
1073 
1074 
1075  /**
1076  * List of the authorized TLDs
1077  * Returns the list of the authorized TLDs and also the way they are
1078  * authorized. A TLD is the last members (or the last two) of a
1079  * domain. For example, "com", "org" etc... AlternC keeps a table
1080  * containing the list of the TLDs authorized to be installed on the
1081  * server with the instructions to validate the installation of a
1082  * domain for each TLD (if necessary).
1083  *
1084  * @global m_mysql $db
1085  * @return array An associative array like $r["tld"], $r["mode"] where tld
1086  * is the tld and mode is the authorized mode.
1087  */
1088  function listtld() {
1089  global $db;
1090  $db->query("SELECT tld,mode FROM tld ORDER BY tld;");
1091  $c = array();
1092  while ($db->next_record()) {
1093  $c[] = $db->Record;
1094  }
1095  return $c;
1096  }
1097 
1098 
1099  /**
1100  * List the hosted domains on this server
1101  *
1102  * Return the list of hosted domains on this server, (an array of associative arrays)
1103  *
1104  * @global m_mysql $db
1105  * @param boolean $alsocheck Returns also errstr and errno telling the domains dig checks
1106  * @param boolean $forcecheck Force the check of dig domain even if a cache exists.
1107  * @return array $r[$i] / [domaine][member][noerase][gesdns][gesmx]
1108  */
1109  function dom_list($alsocheck = false, $forcecheck = false) {
1110  global $db;
1111  $cachefile = "/tmp/alternc_dig_check_cache";
1112  $cachetime = 3600; // The dns cache file can be up to 1H old
1113  if ($alsocheck) {
1114  if (!$forcecheck && file_exists($cachefile) && filemtime($cachefile) + $cachetime > time()) {
1115  $checked = unserialize(file_get_contents($cachefile));
1116  } else {
1117  // TODO : do the check here (cf checkdom.php) and store it in $checked
1118  $checked = $this->checkalldom();
1119  file_put_contents($cachefile, serialize($checked));
1120  }
1121  }
1122 
1123  $query = "SELECT m.uid,m.login,d.domaine,d.gesdns,d.gesmx,d.noerase FROM domaines d LEFT JOIN membres m ON m.uid=d.compte ";
1124  $query_args = array();
1125  if($hosting_tld = variable_get("hosting_tld")){
1126  $query .= " WHERE domaine not like ?";
1127  array_push($query_args, "%.".$hosting_tld);
1128  }
1129  $query .= " ORDER BY domaine;";
1130  $db->query($query, $query_args);
1131  $c = array();
1132  while ($db->next_record()) {
1133  $tmp = $db->Record;
1134  if ($alsocheck) {
1135  $tmp["errstr"] = $checked[$tmp["domaine"]]["errstr"];
1136  $tmp["errno"] = $checked[$tmp["domaine"]]["errno"];
1137  }
1138  $c[] = $tmp;
1139  }
1140  return $c;
1141  }
1142 
1143 
1144  /**
1145  * Check all the domains for their NS MX and IPs
1146  *
1147  * @global m_mysql $db
1148  * @global string $L_NS1
1149  * @global string $L_NS2
1150  * @global string $L_MX
1151  * @global string $L_PUBLIC_IP
1152  * @return int
1153  */
1154  function checkalldom() {
1155  global $db, $L_NS1, $L_NS2, $L_MX, $L_PUBLIC_IP;
1156  $checked = array();
1157 
1158  $query = "SELECT * FROM domaines ";
1159  $query_args = array();
1160  if($hosting_tld = variable_get("hosting_tld")){
1161  $query .= " WHERE domaine not like ?";
1162  array_push($query_args, "%.".$hosting_tld);
1163  }
1164  $query .= " ORDER BY domaine";
1165  $db->query($query, $query_args);
1166  $dl = array();
1167  while ($db->next_record()) {
1168  $dl[$db->Record["domaine"]] = $db->Record;
1169  }
1170 
1171  // won't search for MX and subdomains record if DNS is hosted here
1172  $lazycheck=1;
1173 
1174  sort($dl);
1175  foreach ($dl as $c) {
1176  // For each domain check its type:
1177  $errno = 0;
1178  $errstr = "";
1179  $dontexist = false;
1180  // Check the domain.
1181  if ($c["gesdns"] == 1) {
1182  // Check the NS pointing to us
1183  $out = array();
1184  exec("dig +short NS " . escapeshellarg($c["domaine"]), $out);
1185  if (count($out) == 0) {
1186  $dontexist = true;
1187  } else {
1188  if (!in_array($L_NS1 . ".", $out) || !in_array($L_NS2 . ".", $out)) {
1189  $errno = 1;
1190  $errstr.=sprintf(_("NS for this domain are not %s and %s BUT %s"),
1191  $L_NS1, $L_NS2, implode(",", $out)) . "\n";
1192  }
1193  }
1194  }
1195 
1196  if (!$dontexist&&(!$lazycheck||!$c["gesdns"])) {
1197  if ($c["gesmx"] == 1) {
1198  $out = array();
1199  exec("dig +short MX " . escapeshellarg($c["domaine"]), $out);
1200  $out2 = array();
1201  foreach ($out as $o) {
1202  list($t, $out2[]) = explode(" ", $o);
1203  }
1204  if (!in_array($L_MX . ".", $out2)) {
1205  $errno = 1;
1206  $errstr.=sprintf(_("MX is not %s BUT %s"), $L_MX, implode(",", $out2))."\n";
1207  }
1208  }
1209 
1210  // We list all subdomains and check they are pointing to us.
1211  $db->query("SELECT * FROM sub_domaines WHERE domaine=? ORDER BY sub;", array($c["domaine"]));
1212  while ($db->next_record()) {
1213  $d = $db->Record;
1214  if ($d["type"] == 'VHOST') {
1215  // Check the IP:
1216  $out = array();
1217  exec("dig +short A " . escapeshellarg($d["sub"] . (($d["sub"] != "") ? "." : "") . $c["domaine"]), $out);
1218  if (!is_array($out)) { // exec dig can fail
1219  $errno = 1;
1220  $errstr.=_("Fail to get the DNS information. Try again.")."\n";
1221  } else {
1222  if (!in_array($L_PUBLIC_IP, $out)) {
1223  $errstr.=sprintf(_("subdomain '%s' doesn't point to %s but to '%s'"), $d["sub"], $L_PUBLIC_IP, implode(",", $out))."\n" ;
1224  $errno = 1;
1225  }
1226  }
1227  }
1228  }
1229  }
1230  if ($dontexist) {
1231  $errno = 2;
1232  $errstr = _("Domain doesn't exist anymore !");
1233  }
1234  if ($errno == 0)
1235  $errstr = "OK";
1236  $checked[$c["domaine"]] = array("errno" => $errno, "errstr" => $errstr);
1237  }
1238  return $checked;
1239  }
1240 
1241 
1242  /**
1243  * Lock / Unlock a domain
1244  *
1245  * Lock (or unlock) a domain, so that the member will be (not be) able to delete it
1246  * from its account
1247  *
1248  * @global m_mysql $db
1249  * @global m_messages $msg
1250  * @param string $domain Domain name to lock / unlock
1251  * @return boolean TRUE if the domain has been locked/unlocked or FALSE if it does not exist.
1252  */
1253  function dom_lock($domain) {
1254  global $db, $msg;
1255  $db->query("SELECT compte FROM domaines WHERE domaine= ?;", array($domain));
1256  if (!$db->next_record()) {
1257  $msg->raise("ERROR", "dom", _("Domain '%s' not found."), $domain);
1258  return false;
1259  }
1260  $db->query("UPDATE domaines SET noerase=1-noerase WHERE domaine= ?;", array($domain));
1261  return true;
1262  }
1263 
1264 
1265  /**
1266  * Add a new TLD to the list of the authorized TLDs
1267  *
1268  * @global m_mysql $db
1269  * @global m_messages $msg
1270  * @param string $tld top-level domain to add (org, com...)
1271  * @return boolean TRUE if the tld has been successfully added, FALSE if not.
1272  */
1273  function gettld($tld) {
1274  global $db, $msg;
1275  $db->query("SELECT mode FROM tld WHERE tld= ?;", array($tld));
1276  if (!$db->next_record()) {
1277  $msg->raise("ERROR", "admin", _("This TLD does not exist"));
1278  return false;
1279  }
1280  return $db->Record["mode"];
1281  }
1282 
1283 
1284  /**
1285  * Prints the list of the actually authorized TLDs
1286  *
1287  * @param boolean $current Value to select in the list
1288  */
1289  function selecttldmode($current = false) {
1290  for ($i = 0; $i < count($this->tldmode); $i++) {
1291  echo "<option value=\"$i\"";
1292  if ($current == $i) {
1293  echo " selected=\"selected\"";
1294  }
1295  echo ">" . _($this->tldmode[$i]) . "</option>\n";
1296  }
1297  }
1298 
1299 
1300  /**
1301  * Deletes the specified tld in the list of the authorized TLDs
1302  * <b>Note</b> : This function does not delete the domains depending
1303  * on this TLD
1304  *
1305  * @global m_mysql $db
1306  * @global m_messages $msg
1307  * @param string $tld The TLD you want to delete
1308  * @return boolean returns true if the TLD has been deleted, or
1309  * false if an error occured.
1310  */
1311  function deltld($tld) {
1312  global $db, $msg;
1313  $db->query("SELECT tld FROM tld WHERE tld= ?;", array($tld));
1314  if (!$db->next_record()) {
1315  $msg->raise("ERROR", "admin", _("This TLD does not exist"));
1316  return false;
1317  }
1318  $db->query("DELETE FROM tld WHERE tld= ?;", array($tld));
1319  return true;
1320  }
1321 
1322 
1323  /** Add a TLD to the list of the authorized TLDs during the installation
1324  *
1325  * <b>Note: </b> If you check in the whois, be sure that
1326  * <code>m_domains</code> knows how to name the whois of the specified
1327  * domain!
1328  *
1329  * @global m_mysql $db
1330  * @global m_messages $msg
1331  * @param string $tld string TLD we want to authorize
1332  * @param boolean $mode Controls to make on this TLD.
1333  * @return boolean TRUE if the TLD has been successfully
1334  * added. FALSE if not.
1335  */
1336  function addtld($tld, $mode) {
1337  global $db, $msg;
1338  if (!$tld) {
1339  $msg->raise("ERROR", "admin", _("The TLD name is mandatory"));
1340  return false;
1341  }
1342  $tld = trim($tld);
1343 
1344  $db->query("SELECT tld FROM tld WHERE tld= ?;", array($tld));
1345  if ($db->next_record()) {
1346  $msg->raise("ERROR", "admin", _("This TLD already exist"));
1347  return false;
1348  }
1349  if (substr($tld, 0, 1) == ".") {
1350  $tld = substr($tld, 1);
1351  }
1352  $mode = intval($mode);
1353  if ($mode == 0) {
1354  $mode = "0";
1355  }
1356  $db->query("INSERT INTO tld (tld,mode) VALUES (?,?);", array($tld, $mode));
1357  return true;
1358  }
1359 
1360 
1361  /**
1362  * Modify a TLD of the list of the authorized TLDs
1363  *
1364  * @global m_mysql $db
1365  * @global m_messages $msg
1366  * @param string $tld TLD we want to modify
1367  * @param int $mode Controls to make on this TLD.
1368  * @return boolean TRUE if the TLD has been successfully
1369  * modified. FALSE if not.
1370 
1371  */
1372  function edittld($tld, $mode) {
1373  global $db, $msg;
1374  $db->query("SELECT tld FROM tld WHERE tld= ?;", array($tld));
1375  if (!$db->next_record()) {
1376  $msg->raise("ERROR", "admin", _("This TLD does not exist"));
1377  return false;
1378  }
1379  $mode = intval($mode);
1380  if ($mode == 0) {
1381  $mode = "0";
1382  }
1383  $db->query("UPDATE tld SET mode= ? WHERE tld= ?;", array($mode, $tld));
1384  return true;
1385  }
1386 
1387 
1388  /**
1389  * Get the login name of the main administrator account
1390  *
1391  * @global m_mysql $db
1392  * @return string the login name of admin, like 'root' for older alterncs
1393  */
1394  function getadmin() {
1395  global $db;
1396  $db->query("SELECT login FROM membres WHERE uid=2000;");
1397  $db->next_record();
1398  return $db->f("login");
1399  }
1400 
1401 
1402  /**
1403  * List the password policies currently installed in the policy table
1404  *
1405  * @global m_mysql $db
1406  * @global array $classes
1407  * @global m_hooks $hooks
1408  * @return array an indexed array of associative array from the MySQL "policy" table
1409  */
1411  global $db, $hooks;
1412  $tmp1 = array();
1413  $tmp2 = array();
1414  $policies = array();
1415  $db->query("SELECT * FROM policy;");
1416  while ($db->next_record()) {
1417  $tmp1[$db->Record["name"]] = $db->Record;
1418  }
1419  $tmp3 = $hooks->invoke("alternc_password_policy");
1420  foreach ($tmp3 as $v) {
1421  foreach ($v as $l => $m) {
1422  $tmp2[$l] = $m;
1423  }
1424  }
1425  foreach ($tmp2 as $k => $v) {
1426  if (!isset($tmp1[$k])) {
1427  // Default policy :
1428  $db->query("INSERT INTO policy SET name= ?, minsize=0, maxsize=64, classcount=0, allowlogin=0;", array($k));
1429  $tmp1[$k] = array(
1430  "minsize" => 0, "maxsize" => 64, "classcount" => 0, "allowlogin" => 0
1431  );
1432  }
1433  $policies[$k] = $tmp1[$k];
1434  $policies[$k]["description"] = _($v);
1435  unset($tmp1[$k]);
1436  }
1437  foreach ($tmp1 as $k => $v) {
1438  // Delete disabled modules :
1439  $db->query("DELETE FROM policy WHERE name= ?;", array($k));
1440  }
1441  return $policies;
1442  }
1443 
1444 
1445  /**
1446  * Change a password policy for one kind of password
1447  *
1448  * @global m_mysql $db
1449  * @param string $policy Name of the policy to edit
1450  * @param int $minsize Minimum Password size
1451  * @param int $maxsize Maximum Password size
1452  * @param int $classcount How many class of characters must this password have
1453  * @param boolean $allowlogin Do we allow the password to be like the login ?
1454  * @return boolean if the policy has been edited, or FALSE if an error occured.
1455  */
1456  function editPolicy($policy, $minsize, $maxsize, $classcount, $allowlogin) {
1457  global $db;
1458  $minsize = intval($minsize);
1459  $maxsize = intval($maxsize);
1460  $classcount = intval($classcount);
1461  $allowlogin = intval($allowlogin);
1462 
1463  $db->query("SELECT * FROM policy WHERE name= ?;", array($policy));
1464  if (!$db->next_record()) {
1465  return false; // Policy not found
1466  }
1467  if ($minsize < 0 || $minsize > 64 || $maxsize < 0 || $maxsize > 64 || $maxsize < $minsize || $classcount < 0 || $classcount > 4) {
1468  return false; // Incorrect policy ...
1469  }
1470  $allowlogin = ($allowlogin) ? 1 : 0;
1471  $db->query("UPDATE policy SET minsize= ?, maxsize= ?, classcount= ?, allowlogin= ? WHERE name= ?;", array($minsize, $maxsize, $classcount, $allowlogin, $policy));
1472  return true;
1473  }
1474 
1475 
1476  /**
1477  *
1478  * @global m_mysql $db
1479  * @global m_messages $msg
1480  * @param string $policy Name of the policy to check for
1481  * @param string $login The login that will be set
1482  * @param string $password The password we have to check
1483  * @return boolean TRUE if the password if OK for this login and this policy, FALSE if it is not.
1484  */
1485  function checkPolicy($policy, $login, $password, $canbeempty = false) {
1486  global $msg;
1487 
1488  if (empty($login)) {
1489  $msg->raise("ALERT", "admin", _("Please enter a login"));
1490  return false;
1491  }
1492  if (empty($password) && !$canbeempty) {
1493  $msg->raise("ALERT", "admin", _("Please enter a password"));
1494  return false;
1495  }
1496 
1497  $pol = $this->listPasswordPolicies();
1498  if (!$pol[$policy]) {
1499  $msg->raise("ERROR", "admin", _("-- Program error -- The requested password policy does not exist!"));
1500  return false;
1501  }
1502  $pol = $pol[$policy];
1503  // Ok, now let's check it :
1504  $plen = strlen($password);
1505 
1506  if ($plen < $pol["minsize"] && !($canbeempty && empty($password))) {
1507  $msg->raise("ERROR", "admin", _("The password length is too short according to the password policy"));
1508  return false;
1509  }
1510 
1511  if ($plen > $pol["maxsize"] && !($canbeempty && empty($password))) {
1512  $msg->raise("ERROR", "admin", _("The password is too long according to the password policy"));
1513  return false;
1514  }
1515 
1516  if (!$pol["allowlogin"]) {
1517  // We do misc check on password versus login :
1518  $logins = preg_split("/[@_-]/", $login);
1519  $logins[] = $login;
1520  foreach ($logins as $l) {
1521  if (!$l) {
1522  continue;
1523  }
1524  if (strpos($password, $l) !== false || strpos($l, $password) !== false) {
1525  $msg->raise("ERROR", "admin", _("The password policy prevents you to use your login name inside your password or the other way around"));
1526  return false;
1527  }
1528  }
1529  }
1530 
1531  if ($pol["classcount"] > 0 && !($canbeempty && empty($password))) {
1532  $cls = array(0, 0, 0, 0, 0);
1533  for ($i = 0; $i < strlen($password); $i++) {
1534  $p = substr($password, $i, 1);
1535  if (strpos("abcdefghijklmnopqrstuvwxyz", $p) !== false) {
1536  $cls[0] = 1;
1537  } elseif (strpos("ABCDEFGHIJKLMNOPQRSTUVWXYZ", $p) !== false) {
1538  $cls[1] = 1;
1539  } elseif (strpos("0123456789", $p) !== false) {
1540  $cls[2] = 1;
1541  } elseif (strpos('!"#$%&\'()*+,-./:;<=>?@[\\]^_`', $p) !== false) {
1542  $cls[3] = 1;
1543  } else {
1544  $cls[4] = 1;
1545  }
1546  } // foreach
1547  $clc = array_sum($cls);
1548  if ($clc < $pol["classcount"]) {
1549  $msg->raise("ERROR", "admin", _("Your password contains not enough different classes of character, between low-case, up-case, figures and special characters."));
1550  return false;
1551  }
1552  }
1553  return true; // congratulations !
1554  }
1555 
1556 
1557 } /* Class m_admin */
1558 
1559 
$query
Definition: 3.0.0~3.php:37
$forcecheck
Definition: adm_doms.php:49
$mode
Definition: adm_tldedit.php:40
$hooks
Definition: bootstrap.php:74
global $L_MYSQL_LOGIN
Definition: bootstrap.php:26
global $db
Definition: bootstrap.php:26
$mem
Definition: bootstrap.php:71
$msg
Definition: bootstrap.php:75
$c
Definition: bootstrap.php:47
global $L_MYSQL_DATABASE
Definition: bootstrap.php:26
$cuid
Definition: bootstrap.php:43
$d
$p
Definition: bro_editor.php:46
$res
Definition: index.php:111
variable_get($name, $default=null, $createit_comment=null)
Return a persistent variable.
Definition: variables.php:85
$errstr
Definition: change.php:62
Manage the AlternC's account administration (create/edit/delete)
Definition: m_admin.php:26
update_mem($uid, $mail, $nom, $prenom, $pass, $enabled, $canpass, $type='default', $duration=0, $notes="", $reset_quotas=false)
Edit an account.
Definition: m_admin.php:762
edittld($tld, $mode)
Modify a TLD of the list of the authorized TLDs.
Definition: m_admin.php:1372
gettld($tld)
Add a new TLD to the list of the authorized TLDs.
Definition: m_admin.php:1273
onesu()
Definition: m_admin.php:314
editPolicy($policy, $minsize, $maxsize, $classcount, $allowlogin)
Change a password policy for one kind of password.
Definition: m_admin.php:1456
listtld()
List of the authorized TLDs Returns the list of the authorized TLDs and also the way they are authori...
Definition: m_admin.php:1088
hook_menu()
Hook function called by the menu class to add menu to the left panel.
Definition: m_admin.php:76
add_mem($login, $pass, $nom, $prenom, $mail, $canpass=1, $type='default', $duration=0, $notes="", $force=0, $create_dom='', $db_server_id)
Creates a new hosted account.
Definition: m_admin.php:593
add_shared_domain($u, $domain_name)
When the admin want to delegate a subdomain to an account.
Definition: m_admin.php:531
renew_get_expiry($uid)
Get the expiry date for an account.
Definition: m_admin.php:970
dom_list($alsocheck=false, $forcecheck=false)
List the hosted domains on this server.
Definition: m_admin.php:1109
renew_get_expiring_accounts()
Get the expired/about to expire accounts.
Definition: m_admin.php:1006
get_creator($uid)
Returns the known information about a specific hosted account.
Definition: m_admin.php:268
checkcreator($uid)
Check if I am the creator of the member $uid.
Definition: m_admin.php:504
addtld($tld, $mode)
Add a TLD to the list of the authorized TLDs during the installation.
Definition: m_admin.php:1336
checkalldom()
Check all the domains for their NS MX and IPs.
Definition: m_admin.php:1154
del_mem($uid)
Deletes an account Deletes the specified account.
Definition: m_admin.php:871
get_creator_list()
Returns an array with the known information about resellers (uid, login, number of accounts) Does not...
Definition: m_admin.php:468
su2normal($uid)
Turns a super-admin account into a common account.
Definition: m_admin.php:1059
listPasswordPolicies()
List the password policies currently installed in the policy table.
Definition: m_admin.php:1410
mailallmembers($subject, $message, $from)
Send an email to all AlternC's accounts.
Definition: m_admin.php:425
__construct()
Constructor.
Definition: m_admin.php:50
hook_admin_add_member()
AlternC's standard function called when a user is created This sends an email if configured through t...
Definition: m_admin.php:688
renew_get_status($uid)
Get the expiry status for an account.
Definition: m_admin.php:989
$tldmode
List of the controls made for each TLD.
Definition: m_admin.php:40
checkPolicy($policy, $login, $password, $canbeempty=false)
Definition: m_admin.php:1485
$enabled
$enabled tells if the logged user is super-admin or not
Definition: m_admin.php:32
lock_mem($uid)
Lock an account.
Definition: m_admin.php:811
selecttldmode($current=false)
Prints the list of the actually authorized TLDs.
Definition: m_admin.php:1289
dom_lock($domain)
Lock / Unlock a domain.
Definition: m_admin.php:1253
renew_update($uid, $duration)
Update the duration information for an account.
Definition: m_admin.php:945
get_list($all=0, $creator=0, $pattern=FALSE, $pattern_type=FALSE)
@TODO :EM: those request should have been escaped Returns the list of the hosted accounts
Definition: m_admin.php:343
$archive
Definition: m_admin.php:41
unlock_mem($uid)
UnLock an account.
Definition: m_admin.php:839
normal2su($uid)
Turns a common account into a super-admin account.
Definition: m_admin.php:1035
renew_mem($uid, $periods=1)
Renew an account.
Definition: m_admin.php:920
getadmin()
Get the login name of the main administrator account.
Definition: m_admin.php:1394
deltld($tld)
Deletes the specified tld in the list of the authorized TLDs Note : This function does not delete the...
Definition: m_admin.php:1311
$dl
Definition: dom_add.php:61
$domain
Definition: dom_import.php:36
checkmail($mail)
Check an email address, use filter_var with emails, which works great ;)
Definition: functions.php:244
getuserpath($user=null)
get the home of the user
Definition: functions.php:329
$uid
$admin enabled
Definition: newone.php:38
$password
Definition: bootstrap.php:85
if(empty($site_name)) elseif($piwik->site_add( $site_name, $site_urls))
foreach($domaines_user as $domaine) $t
$login
$request
$i
$val
Definition: tempovars.php:15
if(empty($_POST['key'])||empty($_POST['val'])) $key
Definition: tempovars.php:14
$dom
Definition: whois_test.php:10