Archive

Archive for the ‘dev’ Category

Entrando dentro do kernel sem bater na porta :D

March 19, 2010 1 comment

Ola após um longo período bem turbulento sem postagem devido a falta de tempo, agora me sobrou um tempo resolvi postar algo interessante(pelo menos para mim), esse e o primeiro de alguns posts que quero falar sobre lkm. Mas e ai? que macumba é LKM?!?. Bom LKM é Load Kernel Module ou módulos do kernel carregavéis “aportuguesado” :D. O que exatamente é um módulo do kernel? Os módulos são pedaços de código que podem ser carregadas e descarregadas dentro do kernel. Eles estendem a funcionalidade do kernel sem a necessidade de reiniciar o sistema. Por exemplo, um tipo de módulo é o driver de dispositivo, que permite o acesso ao hardware conectados ao sistema. Sem os módulos, teríamos que ter o núcleo do sistema operacional na forma de um kernel monolíticos e quando fosse adicionar novas funcionalidades teria que ser feito direto na imagem do kernel. Ou seja nova compilação, recompilação,.., etc. Outra desvantagem em kernel monoliticos é o tamanho do arquivo de imagem do kernel se torna grande devido a ter que conter todo os “pedaços” de codigos ou drivers para cada possível placa de rede, placa de video, ou dispositivo quaisquer, sem contar que a cada inserção de dispositivo um novo suporte de driver também deve ser adicionado gerando com isso a necessidade de recompilar o kernel e reiniciar a máquina. Bom eu desenvolvi esse modulo quando estava no primeiro ano de faculdade nos primórdios do meu aprendizado em Linux. Conforme eu for encontrando tempo vou postar alguns lkm que fiz um deles para interceptar syscall, device driver didatico, criar uma syscall, o duro vai ser converter e ajustar meu código de kernel 2.4 para 2.6 😛

Bom para criar um lkm voce precisa de pre-requisitos um deles é saber a melhor linguagem de todos os tempos “C” 😛 sendo assim eu vou pressupor que voce leitor ja é um programador C. Segue codigo abaixo do nosso LKM.


/*
* hello_world.c - Um simples LKM.
*/
#include <linux/module.h> /* cabeçalhos requeridos */
#include <linux/kernel.h>

int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}

void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

Vamos as explicações? Pois bem as primeiras linhas e bem intuitivo declaracao de bilbliotecas do kernel. Na linha:


int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0;
}

E a função responsavél por inicializar nosso módulo ou seja carrega nosso código dentro do espaço kernel, vamos fazer uma parada aqui. Afinal o que é espaço kernel? Bom uma regra, todo LKM e executado no assim chamado “espaço kernel” ou “kernel space” enquanto que aplicativos como o editor vim, openoffice, firefox rodam em “espaço usuário” ou “user space”. Livro do Tannenbaum função de um sistema operacional é a de criar programas ou softwares para serem executados em um computador e criar uma interface para esses programas ou softwares protegendo o acesso nao autorizado a dispositivos de hardware e software tirando assim a responsabilidade do programador de aplicativos de se preocupar em carregar registradores da CPU chamar interrupção tal, etc. Esse “espaço” assim designado e chamado de espaço kernel e cria essa proteção dos softwares de usuários do sistema operacional. Bom agora que sabemos o que é espaço kernel e espaço usuário continuamos analisando o código.


void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

Como temos a função de entrada no kernel(kernel space), também temos a função de saida do kernel “cleanup_module” simples né. Agora vamos a função dentro de cada item(init e cleanup) os “printk”. Quem e acostumado ou é programador C já sacou o que faz o printk sim ele e equivalente ao printf no espaço usuário porém com resalvas. A macro “KERN_INFO” é uma macro que indica prioridade para a mensagem via printk normalmente utilizado pelo ksyslog ou klogd em sistemas Linux antigos. Com isso você pode definir prioridade quando for definir mensagem para o programador do kernel. Existem 8 niveis de prioridade definidas no arquivo de cabeçalho kernel.h normalmente nos fontes do kernel fica em linux-versao/include/linux/kernel.h, vejam as prioridades abaixo.


#define KERN_EMERG "" /* system is unusable */
#define KERN_ALERT "" /* action must be taken immediately */
#define KERN_CRIT "" /* critical conditions */
#define KERN_ERR "" /* error conditions */
#define KERN_WARNING "" /* warning conditions */
#define KERN_NOTICE "" /* normal but significant condition */
#define KERN_INFO "" /* informational */
#define KERN_DEBUG "" /* debug-level messages */

Blz código explicado vamos compilar, mas antes precisamos criar um arquivo Makefile para ser utilizado pela ferramenta de compilação make. Segue Makefile abaixo:


obj-m += hello_world.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Não é intuito deste post explicar o funcionamento do make senão o post vai ficar muito extenso talvez num post futuro. Após a criacao do arquivo execute o comando make


root@capsula:~/lkm# ls
hello_world.c Makefile
root@capsula:~/lkm#
root@capsula:~/lkm# make
make -C /lib/modules/2.6.31-14-generic-pae/build M=/home/ricardobarbosa/lkm modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.31-14-generic-pae'
CC [M] /home/ricardobarbosa/lkm/hello_world.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/ricardobarbosa/lkm/hello_world.mod.o
LD [M] /home/ricardobarbosa/lkm/hello_world.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.31-14-generic-pae'
root@capsula:~/lkm# ls
hello_world.c hello_world.mod.c hello_world.o Module.markers Module.symvers
hello_world.ko hello_world.mod.o Makefile modules.order
root@capsula:~/lkm#

Ótimo meu módulo compilou com sucesso e podemos ver o modulo .ko (uma curiosidade sabe oque significa a extensao .ko – Kernel Object). Vamos subir nosso módulo dentro do kernel? para isso utilizamos o comando insmod (utilitário para carregamento e descarregamento de lkm).


root@capsula:~/lkm# modinfo hello_world.ko
filename: hello_world.ko
srcversion: 140276773A3090F6F33891F
depends:
vermagic: 2.6.31-14-generic-pae SMP mod_unload modversions 586
root@capsula:~/lkm# insmod hello_world.ko
root@capsula:~/lkm# lsmod
Module Size Used by
hello_world 988 0
crc_ccitt 1852 1 dahdi
iptable_filter 3100 0
ip_tables 11692 1 iptable_filter
x_tables 16544 1 ip_tables
snd_intel8x0 30168 0
snd_ac97_codec 101216 1 snd_intel8x0
ppdev 6688 0
ac97_bus 1532 1 snd_ac97_codec
psmouse 56180 0
snd_pcm 75488 2 snd_intel8x0,snd_ac97_codec
serio_raw 5280 0
snd_timer 22276 1 snd_pcm
lp 8964 0
i2c_piix4 10124 0
snd 59204 4 snd_intel8x0,snd_ac97_codec,snd_pcm,snd_timer
parport_pc 32228 0
soundcore 7264 1 snd
snd_page_alloc 9252 2 snd_intel8x0,snd_pcm
parport 35340 3 ppdev,lp,parport_pc
pcnet32 33156 0
mii 5212 1 pcnet32
floppy 54980 0
root@capsula:~/lkm#

Blz nosso lkm subiu sem erro e podemos ver ele carregado quando executamos o comando lsmod(list modules). Subimos o módulo e como sabemos se o nosso módulo funcionou?? Para isso iremos usar o comando dmesg utilitário que exibe as mensagens de inicialização e vindas do kernel.


root@capsula:~/lkm#
.....
[ 105.300548] eth0: link up, 100Mbps, full-duplex
[ 115.782079] eth0: no IPv6 routers present
[13593.784665] hello_world: module license 'unspecified' taints kernel.
[13593.785548] Disabling lock debugging due to kernel taint
[13593.785716] Hello world 1.
root@capsula:~/lkm#

Notem a mensagem hello world nosso módulo subiu perfeitamente notem tambem a mensagem “hello_world: module license ‘unspecified’ taints kernel.” isso é uma forma de indicar que nosso módulo foi inserido no kernel sem uma declaração de licença explicita, o que falta é uma declaração da licença usada pelo módulo. Para isso usamos a macro.


MODULE_LICENSE("GPL");

Adicione o código acima ao fonte e recompile o módulo. após isso a mensagem de “hello_world: module license ‘unspecified’ taints kernel.” irá sumir. Com essa declaração de licença GPL nosso módulo terá acesso aos símbolos do kernel GPL, isso é feito para garantir que tudo dentro do kernel seja GPL 😀

Agora iremos remover nosso módulo das entranhas do kernel para isso outro utilitário rmmod


root@capsula:~/lkm# rmmod hello_world
root@capsula:~/lkm# dmesg
....
[ 105.300548] eth0: link up, 100Mbps, full-duplex
[ 115.782079] eth0: no IPv6 routers present
[16057.727314] Hello world 1.
[17080.476439] Goodbye world 1.
root@capsula:~/lkm#

Nossa este post estava ficando gigante, espero ter conseguido passar o assunto de forma objetiva. Qualquer dúvidas em relação ao assunto e claro se eu souber basta perguntar 😀

Até a próxima.

Categories: kernel

Script em ruby para monitoramento de serviços – Nagios

January 13, 2010 1 comment

   Estou em um projeto de monitoramento de infra-estrutura de TI onde estou tendo que monitorar roteadores, servidores(tanto linux quando windows). Para o monitoramento dos recursos mais usuais como CPU, memória, trafego, etc, o uso do SNMP e plugins padrões do nagios são bastante eficazes. Entretanto, tive que monitorar processos e daemon destes servidores e pelo menos na busca nos plugins padroes do nagios não encontrei algum que pudesse atender minha demanda. Então parti para o desenvolvimento, teria que criar um script que iria dar um get em MIB de vários servidores buscando determinado processo. Graças aos padrões criados do protocolo SNMP existe na principal “base de dados” de um host uma MIB chamada MIB-2(Padrão na maioria das implementações) que já possue essas informações(como nome de processos, uso de memória por processo, etc). Então vi a chance de aprender uma nova linguagem de programação. Há tempos venho tentando arrumar um tempo para aprender ruby, eis que a chance surgiu. Resolvi desenvolver o script de monitoramento do Nagios em ruby. Fiz um “hello world” em ruby, e logo percebi o poder dessa linguagem. Uma linguagem dinâmicamente tipada, possue um framework criado para desenvolvimento web o Rails, além disso no ruby tudo o que é manipulado é um objeto, não havendo tipos primitivos, ela é altamente produtivo(você escreve pouco e faz muito), e várias outras vantagens :D. O Ruby foi criado por Yukihiro “Matz” Matsumoto, o qual dizia que a linguagem deveria ter o nome de uma pedra preciosa, o qual batizou o nome de ruby.

  Bom para começar a escrever meu plugin do nagios precisaria ver como funciona a parte de sockets no ruby ou usar uma biblioteca pronta. Para minha “sorte” essa bilblioteca existe 😀

http://snmplib.rubyforge.org/

  Utilizei a snmplib, fiz alguns testes com sucesso fiquei impressionado com a rapidez de se “fazer as coisas”. O código que se segue funciona da seguinte forma, ele vai receber via parametros de linha de comando a comunidade SNMP, versão SNMP, nome do processo/aplicativo a verificar, um descritivo além do endereço IP.

#!/usr/bin/env ruby

include SNMP
require ‘optparse’
require ‘pp’
require ‘snmp’

optparse = OptionParser.new do|opts|
 opts.banner = “Usage: check_windows_processes_snmp.rb [options] host”

 options[:opt_comunidade] = nil
  opts.on( ‘-c’, ‘–comunidade NOME’, ‘Nomme da Comunidade SNMP’ ) do|comunidade|
  options[:opt_comunidade] = comunidade
end

 options[:opt_descricao] = nil
  opts.on( ‘-d’, ‘–descricao NOME’, ‘Descricao do processo’ ) do|descricao|
  options[:opt_descricao] = descricao
 end

 options[:opt_versao] = nil
  opts.on( ‘-v’, ‘–versao NOME’, ‘Versao SNMP’ ) d do|versao|
  options[:opt_versao] = versao
 end

 options[:opt_processo] = nil
  opts.on( ‘-p’, ‘–processo NOME’, ‘Nome do Processo’ ) do|processo|
  options[:opt_processo] = processo
 end

 opts.on( ‘-h’, ‘–help’, ‘Display this screen’ ) do
  puts opts
  exit
 end
end

optparse.parse!

if ( (options[:opt_versao] == nil) && (options[:opt_comunidade] == nil) && (options[:opt_processo] == nil) )
  puts “Argumentos inexistente: utilize o parametro -h para obter ajuda”
  exit
end

comunidade = options[:opt_comunidade]
processo = options[:opt_processo]
descricao = options[:opt_descricao]

case options[:opt_versao]
 when “1”
  versao = :SNMPv1
 when “2c”
  versao = :SNMPv2c
 when “3”
  versao = :SNMPv3
end

axou = 0

Manager.open(:Host => ARGV[0],:Version => versao, :Community => comunidade) do |manager|
 ifTable = ObjectId.new(“1.3.6.1.2.1.25.4.2.1.2”)
 next_oid = ifTable
 while next_oid.subtree_of?(ifTable)
  response = manager.get_next(next_oid)
  varbind = response.varbind_list.first
  next_oid = varbind.name
  string = varbind.to_s
  if string.match(processo)
   puts “Processo: #{descricao} STATUS: rodando”
   axou = 1
  end
 end
end

if ( axou != 1 )
 puts “Processo: #{descricao} STATUS: stop”
 exit
end

Encontrei um biblioteca muito interessante chamada optparse (http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html) ela serve para manipular caracteres passados na linha de comando vamos dissecar esse código por partes. Abaixo declaração de bilblioteas como você faz em outras linguagens como C, Perl e python, etc.

include SNMP
require ‘optparse’
require ‘pp’
require ‘snmp’

Aqui declaramos um objeto do tipo “OptionParser” que será o obejto para manipular os parametros repassados pela linha de comandos. Um parametro interessante dessa biblioteca é o “objeto.on”, o qual insere cada parametros da linha de comando no caso criamos a opção de linha de comando “-c”, “-v”, “-p” e “-d” para você especificar a comunidade SNMP, versão do protocolo SNMP usado, nome do processo/aplicativo e descrição respectivamente.

optparse = OptionParser.new do|opts|
 opts.banner = “Usage: check_windows_processes_snmp.rb [options] host”

 options[:opt_comunidade] = nil
  opts.on( ‘-c’, ‘–comunidade NOME’, ‘Nomme da Comunidade SNMP’ ) do|comunidade|
  options[:opt_comunidade] = comunidade
 end

 options[:opt_descricao] = nil
  opts.on( ‘-d’, ‘–descricao NOME’, ‘Descricao do processo’ ) do|descricao|
  options[:opt_descricao] = descricao
 end

 options[:opt_versao] = nil
  opts.on( ‘-v’, ‘–versao NOME’, ‘Versao SNMP’ ) do|versao|
  options[:opt_versao] = versao
 end

 options[:opt_processo] = nil
  opts.on( ‘-p’, ‘–processo NOME’, ‘Nome do Processo’ ) do|processo|
  options[:opt_processo] = processo
 end

 opts.on( ‘-h’, ‘–help’, ‘Display this screen’ ) do
  puts opts
  exit
 end
end

Aqui fazemos uma validação(precaução) caso o usuário digite o script sem parametro algum.

if ( (options[:opt_versao] == nil) && (options[:opt_comunidade] == nil) && (options[:opt_processo] == nil) )
  puts “Argumentos inexistente: utilize o parametro -h para obter ajuda”
  exit
end

Definimos as variaveis comunidade, processo, descricao e versao obtidos atraves da biblioteca “optparse”. Uma pecualiaridade manipulamos a variavel versao para utilizar a MACRO correspondente a versão do protocolo SNMP. Utilizei uma variavel “axou” para manipular quando encontrar o retorno da busca.

comunidade = options[:opt_comunidade]
processo = options[:opt_processo]
descricao = options[:opt_descricao]

case options[:opt_versao]
  when “1”
    versao = :SNMPv1
  when “2c”
    versao = :SNMPv2c
  when “3”
    versao = :SNMPv3
end

axou = 0

Abaixo temos a parte do código que faz o “get” na MIB dos servidores via biblioteca “snmplib”, são passados os parametros host, versão, comunidade, e o retorno e analisado com o nome do processo passado via linha de comando se der “match” ele escreve que o processo esta rodando no servidor em questão, senão(a variavel “axou” esta definida como falso ou seja igual a zero), ele testa a variavel axou e printa que o processo não esta sendo executado.

Manager.open(:Host => ARGV[0],:Version => versao, :Community => comunidade) do |manager|
   ifTable = ObjectId.new(“1.3.6.1.2.1.25.4.2.1.2”)
   next_oid = ifTable
   while next_oid.subtree_of?(ifTable)
     response = manager.get_next(next_oid)
     varbind = response.varbind_list.first
     next_oid = varbind.name
    string = varbind.to_s
    if string.match(processo)
      puts “Processo: #{descricao} STATUS: rodando”
      axou = 1
    end
   end
end

if ( axou != 1 )
  puts “Processo: #{descricao} STATUS: stop”
  exit
end

Abaixo segue a execução do script.

ricardobarbosa@capsula:~$ ./check_snmp.rb
Argumentos inexistente: utilize o parametro -h para obter ajuda
ricardobarbosa@capsula:~$ ./check_snmp.rb -h
Usage: check_windows_processes_snmp.rb [options] host
-c, –comunidade NOME Nomme da Comunidade SNMP
-d, –descricao NOME Descricao do processo
-v, –versao NOME Versao SNMP
-p, –processo NOME Nome do Processo
-h, –help Display this screen
ricardobarbosa@capsula:~$

Testamos o snmp via comando snmpwalk do tools net-snmp(http://www.net-snmp.org/), vamos buscar os nomes de todos os processos.

ricardobarbosa@capsula:~$ snmpwalk -c public -v 2c 192.168.1.3 hrSWRunName
HOST-RESOURCES-MIB::hrSWRunName.1 = STRING: “init”
HOST-RESOURCES-MIB::hrSWRunName.2 = STRING: “kthreadd”
HOST-RESOURCES-MIB::hrSWRunName.3 = STRING: “migration/0”
HOST-RESOURCES-MIB::hrSWRunName.4 = STRING: “ksoftirqd/0”
HOST-RESOURCES-MIB::hrSWRunName.5 = STRING: “watchdog/0”
HOST-RESOURCES-MIB::hrSWRunName.6 = STRING: “events/0”
HOST-RESOURCES-MIB::hrSWRunName.7 = STRING: “khelper”
HOST-RESOURCES-MIB::hrSWRunName.41 = STRING: “kblockd/0”
HOST-RESOURCES-MIB::hrSWRunName.44 = STRING: “kacpid”
HOST-RESOURCES-MIB::hrSWRunName.45 = STRING: “kacpi_notify”
HOST-RESOURCES-MIB::hrSWRunName.88 = STRING: “kseriod”
HOST-RESOURCES-MIB::hrSWRunName.123 = STRING: “pdflush”
HOST-RESOURCES-MIB::hrSWRunName.124 = STRING: “pdflush”
HOST-RESOURCES-MIB::hrSWRunName.125 = STRING: “kswapd0”
HOST-RESOURCES-MIB::hrSWRunName.167 = STRING: “aio/0”
HOST-RESOURCES-MIB::hrSWRunName.1289 = STRING: “ata/0”
HOST-RESOURCES-MIB::hrSWRunName.1294 = STRING: “ata_aux”
HOST-RESOURCES-MIB::hrSWRunName.1308 = STRING: “scsi_eh_0”
HOST-RESOURCES-MIB::hrSWRunName.1312 = STRING: “scsi_eh_1”
HOST-RESOURCES-MIB::hrSWRunName.2317 = STRING: “kjournald”
HOST-RESOURCES-MIB::hrSWRunName.2473 = STRING: “udevd”
HOST-RESOURCES-MIB::hrSWRunName.2667 = STRING: “kpsmoused”
HOST-RESOURCES-MIB::hrSWRunName.3648 = STRING: “dhclient3”
HOST-RESOURCES-MIB::hrSWRunName.4041 = STRING: “getty”
HOST-RESOURCES-MIB::hrSWRunName.4044 = STRING: “getty”
HOST-RESOURCES-MIB::hrSWRunName.4047 = STRING: “getty”
HOST-RESOURCES-MIB::hrSWRunName.4051 = STRING: “getty”
HOST-RESOURCES-MIB::hrSWRunName.4053 = STRING: “getty”
HOST-RESOURCES-MIB::hrSWRunName.4090 = STRING: “syslogd”
HOST-RESOURCES-MIB::hrSWRunName.4109 = STRING: “dd”
HOST-RESOURCES-MIB::hrSWRunName.4111 = STRING: “klogd”
HOST-RESOURCES-MIB::hrSWRunName.4130 = STRING: “sshd”
HOST-RESOURCES-MIB::hrSWRunName.4186 = STRING: “mysqld_safe”
HOST-RESOURCES-MIB::hrSWRunName.4228 = STRING: “mysqld”
HOST-RESOURCES-MIB::hrSWRunName.4229 = STRING: “logger”
HOST-RESOURCES-MIB::hrSWRunName.4313 = STRING: “asterisk”
HOST-RESOURCES-MIB::hrSWRunName.4359 = STRING: “atd”
HOST-RESOURCES-MIB::hrSWRunName.4370 = STRING: “cron”
HOST-RESOURCES-MIB::hrSWRunName.4392 = STRING: “apache2”
HOST-RESOURCES-MIB::hrSWRunName.4408 = STRING: “apache2”
HOST-RESOURCES-MIB::hrSWRunName.4410 = STRING: “apache2”
HOST-RESOURCES-MIB::hrSWRunName.4412 = STRING: “apache2”
HOST-RESOURCES-MIB::hrSWRunName.4413 = STRING: “apache2”
HOST-RESOURCES-MIB::hrSWRunName.4414 = STRING: “apache2”
HOST-RESOURCES-MIB::hrSWRunName.4415 = STRING: “miniserv.pl”
HOST-RESOURCES-MIB::hrSWRunName.4422 = STRING: “login”
HOST-RESOURCES-MIB::hrSWRunName.4423 = STRING: “bash”
HOST-RESOURCES-MIB::hrSWRunName.4439 = STRING: “bash”
HOST-RESOURCES-MIB::hrSWRunName.4855 = STRING: “snmpd”
ricardobarbosa@capsula:~$

Em seguida executamos nosso script em busca do processo apache2 e do postfix para verificar a inexistencia do processo.

ricardobarbosa@capsula:~$ ./check_snmp.rb -c public -v 2c -d “Servidor HTTP APACHE2” -p apache2 192.168.1.3
Processo: Servidor HTTP APACHE2 STATUS: rodando
ricardobarbosa@capsula:~$
ricardobarbosa@capsula:~$ ./check_snmp.rb -c public -v 2c -d “Servidor SMTP POSTFIX” -p master 192.168.1.3
Processo: Servidor SMTP POSTFIX STATUS: stop
ricardobarbosa@capsula:~$

Agora e necessário configurar o arquivo checkcommands.cfg do nagios e inserir o comando com as variaveis.(para o post não ficar muito extenso não vou passar essa configuração num post futuro eu farei isso :D)
Não sou desenvolvedor atualmente mas já trabalhei como desenvolvedor delphi e php. Gosto de criar códigos que me ajudem na infra-estrutura. Espero que o post seja útil até a próxima.

Att. Read more…

Categories: ruby

VBScript – Script de verificação de data de criação de usuários

January 7, 2010 2 comments

Estava trocando idéia com um grande amigo Rodrigo Diniz, ele me dizia que precisava de um script para verificar a datas de criação das contas de usuário do Active Directory. Então achei interessante e aceitei o desafio, resolvi ajuda-lo a encontrar a solução. Fiz algumas pesquisas na internet especificamente no site technet e montei um vbscript baseado no link abaixo.

http://blogs.technet.com/heyscriptingguy/archive/2005/01/06/how-can-i-tell-on-what-date-an-active-directory-user-account-was-created.aspx

O script usa “Active Data Objects” (que dá base para o provedor de serviços de diretorio OLE DB provider chamado ADsDSOObject) para extrair ou buscar informações de objetos a partir do servidor de diretório da Microsoft o Active Directory.

On Error Resume Next

Set objConnection = CreateObject(“ADODB.Connection”)
Set objCommand = CreateObject(“ADODB.Command”)

objConnection.Provider = “ADsDSOObject”
objConnection.Open “Active Directory Provider”

Set objCommand.ActiveConnection = objConnection

objCommand.Properties(“Page Size”) = 1000
objCommand.Properties(“Searchscope”) = 2

objCommand.CommandText = “SELECT ADsPath FROM ‘LDAP://dc=yamaha,dc=com,dc=br’ WHERE objectCategory=’user'”

Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst

Do Until objRecordSet.EOF
strPath = objRecordSet.Fields(“ADsPath”).Value
Set objUser = GetObject(strPath)
Wscript.Echo “Usuario: ” & objUser.FullName
Wscript.Echo “Data de criacao: ” & objUser.whenCreated & ” GMT”
objRecordSet.MoveNext
Loop

Vou tentar explicar passo a passo os comandos do script.

Set objConnection = CreateObject(“ADODB.Connection”)

Criamos o objeto ADODB.Connection o qual é usado para criar uma conexão para uma fonte de dados ou data source como se fosse um ponteiro, e através deste objeto você pode acessar e manipular o banco de dados, no nosso caso não será um banco de dados com tabelas e sim um serviço de diretório.

Set objCommand = CreateObject(“ADODB.Command”)

Criamos outro objeto “ADODB.Command” o qual é usado para executar uma consulta ou comandos dentro do banco de dados(ou data source), este objeto também serve para você poder deletar, excluir ou atualizar dados.

objConnection.Provider = “ADsDSOObject”
objConnection.Open “Active Directory Provider”

Aqui definimos as propriedades da variavel objConnection. A propriedade “Provider” determina qual provedor OLE DB será utilizado no caso do nosso script “ADsDSOObject” o qual é usado para conexão ao Active Directory.

Set objCommand.ActiveConnection = objConnection

Nesta linha ativamos a conexão ao AD utilizado um “ponteiro” para executar comandos dentro do AD(falando resumidamente).

objCommand.Properties(“Page Size”) = 1000
objCommand.Properties(“Searchscope”) = 2

Definimos algumas propriedades.

objCommand.CommandText = “SELECT ADsPath FROM ‘LDAP://dc=yamaha,dc=com,dc=br’ WHERE objectCategory=’user'”

Definimos a string de consulta, o qual iremos buscar todos os objetos do AD com categoria “User”, ou seja, vamos buscar todos os objetos que representam usuários.

Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst

Executamos a consulta e movemos o ponteiro para o primeiro registro.

Do Until objRecordSet.EOF
strPath = objRecordSet.Fields(“ADsPath”).Value
Set objUser = GetObject(strPath)
Wscript.Echo “Usuario: ” & objUser.FullName
Wscript.Echo “Data de criacao: ” & objUser.whenCreated & ” GMT”
objRecordSet.MoveNext
Loop

Aqui fazemos um loop buscando nos objetos “User”, nome e data de criação da conta e “printando” e no final movendo o “ponteiro” para o próximo registro.

Nomeie o arquivo para user.vbs dé um duplo o qual invocará o
wscript.exe que é o padrão para o WIndows e usa janelas gráficas ou ainda utilizar o cscript.exe para poder escrever arquivos de lote sem recursos gráficos. Abaixo segue a saída do comando via cscript.exe.

C:\Documents and Settings\Administrator\Desktop>cscript user.vbs
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Account created: 5/5/2009 8:08:02 PM GMT
Password last changed: 5/5/2009 1:42:23 PM

Account created: 5/5/2009 8:08:02 PM GMT

User: CN=Microsoft Corporation,L=Redmond,S=Washington,C=US
Account created: 5/5/2009 8:08:02 PM GMT
Password last changed: 5/5/2009 4:48:36 PM

Account created: 5/5/2009 7:15:59 PM GMT
Password last changed: 5/5/2009 5:15:59 PM

User: srv-winbind
Account created: 5/26/2009 8:26:54 PM GMT
Password last changed: 5/28/2009 6:31:36 PM

User: kakaroto
Account created: 5/28/2009 8:23:08 PM GMT
Password last changed: 6/25/2009 6:22:54 PM

User: email
Account created: 6/19/2009 9:52:05 PM GMT
Password last changed: 6/25/2009 6:27:04 PM

C:\Documents and Settings\Administrator\Desktop>

Após o script ser testado e funcionando o Dr Diniz veio com mais uma “bucha”, descobrir qual a ultima vez que o usuario fez logon. Aceitei mais uma fez o desafio, em principio e somente dar um “wscript.echo” no lastlogon, porém não é bem assim lendo e relendo nos confins da internet descobri uma coisa interessante conforme link abaixo.

http://www.linhadecodigo.com.br/Artigo.aspx?id=1706

O valor retornado representa número de segundos passados desde as 0:00 de 01/01/1601. assim teremos que fazer um pequeno calculo para converter para o formato de data convencional.

On Error Resume Next

Set objUser = GetObject(“LDAP://cn=kakaroto,cn=users,dc=yamaha,dc=com,dc=br”)
Wscript.Echo objUser.WhenCreated

Set objLastLogon = objUser.Get(“lastLogonTimestamp”)
intLastLogonTime = objLastLogon.HighPart * (2^32) + objLastLogon.LowPart
intLastLogonTime = intLastLogonTime / (60 * 10000000)
intLastLogonTime = intLastLogonTime / 1440
Wscript.Echo “Last logon time: ” & intLastLogonTime + #1/1/1601#

Salve o arquivo com qualquer nome de sua preferencia, porém com extensão vbs e execute(novamente com cscript.exe).

C:\Documents and Settings\Administrator\Desktop>cscript lastlogon.vbs
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

5/28/2009 8:23:08 PM
Last logon time: 1/1/1601

C:\Documents and Settings\Administrator\Desktop>

Bom nao é muito de costume programar, mas gosto de utilizar o desenvolvimento para resolver problema de infra-estrutura e este foi mais um exemplo. Como dizia um grande amigo Thiago(vulgo maluco) “O melhor programador é o melhor administrador de rede” e “O melhor administrador de rede é o melhor programador”. 🙂

Até a próxima.

Categories: vbscript, windows