#!/bin/bash
#---------------------------------------------------------------------
## @Synopsis A set of functions for the Cabal distributed administration system.
## @Copyright Copyright 2002 by the Source Mage Team. Some parts Copyright 2001 by Kyle Sallee
## Control a set of SourceMage boxes on a network. This documentation was
## written by someone who never used cabal or looked at this code before.
##
## @Globals CABAL_DIRECTORY CABAL_NAMES MAX_CABALS
#---------------------------------------------------------------------

#------------------
## Get the names of the machines in the cabal and store in CABAL
## @Stdout The names of the machines in the cabal
## @Globals CABAL_NAMES CABAL
#------------------
function read_cabal_names()  {

  mkdir  -p  $CABAL_DIRECTORY

  [  -f  $CABAL_NAMES  ] || return

  eval `awk '{ print "CABAL[" NR-1 "]=\"" $0 "\""; }' "$CABAL_NAMES"`

}

#--------------------
## Overwrite the cabal name file with new member names
## @Note The loop can probably be done more intelegently, so a MAX_CABALS is not necessary.
## @Globals CABAL_NAMES MAX_CABALS
#--------------------
function write_cabal_names()  {

  rm  -f  $CABAL_NAMES
  for  ((  COUNT=0;  COUNT != MAX_CABALS;  COUNT++  ));   do
    echo  "${CABALS[$COUNT]}"  >>  $CABAL_NAMES
  done

}

#---------------------
## Print out the member of the cabal (assuming the names have been read)
## @Globals MAX_CABALS
## @Stdout Names of each cabal member
## @NOTE MAX_CABAL can be eliminated
#---------------------
function print_cabal_names()  {

  for  ((  COUNT = 0;  COUNT  !=  MAX_CABALS;  COUNT++  ));  do
    echo  "${CABALS[$COUNT]}"
  done

}

#---------------------
## Outputs the number and name of each cabal member
## @Stdout <number>\n<cabal name or "Undefined"> for all cabal members
## @NOTE Dito about MAX_CABALS
#---------------------
function print_cabal_numbers_names()  {

  for  ((  COUNT = 0;  COUNT  !=  MAX_CABALS;  COUNT++  ));  do
    echo  "$COUNT"
    if    [  -n  "${CABALS[$COUNT]}"  ]
    then  echo   "${CABALS[$COUNT]}"
    else  echo   "Undefined"
    fi
  done

}

#-----------------------
## Pops up a dialog box for selecting a specific cabal member
## @Stdout dialog output
## @Stderr Cabal member selection
#-----------------------
function select_cabal()  {

  eval $DIALOG  '--title         "Cabal Selection Menu"  \
           --ok-label      "Select"                \
           --cancel-label  "Exit"                  \
           --menu                                  \
           "Please Select a Cabal"                 \
           0 0 0                                   \
           $( print_cabal_numbers_names )'

}

#----------------------
## Edit the file about selected members
#----------------------
function edit_cabals()  {

  while  SELECTED=`select_cabal`
  do     edit_file  "$CABAL_DIRECTORY/$SELECTED"
  done

}

#---------------------
## Show contents of a member's info file
#---------------------
function show_cabals()  {

  while  SELECTED=`select_cabal`
  do     show_file  "$CABAL_DIRECTORY/$SELECTED"
  done

}

#--------------------
## Generate SSH key for a cabal member
#--------------------
function generate_cabal_key()  {

  while  SELECTED=`select_cabal`
  do

    mkdir  -p   $CABAL_KEYS
    chmod  600  $CABAL_KEYS

    ssh-keygen  -t  dsa  \
                -b  1024 \
                -N  ""   \
                -f  $CABAL_KEYS/$SELECTED

  done

}


function all_cabal_keys()  {

  for  KEY  in  `ls  $CABAL_KEYS/*  |
                 grep  -v  "\.pub"`
  do  echo  "-i"
      echo  "$KEY"
  done

}


function distribute_cabal_key()  {

  while  SELECTED=`select_cabal`
  do

    mkdir  -p   $CABAL_KEYS
    chmod  600  $CABAL_KEYS

    if  !  [  -e  $CABAL_KEYS/$SELECTED.pub  ];  then
      eval $DIALOG  --msgbox  "Generate the key first!"
      return
    fi

    AK2="/root/.ssh/authorized_keys2"

    cat    $CABAL_DIRECTORY/$SELECTED  |
    while  read  BOX
    do     cat  $CABAL_KEYS/$SELECTED.pub  |
           ssh  `all_cabal_keys`           \
                root@$BOX                  \
                "cat   >>  $AK2;           \
                 sort      $AK2  |         \
                 uniq  >   $AK2"
    done
  done

}


function revoke_cabal_key()  {

  while  SELECTED=`select_cabal`
  do

    mkdir  -p   $CABAL_KEYS
    chmod  600  $CABAL_KEYS

    if  !  [  -e  $CABAL_KEYS/$SELECTED.pub  ];  then
      eval $DIALOG  --msgbox  "No key to revoke!"
      return
    fi

    AK2="/root/.ssh/authorized_keys2"

    cat    $CABAL_DIRECTORY/$SELECTED  |
    while  read  BOX
    do     REVOKE=KEY="`cat  $CABAL_KEYS/$SELECTED.pub`"
           ssh  `all_cabal_keys`                   \
                root@$BOX                          \
                "grep  -v  "$REVOKE_KEY"  $AK2  |  \
                 sort                  >  $AK2"
    done
  done

}


name_cabals()  {

   TITLE="Name Cabals Menu"
    HELP="Please enter cabal's name"

  while  SELECTED=`select_cabal`
  do

    if  NAME=`$DIALOG  --title         "$TITLE"  \
                       --ok-label      "Enter"   \
                       --cancel-label  "Cancel"  \
                       --inputbox                \
                       "$HELP"                   \
                       0 0 ${CABALS[$SELECTED]}`
    then
      CABALS[$SELECTED]="$NAME"
    fi
  done

  write_cabal_names

}


function set_max_cabals()  {

  PROMPT="Please enter the maximum number of cabals"

  if  NEW_MAX=`eval $DIALOG  '--ok-label  "Commit"  \
                        --inputbox            \
                        "$PROMPT"             \
                        0 0  "$MAX_CABALS"'`
  then
    MAX_CABALS=$NEW_MAX
    modify_local_config "MAX_CABALS" $MAX_CABALS
  fi

}


function cabal_name_menu()  {

  while

      HELP=""
    S_HELP="Show the names of the cabals"
    E_HELP="Edit the names of the cabals"
     TITLE="Cabal Name Menu"

    COMMAND=`eval $DIALOG '--title         "$TITLE"            \
                     --item-help                         \
                     --ok-label      "Select"            \
                     --cancel-label  "Exit"              \
                     --menu                              \
                     "$HELP"                             \
                     0 0 0                               \
                     "S"  "Show Cabal Names"  "$S_HELP"  \
                     "E"  "Edit Cabal Names"  "$E_HELP"'`
  do

    case  $COMMAND in
      S)  print_cabal_names  |  $PAGER  ;;
      E)  name_cabals                   ;;
    esac

  done

}


function cabal_key_menu()  {

  while

      HELP="Generate, distribute, and revoke ssh2 keys to cabal computers to 
enable root login without password prompts"
    G_HELP="Create 2048 bit ssh2 dsa public/private keys for a cabal."
    D_HELP="Install the public key on all computer members of cabal."
    R_HELP="Remove a previously installed cabal key"
     TITLE="Cabal Key Menu"

    COMMAND=`eval $DIALOG '--title         "$TITLE"                 \
                     --item-help                              \
                     --ok-label      "Select"                 \
                     --cancel-label  "Exit"                   \
                     --menu                                   \
                     "$HELP"                                  \
                     0 0 0                                    \
                     "G"  "Generate    Cabal Key"  "$G_HELP"  \
                     "D"  "Distribute  Cabal Key"  "$D_HELP"  \
                     "R"  "Revoke      Cabal Key"  "$R_HELP"'`
  do

    case  $COMMAND in
      G)  generate_cabal_key    ;;
      D)  distribute_cabal_key  ;;
      R)  revoke_cabal_key      ;;
    esac

  done

}


function cabal_content_menu()  {

  while

      HELP=""
    S_HELP="Show the computers which belong to a cabal"
    E_HELP="Edit the computers which belong to a cabal"
     TITLE="Cabal Content Menu"

    COMMAND=`eval $DIALOG '--title         "$TITLE"       \
                     --item-help                    \
                     --ok-label      "Select"       \
                     --cancel-label  "Exit"         \
                     --menu                         \
                     "$HELP"                        \
                     0 0 0                          \
                     "S"  "Show  Cabal"  "$S_HELP"  \
                     "E"  "Edit  Cabal"  "$E_HELP"'`
  do

    case  $COMMAND in
      S)  show_cabals  ;;
      E)  edit_cabals  ;;
    esac

  done

}


function select_order()  {

  eval $DIALOG  '--title  "Order Selection Menu"  \
           --menu  ""  0 0 0                \
           "S"  "Sequentially"              \
           "C"  "Concurrently"'

}


function cabal_admin_menu()  {

  while

      HELP=""
    M_HELP="Define maximum amount of cabals."
    N_HELP="Define and display the names of cabals"
    C_HELP="Define and display the computers belong to a cabal"
    K_HELP="Generate and distribute keys for cabals"
     TITLE="Cabal Admin Menu"

    COMMAND=`eval $DIALOG '--title         "$TITLE"                 \
                     --item-help                              \
                     --ok-label      "Select"                 \
                     --cancel-label  "Exit"                   \
                     --menu                                   \
                     "$HELP"                                  \
                     0 0 0                                    \
                     "N"  "Cabal Name       Menu"  "$N_HELP"  \
                     "C"  "Cabal Content    Menu"  "$C_HELP"  \
                     "K"  "Cabal Key        Menu"  "$K_HELP"  \
                     "M"  "Maximum Cabals:  $MAX_CABALS"   "$M_HELP"'`

  do

    case  $COMMAND in
      N)  cabal_name_menu     ;;
      C)  cabal_content_menu  ;;
      K)  cabal_key_menu      ;;
      M)  set_max_cabals      ;;
    esac

  done

}


function cabal_copy()  {

  SOURCE_MESSAGE="Please enter source files and directories."
    DEST_MESSAGE="Please enter destination directory."

  mkdir  -p  $CABAL_OUTPUT || {
    messasge "Failed to make CABAL_OUTPUT directory $CABAL_OUTPUT"
    exit 1
  }

       SOURCE=`eval $DIALOG  --inputbox  "$SOURCE_MESSAGE"  0 0`  &&
  DESTINATION=`eval $DIALOG  --inputbox  "$DEST_MESSAGE"    0 0`  &&
        CABAL=`select_cabal`                                 &&
        ORDER=`select_order`                                 &&

  case  $ORDER  in
    C)  cat  $CABAL_DIRECTORY/$CABAL  |
        while  read  BOX;  do  
          scp  -i  $CABAL_KEYS/$CABAL    \
               -r  $SOURCE               \
               root@${BOX}:$DESTINATION  \
          >  $CABAL_OUTPUT/$BOX          &
        done
        ;;
    S)  cat  $CABAL_DIRECTORY/$CABAL  |
        while  read  BOX;  do  
          scp  -i  $CABAL_KEYS/$CABAL    \
               -r  $SOURCE               \
               root@${BOX}:$DESTINATION
        done
        read  -n 1  -p  "Press any key to continue"
        ;;
  esac

}


function cabal_execute()  {

  COMMAND_MESSAGE="Please enter command to be execute remotely on cabal."

  mkdir  -p  $CABAL_OUTPUT || {
    messasge "Failed to make CABAL_OUTPUT directory $CABAL_OUTPUT"
    exit 1
  }

  COMMAND=`eval $DIALOG  '--inputbox  "$COMMAND_MESSAGE"  0 0'`  &&
    CABAL=`select_cabal`                                  &&
    ORDER=`select_order`                                  &&

  case  $ORDER  in
    C)  cat  $CABAL_DIRECTORY/$CABAL  |
        while  read  BOX;  do  
          ssh  -i  $CABAL_KEYS/$CABAL  \
                   root@${BOX}         \
                   "$COMMAND"          \
          >  $CABAL_OUTPUT/$BOX        &
        done
        ;;

    S)  cat  $CABAL_DIRECTORY/$CABAL  |
        while  read  BOX;  do  
          ssh  -i  $CABAL_KEYS/$CABAL  \
                   root@${BOX}         \
                   "$COMMAND"
        done
        read  -n 1  -p  "Press any key to continue"
        ;;
  esac

  sleep  10

}


function cabal_output()  {

  if  [  -d  $CABAL_OUTPUT  ];  then
    for  FILE  in  `ls  $CABAL_OUTPUT`;  do
      echo  "$FILE  Beginning Output"
      cat   $CABAL_OUTPUT/$FILE
      echo  "$FILE  Ending Output"
    done
  fi
}


function cabal_enchantment_menu()  {

  while

      HELP=""
    C_HELP="Copy files and directories to cabals via scp"
    E_HELP="Execute commands on cabals"
    S_HELP="Show the output of previously execute concurrent commands and 
copies"
     TITLE="Enchantment Menu"

    COMMAND=`eval $DIALOG '--title         "$TITLE"   \
                     --item-help                \
                     --ok-label      "Select"   \
                     --cancel-label  "Exit"     \
                     --menu                     \
                     "$HELP"                    \
                     0 0 0                      \
                     "C"  "Copy"     "$A_HELP"  \
                     "E"  "Execute"  "$E_HELP"  \
                     "S"  "Show"     "$S_HELP"'`

  do

    case  $COMMAND in
      C)  cabal_copy               ;;
      E)  cabal_execute            ;;
      S)  cabal_output  |  $PAGER  ;;
    esac

  done

}


function cabal_menu()  {

  while

    read_cabal_names

      HELP="Administrate Multiple Boxes Simultaneously With Cabal"
    A_HELP="Set up Cabals"
    E_HELP="Execute scripts and copy files."
     TITLE="Cabal Menu"

    COMMAND=`eval $DIALOG '--title         "$TITLE"          \
                     --item-help                       \
                     --ok-label      "Select"          \
                     --cancel-label  "Exit"            \
                     --menu                            \
                     "$HELP"                           \
                     0 0 0                             \
                     "A"  "Administration"  "$A_HELP"  \
                     "E"  "Enchantment"     "$E_HELP"'`

  do

    case  $COMMAND in
      A)  cabal_admin_menu        ;;
      E)  cabal_enchantment_menu  ;;
    esac

  done

}

. /etc/sorcery/config
DIALOG='$DIALOGPROG  --backtitle "Sorcery Spell Management Utility" --stdout'
cabal_menu

#---------------------------------------------------------------------
##=back
##
##=head1 LICENSE
##
## This software is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This software is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
##
#---------------------------------------------------------------------
