O que poderia ser uma maneira de recuperar uma lista de todos os caracteres em uma determinada classe de personagem (como blank
, alpha
, digit
...) no local atual.
Por exemplo,
LC_ALL=en_GB.UTF-8 that-command blank
idealmente, no meu sistema Debian, exibiria algo como:
09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE
e1 9a 80 U+1680 OGHAM SPACE MARK
e1 a0 8e U+180E MONGOLIAN VOWEL SEPARATOR
e2 80 80 U+2000 EN QUAD
e2 80 81 U+2001 EM QUAD
e2 80 82 U+2002 EN SPACE
e2 80 83 U+2003 EM SPACE
e2 80 84 U+2004 THREE-PER-EM SPACE
e2 80 85 U+2005 FOUR-PER-EM SPACE
e2 80 86 U+2006 SIX-PER-EM SPACE
e2 80 88 U+2008 PUNCTUATION SPACE
e2 80 89 U+2009 THIN SPACE
e2 80 8a U+200A HAIR SPACE
e2 81 9f U+205F MEDIUM MATHEMATICAL SPACE
e3 80 80 U+3000 IDEOGRAPHIC SPACE
E na localidade C poderia exibir algo como:
09 U+0009 HORIZONTAL TAB
20 U+0020 SPACE
Ou seja, a representação do caractere no código do idioma em termos de matrizes de bytes (como UTF-8 no primeiro exemplo e byte único no segundo), o ponto de código do caractere Unicode equivalente e uma descrição.
Contexto
(editar) Agora que a vulnerabilidade foi corrigida e divulgada há muito tempo, posso adicionar um pouco de contexto.
Fiz essa pergunta no momento em que estava investigando o CVE 2014-0475 . glibc
tinha um bug, pois permitia que o usuário usasse códigos de LC_ALL=../../../../tmp/evil-locale
idioma assim resolvidos em relação ao caminho de pesquisa de código de idioma padrão do sistema e, portanto, permitia usar qualquer arquivo como definição de código de idioma.
Eu poderia criar uma localidade não autorizada, por exemplo, com um único byte por conjunto de caracteres de caracteres, onde a maioria dos caracteres s
, exceto h
alguns, eram considerados espaços em branco e isso seria bash
executado sh
ao analisar um /etc/bash.bashrc
arquivo Debian típico (e que poderia ser usado para obter acesso ao shell em um git
o servidor de hospedagem, por exemplo, fornecido bash
é usado como o shell de login do git
usuário do servidor e que o ssh
servidor aceita LC_*
/ LANG
variáveis e que o invasor pode fazer upload de arquivos para o servidor).
Agora, se eu encontrasse uma LC_CTYPE
(definição compilada de localidade) em /tmp/evil
, como descobriria que era desonesta e de que maneira.
Portanto, meu objetivo é descompilar essas definições de localidade e, se não, pelo menos saber qual caractere (junto com sua codificação) está em uma determinada classe de caracteres.
Então, com isso em mente:
- Soluções que analisam os arquivos de origem para o código do idioma (as definições de código do idioma como as
/usr/share/i18n/locale
do Debian) não são úteis no meu caso. - As propriedades de caracteres Unicode são irrelevantes. Eu só me importo com o que o local diz. Em um sistema Debian, mesmo entre dois locais do sistema UTF-8, sem falar nos invasores, a lista de caracteres em uma classe pode ser diferente.
- Ferramentas como
recode
,python
ouperl
que faça o byte / multi-byte de / para a conversão de caracteres não podem ser usados como eles podem (e na prática não) fazer a conversão de uma forma diferente da localidade.
fonte
/usr/share/i18n/locales/i18n
... o qual, é claro, vem em grande parte do banco de dados de caracteres Unicode. Claro, seria bom ter um comandolocale
(pelo menos a GNU) recupera muitas das informações armazenadas em muitas das categorias, coisas que não são as mais importantes em LC_CTYPE e LC_COLLATE. Gostaria de saber se existe uma API oculta para recuperar essas informações ou descompilar as informações de localidade.recode
euconv
pode dar a você o que você diz estar procurando. Possivelmente até mesmoluit
eod
eu acho ...perl
, eu acho.LC_CTYPE
com apenasod -A n -t c <LC_CTYPE | tsort
Provavelmente você já tentou fazê-lo já, mas eu nunca tinha ouvido falar dele antes e eu estava lendoinfo
e lembrou-me deste - e parece trabalho. Há também,ptx
mas acho que é menos relevante. De qualquer forma, se você ainda não experimentou e decide fazê-lo - aviso justo -, é preciso um pouco de paciência. VocêRespostas:
POSSÍVEL SOLUÇÃO FINAL
Então, eu peguei todas as informações abaixo e criei isso:
NOTA :
Eu uso
od
como o filtro final acima como preferência e porque sei que não vou trabalhar com caracteres de vários bytes, com os quais ele não lidará corretamente.recode u2..dump
ambos irão gerar uma saída mais semelhante à especificada na pergunta e manipularão caracteres largos corretamente.RESULTADO
API DO PROGRAMADOR
Como demonstro abaixo,
recode
você fornecerá seu mapa de caracteres completo. De acordo com o manual, ele faz isso de acordo com o valor atual daDEFAULT_CHARSET
variável de ambiente ou, na sua falta, opera exatamente como você especifica:Também digno de nota
recode
é que é uma API :#include <recode.h>
Para comparação internacionalmente amigável de strings Os padrões
POSIX
eC
definem astrcoll()
função:Aqui está um exemplo localizado separadamente de seu uso:
Com relação às
POSIX
classes de caracteres, você já observou que usou aC
API para encontrá-las. Para caracteres e classes unicode, você pode usar charsetrecode's
dump-with-names para obter a saída desejada. De seu manual novamente :Usando uma sintaxe semelhante à acima combinada com seu conjunto de dados de teste incluído, posso obter meu próprio mapa de caracteres com:
RESULTADO
Mas para caracteres comuns,
recode
aparentemente não é necessário. Isso deve fornecer chars nomeados para tudo no conjunto de 128 bytes:RESULTADO
Obviamente, apenas 128 bytes são representados, mas isso ocorre porque meu local, utf-8 charmaps ou não, usa o conjunto de caracteres ASCII e nada mais. Então é tudo que eu recebo. Se eu o executasse sem
luit
filtrá-lo,od
o reverteria e imprimiria o mesmo mapa novamente até\0400.
Existem dois grandes problemas com o método acima. Primeiro, há a ordem de intercalação do sistema - para localidades não ASCII, os valores de mordida para os conjuntos de caracteres não são simplesmente in
seq
uêncios, o que, como eu acho, é provavelmente o núcleo do problema que você está tentando resolver.Bem, a
tr's man
página do GNU afirma que expandirá as[:upper:]
[:lower:]
classes em ordem - mas isso não é muito.Eu imagino que alguma solução pesada possa ser implementada,
sort
mas isso seria uma ferramenta bastante difícil para uma API de programação de back-end.recode
fará isso corretamente, mas você não parecia muito apaixonado pelo programa outro dia. Talvez as edições de hoje tenham uma luz mais amigável ou talvez não.O GNU também oferece a
gettext
biblioteca de funções e parece capaz de resolver esse problema pelo menos noLC_MESSAGES
contexto:Você também pode usar categorias de caracteres Unicode nativas , que são independentes do idioma e renunciam completamente às classes POSIX, ou talvez chamar o primeiro para fornecer informações suficientes para definir o último.
O mesmo site que forneceu as informações acima também discute
Tcl
a implementação de regex compatível com POSIX, que pode ser outra maneira de atingir seu objetivo.E, por último, entre as soluções, sugerirei que você possa interrogar o
LC_COLLATE
arquivo em si para obter o mapa de caracteres completo e em ordem do sistema. Isso pode não parecer fácil, mas obtive algum sucesso com o seguinte, depois de compilá-lolocaledef
como demonstrado abaixo:É, reconhecidamente, atualmente falho, mas espero que demonstre a possibilidade pelo menos.
NO PRIMEIRO BLUSH
Realmente não parecia muito, mas então comecei a perceber
copy
comandos em toda a lista. O arquivo acima parececopy
em "en_US", por exemplo, e outro realmente grande que parece que todos compartilham até certo pontoiso_14651_t1_common
.É bem grande:
Aqui está a introdução para
/usr/share/i18n/locales/POSIX
:...
Você pode fazer
grep
isso, é claro, mas você pode apenas:Em vez de. Você obteria algo como isto:
... E MAIS
Também há
luit
umpty
dispositivo de tradução UTF-8 terminal, acho que funciona como intermediário para XTerms sem suporte a UTF-8. Ele lida com muitas opções - como registrar todos os bytes convertidos em um arquivo ou-c
como um|pipe
filtro simples .Eu nunca percebi que havia tanto nisso - os locais e os mapas de personagens e tudo isso. Aparentemente, isso é um grande negócio, mas acho que tudo acontece nos bastidores. Existem - pelo menos no meu sistema - algumas centenas de
man 3
resultados relacionados para pesquisas relacionadas ao código do idioma.E também há:
Isso continuará por muito tempo.
As
Xlib
funções lidam com isso o tempo todo -luit
faz parte desse pacote.As
Tcl_uni...
funções também podem ser úteis.apenas um pouco de
<tab>
conclusão eman
pesquisas e aprendi bastante sobre esse assunto.Com
localedef
- você pode compilarlocales
no seuI18N
diretório. A saída é descolada e não é extraordinariamente útil - não é como a decharmaps
todo -, mas você pode obter o formato bruto exatamente como especificou acima, como eu fiz:Então
od
você pode ler - bytes e strings:Embora esteja muito longe de ganhar um concurso de beleza, essa é uma saída utilizável. E
od
é tão configurável quanto você deseja que seja, é claro.Acho que também esqueci disso:
Provavelmente me esqueci deles porque não consegui fazê-los funcionar. Eu nunca uso
Perl
e não sei como carregar um módulo corretamente, eu acho. Mas asman
páginas parecem bem legais. De qualquer forma, algo me diz que você encontrará chamar um módulo Perl pelo menos um pouco menos difícil do que eu. E, novamente, eles já estavam no meu computador - e eu nunca uso o Perl. Também há algunsI18N
que eu percorri melancolicamente sabendo muito bem que também não os faria funcionar.fonte
i18n
) que podem ou não ter sido usados para gerar o código do idioma que estou usando atualmente. As informações da localidade provavelmente são provenientes de/usr/lib/locale/locale-archive
ou/some/dir/LC_CTYPE
, e essa é a parte relevante para a minha localidade armazenada nos arquivos que busco.LC_STUFF
o arquivo do arquivolocaledef
- ele também faz isso. Eu posso demonstrar isso também, eu acho. Você também pode ver isso e praticamente tudo o resto comstrings
ouod
ou qualquer outro. Eu fiz de qualquer maneira. Mas pela maneira - ocharmaps
são o youre local usando atualmente - elocaledef
apresentará um relatório sobre isso também. Também é o querecode
faz também.od,
recode
,uconv
e o resto. Mas foi um erro meu - não é issolocaledef
que extrai, érecode
essa vontade. Você precisa dar uma olhadainfo recode
- e além dorecode
comando table que apareço, existe praticamente a mesma coisa - e ele lidará com as coisas da mesma maneira, eu acho. Ele não apenas tira seu conjunto de caracteres do nada. De qualquer forma, eu tinha grandes esperanças para essesperl
módulos - você experimentou?iswblank(3)
para todos os valores possíveis de caracteres.Nos sistemas GNU, FreeBSD ou Solaris, pelo menos, essa abordagem de força bruta funciona:
Enquanto por C / POSIX,
wchar_t
é um tipo opaco que não tem relação com Unicode e é garantido apenas para cobrir todos os caracteres suportados pelo código do idioma do sistema, na prática, na maioria dos sistemas que suportam Unicode, os valores correspondem aos pontos de código Unicode e as definições de localidade são baseadas em Unicode.O Unicode deve ser um superconjunto de todos os conjuntos de caracteres conhecidos; portanto, fazer um loop sobre todos os pontos de código válidos no Unicode (0 a 0xD7FF e 0xE000 a 0x10FFFF) deve listar pelo menos todos os caracteres suportados por um determinado conjunto de caracteres.
Aqui, estamos usando a API padrão do código de idioma do sistema para verificar quais são de um determinado tipo e convertê-lo em seu formato codificado na codificação do código de idioma. Usamos
perl
e seucharnames
módulo apenas para obter o nome de um determinado ponto de código Unicode.Em localidades que usam codificações com estado como ISO-2022-JP, garantimos que o formulário codificado seja exibido a partir de um estado inicial padrão.
Eu não encontrei um sistema que tivesse instalado localidades com uma codificação de caracteres com estado, mas pelo menos nos sistemas GNU, é possível gerar alguns para que um local não autorizado possa ser criado (e pelo menos as ferramentas GNU não funcionam corretamente naquelas localidades). Por exemplo, com um código de idioma personalizado que usa ISO-2022-JP com um código de
ja_JP
idioma normal , recebo:Compare com:
No ISO-2022-JP, a
1B 24 42
sequência (\e$B
) muda de ASCII para um estado em que os caracteres são expressos como 2 (7 bits) bytes (aqui 21 21 para esse ESPAÇO IDEOGRÁFICO). Enquanto no EUCJP, são os mesmos bytes, mas a troca de estado é feita com o lançamento do oitavo bit (A1 = 21 | 0x80
), o que o torna mais sem estado.Isso significa que nessas codificações com estado, existem várias maneiras de escrever um determinado caractere (por exemplo, inserindo várias daquelas seqüências de comutação de estado ), e a sequência mostrada pelo código acima é apenas uma delas (a canônica de um inicial). Estado padrão).
Enquanto para uma localidade normal, caracteres não podem estar fora 0..0xD7FF, 0xE000..0x10FFFF, para uma desonestos locale, qualquer caractere no intervalo suportado pelo wchar_t pode ser. Por exemplo, eu poderia criar um local onde caracteres U + DCBA ou U + 12345678 (ou seriam caracteres se permitidos) são espaços em branco . É por isso que você deseja compilar esse código
-D SUPPORT_ROGUE_LOCALES
para cobri-lo, embora isso signifique que leva muito mais tempo para verificar a lista inteira.Eu não poderia usar a solução da @ mikeserv, pois
recode
usa suas próprias conversões, não é mais mantida e suporta apenas caracteres Unicode de até 0xFFFF, e o GNUtr
pelo menos não funciona com caracteres de vários bytes.Eu não poderia usar o @ ChrisDown's, pois
python
não possui interfaces para as classes de caracteres POSIX.Eu tentei o Perl, mas é falso os pontos de código entre 128 e 255 para locais de vários bytes que não sejam o UTF-8 e não usa as bibliotecas de conversão do sistema.
fonte
combining
ecombining_level3
(viz.iswctype(i, wctype("combining"))
)