m_admin.php 43.3 KB
Newer Older
1
<?php
2
/* 
3
4
 ----------------------------------------------------------------------
 AlternC - Web Hosting System
5
6
 Copyright (C) 2000-2012 by the AlternC Development Team.
 https://alternc.org/
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 ----------------------------------------------------------------------
 LICENSE

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License (GPL)
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 To read the license please visit http://www.gnu.org/copyleft/gpl.html
 ----------------------------------------------------------------------
 Purpose of file: Administrate members and rights.
 ----------------------------------------------------------------------
*/
25

26
/* ----------------------------------------------------------------- */
Alan Garcia's avatar
Alan Garcia committed
27

28
/**
29
* Manage the AlternC's account administration (create/edit/delete)
30
31
32
*/
class m_admin {

33

34
  /* ----------------------------------------------------------------- */
35
  /** $enabled tells if the logged user is super-admin or not
36
37
38
39
   */
  var $enabled=0;

  /* ----------------------------------------------------------------- */
40
41
42
43
44
  /** List of the controls made for each TLD
   *
   * $tldmode is used by the administration panel, while choosing
   * the authorized TLDs. It's an array of strings explaining the current state of the TLD.
   */
45
  public $tldmode=array();
46

47

48
  /* ----------------------------------------------------------------- */
49
  /** Constructor
50
51
52
53
54
55
   */
  function m_admin() {
    global $db,$cuid;
    $db->query("SELECT su FROM membres WHERE uid='$cuid';");
    $db->next_record();
    $this->enabled=$db->f("su");
56
57
58
59
60
61
62
63
64

    $this->tldmode=array(
			 0 => _("This TLD is forbidden"),
			 1 => _("primary DNS is checked in WHOIS db"),
			 2 => _("primary & secondary DNS are checked in WHOIS db"),
			 3 => _("Domain must exist, but don't do any DNS check"),
			 4 => _("Domain can be installed, no check at all"),
			 5 => _("Domain can be installed, force NO DNS hosting"),
			 );
65
66
  }

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  function hook_menu() {
    global $mem, $cuid, $debug_alternc, $L_INOTIFY_UPDATE_DOMAIN;
    if (!$mem->checkRight()) return false;

    $obj = array(
      'title'       => _("Administration"),
      'ico'         => 'images/admin.png',
      'link'        => 'toggle',
      'class'       => 'adminmenu',
      'pos'         => 10,
      'links'       => 
        array(
          array(
           'txt'   => _("Manage AlternC accounts"), 
           'url'   => 'adm_list.php',
           'class' => 'adminmenu'
          ),
          array(
           'txt'   => _("User Quotas"), 
           'url'   => 'quotas_users.php?mode=4',
           'class' => 'adminmenu'
          ),
        )
     ) ;

    if ($cuid == 2000) {
      $obj['links'][] = 
        array(
           'txt'   => _("Admin Control Panel"), 
           'url'   => 'adm_panel.php',
           'class' => 'adminmenu'
          );
      $obj['links'][] = 
        array(
           'txt'   => _("PhpMyAdmin"), 
           'url'   => '/alternc-sql/',
103
104
           'class' => 'adminmenu',
           'target' => '_blank',
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
          );
      $obj['links'][] = 
        array(
           'txt'   => ($debug_alternc->status)?_("Switch debug Off"):_("Switch debug On"),
           'url'   => "alternc_debugme.php?enable=".($debug_alternc->status?"0":"1"), 
           'class' => 'adminmenu'
          );
      if (empty($L_INOTIFY_UPDATE_DOMAIN) || file_exists("$L_INOTIFY_UPDATE_DOMAIN") ) {
        $obj['links'][] =
          array(
             'txt'     => _("Applying..."),
             'url'     => 'javascript:alert(\''._("Domain changes are already applying").'\');',
             'class'   => 'adminmenu',
            );
      } else {
        $obj['links'][] =
          array(
             'txt'     => _("Apply changes"),
             'url'     => 'adm_update_domains.php',
             'class'   => 'adminmenu',
             'onclick' => 'return confirm("'.addslashes(_("Server configuration changes are applied every 5 minutes. Do you want to do it right now?")).'");',
            );

      } // L_INOTIFY_UPDATE_DOMAIN

    } // cuid == 2000


    return $obj;
  }

136

137
  /* ----------------------------------------------------------------- */
138
  /** Returns the known information about a hosted account
139
   * 
140
141
142
143
144
145
146
147
   * Returns all what we know about an account (contents of the tables
   *  <code>membres</code> et <code>local</code>)
   * Ckecks if the account is super-admin
   * @param integer $uid a unique integer identifying the account
   * @return an associative array containing all the fields of the
   * table <code>membres</code> and <code>local</code> of the corresponding account.
   * Returns FALSE if an error occurs.
   */
148
149
  function get($uid,$recheck=false) {
    global $err,$db,$lst_users_properties;
150
151
    //    $err->log("admin","get",$uid);
    if (!$this->enabled) {
152
      $err->raise("admin",_("-- Only administrators can access this page! --"));
153
154
      return false;
    }
155
156
157

    if (!isset($lst_users_properties) || empty($lst_users_properties) || !is_array($lst_users_properties) || $recheck ) {
      $lst_users_properties=array();
158
159
160
161
162
163
      $db->query("
	SELECT 
		m.uid as muid, 
		l.*, 
		m.*, 
		parent.login as parentlogin,
164
		dbs.name as db_server_name,
165
166
167
168
169
170
171
172
173
		m.renewed + INTERVAL m.duration MONTH as expiry,
		CASE 
			WHEN m.duration IS NULL THEN 0 
			WHEN m.renewed + INTERVAL m.duration MONTH <= NOW() THEN 3	
			WHEN m.renewed <= NOW() THEN 2
		ELSE 1 END 'status'
		
	FROM membres as m 
		LEFT JOIN membres as parent ON (parent.uid = m.creator) 
174
		LEFT JOIN db_servers as dbs ON (m.db_server_id = dbs.id)
175
		LEFT JOIN local as l ON (m.uid = l.uid) ;");
176
       while ($db->next_record()) {
177
         $lst_users_properties[$db->f('muid')]=$db->Record;
178
179
180
181
182
183
184
185
       }
    }

    if ( !isset($lst_users_properties[$uid]) ) {
      if ( !$recheck ) {
        // don't exist, but is not a forced check. Do a forced check
        return $this->get($uid, true);
      } 
186
      $err->raise("admin",_("Account not found"));
187
188
      return false;
    }
189
190

    return $lst_users_properties[$uid];
191
192
  }

193
194
195

  /* ----------------------------------------------------------------- */
  /** Returns the known information about a specific hosted account
196
197
198
199
200
201
   * Similar to get_list() but for creators/resellers.
   */
  function get_creator($uid) {
    global $err,$db;
    //    $err->log("admin","get",$uid);
    if (!$this->enabled) {
202
      $err->raise("admin",_("-- Only administrators can access this page! --"));
203
204
205
206
207
208
209
210
211
      return false;
    }

    $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='$uid';");

    if ($db->num_rows()) {
      $db->next_record();
      $c=$db->Record;
    } else {
212
      $err->raise("admin",_("Account not found"));
213
214
215
216
217
218
219
220
      return false;
    }

    $db->query("SELECT * FROM local WHERE uid='$uid';");
    if ($db->num_rows()) {
      $db->next_record();
      reset($db->Record);
      while (list($key,$val)=each($db->Record)) {
Alan Garcia's avatar
Alan Garcia committed
221
	      $c[$key]=$val;
222
223
224
225
226
227
228
229
      }
    }

    $db->query("SELECT count(*) as nbcreated FROM membres WHERE creator='$uid';");
    if ($db->num_rows()) {
      $db->next_record();
      reset($db->Record);
      while (list($key,$val)=each($db->Record)) {
Alan Garcia's avatar
Alan Garcia committed
230
	      $c[$key]=$val;
231
232
233
234
235
236
      }
    }

    return $c;
  }

237

238
  /* ----------------------------------------------------------------- */
239
  /** @return TRUE if there's only ONE admin account
240
241
   * @return boolean TRUE if there is only one admin account
   * (allow the program to prevent the destruction of the last admin account)
242
243
244
245
246
247
248
   */
  function onesu() {
    global $db;
    $db->query("SELECT COUNT(*) AS cnt FROM membres WHERE su=1");
    $db->next_record();
    return ($db->f("cnt")==1);
  }
249

250

251
  /* ----------------------------------------------------------------- */
252
  /** Returns the list of the hosted accounts
253
   * 
254
255
256
257
258
259
260
261
   * Returns all what we know about ALL the accounts (contents of the tables
   *  <code>membres</code> et <code>local</code>)
   * Check for super-admin accounts
   * @param
   * @return an associative array containing all the fields of the
   * table <code>membres</code> and <code>local</code> of all the accounts.
   * Returns FALSE if an error occurs.
   */
262
  function get_list($all=0,$creator=0) {
263
264
265
    global $err,$mem,$cuid;
    $err->log("admin","get_list");
    if (!$this->enabled) {
266
      $err->raise("admin",_("-- Only administrators can access this page! --"));
267
268
269
      return false;
    }
    $db=new DB_System();
270
    if ($creator) {
271
272
273
      // Limit listing to a specific reseller
      $db->query("SELECT uid FROM membres WHERE creator='".$creator."' ORDER BY login;");
    } elseif ($mem->user['uid']==2000 || $all) {
274
      $db->query("SELECT uid FROM membres ORDER BY login;");
275
    } else {
276
      $db->query("SELECT uid FROM membres WHERE creator='".$cuid."' ORDER BY login;");
277
278
279
280
281
282
283
284
285
286
287
    }
    if ($db->num_rows()) {
      while ($db->next_record()) {
	$c[]=$this->get($db->f("uid"));
      }
      return $c;
    } else {
      return false;
    }
  }

288

289
290
291
292
293
294
295
  /* ----------------------------------------------------------------- */
  /** Send an email to all AlternC's accounts
   * @param $subject string Subject of the email to send
   * @param $message string Message to send 
   * @param $from string expeditor of that email.
   * @return true if the mail has been successfully sent.
   */ 
Alan Garcia's avatar
Alan Garcia committed
296
297
298
299
  function mailallmembers($subject,$message,$from) {
    global $err,$mem,$cuid,$db;
    $err->log("admin","mailallmembers");
    if (!$this->enabled) {
300
      $err->raise("admin",_("-- Only administrators can access this page! --"));
Alan Garcia's avatar
Alan Garcia committed
301
302
303
304
305
306
307
      return false;
    }
    $subject=trim($subject);
    $message=trim($message);
    $from=trim($from);

    if (empty($subject) || empty($message) || empty($from) ){
308
      $err->raise("admin",_("Subject, message and sender are mandatory"));
Alan Garcia's avatar
Alan Garcia committed
309
310
311
312
      return false;
    }

    if (checkmail($from) != 0) {
313
      $err->raise("admin",_("Sender is syntaxically incorrect"));
Alan Garcia's avatar
Alan Garcia committed
314
315
316
317
      return false;
    }

    @set_time_limit(1200);
318
    $db->query("SELECT DISTINCT mail FROM membres WHERE mail!='';");
Alan Garcia's avatar
Alan Garcia committed
319
320
    while ($db->next_record()) {
      // Can't do BCC due to postfix limitation
321
      // FIXME: use phpmailer, far better for mass-mailing than sendmail (reply-to issue among others)
Alan Garcia's avatar
Alan Garcia committed
322
323
324
325
326
      mail($db->f('mail'), $subject, $message, null, "-f$from");
    }
    return true;
  }

327
328
329

  /* ----------------------------------------------------------------- */
  /** Returns an array with the known information about resellers (uid, login, number of accounts)
330
   * Does not include account 2000 in the list.
331
   * May only be called by the admin account (2000)
332
   * If there are no reseller accounts, returns an empty array.
333
334
335
336
   */
  function get_creator_list() {
    global $err,$mem,$cuid;

337
338
    $creators = array();

339
    $err->log("admin","get_reseller_list");
340
341
    if (!$this->enabled || $cuid!=2000) {
      $err->raise("admin",_("-- Only administrators can access this page! --"));
342
343
344
345
      return false;
    }

    $db=new DB_System();
346
    $db->query("SELECT DISTINCT creator FROM membres WHERE creator <> 0 ORDER BY creator ASC;");
347
348
    if ($db->num_rows()) {
      while ($db->next_record()) {
349
        $creators[] = $this->get_creator($db->f("creator"));
350
351
      }
    }
352
    return $creators;
353
354
  }

355

356
  /* ----------------------------------------------------------------- */
357
  /** Check if I am the creator of the member $uid
358
   * @param integer $uid a unique integer identifying the account
359
   * @return boolean TRUE if I am the creator of that account. FALSE else.
360
361
362
363
364
365
366
367
   */
  function checkcreator($uid) {
    global $err,$mem,$db,$cuid;
    if ($cuid==2000) {
      return true;
    }
    $db->query("SELECT creator FROM membres WHERE uid='$uid';");
    $db->next_record();
368
    if ($db->Record["creator"]!=$cuid) {
369
      $err->raise("admin",_("-- Only administrators can access this page! --"));
370
371
372
373
374
      return false;
    }
    return true;
  }

Alan Garcia's avatar
Alan Garcia committed
375
376
377
378
  // When the admin want to delegate a subdomain to an account
  function add_shared_domain($u, $domain_name) {
    global $db,$err,$dom,$mem,$cuid;
    $err->log("admin","add_shared_domain",$u."/".$domain_name);
379

Alan Garcia's avatar
Alan Garcia committed
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    if (! $mem->checkright() ) {
      $err->raise("admin",_("-- Only administrators can do that! --"));
      return false;
    } 

    // Check if this domain exist on this admin account
    if (! in_array($domain_name, $dom->enum_domains())) {
      $err->raise("admin",_("You don't seem to be allowed to delegate this domain"));
      $err->log("admin","add_shared_domain","domain not allowed");
      return false;
    } 

    // Clean the domain_name 
    $domain_name=preg_replace("/^\.\.*/", "", $domain_name);

    $mem->su($u);
    $dom->lock();
    // option : 1=hébergement dns, 1=noerase, empeche de modifier, 1=force
    $dom->add_domain($mem->user['login'].".".$domain_name,1,1,1);
    $dom->unlock();
    $mem->unsu();
    return true;
  }
    
404
  /* ----------------------------------------------------------------- */
405
  /** Creates a new hosted account
406
   *  
407
408
409
410
411
412
413
414
415
416
417
418
419
   * Creates a new hosted account (in the tables <code>membres</code>
   * and <code>local</code>). Prevents any manipulation of the account if
   * the account $mid is not super-admin.
   *
   * @param $login string Login name like [a-z][a-z0-9]*
   * @param $pass string Password (max. 64 characters)
   * @param $nom string Name of the account owner
   * @param $prenom string First name of the account owner
   * @param $mail string Email address of the account owner, useful to get
   * one's lost password
   * @pararm $type string Account type for quotas
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
420
  function add_mem($login, $pass, $nom, $prenom, $mail, $canpass=1, $type='default', $duration=0, $notes = "", $force=0, $create_dom=false, $db_server_id) {
421
    global $err,$quota,$classes,$cuid,$mem,$L_MYSQL_DATABASE,$L_MYSQL_LOGIN,$hooks,$action;
422
423
    $err->log("admin","add_mem",$login."/".$mail);
    if (!$this->enabled) {
424
      $err->raise("admin",_("-- Only administrators can access this page! --"));
425
426
      return false;
    }
427
428
429
430
    if (empty($db_server_id)) {
      $err->raise("admin",_("Missing db_server field"));
      return false;
    }
431
    if (($login=="")||($pass=="")) {
432
      $err->raise("admin",_("All fields are mandatory"));
433
434
      return false;
    }
435
436
    if (!$force) {
      if ($mail=="") {
437
	$err->raise("admin",_("All fields are mandatory"));
Alan Garcia's avatar
Alan Garcia committed
438
	      return false;
439
440
      }
      if (checkmail($mail)!=0){
441
	$err->raise("admin",_("Please enter a valid email address"));
Alan Garcia's avatar
Alan Garcia committed
442
	      return false;
443
      }
444
445
    }
    $login=strtolower($login);
Benjamin Sonntag's avatar
   
Benjamin Sonntag committed
446
    if (!preg_match("#^[a-z0-9]*$#",$login)) { //$
447
      $err->raise("admin", _("Login can only contains characters a-z and 0-9"));
448
449
      return false;
    }
450
451
452
453
454
    if (strlen($login) > 14) {
      // Not an arbitrary value : MySQL user names can be up to 16 characters long
      // If we want to allow people to create a few mysql_user (and we want to!)
      // we have to limit the login lenght
      $err->raise("admin",_("The login is too long (14 chars max)"));
455
456
      return false;
    }
457
    // Some login are not allowed...
458
    if ($login==$L_MYSQL_DATABASE || $login==$L_MYSQL_LOGIN || $login=="mysql" || $login=="root") {
459
      $err->raise("admin",_("Login can only contains characters a-z, 0-9 and -"));
460
461
462
463
      return false;
    }
    $pass=_md5cr($pass);
    $db=new DB_System();
464
    // Already exist?
465
466
467
    $db->query("SELECT count(*) AS cnt FROM membres WHERE login='$login';");
    $db->next_record();
    if (!$db->f("cnt")) {
468
      $db->query("SELECT max(m.uid)+1 as nextid FROM membres m");
469
      if (!$db->next_record()) {
Alan Garcia's avatar
Alan Garcia committed
470
	      $uid=2000;
471
      } else {
Alan Garcia's avatar
Alan Garcia committed
472
473
	      $uid=$db->Record["nextid"];
	      if ($uid<=2000) $uid=2000;
474
      }
475
      $db->query("INSERT INTO membres (uid,login,pass,mail,creator,canpass,type,created,notes,db_server_id) VALUES ('$uid','$login','$pass','$mail','$cuid','$canpass', '$type', NOW(), '$notes', '$db_server_id');");
476
477
      $db->query("INSERT INTO local(uid,nom,prenom) VALUES('$uid','$nom','$prenom');");
      $this->renew_update($uid, $duration);
478
479
480
481
      #exec("sudo /usr/lib/alternc/mem_add ".$login." ".$uid);
      $action->create_dir(getuserpath("$login"));
      $action->fix_dir(getuserpath("$login"));
      
482
      // Triggering hooks
483
      $mem->su($uid);
484
      // TODO: old hook method FIXME: when unused remove this
485
      /*
486
      foreach($classes as $c) {
Alan Garcia's avatar
Alan Garcia committed
487
488
489
      	if (method_exists($GLOBALS[$c],"alternc_add_member")) {
	        $GLOBALS[$c]->alternc_add_member();
	      }
490
      }
491
492
      */
      $hooks->invoke("alternc_add_member");
493
      // New hook way
Alan Garcia's avatar
Alan Garcia committed
494
      $hooks->invoke("hook_admin_add_member", array(), array('quota')); // First !!! The quota !!! Etherway, we can't be sure to be able to create all
495
      $hooks->invoke("hook_admin_add_member");
496
      $mem->unsu();
Alan Garcia's avatar
Alan Garcia committed
497
498
499
500
501

      if (!empty($create_dom)) { 
        $this->add_shared_domain($uid, $create_dom); 
      }

502
503
      return $uid;
    } else {
504
      $err->raise("admin",_("This login already exists"));
505
506
507
508
      return false;
    }
  }

509
510
  /* ----------------------------------------------------------------- */
  /** AlternC's standard function called when a user is created
511
512
   * This sends an email if configured through the interface.
   */
513
  function hook_admin_add_member() {
514
    global $err, $cuid, $L_FQDN, $L_HOSTING;
515
516
517
518
519
520
    $dest = variable_get('new_email');
    if (!$dest) {
      return false;
    }
    $db=new DB_System();
    if (!$db->query("SELECT m.*, parent.login as parentlogin FROM membres m LEFT JOIN membres parent ON parent.uid=m.creator WHERE m.uid='$cuid'")) {
521
      $err->raise("admin",sprintf(_("query failed: %s "), $db->Error));
522
523
524
      return false;
    }
    if ($db->next_record()) {
525
      // TODO: put that string into gettext ! 
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
      $mail = <<<EOF
A new AlternC account was created on %fqdn by %creator.

Account details
---------------

login: %login (%uid)
email: %mail
createor: %creator (%cuid)
can change password: %canpass
type: %type
notes: %notes
EOF;
       $mail = strtr($mail, array('%fqdn' => $L_FQDN,
       				  '%creator' => $db->Record['parentlogin'],
				  '%uid' => $db->Record['uid'],
				  '%login' => $db->Record['login'],
				  '%mail' => $db->Record['mail'],
				  '%cuid' => $db->Record['creator'],
				  '%canpass' => $db->Record['canpass'],
				  '%type' => $db->Record['type'],
				  '%notes' => $db->Record['notes']));
548
549
550
551
       $subject=sprintf(_("New account %s from %s on %s"), $db->Record['login'], $db->Record['parentlogin'], $L_HOSTING);
       if (mail($dest,$subject,$mail,"From: postmaster@$L_FQDN")) {
         //sprintf(_("Email successfully sent to %s"), $dest);
         return true;
552
       } else {
553
554
         $err->raise("admin",sprintf(_("Cannot send email to %s"), $dest));
         return false;
555
556
       } 
    } else {
557
558
       $err->raise("admin",sprintf(_("Query failed: %s"), $db->Error));
       return false;
559
560
561
    }
  }

562

563
  /* ----------------------------------------------------------------- */
564
  /** Edit an account
565
   *  
566
   * Change an account (in the tables <code>membres</code>
567
568
569
570
571
572
573
574
575
576
577
578
579
580
   * and <code>local</code>). Prevents any manipulation of the account if
   * the account $mid is not super-admin.
   *
   * @param $uid integer the uid number of the account we want to modify
   * @param login string new login name like [a-z][a-z0-9]*
   * @param $pass string new password (max. 64 characters)
   * @param $nom string new name of the account owner
   * @param $prenom string new first name of the account owner
   * @param $mail string new email address of the account owner
   * @param $enabled integer (value: 0 or 1) activates or desactivates the
   * @param $type string new type of account
   * access to the virtual desktop of this account.
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
Alan Garcia's avatar
Alan Garcia committed
581
  function update_mem($uid, $mail, $nom, $prenom, $pass, $enabled, $canpass, $type='default', $duration=0, $notes = "",$reset_quotas=false) {
582
583
584
    global $err,$db;
    global $cuid, $quota;

Alan Garcia's avatar
Alan Garcia committed
585
586
    $notes=addslashes($notes);

587
588
    $err->log("admin","update_mem",$uid);
    if (!$this->enabled) {
589
      $err->raise("admin",_("-- Only administrators can access this page! --"));
590
591
592
593
594
595
596
597
598
      return false;
    }
    $db=new DB_System();
    if ($pass) {
      $pass=_md5cr($pass);
      $ssq=" ,pass='$pass' ";
    } else {
      $ssq="";
    }
599

600
    if (($db->query("UPDATE local SET nom='$nom', prenom='$prenom' WHERE uid='$uid';"))
Alan Garcia's avatar
Alan Garcia committed
601
	     &&($db->query("UPDATE membres SET mail='$mail', canpass='$canpass', enabled='$enabled', `type`='$type', notes='$notes' $ssq WHERE uid='$uid';"))){
Alan Garcia's avatar
Alan Garcia committed
602
      if($reset_quotas == "on") $quota->addquotas();
603
604
605
606
      $this->renew_update($uid, $duration);
      return true;
    }
    else {
607
      $err->raise("admin",_("Account not found"));
608
609
610
611
      return false;
    }
  }

612

613
  /* ----------------------------------------------------------------- */
614
  /** Lock an account
615
616
617
618
619
620
621
622
   * Lock an account and prevent the user to access its account.
   * @param $uid integer the uid number of the account we want to lock
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
  function lock_mem($uid) {
    global $err,$db;
    $err->log("admin","lock_mem",$uid);
    if (!$this->enabled) {
623
      $err->raise("admin",_("-- Only administrators can access this page! --"));
624
625
626
627
628
629
630
      return false;
    }
    $db=new DB_System();
    if ($db->query("UPDATE membres SET enabled='0' WHERE uid='$uid';")) {
      return true;
    }
    else {
631
      $err->raise("admin",_("Account not found"));
632
633
634
635
636
637
      return false;
    }
  }


  /* ----------------------------------------------------------------- */
638
  /** UnLock an account
639
640
641
642
643
644
645
646
   * UnLock an account and prevent the user to access its account.
   * @param $uid integer the uid number of the account we want to unlock
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
  function unlock_mem($uid) {
    global $err,$db;
    $err->log("admin","unlock_mem",$uid);
    if (!$this->enabled) {
647
      $err->raise("admin",_("-- Only administrators can access this page! --"));
648
649
650
651
652
653
654
      return false;
    }
    $db=new DB_System();
    if ($db->query("UPDATE membres SET enabled='1' WHERE uid='$uid';")) {
      return true;
    }
    else {
655
      $err->raise("admin",_("Account not found"));
656
657
658
659
660
661
      return false;
    }
  }


  /* ----------------------------------------------------------------- */
662
  /** Deletes an account
663
664
665
666
667
668
   * Deletes the specified account. Prevents any manipulation of the account if
   * the account $mid is not super-admin.
   * @param $uid integer the uid number of the account we want to delete
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
  function del_mem($uid) {
669
    global $err,$quota,$classes,$cuid,$mem,$dom,$hooks,$action;
670
671
672
    $err->log("admin","del_mem",$uid);

    if (!$this->enabled) {
673
      $err->raise("admin",_("-- Only administrators can access this page! --"));
674
675
676
677
      return false;
    }
    $db=new DB_System();
    $tt=$this->get($uid);
678
    
679
    $mem->su($uid);
680
681
    // This script may take a long time on big accounts, let's give us some time ... Fixes 1132
    @set_time_limit(0);
682
    // WE MUST call m_dom before all others because of conflicts ...
683
    $dom->hook_admin_del_member();
684

685
    // TODO: old hook method, FIXME: remove when unused
686
    /*
687
688
689
    foreach($classes as $c) {
      if (method_exists($GLOBALS[$c],"alternc_del_member")) {
	$GLOBALS[$c]->alternc_del_member();
690
      }
691
    }
692
    */
693
694
695
696
697
698
699

    /* 
     * New way of deleting or backup delted user html folders using action class
     */
    $archive=variable_get('archive_del_data');
    $path=getuserpath($tt['login']);
    if($archive == 1 ){
700
     #echo("archive");
701
702
     $action->archive($path,"html"); 	
    }else{
703
     #echo("del");
704
705
     $action->del($path); 	
    }
706
    $hooks->invoke("alternc_del_member");
707
708
709
710
711
712
713
714
715
    $hooks->invoke("hook_admin_del_member");
    
    if (($db->query("DELETE FROM membres WHERE uid='$uid';")) &&
	($db->query("DELETE FROM local WHERE uid='$uid';"))) {
      $mem->unsu();
      // 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.
      $db->query("UPDATE membres SET creator=2000 WHERE creator='$uid';");
      return true;
    } else {
716
      $err->raise("admin",_("Account not found"));
717
718
719
      $mem->unsu();
      return false;
    }
720
721
  }

722

723
  /* ----------------------------------------------------------------- */
724
  /** Renew an account
725
726
727
728
729
730
731
732
733
734
735
736
   * Renew an account for its duration
   * @param $uid integer the uid number of the account we want to renew
   * @param $periods integer the number of periods we renew for
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
  function renew_mem($uid, $periods=1) {
    global $err,$db;

    $periods = intval($periods);
    if($periods == 0)
      return false;

737
    $query = "UPDATE membres SET renewed = renewed + INTERVAL (duration * $periods) MONTH WHERE uid=${uid};";
738
739
740
    if ($db->query($query)) {
      return true;
    } else {
741
      $err->raise("admin",_("Account not found"));
742
743
744
745
      return false;
    }
  }

746

747
  /* ----------------------------------------------------------------- */
748
  /** Update the duration information for an account
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
   * @param $uid integer the uid number of the account we want to update
   * @param $duration integer the new duration, in months, of the account
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
  function renew_update($uid, $duration) {
    global $err,$db;

    if($duration == 0) {
      if($db->query("UPDATE membres SET duration = NULL, renewed = NULL WHERE uid=$uid;"))
	return true;
    } else {
      if($db->query("UPDATE membres SET duration = $duration WHERE uid=$uid") &&
	 $db->query("UPDATE membres SET renewed = NOW() WHERE uid=$uid and renewed is null;"))
	return true;
    }

765
    $err->raise("admin",_("Account not found"));
766
767
768
    return false;
  }

769

770
  /* ----------------------------------------------------------------- */
771
  /** Get the expiry date for an account
772
773
774
775
   * @param $uid integer The uid number of the account
   * @return string The expiry date, a string as printed by MySQL
   */
  function renew_get_expiry($uid) {
776
777
778
    $jj=$this->get($uid);
    if ( isset($jj) && isset($jj['expiry']) && ! empty($jj['expiry']) ) {
      return $jj['expiry'];
779
780
781
782
    }
    return '';
  }

783

784
  /* ----------------------------------------------------------------- */
785
  /** Get the expiry status for an account
786
787
788
789
790
791
792
793
   * @param $uid integer The uid number of the account
   * @return integer The expiry status:
   *  0: account does not expire
   *  1: expires in more than duration,
   *  2: expires within the duration
   *  3: has expired past the duration
   */
  function renew_get_status($uid) {
794
    $jj=$this->get($uid);
795

796
797
    if ( isset($jj) && isset($jj['status']) && ! empty($jj['status']) ) {
      return $jj['status'];
798
    }
799

800
801
802
    return 0;
  }

803

804
  /* ----------------------------------------------------------------- */
805
  /** Get the expired/about to expire accounts.
806
807
808
809
810
811
812
813
814
815
816
817
818
819
   * @return resource The recordset of the corresponding accounts
   */
  function renew_get_expiring_accounts() {
    global $db;

    if(!$db->query("SELECT *, m.renewed + INTERVAL duration MONTH 'expiry'," .
		   " CASE WHEN m.duration IS NULL THEN 0" .
		   " WHEN m.renewed + INTERVAL m.duration MONTH <= NOW() THEN 3" .
		   " WHEN m.renewed <= NOW() THEN 2" .
		   " ELSE 1 END 'status' FROM membres m, local l" .
		   " WHERE m.uid = l.uid" .
		   " HAVING status=2 or status=3 ORDER BY status DESC, expiry;"))
      return false;
    else {
Alan Garcia's avatar
Alan Garcia committed
820
      $res=array();
821
      while($db->next_record())
Alan Garcia's avatar
Alan Garcia committed
822
	      $res[] = $db->Record;
823
824
825
826
827
828
      return $res;
    }
  }


  /* ----------------------------------------------------------------- */
829
  /** Turns a common account into a super-admin account
830
831
832
833
834
835
836
837
   * @param $uid integer the uid number of the common account we want to turn into a
   *  super-admin account.
   * @return Returns FALSE if an error occurs, TRUE if not.
   */
  function normal2su($uid) {
    global $err,$db;
    $db->query("SELECT su FROM membres WHERE uid='$uid';");
    if (!$db->next_record()) {
838
      $err->raise("admin",_("Account not found"));
839
      return false;
840
    } 
841
    if ($db->Record["su"]!=0) {
842
      $err->raise("admin",_("This account is ALREADY an administrator account"));
843
844
845
846
847
848
      return false;
    }
    $db->query("UPDATE membres SET su=1 WHERE uid='$uid';");
    return true;
  }

849

850
  /* ----------------------------------------------------------------- */
851
  /** Turns a super-admin account into a common account
852
853
854
855
856
857
858
859
   * @param $uid integer the uid number of the super-admin account we want to turn into a
   * common account.
   * @return boolean Returns FALSE if an error occurs, TRUE if not.
   */
  function su2normal($uid) {
    global $err,$db;
    $db->query("SELECT su FROM membres WHERE uid='$uid';");
    if (!$db->next_record()) {
860
      $err->raise("admin",_("Account not found"));
861
862
863
      return false;
    }
    if ($db->Record["su"]!=1) {
864
      $err->raise("admin",_("This account is NOT an administrator account!"));
865
866
867
868
869
870
      return false;
    }
    $db->query("UPDATE membres SET su=0 WHERE uid='$uid';");
    return true;
  }

871

872
  /* ----------------------------------------------------------------- */
873
  /** List of the authorized TLDs
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
   * Returns the list of the authorized TLDs and also the way they are
   * authorized. A TLD is the last members (or the last two) of a
   * domain. For example, "com", "org" etc... AlternC keeps a table
   * containing the list of the TLDs authorized to be installed on the
   * server with the instructions to validate the installation of a
   * domain for each TLD (if necessary).
   * @return array An associative array like $r["tld"], $r["mode"] where tld
   * is the tld and mode is the authorized mode.
   */
  function listtld() {
    global $db;
    $db->query("SELECT tld,mode FROM tld ORDER BY tld;");
    while ($db->next_record()) {
      $c[]=$db->Record;
    }
    return $c;
  }

892

893
  /* ----------------------------------------------------------------- */
894
  /** List the hosted domains on this server
895
   * Return the list of hosted domains on this server, (an array of associative arrays)
896
897
   * @param boolean $alsocheck Returns also errstr and errno telling the domains dig checks
   * @param boolean $forcecheck Force the check of dig domain even if a cache exists.
898
899
   * @return array $r[$i] / [domaine][member][noerase][gesdns][gesmx]
   */
900
  function dom_list($alsocheck=false,$forcecheck=false) {
901
    global $db;
902
903
904
905
    $cachefile="/tmp/alternc_dig_check_cache";
    $cachetime=3600; // The dns cache file can be up to 1H old
    if ($alsocheck) {
      if (!$forcecheck && file_exists($cachefile) && filemtime($cachefile)+$cachetime>time()) {
906
	      $checked=unserialize(file_get_contents($cachefile));
907
      } else {
908
909
910
        // TODO : do the check here (cf checkdom.php) and store it in $checked
        $checked=$this->checkalldom();
        file_put_contents($cachefile,serialize($checked));
911
912
      }
    }
913
    $db->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 ORDER BY domaine;");
914
    while ($db->next_record()) {
915
916
      $tmp=$db->Record;
      if ($alsocheck) {
917
918
      	$tmp["errstr"]=$checked[$tmp["domaine"]]["errstr"];
	      $tmp["errno"]=$checked[$tmp["domaine"]]["errno"];
919
920
      }
      $c[]=$tmp;
921
922
923
924
    }
    return $c;
  }

925
926

  /* ----------------------------------------------------------------- */
927
928
929
  /** Check all the domains for their NS MX and IPs
   */
  function checkalldom() {
930
    global $db,$L_NS1,$L_NS2,$L_MX,$L_PUBLIC_IP;
931
932
933
934
935
936
937
938
    $checked=array();
    $r=$db->query("SELECT * FROM domaines ORDER BY domaine;");
    $dl=array();
    while ($db->next_record()) {
      $dl[$db->Record["domaine"]]=$db->Record;
    }
    sort($dl);
    foreach($dl as $c) {
939
      // For each domain check its type:
940
941
942
      $errno=0;
      $errstr="";
      $dontexist=false;
943
      // Check the domain.
944
      if ($c["gesdns"]==1) {
945
	      // Check the NS pointing to us
Alan Garcia's avatar
Alan Garcia committed
946
947
948
949
950
951
952
953
954
	      $out=array();
	      exec("dig +short NS ".escapeshellarg($c["domaine"]),$out);
	      if (count($out)==0) {
	        $dontexist=true;
	      } else {
	        if (!in_array($L_NS1.".",$out) || !in_array($L_NS2.".",$out)) {
	          $errno=1; $errstr.="NS for this domain are not $L_NS1 and $L_NS2 BUT ".implode(",",$out)."\n";
	        }
	      }
955
956
      }
      if ($c["gesmx"]==1 && !$dontexist) {
Alan Garcia's avatar
Alan Garcia committed
957
958
959
960
961
962
963
964
965
  	    $out=array();
	      exec("dig +short MX ".escapeshellarg($c["domaine"]),$out);
	      $out2=array();
	      foreach($out as $o) {
	        list($t,$out2[])=explode(" ",$o);
	      }
	      if (!in_array($L_MX.".",$out2)) {
	        $errno=1; $errstr.="MX is not $L_MX BUT ".implode(",",$out2)."\n";
	      }
966
967
      }
      if (!$dontexist) {
968
	      // We list all subdomains and check they are pointing to us.
Alan Garcia's avatar
Alan Garcia committed
969
970
971
972
	      $db->query("SELECT * FROM sub_domaines WHERE domaine='".addslashes($c["domaine"])."' ORDER BY sub;");
	      while ($db->next_record()) {
	        $d=$db->Record;
	        if ($d["type"]==0) {
973
	          // Check the IP: 
Alan Garcia's avatar
Alan Garcia committed
974
975
976
977
978
979
980
981
	          $out=array();
	          exec("dig +short A ".escapeshellarg($d["sub"].(($d["sub"]!="")?".":"").$c["domaine"]),$out);
	          if (!in_array($L_PUBLIC_IP,$out)) {
	            $errstr.="subdomain '".$d["sub"]."' don't point to $L_PUBLIC_IP but to ".implode(",",$out)."\n";
	            $errno=1;
	          }
	        }
	      }
982
983
      }
      if ($dontexist) {
Alan Garcia's avatar
Alan Garcia committed
984
985
        $errno=2;
	      $errstr="Domain don't exist anymore !";
986
987
988
989
990
991
992
993
      }
      if ($errno==0) $errstr="OK";
      $checked[$c["domaine"]]=array("errno"=>$errno, "errstr"=>$errstr); 
    }
    return $checked;
  }


994
  /* ----------------------------------------------------------------- */
995
  /** Lock / Unlock a domain 
996
997
998
999
1000
   * Lock (or unlock) a domain, so that the member will be (not be) able to delete it
   * from its account
   * @param $dom string Domain name to lock / unlock
   * @return boolean TRUE if the domain has been locked/unlocked or FALSE if it does not exist.
   */
For faster browsing, not all history is shown. View entire blame