m_admin.php 41.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
/*
 $Id: m_admin.php,v 1.16 2006/02/09 20:12:22 benjamin Exp $
 ----------------------------------------------------------------------
 AlternC - Web Hosting System
 Copyright (C) 2006 Le rseau Koumbit Inc.
 http://koumbit.org/
 ----------------------------------------------------------------------
 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
 ----------------------------------------------------------------------
 Original Author of file: Benjamin Sonntag
 Purpose of file: Administrate members and rights.
 ----------------------------------------------------------------------
*/
/* ----------------------------------------------------------------- */
/**
* Classe de gestion de l'administration du serveur par les super-admin.
*
* Cette classe permet de crer / modifier / dtruire les comptes, ainsi que de
* modifier les paramtres du serveur.<br />
* Copyleft {@link http://alternc.net/ AlternC Team}
*
*
*/
class m_admin {

  /* ----------------------------------------------------------------- */
  /**
   * $enabled precises if the logged user is super-admin or not
   */
  var $enabled=0;

  /* ----------------------------------------------------------------- */
    /** 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.
    */

  var $tldmode=array(
53
54
55
56
57
58
		     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",
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
		     );

  /* ----------------------------------------------------------------- */
  /**
   * Constructeur
   */
  function m_admin() {
    global $db,$cuid;
    $db->query("SELECT su FROM membres WHERE uid='$cuid';");
    $db->next_record();
    $this->enabled=$db->f("su");
  }

  /* ----------------------------------------------------------------- */
  /**
   * Returns the known information about a hosted account
75
   * 
76
77
78
79
80
81
82
83
   * 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.
   *
84
   * Retourne tout ce que l'on sait sur un membre (contenu des tables <code>membres et local</code>) 
85
86
87
88
   * vrifie que le compte appelant est super-admin
   * @param integer $uid Numro de l'utilisateur dont on veut les informations.
   * @return array Retourne un tableau associatif contenant l'ensemble des champs des tables 'membres'
   *  et 'local' pour le membre demand. Retourne FALSE si une erreur s'est produite.
89
   * 
90
91
92
93
94
95
96
97
   */
  function get($uid) {
    global $err,$db;
    //    $err->log("admin","get",$uid);
    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }
98
    $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';");
99
100
101
102
103
104
105
106
107
108
109
110
    if ($db->num_rows()) {
      $db->next_record();
      $c=$db->Record;
    } else {
      $err->raise("admin",2);
      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
111
	      $c[$key]=$val;
112
113
114
115
116
      }
    }
    return $c;
  }

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  /**
   * Returns the known information about a specific hosted account
   * Similar to get_list() but for creators/resellers.
   */
  function get_creator($uid) {
    global $err,$db;
    //    $err->log("admin","get",$uid);
    if (!$this->enabled) {
      $err->raise("admin",1);
      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 {
      $err->raise("admin",2);
      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
144
	      $c[$key]=$val;
145
146
147
148
149
150
151
152
      }
    }

    $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
153
	      $c[$key]=$val;
154
155
156
157
158
159
      }
    }

    return $c;
  }

160
  /* ----------------------------------------------------------------- */
161
  /** 
162
163
164
165
166
167
168
169
170
   * @return TRUE if there's only ONE admin account
   * Retourne true s'il n'existe qu'un seul compte administrateur
   */
  function onesu() {
    global $db;
    $db->query("SELECT COUNT(*) AS cnt FROM membres WHERE su=1");
    $db->next_record();
    return ($db->f("cnt")==1);
  }
171

172
173
174
175
  /* ----------------------------------------------------------------- */
  /**
   * Returns the list of the hosted accounts
   * Retourne la liste des membres hbergs
176
   * 
177
178
179
180
181
182
183
184
185
186
   * 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.
   *
   * Retourne tout ce que l'on sait sur LES membres (contenu de membres et local)
   * vrifie que le compte appelant est super-admin
187
188
   * @return array Retourne un tableau index de tableaux associatifs contenant l'ensemble des 
   *  champs des tables 'membres' et 'local' pour les membre. Retourne FALSE si une erreur s'est 
189
   *  produite.
190
   * 
191
   */
192
  function get_list($all=0,$creator=0) {
193
194
195
196
197
198
199
    global $err,$mem,$cuid;
    $err->log("admin","get_list");
    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }
    $db=new DB_System();
200
    if ($creator) {
201
202
203
      // Limit listing to a specific reseller
      $db->query("SELECT uid FROM membres WHERE creator='".$creator."' ORDER BY login;");
    } elseif ($mem->user['uid']==2000 || $all) {
204
      $db->query("SELECT uid FROM membres ORDER BY login;");
205
    } else {
206
      $db->query("SELECT uid FROM membres WHERE creator='".$cuid."' ORDER BY login;");
207
208
209
210
211
212
213
214
215
216
217
    }
    if ($db->num_rows()) {
      while ($db->next_record()) {
	$c[]=$this->get($db->f("uid"));
      }
      return $c;
    } else {
      return false;
    }
  }

218

Alan Garcia's avatar
Alan Garcia committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  function mailallmembers($subject,$message,$from) {
    global $err,$mem,$cuid,$db;
    $err->log("admin","mailallmembers");
    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }
    $subject=trim($subject);
    $message=trim($message);
    $from=trim($from);

    if (empty($subject) || empty($message) || empty($from) ){
      $err->raise("admin",16);
      return false;
    }

    if (checkmail($from) != 0) {
      $err->raise("admin",17);
      return false;
    }

    @set_time_limit(1200);
    $db->query("select distinct mail from membres;");
    while ($db->next_record()) {
      // Can't do BCC due to postfix limitation
      mail($db->f('mail'), $subject, $message, null, "-f$from");
    }

    return true;
  }

250
  /**
251
252
   * Returns an array with the known information about resellers (uid, login, number of accounts)
   * Does not include account 2000 in the list.
253
   * May only be called by the admin account (2000)
254
   * If there are no reseller accounts, returns an empty array.
255
256
257
258
   */
  function get_creator_list() {
    global $err,$mem,$cuid;

259
260
    $creators = array();

261
262
263
264
265
266
267
268
    $err->log("admin","get_reseller_list");
    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }

    if ($cuid != 2000) {
      $err->raise("admin",1);
269
      return $creators;
270
271
272
273
274
275
276
277
    }

    $db=new DB_System();

    $db->query("SELECT distinct creator FROM membres WHERE creator <> 0 ORDER BY creator asc;");

    if ($db->num_rows()) {
      while ($db->next_record()) {
278
        $creators[] = $this->get_creator($db->f("creator"));
279
280
      }
    }
281
282

    return $creators;
283
284
  }

285
286
287
288
289
290
291
292
  /* ----------------------------------------------------------------- */
  /**
   * Check if I am the creator of the member $uid
   *
   * @param integer $uid a unique integer identifying the account
   */
  function checkcreator($uid) {
    global $err,$mem,$db,$cuid;
293
    // Check that the current user is editing one of it's own account !
294
295
296
297
298
299
    // but ADMIN (always uid 2000) is almighty
    if ($cuid==2000) {
      return true;
    }
    $db->query("SELECT creator FROM membres WHERE uid='$uid';");
    $db->next_record();
300
    if ($db->Record["creator"]!=$cuid) {
301
302
303
304
305
306
307
308
309
      $err->raise("admin",1);
      return false;
    }
    return true;
  }

  /* ----------------------------------------------------------------- */
  /**
   * Creates a new hosted account
310
   *  
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
   * 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.
   *
   *
   * Cre un nouveau membre hberg
326
   * Cration d'un nouveau membre (dans membres et local) Refuse l'utilisation de l'objet 
327
   * si le compte $mid n'est pas super-admin
328
   * 
329
330
331
332
333
334
335
336
337
338
   * @param $login Nom d'utilisateur, de la forme [a-z][a-z0-9]*
   * @param $pass Mot de passe, maxi 64 caractres
   * @param $nom Nom de la personne ou structure
   * @param $prenom Prnom de la personne ou structure
   * @param $mail Adresse email du propritaire du compte, permet de rcuprer son mot de passe
   * @param $type Type de compte pour les quotas
   * @param $duration integer Dure du compte en mois
   * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
   *
   */
339
  function add_mem($login, $pass, $nom, $prenom, $mail, $canpass=1, $type='default', $duration=0, $notes = "", $force=0) {
340
341
342
343
344
345
    global $err,$quota,$classes,$cuid,$mem,$L_MYSQL_DATABASE,$L_MYSQL_LOGIN;
    $err->log("admin","add_mem",$login."/".$mail);
    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }
346
    if (($login=="")||($pass=="")) {
347
348
349
      $err->raise("admin",6);
      return false;
    }
350
351
    if (!$force) {
      if ($mail=="") {
Alan Garcia's avatar
Alan Garcia committed
352
353
	      $err->raise("admin",6);
	      return false;
354
355
      }
      if (checkmail($mail)!=0){
Alan Garcia's avatar
Alan Garcia committed
356
357
	      $err->raise("admin",5);
	      return false;
358
      }
359
360
361
    }
    // Vrification de la conformit du login
    $login=strtolower($login);
Benjamin Sonntag's avatar
   
Benjamin Sonntag committed
362
    if (!preg_match("#^[a-z0-9]*$#",$login)) { //$
363
      $err->raise("admin", "Login can only contains characters a-z and 0-9");
364
365
366
367
368
369
      return false;
    }
    if (strlen($login) > 16) {
      $err->raise("admin",13);
      return false;
    }
370
    // Il ne peut pas tre gal au login ou au nom de base systeme ! 
371
    if ($login==$L_MYSQL_DATABASE || $login==$L_MYSQL_LOGIN || $login=="mysql" || $login=="root") {
372
373
374
      $err->raise("admin",10);
      return false;
    }
375
    //$pass=stripslashes($pass);
376
377
378
379
380
381
    $pass=_md5cr($pass);
    $db=new DB_System();
    // vrification de l'inexistence du membre dans system.membres
    $db->query("SELECT count(*) AS cnt FROM membres WHERE login='$login';");
    $db->next_record();
    if (!$db->f("cnt")) {
382
      $db->query("SELECT max(m.uid)+1 as nextid FROM membres m");
383
      if (!$db->next_record()) {
Alan Garcia's avatar
Alan Garcia committed
384
	      $uid=2000;
385
      } else {
Alan Garcia's avatar
Alan Garcia committed
386
387
	      $uid=$db->Record["nextid"];
	      if ($uid<=2000) $uid=2000;
388
389
      }
      // on le cr ensuite dans system.membres et system.local
Antoine Beaupré's avatar
Antoine Beaupré committed
390
      $db->query("INSERT INTO membres (uid,login,pass,mail,creator,canpass,type,created, notes) VALUES ('$uid','$login','$pass','$mail','$cuid','$canpass', '$type', NOW(), '$notes');");
391
392
393
394
395
396
      $db->query("INSERT INTO local(uid,nom,prenom) VALUES('$uid','$nom','$prenom');");
      $this->renew_update($uid, $duration);
      exec("/usr/lib/alternc/mem_add ".$login." ".$uid);
      // Declenchons les autres classes.
      $mem->su($uid);
      foreach($classes as $c) {
Alan Garcia's avatar
Alan Garcia committed
397
398
399
      	if (method_exists($GLOBALS[$c],"alternc_add_member")) {
	        $GLOBALS[$c]->alternc_add_member();
	      }
400
401
402
403
404
405
406
407
408
      }
      $mem->unsu();
      return $uid;
    } else {
      $err->raise("admin",3);
      return false;
    }
  }

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  /** 
   * AlternC's standard function called when a user is created
   *
   * This sends an email if configured through the interface.
   */
  function alternc_add_member() {
    global $cuid, $L_FQDN, $L_HOSTING;
    $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'")) {
      echo "query failed: " . $db->Error;
      return false;
    }
    if ($db->next_record()) {
      $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']));
Nahuel Angelinetti's avatar
Nahuel Angelinetti committed
448
       if (mail($dest,"New account (" . $db->Record['login']." from ".$db->Record['parentlogin'].") on $L_HOSTING",$mail,"From: postmaster@$L_FQDN")) {
449
450
451
452
453
454
455
456
457
         echo "Successfully sent email to $dest";
       } else {
         echo "Cannot send email to $dest";
       } 
    } else {
      echo "query failed: " . $db->Error;
    }
  }

458
459
460
  /* ----------------------------------------------------------------- */
  /**
   * Modifies an account
461
   *  
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
   * Modifies an 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 $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.
   *
   * Modifie un membre hberg
   *
   * modifie les donnes d'un membre. Refuse l'utilisation de l'objet
   * si le compte $mid n'est pas super-admin
   *
   * @param $uid integer Numro uid de l'utilisateur que l'on souhaite modifier.
   * @param $mail string Nouvelle adresse email
   * @param $nom $prenom string Nouveaux nom et prnom de l'utilisateur
   * @param $pass string Nouveau mot de passe.
   * @param $enabled integer vaut 0 ou 1, active ou dsactive l'accs au bureau virtuel de ce compte.
   * @param $type string Nouveau type de compte
   * @param $duration integer Dure du compte en mois
   * @return boolean Retourne FALSE si une erreur s'est produite, TRUE sinon.
490
   * 
491
   */
Alan Garcia's avatar
Alan Garcia committed
492
  function update_mem($uid, $mail, $nom, $prenom, $pass, $enabled, $canpass, $type='default', $duration=0, $notes = "",$reset_quotas=false) {
493
494
495
    global $err,$db;
    global $cuid, $quota;

Alan Garcia's avatar
Alan Garcia committed
496
497
    $notes=addslashes($notes);

498
499
500
501
502
503
504
    $err->log("admin","update_mem",$uid);
    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }
    $db=new DB_System();
    if ($pass) {
505
      // on modifie aussi le password : 
506
507
508
509
510
      $pass=_md5cr($pass);
      $ssq=" ,pass='$pass' ";
    } else {
      $ssq="";
    }
511

512
    if (($db->query("UPDATE local SET nom='$nom', prenom='$prenom' WHERE uid='$uid';"))
Alan Garcia's avatar
Alan Garcia committed
513
	     &&($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
514
      if($reset_quotas == "on") $quota->addquotas();
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
      $this->renew_update($uid, $duration);
      return true;
    }
    else {
      $err->raise("admin",2);
      return false;
    }
  }

  /* ----------------------------------------------------------------- */
  /**
   * Lock an account
   *
   * 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) {
      $err->raise("admin",1);
      return false;
    }
    $db=new DB_System();
    if ($db->query("UPDATE membres SET enabled='0' WHERE uid='$uid';")) {
      return true;
    }
    else {
      $err->raise("admin",2);
      return false;
    }
  }


  /* ----------------------------------------------------------------- */
  /**
   * UnLock an account
   *
   * 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) {
      $err->raise("admin",1);
      return false;
    }
    $db=new DB_System();
    if ($db->query("UPDATE membres SET enabled='1' WHERE uid='$uid';")) {
      return true;
    }
    else {
      $err->raise("admin",2);
      return false;
    }
  }



  /* ----------------------------------------------------------------- */
  /**
   * Deletes an account
   *
   * 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.
   *
   *
   * Efface un membre hberg
591
   * 
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
   * Supprime le membre spcifi. Refuse l'utilisation de l'objet si le compte $mid n'est pas super-admin
   * @param $uid Numro du membre  supprimer.
   * @return Retourne FALSE si une erreur s'est produite, TRUE sinon.
   *
   */
  function del_mem($uid) {
    global $err,$quota,$classes,$cuid,$mem,$dom;
    $err->log("admin","del_mem",$uid);

    if (!$this->enabled) {
      $err->raise("admin",1);
      return false;
    }
    $db=new DB_System();
    $tt=$this->get($uid);
607
608
    
    // On devient l'utilisateur : 
609
610
    $mem->su($uid);

611
612
613
    // This script may take a long time on big accounts, let's give us some time ... Fixes 1132
    @set_time_limit(0);

614
615
616
    // WE MUST call m_dom before all others because of conflicts ...
    $dom->alternc_del_member();

617
      // Send the event to the other classes : 
618
      foreach($classes as $c) {
Alan Garcia's avatar
Alan Garcia committed
619
620
621
	      if (method_exists($GLOBALS[$c],"alternc_del_member")) {
	        $GLOBALS[$c]->alternc_del_member();
	      }
622
623
      }
      if (($db->query("DELETE FROM membres WHERE uid='$uid';")) &&
Alan Garcia's avatar
Alan Garcia committed
624
625
626
627
628
629
	        ($db->query("DELETE FROM local WHERE uid='$uid';"))) {
	      exec("/usr/lib/alternc/mem_del ".$tt["login"]);
	      $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;
630
      } else {
Alan Garcia's avatar
Alan Garcia committed
631
632
633
        $err->raise("admin",2);
        $mem->unsu();
        return false;
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
      }
  }

  /* ----------------------------------------------------------------- */
  /**
   * Renew an account
   *
   * 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;

    $query =
      "UPDATE membres SET renewed = renewed + INTERVAL (duration * $periods) MONTH WHERE uid=${uid};";

    if ($db->query($query)) {
      return true;
    } else {
      $err->raise("admin",2);
      return false;
    }
  }

  /* ----------------------------------------------------------------- */
  /**
   * Update the duration information for an account
   *
   * @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;
    }

    $err->raise("admin",2);
    return false;
  }

  /* ----------------------------------------------------------------- */
  /**
   *
   * Get the expiry date for an account
   *
   * @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) {
    global $db;

    $db->query("SELECT renewed + INTERVAL duration MONTH 'expiry' FROM membres WHERE uid='$uid' ;");
    if ($db->num_rows()) {
      $db->next_record();
      return $db->Record['expiry'];
    }

    return '';
  }

  /* ----------------------------------------------------------------- */
  /**
   *
   * Get the expiry status for an account
   *
   * @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) {
    global $db;

    $db->query(
      "SELECT CASE" .
      " WHEN duration IS NULL THEN 0" .
      " WHEN renewed + INTERVAL duration MONTH <= NOW() THEN 3" .
      " WHEN renewed <= NOW() THEN 2" .
      " ELSE 1 END 'status' FROM membres where uid=$uid;");

    if($db->num_rows()) {
      $db->next_record();
      return $db->Record['status'];
    }

    return 0;
  }

  /* ----------------------------------------------------------------- */
  /**
   *
   * Get the expired/about to expire accounts.
   *
   * @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
758
      $res=array();
759
      while($db->next_record())
Alan Garcia's avatar
Alan Garcia committed
760
	      $res[] = $db->Record;
761
762
763
764
      return $res;
    }
  }

765
 
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787

  /* ----------------------------------------------------------------- */
  /**
   * Turns a common account into a super-admin account
   *
   * @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.
   *
   *
   * Transforme un membre Normal en membre Administrateur
   *
   * @param $uid Numro du compte  transformer
   * @return Retourne FALSE si une erreur s'est produite.
   *
   */
  function normal2su($uid) {
    global $err,$db;
    $db->query("SELECT su FROM membres WHERE uid='$uid';");
    if (!$db->next_record()) {
      $err->raise("admin",2);
      return false;
788
    } 
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
    if ($db->Record["su"]!=0) {
      $err->raise("admin",8);
      return false;
    }
    $db->query("UPDATE membres SET su=1 WHERE uid='$uid';");
    return true;
  }

  /* ----------------------------------------------------------------- */
  /**
   * Turns a super-admin account into a common account
   *
   * @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.
   *
   *
   * Transforme un membre Administrateur en membre Normal
   * @param integer $uid Numro du compte  transformer
   * @return boolean Retourne FALSE si une erreur s'est produite.
809
   * 
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
   */
  function su2normal($uid) {
    global $err,$db;
    $db->query("SELECT su FROM membres WHERE uid='$uid';");
    if (!$db->next_record()) {
      $err->raise("admin",2);
      return false;
    }
    if ($db->Record["su"]!=1) {
      $err->raise("admin",9);
      return false;
    }
    $db->query("UPDATE membres SET su=0 WHERE uid='$uid';");
    return true;
  }

  /* ----------------------------------------------------------------- */
  /**
   * List of the authorized TLDs
   *
   * 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).
836
   * 
837
838
   * @return array An associative array like $r["tld"], $r["mode"] where tld
   * is the tld and mode is the authorized mode.
839
840
841
842
843
844
845
846
847
   * 
   *
   * Liste des TLD autoriss 
   * 
   * Retourne la liste des tld autoriss, ainsi que la faon dont ils sont autoriss. 
   * Les tld sont le dernier membre (ou parfois les 2 derniers membres) d'un domaine. 
   * Par exemple "org" "com" etc. AlternC conserve une table "tld" qui contient la liste 
   * des TLD autoriss  tre install sur le serveur, accompagn des vrifications  effectuer 
   * pour chaque TLD. Par exemple, on peux vrifier que les DNS du domaine pointent bien vers 
848
849
850
   * notre serveur, ou juste que le domaine existe etc.
   * <p><b>Note</b> : Il faudrait pouvoir effectuer une requete DNS, et pouvoir juste vrifier les DNS
   * via DIG et pas seulement via Whois</p>
851
852
   * 
   * @return array Retourne un tableau de tableau associatif du type $r["tld"], $r["mode"]. 
853
   *  TLD est le tld et MODE est le mode autoris
854
   * 
855
856
857
858
859
860
861
862
863
864
865
866
867
   */
  function listtld() {
    global $db;
    $db->query("SELECT tld,mode FROM tld ORDER BY tld;");
    while ($db->next_record()) {
      $c[]=$db->Record;
    }
    return $c;
  }

  /* ----------------------------------------------------------------- */
  /**
   * List the hosted domains on this server
868
   * 
869
   * Return the list of hosted domains on this server, (an array of associative arrays)
870
871
   * @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.
872
873
   * @return array $r[$i] / [domaine][member][noerase][gesdns][gesmx]
   */
874
  function dom_list($alsocheck=false,$forcecheck=false) {
875
    global $db;
876
877
878
879
    $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()) {
880
	      $checked=unserialize(file_get_contents($cachefile));
881
      } else {
882
883
884
        // TODO : do the check here (cf checkdom.php) and store it in $checked
        $checked=$this->checkalldom();
        file_put_contents($cachefile,serialize($checked));
885
886
      }
    }
887
    $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;");
888
    while ($db->next_record()) {
889
890
      $tmp=$db->Record;
      if ($alsocheck) {
891
892
      	$tmp["errstr"]=$checked[$tmp["domaine"]]["errstr"];
	      $tmp["errno"]=$checked[$tmp["domaine"]]["errno"];
893
894
      }
      $c[]=$tmp;
895
896
897
898
    }
    return $c;
  }

899
900
901
  /** Check all the domains for their NS MX and IPs
   */
  function checkalldom() {
902
    global $db,$L_NS1,$L_NS2,$L_MX,$L_PUBLIC_IP;
903
904
905
906
907
908
909
910
911
912
913
914
915
916
    $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) {
      // Pour chaque domaine on verifie son etat : 
      $errno=0;
      $errstr="";
      $dontexist=false;
      // Check du domaine
      if ($c["gesdns"]==1) {
Alan Garcia's avatar
Alan Garcia committed
917
918
919
920
921
922
923
924
925
926
	      // Check du NS qui pointe chez nous 
	      $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";
	        }
	      }
927
928
      }
      if ($c["gesmx"]==1 && !$dontexist) {
Alan Garcia's avatar
Alan Garcia committed
929
930
931
932
933
934
935
936
937
  	    $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";
	      }
938
939
      }
      if (!$dontexist) {
Alan Garcia's avatar
Alan Garcia committed
940
941
942
943
944
945
946
947
948
949
950
951
952
953
	      // On liste les sous-domaine et on verifie qu'ils pointent bien chez nous...
	      $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) {
	          // Check l'IP : 
	          $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;
	          }
	        }
	      }
954
955
      }
      if ($dontexist) {
Alan Garcia's avatar
Alan Garcia committed
956
957
        $errno=2;
	      $errstr="Domain don't exist anymore !";
958
959
960
961
962
963
964
965
      }
      if ($errno==0) $errstr="OK";
      $checked[$c["domaine"]]=array("errno"=>$errno, "errstr"=>$errstr); 
    }
    return $checked;
  }


966
967
  /* ----------------------------------------------------------------- */
  /**
968
   * Lock / Unlock a domain 
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
   *
   * 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.
   */
  function dom_lock($domain) {
    global $db,$err;
    $db->query("SELECT compte FROM domaines WHERE domaine='$domain';");
    if (!$db->next_record()) {
      $err->raise("dom",1);
      return false;
    }
    $db->query("UPDATE domaines SET noerase=1-noerase WHERE domaine='$domain';");
    return true;
  }


  /* ----------------------------------------------------------------- */
  /**
989
   * Add a new TLD to the list of the authorized TLDs 
990
991
992
993
994
995
996
   *
   * @param $tld string top-level domain to add (org, com...)
   * @param $mode integer number of the authorized mode (0 to 5)
   * @return boolean TRUE if the tld has been successfully added, FALSE if not.
   *
   *
   * Ajoute un nouveau TLD autoris  la liste des tld autoriss.
997
   * 
998
999
1000
   * @param $tld Top-Level Domain  ajouter (org, com ...)
   * @param $mode Numro du mode autoris (0->5)
   * @return boolean True si le tld a bien t ajout, False sinon.
For faster browsing, not all history is shown. View entire blame