#!/bin/bash # Automatisation de configuration backuppc pour poste MAC # Institut de Physique de Rennes UMR6251 # Jérémy GARDAIS, Guillaume RAFFY — Avril 2018 SUCCESS=0 ERROR=1 # Functions {{{ ## GetDefaultUser {{{ function GetDefaultUser() { for user in $(ListUsers); do echo "${user}" return done } ## }}} ## AllowUserToConnectToThisMachineUsingSsh {{{ # this performs the equivalent as adding a remote login user in system preferences using the gui function AllowUserToConnectToThisMachineUsingSsh() { local userLogin userLogin="$1" [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Autoriser les accès SSH pour l'utilisateur (${userLogin})." dscl . append '/Groups/com.apple.access_ssh' user "${userLogin}" dscl . append /Groups/com.apple.access_ssh groupmembers $(dscl . read "/Users/${userLogin}" GeneratedUID | cut -d " " -f 2) } ## }}} ## EnsurePingIsAllowed {{{ function EnsurePingIsAllowed() { [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Désactivation du mode furtif (ping)." sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode off &> /dev/null if [ $? != 0 ]; then printf '\e[1;31m%-6s\e[m\n' "ERREUR : La désactivation du mode furtif a échoué" return "$ERROR" fi } ## }}} ## EnsureSshdIsRunning {{{ function EnsureSshdIsRunning() { [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Vérification si sshd est déjà en cours." sudo launchctl list | grep 'com.openssh.sshd' &> /dev/null if [ $? != 0 ]; then # enable 'Remote login' in 'system preferences' sudo launchctl enable system/com.openssh.sshd &> /dev/null sudo launchctl load /System/Library/LaunchDaemons/ssh.plist &> /dev/null fi [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Activation du serveur ssh." sudo launchctl list | grep 'com.openssh.sshd' &> /dev/null if [ $? != 0 ]; then printf '\e[1;31m%-6s\e[m\n' "ERREUR : L'activation du serveur ssh a échoué"; return "$ERROR" fi } ## }}} ## GetMyHostKey {{{ function GetMyHostKey() { hostkey="/etc/ssh_host_rsa_key.pub" if [ ! -f "${hostkey}" ]; then hostkey="/etc/ssh/ssh_host_rsa_key.pub" if [ ! -f "${hostkey}" ]; then printf '\e[1;31m%-6s\e[m\n' "ERREUR : Impossible de trouver la clef ssh publique ce cette machine, SSH est-il bien installé?\\n Installation annulée." return "$ERROR" fi fi echo "${hostkey}" } ## }}} ## IpAddress {{{ function IpAddress() { local strMyIpAddress strMyIpAddress='' strMyIpAddress=$(dig +short myip.opendns.com @resolver1.opendns.com) if [ "${strMyIpAddress}" == '' ]; then error "failed to retrieve the ip address of this machine" return 1 fi echo "{$strMyIpAddress}" } ## }}} ## MyFqdn {{{ function MyFqdn() { local strMyIpAddress local strMyFqdn strMyIpAddress=$( IpAddress ) # eg '129.20.27.49' strMyFqdn=$(host "${strMyIpAddress}" | awk '{print $5}') echo "${strMyFqdn%?}" # remove the trailing '.' } ## }}} ## ListUsers {{{ function ListUsers() { local users users='' for user in $(ls -d /Users/[a-zA-Z]*); do user=$(basename "${user}") case "${user}" in 'Shared'|'admin') ;; *) users="$users $user" ;; esac done echo "${users}" } ## }}} ## AddUserBackuppc {{{ function AddUserBackuppc() { local userToBackup local homeDir local userLogin local groupId userToBackup="$1" # the login of the user to backup homeDir="$2" # eg. '/var/lib/backuppc' userLogin='backuppc' groupId=$(id -g "${userToBackup}") maxid=$(dscl . -list /Users UniqueID | awk '$2 < 1000 {print $2}' | sort -ug | tail -1) newid=$((maxid+1)) mkdir -p "$homeDir" id "$newid" &> /dev/null if [ $? = 0 ]; then echo "unable to find a suitable uid for user backuppc ($newid is already used)" exit $ERROR fi # Create user [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Création de l'utilisateur ${userLogin}." dscl . -create "/Users/$userLogin" dscl . -create "/Users/$userLogin" UserShell /bin/bash dscl . -create "/Users/$userLogin" RealName "backuppc" dscl . -create "/Users/$userLogin" UniqueID "$newid" dscl . -create "/Users/$userLogin" PrimaryGroupID "$groupId" dscl . -create "/Users/$userLogin" NFSHomeDirectory "$homeDir" dscl . -create "/Users/$userLogin" IsHidden 1 # hide from login window # Homedir permissions [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : chown -R $userLogin:$groupId $homeDir" chown -R "$userLogin:$groupId" "$homeDir" AllowUserToConnectToThisMachineUsingSsh "${userLogin}" AllowBackuppcSudo } ## }}} ## AllowBackuppcSudo {{{ function AllowBackuppcSudo() { # Get sudoers directory from the configuration local sudoersDir sudoersDir=$(grep "^#includedir " /etc/sudoers | cut -d" " -f2) if [ -f /etc/sudoers ]; then sudoersDir=$(grep "^#includedir " /etc/sudoers | cut -d" " -f2) if [ ! "${sudoersDir}" == '' ]; then printf '%b\n' "Configuration de sudo pour BackupPC." else [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Ajout du dossier sudoers (${sudoersDir}) dans la configuration sudo." echo "#includedir /etc/sudoers.d" >> /etc/sudoers fi elif [ -f /private/etc/sudoers ]; then sudoersDir=$(grep "^#includedir " /private/etc/sudoers | cut -d" " -f2) if [ ! "${sudoersDir}" == '' ]; then printf '%b\n' "Configuration de sudo pour BackupPC." else echo "#includedir /private/etc/sudoers.d" >> /private/etc/sudoers [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Ajout du dossier sudoers (${sudoersDir}) dans la configuration sudo." fi else printf '\e[1;31m%-6s\e[m\n' "ERREUR : Impossible de trouver un fichier de configuratio pour sudo." return "$ERROR" fi # Ensure to create the sudoers directory sudo mkdir -p -- "${sudoersDir}" [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Création du dossier pour les sudoers (${sudoersDir})." # Allow backuppc user to use rsync with sudo sudo sh -c "echo '${userLogin} ALL=(ALL:ALL) NOEXEC:NOPASSWD: /usr/bin/rsync' > ${sudoersDir}/backuppc_noexec" [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Ajout des autorisations sudo pour l'utilisateur (${userLogin}) dans le fichier (${sudoersDir}/backuppc_noexec)." } ## }}} # }}} #### VÉRIFIER QUE L’ON A BIEN LES DROITS ADMIN #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Vérification des droits admin" if [ "$EUID" -ne 0 ]; then printf '\e[1;31m%-6s\e[m\n' "ERREUR : À lancer avec les droits administrateur " exit fi #### NOM DU COMPTE À SAUVEGARDER #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Nom du compte à sauvegarder" default_user=$(GetDefaultUser) printf '%b\n' "Liste des comptes détectés sur cette machine : $(ListUsers)" printf '\e[1;34m%-6s\e[m' "Login de l’utilisateur dont les données sont à sauvegarder ? [${default_user}] : " read input_login if [[ ${input_login} != "" ]]; then usr="${input_login}" else usr="${default_user}" fi #### VÉRIFIER QUE LE COMPTE EST BIEN DANS LA LISTE DES USER ID #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Vérification du compte" if ! id "${usr}" &> /dev/null; then printf '\e[1;34m%-6s\e[m' "${usr} n’apparait pas dans la liste des user ids. Continuer tout de même ? [o/N] : " read input_continue if [[ "${input_continue}" != "o" ]]; then printf '\e[1;31m%-6s\e[m\n' "Installation annulée." exit fi fi #### DOSSIER À SAUVEGARDER #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Dossier à sauvegarder" default_dir=$(eval echo ~"${usr}") if [ ! -d "${default_dir}" ]; then default_dir="" fi printf '%b\n' "Par défaut, le dossier sauvegardé est le home de l’utilisateur. Il est possible d’en ajouter un supplémentaire ensuite." printf '\e[1;34m%-6s\e[m' "Dossier à sauvegarder ? [${default_dir}] : " read input_dir if [[ "${input_dir}" == "" ]]; then dir1="${default_dir}" else dir1="${input_dir}" fi #### DOSSIER À SAUVEGARDER INTROUVABLE, ANNULATION #### if [ ! -d "${dir1}" ]; then [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Dossier introuvable" printf '\e[1;31m%-6s\e[m\n' "ERREUR : Dossier ${dir1} introuvable, installation annulée." exit fi #### DOSSIER SUPPLÉMENTAIRE #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Dossier supplémentaire" printf '\e[1;34m%-6s\e[m' "Si vous avez un dossier supplémentaire à sauvegarder (/mnt/data par exemple) entrer-le maintenant, sinon laissez vide. [] : " read input_dir2 if [[ "${input_dir2}" != "" ]]; then #### DOSSIER SUPPLÉMENTAIRE INTROUVABLE, ANNULATION DE CELUI-CI #### if [ ! -d "${input_dir2}" ]; then printf '\n' printf '%b\n' "Dossier supplémentaire introuvable, non ajouté." else directories="'${dir1}','${input_dir2}'" fi else directories="'${dir1}'" fi #### AUTORISER LE PING #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Configuration du poste" EnsurePingIsAllowed #### INSTALLATION DE OPENSSH-SERVER #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Installation de Openssh-server" EnsureSshdIsRunning if [ "$?" != "$SUCCESS" ]; then printf '\e[1;31m%-6s\e[m\n' "ERREUR : L'installation du serveur ssh a échoué, installation annulée." exit fi hostkey=$(GetMyHostKey) #printf "hostkey=$hostkey" if [ "$?" != "$SUCCESS" ]; then printf '\e[1;31m%-6s\e[m\n' "ERREUR : Clé inaccessible, merci de contacter votre administrateur réseau, installation annulée." exit fi #### CRÉATION DU FICHIER DE CONFIGURATION #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Création du fichier de configuration" fqdn="$(MyFqdn)" filepl="${fqdn}.pl" exclude="['ownCloud','.local/share/Trash','.cache','.Play*','.steam','.wine','Perso','temp','tmp','.Trash*','.DS_Store','._*', '.thumbnails','.ssh/id_*','.xsession-*']" echo "\$Conf{XferMethod} = 'rsync';" > "${filepl}" echo "\$Conf{RsyncShareName} = [${directories}];" >> "${filepl}" echo "\$Conf{BackupFilesExclude} = {'*' => ${exclude} };" >> "${filepl}" [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Fichier de configuration créé (${filepl})" #### LE SERVEUR DOIT CONNAITRE #### # Les commandes à exécuter avec sudo # ssh_host_ecdsa_key.pub DU CLIENT # L’ADRESSE MAIL # L'IP # Le nom d'utilisateur [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Informations complémentaires dans le fichier de configuration" printf '\e[1;34m%-6s\e[m' "Votre adresse e-mail : " read input_mail echo "\$Conf{RsyncClientCmd} = '\$sshPath -q -x -l backuppc \$host sudo \$rsyncPath \$argList+';" >> "${filepl}" echo "\$Conf{RsyncClientRestoreCmd} = '\$sshPath -q -x -l backuppc \$host sudo \$rsyncPath \$argList+';" >> "${filepl}" echo "# host:${fqdn}" >> "${filepl}" cmd_hostkey=$(cat "${hostkey}") echo "# hostkey:${cmd_hostkey}" >> "${filepl}" echo "# mail:${input_mail}" >> "${filepl}" echo "# ip:$(IpAddress)" >> "${filepl}" #### Déplacer le fichier dans le dossier de l'utilisateur (plus accessible) mv -f -- "${filepl}" "${dir1}" #### CRÉATION DE L’UTILISATEUR BACKUPPC #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - Création du compte backuppc" homebackuppc='/var/lib/backuppc' [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Création de l'utilisateur backuppc (homebackuppc=${homebackuppc}) avec des droits sur l'utilisateur (${usr})." AddUserBackuppc "${usr}" "${homebackuppc}" mkdir -p -- "${homebackuppc}"/.ssh [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Création du répertoire .ssh de l'utilisateur backuppc (${homebackuppc}/.ssh)" echo "from=\"129.20.203.16\" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIhMc8ixQXfWDACJy4q0v8T877UxahhCjO51PQFzylwVpf88LX3yWeDrWIW0NRu0zoSm396mig918OpD5ggqML/QbYbQsoDdAFUV/tK4JU6UJgEQIl25MOcUBCFepsFBGS09CH/V07xSUqSP/+beeTRLNO2CQzk3S2y3YfkXpM7KmOGfeLgoCaQAcxIkgLXeM3TpCZEzJDlZ8c8k/DjVvsgwCpQktYzNo2b37KHLLfgyW9KSo6N9sReUuNQjS6lu8rjrXfc6+J0pY2D6IxWptTWL/JVrhFCUqe4QQy+xYjoR41wqnAQyl/kOcyBNhSvojMKwQT6vlPwru6pOno16/X backuppc@backuppc.ipr.univ-rennes1.fr" > "${homebackuppc}"/.ssh/authorized_keys [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : Ajout de la clef SSH du serveur dans (${homebackuppc}/.ssh/authorized_keys)." chown -R backuppc "${homebackuppc}"/.ssh/ [[ "${DEBUG}" == "0" ]] && printf '\e[1;33m%-6s\e[m\n' "DEBUG : chown -R backuppc ${homebackuppc}/.ssh/" #### END #### [[ "${DEBUG}" == "0" ]] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Partie - FIN" printf '%b\n' "Configuration du poste terminée." printf '\e[1;31m%-6s\e[m\n' "Envoyez bien votre fichier de configuration situé dans votre répertoire personnel (${dir1}/${filepl}) à Jérémy GARDAIS (jeremy.gardai@univ-rennes1.fr)." printf '%b\n' "Vous pourrez affiner la configuration de votre sauvegarde depuis https://backuppc.ipr.univ-rennes1.fr" exit 0