#!/bin/bash
#-------------------------------------------------------
# file:		cliente_ssh.sh
# comment:	Abre uma conexão SSH num host remoto usando o fwknop-client
# author:	Aecio Pires <aeciopires@gmail.com>
# date:		22-ago-2009
# revision:	Aecio Pires <aeciopires@gmail.com>
# Last updated:	24-ago-2010, 17:00
#-------------------------------------------------------

# OBS.: 
#	1- De permissao de execucao a este script com o comando:
#		 chmod +x cliente_ssh.sh
#	   Depois execute-o com o seguinte comando.
# 	   	 Sintaxe: ./cliente_ssh.sh
#
#       2- Este script só foi testado no Ubuntu 9.04, 9.10 e 10.04


################################################################
# Funcoes Gerais 
################################################################

#------------------------------------------------------------
# Pega o IP da maquina. Se houver mais de um, dah preferencia aos
# enderecos das interfaces em ordem alfabetica eth0, eth1, wlan0 nesta ordem, exceto a loopback (lo).
getmyipaddress(){
for iface in $(/sbin/ifconfig | grep -v lo | cut -d" " -f1 | sort -u) ; do
	IP=$(/sbin/ifconfig $iface | grep -i bcast | cut -d":" -f2 | tr -d "[a-zA-Z ]" | cut -d" " -f2)
	[ ! -z $IP ] && break
done
echo $IP
}

#----------------------------------------------------
# comment: Converte letras minusculas para maiusculas
# syntax: AUX=$(toupper $STRING)
# return: $AUX contendo a string com letras maiusculas
# 
toupper(){
	echo $* | tr '[a-z]' '[A-Z]'
}

#----------------------------------------------------
# comment: Converte letras maiusculas para minusculas
# syntax: AUX=$(tolower $STRING)
# return: $AUX contendo a string com letras minusculas
# 
tolower(){
	echo $* | tr '[A-Z]' '[a-z]'
}

#----------------------------------------------------
# mesmo que 'ask' (veja neste arquivo), mas nao permite resposta vazia
asknoempty(){
	OPTION=""
	[ "$1" = -u -o "$1" = -upper ] && OPTION="-u" && shift
	[ "$1" = -l -o "$1" = -lower ] && OPTION="-l" && shift
	QUESTION="$1"
	POSSIBLE_ANSWERS="$2"
	SHOW_POSSIBLE_ANSWERS="$3"
	DEFAULT_ANSWER="$4"
	SECRET_OPTION=${5:-N}

	MYANSWER=""
	while [ -z "$MYANSWER" ] ; do
		MYANSWER=$(ask $OPTION "$QUESTION" "$POSSIBLE_ANSWERS" "$SHOW_POSSIBLE_ANSWERS" "$DEFAULT_ANSWER" "$SECRET_OPTION")
		[ -z "$MYANSWER" ] && echo "Nao aceito valor vazio. Digite algo." > /dev/tty
	done
	echo $MYANSWER
}

#----------------------------------------------------
# mesmo que 'asknoempty' (veja neste arquivo), mas nao permite espacos no string
# digitado
asknoemptynospace(){
	OPTION=""
	[ "$1" = -u -o "$1" = -upper ] && OPTION="-u" && shift
	[ "$1" = -l -o "$1" = -lower ] && OPTION="-l" && shift
	QUESTION="$1"
	POSSIBLE_ANSWERS="$2"
	SHOW_POSSIBLE_ANSWERS="$3"
	DEFAULT_ANSWER="$4"
	SECRET_OPTION=${5:-N}

	HASSPACES=Y
	while [ $HASSPACES = Y ] ; do
		MYANSWER=$(asknoempty $OPTION "$QUESTION" "$POSSIBLE_ANSWERS" "$SHOW_POSSIBLE_ANSWERS" "$DEFAULT_ANSWER" "$SECRET_OPTION")
		COUNT=$(echo "$MYANSWER" | grep " "  | wc -l)
		[ $COUNT -eq 1 ] && echo "Digite um string sem espacos." > /dev/tty || HASSPACES=N
	done
	echo $MYANSWER
}

#----------------------------------------------------
# pergunta alguma coisa ao usuario
# Sintaxe: ask [-u] PERGUNTA RESPOSTAS_POSSIVEIS RESPOSTA_DEFAULT ESCONDE_DIGITACAO
# Onde: PERGUNTA eh o texto que será mostrado ao usuario
#       RESPOSTAS_POSSIVEIS eh a lista de strings permitidos para digitacao separados por virgula.
#                           Ele insiste na pergunta enquanto um string invalido for digitado.
#       RESPOSTA_DEFAULT eh a resposta adotada caso o usuario digite ENTER
#       ESCONDE_DIGITACAO: Quando=Y, indica se deve esconder o que o usuario digita (ex: senhas)
#       -u eh um parametro opcional que, quando usado, converte a resposta do usuario para maiusculas
#
ask(){
	OPTION=""
	[ "$1" = -u -o "$1" = -upper ] && OPTION="-u" && shift
	[ "$1" = -l -o "$1" = -lower ] && OPTION="-l" && shift
	QUESTION="$1"
	VALID_ANSWERS="$2"
	VALID_ANSWERS_SHOW="$3"
	DEFAULT_ANSWER="$4"
	SECRET_OPTION=${5:-N}

	[ "$SECRET_OPTION" = Y ] && SECRET="-s"
	[ ! -z "$VALID_ANSWERS_SHOW" ] && PREFIX=" [" && SUFFIX="]"
	ANSWERED=FALSE
	while [ $ANSWERED = FALSE ] ; do
		
		echo -ne "${QUESTION}${PREFIX}${VALID_ANSWERS_SHOW}${SUFFIX} " > /dev/tty
		read $SECRET ANSWER
		[ -z "$ANSWER" ] && ANSWER=$DEFAULT_ANSWER
		if [ -z "$VALID_ANSWERS" ] ; then
			ANSWERED=TRUE
		else
			COUNT=$(echo "$VALID_ANSWERS" | grep -w "$ANSWER"  | wc -l)
			[ $COUNT -eq 1 ] && ANSWERED=TRUE
		fi
		[ "$SECRET_OPTION" = Y ] && echo "" > /dev/tty
	done
	if [ "$OPTION" = "-u" ] ; then
		toupper $ANSWER 
	elif [ "$OPTION" = "-l" ] ; then 
		tolower $ANSWER
	else 
		echo $ANSWER
	fi
}

#------------------------------------------------------------
# comment: Exibe as mensagens (Se a variavel $VERBOSE estiver com o valor 'YES')
# syntax: message "Texto da mensagem"
# return: Exibe a mensagem na saida padrao
#
message(){
[ "$VERBOSE" = YES ] && echo $*
}

#------------------------------------------------------------
# comment: Verifica se arquivos existem. Os nomes dos arquivos sao passados como parametro.
#          Se algum nao existe, escreve "NO" na saída. Se todos existem, escreve "YES".
# syntax: existfiles
# return: YES ou NO
#
existfiles(){
	OK=YES
	for file in "$@" ; do
		#echo "verificando arquivo $file ..." > /dev/tty
		[ ! -f $file ] && echo "Nao encontrei o(s) arquivo(s) \"$file\"" > /dev/tty && OK=NO
	done
	[ $OK = YES ] && return 0 || return 1
}

#-----------------------------------------------------------
# comment: Obtem o nome e o codnome da distribuicao
# syntax: LINUXDISTRO=$(get_linux_distro)
#         LINUXCODENAME=$(get_linux_distro -codename)
# return: $LINUXDISTRO contem o nome da distro e $LINUXCODENAME contem o codnome da distro
#
get_linux_distro(){
LINUXCODENAME=UNKNOWN
LINUXDISTRO=UNKNOWN

# Obtendo o nome da distro
grep "Debian" /etc/issue > /dev/null 2>&1 && LINUXDISTRO=DEBIAN 
grep "Ubuntu" /etc/issue > /dev/null 2>&1 && LINUXDISTRO=UBUNTU
grep "Red Hat Enterprise" /etc/issue > /dev/null 2>&1 && LINUXDISTRO=REDHAT
grep "Fedora" /etc/issue > /dev/null 2>&1 && LINUXDISTRO=FEDORA

# Obtendo o codnome da distro
grep "Red Hat Enterprise Linux Server release 5.[234] (Tikanga)" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=Tikanga

grep "Debian GNU/Linux 5.0" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=lenny
grep "Debian GNU/Linux 4.0" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=etch
grep "Debian GNU/Linux 6.0" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=squeeze
grep "Debian GNU/Linux 3.1" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=sarge
grep "Debian GNU/Linux 3.0" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=woody
grep "Debian GNU/Linux 2.2" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=potato
grep "Debian GNU/Linux 2.1" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=slink
grep "Debian GNU/Linux 2.0" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=hamm

grep "Ubuntu 6.06.2" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=dapper
grep "Ubuntu 6.10"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=edgy
grep "Ubuntu 7.04"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=feisty
grep "Ubuntu 7.10"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=gutsy
grep "Ubuntu 8.04.2" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=hardy
grep "Ubuntu 8.10"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=intrepid
grep "Ubuntu 9.04"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=jaunty
grep "Ubuntu 9.10"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=karmic
grep "Ubuntu 10.04"   /etc/issue > /dev/null 2>&1 && LINUXCODENAME=lucid

grep "Fedora release 13" /etc/issue > /dev/null 2>&1 && LINUXCODENAME=goddard

[ "$1" = "-codename" ] && echo $LINUXCODENAME || echo $LINUXDISTRO
}

#------------------------------------------------------------
# comment: Testa se o script tem suporte a distro detectada.
# syntax: test_distro_suport
#
test_distro_suport(){

        case $LINUXDISTRO in
	DEBIAN)
	        message "Este script nao esta preparado para esta distro."
	        exit 1
	        ;;
	UBUNTU)
	        case $LINUXCODENAME in
			jaunty)
			        message "Suporte OK"
			;;
			karmic)
			        message "Suporte OK"
			;;
			lucid)
			        message "Suporte OK"
			;;
			*)
			        message "Este script nao esta preparado para esta distro."
			        exit 1
			;;
	        esac
	        ;;
	REDHAT)
       	        message "Este script nao esta preparado para esta distro."
	        ;;
	FEDORA)
	        message "Este script nao esta preparado para esta distro."
	        exit 1
		;;
	 *)
                message "Este script nao esta preparado para esta distro."
                exit 1
	        ;;
	esac

}

################################################################
# Funcoes Especificas
################################################################

connect_fwknop_server(){

REMOTE_IPADDR=$(asknoempty "Qual o IP do servidor SSH" "" "$REMOTE_IPADDR" "$REMOTE_IPADDR" )
SSH_PORT=$(asknoempty "Qual a porta do servidor SSH" "" "$SSH_PORT" "$SSH_PORT" )

$FWKNOP -A "tcp/$SSH_PORT" -a $MYIPADDR -D $REMOTE_IPADDR

message "Pronto! Agora você tem 30s para abrir uma sessão SSH ou usar o SCP para enviar algo ao host $REMOTE_IPADDR"
message ""
message "Se este tempo expirar, execute este script novamente"

}

#-----------------------------------------------
#-----------------------------------------------
# MAIN 
#-----------------------------------------------
#-----------------------------------------------

################################################################
# Declaracao de variaveis globais
################################################################
LINUXDISTRO=$(get_linux_distro)
LINUXCODENAME=$(get_linux_distro -codename)
MYIPADDR=$(getmyipaddress)
REMOTE_IPADDR=192.168.0.254
SSH_PORT=2220
FWKNOP=/usr/bin/fwknop


test_distro_suport

existfiles $FWKNOP || exit 1

connect_fwknop_server


