SMB/CIFS internamente

Resumindo o SMB/CIFS é um protocolo de redes que permite o compartilhamento de arquivos através dos nós de uma rede. O protocolo é baseado em um design do cliente onde este envia pacotes de requisições ao servidor, o servidor por sua vez envia pacotes de resposta ao cliente. Cada pacote que é enviado contêm um cabeçalho padrão e mais dois campos de tamanho variável que são utilizados para informações específicas do pacote. Os pacotes também possuem um campo de comando que indica o propósito do pacote. Campos de comando comum indicam se o pacote é de login, abertura de arquivo, leitura de arquivo ou escrita de arquivo.

Para termos um entendimento mais aprofundado do protocolo devemos estudar três seções detalhadas do SMB/CIFS que serão apresetandas mais abaixo. A primeira parte cobre as mais importantes propriedades do protocolo. A segunda dá uma introdução no pacote padrão de cabeçalho e ultima ilustra duas típicas sequências de pacotes: logando no servidor e abertura/leitura de arquivo.

Propriedades do protocolo

Cliente/servidor + requisição/resposta: Como mencionado acima a arquitetura do SMB/CIFS é baseada no cliente enviando requisições e o servidor respondendo a cada uma das requisições enviadas. O protocolo é capaz de suportar múltiplas requisições. O que é feito através do uso de uma id multiplexada (MID). O cliente assegura que cada requisição que é enviada ao servidor possui um único MID. Quando o servidor responde a uma determinada requisição a resposta contêm o mesmo MID. Dessa forma, múltiplas requisições podem ser enviadas ao servidor e o cliente simplesmente compara o MID da resposta com o MID gerado para saber a qual requisição aquela resposta esta se referindo.

Baseado em comandos: Cada pacote contêm um octeto para o campo de comando. Respostas ao cliente sempre possuem o mesmo código de comando do pacote de requisição.

Dialetos/negociação: Existem várias versões do protocolo SMB/CIFS desde sua criação nos anos 80. Cada versão do protocolo é referida como um dialeto é a este dialeto é associado uma string para indentificá-lo como por exemplo "PC NETWORK PROGRAM 1.0" ou "NT LM 0.12". Quando um cliente deseja acessar arquivos num servidor remoto, o primeiro pacote SMB/CIFS que é enviado é o pacote de negociação de protocolo. Neste pacote o cliente lista todas as strings de dialeto que é capaz de entender, no pacote de resposta o servidor indica com qual dialeto ele deseja se comunicar ou se o servidor não entende qualquer dialeto listado pelo cliente. Desta maneira o cliente e o servidor podem negociar qual dialeto usar para cada sessão particular de SMB/CIFS.

Usuário/compartilhamento - níveis de segurança: Um compartilhamento é uma entidade do servidor (tipicamente uma pasta de arquivos ou uma impressora) que é marcada como disponível para os clientes para o compartilhamento na rede. A restrição de acesso para o compartilhamento é feita com um dos seguintes métodos:

  1. níveis de segurança do usuário, utilizado em Windows NT e Windows 2000;
  2. níveis de segurança do compartilhamento

Encriptação: Para ambos os métodos mencionados acima a senha deve ser enviada ao servidor num formato encriptado. Existem dois métodos de encriptação utilizados, o estilo NT e o antigo estilo LAN Manager. Os dois usam autenticação challenge-response onde o servidor manda uma string aleatória e espera uma resposta que prove que o cliente saiba a string enviada e a senha do usuário

Command batching: Muitos pacotes SMB/CIFS são capazes de "cozinhar" outros pacotes SMB/CIFS para reduzir a latência de resposta e melhorar e utilização da banda da rede. Esta técnica é conhecida como ANDX batching.

Travamento oportunístico(Opportunistic locking): Quando um pacote SMB/CIFS especifica uma abertura de arquivo um oplock pode ser requisitado. Se garantido pelo servido o oplock indica ao cliente que nenhuma outra entidade esta acessando tal arquivo. Isto permite ao cliente fazer modificações no arquivo sem ter que escreve-las no servidor imediatamente.


Cabeçalho SMB/CIFS

Todos as requisições e respostas SMB/CIFS possuem o seguinte template de cabeçalho apresentado abaixo.

Cabeçalho: O início de cada pacote SMB/CIFS contêm um cabeçalho de 4 octetos. O primeiro octeto é 0xFF seguido da representação ASCII das letras ´S´, ´M´ e ´B´.

Command: O campo de comando contêm um código de 1 octeto indicando o tipo de pacote. Alguns exemplos: SMB_COM_READ_ANDX7 (0x2e), SMB_COM_TREE_CONNECT (0x70) e SMB_COM_NEGOTIATE (0x72)

Error class O servidor indica se uma requisição específica foi recebida com este campo. Tipicamente o campo é zero indicando o sucess. Se for um número diferente de zero o campo indentifica a classe de erro, quando seta este campo pode ter os seguinte valores:

  1. ERRDOS (0x01) – Erro é do núcleo do conjunto de instruções do sistema operacional DOS
  2. ERRSRV (0x02) – Erro é gerado pelo gerenciador de arquivos de rede do servidor
  3. ERRHRD (0x03) – Erro no hardware
  4. ERRCMD (0xFF) – O comando não estava no formato 'SMB'

Error code: Este campo de 16 octetos indica o tipo de erro que ocorreu. Esta tipicamente setado em zero indicando que não houve erro. Se setado este número em conjunto com o error class define o erro ocorrido. Alguns destes erros são "bad password" ou "file does not exist". Assim como o campo error class este campo somente é setado pelos servidores nos pacotes de resposta às requisições.

Flags: A maioria dos oito octetos neste campo especificam opções particulares. A não ser o bit 3 que quando setado todos os caminhos devem ser tratados sem se preocupar se os caracteres são maísculos ou minúsculos

Flags2: Mais opções. Alguns bits úteis:

  1. bit 0 - se setado o servidor poderá retornar arquivos com nomes longos
  2. bit 6 - se setado indica que qualquer caminho na requisição pode ser um arquivo com nome longo
  3. bit 16 - se setado indica que as strings no pacote estão codificadas com UNICODE.

Pad/security signature: Tipicamente setado em zero.

Tree ID (TID): O TID é um número de 2 octetos para identificar que recurso este pacote em particular esta se referindo. Quando os pacotes são trocados, o que não tem nada a ver com um recurso este campo não faz sentido e é ignorado. Se um cliente deseja receber acesso a um recurso o cliente envia um pacote com o campo de comando setado em SMB_COM_TREE_CONNECT_ANDX. Neste pacote o nome do compartilhamento ou a impressora é especificado (ex. \\server\dir). O servidor então verifica se o recurso existe e se o cliente possue acesso e então libera o compartilhamento enviando uma resposta de sucesso. Neste pacote o servidor irá setar qualquer número no campo TID. A partir daí o cliente quando quiser fazer requisições se referindo a esse compartilhamente utilizará o TID recebido anteriormente.

Process ID (PID): O PID é um número de 2 octetos que identifica que processo está fazendo a requisição no cliente. O servidor utiliza este número para checar problemas de concorrência (tipicamente para garantir que arquivos não serão corrompidos por processos concorrentes)

User ID (UID): O UID é um número de 2 octetos para identificar que usuário que está fazendo as requisições na máquina cliente. O cliente deve obter um UID do servidor enviando a este uma requisição de setup de sessão contendo o nome do usuário e sua senha. Passada a verificação de nome de usuário/senha o servidor responde a requisição incluíndo na resposta um UID gerado. O cliente então utiliza este UID em todas as futuras requisições. Se alguma das requisições dos clientes esbarrar em permissões de arquivos/ impressoras, o servido irá verificar se o UID da requisição possue as permissões necessárias para acessar tal recurso.

Multiplex ID (MID): O MID é um número de 2 octetos utilizados para gerenciar múltiplas requisições. Sempre que um cliente enviar um pacote o servidor checa o MID para ver se há alguma requisição pendente.

WordCount e parameter words: Os pacotes podem usar estes dois campos para armazenar dados específicos dos comandos. O template acima não suporta todos os possíveis tipos de dados para um pacote SMB/CIFS. Para remediar este problema o campo parameter words foi criado com tamanho variável. O campo wordcaount especifica quantas palavras de 2 octectos o campo parameter words irá conter. Dessa forma cada pacote pode se ajustar ao tamanho necessário para transmitir dados de seu comando específico.

ByteCount e buffer: Estes campos são muito similares aos anteriores wordcount e parameter words. Eles irão armazenar uma quantidade de dados variável específica numa base por pacote.

Voltar