#!/bin/sh

# $Id: creer-base,v 1.5 2008/03/12 09:17:11 pda Exp $

#
# Cration de la base DNS
#
# Syntaxe :
#	creer-base-dns
# (pas d'argument)
#
# Historique
#   2002/02/11 : pda        : conception
#   2002/02/12 : pda/jean   : modifications pour coller au mcd original
#   2002/04/19 : pda/jean   : contrainte unique sur nom+domaine de rr
#   2002/04/19 : pda        : contrainte unique sur le nom de domaine
#   2002/04/23 : pda        : ajout de la priorit dans les droits de domaine
#   2002/04/23 : pda/jean   : ajout de la gestionde la gnration des zones
#   2002/05/02 : pda/jean   : table zone objectise
#   2002/05/06 : pda        : id pour la table zone
#   2002/05/21 : pda        : ajout de la table communaute
#   2004/01/22 : pda        : adaptation au nouveau format de base
#   2005/04/08 : pda        : adaptation au nouveau format de base (v 1.3)
#   2007/11/27 : pda/jean   : validation avec pgsql 8.2
#   2007/11/27 : pda/jean   : ajout de la table log
#

BASE=dns

PGPASSWORD="mot-de-passe-de-dns"
export PGPASSWORD

NOBODY="dns"			# utilisateur(s) non privilgi(s)
ROOT="pda jean"			# utilisateur(s) privilgi(s)

##############################################################################
# POUR EVITER LES ERREURS (LANCEMENT MALENCONTREUX DE CE SCRIPT)

#exit 0

##############################################################################

dropdb $BASE > /dev/null 2> /dev/null

createdb -E unicode $BASE

createlang pltcl $BASE

psql --quiet $BASE <<'EOF'

    -- les domaines

    CREATE SEQUENCE seq_domaine START 1 ;
    CREATE TABLE domaine (
	iddom		INT		-- identifiant du domaine
		DEFAULT NEXTVAL ('seq_domaine'),
	nom		TEXT,		-- le domaine (ex: "u-strasbg.fr")

	UNIQUE (nom),
	PRIMARY KEY (iddom)
    ) ;

    -- les correspondants et les groupes

    CREATE SEQUENCE seq_groupe START 1 ;
    CREATE TABLE groupe (
	idgrp		INT		-- identifiant du correspondant
		DEFAULT NEXTVAL ('seq_groupe'),
	nom		TEXT,		-- login sur le serveur
	admin		INT,		-- 1 si root, 0 si utilisateur normal

	UNIQUE (nom),
	PRIMARY KEY (idgrp)
    ) ;

    CREATE SEQUENCE seq_corresp START 1 ;
    CREATE TABLE corresp (
	idcor		INT		-- identifiant du correspondant
		DEFAULT NEXTVAL ('seq_corresp'),
	login		TEXT,		-- login sur le serveur
	present		INT,		-- 1 si present, 0 si plus l
	idgrp		INT,		-- le groupe qui refrence ses droits

	UNIQUE (login),
	FOREIGN KEY (idgrp) REFERENCES groupe (idgrp),
	PRIMARY KEY (idcor)
    ) ;

    -- la description des rseaux, des communauts et des tablissements

    CREATE SEQUENCE seq_etablissement START 1 ;
    CREATE TABLE etablissement (
	idetabl		INT		-- identifiant de l'tablissement
		DEFAULT NEXTVAL ('seq_etablissement'),
	nom		TEXT,		-- "Universit Louis Pasteur"

	PRIMARY KEY (idetabl)
    ) ;

    CREATE SEQUENCE seq_communaute START 1 ;
    CREATE TABLE communaute (
	idcommu		INT		-- identifiant de la communaute
		DEFAULT NEXTVAL ('seq_communaute'),
	nom		TEXT,		-- "Administration"

	PRIMARY KEY (idcommu)
    ) ;

    CREATE SEQUENCE seq_reseau START 1 ;
    CREATE TABLE reseau (
	idreseau	INT		-- identification du rseau
		DEFAULT NEXTVAL ('seq_reseau'),
	nom		TEXT,		-- nom (ex: "serveurs CRC")
	localisation	TEXT,		-- localisation prcise ventuelle
	adr4		CIDR,		-- plage IPv4 du rseau
	adr6		CIDR,		-- plage IPv6 du rseau
	idetabl		INT,		-- l'tablissement d'appartenance
	idcommu		INT,		-- ADM, ENS, RECH
	commentaire	TEXT,		-- texte libre
	dhcp		INT DEFAULT 0,	-- activer DHCP (1) ou non (0)
	gw4		INET,		-- routeur IPv4 par dfaut du rseau
	gw6		INET,		-- routeur IPv6 par dfaut du rseau


	CONSTRAINT au_moins_un_prefixe_v4_ou_v6
	    CHECK (adr4 IS NOT NULL OR adr6 IS NOT NULL),
	CONSTRAINT gw4_in_net CHECK (gw4 <<= adr4),
	CONSTRAINT gw6_in_net CHECK (gw6 <<= adr6),
	CONSTRAINT dhcp_needs_ipv4_gateway
	    CHECK (dhcp = 0 OR (dhcp != 0 AND gw4 IS NOT NULL)),
	FOREIGN KEY (idetabl) REFERENCES etablissement (idetabl),
	FOREIGN KEY (idcommu) REFERENCES communaute    (idcommu),
	PRIMARY KEY (idreseau)
    ) ;


    -- les types de machines

    CREATE SEQUENCE seq_hinfo MINVALUE 0 START 0 ;
    CREATE TABLE hinfo (
	idhinfo		INT		-- le type de machine
		DEFAULT NEXTVAL ('seq_hinfo'),
	texte		TEXT,		-- le type en clair
	tri		INT,		-- classe de tri
	present		INT,		-- prsent dans l'application
	PRIMARY KEY (idhinfo)
    ) ;

    -- les plages de rseau gres par les correspondants

    CREATE TABLE dr_reseau (
	idgrp		INT,		-- le groupe qui gre le rseau
	idreseau	INT,		-- le rseau
	tri		INT,		-- classe de tri pour l'affichage
	dhcp		INT DEFAULT 0,	-- accs  la gestion DHCP (dynamique)
	acl		INT DEFAULT 0,	-- accs aux ACL (plus tard...)

	FOREIGN KEY (idgrp)    REFERENCES groupe (idgrp),
	FOREIGN KEY (idreseau) REFERENCES reseau (idreseau),
	PRIMARY KEY (idgrp, idreseau)
    ) ;

    -- les droits associs aux groupes

    CREATE TABLE dr_dom (
	idgrp		INT,		-- le groupe
	iddom		INT,		-- texte du domaine
	tri		INT,		-- pour l'affichage dans les menus
	rolemail	INT DEFAULT 0,	-- groupe a accs aux rles mail
	roleweb		INT DEFAULT 0,	-- groupe a accs aux rles web

	FOREIGN KEY (idgrp) REFERENCES groupe (idgrp),
	PRIMARY KEY (idgrp, iddom)
    ) ;

    CREATE TABLE dr_ip (
	idgrp		INT,		-- le groupe
	adr		CIDR,		-- portion de rseau
	allow_deny	INT,		-- 1 = allow, 0 = deny

	FOREIGN KEY (idgrp) REFERENCES groupe (idgrp),
	PRIMARY KEY (idgrp, adr)
    ) ;

    -- les profils DHCP

    CREATE SEQUENCE seq_dhcpprofil START 1 ;
    CREATE TABLE dhcpprofil (
	iddhcpprofil	INT		-- identifiant du profil DHCP
		DEFAULT NEXTVAL ('seq_dhcpprofil'),
	nom 		TEXT UNIQUE,	-- nom du profil
	texte		TEXT,		-- texte  ajouter avant les hosts

	CHECK (iddhcpprofil >= 1),
	PRIMARY KEY (iddhcpprofil)
    ) ;

    -- les droits associs aux profils DHCP

    CREATE TABLE dr_dhcpprofil (
	idgrp		INT,		-- identifiant du groupe
	iddhcpprofil	INT,		-- identifiant du profil DHCP
	tri		INT,		-- classe de tri pour les menus

	FOREIGN KEY (idgrp)        REFERENCES groupe     (idgrp),
	FOREIGN KEY (iddhcpprofil) REFERENCES dhcpprofil (iddhcpprofil),
	PRIMARY KEY (idgrp, iddhcpprofil)
    ) ;

    -- les intervalles d'adresses dynamiques DHCP

    CREATE SEQUENCE seq_dhcprange START 1 ;
    CREATE TABLE dhcprange (
	iddhcprange	INT		-- seulement pour l'dition de tableau
		DEFAULT NEXTVAL ('seq_dhcprange'),
	min 		INET UNIQUE,	-- dbut de l'intervalle dynamique
	max		INET UNIQUE,	-- fin de l'intervalle dynamique
	iddom		INT,		-- domaine fourni par DHCP
	default_lease_time INT DEFAULT 0, -- en secondes
	max_lease_time	INT DEFAULT 0,	-- en secondes

	CHECK (min <= max),
	FOREIGN KEY (iddom) REFERENCES domaine (iddom),
	PRIMARY KEY (iddhcprange)
    ) ;


    -- les RR

    CREATE SEQUENCE seq_rr START 1 ;
    CREATE TABLE rr (
	idrr		INT		-- l'objet
		DEFAULT NEXTVAL ('seq_rr'),
	nom		TEXT,		-- le nom de l'objet (premier composant)
	iddom		INT,		-- domaine de l'objet

	mac		MACADDR UNIQUE,	-- adresse MAC associe au nom, ou NULL
	iddhcpprofil	INT,		-- identifiant du profil DHCP ou NULL

	idhinfo		INT DEFAULT 0,	-- index dans la table hinfo
	commentaire	TEXT,		-- un champ "commentaire" en fait
	respnom		TEXT,		-- nom du responsable
	respmel		TEXT,		-- adresse du responsable

	idcor		INT,		-- auteur de la dernire modification
	date		TIMESTAMP (0) WITHOUT TIME ZONE	-- date dernire modif.
			    DEFAULT CURRENT_TIMESTAMP,

	FOREIGN KEY (idcor)        REFERENCES corresp    (idcor),
	FOREIGN KEY (iddom)        REFERENCES domaine    (iddom),
	FOREIGN KEY (iddhcpprofil) REFERENCES dhcpprofil (iddhcpprofil),
	FOREIGN KEY (idhinfo)      REFERENCES hinfo      (idhinfo),
	UNIQUE (nom, iddom),
	PRIMARY KEY (idrr)
    ) ;

    CREATE TABLE rr_ip (
	idrr		INT,		-- l'objet
	adr		INET,		-- adresse IP (v4 ou v6)

	FOREIGN KEY (idrr) REFERENCES rr (idrr),
	PRIMARY KEY (idrr, adr)
    ) ;

    CREATE TABLE rr_cname (
	idrr		INT,		-- l'objet
	cname		INT,		-- l'objet point

	FOREIGN KEY (idrr)  REFERENCES rr (idrr),
	FOREIGN KEY (cname) REFERENCES rr (idrr),
	PRIMARY KEY (idrr, cname)
    ) ;

    CREATE TABLE rr_mx (
	idrr		INT,		-- l'objet
	priorite	INT,		-- priorite
	mx		INT,		-- objet point par le mx

	FOREIGN KEY (idrr) REFERENCES rr (idrr),
	FOREIGN KEY (mx)   REFERENCES rr (idrr),
	PRIMARY KEY (idrr, mx)
    ) ;

    -- les rles "web"
    CREATE TABLE role_web (
	idrr		INT,		-- id du "serveur web"

	FOREIGN KEY (idrr) REFERENCES rr (idrr),
	PRIMARY KEY (idrr)
    ) ;

    -- les rles "mail"
    CREATE TABLE role_mail (
	idrr		INT,		-- id de "l'adresse de messagerie"
	heberg		INT,		-- id du rr de l'hbergeur des mboxes

	FOREIGN KEY (idrr)   REFERENCES rr (idrr),
	FOREIGN KEY (heberg) REFERENCES rr (idrr),
	PRIMARY KEY (idrr)
    ) ;

    -- table des groupes ayant droit de grer des boites aux lettres
    -- de "l'adresse de messagerie"
    CREATE TABLE dr_mbox (
	idgrp		INT,		-- id du groupe
	idmail		INT,		-- id de "l'adresse de messagerie"

	FOREIGN KEY (idgrp)  REFERENCES groupe (idgrp),
	FOREIGN KEY (idmail) REFERENCES role_mail (idrr),
	PRIMARY KEY (idgrp, idmail)
    ) ;

    -- table des relais de messagerie pour les adresses d'un domaine
    CREATE TABLE relais_dom (
	iddom		INT,		-- id du domaine
	priorite	INT,		-- priorit du MX  gnrer
	mx		INT,		-- id du rr du relais pour ce domaine

	FOREIGN KEY (iddom) REFERENCES domaine (iddom),
	FOREIGN KEY (mx)    REFERENCES rr      (idrr),
	PRIMARY KEY (iddom, mx)
    ) ;


    -- la gnration des zones DNS

    CREATE SEQUENCE seq_zone START 1 ;
    CREATE TABLE zone (
	idzone		INT		-- l'id de la zone
		DEFAULT NEXTVAL ('seq_zone'),
	domaine		TEXT,		-- le domaine  gnrer
	version		INT,		-- numro de version dans la zone
	prologue	TEXT,		-- prologue de la zone (trou %VERSION%)
	rrsup		TEXT,		-- ajout  chaque gnration de nom
	generer		INT,		-- modifie depuis dernire gnration

	UNIQUE (domaine),
	PRIMARY KEY (idzone)
    ) ;

    CREATE TABLE zone_normale (
	selection	TEXT		-- critre de slection des noms
    ) INHERITS (zone) ;

    CREATE TABLE zone_reverse4 (
	selection	CIDR		-- critre de slection des adresses
    ) INHERITS (zone) ;

    CREATE TABLE zone_reverse6 (
	selection	CIDR		-- critre de slection des adresses
    ) INHERITS (zone) ;

    -- une table  une seule ligne pour indiquer s'il faut regnrer dhcpd.conf

    CREATE TABLE dhcp (
	generer INTEGER			-- 1 s'il faut regnerer la config
    ) ;

    INSERT INTO dhcp (generer) VALUES (0) ;

    -- les paramtres de configuration de la base
    CREATE TABLE config (
	clef		TEXT,		-- la clef de configuration
	valeur		TEXT,		-- valeur de la clef

	PRIMARY KEY (clef)
    ) ;


    -- les entres dans le log
    CREATE TABLE log (
	date		TIMESTAMP (0) WITHOUT TIME ZONE
				    DEFAULT CURRENT_TIMESTAMP
				    NOT NULL,
	subsys		TEXT NOT NULL,	-- sous-systme ("dns" ici)
	event		TEXT NOT NULL,	-- ajoutmachine, suppralias, etc.
	login		TEXT,		-- du correspondant
	ip		INET,		-- du correspondant
	msg		TEXT		-- message en clair
    ) ;

    -- fonctions

    -- valide un intervalle DHCP (min-max) par rapport aux droits du groupe
    -- $1 : idgrp
    -- $2 : dhcp min
    -- $3 : dhcp max
    CREATE OR REPLACE FUNCTION valide_dhcprange_grp (INTEGER, INET, INET)
		    RETURNS BOOLEAN AS '
	set min {}
	foreach o [split $2 "."] {
	    lappend min [format "%02x" $o]
	}
	set min [join $min ""]
	set min [expr 0x$min]
	set ipbin [expr 0x$min]

	set max {}
	foreach o [split $3 "."] {
	    lappend max [format "%02x" $o]
	}
	set max [join $max ""]
	set max [expr 0x$max]

	set r t
	for {set ipbin $min} {$ipbin <= $max} {incr ipbin} {
	    # Preparer la nouvelle adresse IP
	    set ip {}
	    set o $ipbin
	    for {set i 0} {$i < 4} {incr i} {
		set ip [linsert $ip 0 [expr $o & 0xff]]
		set o [expr $o >> 8]
	    }
	    set ip [join $ip "."]

	    # Tester la validite
	    spi_exec "SELECT valide_ip_grp (''$ip'', $1) AS v"

	    if {! [string equal $v "t"]} then {
		set r f
		break
	    }
	}
	return $r
	' LANGUAGE pltcl ;

EOF

##############################################################################
# Les droits pour les administrateurs de la base
##############################################################################

for root in $ROOT
do
    psql -q $BASE <<EOF
	GRANT ALL
	    ON 
		seq_domaine, domaine,
		seq_groupe, groupe, seq_corresp, corresp,
		seq_reseau, reseau, dr_reseau,
		seq_etablissement, etablissement,
		seq_communaute, communaute,
		dr_dom, dr_ip,
		seq_dhcprange, dhcprange,
		seq_dhcpprofil, dhcpprofil, dr_dhcpprofil,
		seq_rr, rr,
		rr_ip, rr_cname, rr_mx,
		seq_hinfo, hinfo,
		role_web, role_mail, dr_mbox, relais_dom,
		seq_zone, zone, zone_normale, zone_reverse4, zone_reverse6,
		dhcp,
		config, log
	    TO $root ;
EOF
done

##############################################################################
# Les droits pour l'interface Web (utilisateur nobody)
##############################################################################

for nobody in $NOBODY
do
    psql -q $BASE <<EOF
	GRANT SELECT
	    ON
		seq_domaine, domaine,
		seq_groupe, groupe, seq_corresp, corresp,
		seq_reseau, reseau, dr_reseau,
		seq_etablissement, etablissement,
		seq_communaute, communaute,
		dr_dom, dr_ip,
		seq_dhcprange, dhcprange,
		seq_dhcpprofil, dhcpprofil, dr_dhcpprofil,
		seq_rr, rr,
		rr_ip, rr_cname, rr_mx,
		seq_hinfo, hinfo,
		role_web, role_mail, dr_mbox, relais_dom,
		seq_zone, zone, zone_normale, zone_reverse4, zone_reverse6,
		dhcp,
		config, log
	    TO $nobody ;
	GRANT INSERT
	    ON
		domaine,
		groupe, corresp,
		reseau, dr_reseau,
		etablissement,
		communaute,
		dr_dom, dr_ip,
		dhcprange,
		dhcpprofil, dr_dhcpprofil,
		rr,
		rr_ip, rr_cname, rr_mx,
		hinfo,
		role_web, role_mail, dr_mbox, relais_dom,
		zone, zone_normale, zone_reverse4, zone_reverse6,
		dhcp,
		config, log
	    TO $nobody ;
	GRANT UPDATE
	    ON
		seq_domaine, domaine,
		seq_groupe, groupe, seq_corresp, corresp,
		seq_reseau, reseau, dr_reseau,
		seq_etablissement, etablissement,
		seq_communaute, communaute,
		dr_dom, dr_ip,
		seq_dhcprange, dhcprange,
		seq_dhcpprofil, dhcpprofil, dr_dhcpprofil,
		seq_rr, rr,
		rr_ip, rr_cname, rr_mx,
		seq_hinfo, hinfo,
		role_web, role_mail, dr_mbox, relais_dom,
		seq_zone, zone, zone_normale, zone_reverse4, zone_reverse6,
		dhcp,
		config, log
	    TO $nobody ;
	GRANT DELETE
	    ON
		domaine,
		corresp,
		reseau, dr_reseau,
		etablissement,
		communaute,
		dr_dom, dr_ip,
		dhcprange,
		dhcpprofil, dr_dhcpprofil,
		rr,
		rr_ip, rr_cname, rr_mx,
		hinfo,
		role_web, role_mail, dr_mbox, relais_dom,
		zone, zone_normale, zone_reverse4, zone_reverse6,
		dhcp,
		config, log
	    TO $nobody ;
EOF
done
