[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3-clients-linux/home/netlogon/clients-linux/.defaut/ -> logon (source)

   1  #! /bin/bash
   2  
   3  # NE PAS ÉDITER CE FICHIER !!!
   4  
   5  
   6  # Voici les appels qui ont un sens pour ce script :
   7  #   logon xxx yyy zzz
   8  #
   9  # Avec :
  10  #   - xxx = "initialisation" ou "ouverture" ou "fermeture"
  11  #   - yyy = "true" ou "false" pour indiquer s'il doit y avoir tentative
  12  #           de mise à jour avoir le script distant.
  13  #   - zzz = "true" ou "false" pour indiquer si le script s'exécute lors d'une
  14  #           d'une phase d'initialisation qui correspond au démarrage du
  15  #           système (true) ou non (false).
  16  
  17  
  18  
  19  # Le plus tôt possible dans le script, on procède aux redirections 
  20  # de stdout et de stderr.
  21  PHASE="$1" 
  22  
  23  REP_SE3_LOCAL="/etc/se3"
  24  REP_LOG_LOCAL="$REP_SE3_LOCAL/log"
  25  
  26  # En fonction de l'argument PHASE, on redirige différemment
  27  # la sortie standard et la sortie des erreurs du script.
  28  case "$PHASE" in
  29  
  30      "initialisation")
  31      
  32          # On cherche d'abord à récupérer le nom absolu du script exécuté.
  33          if echo "$0" | grep -q '^/'; then
  34              # L'appel du script s'est fait via son nom absolu.
  35              nom_absolu_script="$0"
  36          else
  37              rep=$(dirname "$0")
  38              nom=$(basename "$0")
  39              nom_absolu_script=$(cd "$rep"; pwd)"/$nom"
  40          fi
  41  
  42          # Ici on fait appel à un grep classique car aucune fonction
  43          # n'est encore définie à ce stade du script. Mais ce n'est
  44          # pas très grave car le motif ici est une chaîne de caractères
  45          # sans surprise.
  46          if echo "$nom_absolu_script" | grep -q -- "^$REP_SE3_LOCAL"; then
  47              # Le script exécuté se trouve dans le répertoire local.
  48              exec 1> "$REP_LOG_LOCAL/1.initialisation.log" 2>&1
  49          else
  50              # Sinon, c'est la version distante qui est exécutée
  51              # et il vaut mieux rediriger la sortie dans un autre
  52              # fichier, sans quoi le script distant va réécrire
  53              # par dessus le log du script local.
  54              exec 1> "$REP_LOG_LOCAL/1.initialisation_distant.log" 2>&1
  55          fi
  56          ;;
  57  
  58      "ouverture")
  59          exec 1> "$REP_LOG_LOCAL/2.ouverture.log" 2>&1
  60          ;;
  61  
  62      "fermeture")
  63          exec 1> "$REP_LOG_LOCAL/3.fermeture.log" 2>&1
  64          ;;
  65          
  66      *)
  67          # L'argument PHASE est incorrect, on arrête tout.
  68          exit 1
  69          ;;
  70  
  71  esac
  72  
  73  unset -v nom_absolu_script rep nom
  74  
  75  
  76  
  77  
  78  
  79  
  80  
  81  ### LOGON_PERSO ###
  82  
  83  
  84  
  85  
  86  
  87  
  88  ### LOGON_PARAM_FOND_ECRAN ###
  89  
  90  
  91  
  92  
  93  
  94  
  95  ##############################################################
  96  ##############################################################
  97  ###                                                        ###
  98  ### On passe à la définition de quelques fonctions utiles. ###
  99  ###                                                        ###
 100  ##############################################################
 101  ##############################################################
 102  
 103  
 104  
 105  # Fonction qui affiche la date du moment.
 106  function afficher_date ()
 107  {
 108      LC_ALL="$LOCALE_FRANCAISE" date '+%Y/%m/%d %Hh%Mmn%Ss (%A %d %b)'
 109  }
 110  
 111  
 112  
 113  # Fonction pour afficher des messages.
 114  function afficher ()
 115  {
 116      # On insère la date au niveau de chaque affichage.
 117      echo "[$(afficher_date)] $@" # | fmt -w 65
 118  }
 119  
 120  
 121  
 122  # Cette fonction prend une chaîne en argument et teste si
 123  # le nom en argument correspond à un login d'utilisateur local
 124  # (c'est-à-dire qui se trouve dans /etc/passwd). Si c'est 
 125  # le cas la fonction s'exécute correctement en renvoyant 0,
 126  # sinon elle renvoie 1.
 127  function est_utilisateur_local ()
 128  {
 129      if cat "/etc/passwd" | grep_debut_verbatim "$1:"; then
 130          return 0
 131      else
 132          return 1
 133      fi
 134  }
 135  
 136  
 137  
 138  # Donne la liste des répertoires qui sont point de montage
 139  # sur le système. Attention, avec cette sortie, les caractères
 140  # un peu spéciaux dans les noms sont exprimés sous la forme
 141  # \NNN avec NNN le numéro ASCII du caractère sous la forme
 142  # octale.
 143  function donner_liste_montages ()
 144  {
 145      cat "/proc/mounts" | cut -d ' ' -f 2
 146  }
 147  
 148  
 149  
 150  # Fonction qui permet de savoir si un répertoire, avec son chemin absolu,
 151  # est bien un point de montage. Si c'est le cas la fonction s'exécute
 152  # correctement en renvoyant 0 sinon elle renvoie 1.
 153  # Le chemin absolu ne doit pas avoir de « / » à la fin.
 154  # Par ailleurs cette commande ne fonctionnera que pour des noms de
 155  # répertoires sans espace et sans caractère « spécial » au yeux du
 156  # fichier /proc/mounts (par exemple « \ » est un caractère spécial,
 157  # qui est représenté par \134 dans le fichier /proc/mounts sachant
 158  # que 134 est le numéro ASCII du caractère « \ »).
 159  # Mais en vérité je ne saurais donner une définition précise de ce qui
 160  # est considéré comme caractère « spécial » dans ce fichier.
 161  # Mais ce n'est pas grave car cette fonction devra être appelée avec 
 162  # en argument un nom de répertoire sans caractère « exotique »,
 163  # ça fait partie du contrat. Par exemple, la classe de caractères 
 164  # [-_a-z0-9] est constitué de caractères non spéciaux, il faudra
 165  # se limiter à cette classe.
 166  #
 167  # Remarque : la commande mountpoint aurait pu sembler plus naturelle
 168  # pour remplir cette tâche. Mais le souci, c'est que :
 169  #   1. Si c'est un montage réseau et si le serveur est inaccessible
 170  #      alors la commande peut durer un certain temps.
 171  #   2. On pourrait ajouter un timeout, mais dans ce cas si la commande
 172  #      dépasse ce timeout (parce que le serveur est inaccessible), la
 173  #      valeur de retour est autre que 0 et cela signifie que le
 174  #      répertoire n'est pas un point de montage alors que c'est
 175  #      en fait le cas.
 176  function est_point_montage ()
 177  {
 178      # $1 est le chemin absolu du répertoire.
 179      if donner_liste_montages | grep_debut_fin_verbatim "$1"; then
 180          return 0
 181      else
 182          return 1
 183      fi
 184  }
 185  
 186  
 187  
 188  # Fonction qui supprime le répertoire de montage donné
 189  # en argument sous la forme d'un chemin absolu.
 190  # Si le répertoire n'existe pas alors la fonction ne fera
 191  # rien, et ne provoquera pas d'erreur.
 192  function nettoyer_un_rep_montage ()
 193  {
 194      local f
 195      local ff
 196      f="$1"
 197      
 198      shopt -s dotglob
 199      
 200      for ff in "$f/"*; do
 201          [ "$ff" = "$f/*" ] && continue
 202          # Si c'est un point de montage (et donc aussi un répertoire),
 203          # il faut d'abord procéder au démontage.
 204          if est_point_montage "$ff"; then
 205              umount "$ff" && rm -rf --one-file-system "$ff"
 206          else
 207              # Dans tous les autres cas, on peut supprimer directement.
 208              rm -rf --one-file-system "$ff"
 209          fi        
 210      done
 211      
 212      # On peut ensuite effacer "$f" qui doit être vide en principe.
 213      rm -rf --one-file-system "$f"
 214      
 215      shopt -u dotglob
 216      
 217  }
 218  
 219  
 220  
 221  # Fonction qui démonte tous les répertoires (qui se trouvent dans REP_MONTAGE)
 222  # de partages des utilisateurs non connectés au système, sans toucher 
 223  # à REP_NETLOGON.
 224  function nettoyer_rep_montage ()
 225  {
 226      local f
 227      shopt -s dotglob
 228  
 229      for f in "$REP_MONTAGE/_"*; do
 230          # On itère sur tous les fichiers de la forme "$REP_MONTAGE/_xxx".
 231  
 232          # On passe à l'itération suivante si f est égal à REP_NETLOGON
 233          # (aucune chance à cause du caractère underscore mais on ne sait
 234          # jamais) ou bien si f ne correspond à aucun fichier ce qui est
 235          # possible si le * n'attrape rien, ou bien si ce n'est pas un
 236          # répertoire.
 237          [ "$f" = "$REP_NETLOGON" ] && continue
 238          [ "$f" = "$REP_MONTAGE/*" ] && continue
 239          [ ! -d "$f" ] && continue
 240          
 241          local n
 242          local nom
 243          n=$(basename "$f") # "$n" sera de la forme "_xxx"
 244          nom="${n#_}" # "$nom" sera de la forme "xxx"
 245          
 246          # Si l'utilisateur est connecté, on passe.
 247          est_connecte "$nom" && continue
 248          
 249          # Enfin on efface le contenu du répertoire "$f".
 250          nettoyer_un_rep_montage "$f"
 251          
 252      done
 253      
 254      shopt -u dotglob
 255  }
 256  
 257  
 258  
 259  # Fonction qui vide REP_TMP_LOCAL de son contenu.
 260  function nettoyer_rep_tmp_local ()
 261  {
 262      local f
 263      shopt -s dotglob
 264      for f in "$REP_TMP_LOCAL/"*; do
 265          [ "$f" = "$REP_TMP_LOCAL/*" ] && continue
 266          rm -rf "$f"
 267      done
 268      shopt -u dotglob
 269  }
 270  
 271  
 272  
 273  # Fonction qui efface les homes des utilisateurs non locaux et qui
 274  # ne sont pas connectés au système.
 275  function nettoyer_rep_home ()
 276  {
 277      # On efface tous les home des utilisateurs non locaux (non connectés).
 278      local f
 279      shopt -s dotglob
 280      for f in "/home/"*; do
 281          [ "$f" = "/home/*" ] && continue
 282          nom=$(basename "$f")
 283          if est_utilisateur_local "$nom"; then
 284              # Là, on garde le répertoire car c'est un utilisateur local.
 285              true
 286          else
 287              # Sinon on supprime le home si celui-ci ne correspond pas
 288              # à un utilisateur déjà connecté. Par ailleurs, on évite
 289              # la suppression de "lost+found" qui est présent quand le
 290              # répertoire /home est monté sur une partition séparée. 
 291              if [ "$nom" != "lost+found" ] && ! est_connecte "$nom"; then
 292                  # L'option --one-file-system est capitale, car sans cette
 293                  # option, si un lien symbolique se trouve dans le « /home »
 294                  # et s'il pointe vers un partage alors le contenu du
 295                  # partage est tout simplement effacé.
 296                  rm -fr --one-file-system "$f"
 297              fi
 298          fi    
 299      done    
 300      shopt -u dotglob
 301  }
 302  
 303  
 304  
 305  # Cette fonction va mettre à jour le profil local afin de
 306  # copier le profil distant dans REP_SKEL_LOCAL. A priori,
 307  # cette fonction sera appelée si et seulement si le profil 
 308  # distant a changé de version.
 309  function mettre_a_jour_profil ()
 310  {
 311      local version version_local exit_code
 312      version=$(cat "$VERSION_SKEL")
 313      version_local=$(cat "$VERSION_SKEL_LOCAL")
 314      afficher "Mise à jour du profil par défaut local." \
 315               "Le contenu du fichier .VERSION du profil distant est" \
 316               "<citation> $version </citation>."
 317      if [ ! -d  "$REP_SKEL_LOCAL" ]; then
 318          mkdir -p "$REP_SKEL_LOCAL"
 319          chown "root:" "$REP_SKEL_LOCAL"
 320      fi 
 321  
 322      # On oublie cp qui, apparemment, peut planter quand il
 323      # fait des copies qui passent par le réseau (ce qui est
 324      # le cas ici). Et perso, j'ai constaté ce bug avec un
 325      # message du genre « cp: skipping file ... as it was 
 326      # replaced while being copied ». Ceci étant, je n'ai
 327      # pas réussi à reproduire le bug, alors je ne sais plus.
 328      #rm -fr --one-file-system "$REP_SKEL_LOCAL"
 329      #cp -r "$REP_SKEL" "$REP_SE3_LOCAL"
 330  
 331      # Pas de chose dans le genre « --modify-window=20 » car il 
 332      # vaut mieux que des copies en trop soient faites plutôt 
 333      # qu'il y ait certaines copies non faites.
 334      # L'option --bwlimit indique une limite de téléchargement
 335      # en KiloBytes/s. Ici on a 2048 KB/s soit 2 Mo/s.
 336      if rsync -rtxh --links --delete --bwlimit=2048 "$REP_SKEL" "$REP_SE3_LOCAL"
 337      then
 338          # La commande rsync s'est bien passée.
 339          exit_code=0
 340      else
 341          sleep 0.5
 342          # La commande rsync a planté, il faut remettre le fichier
 343          # .VERISON local dans son état initial.
 344          exit_code=1
 345          cat "$version_local" > "$VERSION_SKEL_LOCAL"
 346      fi
 347  
 348      chown -R "root:" "$REP_SKEL_LOCAL"
 349      # On met des droits cohérents sur les fichiers et les répertoires.
 350      find "$REP_SKEL_LOCAL" -type f -exec chmod u=rw,g=rw,o='',u-s,g-s,o-t '{}' \;
 351      find "$REP_SKEL_LOCAL" -type d -exec chmod u=rwx,g=rwx,o='',u-s,g-s,o-t '{}' \;
 352      sync
 353  
 354      return "$exit_code"
 355  }
 356  
 357  
 358  
 359  # Met à jour le script de logon local. A priori cette fonction sera
 360  # appelée si et seulement le script de logon local est différent (au
 361  # sens de la commande diff) de la version distante sur le serveur.
 362  function mettre_a_jour_logon ()
 363  {
 364      if [ ! -d  "$REP_BIN_LOCAL" ]; then
 365          mkdir -p "$REP_BIN_LOCAL"
 366          chown "root:" "$REP_BIN_LOCAL"
 367          chmod "700" "$REP_BIN_LOCAL"
 368      fi
 369  
 370      # On met à jour le script de logon en lançant une tâche en arrière plan.
 371      afficher "Le déroulement de la mise à jour du script de logon sera écrit" \
 372               "dans le fichier \"0.maj_logon.log\"."
 373      {
 374          afficher_date
 375          
 376          # On attend que le script local ne soit lu par aucun processus
 377          # afin qu'il soit disponible pour être réécrit.
 378          local compteur
 379          compteur="1"
 380          while fuser "$LOGON_SCRIPT_LOCAL" >/dev/null 2>&1; do 
 381              sleep 0.5
 382              if [ "$compteur" -ge "40" ]; then
 383                  # Au bout de 40 x 0.5 = 20 secondes on abandonne la mise à jour.
 384                  afficher "Mise à jour du script de logon local abandonnée" \
 385                           "car celui-ci semble toujours lu par un processus" \
 386                           "alors que le temps d'attente maximum est dépassé."
 387                  return 1
 388              fi
 389              compteur=$((compteur+1))
 390          done
 391          
 392          # On crée une sauvegarde de la version locale du script de logon.
 393          if cp -a "$LOGON_SCRIPT_LOCAL" "$LOGON_SCRIPT_LOCAL.SAVE" && \
 394             diff -q "$LOGON_SCRIPT_LOCAL" "$LOGON_SCRIPT_LOCAL.SAVE" >/dev/null 2>&1
 395          then
 396              # On a une sauvegarde de la version locale qui est fiable.
 397              # On peut alors tenter la mise à jour du script de logon local.
 398              # Une dernière fois, on vérifie que le script local est
 399              # bien disponible, juste avant de le réécrire.
 400              if ! fuser "$LOGON_SCRIPT_LOCAL" >/dev/null 2>&1 && \
 401                 cp "$LOGON_SCRIPT" "$LOGON_SCRIPT_LOCAL" && \
 402                 diff -q "$LOGON_SCRIPT" "$LOGON_SCRIPT_LOCAL" >/dev/null 2>&1
 403              then
 404                  # La mise à jour a fonctionné.
 405                  chown "root:" "$LOGON_SCRIPT_LOCAL"
 406                  chmod "700" "$LOGON_SCRIPT_LOCAL"
 407                  afficher "Mise à jour du script de logon local réussie."
 408                  [ -e "$LOGON_SCRIPT_LOCAL.SAVE" ] && rm -f "$LOGON_SCRIPT_LOCAL.SAVE"
 409                  return 0
 410              else
 411                  # La mise à jour n'a pas fonctionné, il faut alors
 412                  # restaurer la sauvegarde.
 413                  [ -e "$LOGON_SCRIPT_LOCAL" ] && rm -f "$LOGON_SCRIPT_LOCAL"
 414                  mv "$LOGON_SCRIPT_LOCAL.SAVE" "$LOGON_SCRIPT_LOCAL"
 415                  chown "root:" "$LOGON_SCRIPT_LOCAL"
 416                  chmod "700" "$LOGON_SCRIPT_LOCAL"
 417                  afficher "La mise à jour du script de logon local a échoué." \
 418                           "La version locale actuelle a été restaurée en attendant" \
 419                           "une prochaine tentative de mise à jour."
 420                  return 1
 421              fi            
 422          else
 423              # Si la création de la sauvegarde de la version locale a échoué
 424              # alors on supprime la sauvegarde si elle existe et on ne fait
 425              # plus rien.
 426              [ -e "$LOGON_SCRIPT_LOCAL.SAVE" ] && rm -f "$LOGON_SCRIPT_LOCAL.SAVE"
 427              afficher "Erreur lors de sauvegarde de la version locale du" \
 428                       "script de logon. Pas de mise à jour de script."
 429              return 1
 430          fi
 431      } > "$REP_LOG_LOCAL/0.maj_logon.log" 2>&1 & 
 432      # Tout ça se fait en arrière plan pour que le script continue son exécution.
 433      # On ne sait pas vraiment à quel moment cette tâche en arrière
 434      # plan va se lancer donc il vaut mieux rediriger la sortie
 435      # standard et la sortie des erreurs vers un fichier à part.
 436  }
 437  
 438  
 439  
 440  # Cette fonction crée un lien symbolique "/le/lien_symb" qui pointe vers un 
 441  # répertoire "/le/rep" et fait de "user" le propriétaire de ce fichier lien
 442  # symbolique.
 443  # creer_lien_symb "/le/rep" "/le/lien_symb" "user"
 444  function creer_lien_symb () 
 445  {
 446      # $1 est le répertoire vers lequel pointe le lien.
 447      # $2 est le chemin absolu du fichier lien symbolique.
 448      # $3 est le propriétaire du fichier lien symbolique.
 449      ln -s "$1" "$2"
 450      # L'option permet de changer les propriétaires
 451      # sur le lien symbolique lui-même car par défaut
 452      # sinon c'est un changement sur la cible qui s'opère.
 453      chown --no-dereference "$3:" "$2"
 454  }
 455  
 456  
 457  
 458  # Cette fonction tente de monter REP_NETLOGON s'il ne l'est
 459  # pas déjà et renvoie 0 si ça marche, 1 sinon.
 460  function monter_netlogon ()
 461  {
 462      local n
 463      local c
 464      
 465      n=$(donner_liste_montages | grep -c -- "^$REP_NETLOGON$")
 466      c="1"
 467  
 468      # Si n >= 1, le montage est fait, mais ce n'est pas pour autant qu'il
 469      # est valide. J'ai déjà vu des cas comme ça. On va donc vérifier
 470      # que le script de logon distant (par exemple) est bien lisible.
 471      if [ "$n" -ge 1  ]; then
 472          if ! timeout "--signal=SIGTERM" 2s test -r "$LOGON_SCRIPT"; then
 473              # Le montage est incorrect car le fichier de logon distant
 474              # n'est pas accessible. Du coup, on démonte netlogon pour
 475              # repartir sur de nouvelles bases et retenter un montage
 476              # ci-dessous.
 477              while [ ! "$n" -eq 0 ]; do
 478                  # Pas de timeout nécessaire car en principe un umount est
 479                  # instantané quel que soit l'état du serveur de partages.
 480                  umount "$REP_NETLOGON"
 481                  sleep 0.25 # On ne sait jamais.
 482                  n=$(donner_liste_montages | grep -c -- "^$REP_NETLOGON$")
 483              done
 484          fi
 485      fi
 486  
 487      while [ ! "$n" -eq 1 ] && [ "$c" -le 4 ] ; do
 488          if [ "$n" -eq 0 ]; then
 489              timeout "--signal=SIGTERM" 2s \
 490                  mount -t cifs "$CHEMIN_PARTAGE_NETLOGON" "$REP_NETLOGON" -o ro,guest,"$OPTIONS_MOUNT_CIFS_BASE"
 491          else
 492              # différent de 1 et de 0, ça veut dire que n > 1.
 493              # Cas qui ne devrait pas se produire, mais sait-on jamais.
 494              # Ici il faut démonter une fois REP_NETLOGON.
 495              umount "$REP_NETLOGON"
 496          fi
 497          sleep 0.5
 498          n=$(donner_liste_montages | grep -c -- "^$REP_NETLOGON$")
 499          c=$((c+1))
 500      done
 501      
 502      if [ "$n" -eq 1 ]; then
 503          # Montage réussi.
 504          return 0
 505      else
 506          # Montage pas réussi
 507          return 1
 508      fi
 509  }
 510  
 511  
 512  
 513  # Cette fonction tente de monter un partage CIFS (comme par exemple
 514  # le partage « Classes » du Se3). Le premier paramètre est le chemin
 515  # du partage CIFS et le deuxième paramètre est le répertoire servant
 516  # de point de montage. Le troisième paramètre, s'il existe, permet
 517  # d'ajouter des options de montage en plus de celles par défaut.
 518  function monter_partage_cifs ()
 519  {
 520      # 10 secondes avant le timeout du montage, ça fait beaucoup
 521      # mais pour l'instant, le Se3 n'étant pas bien adapté aux
 522      # clients Linux (aux montages CIFS pour être plus précis), 
 523      # lors par exemple d'un montage d'un /home via CIFS,
 524      # le script connexion.sh sur le Se3 est exécuté avant que
 525      # le montage ne soit accepté (preexec dans smb.conf) et
 526      # il a tendance à durer un peu hélas.
 527      local options
 528      # Les options par défaut.
 529      options="$OPTIONS_MOUNT_CIFS_BASE"
 530      if [ -n "$3" ]; then
 531          # Des options supplémentaires sont spécifiées, 
 532          # on les ajoute à la liste.
 533          options="$3,$options"
 534      fi
 535      timeout "--signal=SIGTERM" 10s mount -t cifs "$1" "$2" -o "$options"
 536  }
 537  
 538  
 539  
 540  # Affiche une petite fenêtre signalant une erreur. 
 541  # Le premier argument correspond au titre de la fenêtre et
 542  # les suivants sont concaténés (avec un espace pour faire la jointure)
 543  # afin de former le message d'erreur contenu dans la fenêtre.
 544  function afficher_fenetre_erreur ()
 545  {
 546      local titre
 547      local message
 548  
 549      titre="$1"
 550      
 551      # On mange le premier argument.
 552      shift 1
 553      
 554      # Avec les arguments restants, on forme le message.
 555      local m
 556      for m in "$@"; do
 557          message="$message $m"
 558      done
 559      # On enlève l'espace au début.
 560      message="${message# }"
 561      
 562      # Attention d'appeler zenity avec une locale adaptée.
 563      LC_ALL="$LOCALE_FRANCAISE" zenity --error --title "$titre" --text "$message" 
 564  }
 565  
 566  
 567  
 568  # Fonction qui retourne la valeur 0 si le login donné en deuxième argument
 569  # appartient au groupe donné en premier argument et retourne la valeur 1 sinon.
 570  # Exemples d'appels : 
 571  #       appartient_au_groupe Eleves hugov
 572  #       appartient_au groupe Profs hugov
 573  # La recherche est insensible à la casse.
 574  function appartient_au_groupe ()
 575  {
 576      # $1 = le groupe
 577      # $2 = le login
 578      local n
 579      # On cherche à afficher la liste des DN des entrées de l'OU Groups
 580      # qui possèdent un attribut memberUid égal à "$2".
 581      n=$(timeout "--signal=SIGTERM" 4s ldapsearch -xLLL -h "$SE3" -b "cn=$1,ou=Groups,$BASE_DN" "(memberUid=$2)" "dn" | wc -l)
 582      if [ "$n" -eq "0" ]; then
 583          # n = 0 signifie que la recherche n'a donné aucun résultat et
 584          # donc le compte n'appartient pas au groupe.
 585          return 1
 586      else
 587          # Sinon, la recherche a donné un résultat et donc le compte
 588          # appartient au groupe.
 589          return 0
 590      fi
 591  }
 592  
 593  
 594  
 595  # Fonction qui retourne la valeur 0 si le nom de machine donné en 
 596  # deuxième argument appartient au nom de parc donné en premier argument 
 597  # et retourne la valeur 1 sinon.
 598  # Exemple d'appel : 
 599  #       appartient_au_parc CDI S121-PC04
 600  # La recherche est insensible à la casse.
 601  function appartient_au_parc ()
 602  {
 603      # $1 = le parc
 604      # $2 = le nom de machine
 605      local n
 606      n=$(timeout "--signal=SIGTERM" 4s ldapsearch -xLLL -h "$SE3" -b "cn=$1,ou=Parcs,$BASE_DN" "(member=cn=$2,ou=Computers,$BASE_DN)" "dn" | wc -l)
 607      if [ "$n" -eq "0" ]; then
 608          # n = 0 signifie que la recherche n'a donné aucun résultat et
 609          # donc la machine n'appartient pas au parc.
 610          return 1
 611      else
 612          # Sinon, la recherche a donné un résultat et donc la machine
 613          # appartient au parc.
 614          return 0
 615      fi
 616  }
 617  
 618  
 619  
 620  # Cette fonction affiche la liste des groupes qui contiennent le
 621  # compte dont le login est donné en paramètre. Le format d'affichage
 622  # est de la forme « une ligne par nom de groupe ». Un exemple
 623  # typique d'appel de la fonction :
 624  #       liste_groupes=$(afficher_liste_groupes "hugov")
 625  function afficher_liste_groupes ()
 626  {
 627      # $1 = le login
 628      # Recherche dans l'OU Groups de tous les dn des entrées qui
 629      # possèdent un attribut memberUid égal "$1".
 630      timeout "--signal=SIGTERM" 4s ldapsearch -xLLL -h "$SE3" -b "ou=Groups,$BASE_DN" "(memberUid=$1)" "dn" \
 631          | awk 'BEGIN { RS="\0" } { gsub("\n ", ""); print $0 }' \
 632          | awk '$0 ~ /^dn: / { print $2 }' \
 633          | sed -r 's/^cn=([^,]+),.*$/\1/g'
 634          # Avec le premier awk, on prend la sortie de la recherche dans son 
 635          # ensemble (RS="\0") et on remplace "\n " par "" car, dans une
 636          # recherche LDAP, une ligne trop longue est cassée et la suite de 
 637          # la ligne est indentée sur un espace. Avec cette substitution,
 638          # les lignes trop longues ne sont pas cassées.
 639          #
 640          # Avec le second awk, étant donné qu'on a des lignes soit vides,
 641          # soit de la forme "dn: <le-dn-du-groupe>". On affiche alors seulement
 642          # les lignes non vides et on affiche uniquement la partie située
 643          # après l'espace.
 644          #
 645          # Avec sed, on récupère uniquement le nom du groupe.
 646  }
 647  
 648  
 649  
 650  # Cette fonction affiche la liste des parcs qui contiennent la
 651  # machine dont le nom est donné en paramètre. Le format d'affichage
 652  # est de la forme « une ligne par nom de machine ». Un exemple
 653  # typique d'appel de la fonction :
 654  #       liste_parcs=$(afficher_liste_parcs "S121-HP-04")
 655  function afficher_liste_parcs ()
 656  {
 657      # $1 = le nom de machine
 658      # Recherche dans l'OU Parcs de tous les dn des entrées qui
 659      # possèdent un attribut member égal "cn=$1,ou=Computers,$BASE_DN".
 660      timeout "--signal=SIGTERM" 4s ldapsearch -xLLL -h "$SE3" -b "ou=Parcs,$BASE_DN" "(member=cn=$1,ou=Computers,$BASE_DN)" "dn" \
 661          | awk 'BEGIN { RS="\0" } { gsub("\n ", ""); print $0 }' \
 662          | awk '$0 ~ /^dn: / { print $2 }' \
 663          | sed -r 's/^cn=([^,]+),.*$/\1/g'
 664          # Avec le premier awk, on prend la sortie de la recherche dans son 
 665          # ensemble (RS="\0") et on remplace "\n " par "" car, dans une
 666          # recherche LDAP, une ligne trop longue est cassée et la suite de 
 667          # la ligne est indentée sur un espace. Avec cette substitution,
 668          # les lignes trop longues ne sont pas cassées.
 669          #
 670          # Avec le second awk, étant donné qu'on a des lignes soit vides,
 671          # soit de la forme "dn: <le-dn-d-un-parc>". On affiche alors seulement
 672          # les lignes non vides et on affiche uniquement la partie située
 673          # après l'espace.
 674          #
 675          # Avec sed, on récupère uniquement le nom du parc.
 676  }
 677  
 678  
 679  
 680  # Une liste (de la forme un item par ligne) étant donnée, la fonction
 681  # renvoie 0 si le paramètre est dedans, 1 sinon. La recherche est
 682  # sensible à la casse, c'est-à-dire que 
 683  # « est_dans_liste "$liste" "un_item" », et 
 684  # « est_dans_liste "$liste" "UN_ITEM" » ne renverront pas
 685  # forcément la même valeur.
 686  function est_dans_liste ()
 687  {
 688      # $1 = la liste
 689      # $2 = le nom à tester
 690      if echo "$1" | grep_debut_fin_verbatim "$2"; then
 691          return 0
 692      else
 693          return 1
 694      fi
 695  }
 696  
 697  
 698  
 699  # Fonction qui se charge de lancer les exécutables « unefois ».
 700  function lancer_unefois ()
 701  {
 702      if test -e "$REP_UNEFOIS/PAUSE"; then
 703          # Si le fichier PAUSE est présent alors on ne fait rien.
 704          # et on s'arrête.
 705          return 0
 706      fi
 707      
 708      if test -e "$REP_UNEFOIS/BLACKOUT"; then
 709          # Si le fichier BLACKOUT est présent alors on supprime
 710          # tous les exécutables dans REP_UNEFOIS_LOCAL.
 711          local f
 712          for f in "$REP_UNEFOIS_LOCAL/"*; do
 713              [ "$f" = "$REP_UNEFOIS_LOCAL/*" ] && continue
 714              rm -rf "$f"
 715          done
 716          # Et on arrête tout.
 717          return 0
 718      fi
 719  
 720      # Dans cette situation (pas de fichier PAUSE ni de fichier
 721      # BLACKOUT), il faut copier les « unefois » distants
 722      # dont le nom n'existe pas en local et les exécuter.
 723      
 724      local d
 725      local regex
 726      
 727      shopt -s dotglob
 728      for d in "$REP_UNEFOIS/"*; do
 729          [ "$d" = "$REP_UNEFOIS/*" ] && continue
 730          if [ -d "$d" ]; then
 731          
 732           parc="$(echo ${d##*/})" 
 733           if appartient_au_parc $parc $NOM_HOTE; then
 734          lancer_unefois_dans_repertoire "$d"
 735           fi
 736                 
 737              regex=$(basename "$d")
 738              if echo "$NOM_HOTE" | grep -Eiq -- "$regex"; then
 739                  lancer_unefois_dans_repertoire "$d"
 740              fi
 741          fi
 742      done
 743      shopt -u dotglob
 744  }
 745  
 746  
 747  
 748  # Fonction qui se charge de l'installation des pilotes d'imprimantes 
 749  function lancer_parc ()
 750  {
 751   for p in "$REP_LANCEPARC/"*; do
 752      [ "$p" = "$REP_LANCEPARC/*" ] && continue
 753      parc="$(echo ${p##*/})"
 754      echo "$p"
 755      echo "$parc"
 756      if [ "$parc" = "_TousLesPostes" ]; then 
 757          for script in $p/*.sh; do
 758              [ "$script" = "$p/*.sh" ] && continue
 759              echo "on lance $script"
 760              /bin/bash $script
 761          done
 762      fi
 763      if appartient_au_parc $parc $NOM_HOTE; then
 764  #         [ -e $REP_LANCEPARC/$parc.sh ] && $REP_LANCEPARC/$parc.sh
 765          for script in $p/*.sh; do
 766              [ "$script" = "$p/*.sh" ] && continue
 767              echo "on lance $script"
 768              /bin/bash $script
 769          done
 770      fi
 771     done
 772  }
 773  
 774  
 775  
 776  
 777  # Cette fonction lance tous les scripts unefois situés dans le
 778  # répertoire dont le chemin absolu doit être donné en paramètre
 779  # (sans / à la fin).
 780  function lancer_unefois_dans_repertoire ()
 781  {
 782  
 783      # $1 = le chemin absolu du répertoire.
 784  
 785      local nom_local
 786      local nom_distant
 787      
 788      for nom_distant in "$1/"*".unefois"; do
 789      
 790          [ "$nom_distant" = "$1/*.unefois" ] && continue
 791          [ ! -f "$nom_distant" ] && continue
 792          
 793          nom_local="$REP_UNEFOIS_LOCAL/"$(basename "$nom_distant")
 794          
 795          if ! test -e "$nom_local"; then
 796              # Si le « unefois » distant n'existe pas en local
 797              # alors on le copie en local et on le lance.
 798  
 799              # À ce stade, j'ai vu des plantages de la commande cp du
 800              # genre « cp: ignore le fichier « /xxx/yyy » car il a été 
 801              # remplacé durant la copie », alors que ce n'est pas le
 802              # cas. Ça semble être plus ou moins un bug...
 803              if cp "$nom_distant" "$nom_local" && \
 804                 diff -q "$nom_distant" "$nom_local" >/dev/null 2>&1
 805              then
 806                  chmod u+x "$nom_local"
 807                  # L'exécutable « unefois » est lancé en arrière plan.
 808                  "$nom_local" > "$nom_local.log" 2>&1 &
 809              else
 810                  # Si la copie en local n'a pas bien fonctionné,
 811                  # on ne lance pas l'exécutable et on supprime
 812                  # sa version locale si elle existe afin qu'il y
 813                  # ait tentative d'exécution la prochaine fois.
 814                  test -e "$nom_local" && rm -rf "$nom_local"
 815                  afficher "Échec de la copie de $nom_distant en local." \
 816                           "L'exécutable ne sera pas lancé. Il y aura" \
 817                           "tentative au prochain démarrage du système."
 818              fi
 819          fi
 820      done
 821  }
 822  
 823  
 824  
 825  # Fonction qui permet d'activer le pavé numérique. Cette fonction
 826  # s'exécute à la fin du script et peut prendre un argument optionnel
 827  # qui est le délai d'attente entre la fin du script et le lancement
 828  # de l'activation du pavé numérique. Si l'argument est absent, par
 829  # défaut le délai est de 1 seconde.
 830  function activer_pave_numerique ()
 831  {
 832      local commande
 833  
 834      if [ "$ARCHITECTURE" = "x86_64" ]; then
 835          # On est sur du 64 bits.
 836          commande="$REP_BIN_LOCAL/activer_pave_numerique_x86_64"
 837      else
 838          # Sinon, on est a priori sur du 32 bits.
 839          commande="$REP_BIN_LOCAL/activer_pave_numerique_i386"
 840      fi
 841      
 842      local delai
 843      
 844      if echo "$1" | grep -Eq -- '^[0-9]+$'; then
 845          delai="$1"
 846      else
 847          delai="1"
 848      fi
 849      
 850      executer_a_la_fin "$delai" "$commande"
 851  }
 852  
 853  
 854  
 855  # Fonction qui renvoie 0 si l'argument correspond à un login
 856  # d'un compte connecté au système, et renvoie 1 sinon.
 857  function est_connecte ()
 858  {
 859  
 860      ### ---%<------%<------%<------%<------%<------%<------%<------%<---
 861      ### Sans doute depuis une mise à jour, ce problème ne semble plus
 862      ### être d'actualité.
 863      # Sur Precise, pour des raisons que j'ignore, la commande who ne
 864      # liste aucune session graphique ouverte. Du coup, je n'ai pas
 865      # trouvé mieux que de bricoler un truc basé sur la commande ps
 866      # avec la recherche de la chaîne unity. C'est bien dommage,
 867      # mais je n'ai pas trouvé mieux.
 868      ###if [ "$NOM_DE_CODE" = "precise" ]; then
 869      ###    if ps -u "$1" -U "$1" | awk '{ if (NR>0) print $4 }' | grep -q '^unity'; then
 870      ###        return 0
 871      ###    else
 872      ###        return 1
 873      ###    fi
 874      ###fi
 875      ### ---%<------%<------%<------%<------%<------%<------%<------%<---
 876      
 877      # Sinon, dans le cas général, on va utiliser la commande who.
 878      # $1 est une chaîne représentant un login.
 879      if who | cut -d ' ' -f 1 | grep_debut_fin_verbatim "$1"; then
 880          return 0
 881      else
 882          return 1
 883      fi
 884  }
 885  
 886  
 887  
 888  # Fonction qui affiche le nombre d'utilisateurs différents
 889  # sont sont connectés au système.
 890  function afficher_nombre_utilisateurs_connectes ()
 891  {
 892      ### ---%<------%<------%<------%<------%<------%<------%<------%<---
 893      ### Sans doute depuis une mise à jour, ce problème ne semble plus
 894      ### être d'actualité.
 895      # Pour les mêmes raisons que celles expliquées dans la fonction
 896      # est_connecte, dans le cas de la distribution Precise, je n'ai
 897      # rien trouvé de mieux que cet immonde bricolage avec ps.
 898      ###if [ "$NOM_DE_CODE" = "precise" ]; then
 899      ###    ps aux | awk '/ [u]nity/ { print $1, $11 }' | cut -d' ' -f'1' | sort | uniq | wc -l
 900      ###    return 0
 901      ###fi
 902      ### ---%<------%<------%<------%<------%<------%<------%<------%<---
 903      
 904      # Sinon, dans le cas général, on va utiliser la commande who.
 905      who | cut -d' ' -f'1' | sort | uniq | wc -l
 906  }
 907  
 908  
 909  
 910  # Fonction qui permet de monter le partage avec les droits de l'utilisateur
 911  # qui se connecte. Le premier argument est le chemin UNC du partage. Le
 912  # deuxième argument est le nom du répertoire qui sera créé dans
 913  # "$REP_MONTAGE_UTILISATEUR/" et qui sera le point de montage du partage.
 914  # Les arguments suivants correspondent aux chemins absolus des liens
 915  # symboliques qui seront créés et qui pointeront vers le point de
 916  # montage.
 917  # Le montage se fait via une authentification
 918  # sachant que c'est le fichier CREDENTIALS qui contient le login
 919  # et le mot de passe sous la forme : 
 920  # --%<----%<----%<----%<----%<----%<----%<--
 921  # username=toto
 922  # password=le-mot-de-passe
 923  # --%<----%<----%<----%<----%<----%<----%<--
 924  function monter_partage ()
 925  {
 926      # Si on n'est pas pendant la phase d'ouverture, on abandonne.
 927      [ "$PHASE" != "ouverture" ] && return 1
 928      
 929      local partage
 930      local nom_repertoire
 931      
 932      partage="$1"
 933      nom_repertoire="$2"
 934  
 935      if [ -z "$partage" ] || [ -z "$nom_repertoire" ]; then
 936          # Les arguments ne sont pas correctement renseignés.
 937          afficher_fenetre_erreur "Problème" \
 938              "Erreur lors de l'appel de la fonction \"monter_partage\". Au moins" \
 939              "un des deux arguments est vide."
 940          return 1
 941      fi
 942  
 943      if ! echo "$nom_repertoire" | grep -Eiq '^[-_a-z0-9]+$'; then
 944          # Le nom du répertoire futur point de montage comporte des
 945          # caractères illicites.
 946          afficher_fenetre_erreur "Problème" \
 947              "Erreur lors de l'appel de la fonction \"monter_partage\". Le" \
 948              "nom du répertoire de montage (le deuxième argument de la fonction)" \
 949              "contient des caractères illicites. Le nom de ce répertoire doit" \
 950              "être constitué uniquement des caractères a-z, A-Z, du tiret (-)" \
 951              "et du tiret-bas (_)."
 952          return 2
 953      fi
 954  
 955      local point_de_montage
 956      
 957      point_de_montage="$REP_MONTAGE_UTILISATEUR/$nom_repertoire"
 958      
 959      if [ -e "$point_de_montage" ]; then
 960          # Le répertoire de point de montage correspond à un nom
 961          # de fichier déjà existant.
 962          afficher_fenetre_erreur "Problème" \
 963              "Erreur lors de l'appel de la fonction \"monter_partage\". Le" \
 964              "répertoire de montage \"$nom_repertoire\" correspond à un nom" \
 965              "de fichier déjà existant."
 966          return 3
 967      fi
 968      
 969      mkdir "$point_de_montage"
 970      
 971      # Par défaut, la commande mount.cifs tente d'utiliser le port 445 d'abord
 972      # pour contacter le serveur. Mais dans ce cas la variable de substitution
 973      # %m utilisée dans les fichiers smb*.conf du serveur et qui est censée
 974      # être remplacée par le nom (netbios) du client est alors remplacée par
 975      # son adresse IP. Avec l'option « port=139 », la variable %m sera bien
 976      # remplacée par le nom (netbios) du client. En principe, l'option suivante
 977      # « netbiosname=... », qui indique le nom (netbios) du client à envoyer au
 978      # serveur, n'est pas nécessaire mais on la met quand même histoire 
 979      # d'enfoncer le clou encore un peu.
 980      monter_partage_cifs "$partage" "$point_de_montage" \
 981          "credentials=$CREDENTIALS,uid=$LOGIN,gid=lcs-users,port=139,netbiosname=$NOM_HOTE"
 982      if [ "$?" != "0" ]; then
 983          # Ici, il y a un problème réseau.
 984          afficher_fenetre_erreur "Problème" \
 985              "Erreur lors de l'appel de la fonction \"monter_partage\"." \
 986              "Impossible de monter le partage \"$partage\"."
 987          return 4
 988      fi
 989      
 990      # On « mange » les arguments $1 et $2.
 991      shift 2
 992      
 993      # S'il n'y a pas d'autre argument...
 994      if [ "$#" = "0" ]; then
 995          # ... alors pas de création de lien symbolique.
 996          return 0
 997      fi
 998      
 999      # Création des liens symboliques.
1000      local lien
1001      for lien in "$@"; do
1002          # Si le lien correspond à un fichier qui existe déjà, on passe.
1003          [ -e "$lien" ] && continue
1004          # Si le lien ne se trouve pas dans le home de l'utilisateur, on passe.
1005          ! echo "$lien" | grep_debut_verbatim "$REP_HOME/" && continue
1006          creer_lien_symb "$point_de_montage" "$lien" "$LOGIN"
1007      done   
1008  }
1009  
1010  
1011  
1012  # Fonction qui permet de créer des liens symboliques appartenant
1013  # à l'utilisateur qui se connecte. Le premier argument est le
1014  # fichier (au sens large, ça peut être un répertoire) vers lequel
1015  # pointent les liens et les arguments suivants (autant qu'on veut) 
1016  # sont les chemins absolus des liens symboliques à créer.
1017  # Si jamais la cible n'est pas un chemin absolu, alors la
1018  # fonction considère que le chemin absolu de la cible est 
1019  # "$REP_MONTAGE_UTILISATEUR/$cible".
1020  function creer_lien ()
1021  {
1022      # Si on n'est pas pendant la phase d'ouverture, on abandonne.
1023      [ "$PHASE" != "ouverture" ] && return 1
1024  
1025      local cible
1026      cible="$1"
1027  
1028      # On teste si la cible est un chemin absolu (ie commence par un /).
1029      if ! echo "$cible" | grep -q '^/'; then
1030          # La cible n'est pas un chemin absolu, on complète le chemin
1031          # pour en faire un chemin absolu.
1032          cible="$REP_MONTAGE_UTILISATEUR/$cible"
1033      fi
1034  
1035      # On « mange » l'argument $1.
1036      shift 1
1037      
1038      # S'il n'y a pas d'autre argument, c'est qu'il y a une erreur...
1039      if [ "$#" = "0" ]; then
1040          # ... alors pas de création de lien symbolique.
1041          return 1
1042      fi
1043      
1044      # Création des liens symboliques.
1045      local lien
1046      for lien in "$@"; do
1047          # Si le lien correspond à un fichier qui existe déjà, on passe.
1048          [ -e "$lien" ] && continue
1049          # Si le lien ne se trouve pas dans le home de l'utilisateur, on passe.
1050          ! echo "$lien" | grep_debut_verbatim "$REP_HOME/" && continue
1051          creer_lien_symb "$cible" "$lien" "$LOGIN"
1052      done
1053  }
1054  
1055  
1056  
1057  # Fonction qui lit son entrée standard et qui attend un unique argument 
1058  # (une chaîne de caractères). Elle renvoie 0 si la chaîne donnée en argument 
1059  # se trouve en début de ligne d'au moins une ligne de l'entrée standard et 
1060  # renvoie 1 sinon. Attention, la chaîne donnée en argument n'est pas vue 
1061  # comme une regex mais comme une « chaîne brute », ie  les caractères 
1062  # habituellement spéciaux pour une regex ne le sont pas et représentent
1063  # eux-même (le point représente le point et pas un caractère quelconque).
1064  grep_debut_verbatim ()
1065  {
1066      local motif n debut
1067      
1068      motif="$1"
1069      
1070      # Le nombre de caractères du motif.
1071      n=${#motif};
1072  
1073      # L'option -r est indispensable car sans elle la chaîne 'a\aa'
1074      # deviendrait 'aaa' une fois passée dans le filtre read.
1075      while read -r; do
1076          # On coupe la ligne à n caractères maximum.
1077          debut=${REPLY:0:$n}
1078          
1079          # On compare le début de ligne avec le motif.
1080          if [ "$debut" = "$motif" ]; then
1081              return 0
1082          fi
1083      done
1084      
1085      # Si on arrive ici, cela veut dire que le motif n'a jamais
1086      # été trouvé en début de ligne. Du coup, on renvoie 1.
1087      return 1
1088  }
1089  
1090  
1091  
1092  # Fonction identique à la précédente sauf qu'elle renvoie 0 uniquement
1093  # si la chaîne donnée en argument correspond exactement à au moins une
1094  # ligne complète de l'entrée standard.
1095  grep_debut_fin_verbatim ()
1096  {
1097      local motif
1098      
1099      motif="$1"
1100  
1101      # L'option -r est indispensable car sans elle la chaîne 'a\aa'
1102      # deviendrait 'aaa' une fois passée dans le filtre read.
1103      while read -r; do
1104          # On compare la ligne avec le motif.
1105          if [ "$REPLY" = "$motif" ]; then
1106              return 0
1107          fi
1108      done
1109      
1110      # Si on arrive ici, cela veut dire que le motif n'a jamais
1111      # été trouvé dans une ligne. Du coup, on renvoie 1.
1112      return 1
1113  }
1114  
1115  
1116  
1117  # Fonction qui permet d'afficher la variable d'environnement
1118  # DBUS_SESSION_BUS_ADDRESS de l'utilisateur toto qui ouvre une session afin
1119  # de pouvoir ensuite exécuter en tant que toto certaines commandes
1120  # impossibles à exécuter sans cette variable d'environnement.
1121  # On lancera alors la commande ainsi :
1122  # DBUS_SESSION_BUS_ADDRESS="$(afficher_adresse_bus)" sudo -Eu "$LOGIN" commande
1123  # Attention, le temps pour exécuter cette fonction est indéterminé et surtout
1124  # la fonction ne se terminera qu'une fois l'ouverture de session achevée (car 
1125  # c'est apparemment seulement une fois l'ouverture de session achevée que le 
1126  # fichier dans lequel on récupère la variable d'environnement est créé). Donc 
1127  # il faudra TOUJOURS lancer la fonction dans un sous-shell ainsi « { ... } & »,
1128  # sans quoi on risque de bloquer le script de logon.
1129  function afficher_adresse_bus ()
1130  {
1131      local n compteur
1132      
1133      n=$(\ls "$REP_HOME/.dbus/session-bus/" 2> /dev/null | wc -l)
1134      compteur=1
1135      
1136      # On attend que le fichier dans "$REP_HOME/.dbus/session-bus/ soit
1137      # créé lors de l'ouverture de session.
1138      while [ "$n" != "1" ]; do
1139          sleep 0.2
1140          n=$(\ls "$REP_HOME/.dbus/session-bus/" 2> /dev/null | wc -l)
1141          compteur=$((compteur+1))
1142          if [ "$compteur" -ge "100" ]; then
1143              # Au bout d'un certain nombre de tentatives on abandonne. 
1144              # Important pour éviter une boucle infinie.
1145              return 1
1146          fi
1147      done
1148  
1149      # On récupère et on affiche la valeur de la variable d'environnement
1150      # DBUS_SESSION_BUS_ADDRESS trouvée dans le fichier qui vient d'être créé.
1151      grep "^DBUS_SESSION_BUS_ADDRESS=" "$REP_HOME/.dbus/session-bus/"* | cut -d"=" -f"2-"
1152  }
1153  
1154  
1155  
1156  # Fonction, utilisable uniquement lors de l'ouverture de session, qui
1157  # prend comme premier argument le chemin absolu d'un fichier et
1158  # comme deuxième argument le chemin absolu d'une image qui sera
1159  # l'icône associé au fichier. Le chemin du fichier dont on veut changer
1160  # l'icône doit forcément se trouver dans "$REP_HOME".
1161  #
1162  # Rq: bien que la commande gvfs-set-attribute existe sous XUbuntu,
1163  #     celle-ci semble sans effet. Apparemment, sous XUbuntu, impossible
1164  #     de faire de changement d'icône.
1165  function changer_icone ()
1166  {
1167      # Cette partie sera lancée via un « & » et donc dans un sous-shell d'après
1168      # la page man de bash.
1169      {
1170          # Si on n'est pas pendant la phase d'ouverture, on abandonne.
1171          [ "$PHASE" != "ouverture" ] && return 1
1172  
1173          # Si le fichier cible ne se trouve pas dans le home de l'utilisateur, 
1174          # on abandonne.
1175          ! echo "$1" | grep_debut_verbatim "$REP_HOME/" && return 1
1176  
1177          # Si le fichier image n'existe pas, on abandonne.
1178          [ ! -f "$2" ] && return 1
1179  
1180          # On récupère la variable d'environnement « adresse bus ».        
1181          local valeur
1182          valeur=$(afficher_adresse_bus)
1183          if [ "$valeur" = "" ]; then
1184              # Si la valeur récupérée est vide, on abandonne.
1185              exit 1
1186          fi
1187  
1188          # On change l'attribut concernant l'icône du fichier.
1189          DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1190          gvfs-set-attribute -t string "$1"  "metadata::custom-icon" "file://$2"
1191              
1192          # Sur le bureau, pour que l'affichage se mette à jour, il faut faire
1193          # un touch sur le fichier avec l'option « --no-dereference », sinon
1194          # c'est la cible du lien symbolique qui est visée et non le lien
1195          # symbolique lui-même.
1196          touch --no-dereference "$1"
1197          
1198      } > "/dev/null" 2>&1 &
1199      # Ce sous-processus pourra être lancé à plusieurs reprises et,
1200      # sans la redirection ci-dessus, tous les sous-processus écriraient
1201      # plus ou moins en même temps sur un même fichier de log ce
1202      # qui pourrait donner un résultat imprévisible sur le fichier
1203      # de log. Le plus sage est de rediriger les deux sorties de
1204      # ce bout de code dans /dev/null. Ce n'est pas très grave, ce
1205      # n'est pas une partie critique.
1206  }
1207  
1208  
1209  
1210  # Cette fonction change le papier peint de l'utilisateur qui se
1211  # connecte lors de l'ouverture de session. Elle prend 1 argument qui doit
1212  # être le chemin absolu du fichier image (un accès à ce fichier en lecture 
1213  # pour l'utilisateur suffit).
1214  function changer_papier_peint ()
1215  {
1216      # Cette partie sera lancée via un « & » et donc dans un sous-shell d'après
1217      # la page man de bash.
1218      {
1219          # Si on n'est pas pendant la phase d'ouverture, on abandonne.
1220          [ "$PHASE" != "ouverture" ] && return 1
1221  
1222          # Si le fichier image n'existe pas, on abandonne.
1223          [ ! -f "$1" ] && return 1
1224  
1225          # On récupère la variable d'environnement « adresse bus ».        
1226          local valeur
1227          valeur=$(afficher_adresse_bus)
1228          if [ "$valeur" = "" ]; then
1229              # Si la valeur récupérée est vide, on abandonne.
1230              exit 1
1231          fi
1232  
1233          # La commande pour changer de papier peint dépend de l'environnement
1234          # de bureau utilisé. Comment connaître l'environnement de bureau
1235          # utilisé par le compte qui se connecte ? Je pensais utiliser des
1236          # choses comme « if ps -u "$LOGIN" | grep -q unity; then » mais hélas
1237          # pour des raisons de timing ça ne fonctionne pas. La commande ps
1238          # ne renvoie pas (encore) de processus unity* alors que l'utilisateur
1239          # courant se connecte pourtant avec Unity. On pourrait résoudre ce
1240          # problème de timing avec la commande sleep mais ça n'est pas 100% 
1241          # fiable : quel argument donner à sleep dans ce cas ? Du coup, on 
1242          # va se contenter de lancer la commande pour chacun des
1243          # environnements de bureau pris en charge, pour peu que la commande 
1244          # en question existe sur le système. Le résultat sera garanti et je
1245          # pense que la charge processeur supplémentaire due aux commandes
1246          # inutiles sera négligeable.
1247          
1248          # Sur Unity.
1249          if which gsettings > /dev/null; then
1250              # Il est hautement probable que l'utilisateur soit sur Unity.
1251              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1252                  gsettings set org.gnome.desktop.background picture-options stretched
1253              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1254                  gsettings set org.gnome.desktop.background picture-uri "file://$1"            
1255          fi
1256  
1257          # Sur Xfce.        
1258          if which xfconf-query > /dev/null; then
1259              # Il est hautement probable que l'utilisateur soit sur Xfce.
1260              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1261                  xfconf-query --create -c xfce4-desktop -p /backdrop/screen0/monitor0/image-style -s "3" -t int # la valeur correspond à "stretched"
1262              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1263                  xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/image-path -s "$1"
1264          fi
1265  
1266          # Sur Gnome.
1267          if which gconftool-2 > /dev/null; then
1268              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1269                  gconftool-2 --set /desktop/gnome/background/picture_options --type string stretched
1270              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" \
1271                  gconftool-2 --set /desktop/gnome/background/picture_filename --type string "$1"
1272          fi    
1273  
1274          # Sur LXDE.
1275          if which pcmanfm > /dev/null; then
1276              DBUS_SESSION_BUS_ADDRESS="$valeur" sudo -Eu "$LOGIN" pcmanfm --set-wallpaper="$1" --wallpaper-mode=center
1277          fi
1278  
1279      } > "/dev/null" 2>&1 &
1280  }
1281  
1282  
1283  
1284  # Fonction qui lance, à la fin de l'exécution du script, une commande 
1285  # quelconque. Le premier argument est le délai en secondes entre la fin
1286  # de l'exécution du script et le début du lancement de la commande.
1287  # Les arguments suivants correspondent à la commande à lancer avec ses
1288  # paramètres. Si le script est trop long à se terminer (plus précisément,
1289  # si la fonction executer_a_la_fin doit attendre que le script se termine
1290  # plus de 30 secondes) alors la commande ne sera pas lancée.
1291  # Attention, la sortie standard et la sortie des erreurs seront
1292  # redirigées vers /dev/null afin qu'il n'y ait pas d'écritures
1293  #  simultanées sur les fichiers de log.
1294  function executer_a_la_fin ()
1295  {
1296      # Tout sera lancé dans un sous-shell à cause du « & » à la fin.
1297      {
1298          local compteur
1299          compteur="1"
1300          # Tant que le script de logon local est lu par un processus
1301          # et donc qu'a priori il est en cours d'exécution, on attend.
1302          while fuser "$LOGON_SCRIPT_LOCAL" >/dev/null 2>&1; do 
1303              sleep 0.5
1304              if [ "$compteur" -ge "60" ]; then
1305                  # Au bout de 30 secondes, si ce n'est toujours
1306                  # pas fini, on abandonne.
1307                  return 1
1308              fi
1309              compteur=$((compteur+1))
1310          done
1311  
1312          sleep "$1" # petit délai avant de commencer.
1313          
1314          # On « mange » $1.
1315          shift 1
1316          
1317          # Et on lance la commande avec ses arguments.
1318          "$@"
1319          
1320      } > "/dev/null" 2>&1 &
1321  }
1322  
1323  
1324     
1325  ######################################
1326  ######################################
1327  ###                                ###
1328  ### Les arguments passés au script ###
1329  ###                                ###
1330  ######################################
1331  ######################################
1332  
1333  # Variable déjà affectée afin de rediriger les sorties stdout stderr 
1334  # dans des fichiers, dès le début du script.
1335  #PHASE="$1" 
1336  
1337  if [ -z "$2" ]; then
1338      # Si "$2" est vide alors par défaut il y a tentative de MAJ.
1339      TENTATIVE_DE_MAJ="true"
1340  else
1341      TENTATIVE_DE_MAJ="$2" # avec "$2" qui doit valoir true ou false.
1342  fi
1343  
1344  DEMARRAGE="$3"
1345  
1346  if [ "$DEMARRAGE" != "true" ]; then
1347      # Par défaut, cette variable, qui indique si le script s'exécute
1348      # lors du démarrage, est sur false. La fonction "initialisation"
1349      # se chargera de mettre cette variable sur true le cas échéant (en
1350      # se basant sur le montage ou non de REP_TMP_LOCAL).
1351      DEMARRAGE=false
1352  fi
1353  
1354  
1355  
1356  # On met dès le départ et une bonne fois pour toute
1357  # la date du moment dans le fichier de log.
1358  afficher_date
1359  
1360  set -x
1361  
1362  
1363  
1364  
1365  
1366  #############################################
1367  #############################################
1368  ###                                       ###
1369  ### Réglage des variables d'environnement ###
1370  ###                                       ###
1371  #############################################
1372  #############################################
1373  
1374  # Pour avoir des sorties les plus simples possibles, c'est-à-dire
1375  # en anglais avec des caractères 100% ASCII.
1376  export LC_ALL="C"
1377  
1378  # Du coup, on utilisera la locale française au coup par coup.
1379  # Celle-ci, il n'est pas nécessaire de l'exporter.
1380  LOCALE_FRANCAISE="fr_FR.utf8"
1381  
1382  # Réglage du PATH.
1383  export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
1384  
1385  
1386  
1387  
1388  
1389  
1390  ########################################################
1391  ########################################################
1392  ###                                                  ###
1393  ### Définitions des variables globales et exports de ###
1394  ### certaines variables et fonctions                 ###   
1395  ###                                                  ###
1396  ########################################################
1397  ########################################################
1398  
1399  
1400  #############################################
1401  ### Définitions de variables « globales » ###
1402  #############################################
1403  
1404  # Variables liées au Se3.
1405  SE3="__SE3__"
1406  BASE_DN="__BASE_DN__"
1407  SERVEUR_NTP="__SERVEUR_NTP__"
1408  NOM_PARTAGE_NETLOGON="netlogon-linux"
1409  CHEMIN_PARTAGE_NETLOGON="//$SE3/$NOM_PARTAGE_NETLOGON"
1410  
1411  # Variables liées à l'hôte.
1412  NOM_HOTE=$(hostname)
1413  NOM_DE_CODE=$(lsb_release --codename | cut -f 2)
1414  ARCHITECTURE=$(uname -m)
1415  
1416  MAX_UTILISATEURS_CONNECTES="4"
1417  
1418  # Apparemment, l'option serverino permet d'éviter des erreurs obscures 
1419  # lors de copies avec la commande cp (notamment avec les exécutables
1420  # *.unfois), alors qu'avec l'option noserverino j'avais rencontré
1421  # ces erreurs obscures.
1422  OPTIONS_MOUNT_CIFS_BASE="nobrl,serverino,iocharset=utf8,sec=ntlmv2"
1423  
1424  # Noms de fichiers ou de répertoires locaux au client.
1425  #REP_SE3_LOCAL="/etc/se3" # Déjà affectée en début de script.
1426  REP_BIN_LOCAL="$REP_SE3_LOCAL/bin"
1427  REP_TMP_LOCAL="$REP_SE3_LOCAL/tmp"
1428  #REP_LOG_LOCAL="$REP_SE3_LOCAL/log" # Déjà affectée en début de script.
1429  REP_SKEL_LOCAL="$REP_SE3_LOCAL/skel"
1430  REP_UNEFOIS_LOCAL="$REP_SE3_LOCAL/unefois"
1431  LOGON_SCRIPT_LOCAL="$REP_BIN_LOCAL/logon"
1432  VERSION_SKEL_LOCAL="$REP_SKEL_LOCAL/.VERSION"
1433  CREDENTIALS="$REP_TMP_LOCAL/credentials"
1434  REP_MONTAGE="/mnt"
1435  
1436  # Noms de fichiers ou de répertoires du Se3 accessibles par le client 
1437  # via le montage du partage NOM_PARTAGE_NETLOGON du Se3.
1438  REP_NETLOGON="$REP_MONTAGE/netlogon"
1439  LOGON_SCRIPT="$REP_NETLOGON/bin/logon"
1440  REP_SKEL="$REP_NETLOGON/distribs/$NOM_DE_CODE/skel"
1441  VERSION_SKEL="$REP_SKEL/.VERSION"
1442  REP_UNEFOIS="$REP_NETLOGON/unefois"
1443  REP_LANCEPARC="$REP_NETLOGON/lanceparc"
1444  
1445  
1446  ####################################################################################
1447  ### Définitions de variables « globales » valables uniquement lors d'une session ###
1448  ####################################################################################
1449  if [ "$PHASE" = "ouverture" ] || [ "$PHASE" = "fermeture" ]; then
1450  
1451      LOGIN="$LOGNAME"
1452      REP_MONTAGE_UTILISATEUR="$REP_MONTAGE/_$LOGIN"
1453      REP_HOME="/home/$LOGIN"
1454      NOM_COMPLET_LOGIN=$(getent passwd "$LOGIN" | cut -d':' -f5 | cut -d',' -f1)
1455      
1456      if [ "$PHASE" = "ouverture" ]; then
1457          # La requête LDAP ne sera faite qu'au moment de l'ouverture de session.
1458          if ! est_utilisateur_local "$LOGIN" ; then
1459              LISTE_GROUPES_LOGIN=$(afficher_liste_groupes "$LOGIN")
1460          fi
1461      fi
1462      
1463  fi
1464  
1465  
1466  ############################################################################
1467  ### On exporte certaines variables « globales » pour les scripts unefois ###
1468  ############################################################################
1469  
1470  export SE3
1471  export BASE_DN
1472  export NOM_HOTE
1473  export NOM_DE_CODE
1474  export ARCHITECTURE
1475  export REP_BIN_LOCAL # Seulement parce que la fonction activer_pave_numerique l'utilise.
1476  
1477  # Les variables LOGIN, NOM_COMPLET_LOGIN, LISTE_GROUPES_LOGIN seront utilisables 
1478  # dans les fonctions ouverture_perso et fermeture_perso, mais un export 
1479  # ne sert à rien pour ces variables car elles n'ont pas de sens dans 
1480  # les scripts unefois.
1481  
1482  # Quant à la variable DEMARRAGE, pas d'export non plus car dans un script
1483  # unefois elle vaudra toujours true, puisque les scripts unefois ne sont
1484  # lancés qu'au démarrage du système.
1485  
1486  
1487  ############################################################################
1488  ### On exporte certaines fonctions « globales » pour les scripts unefois ###
1489  ############################################################################
1490  
1491  export -f appartient_au_groupe
1492  export -f appartient_au_parc
1493  export -f afficher_liste_groupes
1494  export -f afficher_liste_parcs
1495  export -f est_dans_liste
1496  export -f activer_pave_numerique
1497  export -f est_utilisateur_local
1498  export -f est_connecte
1499  
1500  
1501  
1502  
1503  
1504  ################################################################################
1505  ################################################################################
1506  ###                                                                          ###
1507  ### Définitions des trois fonctions de base appelées à des instants          ###
1508  ### différents par la machine clientes :                                     ###
1509  ###                                                                          ###
1510  ###    - "initialisation" qui sera appelée juste avant l'affichage de        ###
1511  ###      la fenêtre de connexion, c'est-à-dire au moment du                  ###
1512  ###      démarrage et après chaque fermeture de session.                     ###
1513  ###                                                                          ###
1514  ###    - "ouverture" qui sera appelée au moment de                           ###
1515  ###      l'ouverture de session de l'utilisateur, juste après                ###
1516  ###      l'authentification de celui-ci.                                     ###
1517  ###                                                                          ###
1518  ###    - "fermeture" qui sera appelée au moment de la fermeture              ###
1519  ###      de session de l'utilisateur.                                        ###
1520  ###                                                                          ###
1521  ################################################################################
1522  ################################################################################
1523  
1524  
1525  
1526  function initialisation ()
1527  {
1528      nettoyer_rep_tmp_local
1529      
1530      # On attend un petit peu car, sur Precise par exemple, les processus de
1531      # l'utilisateur qui vient de fermer sa session sont encore en vie si
1532      # bien que, aux yeux du script de logon, l'utilisateur est encore
1533      # connecté et le nettoyage est alors incomplet.
1534      sleep 1
1535      
1536      nettoyer_rep_montage
1537      nettoyer_rep_home
1538      
1539      local n
1540      local message
1541      n=$(afficher_nombre_utilisateurs_connectes)
1542      if [ "$n" -ge "$MAX_UTILISATEURS_CONNECTES" ]; then
1543          message="Trop de sessions n'ont pas été fermées. Le système va"
1544          message="$message redémarrer ce qui provoquera la fermeture"
1545          message="$message de toutes les sessions en suspens."
1546          LC_ALL="$LOCALE_FRANCAISE" zenity \
1547                              --info "Trop de sessions non fermées" \
1548                              --text "$message" --timeout 10
1549          reboot && exit
1550      fi
1551  
1552      if ! mountpoint -q "$REP_TMP_LOCAL"; then
1553          # REP_TMP_LOCAL n'est pas monté, donc c'est le démarrage du système,
1554          # il faut donc modifier la variable DEMARRAGE.
1555          DEMARRAGE=true
1556          mount -t tmpfs -o size=100k tmpfs "$REP_TMP_LOCAL"
1557      fi
1558  
1559      if monter_netlogon; then
1560          # Montage réussi ou bien il avait été effectué auparavant.
1561          # Donc le contenu n'est pas forcément lisible (le service
1562          # Samba entre temps est peut être tombé en panne).
1563  
1564          # Tentative de MAJ de LOGON_SCRIPT.       
1565          if $TENTATIVE_DE_MAJ \
1566            && timeout "--signal=SIGTERM" 2s test -r "$LOGON_SCRIPT" \
1567            && ! diff -q "$LOGON_SCRIPT_LOCAL" "$LOGON_SCRIPT" >/dev/null 2>&1
1568          then
1569              # On exécute le script distant avec l'argument empêchant une MAJ
1570              # et en signalant, avec la variable DEMARRAGE, si l'on est pendant
1571              # le démarrage du système ou non. En effet, si c'est le script
1572              # de logon distant qui est lancé, alors REP_TMP_LOCAL est
1573              # sans doute déjà monté cela ne sera plus un critère pour savoir
1574              # si l'on est pendant le démarrage du système.
1575              "$LOGON_SCRIPT" "initialisation" false "$DEMARRAGE"
1576              # Si le script distant s'est effectué sans erreur (typiquement il
1577              # ne possède pas d'erreur de syntaxe), alors on lance la mise à
1578              # jour.
1579              if [ "$?" = "0" ]; then
1580                  mettre_a_jour_logon
1581              else
1582                  afficher "Attention, a priori le script de logon distant n'est pas correct." \
1583                           "Pas de mise à jour effectuée en local."
1584              fi
1585              # Inutile de continuer le script, on vient d'exécuter une fois 
1586              # sa version à jour (celle du serveur) au complet. Alors on sort.
1587              exit 0
1588          fi
1589          
1590          # Tentative de MAJ du profil et lancements des « unefois ».
1591          if timeout "--signal=SIGTERM" 2s test -r "$VERSION_SKEL"; then
1592              if ! diff -q "$VERSION_SKEL_LOCAL" "$VERSION_SKEL" >/dev/null 2>&1; then
1593                  mettre_a_jour_profil
1594              fi
1595              # Puisque le serveur semble accessible, on tente d'accéder à
1596              # REP_UNEFOIS, dans le cas où l'on est dans une phase d'initialisation
1597              # qui correspond à un démarrage.
1598              if "$DEMARRAGE" && timeout "--signal=SIGTERM" 2s test -d "$REP_UNEFOIS"; then
1599                  lancer_unefois
1600              fi
1601              
1602              # Idem ci-dessus pour le répertoire lance-parc
1603              
1604              if timeout "--signal=SIGTERM" 2s test -d "$REP_LANCEPARC"; then
1605          lancer_parc
1606              fi
1607          fi
1608                  
1609      fi
1610  
1611      # Si jamais le répertoire ".dbus" existe déjà dans le profil par défaut 
1612      # local, il faut le supprimer car il devra être généré à la volée au
1613      # moment de l'ouverture de session dans le home de l'utilisateur qui
1614      # se connecte. En effet, ce répertoire contiendra alors un fichier
1615      # qui permettra de connaître la valeur de la variable 
1616      # DBUS_SESSION_BUS_ADDRESS de la session en cours. Si on ne prend pas
1617      # la précaution de supprimer ce répertoire dans le profil local maintenant, 
1618      # on risque de récupérer alors la valeur de cette variable pour une
1619      # ancienne session, et toutes les fonctions qui dépendent de cette 
1620      # variable risqueront de ne pas marcher.
1621      if [ -e "$REP_SKEL_LOCAL/.dbus" ]; then
1622          afficher "Suppression du répertoire .dbus/ dans le profil local."
1623          rm -fr --one-file-system "$REP_SKEL_LOCAL/.dbus"
1624      fi
1625  
1626      initialisation_perso 1> "$REP_LOG_LOCAL/1.initialisation_perso.log" 2>&1
1627      
1628      exit 0
1629  }
1630  
1631  
1632  function ouverture ()
1633  {
1634      # Quoi qu'il arrive, à la fin du script lors de l'ouverture, on
1635      # nettoie le répertoire temporaire local.
1636      trap nettoyer_rep_tmp_local EXIT
1637      
1638      # Dans cette fonction, on peut faire usage de $LOGIN
1639      # qui est le login de l'utilisateur courant.
1640  
1641      if est_utilisateur_local "$LOGIN" ; then
1642          # On ne fait rien et on arrête le script.
1643          exit 0
1644      fi
1645     
1646      # Mise en place du home de l'utilisateur qui n'est pas un
1647      # utilisateur local ici.
1648      if [ -e "$REP_HOME" ]; then
1649          rm -fr --one-file-system "$REP_HOME"
1650      fi
1651      mkdir -p "$REP_HOME/Bureau"
1652      
1653      # On copie tout le contenu de REP_SKEL_LOCAL dans le HOME_LOCAL.
1654      shopt -s dotglob
1655      local f
1656      for f in "$REP_SKEL_LOCAL/"*; do
1657          cp -r "$f" "$REP_HOME"
1658      done
1659      shopt -u dotglob
1660      
1661      # Ajustement des droits sur le home.
1662      chown -R "$LOGIN:" "$REP_HOME"
1663      # On rend les fichiers *.desktop exécutables pour l'utilisateur au cas où...
1664      for f in "$REP_HOME/Bureau/"*".desktop"; do
1665          [ "$f" = "$REP_HOME/Bureau/*.desktop" ] && continue
1666          chmod u+x "$f"
1667      done 
1668      chmod 700 "$REP_HOME"
1669      sync
1670      
1671      # Après la création du home de l'utilisateur, on attend un peu.
1672      # En effet, j'ai constaté empiriquement que, sur Precise par exemple,
1673      # sans ce laps de temps les réglages inscrits dans le profil
1674      # (notamment dans le répertoire "~/.config/") n'étaient pas
1675      # systématiquement pris en compte par l'environnement de bureau.
1676      sleep 1
1677  
1678      # Maintenant, il faut procéder aux montages des partages CIFS.
1679      # Pour commencer, il faut attendre la création du fichier CREDENTIALS.
1680      local c
1681      c="1"
1682      while ! test -r "$CREDENTIALS" && [ "$c" -le 4 ]; do
1683          # Tant que le fichier n'est pas accessible en lecture, on attend un peu.
1684          sleep 0.5
1685          c=$((c+1)) # pour éviter une boucle infinie, après 4 tentatives, on sort de la boucle.
1686      done
1687  
1688      # Si c vaut 5, c'est qu'il a été impossible de lire le fichier CREDENTIALS
1689      # et donc que les montages seront impossibles. Dans ce cas, il vaut mieux
1690      # sortir et ne pas tenter les-dits montages.
1691      if [ "$c" -eq "5" ]; then
1692          afficher_fenetre_erreur "Problème" \
1693              "Le montage des partages de l'utilisateur sont impossibles car" \
1694              "le fichier \"CREDENTIALS\" est inaccessible."
1695          exit 1
1696      fi
1697  
1698      if [ -e "$REP_MONTAGE_UTILISATEUR" ]; then
1699          # Le répertoire existe déjà ce qui n'est pas normal.
1700          # Du coup, on nettoie le répertoire de montage, étant 
1701          # donné qu'il sera créé juste après.
1702          nettoyer_un_rep_montage "$REP_MONTAGE_UTILISATEUR"
1703      fi
1704      
1705      # On crée le répertoire où seul LOGIN pourra se rendre.
1706      mkdir "$REP_MONTAGE_UTILISATEUR"
1707      chown "$LOGIN:" "$REP_MONTAGE_UTILISATEUR"
1708      chmod "700" "$REP_MONTAGE_UTILISATEUR"
1709  
1710      # C'est dans la fonction ouverture_perso que les montages seront
1711      # effectués pour que l'administrateur puisse les gérer comme
1712      # bon lui semble.
1713      ouverture_perso 1> "$REP_LOG_LOCAL/2.ouverture_perso.log" 2>&1
1714      
1715      # Surtout, on détruit immédiatement le fichier CREDENTIALS contenu
1716      # dans le répertoire temporaire local. En principe, c'est fait
1717      # automatiquement grâce à la fonction trap ci-dessus, mais on
1718      # rajoute une couche au cas où...
1719      nettoyer_rep_tmp_local
1720      
1721      exit 0
1722  }
1723  
1724  
1725  
1726  function fermeture ()
1727  {
1728      # Dans cette fonction, on peut faire usage de $LOGIN
1729      # qui est le login de l'utilisateur courant.
1730  
1731      if est_utilisateur_local "$LOGIN" ; then
1732          # On ne fait rien et on arrête le script.
1733          exit 0
1734      fi
1735      
1736      # Par mesure de sécurité, avant le nettoyage, on débarrasse le
1737      # /home des liens symboliques qui pointent vers des partages.
1738      # Il y en a à la racine du /home et sur le « Bureau ».
1739      
1740      # Le « ! -name '.gvfs' » permet d'éviter une petite erreur lors 
1741      # de la commande « find » quand on est sous Ubuntu.
1742      find "$REP_HOME" -maxdepth 1 ! -name '.gvfs' -type l -exec rm -f '{}' \;
1743      find "$REP_HOME/Bureau" -maxdepth 1 -type l -exec rm -f '{}' \;
1744      
1745      fermeture_perso 1> "$REP_LOG_LOCAL/3.fermeture_perso.log" 2>&1
1746      
1747      exit 0
1748  }
1749  
1750  
1751  # Dans logon, les variables SE3 et BASE_DN sont definies
1752  function genere_fond_ecran() {
1753  
1754      if [ -z "$LOGIN" ]
1755      then
1756          # La variable LOGIN n'est pas définie. On arrête là.
1757          return 1
1758      fi
1759  
1760      # Quelques parametres
1761      dossier_base_fond="$REP_NETLOGON/fond_ecran"
1762      dossier_dest_fond=/tmp
1763      ext=jpg
1764  
1765      t=$(which convert)
1766      if [ -z "$t" ]; then
1767          echo "La generation de fond d'ecran necessite l'installation d'imagemagick cote client."
1768      else
1769          # Menage
1770          if [ -e "${dossier_dest_fond}/fond_ecran_$LOGIN.$ext" ]; then
1771            rm -f "${dossier_dest_fond}/fond_ecran_$LOGIN.$ext"
1772          fi
1773  
1774          # Recuperation des parametres generaux
1775          parametres_generation_fonds
1776  
1777          if [ -n "$prefixe" ]; then
1778  
1779            if [ "$LOGIN" = "admin" ]; then
1780                t=$(grep "function parametres_fond_ecran_admin()" $REP_BIN_LOCAL/logon)
1781                if [ -n "$t" ]; then
1782                    parametres_fond_ecran_admin
1783                    if [ "$generation_fonds_ecran" = "actif" ]; then
1784                        annotation_fond_ecran_admin
1785  
1786                        temoin="admin"
1787                        classe="Admins"
1788                    fi
1789                fi
1790            else
1791                if est_dans_liste "$LISTE_GROUPES_LOGIN" "overfill"; then
1792                    t=$(grep "function parametres_fond_ecran_overfill()" $REP_BIN_LOCAL/logon)
1793                    if [ -n "$t" ]; then
1794                        parametres_fond_ecran_overfill
1795                        if [ "$generation_fonds_ecran" = "actif" ]; then
1796                            annotation_fond_ecran_overfill
1797  
1798                            temoin="overfill"
1799                            classe=""
1800                        fi
1801                    fi
1802                fi
1803  
1804                # Pour les profs on outrepasse les parametres overfill
1805                if est_dans_liste "$LISTE_GROUPES_LOGIN" "Profs"; then
1806                    t=$(grep "function parametres_fond_ecran_Profs()" $REP_BIN_LOCAL/logon)
1807                    if [ -n "$t" ]; then
1808                        parametres_fond_ecran_Profs
1809                        if [ "$generation_fonds_ecran" = "actif" ]; then
1810                            annotation_fond_ecran_Profs
1811  
1812                            temoin="Profs"
1813                            classe="Profs"
1814                        fi
1815                    fi
1816                fi
1817  
1818                if [ -z "$temoin" ]; then
1819                    # Utilisateur non prof... -> eleves ou administratifs?
1820                    if est_dans_liste "$LISTE_GROUPES_LOGIN" "Eleves"; then
1821                        # Utilisateur eleve
1822                        # Dans le cas d'un eleve, le groupe Classe est prioritaire (pour l'image) sur le groupe eleves.
1823                        #classe=$(ldapsearch -xLLL -h "$SE3" -b "ou=Groups,$BASE_DN" "(&(memberuid=$LOGIN)(cn=Classe*))" cn | grep "^cn: " | sed -e "s/^cn: //"|head -n1)
1824                        #classe=$(echo "$LISTE_GROUPES_LOGIN" | sed -rn 's/^Classe_(.*)$/\1/p')
1825                        # Les fonctions sont formatees
1826                        #    en annotation_fond_ecran_admin,
1827                        #    annotation_fond_ecran_<groupe>,...
1828                        # mais si un admin cree une classe 'Classe_admin', et qu'on vire le prefixe 'Classe_', on va avoir une collision de noms.
1829                        classe=$(echo "$LISTE_GROUPES_LOGIN" | grep "^Classe_" |head -n1)
1830                        if [ ! -z "$classe" ]; then
1831                            # PROBLEME AVEC CA... IL NE DOIT PAS ETRE POSSIBLE D APPELER UNE TELLE FONCTION
1832                            # Il semble que si...
1833                            t=$(grep "function parametres_fond_ecran_$classe()" $REP_BIN_LOCAL/logon)
1834                            if [ -n "$t" ]; then
1835                                parametres_fond_ecran_$classe
1836                                if [ "$generation_fonds_ecran" = "actif" ]; then
1837                                    annotation_fond_ecran_$classe
1838  
1839                                    temoin="$classe"
1840                                    classe="$classe"
1841                                fi
1842                            fi
1843                        fi
1844  
1845                        if [ -z "$temoin" ]; then
1846                            t=$(grep "function parametres_fond_ecran_Eleves()" $REP_BIN_LOCAL/logon)
1847                            if [ -n "$t" ]; then
1848                                parametres_fond_ecran_Eleves
1849                                if [ "$generation_fonds_ecran" = "actif" ]; then
1850                                    annotation_fond_ecran_Eleves
1851  
1852                                    temoin="Eleves"
1853                                fi
1854                            fi
1855                        fi
1856                    else
1857  
1858                        if est_dans_liste "$LISTE_GROUPES_LOGIN" "Administratifs"; then
1859                            # Utilisateur membre de: Administratifs
1860                            t=$(grep "function parametres_fond_ecran_Administratifs()" $REP_BIN_LOCAL/logon)
1861                            if [ -n "$t" ]; then
1862                                parametres_fond_ecran_Administratifs
1863                                if [ "$generation_fonds_ecran" = "actif" ]; then
1864                                    annotation_fond_ecran_Administratifs
1865  
1866                                    temoin="Administratifs"
1867                                    classe="Administratifs"
1868                                fi
1869                            fi
1870                        fi
1871                    fi
1872                fi
1873            fi
1874  
1875            if [ -n "$temoin" ]; then
1876                # Generation avec les parametres...
1877  
1878                # Passage de variable:
1879                base=$temoin
1880                if [ "$base" == "admin" ]; then
1881                    orig="Adminse3"
1882                else
1883                    orig="$base"
1884                fi
1885  
1886                # Generation du fond commun s'il n'existe pas:
1887                if [ ! -e "${dossier_base_fond}/$orig.jpg" ]; then
1888                    convert -size ${largeur}x${hauteur} gradient:${couleur1}-${couleur2} jpeg:${dossier_dest_fond}/$orig.jpg
1889                else
1890                    cp ${dossier_base_fond}/$orig.jpg ${dossier_dest_fond}/
1891                fi
1892  
1893                #===============================================================
1894                # Generation de la chaine des infos a afficher:
1895                chaine=""
1896                if [ "$annotation_nom" = "1" ]; then
1897                    nom_prenom=$NOM_COMPLET_LOGIN
1898                    chaine=$(echo "$nom_prenom" | tr "'ÂÄÀÁÃÄÅÇÊËÈÉÎÏÌÍÑÔÖÒÓÕ¦ÛÜÙÚݾ´áàâäãåçéèêëîïìíñôöðòóõ¨ûüùúýÿ¸" "_AAAAAAACEEEEIIIINOOOOOSUUUUYYZaaaaaaceeeeiiiinoooooosuuuuyyz" | sed -e "s|[^A-Za-z_ -]||g" | sed -e "s|Æ|AE|g" | sed -e "s|¼|OE|g" | sed -e "s|æ|ae|g" | sed -e "s|½|oe|g")
1899                fi
1900  
1901                if [ "$annotation_classe" = "1" ]; then
1902                    if [ -z "$classe" ]; then
1903                        # Cas d'un eleve dans le groupe overfill:
1904                        #classe=$(ldapsearch -xLLL -h "$SE3" -b "ou=Groups,$BASE_DN" "(&(memberUid=$LOGIN)(cn=Classe_*))" cn | grep "^cn: " | sed -e "s/^cn: //"|head -n1)
1905                        #classe=$(echo "$LISTE_GROUPES_LOGIN" | sed -rn 's/^Classe_(.*)$/\1/p')
1906                        classe=$(echo "$LISTE_GROUPES_LOGIN" | grep "^Classe_" |head -n1)
1907                    fi
1908  
1909                    if [ -z "$classe" ]; then
1910                        if est_dans_liste "$LISTE_GROUPES_LOGIN" "Profs"; then
1911                            classe="Profs"
1912                        elif est_dans_liste "$LISTE_GROUPES_LOGIN" "Administratifs"; then
1913                            classe="Administratifs"
1914                        fi
1915                    fi
1916  
1917                    if [ ! -z "$classe" ]; then
1918                        if [ -n "${chaine}" ]; then
1919                            chaine="$chaine ($classe)"
1920                        else
1921                            chaine="$classe"
1922                        fi
1923                    fi
1924                fi
1925  
1926                # Generation de l'image:
1927                if [ -n "$couleur_txt" ]; then
1928                    convert -fill ${couleur_txt} -pointsize $taille_police -draw "gravity North text 0,0 '$chaine'" ${dossier_dest_fond}/$orig.jpg ${prefix}${dossier_dest_fond}/fond_ecran_$LOGIN.$ext
1929                else
1930                    cp ${dossier_dest_fond}/$orig.jpg ${dossier_dest_fond}/fond_ecran_$LOGIN.$ext
1931                fi
1932  
1933            fi
1934          fi
1935  
1936          if [ -e /tmp/fond_ecran_${LOGIN}.jpg ]; then
1937              changer_papier_peint /tmp/fond_ecran_${LOGIN}.jpg
1938          fi
1939      fi
1940  }
1941  
1942  
1943  
1944  function supprimer_fond_ecran() {
1945  
1946      if [ -z "$LOGIN" ]
1947      then
1948          # La variable LOGIN n'est pas définie. On arrête là.
1949          return 1
1950      fi
1951  
1952      if [ -e /tmp/fond_ecran_${LOGIN}.jpg ]; then
1953          rm -f /tmp/fond_ecran_${LOGIN}.jpg
1954      fi
1955  }
1956  
1957  
1958  
1959  
1960  ################################################################################
1961  ################################################################################
1962  ###                                                                          ###
1963  ### Fin des définitions de fonctions et autres variables.                    ###
1964  ### Suivant le paramètre $1 (qui s'appelle $PHASE dans le script) qui est    ###
1965  ### passé à ce script, c'est une des quatre fonctions de base qui sera       ###
1966  ### appelée.                                                                 ###
1967  ###                                                                          ###
1968  ################################################################################
1969  ################################################################################
1970  
1971  
1972  
1973  case "$PHASE" in
1974  
1975      "initialisation")
1976          initialisation
1977          ;;
1978  
1979      "ouverture")
1980          ouverture
1981          ;;
1982  
1983      "fermeture")
1984          fermeture
1985          ;;
1986          
1987      *)
1988          # On ne fait rien de spécial
1989          true
1990          ;;
1991  
1992  esac
1993  
1994  
1995  
1996  exit 0
1997  # Fin du script
1998  ################################################################################
1999  
2000  
2001  


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1