Você está na página 1de 24

Caso de Estudo: Linux e Windows

Daniel Braga Moura

Universidade Federal do Piauí

Departamento de Informática e Estatística

nsontt@yahoo.com.br

30 de Abril de 2006.

Abstract
The Unix has a long and interesting history. What it started as a favourite project of a
young researcher if it became a multimillionaire industry involving international
universities, corporations, governments and groups. The version of the following NT to
the NT4.0 would be called originally NT5.0. However, in 1999, the Microsoft changed
the name for Windows 2000. Windows 2000 is a modern operational system that it
executes in PCs of table and servers.

Keywords: Unix, NT5.0, Windows 2000.

Resumo
O Unix tem uma história longa e interessante. Aquilo que começou como um projeto
favorito de um jovem pesquisador se tornou uma indústria multimilionária envolvendo
universidades, corporações, governos e grupos internacionais . A versão do NT
seguinte à NT4.0 seria chamada originalmente de NT5.0. Contudo, em 1999, a
Microsoft mudou o nome para Windows 2000. O Windows 2000 é um sistema
operacional moderno que executa em PCs de mesa e em servidores.

Palavras - chave: Unix, NT5.0, Windows 2000


Lista de Ilustrações

Figura1.1 - Mapa Linux .........................................................................................07


Figura1.2 – Criação de processo no Linux............................................................08
Figura1.3 – Algumas chamadas ao sistema relacionadas com processos...........09
Figura1.4 – Chamadas ao sistema relacionadas com o gerenciamento de
memória..........................................................................................................................11
Figura1.5 – Principais chamadas do POSIX para o gerenciamento de
terminal...........................................................................................................................12
Figura1.6 – Alguns diretórios importantes encontrados na maioria dos
sistemas Unix..................................................................................................................13
Figura1.7 – Alguns chamadas ao sistema relacionadas com arquivos..............14
Figura1.8 – Alguns chamadas ao sistema relacionadas a segurança.................15
Figura2.1 – Conceitos básicos usados para o gerenciamento da CPU e de
recursos...........................................................................................................................17
Figura2.2 – O esquema do espaço de endereçamento virtual para três
processos de usuário. As áreas brancas são privadas aos processos. As áreas
sombreadas são compartilhadas entre todos os processos.........................................18
Figura2.3 – Principais funções API Win32 para gerenciamento de memória
virtual no Windows 2000..............................................................................................19
Figura2.4 – Algumas categorias de chamadas API Win32.................................20
Figura2.5 – Principais funções da API Win32 para E/S de arquivos................22
Figura2.6 – Estrutura de uma ficha de acesso.....................................................23
Figura2.7 – As principais funções da API Win32 para segurança....................23

2
Lista de Siglas

GPL - GNU Public Licence


MULTICS - Multiplexed Information and Computing Service
TCP/IP – Transmission Control Protocol/Internet Protocol
UNICS - Uniplexed Information and Computing Service

3
Sumário

1 Linux .......................................................................................................05

1.1. Histórico ..................................................................................................................05

1.2. Processos..................................................................................................................08

1.3. Gerenciamento de Memória.....................................................................................10

1.4. Entrada/ Saída...........................................................................................................11

1.4. Sistema de Arquivos.................................................................................................12

1.5. Segurança..................................................................................................................14

2 Windows 2000 ........................................................................................16

2.1. Histórico...................................................................................................................16

2.2. Processos..................................................................................................................17

2.3. Gerenciamento de Memória.....................................................................................18

2.4. Entrada/ Saída...........................................................................................................19

2.5.Sistema de Arquivos..................................................................................................21

2.6. Segurança..................................................................................................................22

3 Referências .............................................................................................24

4
1. Linux

1.1 – Histórico

Nas décadas de 40 e 50, a maneira normal de usar um computador era reservá-lo por
um tempo e então ficar com a máquina toda durante aquele período. Obviamente, essas
máquinas eram fisicamente imensas, mas somente o programador podia usá-la em um
dado momento. Quando surgiram os sistemas em lote, nos anos 60, o programador
submetia um job através de cartões perfurados carregando-os para a sala de máquinas.
Quando vários jobs tinham sido montados, o operador lia todos eles como um único
lote. Em geral levava uma hora ou mais, após a submissão do job, até que a saída fosse
gerada. Sob essas circunstâncias, a depuração era um processo que consumia tempo,
pois uma única vírgula mal posicionada poderia resultar no desperdício de várias horas
do tempo do programador.
Para contornar aquilo que quase todos consideravam uma organização insatisfatória
e improdutiva, o compartilhamento de tempo foi inventado no MIT e no Instituto
Dartmouth. O sistema Dartmouth executava somente BASIC e durante pouco tempo
desfrutou de certo sucesso comercial antes de desaparecer. O CTTSS – o sistema do
MIT – era de propósito geral e foi um enorme sucesso entre a comunidade científica.
Dentro de pouco tempo, os pesquisadores do MIT juntaram esforços com a Bell Labs e
a General Electric (na época um fabricante de computadores) e começaram a projetar
um sistema de segunda geração, chamado MULTICS (multiplexed information and
computing service – informação multiplexada e serviço de computação).
Embora a Bell Labs fosse um dos parceiros fundadores do projeto MULTICS, mais
tarde o abandonou, mas manteve um de seus pesquisadores, Ken Thompson, na
tentativa de encontrar algo interessante para fazer. Ele por fim decidiu escrever por si
próprio um MULTICS mais enxuto (em linguagem de montagem, dessa vez) em um
minicomputador PDP-7 abandonado. Independentemente do pequeno tamanho do PDP
– 7, o sistema realmente funcionava e podia suportar os esforços de desenvolvimento de
Thompson. Por causa disso, outro pesquisador da Bell Labs, Brian Kernighan, em tom
de brincadeira, chamou o sistema de UNICS (uniplexed information and computing
service – serviço de computação e de informação uniplexada). Apesar do trocadilho que
chamava o sistema de EUNUCOS por ser um MULTICS castrado, o nome pegou,
embora a ortografia tenha sido posteriormente trocada para Unix. Depois disso,
surgiram vários clones do Unix.
Após vários anos, um estudante filandês chamado Linus Torvalds decidiu escrever
um outro clone do Unix, chamado Linux, o qual seria um sistema de produção completo
com muitas características que faltavam (intencionalmente) no Minix (um clone anterior
do Unix). A primeira versão do Linux, 0.01, foi liberada em 1991. Ela foi desenvolvida
de modo cruzado (cross-developed) em uma máquina Minix, utilizando algumas de suas
idéias, as quais iam desde a estrutura de árvore da fonte até o layout do sistema de
arquivos. Contudo, era um projeto monolítico em vez de micronúcleo, com o sistema
operacional todo no núcleo. O tamanho do código totalizava 9300 linhas de C e 950
linhas em linguagem de montagem – tamanho aproximadamente similar à versão do
Minix e funcionalidades também aproximadamente parecidas.
O Linux cresceu rapidamente de tamanho e evoluiu para um completo clone Unix
de produção quando uma memória virtual, um sistema de arquivos mais sofisticado e
muitas outras características lhe foram adicionadas.
O maior lançamento seguinte do Linux foi a versão 1.0, em 1994. Ela tinha em
torno de 165 mil linhas de código incluindo um novo sistema de arquivos, arquivos

5
mapeados em memória e conexão de rede compatível com o BSD usando sockets e
TCP/IP. Ela também incluiu muitos novos drivers de dispositivos. Várias pequenas
revisões ocorreram nos dois anos seguintes.
Naquele momento, o Linux era suficientemente compatível com o Unix e uma vasta
quantidade de softwares do Unix foi transportada para ele, tornando-o muito mais útil
do que ele teria sido se isso não tivesse ocorrido. Além disso, muitas pessoas foram
atraídas pelo Linux e começaram a trabalhar com seu código, estendendo-o de muitas
maneiras sob a supervisão geral de Torvalds.
O maior lançamento depois disso, a versão 2.0, ocorreu em 1996. Essa versão
possuía em torno de 470 mil linhas de C e oito mil linhas de código em linguagem de
montagem. Ela incluiu suporte para a arquitetura de 64 bits, multiprogramação
simétrica, novos protocolos de redes e inúmeras outras características. Uma extensa
parcela do código total foi ocupada por uma grande quantidade de drivers de
dispositivo. Outras versões continuaram surgindo e delas se derivaram diversas
distribuições (ver figura 1.1).
Uma grande quantidade de software Unix-padrão foi transportada para o Linux,
incluindo mais de mil programas utilitários, X Windows e muito software para conexões
em redes. Duas GUIs diferentes (GNOME e KDE) foram também escritas para Linux.
Em resumo, ele se tornou um clone poderoso do Unix com todas as características
avançadas que os adeptos do Unix podem querer.
Uma característica não usual do Linux é seu modelo comercial: ele é um software
livre; pode ser copiado de vários lugares da Internet – por exemplo: www.nucleo.org. O
Linux vem com uma licença criada por Richard Stallman, fundador da Fundação para
Software Livre. Independentemente de o Linus ser livre, essa licença, a GPL (GNU
Public Licence – Licença Pública GNU), é mais longa do que a licença do Windows
2000 da Microsoft e especifica o que você pode e não pode fazer com o código. Os
usuários podem usar, copiar, modificar e redistribuir os códigos-fonte e binários
livremente. A principal restrição é que todos os trabalhos derivados do núcleo do Linux
não podem ser vendidos ou redistribuídos somente na forma de código binário; os
códigos-fonte devem ser enviados com o produto ou disponibilizados mediante uma
solicitação.

6
Figura1.1 - Mapa Linux .

7
1.2 – Processos

O Linux é um sistema multiprogramado, de modo que múltiplos processos


independentes podem executar ao mesmo tempo. Cada usuário pode ter vários
processos ativos de uma só vez, e, assim, em um grande sistema, é possível haver
centenas ou talvez milhares de processos executando. De fato, na maioria das estações
de trabalho de um único usuário, mesmo que o usuário esteja ausente, muitos processos,
chamados de daemons, estão executando em segundo plano. Esses processos são
iniciados automaticamente quando o sistema é inicializado.
No Linux os processos são criados de um jeito bastante simples. A chamada ao
sistema fork cria uma cópia exata do processo original. O processo criador é chamado
de processo pai. O novo processo é chamado de processo filho. Cada um tem sua
própria imagem da memória privada. Se, após a criação o pai alterar suas variáveis,
essas alterações não serão visíveis pelo processo filho e vice-versa.
Os arquivos abertos são compartilhados entre o processo pai e o processo filho. Ou
seja, se um certo arquivo estava aberto no pai, antes da criação do filho, ele continuará
aberto em ambos os processos, pai e filho. Alterações feitas nesse arquivo serão visíveis
a ambos os processos. Esse comportamento é razoável, pois essas alterações são, da
mesma maneira, visíveis a qualquer processo não relacionado que também abre o
arquivo.
O fato de as imagens da memória, as variáveis, os registradores e tudo o mais serem
idênticos tanto no processo pai quanto no processo filho gera uma pequena dificuldade:
como permitir que os processos saibam quem deve executar no código do pai e quem
deve executar no código do filho? O segredo é que a chamada ao sistema fork retorna 0
para filho e um valor não-nulo – o PID (identificador de processo) – do processo filho
para o processo pai. Ambos os processos costumam verificar o valor retornado e assim
podem agir diferentemente. (ver figura 1.2).

pid = fork(); /* se o fork tiver êxito, o processo pai obterá pid >0 */
if (pid < 0) {
handle_error(); /* o fork falho (por exemplo, a memória está cheia) */
} else if (pid > 0) {
/* código do pai */
} else {
/* código do filho */
}

Figura1.2 – Criação de processo no Linux.

Vamos agora conhecer as chamadas ao sistema do Linux que tratam do


gerenciamento de processos. As principais são relacionadas na Figura 1.3. a chamada
fork é um bom início de discussão. Fork é a única maneira de criar um novo processo
nos sistemas Linux: gera uma duplicata exata do processo original, incluindo todos os
descritores de arquivos, registradores e tudo o mais. Após o fork, o processo original e a
cópia (o pai e o filho) seguem por caminhos separados. Todas as variáveis têm valores
idênticos àqueles do momento da execução do fork, mas, visto que a imagem da

8
memória do pai é copiada para criar o filho, as alterações subseqüentes em um deles não
afetam o outro. A chamada fork retorna um valor, o qual é zero no filho e igual ao PID
do filho no pai. Usando o PID retornado, os dois processos podem saber quem é o pai e
quem é o filho.
Na maioria dos casos, após um fork, o filho precisa executar um código diferente do
código do pai. Considere o caso do shell que lê um comando do terminal, cria um
processo filho, espera até que o filho execute o referido comando e, depois que o filho
termina, lê o próximo comando. Para esperar o filho terminar, o pai executa uma
chamada ao sistema waitpid, que simplesmente espera o filho terminar (qualquer filho,
caso exista mais do que um). Waitpid tem três parâmetros. O primeiro permite que o
chamador espere por um filho específico. Se o valor dele é 1, qualquer filho antigo
servirá (isto é, o filho que terminar primeiro). O segundo parâmetro é o endereço de
uma variável que será ajustada com o status de término do filho (término normal ou
anormal e valor de retorno). O terceiro parâmetro determina se o chamador deve ou não
ser bloqueado caso nenhum filho seja chamado.
No caso do shell, o processo filho deve executar o comando digitado pelo usuário.
Ele faz isso por meio da chamada ao sistema exec, que substitui toda a sua imagem na
memória pelo arquivo indicado no primeiro parâmetro da chamada.

Chamada ao sistema Descrição


pid = fork() Cria um processo filho idêntico ao pai
pid = waitpid(pid, &statloc, opts) Espera o processo filho terminar
s = execve(name, argv, envp) Substitui a imagem da memória de um processo
exit(status) Termina a execução de um processo e retorna o status
s = sigaction(sig, &act, &oldact) Define a ação a ser tomada nos sinais
s = sigreturn(&context) Retorna de um sinal
s = sigprocmask(how, &set, &old) Examina ou modifica a máscara do sinal
s = sigpending(set) Obtém o conjunto de sinais bloqueados
s = sigsuspend(sigmask) Substitui a mascara de sinal e suspende o processo
s = kill(pid, sig) Envia um sinal para um processo
residual = alarm(seconds) Ajusta o relógio do alarme
s = pause Suspende o chamador até o próximo sinal

Figura1.3 – Algumas chamadas ao sistema relacionadas com processos.

9
1.3 – Gerenciamento de Memória

O modelo de memória do Linux é direto e objetivo de modo que permita a


portabilidade dos programas e possibilite a implementação do Linux em máquinas com
unidades de gerenciamento de memória muito diferentes, desde as mais simples (por
exemplo, IBM PC original) até aquelas com hardware de paginação sofisticado. Essa é
uma área do projeto pouco alterada durante décadas – como funcionou bem, não
precisou de muita revisão.
Todo processo do Linux tem um espaço de endereçamento que consiste de três
segmentos: código, dado e pilha. O segmento de código contém as instruções de
máquina que formam o código executável do programa. Ele é produzido pelo
compilador e montado por meio da tradução de C, C++ ou outros programas em código
de máquina. O segmento de código é em geral marcado como somente-para-leitura. A
modificação do código pelo próprio programa saiu de linha em torno de 1950 porque
ele ficava muito difícil de compreender e depurar. Assim, o segmento de código não
cresce, não diminui nem se altera de nenhuma maneira.
O segmento de dados é o local de armazenamento das variáveis do programa, das
cadeias de caracteres, dos vetores e de outros dados. Ele tem duas partes: os dados
inicializados e os dados não inicializados. Por razões históricas o segundo é conhecido
como BSS. A parte inicializada do segmento de dados contém as variáveis e as
constantes que necessitam de um valor inicial quando o programa é iniciado.
O terceiro segmento é o de pilha. Na maioria das máquinas, ele inicia no topo do
espaço de endereçamento virtual – ou próximo dele – e cresce para baixo, em direção ao
endereço 0. Se a pilha cresce além da base do segmento de pilha, uma interrupção
ocorre e o sistema operacional atualiza a posição da base em uma página mais abaixo.
Os programas não gerenciam explicitamente o tamanho do segmento de pilha.
Quando um programa inicia, sua pilha não está vazia, pelo contrário: ela contém
todas as variáveis de ambiente (shell) além da linha de comando digitada no shell
quando ele foi invocado. Dessa maneira, um programa pode descobrir seus argumentos.
Muitas versões do Linux suportam arquivos mapeados em memória. Essa
característica possibilita mapear arquivos em uma parte do espaço de endereçamento do
processo permitindo que o arquivo seja lido e escrito como se ele fosse um vetor de
bytes na memória. Mapear um arquivo na memória facilita muito mais o acesso
aleatório do que usar chamadas ao sistema para E/S como read e write. As bibliotecas
compartilhadas são acessadas por meio do mapeamento em memória usando esse
mecanismo.
Uma vantagem adicional do mapeamento de arquivos é que dois ou mais processos
podem mapear o mesmo arquivo simultaneamente. As escritas no arquivo feitas por
qualquer um deles são instantaneamente visíveis para os demais processos. De fato, por
meio do mapeamento de um arquivo auxiliar, esse mecanismo fornece um canal de alta
largura de banda para múltiplos processos compartilharem memória. No caso mais
extremo, dois ou mais processos podem mapear um arquivo que abranja o espaço de
endereçamento todo, fornecendo uma forma de compartilhamento entre processos
separados e threads. Na prática, porém, nunca são criados dois espaços de
endereçamento exatamente correspondentes.
Muitos sistemas Unix têm chamadas ao sistema para o gerenciamento de memória.
As mais comuns são apresentadas na figura 1.4. Brk especifica o tamanho do segmento
de dados informando o endereço do primeiro byte depois dele. Se o novo valor é maior
do que o antigo, o segmento de dados aumenta; caso contrário, diminui.
As chamadas ao sistema mmap e munmap controlam os arquivos mapeados em
memória. O primeiro parâmetro de mmap, addr, determina o endereço no qual é

10
mapeado o arquivo (ou parte dele). Ele deve ser múltiplo do tamanho da página. Se esse
parâmetro é 0, o sistema determina o endereço por si próprio e o retorna em a. o
segundo parâmetro, len, diz quantos bytes devem ser mapeados. Ele também deve ser
múltiplo do tamanho da página. O terceiro parâmetro, prot, determina a proteção do
arquivo mapeado. Ele pode ser marcado como para-leitura, para-escrita, para-execução
ou alguma combinação dessas possibilidades. O quarto parâmetro, flags, controla se o
arquivo é privado ou é compartilhado e se addr é uma exigência ou meramente uma
sugestão. O quinto parâmetro, fd, é o descritor de arquivo a ser mapeado. Somente
arquivos abertos podem ser mapeados, de modo que para mapear um arquivo na
memória ele deve primeiramente ser aberto. Por fim, offset diz a posição do arquivo
onde deve ser iniciado o mapeamento. Ele não é necessário quando se deseja mapear a
partir do byte 0; caso contrário, sim.
A outra chamada, munmap, remove um arquivo mapeado. Se somente parte dele é
removida do mapeamento, o restante continua mapeado.

Chamada ao sistema Descrição


S = brk(addr) Troca o tamanho do segmento de dados
A = mmap(addr, len, prot, flags, fd, offset) Mapeia um arquivo na memória
S = unmap(addr, len) Remove o mapeamento do arquivo

Figura1.4 – Chamadas ao sistema relacionadas com o gerenciamento de memória.

1.4 – Entrada/ Saída

Usar sistema de E/S no Linux é bastante simples. Basicamente, todos os dispositivos


de E/S são tratados como arquivos e são acessados com as mesmas chamadas ao
sistema read e write usadas para acessar os arquivos comuns. Em alguns casos, os
parâmetros do dispositivo devem ser configurados, e isso é feito com uma chamada ao
sistema especial.
Assim como todos os computadores, aqueles que executam Linux têm dispositivos
de E/S como discos, impressoras e redes conectadas. Torna-se necessária alguma
maneira de permitir o acesso a esses dispositivos. Embora várias soluções sejam
possíveis, o Linux integra os dispositivos no sistema de arquivos, chamando-os de
arquivos especiais. Cada dispositivo de E/S é associado a um nome de caminho,
geralmente no /dev. Por exemplo, um disco pode ser /dev/hd1, uma impressora pode ser
/dev/lp e a rede pode ser /dev/net.
Esses arquivos especiais podem ser acessados da mesma maneira que os demais
arquivos. Não são necessários quaisquer comandos especiais nem chamadas ao sistema
– as chamadas ao sistema usuais read e write são suficientes.
Os arquivos especiais são divididos em duas categorias: blocos e caracteres. Um
arquivo especial de bloco consiste em uma seqüência de blocos enumerados. A
propriedade principal do arquivo especial de bloco é que cada bloco pode ser
endereçado e acessado individualmente. Em outras palavras, um programa pode abrir
um arquivo especial de bloco e ler, digamos, o bloco 124 sem primeiro passar pelos
blocos de 0 a 123. Os arquivos especiais de blocos são em geral usados em discos.
Os arquivos especiais de caracteres são normalmente empregados em dispositivos
em que a entrada e a saída são feitas como fluxos de caracteres. Teclados, impressoras,
redes, mouses, plotters e a maioria dos dispositivos de E/S que recebem ou enviam

11
dados usam arquivos especiais de caracteres. Não é possível (ou mesmo significativo)
posicionar no bloco 124 de um mouse.
Associado a cada arquivo especial existe um driver do dispositivo que trata o
dispositivo correspondente. Cada driver tem um número do dispositivo principal, que
serve para identifica-lo. Se um driver suportar vários dispositivos – digamos, dois
discos de mesmo tipo -, cada um também terá um número do dispositivo secundário que
o identificará.
Cada dispositivo de E/S no Linux possui, em geral, um arquivo especial associado a
ele. A maioria da E/S pode ser feita simplesmente pelo uso do arquivo correto,
eliminando a necessidade de chamadas especiais ao sistema. No entanto, algumas vezes
existe uma necessidade de algo específico do dispositivo. Antes do POSIC, a maioria
dos sistemas Unix tinha uma chamada ao sistema, ioctl, que executava inúmeras ações
específicas dos dispositivos nos arquivos especiais. Com o passar do tempo, ela se
tornou muito confusa. O POSIC simplificou-se e distribuiu suas funções em chamadas
separadas, primeiramente para os terminais. Ou cada uma é uma chamada ao sistema
separada, ou elas compartilham uma única chamada ao sistema, ou tudo fica
independente da implementação.
As primeiras quatro relacionadas na Figura 1.5 são usadas para obter e ajustar a
velocidade do terminal. As duas últimas chamadas da lista em questão são usadas para a
configuração e a leitura de volta de todos os caracteres especiais empregados para a
deleção de caracteres e linhas, interrupção de processos e assim por diante. Além disso,
elas habilitam e desabilitam o eco, tratam do fluxo de controle e de outras funções
relacionadas. Existem ainda outras chamadas a funções de E/S, mas, como elas são
especializadas, não iremos muito a fundo. Além disso, ioctl ainda existe na maioria dos
sistemas Linux.

Chamada a função Descrição


s = cfwetospeed(&termios, speed) Ajusta a velocidade de saída
s = cfwetispeed(&termios, speed) Ajusta a velocidade de entrada
s = cfgetospeed(&termios, speed) Obtém a velocidade de saída
s = cfgtetispeed(&termios, speed) Obtém a velocidade de entrada
s = tcsetattr(fd, opt, &termios) Ajusta os atributos
s = tcgetattr(fd, speed) Obtém os atributos

Figura1.5 – Principais chamadas do POSIX para o gerenciamento de terminal.

1.5 Sistema de Arquivos

A parte mais visível de qualquer sistema operacional, inclusive o Linux, é o sistema


de arquivos. Iremos ver a seguir as idéias básicas relacionadas ao sistema de arquivos
do Linux e as chamadas ao sistema. Algumas dessas idéias derivam do MULTICS e
muitas delas foram copiadas pelo MS-DOS, pelo Windows e por outros sistemas, mas
outras idéias são exclusivas do Linux. O projeto do Linux é especialmente interessante
porque ele ilustra nitidamente o princípio O Pequeno É Bonito. Com um mínimo de
mecanismo e um número muito limitado de chamadas ao sistema, o Linux fornece,
contudo, um sistema de arquivos poderoso e superior.

12
Um arquivo do Linux é uma seqüência de 0 ou mais bytes contendo qualquer
informação. Nenhuma distinção é feita entre arquivos ASCII, arquivos binários ou
quaisquer outros tipos de arquivos. O significado dos bits de um arquivo é de total
conhecimento do proprietário do arquivo. O sistema não se preocupa com isso. Os
nomes de arquivos eram originalmente restritos a 14 caracteres comuns, mas o Unix de
Berkeley aumentou esse limite para 255 caracteres, que foi adotado pelo System V e
pela maioria das outras versões também. Todos os caracteres ASCII, exceto NUL, são
permitidos nos nomes dos arquivos, de modo que um nome de arquivo consistindo em
três retornos de carro (carriage returns) é um nome de arquivo válido.
Os arquivos podem ser agrupados em diretórios por questões de conveniência. Os
diretórios são armazenados como arquivos e em grande parte são passíveis de ser
tratados como arquivos. Eles podem conter subdiretórios, proporcionando um sistema
de arquivos hierárquico. O diretório-raiz é chamado / e geralmente contém vários
subdiretórios. O caractere / também é usado para separar nomes de diretórios; assim, o
nome /usr/ast/x indica o arquivo x localizado no diretório ast, o qual está no diretório
/usr.
Alguns diretórios principais próximos ao topo da árvore hierárquica são mostrados
na Figura 1.6.

Diretório Conteúdos
bin Programas binários (executáveis)
dev Arquivos especiais para dispositivos de E/S
etc Arquivos diversos do sistema
lib Bibliotecas
usr Diretórios de usuários

Figura1.6 – Alguns diretórios importantes encontrados na maioria dos sistemas Unix

Existem duas maneiras de especificar os nomes de arquivos no Linux, tanto no shell


quanto durante a abertura de um arquivo por meio de um programa. A primeira maneira
consiste em usar o caminho absoluto que especifica como obter o arquivo a partir do
diretório-raiz. Um exemplo de caminho absoluto é /usr/ast/books/mos3/chapter-10, que
pede ao sistema para procurar no diretório-raiz o diretório chamado usr, depois procurar
outro diretório chamado ast. Esse diretório contém o diretório books, o qual contém o
diretório mos3, que contém o arquivo chapter-10.
Os nomes de caminhos também podem ser definidos em relação ao diretório de
trabalho. Um nome de caminho especificado de modo relativo ao diretório de trabalho é
um caminho relativo.
Muitas chamadas ao sistema são relacionadas a arquivos e ao sistema de arquivos.
Primeiramente, veremos as chamadas ao sistema que operam sobre arquivos
individuais. Em seguida, examinaremos as que envolvem diretórios ou sistema de
arquivos como um todo. Para criar um novo arquivo, é possível empregar a chamada
creat. Os parâmetros fornecem o nome do arquivo e o modo de proteção. Assim,

fd = creat(“abc”,modo);

cria um arquivo chamado abc com os bits de proteção obtidos de modo. Esses bits
determinam quais usuários podem acessar o arquivo e como isso pode ser feito.
A chamada creat, além de criar um novo arquivo, também o abre para escrita. A fim
de permitir que novas chamadas ao sistema acessem o arquivo, uma chamada creat

13
bem-sucedida retorna como resultado um pequeno número inteiro não negativo
chamado descritor de arquivo – fd no exemplo anterior. Se a chamada creat é feita sobre
um arquivo existente, o referido arquivo tem seu tamanho zerado e seu conteúdo é
descartado.
Vamos ver as principais chamadas ao sistema de arquivos conforme Figura 1.7.

Chamadas ao sistema Descrição


fd = creat(nome, modo) Uma maneira de criar um novo arquivo
fd = open(arquivo, como, ...) Abre um arquivo para leitura, escrita ou ambos
s = close(fd); Fecha um arquivo aberto
n = read(fd, buffer, nbytes) Lê dados de um arquivo para um buffer
n = write(fd, buffer, nbytes) Escreve dados de um buffer para um arquivo
posição = lseek(fd, deslocamento, de-onde) Move o ponteiro do arquivo
s = stat(nome, &buf) Obtém a informação de estado do arquivo
s = fstat(fd, &buf) Obtém a informação de estado do arquivo
s = pipe(&fd[0]) Cria um pipe
s = fcntl(fd, comando, ....) Impedimento de arquivo e outras operações

Figura1.7 – Alguns chamadas ao sistema relacionadas com arquivos.

1.6 Segurança

O Linux tem sido um sistema multiusuário desde o início. Isso significa que a
segurança e o controle da informação foram embutidos no sistema há muito tempo.
A comunidade de usuários em um sistema Linux consiste em alguns usuários
registrados, cada um deles com um UID (ID do usuário) único. Um UID é um número
inteiro entre 0 e 65535. os arquivos (e também processos e outros recursos) são
marcados com o UID de seu proprietário. Por convenção, o proprietário de um arquivo
é a pessoa que o criou, embora exista como trocar a posse.
Os usuários podem ser organizados em grupos, os quais são também numerados
com inteiros de 16 bits chamados GIDs (ID do grupo). A associação de usuários em
grupo é feita manualmente pelo administrador do sistema e consiste na inserção de
entradas na base de dados do sistema para informar quais usuários estão em quais
grupos.
O mecanismo de segurança básico do Linux é simples. Cada processo carrega o
UID e o GID de seu proprietário. Quando um arquivo é criado, ele obtém o UID e o
GID do processo criador. O arquivo obtém ainda um conjunto de permissões
determinadas pelo processo criador. Essas permissões especificam quais os tipos de
acessos que o proprietário, ou outros membros do grupo do proprietário e o restante dos
usuários têm sobre o arquivo.
Existe somente um pequeno número de chamadas ao sistema relacionadas à
segurança. As mais importantes estão relacionadas na Figura 1.8. A chamada ao sistema
mais amplamente usada é chmod, que serve para alterar o modo de proteção.

14
Chamada ao sistema Descrição
s = chmod(caminho, modo) Troca o modo de proteção do arquivo
s = access(caminho, modo) Verifica acesso usando UID e GID reais
uid = getuid() Obtém o UID real
uid = geteuid() Obtém o UID efetivo
uid = gedid() Obtém o GID real
gid = getegid() Obtém o GID efetivo
s = chown(caminho, proprietário, grupo) Troca proprietário e grupo
s = setuid(uid) Configura o UID
s = setgid(gid) Configura o GID

Figura1.8 – Alguns chamadas ao sistema relacionadas a segurança.

15
2. Windows 2000

2.1– Histórico

Os sistemas operacionais da Microsoft para PCs desktops e para PCs portáteis


podem ser divididos em três famílias: MS-DOS, Consumer Windows (Windows
95/98/Me) e Windows NT.
A versão NT seguinte à NT 4.0 seria originalmente chamada de NT 5.0. contudo, em
1999, a Microsoft mudou o nome para Windows 2000, mais como uma tentativa de
conseguir um nome neutro que tanto os usuários do Windows 98 quanto os do NT
pudessem ver como a próxima etapa lógica para eles. Uma vez funcionando essa
abordagem, a Microsoft teria um único sistema operacional construído em uma
tecnologia confiável de 32 bits, mas usando a interface com o usuário do popular
Windows 98.
Como o Windows 2000 é na verdade o NT 5.0, ele herda muitas propriedades do NT
4.0. É um verdadeiro sistema multiprogramação de 32 bits com processos
individualmente protegidos. Cada processo tem um espaço de endereçamento virtual de
32 bits com paginação sob demanda. O sistema operacional executa no modo núcleo; já
o processo do usuário executa no modo usuário, oferecendo uma proteção completa
(sem os problemas de proteção do Windows 98). Os processos podem ter um ou mais
threads, que são visíveis e escalonados pelo sistema operacional. Possui um nível de
segurança padrão C2 do Departamento de Defesa – isso para todos os arquivos,
diretórios, processos e outros objetos compartilháveis (pelo menos, se a unidade de
disco flexível for removida e se a rede estiver desconectada). Por fim, oferece também
suporte total à execução em multiprocessadores simétricos com até 32 CPUs.
O Windows 2000 é mais que apenas um NT 4.0 melhorado com uma interface com
o usuário do Windows 98. para começar, ele tem diversas características encontradas
comente no Windows 98, que incluem um suporte completo para dispositivos plug and
play, barramentos USB, IEE 1394 (FireWire), IrDA, gerenciamento de energia, entre
outras. Além disso, várias características que não estavam presentes em outros sistemas
operacionais da Microsoft foram incorporadas – dentre elas o serviço de diretório ativo,
de segurança usando Kerberos, de suporte a cartões inteligentes, de ferramentas de
monitoramento de sistemas, uma melhor integração entre computadores portáteis e
computadores de mesa, uma infra-estrutura de gerenciamento do sistema e objetos de
trabalhos. Além disso, o principal sistema de arquivos, o NTFS foi extendido para
suportar, por exemplo, arquivos criptografados, cotas, redirecionamento de arquivos,
volumes montados e indexação por conteúdo. Outra novidade do NTFS é o
armazenamento em instância simples, que é um tipo de redirecionamento de cópia-
depois-da-escrita na qual dois usuários podem compartilhar um arquivo redirecionando
até que um deles escreva nele; nesse momento é gerada, automaticamente, uma cópia.
Um outro aperfeiçoamento importante é a internacionalização. O NT 4.0 tem
versões diferentes para cada idioma, ou seja, as cadeias de caracteres ficam embutidas
no código. A instalação de um aplicativo inglês em um computador holandês fazia com
que o sistema operacional parasse de usar o holandês e começasse a usar o inglês, pois
certos arquivos contendo código e cadeias de texto eram sobrescritos. Esse problema foi
eliminado. O Windows 2000 tem um único arquivo binário que executa em qualquer
lugar do mundo.
O Windows 2000 é um sistema imensamente complexo, contendo agora, mais de 29
milhões de linhas de código em C.

16
2.2– Processos

O Windows 2000 tem vários conceitos de gerenciamento da CPU e de agrupamento


de recursos.
O Windows 2000 suporta processos tradicionais, que podem se comunicar e
sincronizar uns com os outros, assim como no Linux. Cada processo contém pelo menos
um thread, que por sua vez contém um filamento (thread de peso leve). Além disso, os
processos podem ser reunidos em trabalhos para fins de gerenciamento de recursos.
Juntos, trabalhos, processos, threads e filamentos oferecem um conjunto de ferramentas
bastante geral para gerenciar paralelismo e recursos, tanto para monoprocessadores
(máquinas com uma CPU) quanto para multiprocessadores (máquinas com várias
CPUs). Um breve resumo desses quatro conceitos é apresentado na Figura 2.1

Nome Descrição
Trabalho Coleção de processos que compartilham cotas e limites
Processo Recipiente de recursos
Thread Entidade escalonada pelo núcleo
Filamento Um thread de peso leve, gerenciado totalmente no espaço
do usuário

Figura2.1 – Conceitos básicos usados para o gerenciamento da CPU e de recursos.

Novos processos são criados usando-se a função CreateProcess da API Win32. essa
função possui dez parâmetros, cada um com muitas opções. Esse projeto é, obviamente,
muito mais complicado que o esquema Linux, no qual a fork não tem parâmetros e exec
tem apenas três (ponteiros para o nome do arquivo a ser executado, o arranjo de
parâmetros da linha de comando – analisada sintaticamente – e as cadeias de caracteres
do ambiente). Grosso modo, os dez parâmetros de CreateProcess são os seguintes:

1. Um ponteiro para o nome do arquivo executável.


2. A própria linha de comandos (não analisada sintaticamente).
3. Um ponteiro para um descritor de segurança para o processo.
4. Um ponteiro para um descritor de segurança para o thread inicial.
5. Um bit indicando se o novo processo herda os manipuladores de seu criador.
6. Diversos sinalizadores (por exemplo, modo de erro, prioridade, depuração,
consoles).
7. Um ponteiro para as cadeias de caracteres do ambiente.
8. Um ponteiro para o nome do novo diretório de trabalho do processo atual.
9. Um ponteiro para uma estrutura que descreve a janela inicial na tela.
10. Um ponteiro para uma estrutura que retorna 18 valores a quem chama.

O Windows 2000 não garante qualquer tipo de hierarquia, seja pai-filho, ou


qualquer outra. Todos os processos são criados igualmente. Contudo, como um dos 18
parâmetros retornados ao processo criador é o manipulador do novo processo, há uma
hierarquia implícita sobre quem tem o manipulador de quem. Todavia, esses
manipuladores não podem ser passados diretamente a outros processos – há uma
maneira adequada de o processo duplicar um manipulador e então passá-lo a outro
processo. Portanto, a hierarquia implícita dos processos pode não ser muito profunda.
Cada processo, no Windows 2000, é criado com um único thread, mas um processo
pode criar mais threads depois. A criação de thread é mais simples que a criação de
processo, pois CreateThread tem apenas seis parâmetros, em vez de dez:

17
1. O descritor opcional de segurança.
2. O tamanho inicial da pilha.
3. O endereço de início.
4. Um parâmetro definido pelo usuário.
5. O estado inicial de um thread (pronto ou bloqueado).
6. O ID do thread

O núcleo faz a criação do thread; portanto, ele sabe tudo o que se passa com os
threads (isto é, eles não são totalmente implementados no espaço do usuário, como é o
caso em alguns outros sistemas).

2.3 – Gerenciamento de Memória

O Windows 2000 tem um sistema de memória virtual extremamente sofisticado. Ele


dispõe de diversas funções Win32 para usar a memória virtual e parte do executivo,
além de mais seis threads do núcleo dedicados a gerenciá-la.
No Windows 2000, todo processo de usuário tem seu próprio espaço de
endereçamento virtual. Os endereços virtuais são de 32 bits de largura; portanto, cada
processo tem 4 GB de espaço de endereçamento virtual. Os 2 GB inferiores menos
cerca de 256 MB estão disponíveis para o código e para os dados dos processos; os 2
GB superiores mapeiam a memória do núcleo de uma maneira protegida. O espaço de
endereçamento virtual é paginado sob demanda, com um tamanho fixo de página (4 KB
no Pentium).
Processo A Processo B Processo C
4GB

Reservatório não paginado Reservatório não paginado Reservatório não paginado


Reservatório paginado Reservatório paginado Reservatório paginado

Tabelas de páginas de A Tabelas de páginas de B Tabelas de páginas de C


Pilhas, dados etc. Pilhas, dados etc. Pilhas, dados etc.
2GB HAL + SO HAL + SO HAL + SO
Dados do sistema Dados do sistema Dados do sistema
Códigos e dados privados Códigos e dados privados Códigos e dados privados
ao processo A ao processo B ao processo C

Os 64 KB do topo e de baixo são válidos


Figura2.2 – O esquema do espaço de endereçamento virtual para três processos de usuário. As
áreas brancas são privadas aos processos. As áreas sombreadas são compartilhadas entre todos os
processos.

O esquema do espaço de endereçamento virtual para três usuários é mostrado na


Figura 2.2 bem simplificadamente. A parte de baixo e a de cima dos 64KB do espaço de
endereçamento virtual de cada processo normalmente não estão mapeadas. Essa escolha

18
foi intencional, visando auxiliar a identificação de erros de programas. Ponteiros
inválidos são, muitas vezes, 0 ou -1, portanto, a tentativa de usá-los no Windows 2000
causa um desvio em vez de gerar uma leitura de lixo ou, pior ainda, uma escrita em um
local incorreto da memória. Entretanto, quando programas antigos do MS-DOS
começam a executar no modo de emulação, eles podem ser mapeados nessa parte. Cada
página virtual pode estar em um de três estados: livre, reservada ou comprometida.
A API Win32 contém diversas funções que permitem a um processo gerenciar
explicitamente sua memória virtual. As mais importantes estão relacionadas na Figura
2.3. Todas elas operam em uma região formada por uma única página ou por uma
seqüência de duas ou mais páginas que são consecutivas no espaço de endereçamento
virtual.

Função API Descrição


Win32
VirtualAlloc Reserva ou compromete uma região
VirtualFree Libera ou descompromete uma região
VirtualProtect Altera a proteção de leitura/escrita/execução de uma região
VirtualQuery Pergunta sobre o estado de uma região
VirtualLock Torna uma região residente em memória
VirtualUnlock Torna a região paginável, de maneira usual
CreateFileMapping Cria um objeto de mapeamento de arquivo e atribui um nome a ele
MapViewOfFile Mapeia (parte de) um arquivo no espaço de endereçamento
UnmapViewOfFile Remove um arquivo mapeado do espaço de endereçamento
OpenFileMapping Abre um objeto de mapeamento de arquivo criado anteriormente

Figura2.3 – Principais funções API Win32 para gerenciamento de memória virtual no


Windows 2000.

2.4 – Entrada/ Saída

O objetivo do sistema de E/S do Windows 2000 é fornecer uma estrutura para lidar,
de modo eficiente, com uma grande variedade de dispositivos de E/S. Entre os
dispositivos atuais de entrada estão os teclados, os mouses, as telas sensíveis a toque, os
joysticks, os digitalizadores de imagens, as câmeras fotográficas, as câmeras de
aquisição de vídeo, os leitores de códigos de barra, os microfones e os ratos de
laboratório. Entre os dispositivos atuais de saída estão os monitores, as impressoras, os
plotters, os sinalizadores sonoros, os gravadores de CD e as placas de som. Entre os
dispositivos de armazenamento estão os discos flexíveis, os discos rígidos IDE e SCSI,
os CD-ROMs, os DVDs, os zip-drives e as unidades de fita. Por fim, outros dispositivos
incluem os relógios, as redes, os telefones e os gravadores de vídeo. Não há dúvida de
que outros dispositivos de E/S serão inventados nos próximos anos; portanto, o
Windows 2000 foi projetado com uma estrutura geral, para que novos dispositivos
possam ser facilmente conectados.
O gerenciador de E/S está bastante relacionado com o gerenciador de plug and play.
A idéia básica por trás do plug and play é a de barramento enumerável. Muitos
barramentos, dentre eles PC Card, PCI, USB, IEEE 1394 e SCSI, foram projetados para

19
que o gerenciador de plug and play pudesse enviar uma requisição a cada slot, pedindo
para que o dispositivo ali alojado se identifique. Uma vez que se descobre o que existe
lá, o gerenciador de plug and play aloca os recursos de hardware, como os níveis de
interrupção, localiza os drivers apropriados e carrega-os na memória. Á medida que
cada um vai sendo carregado, um objeto-driver é criado para ele. Para alguns
barramentos, como o SCSI, a enumeração ocorre somente no momento do boot, mas
para outros barramentos, como o USB e o IEEE 1394, a enumeração pode ocorrer a
qualquer momento, exigindo um contato mais próximo entre o gerenciador de plug and
play, o driver do barramento (que é quem realmente faz a enumeração) e o gerenciador
de E/S.
O gerenciador de E/S está também bastante próximo do gerenciador de energia. O
gerenciador de energia pode deixar o computador em um dentre seis estados, grosso
modo descritos como:

1. Completamente operacional
2. Dorme-1: energia da CPU reduzida, RAM e cachê ligados; desperta
instantaneamente
3. Dorme-2: CPU e RAM ligadas; cachê da CPU desligada; continua executando a
partir do contador de programa atual
4. Dorme-3: CPU e cachê desligados; RAM ligada; reinicia a partir de um
endereço fixo da memória
5. Hiberna: CPU, cache e RAM desligados; reinicia a partir de um arquivo salvo
em disco
6. Desligado: tudo desligado; exige um reinício completo.

Os dispositivos de E/S podem estar também em vários estados de alimentação de


energia. Juntos, o gerenciador de energia e o gerenciador de E/S lidam com o ligamento
e o desligamento dos dispositivos. Perceba que somente se entra no estado 2 até o
estado 6 quando a CPU fica ociosa por um intervalo de tempo mais curto ou mais longo.
O Windows 2000 tem mais de cem APIs diferentes para uma grande variedade de
dispositivos de E/S, entre mouse, placas de som, telefones etc. Provavelmente o mais
importante seja o sistema de saída gráfica, para o qual há milhares de chamadas para
API Win32. Um pequeno sumário das categorias é dado pela Figura 2.4.
As chamadas Win32 existem para criar, destruir e gerenciar janelas. As janelas têm
um grande número de estilos e opções que podem ser especificados, incluindo títulos,
bordas, cores, tamanhos e barras de rolagens. As janelas podem ser fixas ou móveis, de
tamanho constante ou redimensionáveis. Suas propriedades são passíveis de consulta e
mensagens podem ser enviadas a elas.

Grupo da API Descrição


Gerenciamento de janelas Cria, destrói e gerencia janelas
Menus Cria, destrói e adiciona menus e barras de menus
Caixas de diálogo Faz aparecer uma caixa de diálogo e coleta informações
Pintura e desenho Mostra pontos, linhas e figuras geométricas
Texto Mostra texto em alguma fonte, tamanho e cor
Bitmaps e ícones Exibe bitmaps e ícones na tela
Cores e paletas Gerencia o conjunto de cores disponíveis
Áreas de transferências Passa informação de uma aplicação para outra
Entradas Adquire informação do mouse e do teclado

Figura2.4 – Algumas categorias de chamadas API Win32.

20
2.5 – Sistema de Arquivos

O Windows 2000 suporta vários sistemas de arquivos, sendo os mais importantes o


FAT-16, o FAT-32 e o NTFS (NT File System – Sistema de Arquivos do NT). O FAT-16
é o sistema de arquivos do antigo MS-DOS. Ele usa endereços de disco de 16 bits, o que
o limita a partições de disco não maiores que 2GB. O FAT-32 usa endereços de disco de
32 bits e suporta partições de disco de até 2TB. O NTFS é um novo sistema de arquivos
desenvolvido especificamente para o Windows NT e trazido para o Windows 2000. Ele
usa endereços de disco de 64 bits e pode suportar partições de disco de até 2^64 bytes,
embora outros fatores a limitem a tamanhos menores. O Windows 2000 também suporte
sistemas de arquivos apenas para leitura para CD-ROMs e DVDs. É possível que o
mesmo sistema em execução tenha acesso a múltiplos tipos de sistemas de arquivos
disponíveis simultaneamente.
Os nomes de arquivo no NTFS são limitados a 255 caracteres; os caminhos desde a
raiz são limitados a 32767 caracteres. Os nomes de arquivos estão em Unicode,
permitindo que as pessoas de países que não usam o alfabeto latino escrevam nomes de
arquivos em seu idioma nativo. Por exemplo, λξπζ é um nome de arquivo perfeitamente
legal. O NTFS diferencia totalmente os nomes com letras maiúsculas daqueles com
minúsculas. Infelizmente, a API Win32 não diferencia totalmente as maiúsculas de
minúsculas para nomes de arquivos nem para nomes de diretórios; desse modo essa
vantagem é perdida em programas que se restrinjam a usar o Win32.
Um arquivo NTFS não é apenas uma seqüência linear de bytes, como nos arquivos
FAT-32 e Unix. Em vez disso, um arquivo é constituído de vários atributos, cada qual
representado por um fluxo de bytes. A maioria dos arquivos tem alguns fluxos curtos,
com nome de arquivo, seu ID de objeto de 64 bits, mais um fluxo longo com os dados.
Contudo, um arquivo pode ser também dois ou mais fluxos de dados. Cada fluxo tem
um nome formado pelo nome do arquivo, seguido de dois pontos e o nome do fluxo,
como foo:stream1. cada fluxo tem seu próprio tamanho e pode ser impedido,
independentemente de todos os outros fluxos. A idéia de múltiplos fluxos em um
arquivo foi trazida do Apple Macintosh, no qual os arquivos têm dois fluxos, os dados e
os recursos. Esse conceito foi incorporado ao NTFS para permitir que um servidor
NTFS seja capaz de servir clientes Macintosh.
As principais funções API Win32 para gerenciamentos de arquivos estão
apresentadas na Figura 2.5. Elas são, na verdade, muitas mais, porém as funções
mostradas na figura dão uma idéia razoável das básicas.

21
Função da API Win32 Unix Descrição
CreateFile Open Cria um arquivo ou abre um existente
DeleteFile Unlink Destrói um arquivo existente
CloseHandle Close Fecha um arquivo
ReadFile Read Lê dados de um arquivo
WriteFile write Escreve dados em um arquivo
SetFilePointer Lseek Atribui ao ponteiro de arquivo um local específico no
arquivo
GetFileAttributes Stat Retorna as propriedades do arquivo
LockFile Fcntl Impede uma região do arquivo de implementar exclusão
mútua
UnlockFile fcntl Desimpede uma região do arquivo anteriormente
impedida

Figura2.5 – Principais funções da API Win32 para E/S de arquivos.

2.6 – Segurança

O NT foi projetado para cumprir as determinações de segurança C2 do


Departamento de Defesa dos Estados Unidos. Esse padrão exige que os sistemas
operacionais tenham certas propriedades para serem classificados como seguros o
suficiente para certos tipos de atividades militares. Embora o Windows 2000 não tenha
sido especificamente projetado para o cumprimento das determinações C2, ele herda
várias das propriedades de segurança do NT. Entre elas estão:

1. Conexão de segurança com medidas contra trapaças


2. Controles de acesso discricionário
3. Controles de acesso privilegiado
4. Proteção do espaço de endereçamento por processo
5. Novas páginas devem ser zeradas antes de serem mapeadas
6. Auditoria de segurança

Todo usuário do Windows 2000 é identificado por um SID (security id –


identificador de segurança). Os SIDs são números binários com um pequeno cabeçalho
seguido por um componente longo e aleatório. A intenção é que cada SID seja único em
todo o mundo. Quando um usuário inicia um processo, o processo e seus threads
executam sob o SID do usuário. A maior parte do sistema de segurança destina-se a
assegurar que cada objeto possa ser acessado somente pelos threads com SIDs
autorizados.
Cada processo tem uma ficha de acesso que especifica seu SID e suas propriedades.
Essa ficha é normalmente atribuída no momento de acesso ao sistema, pelo winlogon, e
é mostrada na Figura 2.6; contudo, os processos devem chamar GetTokenInformation
para obter essa informação, pois, no futuro, ela poderá mudar. O cabeçalho contém
algumas informações administrativas. O campo de validade pode indicar quando a ficha
deixa de ser válida, mas atualmente ele não está sendo utilizado.

22
Cabeçalho Validade Grupos CACL SID do SID do SIDs Privilégios
inicial usuário grupo restritos

Figura2.6 – Estrutura de uma ficha de acesso.

A maioria dos mecanismos de controle de acesso do Windows 2000 é baseada em


descritores de segurança. O padrão usual é que, quando um processo cria um objeto, ele
fornece um descritor de segurança como um dor parâmetros para CreateProcess,
CreateFile ou para outra chamada de criação de um objeto. Esse descritor de segurança
torna-se então o descritor de segurança associado ao objeto. Se nenhum descritor de
segurança for fornecido na chamada de criação do objeto, será usada a configuração
padrão de segurança da ficha de acesso de quem fez a chamada (ver figura 2.6).
Muitas das chamadas de segurança da API Win32 relacionam-se com o
gerenciamento dos descritores de segurança. As chamadas mais importantes são
apresentadas na Figura 2.7.

Função API Win32 Descrição


InitializeSecurityDescriptor Prepara um novo descritor de segurança para ser usado
LookupAccountSid Busca o SID para um dado nome de usuário
SetSecurityDescriptorOwner Entra com o SID do dono no descritor de segurança
setSecurityDescriptorGroup Entra com o SID do grupo no descritor de segurança
InitializeAcl Inicia uma DACL ou uma SACL
AddAccessAllowedAce Adiciona um novo ACE a uma DACL ou SACL
permitindo o acesso
AddAccessDeniedAce Adiciona um novo ACE a uma DACL ou SACL negando
o acesso
DeleteAce Remove um ACE de uma DACL ou SACL
SetSecurityDescriptorDacl Anexa uma DACL a um descritor de segurança

Figura2.7 – As principais funções da API Win32 para segurança.

23
3. Referências
[1] TANEMBAUM, A.S. Sistemas Operacionais Modernos. 2 edição.
Prentice Hall.2003.
[2] TANEMBAUM, A.S. Redes de Computadores. 4 edição. Editora
Campus.2003.
[3] Wikipedia. Disponível por www em http://www.wikipedia.com
(28/04/06).
[4] Guia do Hardware. Disponível por www em
http://www.guiadohardware.net
(30/04/2006).

24