instituto federal de educaÇÃo, ciÊncia e...
TRANSCRIPT
INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA
E TECNOLOGIA CATARINENSE – CAMPUS SOMBRIO
ARONI SILVEIRA DAL PONT
PORTAL DE AUTENTICAÇÃO COM MONITORAMENTO NA
INFRAESTRUTURA DO INSTITUTO FEDERAL CATARINENSE – CAMPUS
SOMBRIO
Sombrio
2013
ARONI SILVEIRA DAL PONT
PORTAL DE AUTENTICAÇÃO COM MONITORAMENTO NA
INFRAESTRUTURA DO INSTITUTO FEDERAL CATARINENSE – CAMPUS
SOMBRIO
Trabalho de Conclusão de Curso apresentado ao Curso
Superior de Tecnologia em Redes de Computadores do
Instituto Federal de Educação, Ciência e Tecnologia
Catarinense, como requisito parcial à obtenção do título
de Tecnólogo em Redes de Computadores do Instituto
Federal de Educação, Ciência e Tecnologia Catarinense
– Campus Sombrio.
Orientador: Prof. Msc. Jéferson Mendonça de Limas
Coorientador: Prof. Msc Gerson Luis da Luz
Sombrio
2013
ARONI SILVEIRA DAL PONT
PORTAL DE AUTENTICAÇÃO COM MONITORAMENTO NA
INFRAESTRUTURA DO INSTITUTO FEDERAL CATARINENSE – CAMPUS
SOMBRIO
Este Trabalho de Conclusão de Curso foi julgado
adequado à obtenção do título de Tecnólogo em Redes
de Computadores e aprovado em sua forma final pelo
Curso Superior de Tecnologia em Redes de
Computadores do Instituto Federal de Educação,
Ciência e Tecnologia Catarinense – Campus Sombrio.
Sombrio, 07 de dezembro de 2013.
______________________________________________________
Professor e orientador Jéferson Mendonça de Limas, Msc.
Instituto Federal de Educação, Ciência e Tecnologia Catarinense – Campus Sombrio
Orientador
______________________________________________________
Prof. Lucyene Lopes da Silva Todesco Nunes, Msc.
Instituto Federal de Educação, Ciência e Tecnologia Catarinense – Campus Sombrio
Membro
______________________________________________________
Prof. Marco Antonio Silveira de Souza, Msc.
Instituto Federal de Educação, Ciência e Tecnologia Catarinense – Campus Sombrio
Membro
Dedico esta produção a minha família,
principalmente minha esposa que muitas
noites ficou a cuidar sozinha de nossa filha e
pelo apoio e motivação para continuar nos
momentos de cansaço e desânimo nesta etapa
de minha vida.
AGRADECIMENTOS
Primeiramente agradeço a Deus por ter saúde, trabalho e uma família muito, mas
muito especial. Agradeço a minha esposa Luciani Q. da Cunha Dal Pont por entender minha
ausência e por sempre dar uma palavra de incentivo durante esta jornada. Aos professores
pela dedicação em compartilhar seus conhecimentos e pela compreensão dos atrasos no inicio
das aulas. Aos colegas que sempre tivemos uma relação de amizade e companheirismo
compartilhando conhecimentos. E por fim ao professor Orientador Jéferson Mendoça de
Limas que não poupou esforços para que eu concluísse este trabalho.
RESUMO
Este trabalho tem o intuito de documentar a implantação de um servidor de gerenciamento,
com ferramentas de autenticação e captura de dados junto aos outros servidores do Instituto
Federal Catarinense Campus Sombrio (IFC-Sombrio). Nele será implementado a ferramenta
Coovachilli, fazendo com que o usuário aluno ou servidor tenha que colocar através do
navegador seu login e senha para ter acesso à internet, que após autenticação efetuada no
servidor FreeRADIUS, o armazena em um banco de dados MySQL. Junto a este processo
colocou-se a ferramenta Ngrep para a captura de dados determinados pelo administrador, no
uso do facebook, youtube e twiter, meios de acesso que não são para estudos ou trabalho do
IFC-Campus Sombrio. Todos os acessos de usuários serão colocados em arquivos de texto, e
a linguagem Shell Script fará o tratamento dos dados, e através de uma pagina html será
mostrado ao administrador o tempo de uso gasto nas redes sociais por usuário.
Palavras-chave: CoovaChilli. FreeRADIUS. ShellScript.
ABSTRACT
This study aims to document the implementation of a management server with authentication
tools and capture data from the other servers in the Santa Catarina Federal Institute Campus
dingy (IFC-dingy). In it the Coovachilli tool will be implemented, making the student user or
server has to put through the browser your login and password to access the internet, which
performed after authentication in FreeRADIUS server, stores it in a MySQL database Along
the this process was placed the ngrep tool to capture data determined by the administrator, the
use of facebook, youtube and twiter, means of access which are not to study or work of IFC-
Campus dingy. All user access will be placed in text files, and Shell Script language will treat
the data, and through a html page will be shown to the administrator use time spent on social
networks per user.
Keywords : CoovaChilli. FreeRADIUS. ShellScript.
LISTA DE ILUSTRAÇÕES
Figura 1 - Redes ponto a ponto ............................................................................................... 15
Figura 2 - Redes em estrela ..................................................................................................... 15
Figura 3 - Redes em anel ......................................................................................................... 16
Figura 4 - Redes em Barramento ............................................................................................. 16
Figura 5 - Redes mistas ........................................................................................................... 17
Figura 6 - Redes ponto-multiponto ......................................................................................... 18
Figura 7 - Tratamento de conexão CoovaChilli. ..................................................................... 25
Figura 8 - Captura Ngrep das URLs ........................................................................................ 26
Figura 9 - Topologia Lógica da Rede ...................................................................................... 31
Figura 10 - Arquivo interfaces editado para funcionamento ................................................... 32
Figura 11 - Arquivo editado sql.conf. ..................................................................................... 33
Figura 12 - Arquivo editado clients.conf ................................................................................. 34
Figura 13 - Teste de funcionamento do FreeRADIUS ............................................................ 35
Figura 14 - Arquivo config editado ......................................................................................... 35
Figura 15 - Arquivo hotspot editado ....................................................................................... 36
Figura 16 - Captura login e senha Coovachilli ........................................................................ 37
Figura 17 - Arquivo captura Ngrep ......................................................................................... 38
Figura 18 - Filtro dos dados capturados pelo Ngrep ............................................................... 39
Figura 19 – Importação arquivo texto para tabela MySQL. .................................................... 39
Figura 20 - Consulta de tabelas MySQL ................................................................................. 40
Figura 21 - Código HTML para pagina web ........................................................................... 40
Figura 22 - Código PHP para pagina web. .............................................................................. 41
Figura 23 - Pagina web com relatório final ............................................................................. 42
LISTA DE SIGLAS
AAA: (Autenticação, Autorização e Contabilização)
ACK: (Acknowledgment)
ASC: (Access Control Server)
ASCII: (American Standard Code for Information Interchange)
BNC: (Bayonet Neill–Concelman)
BPF: (BSD Packet Filter)
CHAP: (Challenge-Handshake Authentication Protocol)
EAP: (Extensible Authentication Protocol)
FDDI: (Fiber Distributed Data Interface)
GB: (Gigabyte)
GBPS: (Gigabits Por Segundo)
GPL: (General Public License)
HTML: (HyperText Markup Language)
HTTP: (Hypertext Transfer Protocol)
HTTPS: (HyperText Transfer Protocol Secure)
IAS: (Internet Authentication Service)
ICMP: (Internet Control Message Protocol)
IFC: (Instituto Federal Catarinense)
IGMP: (Internet Group Management Protocol)
IP: (Internet Protocol)
LAN: (Local Area Network)
MAN: (Metropolitan Area Network)
MBPS: (Megabits Por Segundo)
NAK: (Not Acknowledgment)
NAS: (Network Attached Storage)
PAP: (Password Authentication Protocol)
PPP: (Point-to-Point Protocol)
RFC: (Request For Coments)
SLIP: (Serial Line Internet Protocol)
SNMP: (Simple Network Management Protocol)
SO: (Sistema Operacional)
TCP: (Transmission Control Protocol)
UDP: (User Datagram Protocol)
WAN: (Wide Area Network)
YYYY / MM / DD HH: MM: SS.UUUUUU: (Ano/Mês/Dia Hora: Minuto: Segundos)
SUMÁRIO
1 INTRODUÇÃO................................................................................................................. 11
2 OBJETIVOS ..................................................................................................................... 13
2.1 OBJETIVO GERAL ........................................................................................................ 13
2.2 OBJETIVOS ESPECÍFICOS........................................................................................... 13
3 REFERENCIAL TEÓRICO ........................................................................................... 14
3.1 REDES DE COMPUTADORES ..................................................................................... 14
3.1.1 Redes Locais (LANs) ................................................................................................... 14
3.1.2 Redes Geograficamente Distribuídas (WANs) ......................................................... 17
3.2 GERÊNCIA DE REDES ................................................................................................. 18
3.2.1 Requisitos de Gerenciamento ..................................................................................... 19
3.3 AUTENTICAÇÃO DE USUÁRIOS ............................................................................... 20
3.3.1 RADIUS........................................................................................................................ 21
3.3.1.1 Métodos de Autenticação ........................................................................................... 22
3.3.1.2 FreeRADIUS .............................................................................................................. 23
3.4 COOVACHILLI .............................................................................................................. 24
3.5 NGREP ............................................................................................................................ 25
3.6 SHELL SCRIPT ............................................................................................................... 26
4 MATERIAL E MÉTODOS ............................................................................................. 29
4.1 TIPO DE PESQUISA ...................................................................................................... 29
4.2 MATERIAIS .................................................................................................................... 29
4.4 INSTALAÇÃO E CONFIGURAÇÃO ............................................................................ 31
5 RESULTADOS E DISCUSSÃO ...................................................................................... 42
6 CONSIDERAÇÕES FINAIS ........................................................................................... 43
REFERÊNCIAS ..................................................................................................................... 44
ANEXOS ................................................................................................................................. 46
11
1 INTRODUÇÃO
O estudo das tecnologias está trazendo cada vez mais aplicativos que nos ajudam a
resolver problemas para as redes de computadores e nos diversos outros seguimentos da
informática. O tema tratado é a implantação de uma ferramenta que ajuda a ter controle sobre
os acessos dos usuários a Internet. Aplicar-se-á o estudo em autenticar e controlar a rede
através de um servidor FreeRADIUS com um portal de autenticação para os usuários se
identificarem antes do acesso a Internet. Nestes aplicativos será implantado também um
monitoramento que ajudará a verificar quais os sites de mais acesso por usuário.
Para Filagrana (2002) a autenticação é sinônimo de segurança, pois torna os acessos
restritos a uma permissão, fazendo com que só pessoas autorizadas tenham acesso às
informações de acesso a Web.
Tendo em vista a dificuldade de alunos e professores na navegação de sites e
conteúdos da Internet, ter controle sobre o tráfego que cada usuário pode utilizar é uma
maneira de tornar os serviços de rede mais eficientes.
No Instituto Federal Catarinense Campus Sombrio (IFC – Sombrio), a rede de
computadores e Internet não possui um controle de acesso de usuários, com identificação e
controle de velocidade, muitas vezes deixando o serviço de navegação Web prejudicado. Que
ferramentas implantar na infraestrutura de rede para autenticar e monitorar os acessos dos
usuários? Durante os estudos foi possível identificar uma variedade muito grande de
ferramentas úteis para realizar as tarefas de autenticação e monitoramento de acessos de
usuários, escolheu-se as seguintes devido a grande documentação e facilidade de
implementação: Coovachilli, FreeRADIUS, Apache2, Ngrep e Shell Script.
Estes aplicativos instalados dentro do sistema operacional Ubuntu Server 12.04 terão
tarefas de proteger, controlar e mostrar os sites que passam na rede de computadores do IFC –
Campus Sombrio.
Com um banco de dados juntam-se os controles de usuário e senha feitos através do
FreeRADIUS, além dos dados da captura do Ngrep. Com o uso de shell script foi gerado uma
pagína html com resultado do tempo de uso destes sites por usuário.
A estrutura deste Trabalho de Conclusão de Curso está explanada da seguinte forma: o
capitulo 2 com os objetivos alcançados, capítulo 3 com a fundamentação teórica trazendo o
básico de redes de computadores e a base das ferramentas usadas. O capítulo 4 traz o tipo de
12
pesquisa, os métodos, os materiais, a instalação e configuração dos arquivos necessários ao
funcionamento da implantação do serviço. O capítulo 5 que relata os objetivos alcançados,
não realizados e os resultados e o capítulo 6 define o trabalho mostrando as dificuldades
elencadas, as soluções dos problemas, a explicação dos objetivos não alcançados e a proposta
de trabalhos futuros no mesmo seguimento.
13
2 OBJETIVOS
Neste contexto encontram-se os objetivos a serem concluídos ao final do projeto.
2.1 OBJETIVO GERAL
Implementar serviços capazes de autenticar e monitorar os usuários da infraestrutura
de redes do Instituto Federal Catarinense – Campus Sombrio.
2.2 OBJETIVOS ESPECÍFICOS
Usar como ferramenta de implementação os seguintes serviços:
a) Implantar serviço de autenticação;
b) Implantar serviço de captura de dados na rede;
c) Implantar serviço para gerenciamento de portal para login de acesso; e
d) Implementar software para manipular os resultados das ferramentas de
autenticação, monitoramento e gerenciamento.
14
3 REFERENCIAL TEÓRICO
Neste tópico mostra-se através de autores o projeto de autenticação e monitoramento
de redes, por soluções de software. Além de descrever sobre a documentação e o
conhecimento das redes de computadores.
3.1 REDES DE COMPUTADORES
As redes de computadores realmente ganharam força no início da década de 1980
descobrindo que os computadores pessoais ou individuais não trariam um avanço, pois
ficaram presos aos seus próprios recursos. Neste intuito surgiu à palavra mágica do ápice das
redes de computadores, “O COMPARTILHAMENTO” (MORAES, 2010).
Segundo Souza (2009), podemos definir rede de computadores como um conjunto de
equipamentos interligados trocando informações, compartilhando recursos e a rápida troca de
mensagens, conectados por cabos e dispositivos em um ambiente interno ou externo, com as
redes LANs e WANs.
3.1.1 Redes Locais (LANs)
São redes privadas dentro de uma instituição, empresas, edifícios ou alguns
quilômetros interligando computadores e ativos de rede para compartilhamento de dados e
envio de mensagens. As LANs possuem três modos de se diferenciar das outras: o tamanho
restrito da rede, que facilita o gerenciamento, a tecnologia de transmissão, que consiste em
conexões através de cabos, com pouquíssimos erros e funcionam em velocidades de 10Mbps,
100Mbps chegando até 10Gbps e a topologia que pode ser ponto a ponto, estrela, anel e
barramento (TANENBAUM, 2003).
15
A topologia ponto a ponto (figura 1) são dois pontos conectados diretamente que
trocam informações um como receptor e o outro transmissor, forma esta mais comum que
temos (SOUZA, 2009).
Figura 1 - Redes ponto a ponto
Fonte: MARTINEZ, 2010
Segundo Moraes, (2010) a topologia de redes em estrela (figura 2) caracteriza-se por
todos os hosts se conectarem em um núcleo central, podendo ser este, um roteador, um switch
ou um hub. Como o nó fica centralizado qualquer problema que acontecer com o mesmo toda
rede fica prejudicada, mas ao mesmo tempo tornam-se de fácil detecção e correção de falhas.
Figura 2 - Redes em estrela
Fonte: MARTINEZ, 2010
Na topologia de rede em anel (figura 3) são arquiteturas que todos os hosts estão
conectados por cabo em formato circular, sendo obrigatório que os dados passem por todos os
nós da rede, até encontrar seu destino. Os dados transmitidos são transportados em um único
sentido, fazendo assim com que se um nó falhar toda a rede fique prejudicada (SOUZA,
2009).
16
Figura 3 - Redes em anel
Fonte: MARTINEZ, 2010
Barramento é uma topologia cuja conexão é feita através de cabo coaxial, com
conector BNC inserindo os hosts ao longo do cabo e por fim conectores de terminação,
mostrado na figura 4. Nesta topologia de rede, o rompimento do cabo em qualquer parte da
rede para todo funcionamento da mesma (MORAES, 2010).
Figura 4 - Redes em Barramento
Fonte: MARTINEZ, 2010
Segundo Martinez (2010), redes mistas são complexas e muito utilizadas em grandes
redes. Nela pode-se encontrar uma mistura de topologias, tais como as de anel, estrela,
barramento, entre outras, que possuem como características as ligações ponto a ponto e
multiponto, usada principalmente que interconectar duas redes de topologias diferentes.
Identificado na figura 5.
17
Figura 5 - Redes mistas
Fonte: MARTINEZ, 2010
3.1.2 Redes Geograficamente Distribuídas (WANs)
As redes WAN ou mais conhecida como rede de longas distâncias, tem abrangência de
grandes regiões geográficas, pontos entre cidades, estados, países e continentes, através dos
cabos de cobre, satélite, micro-ondas e fibras como meios de transmissão mais comuns
(MORAES, 2010).
Dentro de WAN existem as redes metropolitanas (MANs) como um subitem. É todo e
qualquer tipo de conexão distribuindo Internet ou dados por uma rede abrangendo uma cidade
pode ser chamada de MAN, podendo ser por cabos coaxiais, fibras ou por ondas
eletromagnéticas através de antenas sem fio (TANENBAUM, 2003).
Toda rede WAN contém numerosas linhas de transmissão, todas conectadas a vários
roteadores. Quando um host em qualquer rede LAN for se comunicar com outro host em outra
rede LAN, seus dados serão encaminhados através de uma linha de transmissão para um
roteador e através de outros roteadores conectados a ele que os dados chegarão ao seu destino
na outra rede LAN (TANENBAUM, 2003).
Nas redes WAN usa-se a arquitetura multiponto ou ponto-multiponto, onde uma
informação sai de um ponto principal em um único meio de transmissão e é dividida para
vários pontos por meios de endereços lógicos diferentes como mostra na figura 6 (SOUZA,
2009). Um bom exemplo desta rede WAN é a Internet (TORRES, 2009).
18
Figura 6 - Redes ponto-multiponto
Fonte: NETVOX, 2013.
3.2 GERÊNCIA DE REDES
Segundo Stallings (2005), gerenciamento de rede é um conjunto de ferramentas
instaladas em um ambiente de rede, capaz de gerenciar através dos endereços e rótulos
atribuídos a cada ponto, e os atributos de cada host e enlace conhecido ao sistema. O
gerenciamento é necessário para o controle e monitoramento das redes LANs e WANs. Uma
grande rede não pode ser gerenciada apenas pelo administrador, mas sim ter o suporte de
ferramentas que o auxiliem no seu trabalho.
Para o gerenciamento instala-se um software cliente nos ativos de rede e um software
de gerenciamento em um equipamento central, assim o cliente envia informações para o
gerenciador e transforma em informações para o administrador, ou até mesmo transforma em
mensagens de avisos e guarda em um banco de dados (SOUZA, 2009).
19
3.2.1 Requisitos de Gerenciamento
Conforme nos coloca Stallings (2005) e proposto pela International Organization for
Standardization (ISO), as principais áreas de gerenciamento são:
a) Gerenciamento de falhas: recurso que detecta exatamente onde está à
falha, tomando o cuidado de isolar a mesma de toda a rede para que fique operando
sem causar muito impacto. Tornando o mais rápido possível a correção e reparo para a
volta da normalidade;
b) Gerenciamento de contabilidade: recurso capaz de determinar taxas de
uso conforme prioridades de consumo da rede analisando os custos. Tornando a rede
mais correta e inibindo que um usuário específico fique ocupando todo fluxo da rede,
deixando os outros que realmente produzem a necessidade de fazer seu trabalho;
c) Gerenciamento de configuração e de nome: tem o controle de
configurações de dispositivos gerenciáveis para fornecer maior controle, ter mais
informações de uso e de recursos para dar maior tempo de uso e operação continua da
conexão;
d) Gerenciamento de desempenho: faz dentro da rede o monitoramento,
que é a função de acompanhar as atividades da rede, e recursos para fornecer
informações sobre o nível operacional da rede. Já o controle faz a função de analisar
estes dados e gerar um feedback para que o gerenciamento de desempenho possa
realizar ajustes para melhorar o desempenho da rede;
e) Gerenciamento de segurança: concentra-se na geração, na distribuição e
no armazenamento de chaves de criptografia e na coleta, armazenamento de registros,
informações de gerenciamento de hosts da rede através de logs, podendo assim fazer
um exame da rede através do logs armazenados.
20
3.3 AUTENTICAÇÃO DE USUÁRIOS
Segundo Rufino (2007), autenticação é um cadastro de um equipamento ou usuário
para permitir o acesso à rede estabelecendo ou não uma conexão. As autenticações podem ser
corretas ou incorretas, fazendo à liberação de acesso a rede se corretas e restringidas o acesso
caso incorretas. A autenticação é a primeira coisa feita antes de disponibilizar qualquer
serviço na rede.
Existem vários tipos de autenticação por protocolos desenvolvidos por empresas
privadas sendo elas pagas e usualmente em hardware próprio e as desenvolvidas por
comunidades ou no meio acadêmico de código aberto sendo elas gratuitas ou de código
aberto. As ferramentas pagas são destinadas a ativos de redes próprios e com preço de
mercado alto, muitas não sendo compatíveis com outros protocolos livres para manter o
monopólio das redes. Já as de código aberto são ferramentas que são instaladas como serviço
em qualquer hardware e tem compatibilidades com os outros dispositivos de rede,
proporcionando o mesmo resultado que as pagas.
Para Filagrana (2002) a autenticação é sinônimo de segurança, pois torna os acessos
restritos a uma permissão, fazendo com que só pessoas autorizadas tenham acesso às
informações armazenadas nos sistemas.
Segundo Walt (2011); Pereira (2009), a RFC2903 garanti um controle de acesso à rede
determinando três modelos básicos de segurança descritos como AAA: Autenticação,
Autorização e Contabilização:
a) Autenticação: caracteriza-se pela conferência entre os dados fornecidos
pelo usuário ao banco de dados para perfeita conferência de igualdade. As formas
mais comuns e utilizadas são o usuário e senha, certificados e tokens, caso uma delas
sejam consideras incorretas ao banco de dados negará o acesso, caso contrário a sessão
será aberta por tempo determinado;
b) Autorização: são regras determinadas para cada usuário ou grupo de
uma rede, dando a ele permissões, privilégios, restrições para o acesso ao recurso
dentro de uma rede. É através destas regras que podemos limitar quantidade de sessões
por usuário, controle de acesso à rede e limitar acesso por tempo determinado;
21
c) Contabilização: são todos os tipos de contagem feitos durante o uso da
rede, para o gerenciamento e cobrança da utilização, com a identificação ou
autenticação do usuário da rede com início e fim do uso;
3.3.1 RADIUS
O protocolo RADIUS segundo Walt (2011), segue a arquitetura servidor/cliente. O
usuário que deseja utilizar um determinado serviço de rede envia as suas informações para o
NAS (Network Atachament Storage) solicitado (o NAS atua como um cliente para o servidor
RADIUS), que pode solicitar a autenticação deste usuário a um servidor RADIUS AAA, na
forma de uma mensagem de requisição de acesso (Access- Request message). De acordo com
a resposta fornecida pelo servidor AAA, o cliente (NAS) pode então fornecer os serviços
requisitados pelo usuário de acordo com as políticas e informações estabelecidas pelo servidor
RADIUS AAA. Após receber uma requisição do cliente, o servidor RADIUS tenta promover
a autenticação do usuário, e retorna as informações de configuração e as políticas a serem
aplicadas para o mesmo.
Devido a grande flexibilidade do protocolo e devido as diferentes tecnologias
agregadas ao RADIUS, o servidor pode ser configurado para autenticar os usuários
localmente ou como um cliente proxy que redireciona os pedidos de acesso para outro
servidor AAA remoto. Quando utilizamos o servidor RADIUS desta forma, o servidor AAA
que atua como proxy passa a ser o responsável pela intermediação das mensagens trocadas
entre o cliente e o servidor remoto. Um servidor RADIUS pode ser configurado para efetuar
determinadas requisições localmente e atuar como proxy para outros servidores remotos. Um
exemplo muito prático e útil desta flexibilidade do RADIUS é a utilização do mesmo para a
autenticação em serviços que executam em sistemas embarcados. Como os sistemas
embarcados geralmente possuem limitações de gasto de energia e de espaço de
armazenamento e memória, a utilização de um servidor AAA embarcado atuando somente
como proxy pode garantir a autenticação segura de usuários de um serviço, como o acesso de
uma rede wireless em um ponto de acesso (WALT, 2011).
22
3.3.1.1 Métodos de Autenticação
Os métodos de autenticação do RADIUS podem ser explorados em três formas mais
comuns e adequada ao seu uso: PAP, CHAP e EAP.
a) Password Authentication Protocol (PAP): segundo Campos (2005), o
Protocolo de Autenticação por Senha é um protocolo de autenticação simples. Este
protocolo transmite as senhas na forma de texto plano (sem criptografia) em ASCII.
Conforme Walt (2011), por não ter criptografia das senhas, este protocolo é
considerado inseguro. Ele ainda é utilizado como uma última solução para efetuar a
autenticação de usuários, em cenários onde o servidor não suporta protocolos mais
seguros. No processo de autenticação com PAP, o cliente envia o nome do usuário e a
sua senha, e o servidor envia um ACK (acesso permitido), ou envia um NAK (acesso
não permitido). Para o caso específico do RADIUS, caso o cliente não suporte outras
formas de autenticação, os pacotes do tipo “Desafio de Acesso” são considerados
como pacotes de “Acesso Negado”;
b) Challenge-Handshake Authentication Protocol (CHAP): o Protocolo de
Autenticação por Desafios de Identidade é um método relativamente seguro de
autenticação, em comparação a protocolos mais simples como o PAP. O CHAP
verifica periodicamente a identidade do usuário, através de um reconhecimento em
três etapas (three-way handshake). Esta autenticação ocorre no estabelecimento da
conexão, e também pode ocorrer a qualquer momento após o seu estabelecimento. A
verificação da autenticidade dos usuários é feita através do segredo compartilhado
(shared secret) entre o usuário e o servidor RADIUS. Após a etapa de estabelecimento
da conexão, o servidor RADIUS envia um desafio para o usuário. O usuário então
emite uma resposta que contém o hash do segredo compartilhado. O servidor de
Autenticação então verifica o valor do hash enviado e o compara com o hash gerado
por ele mesmo. Caso o valor esteja correto, o servidor envia um Reconhecimento
positivo (ACK). Caso contrário, o Servidor Finaliza a conexão. Em intervalos de
tempo aleatórios, o servidor realiza novamente um desafio para o usuário (CAMPOS,
2005);
23
c) Extensible Authentication Protocol (EAP): é um Protocolo de
Autenticação Extensível que segundo os autores Peres & Weber (2003), provê funções
de negociação a respeito de quais métodos de autenticação serão utilizados e, além
disso, oferece suporte a múltiplos métodos de autenticação, chamados de métodos
EAP. Dentre estes métodos, podemos citar o EAP-MD5, EAP-TLS (muito utilizado
em redes sem fio) e EAP-TTLS. O servidor que deseja autenticar o cliente, requisita
informações adicionais a respeito do mesmo, e um dos métodos EAP é então
solicitado para prover a autenticação.
3.3.1.2 FreeRADIUS
De acordo com site do projeto freeradius.org, este é uma implementação do protocolo
RADIUS modular, de alto desempenho e rica em opções e funcionalidades. Segundo Walt
(2011), FreeRADIUS é um projeto open source fornecendo uma implementação muito rica
em recursos do protocolo RADIUS com vários plug-ins para acessórios. Conforme nos
averbera Antunes (2008;2009) o FreeRADIUS é o servidor de autenticação mais utilizados
nos sistemas Linux, responsável por autenticar um terço dos usuários de Internet no mundo.
Entre as suas as vantagens pode-se limitar o número máximo de acessos simultâneos e
o funcionamento como proxy, além de Permitir a edição de usuários, clientes e regras de
acesso tanto em arquivos como em bases de dados. O MySQL, PostgresSQL e Oracle são
banco de dados compatíveis com o FreeRADIUS (ANTUNES, 2008;2009).
O protocolo RADIUS, base do FreeRADIUS, possui uma boa aceitação e foi publicado
em 1997, como RFCs, trazendo algumas mudanças aplicadas nele. A RFC 2865 ficou como
norma do protocolo RADIUS e a RFC 2866 com a contabilidade RADIUS. Com estas
publicações começou-se a implementar o protocolo em qualquer equipamento ou software,
incorporando o protocolo RADIUS para as redes AAA sobre TCP/IP.
O desenvolvimento do FreeRADIUS começou em 1999, com código aberto e com a
participação ativa da comunidade desenvolvedora. Hoje o FreeRADIUS continua como uma
ferramenta de código aberto e gratuita, competindo de igual para igual com ferramentas pagas
24
como o ACS Cisco (Access Control Server) e o Microsoft IAS (Internet Authentication
Service), tornando-se uma ferramenta bastante popular.
Segundo a RFC 2865 e RFC 2866 a comunicação do protocolo RADIUS entre o
cliente e o servidor é feita através do protocolo UDP. Segundo Antunes (2009), o
FreeRADIUS trabalha com a tecnologia cliente e servidor. A comunicação entre cliente e
servidor se dá pelo protocolo RADIUS que trabalha a autenticação até o banco de dados NAS
por meio do protocolo UDP na porta 1812 e na porta 1813 para contabilização-radacct
definido na RFC 2865.
O FreeRADIUS quando instalado em modo completo oferece as seguintes
ferramentas:
radclient – emula um cliente RADIUS, enviando pacotes para o servidor;
radlast – mostra as últimas sessões de utilizadores;
radtest – frontend para o radclient, utilizado para testar o servidor;
radwho – mostra os utilizadores ligados;
radrelay – reenvia dados de acoounting para um outro servidor RADIUS;
radzap – efetua a limpeza da base de dados de sessões ativas.
Conforme o autor Walt (2011), FreeRADIUS é serviço multiplataforma, podendo ser
instalado em Sistemas Operacionais Windows e Linux, pois existem versões apropriadas a
cada um. Instalado em Sistema Operacional Linux, que em nosso caso foi utilizada a
distribuição Ubuntu Server 12.04, permite uma maior flexibilidade ao usuário.
3.4 COOVACHILLI
CoovaChilli é um controlador de acesso de software em código aberto, auto
denominado portal de captura (Captive Portal). Foi baseado no seu antecessor, ChilliSpot,
sendo mantido pelos mesmo colaboradores. É distribuído sob a GPL (General Public
License), ou seja, código fonte aberto e livre para alterações. Seu proposito é capturar através
do navegador, login e senha dos usuários e conduzir através do protocolo RADIUS ao
servidor de autenticação escolhido, como mostra a figura 7, tornando a rede mais segura,
permitindo mais controle e com uma abordagem de autenticação por protocolo HTTP para o
25
provisionamento de acesso e contabilidade, através do navegador. Sua versão atual esta na
1.3.0 lançada em 21 de outubro de 2012 (COOVA.org).
Figura 7 - Tratamento de conexão CoovaChilli.
Fonte: COOVA.ORG, 2013
3.5 NGREP
Segundo Ritter (2011), a ferramenta Ngrep usa o pcap-aware que permite a você
especificar expressões regulares estendidas ou hexadecimais para comparação das cargas de
dados de pacotes (payload). Identificando o conteúdo relevante ao que se procura, scaneando
a saída do comando linha por linha, procurando pelos argumentos especificados na sintaxe de
pesquisa deste comando. Atualmente, reconhece IPv4 / 6, TCP, UDP, ICMPv4 / 6, IGMP e
Raw através de Ethernet, PPP, SLIP, FDDI, Token Ring e interfaces nulas, e entende lógica
de filtro BPF da mesma forma como ferramentas de detecção de pacotes mais comuns, tais
como tcpdump e snoop.
O NGrep tenta copiar ao máximo todas as funcionalidades presentes no Grep do Unix,
porém as aplica aos pacotes de rede. Ele tem suporte ao Linux, Mac OS X, Solaris, FreeBSD,
OpenBSD, NetBSD, HP-UX, AIX e todas as versões de Windows. Para funcionar
tranquilamente ele precisa da biblioteca PCAP, que no Unix é a libpcap e no Windows é a
WinPcap. Alguns comandos básicos:
-l = Cria a linha de saída no buffer1;
1 Memória temporária.
26
-q = Fica estático, sem mostrar qualquer outra informação dos cabeçalhos dos pacotes
e sua carga útil (só mostra o que for pedido no comando);
-t = Imprime o timestamp no formato YYYY / MM / DD HH: MM: SS.UUUUUU
sempre que um pacote é correspondido à pesquisa;
-d = forçar o ngrep escutar a interface que você especificar;
eth2 = interface especificada pelo administrador para o ngrep escutar, do contrário o
ngrep irá escutar a eth0 por padrão;
-i = ignorar caso a expressão não possuir o expressão a ser filtrada entre os apóstrofos.
Segue exemplificação na figura 8 dos comandos dados pelo Ngrep neste trabalho.
Figura 8 - Captura Ngrep das URLs
Fonte: AUTOR, 2013.
3.6 SHELL SCRIPT
Segundo Jargas (2008), Shell Script é a junção de um script e o prompt da linha de
comando do Unix e do Linux (Shell). Script é uma lista de comandos para serem executados
em sequência, um após o outro. Em outros casos usa-se em condições repetitivas de
execução, como por exemplos backups automatizados por tempo. O Shell é o local que recebe
os comandos, parâmetros e funções digitados pelo usuário, e os executa. Cada comando é
lido, verificado, interpretado e enviado ao sistema operacional para ser executado, ou seja, é a
ligação entre o usuário e o kernel (ligação do Sistema Operacional com o hardware).
Conforme o mesmo autor (2008), a junção do Shell com o Script, foi para facilitar a
automatização de funções do dia a dia principalmente aos administradores de rede. Nos dias
de hoje scripts são considerados roteiros de comandos desleixados, usados somente para
27
aprendizados e ou para improvisações não sendo tecnicamente recomendáveis. Estes mesmos
scripts estão sendo substituídos por programas, ou seja, os mesmos roteiros de comandos,
estão se tornando melhor elaborados, analisados, codificados com cautela, comentados,
traçando cabeçalhos, executando tratamento de erros e exceções, sendo alinhados e podendo
ser atualizados conforme as necessidades do programador.
Seguindo o mesmo autor (2008), o Shell Script tem um formato padrão de execução:
COMANDO+OPÇÕES+PARAMETROS. Há vários comandos feitos para o Shell como por
exemplo as ferramentas abaixo relacionadas:
a) cat: mostra o conteúdo de um ou mais arquivos;
b) cut: extrai campos ou trechos de uma linha;
c) date: mostra a data;
d) diff: mostra a diferença entre dois arquivos;
e) echo: mostra um texto como mensagens na tela;
f) find: encontra arquivos procurando pelo nome, data, tamanho e outras
propriedades;
g) fmt: formatador simples de parágrafos, adicionando ou removendo quebras de
linha e espaços;
h) grep: procura em arquivos ou textos por linhas que contem determinado padrão
de pesquisa;
i) head: mostra o inicio de um texto expressas em linhas ou caracteres;
j) od: mostra o código de cada caractere de um arquivo ou texto em octal,
hexadecimal e ASCII;
k) paste: junta linha de vários arquivos em um só;
l) printf: mostra um texto usando vários formatadores especiais;
m) ver: inverte a ordem dos caracteres da linha, de trás para frente;
n) sed: editor de texto que troca uma string por outra;
o) seq: faz a contagem numérica por linha e mostra a sequência na tela;
p) sort: ordena as linhas de um texto em ordem alfabética ou numérica;
q) tac: faz a contagem numérica por linha e mostra a sequencia inversa na tela;
r) tail: mostra o final de um texto expressas em linhas ou caracteres;
s) tee: salva um fluxo de dados de um pipe para um arquivo, sem interrompê-lo;
t) tr: transforma, comprime e apaga caracteres, funcionando como um filtro;
28
u) uniq: remove linhas repetidas consecutivas em um texto, deixando somente
uma;
v) wc: conta letras, palavras e linhas em um texto;
w) xargs: gerencia e executa comandos passando os argumentos recebidos via
STDIN.
Com base nos comandos citados é possível gerar programas com execução em modo
oculto liberando o usuário de comandos repetitivos e cansativos. Estes programas podem
servir para realizar consultas, inserção, alteração entre outras funções em arquivos de log e de
sistemas.
29
4 MATERIAL E MÉTODOS
Foram utilizados os seguintes materiais e métodos na construção deste trabalho:
4.1 TIPO DE PESQUISA
O trabalho proposto caracteriza-se como uma pesquisa aplicada, pois como esta é
definida por Lakatos e Marconi (2012), este tipo de pesquisa busca aplicar o conhecimento
adquirido na solução de um problema. Assim podemos considerar a implantação de um Portal
de Autenticação e Monitoramento de Usuários no IFC – Campus Sombrio como uma
pesquisa aplicada.
Ainda conforme as mesmas autoras (2012), temos a pesquisa experimental que trata de
estudos explicativos, avaliativos e interpretativos colocado em implementação para a
mudança do problema proposto ao trabalho, e assim caracteriza-se a implantação do Portal de
Autenticação e Monitoramento de Usuários, pois no decorrer do processo a pesquisa foi sendo
reavaliada e alterada conforme as necessidades surgidas.
4.2 MATERIAIS
Para a realização da Implantação foram utilizados os seguintes materiais:
→ Ultrabook com 4gb memória RAM e processador Core I5;
→ Sistema Operacional (SO) Windows 8;
30
→ Uma Máquina Virtual com o SO Linux Ubuntu Server 12.04, com 1gb memória e
com três placas de rede. Uma placa de entrada para Internet, e uma placa para o range2 dos
usuários e outra placa para o range do administrador;
→ Duas Máquinas Virtuais com SO Windows XP com uma placa de rede cada para
testes no ranges dos usuários e administrador;
4.3 MÉTODOS
Na infraestrutura de redes de computadores do IFC propôs-se implementar um
servidor Ubuntu 12.04 com serviços de autenticação e captura de dados. Para autenticação
usou-se o servidor FreeRADIUS com banco de dados MySQL e com gerenciamento do
aplicativo DaloRADIUS. Já para o usuário efetuar o login de autenticação usou-se o
CoovaChilli como um Hotspot, fazendo assim a interface entre o usuário e o servidor
FreeRADIUS.
No monitoramento apresentou-se melhor a ferramenta Ngrep que faz a captura de
dados determinados pelo administrador e armazena em arquivos de texto. Como nosso
propósito é fazer o monitoramento por usuário logado no servidor FreeRADIUS, usamos a
linguagem Shell Script para filtrar os usuários cadastrados no banco de dados MySQL e
atrelar o ip do arquivo armazenado do Ngrep. Trazendo para o administrador de rede o nome
do usuário e o tempo que ele usou durante o seu expediente. Gerando ao administrador uma
página web com os dados e para relatórios para sua análise.
Para que o FreeRadius, o CoovaChilli e Ngrep ter um funcionamento adequado é
necessário instalar no servidor Ubuntu mais um componente básico, o Apache2. Ele fará com
que o CoovaChilli mostre, através do navegador, onde o usuário possa fazer seu login e senha
e as guarde no banco de dados proposto. A topologia lógica da rede esta exemplificada na
figura 9.
2 Faixa de IPs de uma rede.
31
Figura 9 - Topologia Lógica da Rede
Fonte: AUTOR, 2013.
4.4 INSTALAÇÃO E CONFIGURAÇÃO
Para que possamos instalar sem nenhum problema faremos a autenticação no Ubuntu
Server como root, para ter todos os privilégios de administrador executando o comando #sudo
su, e preenchendo a senha de super usuário. Como se trata de um servidor que fará
autenticação por usuário usando o CoovaChilli tem-se que configurar uma placa de rede em
modo manual, pois quem fará o DHCP3 para a rede será o próprio CoovaChilli. Por padrão as
placas de redes estão configuradas por DHCP, no arquivo interfaces, localizado no diretório
/etc/network/, que será editado para o modo manual e estático, como mostra na figura 10. Para
ter efeito estas configurações nas interfaces aqui modificadas foi executado o comando
3 Protocolo de configuração dinâmica de host.
32
#/etc/init.d/networking restart para reiniciar os serviços da rede. Para confirmar as
configurações que foram feitas foi utilizado o comando #ifconfig.
Figura 10 - Arquivo interfaces editado para funcionamento
Fonte: AUTOR, 2013
Antes de instalar as ferramentas utiliza-se fazer uma verificação e atualização do
banco de dados do repositório do sistema operacional Ubuntu Server com o comando #apt-get
update && apt-get upgrade para deixar o repositório completo. Após o repositório
atualizado, e antes da instalação das ferramentas, autenticação e monitoramento, instala-se
algumas aplicações para o correto funcionamento dos mesmos. Através do comando
#aptitude install apache2 ssl-cert php5-gd php-db php-pear libapache2-mod-php5 mysql-
server mysql-client freeradius freeradius-mysql phpmyadmin freeradius-utils gcc logado
como root, instalar-se-á o Apache2, php, FreeRADIUS e o MySQL para autenticar, guardar no
banco de dados e fazer o hotspot.
Após instalação usam-se os seguintes comandos para poder ter acesso ao navegador
via HTTS, ou seja, em modo seguro. Executa-se os comandos #a2enmod ssl, #a2ensite
default-ssl em sequência e o comando #service apache2 restart para reiniciar os serviços do
Servidor Web para as alterações serem realizadas.
Com o FreeRADIUS instalado cria-se o banco de dados MySQL usado para guardar as
autenticações dos usuários logados pelo CoovaChilli. Para criar um banco de dados entre
como usuário root em seu terminal usando os seguintes comandos:
#MySQL –u root –p comando para entrar no banco de dados;
#Enter password coloque a senha usada na instalação do banco de dados MySQL;
mysql> CREATE DATABASE radius comando para criar o banco de dados;
33
mysql> quit comando para sair.
Criado a base de dados adicione os scripts SQL schema.sql e nas.sql com os seguintes
comandos:
#mysql –u root –p radius < /etc/freeradius/sql/mysql/shema.sql;
#mysql –u root –p radius < /etc/freeradius/sql/mysql/nas.sql.
Para modificar e cadastrar no banco de dados usa-se alguns privilégios com os
comandos:
#mysql –u root –p para entrar no banco de dados;
Enter password coloque a senha cadastrada na instalação do MySQL;
mysql> GRANT ALL PRIVILEGES ON radius.* TO ‘radius’@’localhost’
IDENTIFIED BY ‘mysqlsecret’;
mysql> FLUSH PRIVILEGES banco de dados com os devidos privilégios;
mysql> quit Sair.
A edição dos arquivos de configuração pode ser feita com qualquer editor de textos
presente no sistema operacional, como por exemplo: Nano, Vim, Vi ou mcedit. O primeiro
arquivo é o sql.conf que fica em /etc/freeradius/ modificado para o conteúdo da figura 11.
Figura 11 - Arquivo editado sql.conf.
Fonte: AUTOR, 2013
O segundo arquivo a ser editado esta em /etc/freeradius/clientes.conf que foi alterado
para a palavra chave mysqlsecret como mostra na figura 12.
34
Figura 12 - Arquivo editado clients.conf
Fonte: AUTOR, 2013
Todos os usuários do FreeRADIUS são cadastrados ou alterados no arquivo users no
diretório /etc/freeradius/ após o cadastramento reiniciou-se o sistema operacional com o
comando #reboot. Após o reinício do SO parou-se o serviço FreeRADIUS com o comando
#/etc/init.d/freeradius stop, para a depuração e verificação de erros com o comando
#freeradius –XXX, se o resultado da depuração mostrar êxito dê o comando pelo teclado
control+c para sair, caso contrario revise os erros de configuração e os refaça.
Aqui nestas configurações fez-se os usuários no próprio arquivo do FreeRADIUS, para
segurança e armazenamento destes usuários, cadastra-se direto no banco de dados MySQL
que criamos nas etapas anteriores. Para fazer esta ligação teremos que editar novamente o
arquivo sql.conf no diretório /etc/freeradius/ tirando o comentário da linha readclients=yes. Já
no arquivo default no diretório /etc/freeradius/sites-enabled/ um pouco mais extenso terá que
ter mais atenção em comentar algumas linhas e excluir o comentário de outras, deixando
como o arquivo do Anexo 1. Para finalizar a configuração da autorização do FreeRADIUS
com o banco tem que edita-se o arquivo radius.conf no diretório /etc/freeradius/ tirando o
comentário da linha INCLUDE sql.conf conforme anexo 2.
Nesta etapa fez-se a inserção de um usuário e senha no MySQL para fazer o
teste na conexão. Após reinicializar o serviço do FreeRADIUS, usou-se o comando radtest
com o nome e a senha cadastrada, o IP ou nome do servidor e a porta, e por último a palavra-
chave do FreeRADIUS para comprovar o correto funcionamento da integração do
FreeRADIUS e o banco MySQL como mostra na figura 13.
35
Figura 13 - Teste de funcionamento do FreeRADIUS
Fonte: AUTOR, 2013
Com o banco de dados, o Apache2 e o FreeRADIUS já instalado e configurado, o
próximo passo é a instalação do CoovaChilli que fará a interação do usuário com o
FreeRADIUS. O CoovaChilli é uma aplicação que quando iniciou-se a configuração do
Sistema Operacional foi deixado a placa de rede de usuários em modo manual, que agora este
aplicativo fará o serviço de DHCP e fornecerá a página de autenticação. Como este aplicativo
ainda não esta instalado e não possui no repositório do SO, executa-se a baixa e a instalação
pelo comando #cd /tmp && wget ‘http://ap.coova.org/chilli/coova-chilli_1.3.0_i386.deb &&
dpkg –i coova-chilli_1.3.0_i386.deb com intuito de preparar para a configuração.
Já instalado falta apenas à configuração por um seguimento padrão dos outros
aplicativos que configuramos. Edita-se o diretório /etc/chilli e já com uma cópia do arquivo
defaults para config e edita-se da linha 12 até a 85 como mostra a figura 14.
Figura 14 - Arquivo config editado
Fonte: AUTOR, 2013
36
Após configurado o arquivo config, passará a modelar a página da autenticação para o
usuário, neste caso cria-se dois diretórios em /etc/chilli/www, um chamado images e outro
uam. Para o correto funcionamento baixou-se da internet dentro do diretório uam os seguintes
arquivos com o comando #wget http://ap.coova.org/uam/ e #wget
http://ap.coova.org/js/chilli.js. No mesmo diretório, editou-se o arquivo index.html na linha
85, como mostra no anexo 3, e um diretório abaixo modificou-se o arquivo ChilliLibrary.js
nas linhas 81 e 82 descrita no anexo 4. Para não precisar sempre que for iniciado o SO ter que
iniciar o CoovaChilli, edita-se o arquivo chilli no diretório /etc/default o parâmetro
START_CHILLI=0 para START_CHILLI=1. Para conferir e testar a configuração, usa-se um
depurador de erros com o comando #chilli –f –d e aguarde o resultado, se aparecer erros
inicia-se passo a passo as configurações.
Tudo corretamente instalado e configurado necessita-se apenas a configuração da
página de login, que o CoovaChilli já possui por padrão. Com o comando #zcat –c
/usr/share/doc/coova-chilli/hotspotlogin.cgi.gz > /usr/lib/cgi-bin/hotspotlogin.cgi para
descompactar o mesmo edita-se o hotspotlogin.cgi do diretório /usr/lib/cgi-bin/ alterando o
parametro $uamsecret= “ “ com a palavra secreta que foi colocado no arquivo config editado
anteriormente ou verifique no anexo 5. Para configurar a VirtualHost foi criado um arquivo
no diretório /etc/apache2/sites-available/ com o nome de hotspot como mostra a figura 15 e
para o seu funcionamento ativa-se com o comando #a2ensite hotspot, com o reinício do
apache2 com o comando #/etc/init.d/apache2 restart para que todas as configurações venham
prevalecer.
Figura 15 - Arquivo hotspot editado
Fonte: AUTOR, 2013
37
Após reinício do SO usa-se fazer uma cópia do diretório /etc/chilli/www para
/var/www/hotspot e dentro de hotspot copia-se a imagem coova.jpg para
/var/www/hotspot/images. Com os comandos #chown –R www-data.www-data
/var/www/hotspot/, #chown –R www-data.www-data /var/www/hotspot/*, #chown –R www-
data.www-data /usr/lib/cgi-bin/hotspotlogin.cgi e chmod 777 /usr/lib/cgi-
bin/hotspotlogin.cgi mudará as permissões para estes arquivos.
Para o perfeito funcionamento do hotspotlogin usa-se o comando #cd /tmp && wget
http://dowloads.souceforge.net/project/haserl/haserl-devel/0.9.27/haserl-0.9.27.tar.gz para
baixar este plugin que funcionará na autenticação do usuário pelo CoovaChilli até o banco de
dados. Para instalar, usou-se o comando #tar –xzf haserl-0.9.27.tar.gz && cd /tmp/haserl-
0.9.27 que extrai o arquivo zip, e os comandos #./configure, #make e #make install.
Com o término da instalação modificou-se o arquivo wwwsh no diretório /etc/chilli
seguindo o anexo 6, e o arquivo up.sh adicionando quatro linhas no final do arquivo
especificado no anexo 7. Para terminar esta etapa da autenticação foi atualizado os scripts
com o comando #update-rc.d chilli defaults e feito a reinicialização do SO para que o
navegador abrar pedindo o login e senha como mostra a figura 16 quando for usar a internet.
Dando ao administrador da rede poder de controlar por nome seus usuários.
Figura 16 - Captura login e senha Coovachilli
Fonte: AUTOR, 2013
38
Como no Ubuntu Server 12.04 não vem instalado a ferramenta de captura de dados na
rede, faz-se logue no terminal como usuário root e instala-se o ngrep com o comando #apt-get
install ngrep. Com esta ferramenta instalada usou-se três parâmetros de captura para filtrar o
trafego e armazenar em um arquivo texto como mostra na figura 17. Para que o comando
possa ficar capturando os dados em tempo real, usa-se um script com todos os comandos em
sequência sendo executados pelo Shell. Para colocar estes comandos cria-se um arquivo com
o comando #vim dentro de qualquer partição, neste caso foi em /home/suporte/ com o nome
capturapaginas.sh e dentro deste arquivo foi descrito os comandos como mostra a figura 17.
Figura 17 - Arquivo captura Ngrep
Fonte: AUTOR, 2013
Neste script o ngrep faz a captura através dos parâmetros e expressão, sendo o –l que
cria a linha de saída no buffer, o –q que mostra só o que esta no comando, o –t que cria a data
e a hora quando encontra a expressão, o –d que força escutar a placa de rede determinada e
por fim o –i passa direto se na pesquisa não encontrar a expressão imposta, guardando em um
arquivo texto especificado.
Com os dados capturados e gravados no arquivo texto, trata-se estes dados para
eliminar partes que não necessitam e fica somente o que é necessário para o propósito de
saber quanto tempo o usuário ficou usando uma destas urls4. Na figura 18 mostra o script de
limpeza dos dados.
4 Endereço de um arquivo na web.
39
Figura 18 - Filtro dos dados capturados pelo Ngrep
Fonte: AUTOR, 2013
Neste script de filtro usa varia ferramentas, o grep que procura por linha o que contém
entre colchetes, o cut que extrai campos ou trechos de uma linha, o tr que comprimi ou apaga
caracteres que for determinado e o sed que troca ou substitui uma string por outra. Este script
é salvo em um arquivo texto para poder ser manipulado.
Usa-se um comando em Shell Script e MySQL para importar do arquivo texto anterior
em uma tabela dentro do banco de dados. Segue a figura 19 dos comandos executados.
Figura 19 – Importação arquivo texto para tabela MySQL.
Fonte: AUTOR, 2013
40
Com todos os dados na tabela fez-se uma consulta em linguagem SQL, foram
capturados os dados das tabelas e os comparando para retirar a tabela de dados por nome e
tempo de uso. Como mostra na figura 20.
Figura 20 - Consulta de tabelas MySQL
Fonte: Autor, 2013
Para mostrar o resultado através de uma pagina web, usou-se um código em html
chamando um código em php descrito na figura 21, por nome de usuário.
Figura 21 - Código HTML para pagina web
Fonte: Autor, 2013
41
Com o código em html feito, desenvolveu-se um código em php que consulta o banco de
dados SQL, e compara os dados pela data, hora e usuário, mostrando um relatório com data e hora de
uso por usuário de quem o fez como mostra a figura 22.
Figura 22 - Código PHP para pagina web.
Fonte: Autor, 2013
42
5 RESULTADOS E DISCUSSÃO
Com a realização das pesquisas e testes, foi possível perceber que os objetivos de
melhorar o uso de Internet através do servidor de gerenciamento da rede foi positivo. Levando
em consideração que a autenticação de cada usuário, através do servidor FreeRADIUS
garante uma maior segurança à rede, dando ao administrador a possibilidade de controle pelo
banco de dados armazenado. A navegação que antes era livre teve um ponto positivo ao
momento que o cadastramento de cada usuário e a captura de dados foi relacionadas tornando
visível o tempo gasto de cada usuário com acessos indevidos aos parâmetros educacionais ou
de trabalho, mostrado através de uma pagina html ilustrado na figura 23.
Para a o administrador da rede tornou-se mais fácil o controle de acesso aos alunos,
professores e servidores tendo um relatório diário de uso para tomar suas decisões em relação
ao consumo excessivo de internet, caso mais crítico no ponto de vista do objetivo deste
trabalho.
Figura 23 - Pagina web com relatório final
Fonte: Autor, 2013
43
6 CONSIDERAÇÕES FINAIS
Este trabalho teve por objetivo implementar serviços capazes de autenticar e monitorar
os usuários para melhorar a resolução do problema com segurança do acesso aos alunos e
servidores do Instituto Federal Catarinense Campus Sombrio. Também irá proporcionar o
conhecimento dos usuários que mais consomem banda da rede e ter o controle de acesso para
fazer uma divisão igualitária de banda. Propor-se a instalação de um servidor de
gerenciamento e monitoramento da rede do Campus Sombrio. Para que este servidor pudesse
ser implantado a rede, com autenticação pelo servidor FreeRADIUS, com o serviço do portal
de captura dos logins e senhas dos usuários bem sucedida.
Para estes serviços usou-se as principais áreas de gerenciamento colocando na
estrutura a autenticação de login e senha e armazenando em banco de dados para a segurança
e contabilidade dos acessos. Complementando a estrutura da rede capturou-se dados dos
usuários para verificação de possíveis erros, número de acessos e fluxo para verificar o
desempenho e as falhas contidas na rede.
Para o propósito de monitoramento usou-se a ferramenta Ntop que tinha tudo para dar
certo após análises e estudos sobre ela, mas não foi possível fazer a leitura do banco de dados
em formato .rrd e .db, ambos com criptografia ativa. Neste intuito foi necessário mudar para a
captura de dados através da ferramenta Ngrep que foi muito rápido e fácil de implementação.
Nela aplicamos a captura de dados relacionados a parâmetros como palavras, urls, sites,
protocolos, para analisar e relacionar com a autenticação de cada usuário na rede através da
linguagem de programação Shell Script, filtrando os dados e comparando o IP da captura com
o IP do usuário. Nesta programação foi encontrado um pouco de dificuldade, pois envolve
muitos detalhes da linguagem para comparação, extração dos dados ao resultado final.
Para trabalhos futuros propõem-se a geração de gráficos com os resultados obtidos e
com a diversificação da captura de dados por outros parâmetros.
44
REFERÊNCIAS
ANTUNES, Vitor Hugo Leite. Frontend web 2.0 para Gestão de RADIUS. Major
Telecomunicações. Dessertação de mestrado. 2008/2009. Disponível em:
http://paginas.fe.up.pt/~ee04199/Frontend%20Web%202.0%20para%20Gestao%20de%20
RADIUS.pdf. Acessado em: 23 nov. 2013.
CAMPOS, Juliana C. Moura.et al. Segurança de redes. Pontifícia Universidade Católica de
Campinas. 2005.
COOVACHILLI, Coova.org. 2008, Disponível em: http://www.coova.org/CoovaChilli
acessado em 15 nov. 2013.
FILAGRANA, Artur Carlos. Sistema de autenticação de usuários para provedores de
internet baseado no numero telefônico. Universidade para o Desenvolvimento do
Alto Vale do Itajaí. INIDAVI. Itajaí, SC, 2002.
JARGAS, Aurelio Marinho. Shell Script: Profissional / Aurelio Marinho Jargas. São Paulo:
Novatec Editora, 2008.
MARCONI, Marina de Andrade; LAKATOS, Eva Maria. Técnicas de pesquisa:
planejamento e execução de pesquisas, amostragens e técnicas de pesquisa, elaboração,
análise e interpretação de dados. 7 ed. 6 Reimpr. São Paulo: Atlas, 2012.
MARTINEZ, Marina. Topologias de Redes. 2010, Disponível
em:http://www.infoescola.com/informatica/topologias-de-redes/ acessado em 14 nov.
2013.
MORAES, Alexandre Fernandes de. Redes de Computadores: fundamentos. 7 ed. São
Paulo: Érica, 2010.
NETVOX, Disponível em:http://www.netvoxdigital.com.br acessado em 18 nov. 2013.
PEREIRA, Marcos Heyse. Segurança de redes sem fio, uma proposta com serviços
integrados de autenticação LDAP e RADIUS. Pontifícia Universidade Católica da
Paraná. 2009. P. 9.
PERES, André; WEBER, Raul Fernando. Considerações sobre Segurança em Redes Sem
Fio. ULBRA – Universidade Luterana do Brasil; UFRGS – Universidade Federal do Rio
Grande do Sul. 2003.
RFC2865. RADIUS Accounting. 2000. Disponível em: http://tools.ietf.org/html/rfc2866.
Acessado em 22 de nov. 2013.
RFC2866. Remote Authentication Dial In User Service: RADIUS. 2000. Disponível em:
http://tools.ietf.org/pdf/rfc2865.pdf. Acessado em 22 de nov. 2013.
45
RITTER, Jordan. ngrep – network grep. 2011, Disponivel
em:http://www.ngrep.sourceforge.net acessado em 15 de nov. 2013.
RUFINO, Nelson Murilo de Oliveira. Segurança em Redes sem Fio: Aprenda a proteger
suas informações em ambientes Wi-Fi e Bluetooth. Edição 3ª. Editora Novatec. 2007.
SOUZA, Lindeberg Barros de. Redes de Computadores: guia total – 1 ed. São Paulo: Érica,
2009.
SOUZA, Lindeberg Barros de. Projetos e implementação de redes: fundamentos, soluções,
arquiteturas e planejamento. 2 ed. São Paulo: Érica, 2009.
STALLINGS, William. Redes e sistemas de comunicação de dados: teoria e aplicações
corporativas – Rio de Janeiro: Elsevier, 2005 5 Reimpr.
TANENBAUM, Andrew S. Redes de Computadores. 4 ed. Rio de Janeiro: Elsevier, 2003.
TORRES, Gabriel. Redes de Computadores. Rev. e atualiz. São Paulo: Novaterra, 2009.
WALT, Dirk Van Der. FreeRADIUS: Manage your network resources with FreeRADIUS.
Editora: Published by Packt Publishing Ltda. 2011.
46
ANEXOS
Anexo 1 – Arquivo de Configuração default
#####################################################################
#
#
# As of 2.0.0, FreeRADIUS supports virtual hosts using the
# "server" section, and configuration directives.
#
# Virtual hosts should be put into the "sites-available"
# directory. Soft links should be created in the "sites-enabled"
# directory to these files. This is done in a normal installation.
#
# $Id$
#
#####################################################################
#
#
# Read "man radiusd" before editing this file. See the section
# titled DEBUGGING. It outlines a method where you can quickly
# obtain the configuration you want, without running into
# trouble. See also "man unlang", which documents the format
# of this file.
#
# This configuration is designed to work in the widest possible
# set of circumstances, with the widest possible number of
# authentication methods. This means that in general, you should
# need to make very few changes to this file.
#
# The best way to configure the server for your local system
# is to CAREFULLY edit this file. Most attempts to make large
# edits to this file will BREAK THE SERVER. Any edits should
47
# be small, and tested by running the server with "radiusd -X".
# Once the edits have been verified to work, save a copy of these
# configuration files somewhere. (e.g. as a "tar" file). Then,
# make more edits, and test, as above.
#
# There are many "commented out" references to modules such
# as ldap, sql, etc. These references serve as place-holders.
# If you need the functionality of that module, then configure
# it in radiusd.conf, and un-comment the references to it in
# this file. In most cases, those small changes will result
# in the server being able to connect to the DB, and to
# authenticate users.
#
#####################################################################
#
#
# In 1.x, the "authorize", etc. sections were global in
# radiusd.conf. As of 2.0, they SHOULD be in a server section.
#
# The server section with no virtual server name is the "default"
# section. It is used when no server name is specified.
#
# We don't indent the rest of this file, because doing so
# would make it harder to read.
#
# Authorization. First preprocess (hints and huntgroups files),
# then realms, and finally look in the "users" file.
#
# The order of the realm modules will determine the order that
# we try to find a matching realm.
#
48
# Make *sure* that 'preprocess' comes before any realm if you
# need to setup hints for the remote radius server
authorize {
#
# The preprocess module takes care of sanitizing some bizarre
# attributes in the request, and turning them into attributes
# which are more standard.
#
# It takes care of processing the 'raddb/hints' and the
# 'raddb/huntgroups' files.
preprocess
#
# If you want to have a log of authentication requests,
# un-comment the following line, and the 'detail auth_log'
# section, above.
# auth_log
#
# The chap module will set 'Auth-Type := CHAP' if we are
# handling a CHAP request and Auth-Type has not already been set
chap
#
# If the users are logging in with an MS-CHAP-Challenge
# attribute for authentication, the mschap module will find
# the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP'
# to the request, which will cause the server to then use
# the mschap module for authentication.
mschap
#
# If you have a Cisco SIP server authenticating against
49
# FreeRADIUS, uncomment the following line, and the 'digest'
# line in the 'authenticate' section.
digest
#
# The WiMAX specification says that the Calling-Station-Id
# is 6 octets of the MAC. This definition conflicts with
# RFC 3580, and all common RADIUS practices. Un-commenting
# the "wimax" module here means that it will fix the
# Calling-Station-Id attribute to the normal format as
# specified in RFC 3580 Section 3.21
# wimax
#
# Look for IPASS style 'realm/', and if not found, look for
# '@realm', and decide whether or not to proxy, based on
# that.
# IPASS
#
# If you are using multiple kinds of realms, you probably
# want to set "ignore_null = yes" for all of them.
# Otherwise, when the first style of realm doesn't match,
# the other styles won't be checked.
#
suffix
# ntdomain
#
# This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP
# authentication.
#
# It also sets the EAP-Type attribute in the request
50
# attribute list to the EAP type from the packet.
#
# As of 2.0, the EAP module returns "ok" in the authorize stage
# for TTLS and PEAP. In 1.x, it never returned "ok" here, so
# this change is compatible with older configurations.
#
# The example below uses module failover to avoid querying all
# of the following modules if the EAP module returns "ok".
# Therefore, your LDAP and/or SQL servers will not be queried
# for the many packets that go back and forth to set up TTLS
# or PEAP. The load on those servers will therefore be reduced.
#
eap {
ok = return
}
#
# Pull crypt'd passwords from /etc/passwd or /etc/shadow,
# using the system API's to get the password. If you want
# to read /etc/passwd or /etc/shadow directly, see the
# passwd module in radiusd.conf.
#
# unix
#
# Read the 'users' file
# files
#
# Look in an SQL database. The schema of the database
# is meant to mirror the "users" file.
#
# See "Authorization Queries" in sql.conf
51
sql
#
# If you are using /etc/smbpasswd, and are also doing
# mschap authentication, the un-comment this line, and
# configure the 'etc_smbpasswd' module, above.
# etc_smbpasswd
#
# The ldap module will set Auth-Type to LDAP if it has not
# already been set
# ldap
#
# Enforce daily limits on time spent logged in.
# daily
#
# Use the checkval module
# checkval
expiration
logintime
#
# If no other module has claimed responsibility for
# authentication, then try to use PAP. This allows the
# other modules listed above to add a "known good" password
# to the request, and to do nothing else. The PAP module
# will then see that password, and use it to do PAP
# authentication.
#
# This module should be listed last, so that the other modules
52
# get a chance to set Auth-Type for themselves.
#
pap
#
# If "status_server = yes", then Status-Server messages are passed
# through the following section, and ONLY the following section.
# This permits you to do DB queries, for example. If the modules
# listed here return "fail", then NO response is sent.
#
# Autz-Type Status-Server {
#
# }
}
# Authentication.
#
#
# This section lists which modules are available for authentication.
# Note that it does NOT mean 'try each module in order'. It means
# that a module from the 'authorize' section adds a configuration
# attribute 'Auth-Type := FOO'. That authentication type is then
# used to pick the apropriate module from the list below.
#
# In general, you SHOULD NOT set the Auth-Type attribute. The server
# will figure it out on its own, and will do the right thing. The
# most common side effect of erroneously setting the Auth-Type
# attribute is that one authentication method will work, but the
# others will not.
#
# The common reasons to set the Auth-Type attribute by hand
53
# is to either forcibly reject the user (Auth-Type := Reject),
# or to or forcibly accept the user (Auth-Type := Accept).
#
# Note that Auth-Type := Accept will NOT work with EAP.
#
# Please do not put "unlang" configurations into the "authenticate"
# section. Put them in the "post-auth" section instead. That's what
# the post-auth section is for.
#
authenticate {
#
# PAP authentication, when a back-end database listed
# in the 'authorize' section supplies a password. The
# password can be clear-text, or encrypted.
Auth-Type PAP {
pap
}
#
# Most people want CHAP authentication
# A back-end database listed in the 'authorize' section
# MUST supply a CLEAR TEXT password. Encrypted passwords
# won't work.
Auth-Type CHAP {
chap
}
#
# MSCHAP authentication.
Auth-Type MS-CHAP {
mschap
}
54
#
# If you have a Cisco SIP server authenticating against
# FreeRADIUS, uncomment the following line, and the 'digest'
# line in the 'authorize' section.
digest
#
# Pluggable Authentication Modules.
# pam
#
# See 'man getpwent' for information on how the 'unix'
# module checks the users password. Note that packets
# containing CHAP-Password attributes CANNOT be authenticated
# against /etc/passwd! See the FAQ for details.
#
# For normal "crypt" authentication, the "pap" module should
# be used instead of the "unix" module. The "unix" module should
# be used for authentication ONLY for compatibility with legacy
# FreeRADIUS configurations.
#
unix
# Uncomment it if you want to use ldap for authentication
#
# Note that this means "check plain-text password against
# the ldap database", which means that EAP won't work,
# as it does not supply a plain-text password.
# Auth-Type LDAP {
# ldap
# }
#
55
# Allow EAP authentication.
eap
#
# The older configurations sent a number of attributes in
# Access-Challenge packets, which wasn't strictly correct.
# If you want to filter out these attributes, uncomment
# the following lines.
#
# Auth-Type eap {
# eap {
# handled = 1
# }
# if (handled && (Response-Packet-Type == Access-Challenge)) {
# attr_filter.access_challenge.post-auth
# handled # override the "updated" code from attr_filter
# }
# }
}
#
# Pre-accounting. Decide which accounting type to use.
#
preacct {
preprocess
#
# Session start times are *implied* in RADIUS.
# The NAS never sends a "start time". Instead, it sends
# a start packet, *possibly* with an Acct-Delay-Time.
# The server is supposed to conclude that the start time
# was "Acct-Delay-Time" seconds in the past.
56
#
# The code below creates an explicit start time, which can
# then be used in other modules.
#
# The start time is: NOW - delay - session_length
#
# update request {
# FreeRADIUS-Acct-Session-Start-Time = "%{expr: %l - %{%{Acct-
Session-Time}:-0} - %{%{Acct-Delay-Time}:-0}}"
# }
#
# Ensure that we have a semi-unique identifier for every
# request, and many NAS boxes are broken.
acct_unique
#
# Look for IPASS-style 'realm/', and if not found, look for
# '@realm', and decide whether or not to proxy, based on
# that.
#
# Accounting requests are generally proxied to the same
# home server as authentication requests.
# IPASS
suffix
# ntdomain
#
# Read the 'acct_users' file
files
}
57
#
# Accounting. Log the accounting data.
#
accounting {
#
# Create a 'detail'ed log of the packets.
# Note that accounting requests which are proxied
# are also logged in the detail file.
detail
# daily
# Update the wtmp file
#
# If you don't use "radlast", you can delete this line.
unix
#
# For Simultaneous-Use tracking.
#
# Due to packet losses in the network, the data here
# may be incorrect. There is little we can do about it.
radutmp
# sradutmp
# Return an address to the IP Pool when we see a stop record.
# main_pool
#
# Log traffic to an SQL database.
#
# See "Accounting queries" in sql.conf
sql
58
#
# If you receive stop packets with zero session length,
# they will NOT be logged in the database. The SQL module
# will print a message (only in debugging mode), and will
# return "noop".
#
# You can ignore these packets by uncommenting the following
# three lines. Otherwise, the server will not respond to the
# accounting request, and the NAS will retransmit.
#
# if (noop) {
# ok
# }
#
# Instead of sending the query to the SQL server,
# write it into a log file.
#
# sql_log
# Cisco VoIP specific bulk accounting
# pgsql-voip
# For Exec-Program and Exec-Program-Wait
exec
# Filter attributes from the accounting response.
attr_filter.accounting_response
#
# See "Autz-Type Status-Server" for how this works.
#
59
# Acct-Type Status-Server {
#
# }
}
# Session database, used for checking Simultaneous-Use. Either the radutmp
# or rlm_sql module can handle this.
# The rlm_sql module is *much* faster
session {
radutmp
#
# See "Simultaneous Use Checking Queries" in sql.conf
sql
}
# Post-Authentication
# Once we KNOW that the user has been authenticated, there are
# additional steps we can take.
post-auth {
# Get an address from the IP Pool.
# main_pool
#
# If you want to have a log of authentication replies,
# un-comment the following line, and the 'detail reply_log'
# section, above.
# reply_log
#
# After authenticating the user, do another SQL query.
60
#
# See "Authentication Logging Queries" in sql.conf
# sql
#
# Instead of sending the query to the SQL server,
# write it into a log file.
#
# sql_log
#
# Un-comment the following if you have set
# 'edir_account_policy_check = yes' in the ldap module sub-section of
# the 'modules' section.
#
# ldap
# For Exec-Program and Exec-Program-Wait
exec
#
# Calculate the various WiMAX keys. In order for this to work,
# you will need to define the WiMAX NAI, usually via
#
# update request {
# WiMAX-MN-NAI = "%{User-Name}"
# }
#
# If you want various keys to be calculated, you will need to
# update the reply with "template" values. The module will see
# this, and replace the template values with the correct ones
# taken from the cryptographic calculations. e.g.
#
61
# update reply {
# WiMAX-FA-RK-Key = 0x00
# WiMAX-MSK = "%{EAP-MSK}"
# }
#
# You may want to delete the MS-MPPE-*-Keys from the reply,
# as some WiMAX clients behave badly when those attributes
# are included. See "raddb/modules/wimax", configuration
# entry "delete_mppe_keys" for more information.
#
# wimax
# If there is a client certificate (EAP-TLS, sometimes PEAP
# and TTLS), then some attributes are filled out after the
# certificate verification has been performed. These fields
# MAY be available during the authentication, or they may be
# available only in the "post-auth" section.
#
# The first set of attributes contains information about the
# issuing certificate which is being used. The second
# contains information about the client certificate (if
# available).
#
# update reply {
# Reply-Message += "%{TLS-Cert-Serial}"
# Reply-Message += "%{TLS-Cert-Expiration}"
# Reply-Message += "%{TLS-Cert-Subject}"
# Reply-Message += "%{TLS-Cert-Issuer}"
# Reply-Message += "%{TLS-Cert-Common-Name}"
#
# Reply-Message += "%{TLS-Client-Cert-Serial}"
# Reply-Message += "%{TLS-Client-Cert-Expiration}"
# Reply-Message += "%{TLS-Client-Cert-Subject}"
62
# Reply-Message += "%{TLS-Client-Cert-Issuer}"
# Reply-Message += "%{TLS-Client-Cert-Common-Name}"
# }
# If the WiMAX module did it's work, you may want to do more
# things here, like delete the MS-MPPE-*-Key attributes.
#
# if (updated) {
# update reply {
# MS-MPPE-Recv-Key !* 0x00
# MS-MPPE-Send-Key !* 0x00
# }
# }
#
# Access-Reject packets are sent through the REJECT sub-section of the
# post-auth section.
#
# Add the ldap module name (or instance) if you have set
# 'edir_account_policy_check = yes' in the ldap module configuration
#
Post-Auth-Type REJECT {
# log failed authentications in SQL, too.
# sql
attr_filter.access_reject
}
}
#
# When the server decides to proxy a request to a home server,
# the proxied request is first passed through the pre-proxy
# stage. This stage can re-write the request, or decide to
63
# cancel the proxy.
#
# Only a few modules currently have this method.
#
pre-proxy {
# attr_rewrite
# Uncomment the following line if you want to change attributes
# as defined in the preproxy_users file.
# files
# Uncomment the following line if you want to filter requests
# sent to remote servers based on the rules defined in the
# 'attrs.pre-proxy' file.
# attr_filter.pre-proxy
# If you want to have a log of packets proxied to a home
# server, un-comment the following line, and the
# 'detail pre_proxy_log' section, above.
# pre_proxy_log
}
#
# When the server receives a reply to a request it proxied
# to a home server, the request may be massaged here, in the
# post-proxy stage.
#
post-proxy {
# If you want to have a log of replies from a home server,
# un-comment the following line, and the 'detail post_proxy_log'
# section, above.
# post_proxy_log
64
# attr_rewrite
# Uncomment the following line if you want to filter replies from
# remote proxies based on the rules defined in the 'attrs' file.
# attr_filter.post-proxy
#
# If you are proxying LEAP, you MUST configure the EAP
# module, and you MUST list it here, in the post-proxy
# stage.
#
# You MUST also use the 'nostrip' option in the 'realm'
# configuration. Otherwise, the User-Name attribute
# in the proxied request will not match the user name
# hidden inside of the EAP packet, and the end server will
# reject the EAP request.
#
eap
#
# If the server tries to proxy a request and fails, then the
# request is processed through the modules in this section.
#
# The main use of this section is to permit robust proxying
# of accounting packets. The server can be configured to
# proxy accounting packets as part of normal processing.
# Then, if the home server goes down, accounting packets can
# be logged to a local "detail" file, for processing with
# radrelay. When the home server comes back up, radrelay
# will read the detail file, and send the packets to the
# home server.
#
65
# With this configuration, the server always responds to
# Accounting-Requests from the NAS, but only writes
# accounting packets to disk if the home server is down.
#
# Post-Proxy-Type Fail {
# detail
# }
}
Anexo 2 – Arquivo de configuração radiusd.conf
/**
* ChilliLibrary.js
* V2.0
*
* This Javascript library can be used to create HTML/JS browser
* based smart clients (BBSM) for the CoovaChilli access controller
* Coova Chilli rev 81 or higher is required
*
* This library creates four global objects :
*
* - chilliController Expose session/client state and
* connect()/disconnect() methods the to BBSM.
*
66
* - chilliJSON INTERNAL (should not be called from the BBSM).
* Issues a command to the chilli daemon by adding a new <SCRIPT>
* tag to the HTML DOM (this hack enables cross server requests).
*
* - chilliClock Can be used by BBSMs to display a count down.
* Will sync with chilliController for smooth UI display (not yet
implemented)
*
* - chilliLibrary Expose API and library versions
*
* For more information http://www.coova.org/CoovaChilli/JSON
*
* TODO :
* - Fine tune level of debug messages
* - Define error code when invoking onError
* - Retry mechanism after a JSON request fails
* - Delay clock tick when there is already an ongoing request
* - Use a true JSON parser to validate what we received
67
* - Use idleTime and idleTimeout to re-schedule autofresh after
* a likely idle termination by chilli
* - check that the library can be compiled as a Flash swf library
* and used from Flash BBSMs with the same API.
*
* Copyright (C) Y.Deltroo 2007
* Distributed under the BSD License
*
* This file also contains third party code :
* - MD5, distributed under the BSD license
* http://pajhome.org.uk/crypt/md5
*
*/
var chilliLibrary = { revision:'85' , apiVersion:'2.0' } ;
/**
68
* Global chilliController object
*
* CONFIGUARION PROPERTIES
* -----------------------
* ident (String)
* Hex encoded string (used for client side CHAP-Password calculations)
*
* interval (Number)
* Poll the gateway every interval, in seconds
*
* host (String)
* IP address of the controller (String)
*
* port (Number)
* UAM port to direct request to on the gateway
*
* ssl (Boolean)
* Shall we use HTTP or HTTPS to communicate with the chilli controller
*
69
* uamService : String
* !!! EXPERIMENTAL FEATURE !!!
* URL to external uamService script (used for external MD5 calculation when
portal/chilli trust is required)
* This remote script runs on a SSL enable web server, and knows UAM SECRET.
* The chilliController javascript object will send the password over SSL (and
challenge for CHAP)
* UAM SERVICE should reply with a JSON response containing
* - CHAP logon : CHAP-Password X0Red with UAM SECRET
* - PAP logon : Password XORed with UAM SECRET
*
* For more information http://www.coova.org/CoovaChilli/JSON
*
*/
if (!chilliController || !chilliController.host)
var chilliController = { interval:30 , host:"10.1.0.1" , port:3990 , ident:'00' , ssl:false ,
uamService: };
70
/* Define clientState numerical code constants */
chilliController.stateCodes = { UNKNOWN:-1 , NOT_AUTH:0 , AUTH:1 ,
AUTH_PENDING:2 , AUTH_SPLASH:3 } ;
/* Initializing session and accounting members, objet properties */
chilliController.session = {} ;
chilliController.accounting = {} ;
chilliController.redir = {} ;
chilliController.location = { name: '' } ;
chilliController.challenge = '' ;
chilliController.message = '' ;
chilliController.clientState = chilliController.stateCodes.UNKNOWN ;
chilliController.command = '' ;
chilliController.autorefreshTimer = 0 ;
/* This method returns the root URL for commands */
chilliController.urlRoot = function () {
var protocol = ( chilliController.ssl ) ? "https" : "http" ;
71
var urlRoot = protocol + "://" + chilliController.host + (chilliController.port ? ":" +
chilliController.port.toString() : "") + "/json/" ;
return urlRoot;
};
/* Default event handlers */
chilliController.onUpdate = function ( cmd ) {
log('>> Default onUpdate handler. <<\n>> You should write your own. <<\n>> cmd =
' + cmd + ' <<' );
};
chilliController.onError = function ( str ) {
log ( '>> Default Error Handler<<\n>> You should write your own <<\n>> ' + str + '
<<' );
};
chilliController.formatTime = function ( t , zeroReturn ) {
if ( typeof(t) == 'undefined' ) {
72
return "Not available";
}
t = parseInt ( t , 10 ) ;
if ( (typeof (zeroReturn) !='undefined') && ( t === 0 ) ) {
return zeroReturn;
}
var h = Math.floor( t/3600 ) ;
var m = Math.floor( (t - 3600*h)/60 ) ;
var s = t % 60 ;
var s_str = s.toString();
if (s < 10 ) { s_str = '0' + s_str; }
var m_str = m.toString();
if (m < 10 ) { m_str= '0' + m_str; }
var h_str = h.toString();
73
if (h < 10 ) { h_str= '0' + h_str; }
if ( t < 60 ) { return s_str + 's' ; }
else if ( t < 3600 ) { return m_str + 'm' + s_str + 's' ; }
else { return h_str + 'h' + m_str + 'm' + s_str + 's'; }
};
chilliController.formatBytes = function ( b , zeroReturn ) {
if ( typeof(b) == 'undefined' ) {
b = 0;
} else {
b = parseInt ( b , 10 ) ;
}
if ( (typeof (zeroReturn) !='undefined') && ( b === 0 ) ) {
return zeroReturn;
}
74
var kb = Math.round(b / 10) / 100;
if (kb < 1) return b + ' Bytes';
var mb = Math.round(kb / 10) / 100;
if (mb < 1) return kb + ' Kilobytes';
var gb = Math.round(mb / 10) / 100;
if (gb < 1) return mb + ' Megabytes';
return gb + ' Gigabytes';
};
/**
* Global chilliController object
*
* PUBLIC METHODS
* --------------
75
* logon ( username, password ) :
* Attempt a CHAP logon with username/password
* issues a /logon command to chilli daemon
*
* logon2 ( username, response ) :
* Attempt a CHAP logon with username/response
* issues a /logon command to chilli daemon
*
* logoff () :
* Disconnect the current user by issuing a
* /logoff command to the chilli daemon
*
* refresh () :
* Issues a /status command to chilli daemon to refresh
* the local chilliController object state/session data
*
*/
76
chilliController.logon = function ( username , password ) {
if ( typeof(username) !== 'string') {
chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
}
if ( typeof(password) !== 'string') {
chilliController.onError( 2 , "password missing (or incorrect type)" ) ;
}
log ( 'chilliController.logon( "' + username + '" , "' + password + ' " )' );
chilliController.temp = { 'username': username , 'password': password };
chilliController.command = 'logon';
log ('chilliController.logon: asking for a new challenge ' );
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.logonStep2 ;
chilliController.clientState = chilliController.AUTH_PENDING ;
77
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
};
chilliController.logon2 = function ( username , response ) {
if ( typeof(username) !== 'string') {
chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
}
if ( typeof(response) !== 'string') {
chilliController.onError( 2 , "response missing (or incorrect type)" ) ;
}
log ( 'chilliController.logon2( "' + username + '" , "' + response + ' " )' );
chilliController.temp = { 'username': username , 'response': response };
chilliController.command = 'logon2';
log ('chilliController.logon2: asking for a new challenge ' );
chilliJSON.onError = chilliController.onError ;
78
chilliJSON.onJSONReady = chilliController.logonStep2 ;
chilliController.clientState = chilliController.AUTH_PENDING ;
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
};
/**
* Second part of the logon process invoked after
* the just requested challenge has been received
*/
chilliController.logonStep2 = function ( resp ) {
log('Entering logonStep 2');
if ( typeof (resp.challenge) != 'string' ) {
log('logonStep2: cannot find a challenge. Aborting.');
return chilliController.onError('Cannot get challenge');
}
79
if ( resp.clientSate === chilliController.stateCodes.AUTH ) {
log('logonStep2: Already connected. Aborting.');
return chilliController.onError('Already connected.');
}
var challenge = resp.challenge;
var username = chilliController.temp.username ;
var password = chilliController.temp.password ;
var response = chilliController.temp.response ;
log ('chilliController.logonStep2: Got challenge = ' + challenge );
if ( chilliController.uamService ) { /* MD5 CHAP will be calculated by uamService */
log ('chilliController.logonStep2: Logon using uamService (external MD5 CHAP)');
var c ;
if ( chilliController.uamService.indexOf('?') === -1 ) {
c = '?' ;
}
80
else {
c = '&' ;
}
// Build command URL
var url = chilliController.uamService + c + 'username=' + escape(username)
+'&password=' + escape(password) +'&challenge=' + challenge ;
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
url += '&userurl='+chilliController.queryObj['userurl'] ;
}
// Make uamService request
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.logonStep3 ;
chilliController.clientState = chilliController.AUTH_PENDING ;
chilliJSON.get( url ) ;
}
else {
/* TODO: Should check if challenge has expired and possibly get a new one */
/* OR always call status first to get a fresh challenge */
if (!response || response == '') {
/* Calculate MD5 CHAP at the client side */
var myMD5 = new ChilliMD5();
response = myMD5.chap ( chilliController.ident , password , challenge );
81
log ( 'chilliController.logonStep2: Calculating CHAP-Password = ' + response );
}
/* Prepare chilliJSON for logon request */
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliController.clientState = chilliController.stateCodes.AUTH_PENDING ;
/* Build /logon command URL */
var logonUrl = chilliController.urlRoot() + 'logon?username=' + escape(username) +
'&response=' + response;
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
}
chilliJSON.get ( logonUrl ) ;
}
};
/**
* Third part of the logon process invoked after
* getting a uamService response
*/
chilliController.logonStep3 = function ( resp ) {
log('Entering logonStep 3');
var username = chilliController.temp.username ;
if ( typeof (resp.response) == 'string' ) {
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliController.clientState = chilliController.stateCodes.AUTH_PENDING ;
82
/* Build /logon command URL */
var logonUrl = chilliController.urlRoot() + 'logon?username=' + escape(username) +
'&response=' + resp.response;
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
}
chilliJSON.get ( logonUrl ) ;
}
}
chilliController.refresh = function ( ) {
if ( chilliController.autorefreshTimer ) {
chilliController.command = 'autorefresh' ;
}
else {
chilliController.command = 'refresh' ;
}
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
};
chilliController.logoff = function () {
chilliController.command = 'logoff' ;
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliJSON.get( chilliController.urlRoot() + 'logoff' );
};
/* *
83
*
* This functions does some check/type processing on the JSON resp
* and updates the corresponding chilliController members
*
*/
chilliController.processReply = function ( resp ) {
if ( typeof (resp.message) == 'string' ) {
/* The following trick will replace HTML entities with the corresponding
* character. This will not work in Flash (no innerHTML)
*/
var fakediv = document.createElement('div');
fakediv.innerHTML = resp.message ;
chilliController.message = fakediv.innerHTML ;
}
if ( typeof (resp.challenge) == 'string' ) {
chilliController.challenge = resp.challenge ;
}
if ( typeof ( resp.location ) == 'object' ) {
chilliController.location = resp.location ;
}
if ( typeof ( resp.accounting ) == 'object' ) {
chilliController.accounting = resp.accounting ;
}
if ( (typeof ( resp.redir ) == 'object') ) {
chilliController.redir = resp.redir ;
}
84
/* Update the session member only the first time after AUTH */
if ( (typeof ( resp.session ) == 'object') &&
( chilliController.session==null || (
( chilliController.clientState !== chilliController.stateCodes.AUTH ) &&
( resp.clientState === chilliController.stateCodes.AUTH )))) {
chilliController.session = resp.session ;
if ( resp.session.startTime ) {
chilliController.session.startTime = new Date();
chilliController.session.startTime.setTime(resp.session.startTime);
}
}
/* Update clientState */
if ( ( resp.clientState === chilliController.stateCodes.NOT_AUTH ) ||
( resp.clientState === chilliController.stateCodes.AUTH ) ||
( resp.clientState === chilliController.stateCodes.AUTH_SPLASH ) ||
( resp.clientState === chilliController.stateCodes.AUTH_PENDING ) ) {
chilliController.clientState = resp.clientState ;
}
else {
chilliController.onError("Unknown clientState found in JSON reply");
}
/* Launch or stop the autorefresh timer if required */
if ( chilliController.clientState === chilliController.stateCodes.AUTH ) {
if ( !chilliController.autorefreshTimer ) {
85
chilliController.autorefreshTimer = setInterval ('chilliController.refresh()' ,
1000*chilliController.interval);
}
}
else if ( chilliController.clientState === chilliController.stateCodes.NOT_AUTH ) {
clearInterval ( chilliController.autorefreshTimer ) ;
chilliController.autorefreshTimer = 0 ;
}
/* Lastly... call the event handler */
log ('chilliController.processReply: Calling onUpdate. clienState = ' +
chilliController.clientState);
chilliController.onUpdate( chilliController.command );
};
/**
* chilliJSON object
*
* This private objet implements the cross domain hack
* If no answer is received before timeout, then an error is raised.
*
*/
var chilliJSON = { timeout:25000 , timer:0 , node:0 , timestamp:0 };
chilliJSON.expired = function () {
if ( chilliJSON.node.text ) {
log ('chilliJSON: reply content \n' + chilliJSON.node.text );
}
else {
86
log ('chilliJSON: request timed out (or reply is not valid JS)');
}
clearInterval ( chilliJSON.timer ) ;
chilliJSON.timer = 0 ;
/* remove the <SCRIPT> tag node that we have created */
if ( typeof (chilliJSON.node) !== 'number' ) {
document.getElementsByTagName('head')[0].removeChild ( chilliJSON.node );
}
chilliJSON.node = 0;
/* TODO: Implement some kind of retry mechanism here ... */
chilliJSON.onError('JSON request timed out (or reply is not valid)');
};
chilliJSON.reply = function ( raw ) {
clearInterval ( chilliJSON.timer ) ;
chilliJSON.timer = 0 ;
var now = new Date() ;
var end = now.getTime() ;
if ( chilliJSON.timestamp ) {
log ( 'chilliJSON: JSON reply received in ' + ( end - chilliJSON.timestamp ) + ' ms\n'
+ dumpObject(raw) );
}
if ( typeof (chilliJSON.node) !== 'number' ) {
document.getElementsByTagName('head')[0].removeChild ( chilliJSON.node );
}
87
chilliJSON.node = 0;
/* TODO: We should parse raw JSON as an extra security measure */
chilliJSON.onJSONReady( raw ) ;
} ;
chilliJSON.get = function ( gUrl ) {
if ( typeof(gUrl) == "string" ) {
chilliJSON.url = gUrl ;
}
else {
log ( "chilliJSON:error:Incorrect url passed to chilliJSON.get():" + gUrl );
chilliJSON.onError ( "Incorrect url passed to chilliJSON.get() " );
return ;
}
if ( chilliJSON.timer ) {
log('logon: There is already a request running. Return without launching a new
request.');
return ;
}
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
var c ;
if ( this.url.indexOf('?') === -1 ) {
c = '?' ;
}
else {
88
c = '&' ;
}
scriptElement.src = chilliJSON.url + c + 'callback=chilliJSON.reply' ;
scriptElement.src += '&'+Math.random(); // prevent caching in Safari
/* Adding the node that will trigger the HTTP request to the DOM tree */
chilliJSON.node =
document.getElementsByTagName('head')[0].appendChild(scriptElement);
/* Using interval instead of timeout to support Flash 5,6,7 */
chilliJSON.timer = setInterval ( 'chilliJSON.expired()' , chilliJSON.timeout ) ;
var now = new Date();
chilliJSON.timestamp = now.getTime() ;
log ('chilliJSON: getting ' + chilliJSON.url + ' . Waiting for reply ...');
}; // end chilliJSON.get = function ( url )
/**
* chilliClock object
*
* Can be used by BBSMs to display a count down.
*
* Will sync with chilliController and modulate the delay to call onTick
* This will avoid ugly sequence of short updates in the IO
* (not yet implemented)
*
*/
var chilliClock = { isStarted : 0 };
89
chilliClock.onTick = function () {
log ("You should define your own onTick() handler on this clock object. Clock value
= " + this.value );
};
chilliClock.increment = function () {
chilliClock.value = chilliClock.value + 1 ;
chilliClock.onTick( chilliClock.value ) ;
};
chilliClock.resync = function ( newval ) {
clearInterval ( chilliClock.isStarted ) ;
chilliClock.value = parseInt( newval , 10 ) ;
chilliClock.isStarted = setInterval ( 'chilliClock.increment()' , 1000 );
};
chilliClock.start = function ( newval ) {
if ( typeof (newval) !== 'Number' ) {
chilliClock.resync ( 0 ) ;
}
else {
chilliClock.resync ( newval ) ;
}
};
chilliClock.stop = function () {
clearInterval ( chilliClock.isStarted ) ;
chilliClock.isStarted = 0 ;
};
90
function getel(e) {
if (document.getElementById) {
return document.getElementById(e);
} else if (document.all){
return document.all[e];
}
}
function log( msg , messageLevel ) {
if (!chilliController.debug) return;
if ( typeof(trace)=="function") {
// ActionScript trace
trace ( msg );
}
else if ( typeof(console)=="object") {
// FireBug console
console.debug ( msg );
}
if ( getel('debugarea') ) {
var e = getel('debugarea') ;
e.value = e.value + '\n' + msg;
e.scrollTop = e.scrollHeight - e.clientHeight;
}
}
/* Transform an object to a text representation */
function dumpObject ( obj ) {
var str = '' ;
for (var key in obj ) {
str = str + " " + key + " = " + obj[key] + "\n" ;
91
if ( typeof ( obj[key] ) == "object" ) {
for ( var key2 in obj[key] ) {
str = str + " " + key2 + " = " + obj[key][key2] + "\n" ;
}
}
}
return str;
}
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*
* added by Y.DELTROO
* - new functions: chap(), hex2binl() and str2hex()
* - modifications to comply with the jslint test, http://www.jslint.com/
*
* Copyright (c) 2007
* Distributed under the BSD License
*
*/
function ChilliMD5() {
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
92
this.hex_md5 = function (s){
return binl2hex(core_md5(str2binl(s), s.length * chrsz));
};
this.chap = function ( hex_ident , str_password , hex_chal ) {
// Convert everything to hex encoded strings
var hex_password = str2hex ( str_password );
// concatenate hex encoded strings
var hex = hex_ident + hex_password + hex_chal;
// Convert concatenated hex encoded string to its binary representation
var bin = hex2binl ( hex ) ;
// Calculate MD5 on binary representation
var md5 = core_md5( bin , hex.length * 4 ) ;
return binl2hex( md5 );
};
function core_md5(x, len) {
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16) {
var olda = a;
93
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
94
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
95
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return [ a, b, c, d ];
}
function md5_cmn(q, a, b, x, s, t) {
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t) {
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t) {
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t) {
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
96
}
function safe_add(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function bit_rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt));
}
function str2binl(str) {
var bin = [] ;
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz) {
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
}
return bin;
}
function binl2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
function str2hex ( str ) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var hex = '';
97
var val ;
for ( var i=0 ; i<str.length ; i++) {
/* TODO: adapt this if chrz=16 */
val = str.charCodeAt(i);
hex = hex + hex_tab.charAt( val/16 );
hex = hex + hex_tab.charAt( val%16 );
}
return hex;
}
function hex2binl ( hex ) {
/* Clean-up hex encoded input string */
hex = hex.toLowerCase() ;
hex = hex.replace( / /g , "");
var bin =[] ;
/* Transfrom to array of integers (binary representation) */
for ( i=0 ; i < hex.length*4 ; i=i+8 ) {
octet = parseInt( hex.substr( i/4 , 2) , 16) ;
bin[i>>5] |= ( octet & 255 ) << (i%32);
}
return bin;
}
} // end of ChilliMD5 constructor
Anexo 3 – Arquivo de configuração index.html
<html>
<head>
<!--
98
A purely HTML based captive portal using the JSON interface of CoovaChilli
-->
<title>coova hotspot</title>
<style><!--
body,td,a,p,h{
font-family:arial,sans-serif;
}
body {
text-align: center;
padding-top: 30px;
margin: auto;
width: 50%;
}
#MyChilli {
background: url("/images/coova.jpg") right top no-repeat;
margin: auto;
text-align: left;
padding: 10px 0 30px 0;
}
#locationName {
height: 50px;
font-size: 120%;
font-weight: bold;
}
#chilliPage {
border: 1px solid orange;
padding: 20px 20px 20px 20px;
margin-top: 20px;
}
#signUpRow {
display: inline;
}
-->
99
</style>
</head>
<body>
<div id="MyChilli">
<div id="noLocation" style="display:none;">
<p style="padding-top: 100px;"><strong>You are not at a hotspot.</strong> If you
want to see a a sample login page using the <a href="http://www.coova.org/Coova
Chilli/JSON">JSON interface</a> of <a
href="http://www.coova.org/CoovaChilli">CoovaChilli</a>, then <a href="javascript:
window.location = 'view-source:' + window.location.href;">
view the source</a> of this page.</p>
</div>
<script id='chillijs' src='http://10.1.0.1/uam/chilli.js'></script>
</div>
</body>
</html>
Anexo 4 – Arquivo de configuração do arquivo ChilliLibrary.js
/**
* ChilliLibrary.js
* V2.0
*
* This Javascript library can be used to create HTML/JS browser
* based smart clients (BBSM) for the CoovaChilli access controller
* Coova Chilli rev 81 or higher is required
*
* This library creates four global objects :
*
* - chilliController Expose session/client state and
* connect()/disconnect() methods the to BBSM.
*
* - chilliJSON INTERNAL (should not be called from the BBSM).
* Issues a command to the chilli daemon by adding a new <SCRIPT>
100
* tag to the HTML DOM (this hack enables cross server requests).
*
* - chilliClock Can be used by BBSMs to display a count down.
* Will sync with chilliController for smooth UI display (not yet
implemented)
*
* - chilliLibrary Expose API and library versions
*
* For more information http://www.coova.org/CoovaChilli/JSON
*
* TODO :
* - Fine tune level of debug messages
* - Define error code when invoking onError
* - Retry mechanism after a JSON request fails
* - Delay clock tick when there is already an ongoing request
* - Use a true JSON parser to validate what we received
* - Use idleTime and idleTimeout to re-schedule autofresh after
* a likely idle termination by chilli
* - check that the library can be compiled as a Flash swf library
* and used from Flash BBSMs with the same API.
*
* Copyright (C) Y.Deltroo 2007
* Distributed under the BSD License
*
* This file also contains third party code :
* - MD5, distributed under the BSD license
* http://pajhome.org.uk/crypt/md5
*
*/
var chilliLibrary = { revision:'85' , apiVersion:'2.0' } ;
101
/**
* Global chilliController object
*
* CONFIGUARION PROPERTIES
* -----------------------
* ident (String)
* Hex encoded string (used for client side CHAP-Password calculations)
*
* interval (Number)
* Poll the gateway every interval, in seconds
*
* host (String)
* IP address of the controller (String)
*
* port (Number)
* UAM port to direct request to on the gateway
*
* ssl (Boolean)
* Shall we use HTTP or HTTPS to communicate with the chilli controller
*
* uamService : String
* !!! EXPERIMENTAL FEATURE !!!
* URL to external uamService script (used for external MD5 calculation when
portal/chilli trust is required)
* This remote script runs on a SSL enable web server, and knows UAM
SECRET.
* The chilliController javascript object will send the password over SSL (and
challenge for CHAP)
* UAM SERVICE should reply with a JSON response containing
* - CHAP logon : CHAP-Password X0Red with UAM SECRET
* - PAP logon : Password XORed with UAM SECRET
*
* For more information http://www.coova.org/CoovaChilli/JSON
102
*
*/
if (!chilliController || !chilliController.host)
var chilliController = { interval:30 , host:"10.1.0.1" , port:3990 , ident:'00' , ssl:false ,
uamService: };
/* Define clientState numerical code constants */
chilliController.stateCodes = { UNKNOWN:-1 , NOT_AUTH:0 , AUTH:1 ,
AUTH_PENDING:2 , AUTH_SPLASH:3 } ;
/* Initializing session and accounting members, objet properties */
chilliController.session = {} ;
chilliController.accounting = {} ;
chilliController.redir = {} ;
chilliController.location = { name: '' } ;
chilliController.challenge = '' ;
chilliController.message = '' ;
chilliController.clientState = chilliController.stateCodes.UNKNOWN ;
chilliController.command = '' ;
chilliController.autorefreshTimer = 0 ;
/* This method returns the root URL for commands */
chilliController.urlRoot = function () {
var protocol = ( chilliController.ssl ) ? "https" : "http" ;
var urlRoot = protocol + "://" + chilliController.host + (chilliController.port ?
":" + chilliController.port.toString() : "") + "/json/" ;
return urlRoot;
};
/* Default event handlers */
chilliController.onUpdate = function ( cmd ) {
103
log('>> Default onUpdate handler. <<\n>> You should write your own. <<\n>>
cmd = ' + cmd + ' <<' );
};
chilliController.onError = function ( str ) {
log ( '>> Default Error Handler<<\n>> You should write your own <<\n>> ' +
str + ' <<' );
};
chilliController.formatTime = function ( t , zeroReturn ) {
if ( typeof(t) == 'undefined' ) {
return "Not available";
}
t = parseInt ( t , 10 ) ;
if ( (typeof (zeroReturn) !='undefined') && ( t === 0 ) ) {
return zeroReturn;
}
var h = Math.floor( t/3600 ) ;
var m = Math.floor( (t - 3600*h)/60 ) ;
var s = t % 60 ;
var s_str = s.toString();
if (s < 10 ) { s_str = '0' + s_str; }
var m_str = m.toString();
if (m < 10 ) { m_str= '0' + m_str; }
var h_str = h.toString();
if (h < 10 ) { h_str= '0' + h_str; }
104
if ( t < 60 ) { return s_str + 's' ; }
else if ( t < 3600 ) { return m_str + 'm' + s_str + 's' ; }
else { return h_str + 'h' + m_str + 'm' + s_str + 's'; }
};
chilliController.formatBytes = function ( b , zeroReturn ) {
if ( typeof(b) == 'undefined' ) {
b = 0;
} else {
b = parseInt ( b , 10 ) ;
}
if ( (typeof (zeroReturn) !='undefined') && ( b === 0 ) ) {
return zeroReturn;
}
var kb = Math.round(b / 10) / 100;
if (kb < 1) return b + ' Bytes';
var mb = Math.round(kb / 10) / 100;
if (mb < 1) return kb + ' Kilobytes';
var gb = Math.round(mb / 10) / 100;
if (gb < 1) return mb + ' Megabytes';
return gb + ' Gigabytes';
};
105
/**
* Global chilliController object
*
* PUBLIC METHODS
* --------------
* logon ( username, password ) :
* Attempt a CHAP logon with username/password
* issues a /logon command to chilli daemon
*
* logon2 ( username, response ) :
* Attempt a CHAP logon with username/response
* issues a /logon command to chilli daemon
*
* logoff () :
* Disconnect the current user by issuing a
* /logoff command to the chilli daemon
*
* refresh () :
* Issues a /status command to chilli daemon to refresh
* the local chilliController object state/session data
*
*/
chilliController.logon = function ( username , password ) {
if ( typeof(username) !== 'string') {
chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
}
if ( typeof(password) !== 'string') {
chilliController.onError( 2 , "password missing (or incorrect type)" ) ;
}
106
log ( 'chilliController.logon( "' + username + '" , "' + password + ' " )' );
chilliController.temp = { 'username': username , 'password': password };
chilliController.command = 'logon';
log ('chilliController.logon: asking for a new challenge ' );
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.logonStep2 ;
chilliController.clientState = chilliController.AUTH_PENDING ;
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
};
chilliController.logon2 = function ( username , response ) {
if ( typeof(username) !== 'string') {
chilliController.onError( 1 , "username missing (or incorrect type)" ) ;
}
if ( typeof(response) !== 'string') {
chilliController.onError( 2 , "response missing (or incorrect type)" ) ;
}
log ( 'chilliController.logon2( "' + username + '" , "' + response + ' " )' );
chilliController.temp = { 'username': username , 'response': response };
chilliController.command = 'logon2';
log ('chilliController.logon2: asking for a new challenge ' );
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.logonStep2 ;
chilliController.clientState = chilliController.AUTH_PENDING ;
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
};
107
/**
* Second part of the logon process invoked after
* the just requested challenge has been received
*/
chilliController.logonStep2 = function ( resp ) {
log('Entering logonStep 2');
if ( typeof (resp.challenge) != 'string' ) {
log('logonStep2: cannot find a challenge. Aborting.');
return chilliController.onError('Cannot get challenge');
}
if ( resp.clientSate === chilliController.stateCodes.AUTH ) {
log('logonStep2: Already connected. Aborting.');
return chilliController.onError('Already connected.');
}
var challenge = resp.challenge;
var username = chilliController.temp.username ;
var password = chilliController.temp.password ;
var response = chilliController.temp.response ;
log ('chilliController.logonStep2: Got challenge = ' + challenge );
if ( chilliController.uamService ) { /* MD5 CHAP will be calculated by
uamService */
log ('chilliController.logonStep2: Logon using uamService (external
MD5 CHAP)');
108
var c ;
if ( chilliController.uamService.indexOf('?') === -1 ) {
c = '?' ;
}
else {
c = '&' ;
}
// Build command URL
var url = chilliController.uamService + c + 'username=' +
escape(username) +'&password=' + escape(password) +'&challenge=' + challenge ;
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
url += '&userurl='+chilliController.queryObj['userurl'] ;
}
// Make uamService request
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.logonStep3 ;
chilliController.clientState = chilliController.AUTH_PENDING ;
chilliJSON.get( url ) ;
}
else {
/* TODO: Should check if challenge has expired and possibly get a new
one */
/* OR always call status first to get a fresh challenge */
if (!response || response == '') {
/* Calculate MD5 CHAP at the client side */
var myMD5 = new ChilliMD5();
109
response = myMD5.chap ( chilliController.ident , password , challenge
);
log ( 'chilliController.logonStep2: Calculating CHAP-Password = ' +
response );
}
/* Prepare chilliJSON for logon request */
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliController.clientState =
chilliController.stateCodes.AUTH_PENDING ;
/* Build /logon command URL */
var logonUrl = chilliController.urlRoot() + 'logon?username=' +
escape(username) + '&response=' + response;
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
}
chilliJSON.get ( logonUrl ) ;
}
};
/**
* Third part of the logon process invoked after
* getting a uamService response
*/
chilliController.logonStep3 = function ( resp ) {
log('Entering logonStep 3');
var username = chilliController.temp.username ;
if ( typeof (resp.response) == 'string' ) {
110
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliController.clientState =
chilliController.stateCodes.AUTH_PENDING ;
/* Build /logon command URL */
var logonUrl = chilliController.urlRoot() + 'logon?username=' +
escape(username) + '&response=' + resp.response;
if (chilliController.queryObj && chilliController.queryObj['userurl'] ) {
logonUrl += '&userurl='+chilliController.queryObj['userurl'] ;
}
chilliJSON.get ( logonUrl ) ;
}
}
chilliController.refresh = function ( ) {
if ( chilliController.autorefreshTimer ) {
chilliController.command = 'autorefresh' ;
}
else {
chilliController.command = 'refresh' ;
}
chilliJSON.onError = chilliController.onError ;
chilliJSON.onJSONReady = chilliController.processReply ;
chilliJSON.get( chilliController.urlRoot() + 'status' ) ;
};
chilliController.logoff = function () {
chilliController.command = 'logoff' ;
chilliJSON.onError = chilliController.onError ;
111
chilliJSON.onJSONReady = chilliController.processReply ;
chilliJSON.get( chilliController.urlRoot() + 'logoff' );
};
/* *
*
* This functions does some check/type processing on the JSON resp
* and updates the corresponding chilliController members
*
*/
chilliController.processReply = function ( resp ) {
if ( typeof (resp.message) == 'string' ) {
/* The following trick will replace HTML entities with the
corresponding
* character. This will not work in Flash (no innerHTML)
*/
var fakediv = document.createElement('div');
fakediv.innerHTML = resp.message ;
chilliController.message = fakediv.innerHTML ;
}
if ( typeof (resp.challenge) == 'string' ) {
chilliController.challenge = resp.challenge ;
}
if ( typeof ( resp.location ) == 'object' ) {
chilliController.location = resp.location ;
}
if ( typeof ( resp.accounting ) == 'object' ) {
112
chilliController.accounting = resp.accounting ;
}
if ( (typeof ( resp.redir ) == 'object') ) {
chilliController.redir = resp.redir ;
}
/* Update the session member only the first time after AUTH */
if ( (typeof ( resp.session ) == 'object') &&
( chilliController.session==null || (
( chilliController.clientState !== chilliController.stateCodes.AUTH )
&&
( resp.clientState === chilliController.stateCodes.AUTH )))) {
chilliController.session = resp.session ;
if ( resp.session.startTime ) {
chilliController.session.startTime = new Date();
chilliController.session.startTime.setTime(resp.session.startTime);
}
}
/* Update clientState */
if ( ( resp.clientState === chilliController.stateCodes.NOT_AUTH ) ||
( resp.clientState === chilliController.stateCodes.AUTH ) ||
( resp.clientState === chilliController.stateCodes.AUTH_SPLASH ) ||
( resp.clientState === chilliController.stateCodes.AUTH_PENDING ) ) {
chilliController.clientState = resp.clientState ;
}
else {
chilliController.onError("Unknown clientState found in JSON reply");
113
}
/* Launch or stop the autorefresh timer if required */
if ( chilliController.clientState === chilliController.stateCodes.AUTH ) {
if ( !chilliController.autorefreshTimer ) {
chilliController.autorefreshTimer = setInterval
('chilliController.refresh()' , 1000*chilliController.interval);
}
}
else if ( chilliController.clientState ===
chilliController.stateCodes.NOT_AUTH ) {
clearInterval ( chilliController.autorefreshTimer ) ;
chilliController.autorefreshTimer = 0 ;
}
/* Lastly... call the event handler */
log ('chilliController.processReply: Calling onUpdate. clienState = ' +
chilliController.clientState);
chilliController.onUpdate( chilliController.command );
};
/**
* chilliJSON object
*
* This private objet implements the cross domain hack
* If no answer is received before timeout, then an error is raised.
*
*/
114
var chilliJSON = { timeout:25000 , timer:0 , node:0 , timestamp:0 };
chilliJSON.expired = function () {
if ( chilliJSON.node.text ) {
log ('chilliJSON: reply content \n' + chilliJSON.node.text );
}
else {
log ('chilliJSON: request timed out (or reply is not valid JS)');
}
clearInterval ( chilliJSON.timer ) ;
chilliJSON.timer = 0 ;
/* remove the <SCRIPT> tag node that we have created */
if ( typeof (chilliJSON.node) !== 'number' ) {
document.getElementsByTagName('head')[0].removeChild (
chilliJSON.node );
}
chilliJSON.node = 0;
/* TODO: Implement some kind of retry mechanism here ... */
chilliJSON.onError('JSON request timed out (or reply is not valid)');
};
chilliJSON.reply = function ( raw ) {
clearInterval ( chilliJSON.timer ) ;
chilliJSON.timer = 0 ;
var now = new Date() ;
var end = now.getTime() ;
115
if ( chilliJSON.timestamp ) {
log ( 'chilliJSON: JSON reply received in ' + ( end -
chilliJSON.timestamp ) + ' ms\n' + dumpObject(raw) );
}
if ( typeof (chilliJSON.node) !== 'number' ) {
document.getElementsByTagName('head')[0].removeChild (
chilliJSON.node );
}
chilliJSON.node = 0;
/* TODO: We should parse raw JSON as an extra security measure */
chilliJSON.onJSONReady( raw ) ;
} ;
chilliJSON.get = function ( gUrl ) {
if ( typeof(gUrl) == "string" ) {
chilliJSON.url = gUrl ;
}
else {
log ( "chilliJSON:error:Incorrect url passed to chilliJSON.get():"
+ gUrl );
chilliJSON.onError ( "Incorrect url passed to chilliJSON.get() "
);
return ;
}
if ( chilliJSON.timer ) {
log('logon: There is already a request running. Return without
launching a new request.');
116
return ;
}
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
var c ;
if ( this.url.indexOf('?') === -1 ) {
c = '?' ;
}
else {
c = '&' ;
}
scriptElement.src = chilliJSON.url + c + 'callback=chilliJSON.reply' ;
scriptElement.src += '&'+Math.random(); // prevent caching in Safari
/* Adding the node that will trigger the HTTP request to the DOM tree
*/
chilliJSON.node =
document.getElementsByTagName('head')[0].appendChild(scriptElement);
/* Using interval instead of timeout to support Flash 5,6,7 */
chilliJSON.timer = setInterval ( 'chilliJSON.expired()' ,
chilliJSON.timeout ) ;
var now = new Date();
chilliJSON.timestamp = now.getTime() ;
log ('chilliJSON: getting ' + chilliJSON.url + ' . Waiting for reply ...');
}; // end chilliJSON.get = function ( url )
117
/**
* chilliClock object
*
* Can be used by BBSMs to display a count down.
*
* Will sync with chilliController and modulate the delay to call onTick
* This will avoid ugly sequence of short updates in the IO
* (not yet implemented)
*
*/
var chilliClock = { isStarted : 0 };
chilliClock.onTick = function () {
log ("You should define your own onTick() handler on this clock object. Clock
value = " + this.value );
};
chilliClock.increment = function () {
chilliClock.value = chilliClock.value + 1 ;
chilliClock.onTick( chilliClock.value ) ;
};
chilliClock.resync = function ( newval ) {
clearInterval ( chilliClock.isStarted ) ;
chilliClock.value = parseInt( newval , 10 ) ;
chilliClock.isStarted = setInterval ( 'chilliClock.increment()' , 1000 );
};
chilliClock.start = function ( newval ) {
118
if ( typeof (newval) !== 'Number' ) {
chilliClock.resync ( 0 ) ;
}
else {
chilliClock.resync ( newval ) ;
}
};
chilliClock.stop = function () {
clearInterval ( chilliClock.isStarted ) ;
chilliClock.isStarted = 0 ;
};
function getel(e) {
if (document.getElementById) {
return document.getElementById(e);
} else if (document.all){
return document.all[e];
}
}
function log( msg , messageLevel ) {
if (!chilliController.debug) return;
if ( typeof(trace)=="function") {
// ActionScript trace
trace ( msg );
}
else if ( typeof(console)=="object") {
// FireBug console
console.debug ( msg );
}
119
if ( getel('debugarea') ) {
var e = getel('debugarea') ;
e.value = e.value + '\n' + msg;
e.scrollTop = e.scrollHeight - e.clientHeight;
}
}
/* Transform an object to a text representation */
function dumpObject ( obj ) {
var str = '' ;
for (var key in obj ) {
str = str + " " + key + " = " + obj[key] + "\n" ;
if ( typeof ( obj[key] ) == "object" ) {
for ( var key2 in obj[key] ) {
str = str + " " + key2 + " = " + obj[key][key2] + "\n" ;
}
}
}
return str;
}
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*
* added by Y.DELTROO
120
* - new functions: chap(), hex2binl() and str2hex()
* - modifications to comply with the jslint test, http://www.jslint.com/
*
* Copyright (c) 2007
* Distributed under the BSD License
*
*/
function ChilliMD5() {
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
this.hex_md5 = function (s){
return binl2hex(core_md5(str2binl(s), s.length * chrsz));
};
this.chap = function ( hex_ident , str_password , hex_chal ) {
// Convert everything to hex encoded strings
var hex_password = str2hex ( str_password );
// concatenate hex encoded strings
var hex = hex_ident + hex_password + hex_chal;
// Convert concatenated hex encoded string to its binary representation
var bin = hex2binl ( hex ) ;
// Calculate MD5 on binary representation
var md5 = core_md5( bin , hex.length * 4 ) ;
121
return binl2hex( md5 );
};
function core_md5(x, len) {
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
122
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
123
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return [ a, b, c, d ];
}
function md5_cmn(q, a, b, x, s, t) {
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
124
function md5_ff(a, b, c, d, x, s, t) {
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t) {
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t) {
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t) {
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function safe_add(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function bit_rol(num, cnt) {
return (num << cnt) | (num >>> (32 - cnt));
}
function str2binl(str) {
var bin = [] ;
var mask = (1 << chrsz) - 1;
for (var i = 0; i < str.length * chrsz; i += chrsz) {
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
}
return bin;
}
125
function binl2hex(binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for (var i = 0; i < binarray.length * 4; i++) {
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
function str2hex ( str ) {
var hex_tab = hexcase ? "0123456789ABCDEF" :
"0123456789abcdef";
var hex = '';
var val ;
for ( var i=0 ; i<str.length ; i++) {
/* TODO: adapt this if chrz=16 */
val = str.charCodeAt(i);
hex = hex + hex_tab.charAt( val/16 );
hex = hex + hex_tab.charAt( val%16 );
}
return hex;
}
function hex2binl ( hex ) {
/* Clean-up hex encoded input string */
hex = hex.toLowerCase() ;
hex = hex.replace( / /g , "");
var bin =[] ;
/* Transfrom to array of integers (binary representation) */
126
for ( i=0 ; i < hex.length*4 ; i=i+8 ) {
octet = parseInt( hex.substr( i/4 , 2) , 16) ;
bin[i>>5] |= ( octet & 255 ) << (i%32);
}
return bin;
}
} // end of ChilliMD5 constructor
Anexo 5 – Arquivo de configuração hotspotlogin.cgi
#!/usr/bin/perl
# chilli - coova.org. A Wireless LAN Access Point Controller
# Copyright (C) 2003, 2004 Mondru AB.
# Copyright (C) 2006-2008 David Bird <[email protected]>
#
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
# This code is horrible -- it came that way, and remains that way. A
# real captive portal is demonstrated here: http://drupal.org/project/hotspot
# Redirects from CoovaChilli daemon:
#
# Redirection when not yet or already authenticated
# notyet: CoovaChilli daemon redirects to login page.
# already: CoovaChilli daemon redirects to success status page.
#
# Response to login:
# already: Attempt to login when already logged in.
127
# failed: Login failed
# success: Login succeded
#
# logoff: Response to a logout
# Shared secret used to encrypt challenge with. Prevents dictionary attacks.
# You should change this to your own shared secret.
$uamsecret = "mysqlsecret";
# Uncomment the following line if you want to use ordinary user-password (PAP)
# for radius authentication.
# $userpassword=1;
$loginpath = "/cgi-bin/hotspotlogin.cgi";
$debug = 1;
# To use MSCHAPv2 Authentication with,
# then uncomment the next two lines.
#$ntresponse = 1;
#$chilli_response = '/usr/local/sbin/chilli_response';
# start program
use Digest::MD5 qw(md5 md5_hex md5_base64);
# Make sure that the form parameters are clean
$OK_CHARS='-a-zA-Z0-9_.@&=%!';
$_ = $input = <STDIN>;
s/[^$OK_CHARS]/_/go;
$input = $_;
# Make sure that the get query parameters are clean
$OK_CHARS='-a-zA-Z0-9_.@&=%!';
128
$_ = $query=$ENV{QUERY_STRING};
s/[^$OK_CHARS]/_/go;
$query = $_;
# If she did not use https tell her that it was wrong.
if (!$debug && !($ENV{HTTPS} =~ /^on$/)) {
print "Content-type: text/html\n\n
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login Failed</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
</head>
<body bgColor = '#c0d8f4'>
<h1 style=\"text-align: center;\">CoovaChilli Login Failed</h1>
<center>
Login must use encrypted connection.
</center>
</body>
<!--
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<WISPAccessGatewayParam
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:noNamespaceSchemaLocation=\"http://www.acmewisp.com/WISPAccessGatewayParam.
xsd\">
<AuthenticationReply>
<MessageType>120</MessageType>
<ResponseCode>102</ResponseCode>
<ReplyMessage>Login must use encrypted connection</ReplyMessage>
</AuthenticationReply>
129
</WISPAccessGatewayParam>
-->
</html>
";
exit(0);
}
#Read form parameters which we care about
@array = split('&',$input);
foreach $var ( @array )
{
@array2 = split('=',$var);
if ($array2[0] =~ /^username$/i) { $username = $array2[1]; }
if ($array2[0] =~ /^password$/i) { $password = $array2[1]; }
if ($array2[0] =~ /^challenge$/) { $challenge = $array2[1]; }
if ($array2[0] =~ /^button$/) { $button = $array2[1]; }
if ($array2[0] =~ /^logout$/) { $logout = $array2[1]; }
if ($array2[0] =~ /^prelogin$/) { $prelogin = $array2[1]; }
if ($array2[0] =~ /^res$/) { $res = $array2[1]; }
if ($array2[0] =~ /^uamip$/) { $uamip = $array2[1]; }
if ($array2[0] =~ /^uamport$/) { $uamport = $array2[1]; }
if ($array2[0] =~ /^userurl$/) { $userurl = $array2[1]; }
if ($array2[0] =~ /^timeleft$/) { $timeleft = $array2[1]; }
if ($array2[0] =~ /^redirurl$/) { $redirurl = $array2[1]; }
}
#Read query parameters which we care about
@array = split('&',$query);
foreach $var ( @array )
{
@array2 = split('=',$var);
if ($array2[0] =~ /^username$/i) { $username = $array2[1]; }
130
if ($array2[0] =~ /^password$/i) { $password = $array2[1]; }
if ($array2[0] =~ /^res$/) { $res = $array2[1]; }
if ($array2[0] =~ /^challenge$/) { $challenge = $array2[1]; }
if ($array2[0] =~ /^uamip$/) { $uamip = $array2[1]; }
if ($array2[0] =~ /^uamport$/) { $uamport = $array2[1]; }
if ($array2[0] =~ /^reply$/) { $reply = $array2[1]; }
if ($array2[0] =~ /^userurl$/) { $userurl = $array2[1]; }
if ($array2[0] =~ /^timeleft$/) { $timeleft = $array2[1]; }
if ($array2[0] =~ /^redirurl$/) { $redirurl = $array2[1]; }
}
$reply =~ s/\+/ /g;
$reply =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
$userurldecode = $userurl;
$userurldecode =~ s/\+/ /g;
$userurldecode =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
$redirurldecode = $redirurl;
$redirurldecode =~ s/\+/ /g;
$redirurldecode =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
$password =~ s/\+/ /g;
$password =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
# If attempt to login
if ($button =~ /^Login$/ || ($res eq "wispr" && $username ne "")) {
print "Content-type: text/html\n\n";
$hexchal = pack "H*", $challenge;
131
if (defined $uamsecret) {
$newchal = md5($hexchal, $uamsecret);
}
else {
$newchal = $hexchal;
}
if ($ntresponse == 1) {
# Encode plain text into NT-Password
$response = `$chilli_response -nt "$challenge" "$uamsecret" "$username"
"$password"`;
$logonUrl =
"http://$uamip:$uamport/logon?username=$username&ntresponse=$response";
} elsif ($userpassword == 1) {
# Encode plain text password with challenge
# (which may or may not be uamsecret encoded)
# If challange isn't long enough, repeat it until it is
while (length($newchal) < length($password)){
$newchal .= $newchal;
}
$pappassword = unpack "H*", substr($password ^ $newchal, 0,
length($password));
$logonUrl =
"http://$uamip:$uamport/logon?username=$username&password=$pappassword";
} else {
132
# Generate a CHAP response with the password and the
# challenge (which may have been uamsecret encoded)
$response = md5_hex("\0", $password, $newchal);
$logonUrl =
"http://$uamip:$uamport/logon?username=$username&response=$response&userurl=$userur
l";
}
#sleep 5;
print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
<meta http-equiv=\"refresh\" content=\"0;url=$logonUrl\">
</head>
<body bgColor = '#c0d8f4'>
<h1 style=\"text-align: center;\">Logging in to CoovaChilli</h1>
<center>
Please wait......
</center>
</body>
<!--
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<WISPAccessGatewayParam
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:noNamespaceSchemaLocation=\"http://www.acmewisp.com/WISPAccessGatewayParam.
xsd\">
<AuthenticationReply>
133
<MessageType>120</MessageType>
<ResponseCode>201</ResponseCode>
<LoginResultsURL>$logonUrl</LoginResultsURL>
</AuthenticationReply>
</WISPAccessGatewayParam>
-->
</html>
";
exit(0);
}
# Default: It was not a form request
$result = 0;
# If login successful
if ($res =~ /^success$/) {
$result = 1;
}
# If login failed
if ($res =~ /^failed$/) {
$result = 2;
}
# If logout successful
if ($res =~ /^logoff$/) {
$result = 3;
}
# If tried to login while already logged in
if ($res =~ /^already$/) {
$result = 4;
134
}
# If not logged in yet
if ($res =~ /^notyet$/) {
$result = 5;
}
# If login from smart client
if ($res =~ /^wispr$/) {
$result = 6;
}
# If requested a logging in pop up window
if ($res =~ /^popup1$/) {
$result = 11;
}
# If requested a success pop up window
if ($res =~ /^popup2$/) {
$result = 12;
}
# If requested a logout pop up window
if ($res =~ /^popup3$/) {
$result = 13;
}
# Otherwise it was not a form request
# Send out an error message
if ($result == 0) {
print "Content-type: text/html\n\n
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
135
<html>
<head>
<title>CoovaChilli Login Failed</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
</head>
<body bgColor = '#c0d8f4'>
<h1 style=\"text-align: center;\">CoovaChilli Login Failed</h1>
<center>
Login must be performed through CoovaChilli daemon.
</center>
</body>
</html>
";
exit(0);
}
#Generate the output
if ($result != 6) {
print "Content-type: text/html\n\n
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
<SCRIPT LANGUAGE=\"JavaScript\">
var blur = 0;
var starttime = new Date();
var startclock = starttime.getTime();
var mytimeleft = 0;
function doTime() {
136
window.setTimeout( \"doTime()\", 1000 );
t = new Date();
time = Math.round((t.getTime() - starttime.getTime())/1000);
if (mytimeleft) {
time = mytimeleft - time;
if (time <= 0) {
window.location =
\"$loginpath?res=popup3&uamip=$uamip&uamport=$uamport\";
}
}
if (time < 0) time = 0;
hours = (time - (time % 3600)) / 3600;
time = time - (hours * 3600);
mins = (time - (time % 60)) / 60;
secs = time - (mins * 60);
if (hours < 10) hours = \"0\" + hours;
if (mins < 10) mins = \"0\" + mins;
if (secs < 10) secs = \"0\" + secs;
title = \"Online time: \" + hours + \":\" + mins + \":\" + secs;
if (mytimeleft) {
title = \"Remaining time: \" + hours + \":\" + mins + \":\" + secs;
}
if(document.all || document.getElementById){
document.title = title;
}
else {
self.status = title;
}
}
function popUp(URL) {
if (self.name != \"chillispot_popup\") {
137
chillispot_popup = window.open(URL, 'chillispot_popup',
'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=375
');
}
}
function doOnLoad(result, URL, userurl, redirurl, timeleft) {
if (timeleft) {
mytimeleft = timeleft;
}
if ((result == 1) && (self.name == \"chillispot_popup\")) {
doTime();
}
if ((result == 1) && (self.name != \"chillispot_popup\")) {
chillispot_popup = window.open(URL, 'chillispot_popup',
'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=375
');
}
if ((result == 2) || result == 5) {
document.form1.UserName.focus()
}
if ((result == 2) && (self.name != \"chillispot_popup\")) {
chillispot_popup = window.open('', 'chillispot_popup',
'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=400,height=200
');
chillispot_popup.close();
}
if ((result == 12) && (self.name == \"chillispot_popup\")) {
doTime();
if (redirurl) {
opener.location = redirurl;
}
else if (opener.home) {
138
opener.home();
}
else {
opener.location = \"about:home\";
}
self.focus();
blur = 0;
}
if ((result == 13) && (self.name == \"chillispot_popup\")) {
self.focus();
blur = 1;
}
}
function doOnBlur(result) {
if ((result == 12) && (self.name == \"chillispot_popup\")) {
if (blur == 0) {
blur = 1;
self.focus();
}
}
}
</script>
</head>
<body onLoad=\"javascript:doOnLoad($result,
'$loginpath?res=popup2&uamip=$uamip&uamport=$uamport&userurl=$userurl&redirurl=$r
edirurl&timeleft=$timeleft','$userurldecode', '$redirurldecode', '$timeleft')\" onBlur =
\"javascript:doOnBlur($result)\" bgColor = '#c0d8f4'>";
}
# if (!window.opener) {
# document.bgColor = '#c0d8f4';
# }
139
#print "THE INPUT: $input";
#foreach $key (sort (keys %ENV)) {
# print $key, ' = ', $ENV{$key}, "<br>\n";
#}
if ($result == 2) {
print "
<h1 style=\"text-align: center;\">CoovaChilli Login Failed</h1>";
if ($reply) {
print "<center> $reply </BR></BR></center>";
}
}
if ($result == 5) {
print "
<h1 style=\"text-align: center;\">CoovaChilli Login</h1>";
}
if ($result == 2 || $result == 5) {
print "
<form name=\"form1\" method=\"post\" action=\"$loginpath\">
<INPUT TYPE=\"hidden\" NAME=\"challenge\" VALUE=\"$challenge\">
<INPUT TYPE=\"hidden\" NAME=\"uamip\" VALUE=\"$uamip\">
<INPUT TYPE=\"hidden\" NAME=\"uamport\" VALUE=\"$uamport\">
<INPUT TYPE=\"hidden\" NAME=\"userurl\" VALUE=\"$userurl\">
<center>
<table border=\"0\" cellpadding=\"5\" cellspacing=\"0\" style=\"width: 217px;\">
<tbody>
<tr>
<td align=\"right\">Username:</td>
<td><input STYLE=\"font-family: Arial\" type=\"text\" name=\"UserName\"
size=\"20\" maxlength=\"128\"></td>
140
</tr>
<tr>
<td align=\"right\">Password:</td>
<td><input STYLE=\"font-family: Arial\" type=\"password\" name=\"Password\"
size=\"20\" maxlength=\"128\"></td>
</tr>
<tr>
<td align=\"center\" colspan=\"2\" height=\"23\"><input type=\"submit\"
name=\"button\" value=\"Login\"
onClick=\"javascript:popUp('$loginpath?res=popup1&uamip=$uamip&uamport=$uamport')\
"></td>
</tr>
</tbody>
</table>
</center>
</form>
</body>
</html>";
}
if ($result == 1) {
print "
<h1 style=\"text-align: center;\">Logged in to CoovaChilli</h1>";
if ($reply) {
print "<center> $reply </BR></BR></center>";
}
print "
<center>
<a href=\"http://$uamip:$uamport/logoff\">Logout</a>
</center>
</body>
141
</html>";
}
if (($result == 4) || ($result == 12)) {
print "
<h1 style=\"text-align: center;\">Logged in to CoovaChilli</h1>
<center>
<a href=\"http://$uamip:$uamport/logoff\">Logout</a>
</center>
</body>
</html>";
}
if ($result == 11) {
print "<h1 style=\"text-align: center;\">Logging in to CoovaChilli</h1>";
print "
<center>
Please wait......
</center>
</body>
</html>";
}
if (($result == 3) || ($result == 13)) {
print "
<h1 style=\"text-align: center;\">Logged out from CoovaChilli</h1>
<center>
<a href=\"http://$uamip:$uamport/prelogin\">Login</a>
</center>
</body>
</html>";
142
}
exit(0);
Anexo 6 – Arquivo de configuração wwwsh
#!/usr/bin/perl
# chilli - coova.org. A Wireless LAN Access Point Controller
# Copyright (C) 2003, 2004 Mondru AB.
# Copyright (C) 2006-2008 David Bird <[email protected]>
#
# The contents of this file may be used under the terms of the GNU
# General Public License Version 2, provided that the above copyright
# notice and this permission notice is included in all copies or
# substantial portions of the software.
# This code is horrible -- it came that way, and remains that way. A
# real captive portal is demonstrated here: http://drupal.org/project/hotspot
# Redirects from CoovaChilli daemon:
#
# Redirection when not yet or already authenticated
# notyet: CoovaChilli daemon redirects to login page.
# already: CoovaChilli daemon redirects to success status page.
#
# Response to login:
# already: Attempt to login when already logged in.
# failed: Login failed
# success: Login succeded
#
# logoff: Response to a logout
143
# Shared secret used to encrypt challenge with. Prevents dictionary attacks.
# You should change this to your own shared secret.
$uamsecret = "mysqlsecret";
# Uncomment the following line if you want to use ordinary user-password (PAP)
# for radius authentication.
# $userpassword=1;
$loginpath = "/cgi-bin/hotspotlogin.cgi";
$debug = 1;
# To use MSCHAPv2 Authentication with,
# then uncomment the next two lines.
#$ntresponse = 1;
#$chilli_response = '/usr/local/sbin/chilli_response';
# start program
use Digest::MD5 qw(md5 md5_hex md5_base64);
# Make sure that the form parameters are clean
$OK_CHARS='-a-zA-Z0-9_.@&=%!';
$_ = $input = <STDIN>;
s/[^$OK_CHARS]/_/go;
$input = $_;
# Make sure that the get query parameters are clean
$OK_CHARS='-a-zA-Z0-9_.@&=%!';
$_ = $query=$ENV{QUERY_STRING};
s/[^$OK_CHARS]/_/go;
$query = $_;
144
# If she did not use https tell her that it was wrong.
if (!$debug && !($ENV{HTTPS} =~ /^on$/)) {
print "Content-type: text/html\n\n
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login Failed</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
</head>
<body bgColor = '#c0d8f4'>
<h1 style=\"text-align: center;\">CoovaChilli Login Failed</h1>
<center>
Login must use encrypted connection.
</center>
</body>
<!--
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<WISPAccessGatewayParam
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:noNamespaceSchemaLocation=\"http://www.acmewisp.com/WISPAccessGatewayParam.
xsd\">
<AuthenticationReply>
<MessageType>120</MessageType>
<ResponseCode>102</ResponseCode>
<ReplyMessage>Login must use encrypted connection</ReplyMessage>
</AuthenticationReply>
</WISPAccessGatewayParam>
-->
</html>
";
exit(0);
145
}
#Read form parameters which we care about
@array = split('&',$input);
foreach $var ( @array )
{
@array2 = split('=',$var);
if ($array2[0] =~ /^username$/i) { $username = $array2[1]; }
if ($array2[0] =~ /^password$/i) { $password = $array2[1]; }
if ($array2[0] =~ /^challenge$/) { $challenge = $array2[1]; }
if ($array2[0] =~ /^button$/) { $button = $array2[1]; }
if ($array2[0] =~ /^logout$/) { $logout = $array2[1]; }
if ($array2[0] =~ /^prelogin$/) { $prelogin = $array2[1]; }
if ($array2[0] =~ /^res$/) { $res = $array2[1]; }
if ($array2[0] =~ /^uamip$/) { $uamip = $array2[1]; }
if ($array2[0] =~ /^uamport$/) { $uamport = $array2[1]; }
if ($array2[0] =~ /^userurl$/) { $userurl = $array2[1]; }
if ($array2[0] =~ /^timeleft$/) { $timeleft = $array2[1]; }
if ($array2[0] =~ /^redirurl$/) { $redirurl = $array2[1]; }
}
#Read query parameters which we care about
@array = split('&',$query);
foreach $var ( @array )
{
@array2 = split('=',$var);
if ($array2[0] =~ /^username$/i) { $username = $array2[1]; }
if ($array2[0] =~ /^password$/i) { $password = $array2[1]; }
if ($array2[0] =~ /^res$/) { $res = $array2[1]; }
if ($array2[0] =~ /^challenge$/) { $challenge = $array2[1]; }
if ($array2[0] =~ /^uamip$/) { $uamip = $array2[1]; }
if ($array2[0] =~ /^uamport$/) { $uamport = $array2[1]; }
146
if ($array2[0] =~ /^reply$/) { $reply = $array2[1]; }
if ($array2[0] =~ /^userurl$/) { $userurl = $array2[1]; }
if ($array2[0] =~ /^timeleft$/) { $timeleft = $array2[1]; }
if ($array2[0] =~ /^redirurl$/) { $redirurl = $array2[1]; }
}
$reply =~ s/\+/ /g;
$reply =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
$userurldecode = $userurl;
$userurldecode =~ s/\+/ /g;
$userurldecode =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
$redirurldecode = $redirurl;
$redirurldecode =~ s/\+/ /g;
$redirurldecode =~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
$password =~ s/\+/ /g;
$password =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/seg;
# If attempt to login
if ($button =~ /^Login$/ || ($res eq "wispr" && $username ne "")) {
print "Content-type: text/html\n\n";
$hexchal = pack "H*", $challenge;
if (defined $uamsecret) {
$newchal = md5($hexchal, $uamsecret);
}
else {
147
$newchal = $hexchal;
}
if ($ntresponse == 1) {
# Encode plain text into NT-Password
$response = `$chilli_response -nt "$challenge" "$uamsecret" "$username"
"$password"`;
$logonUrl =
"http://$uamip:$uamport/logon?username=$username&ntresponse=$response";
} elsif ($userpassword == 1) {
# Encode plain text password with challenge
# (which may or may not be uamsecret encoded)
# If challange isn't long enough, repeat it until it is
while (length($newchal) < length($password)){
$newchal .= $newchal;
}
$pappassword = unpack "H*", substr($password ^ $newchal, 0,
length($password));
$logonUrl =
"http://$uamip:$uamport/logon?username=$username&password=$pappassword";
} else {
# Generate a CHAP response with the password and the
# challenge (which may have been uamsecret encoded)
$response = md5_hex("\0", $password, $newchal);
148
$logonUrl =
"http://$uamip:$uamport/logon?username=$username&response=$response&userurl=$userur
l";
}
#sleep 5;
print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
<meta http-equiv=\"refresh\" content=\"0;url=$logonUrl\">
</head>
<body bgColor = '#c0d8f4'>
<h1 style=\"text-align: center;\">Logging in to CoovaChilli</h1>
<center>
Please wait......
</center>
</body>
<!--
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<WISPAccessGatewayParam
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:noNamespaceSchemaLocation=\"http://www.acmewisp.com/WISPAccessGatewayParam.
xsd\">
<AuthenticationReply>
<MessageType>120</MessageType>
<ResponseCode>201</ResponseCode>
<LoginResultsURL>$logonUrl</LoginResultsURL>
</AuthenticationReply>
</WISPAccessGatewayParam>
149
-->
</html>
";
exit(0);
}
# Default: It was not a form request
$result = 0;
# If login successful
if ($res =~ /^success$/) {
$result = 1;
}
# If login failed
if ($res =~ /^failed$/) {
$result = 2;
}
# If logout successful
if ($res =~ /^logoff$/) {
$result = 3;
}
# If tried to login while already logged in
if ($res =~ /^already$/) {
$result = 4;
}
# If not logged in yet
if ($res =~ /^notyet$/) {
$result = 5;
150
}
# If login from smart client
if ($res =~ /^wispr$/) {
$result = 6;
}
# If requested a logging in pop up window
if ($res =~ /^popup1$/) {
$result = 11;
}
# If requested a success pop up window
if ($res =~ /^popup2$/) {
$result = 12;
}
# If requested a logout pop up window
if ($res =~ /^popup3$/) {
$result = 13;
}
# Otherwise it was not a form request
# Send out an error message
if ($result == 0) {
print "Content-type: text/html\n\n
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login Failed</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
151
</head>
<body bgColor = '#c0d8f4'>
<h1 style=\"text-align: center;\">CoovaChilli Login Failed</h1>
<center>
Login must be performed through CoovaChilli daemon.
</center>
</body>
</html>
";
exit(0);
}
#Generate the output
if ($result != 6) {
print "Content-type: text/html\n\n
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
<head>
<title>CoovaChilli Login</title>
<meta http-equiv=\"Cache-control\" content=\"no-cache\">
<meta http-equiv=\"Pragma\" content=\"no-cache\">
<SCRIPT LANGUAGE=\"JavaScript\">
var blur = 0;
var starttime = new Date();
var startclock = starttime.getTime();
var mytimeleft = 0;
function doTime() {
window.setTimeout( \"doTime()\", 1000 );
t = new Date();
time = Math.round((t.getTime() - starttime.getTime())/1000);
if (mytimeleft) {
time = mytimeleft - time;
152
if (time <= 0) {
window.location =
\"$loginpath?res=popup3&uamip=$uamip&uamport=$uamport\";
}
}
if (time < 0) time = 0;
hours = (time - (time % 3600)) / 3600;
time = time - (hours * 3600);
mins = (time - (time % 60)) / 60;
secs = time - (mins * 60);
if (hours < 10) hours = \"0\" + hours;
if (mins < 10) mins = \"0\" + mins;
if (secs < 10) secs = \"0\" + secs;
title = \"Online time: \" + hours + \":\" + mins + \":\" + secs;
if (mytimeleft) {
title = \"Remaining time: \" + hours + \":\" + mins + \":\" + secs;
}
if(document.all || document.getElementById){
document.title = title;
}
else {
self.status = title;
}
}
function popUp(URL) {
if (self.name != \"chillispot_popup\") {
chillispot_popup = window.open(URL, 'chillispot_popup',
'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=375
');
}
}
153
function doOnLoad(result, URL, userurl, redirurl, timeleft) {
if (timeleft) {
mytimeleft = timeleft;
}
if ((result == 1) && (self.name == \"chillispot_popup\")) {
doTime();
}
if ((result == 1) && (self.name != \"chillispot_popup\")) {
chillispot_popup = window.open(URL, 'chillispot_popup',
'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=375
');
}
if ((result == 2) || result == 5) {
document.form1.UserName.focus()
}
if ((result == 2) && (self.name != \"chillispot_popup\")) {
chillispot_popup = window.open('', 'chillispot_popup',
'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=400,height=200
');
chillispot_popup.close();
}
if ((result == 12) && (self.name == \"chillispot_popup\")) {
doTime();
if (redirurl) {
opener.location = redirurl;
}
else if (opener.home) {
opener.home();
}
else {
opener.location = \"about:home\";
}
self.focus();
154
blur = 0;
}
if ((result == 13) && (self.name == \"chillispot_popup\")) {
self.focus();
blur = 1;
}
}
function doOnBlur(result) {
if ((result == 12) && (self.name == \"chillispot_popup\")) {
if (blur == 0) {
blur = 1;
self.focus();
}
}
}
</script>
</head>
<body onLoad=\"javascript:doOnLoad($result,
'$loginpath?res=popup2&uamip=$uamip&uamport=$uamport&userurl=$userurl&redirurl=$r
edirurl&timeleft=$timeleft','$userurldecode', '$redirurldecode', '$timeleft')\" onBlur =
\"javascript:doOnBlur($result)\" bgColor = '#c0d8f4'>";
}
# if (!window.opener) {
# document.bgColor = '#c0d8f4';
# }
#print "THE INPUT: $input";
#foreach $key (sort (keys %ENV)) {
# print $key, ' = ', $ENV{$key}, "<br>\n";
#}
155
if ($result == 2) {
print "
<h1 style=\"text-align: center;\">CoovaChilli Login Failed</h1>";
if ($reply) {
print "<center> $reply </BR></BR></center>";
}
}
if ($result == 5) {
print "
<h1 style=\"text-align: center;\">CoovaChilli Login</h1>";
}
if ($result == 2 || $result == 5) {
print "
<form name=\"form1\" method=\"post\" action=\"$loginpath\">
<INPUT TYPE=\"hidden\" NAME=\"challenge\" VALUE=\"$challenge\">
<INPUT TYPE=\"hidden\" NAME=\"uamip\" VALUE=\"$uamip\">
<INPUT TYPE=\"hidden\" NAME=\"uamport\" VALUE=\"$uamport\">
<INPUT TYPE=\"hidden\" NAME=\"userurl\" VALUE=\"$userurl\">
<center>
<table border=\"0\" cellpadding=\"5\" cellspacing=\"0\" style=\"width: 217px;\">
<tbody>
<tr>
<td align=\"right\">Username:</td>
<td><input STYLE=\"font-family: Arial\" type=\"text\" name=\"UserName\"
size=\"20\" maxlength=\"128\"></td>
</tr>
<tr>
<td align=\"right\">Password:</td>
<td><input STYLE=\"font-family: Arial\" type=\"password\" name=\"Password\"
size=\"20\" maxlength=\"128\"></td>
</tr>
156
<tr>
<td align=\"center\" colspan=\"2\" height=\"23\"><input type=\"submit\"
name=\"button\" value=\"Login\"
onClick=\"javascript:popUp('$loginpath?res=popup1&uamip=$uamip&uamport=$uamport')\
"></td>
</tr>
</tbody>
</table>
</center>
</form>
</body>
</html>";
}
if ($result == 1) {
print "
<h1 style=\"text-align: center;\">Logged in to CoovaChilli</h1>";
if ($reply) {
print "<center> $reply </BR></BR></center>";
}
print "
<center>
<a href=\"http://$uamip:$uamport/logoff\">Logout</a>
</center>
</body>
</html>";
}
if (($result == 4) || ($result == 12)) {
print "
<h1 style=\"text-align: center;\">Logged in to CoovaChilli</h1>
157
<center>
<a href=\"http://$uamip:$uamport/logoff\">Logout</a>
</center>
</body>
</html>";
}
if ($result == 11) {
print "<h1 style=\"text-align: center;\">Logging in to CoovaChilli</h1>";
print "
<center>
Please wait......
</center>
</body>
</html>";
}
if (($result == 3) || ($result == 13)) {
print "
<h1 style=\"text-align: center;\">Logged out from CoovaChilli</h1>
<center>
<a href=\"http://$uamip:$uamport/prelogin\">Login</a>
</center>
</body>
</html>";
}
exit(0);
Anexo 7 – Arquivo de Configuração up.sh
#!/bin/sh
TUNTAP=$(basename $DEV)
158
UNDO_FILE=/var/run/chilli.$TUNTAP.sh
. /etc/chilli/functions
[ -e "$UNDO_FILE" ] && sh $UNDO_FILE 2>/dev/null
rm -f $UNDO_FILE 2>/dev/null
ipt() {
opt=$1; shift
echo "iptables -D $*" >> $UNDO_FILE
iptables $opt $*
}
ipt_in() {
ipt -I INPUT -i $TUNTAP $*
}
if [ -n "$TUNTAP" ]
then
# ifconfig $TUNTAP mtu $MTU
if [ "$KNAME" != "" ]
then
ipt -I FORWARD -i $DHCPIF -m coova --name $KNAME -j ACCEPT
ipt -I FORWARD -o $DHCPIF -m coova --name $KNAME --dest -j ACCEPT
ipt -I FORWARD -i $TUNTAP -j ACCEPT
ipt -I FORWARD -o $TUNTAP -j ACCEPT
[ -n "$DHCPLISTEN" ] && ifconfig $DHCPIF $DHCPLISTEN
else
if [ "$LAYER3" != "1" ]
then
[ -n "$UAMPORT" -a "$UAMPORT" != "0" ] && \
ipt_in -p tcp -m tcp --dport $UAMPORT --dst $ADDR -j ACCEPT
159
[ -n "$UAMUIPORT" -a "$UAMUIPORT" != "0" ] && \
ipt_in -p tcp -m tcp --dport $UAMUIPORT --dst $ADDR -j ACCEPT
[ -n "$HS_TCP_PORTS" ] && {
for port in $HS_TCP_PORTS; do
ipt_in -p tcp -m tcp --dport $port --dst $ADDR -j ACCEPT
done
}
ipt_in -p udp -d 255.255.255.255 --destination-port 67:68 -j ACCEPT
ipt_in -p udp -d $ADDR --destination-port 67:68 -j ACCEPT
ipt_in -p udp --dst $ADDR --dport 53 -j ACCEPT
ipt_in -p icmp --dst $ADDR -j ACCEPT
ipt -A INPUT -i $TUNTAP --dst $ADDR -j DROP
if [ "$ONLY8021Q" != "1" ]
then
ipt -I INPUT -i $DHCPIF -j DROP
fi
fi
if [ "$ONLY8021Q" != "1" ]
then
ipt -I FORWARD -i $DHCPIF -j DROP
ipt -I FORWARD -o $DHCPIF -j DROP
fi
ipt -I FORWARD -i $TUNTAP -j ACCEPT
ipt -I FORWARD -o $TUNTAP -j ACCEPT
# Help out conntrack to not get confused
# (stops masquerading from working)
160
#ipt -I PREROUTING -t raw -j NOTRACK -i $DHCPIF
#ipt -I OUTPUT -t raw -j NOTRACK -o $DHCPIF
# Help out MTU issues with PPPoE or Mesh
ipt -I FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --
clamp-mss-to-pmtu
ipt -I FORWARD -t mangle -p tcp -m tcp --tcp-flags SYN,RST SYN -j
TCPMSS --clamp-mss-to-pmtu
[ "$HS_LAN_ACCESS" != "on" -a "$HS_LAN_ACCESS" != "allow" ] && \
ipt -I FORWARD -i $TUNTAP \! -o $HS_WANIF -j DROP
ipt -I FORWARD -i $TUNTAP -o $HS_WANIF -j ACCEPT
[ "$HS_LOCAL_DNS" = "on" ] && \
ipt -I PREROUTING -t nat -i $TUNTAP -p udp --dport 53 -j DNAT --to-
destination $ADDR
fi
fi
# site specific stuff optional
[ -e /etc/chilli/ipup.sh ] && . /etc/chilli/ipup.sh
#may not have been populated the first time; run again
[ -e "/var/run/chilli.iptables"] && sh /var/run/chilli.iptables 2>/dev/null
#force-add the final rule necessary to fix routing tables
iptables -I POSTROUTING -t nat -o $HS_WANIF -j MASQUERADE