diff --git a/.travis.yml b/.travis.yml index 62f8ed5..f574611 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ env: - OS=ubuntu DIST=trusty - OS=ubuntu DIST=precise - OS=ubuntu DIST=xenial - - OS=ubuntu DIST=yakkety - OS=debian DIST=jessie - OS=debian DIST=wheezy - OS=debian DIST=stretch diff --git a/Makefile b/Makefile index 96419b1..4c00d50 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS += -Wall -g -std=gnu99 -O3 LDFLAGS += -lssh NAME = cbrutekrag -SRCS = cbrutekrag.c +SRCS = cbrutekrag.c log.c str.c wordlist.c OBJS = $(SRCS:.c=.o) all: $(NAME) diff --git a/README.md b/README.md index 3b8515e..5499d3c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![license](https://img.shields.io/github/license/jorge-matricali/cbrutekrag.svg)](https://jorge-matricali.mit-license.org/2017) [![GitHub contributors](https://img.shields.io/github/contributors/jorge-matricali/cbrutekrag.svg)](https://github.com/jorge-matricali/cbrutekrag/graphs/contributors) +[![license](https://img.shields.io/github/license/jorge-matricali/cbrutekrag.svg)](https://jorge-matricali.mit-license.org/2014) [![GitHub contributors](https://img.shields.io/github/contributors/jorge-matricali/cbrutekrag.svg)](https://github.com/jorge-matricali/cbrutekrag/graphs/contributors) [![Build Status](https://travis-ci.org/jorge-matricali/cbrutekrag.svg?branch=master)](https://travis-ci.org/jorge-matricali/cbrutekrag) # cbrutekrag Penetration tests on SSH servers using dictionary attacks. Written in _C_. @@ -24,24 +24,30 @@ make install Then you can do ```bash $ cbrutekrag -h - _ _ _ | | | | | | ___ | |__ _ __ _ _| |_ ___| | ___ __ __ _ __ _ / __|| '_ \| '__| | | | __/ _ \ |/ / '__/ _` |/ _` | | (__ | |_) | | | |_| | || __/ <| | | (_| | (_| | \___||_.__/|_| \__,_|\__\___|_|\_\_| \__,_|\__, | - OpenSSH Brute force tool 0.2.1 __/ | - (c) Copyright 2017 Jorge Matricali |___/ + OpenSSH Brute force tool 0.3.0 __/ | + (c) Copyright 2014-2018 Jorge Matricali |___/ usage: ./cbrutekrag [-h] [-v] [-T TARGETS.lst] [-C combinations.lst] - [-t THREADS] [-o OUTPUT.txt] + [-t THREADS] [-o OUTPUT.txt] + + -h This help + -v Verbose mode + -T Targets file + -C Username and password file + -t Max threads + -o Output log file ``` ## Example usages ```bash # Many targets, many pre-made combinations of user and password separated by space. -brutekrag -T targets.txt -C combinations.txt -o result.log +cbrutekrag -T targets.txt -C combinations.txt -o result.log ``` diff --git a/cbrutekrag.c b/cbrutekrag.c index a67c0d0..fe13a04 100644 --- a/cbrutekrag.c +++ b/cbrutekrag.c @@ -19,91 +19,22 @@ 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. */ + +#include +#include +#include +#include +#include + #include "cbrutekrag.h" +#include "log.h" +#include "str.h" +#include "wordlist.h" int g_verbose = 0; int g_timeout = 3; char *g_blankpass_placeholder = "$BLANKPASS"; -char** str_split(char* a_str, const char a_delim) -{ - char** result = 0; - size_t count = 0; - char* tmp = a_str; - char* last_comma = 0; - char delim[2]; - delim[0] = a_delim; - delim[1] = 0; - - /* Count how many elements will be extracted. */ - while (*tmp) { - if (a_delim == *tmp) { - count++; - last_comma = tmp; - } - tmp++; - } - - /* Add space for trailing token. */ - count += last_comma < (a_str + strlen(a_str) - 1); - - /* Add space for terminating null string so caller - knows where the list of returned strings ends. */ - count++; - - result = malloc(sizeof(char*) * count); - - if (result) { - size_t idx = 0; - char* token = strtok(a_str, delim); - - while (token) { - assert(idx < count); - *(result + idx++) = strdup(token); - token = strtok(0, delim); - } - assert(idx == count - 1); - *(result + idx) = 0; - } - - return result; -} - -void print_error(const char *format, ...) -{ - va_list arg; - fprintf(stderr, "\033[91m"); - va_start(arg, format); - vfprintf(stderr, format, arg); - va_end (arg); - fprintf(stderr, "\033[0m\n"); -} - -void print_debug(const char *format, ...) -{ - if (g_verbose != 1) { - return; - } - va_list arg; - fprintf(stderr, "\033[37m"); - va_start(arg, format); - vfprintf(stderr, format, arg); - va_end (arg); - fprintf(stderr, "\033[0m\n"); -} - -const char *str_repeat(char *str, size_t times) -{ - if (times < 1) return NULL; - char *ret = malloc(sizeof(str) * times + 1); - if (ret == NULL) return NULL; - strcpy(ret, str); - while (--times > 0) { - strcat(ret, str); - } - return ret; -} - void update_progress(int count, int total, char* suffix, int bar_len) { if (g_verbose) { @@ -126,7 +57,8 @@ void update_progress(int count, int total, char* suffix, int bar_len) if (bar_len > 0) { printf("\033[37m["); if (filled_len > 0) printf("\033[32m%s", str_repeat("=", filled_len)); - printf("\033[37m%s\033[37m]\033[0m", str_repeat("-", empty_len)); + if (empty_len > 0) printf("\033[37m%s", str_repeat("-", empty_len)); + printf("\033[37m]\033[0m"); } if (max_cols > 60) printf(" %.2f%% %s", percents, suffix); if (fill > 0) printf("%s\r", str_repeat(" ", fill)); @@ -142,8 +74,8 @@ void print_banner() "\033[37m / __|\033[92m| '_ \\| '__| | | | __/ _ \\ |/ / '__/ _` |/ _` |\n" "\033[37m | (__ \033[92m| |_) | | | |_| | || __/ <| | | (_| | (_| |\n" "\033[37m \\___|\033[92m|_.__/|_| \\__,_|\\__\\___|_|\\_\\_| \\__,_|\\__, |\n" - " \033[0m\033[1mOpenSSH Brute force tool 0.2.1\033[92m __/ |\n" - " \033[0m(c) Copyright 2017 Jorge Matricali\033[92m |___/\033[0m\n\n" + " \033[0m\033[1mOpenSSH Brute force tool 0.3.0\033[0m\033[92m __/ |\n" + " \033[0m(c) Copyright 2014-2018 Jorge Matricali\033[92m |___/\033[0m\n\n" ); } @@ -168,15 +100,17 @@ int try_login(const char *hostname, const char *username, const char *password) my_ssh_session = ssh_new(); if (my_ssh_session == NULL) { - print_error("Cant create SSH session\n"); + log_error("Cant create SSH session."); return -1; } ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, hostname); ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port); +#if LIBSSH_VERSION_MAYOR > 0 || (LIBSSH_VERSION_MAYOR == 0 && LIBSSH_VERSION_MINOR >= 6) ssh_options_set(my_ssh_session, SSH_OPTIONS_KEY_EXCHANGE, "none"); ssh_options_set(my_ssh_session, SSH_OPTIONS_HOSTKEYS, "none"); +#endif ssh_options_set(my_ssh_session, SSH_OPTIONS_TIMEOUT, &g_timeout); ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, username); @@ -185,8 +119,8 @@ int try_login(const char *hostname, const char *username, const char *password) if (r != SSH_OK) { ssh_free(my_ssh_session); if (g_verbose) { - print_error( - "Error connecting to %s: %s\n", + log_error( + "Error connecting to %s: %s.", hostname, ssh_get_error(my_ssh_session) ); @@ -228,39 +162,6 @@ int try_login(const char *hostname, const char *username, const char *password) return -1; } -wordlist_t load_wordlist(char *filename) -{ - FILE *fp; - wordlist_t ret; - char **words = NULL; - ssize_t read; - char *temp = 0; - size_t len; - - fp = fopen(filename, "r"); - if (fp == NULL) { - print_error("Error opening file. (%s)\n", filename); - exit(EXIT_FAILURE); - } - - for (int i = 0; (read = getline(&temp, &len, fp)) != -1; i++) { - strtok(temp, "\n"); - if (words == NULL) { - words = malloc(sizeof(temp)); - *words = strdup(temp); - } else { - words = realloc(words, sizeof(temp) * (i + 1)); - *(words + i) = strdup(temp); - } - ret.lenght = i + 1; - } - fclose(fp); - - ret.words = words; - - return ret; -} - int brute(char *hostname, char *username, char *password, int count, int total, FILE *output) { char bar_suffix[50]; @@ -269,13 +170,13 @@ int brute(char *hostname, char *username, char *password, int count, int total, update_progress(count, total, bar_suffix, -1); int ret = try_login(hostname, username, password); if (ret == 0) { - print_debug("LOGIN OK!\t%s\t%s\t%s\n", hostname, username, password); + log_debug("LOGIN OK!\t%s\t%s\t%s", hostname, username, password); if (output != NULL) { - fprintf(output, "LOGIN OK!\t%s\t%s\t%s\n", hostname, username, password); + log_output(output, "LOGIN OK!\t%s\t%s\t%s", hostname, username, password); } return 0; } else { - print_debug("LOGIN FAIL\t%s\t%s\t%s\n", hostname, username, password); + log_debug("LOGIN FAIL\t%s\t%s\t%s", hostname, username, password); } return -1; } @@ -288,7 +189,7 @@ int main(int argc, char** argv) char *hostnames_filename = NULL; char *combos_filename = NULL; char *output_filename = NULL; - FILE *output; + FILE *output = NULL; while ((opt = getopt(argc, argv, "T:C:t:o:vh")) != -1) { switch (opt) { @@ -310,6 +211,12 @@ int main(int argc, char** argv) case 'h': print_banner(); usage(argv[0]); + printf(" -h This help\n" + " -v Verbose mode\n" + " -T Targets file\n" + " -C Username and password file\n" + " -t Max threads\n" + " -o Output log file\n"); exit(EXIT_SUCCESS); default: usage(argv[0]); @@ -325,19 +232,19 @@ int main(int argc, char** argv) combos_filename = strdup("combos.txt"); } - wordlist_t hostnames = load_wordlist(hostnames_filename); - wordlist_t combos = load_wordlist(combos_filename); + wordlist_t hostnames = wordlist_load(hostnames_filename); + wordlist_t combos = wordlist_load(combos_filename); total = hostnames.lenght * combos.lenght; - printf("\nCantidad de combos: %zu\n", combos.lenght); - printf("Cantidad de hostnames: %zu\n", hostnames.lenght); - printf("Combinaciones totales: %d\n\n", total); - printf("Cantidad de threads: %d\n\n", THREADS); + printf("\nAmount of username/password combinations: %zu\n", combos.lenght); + printf("Number of targets: %zu\n", hostnames.lenght); + printf("Total attemps: %d\n", total); + printf("Max threads: %d\n\n", THREADS); if (output_filename != NULL) { output = fopen(output_filename, "a"); if (output == NULL) { - print_error("Error opening output file. (%s)\n", output_filename); + log_error("Error opening output file. (%s)", output_filename); exit(EXIT_FAILURE); } } @@ -361,8 +268,8 @@ int main(int argc, char** argv) p--; } - print_debug( - "HOSTNAME=%s\tUSUARIO=%s\tPASSWORD=%s\n", + log_debug( + "HOSTNAME=%s\tUSERNAME=%s\tPASSWORD=%s", hostnames.words[y], login_data[0], login_data[1] @@ -376,7 +283,7 @@ int main(int argc, char** argv) brute(hostnames.words[y], login_data[0], login_data[1], count, total, output); exit(EXIT_SUCCESS); } else { - print_error("Fork failed!\n\n"); + log_error("Fork failed!"); } count++; @@ -389,7 +296,8 @@ int main(int argc, char** argv) fclose(output); } - printf("\n"); + update_progress(count, total, NULL, -1); + printf("\f"); exit(EXIT_SUCCESS); } diff --git a/cbrutekrag.h b/cbrutekrag.h index 6f7740b..fde2351 100644 --- a/cbrutekrag.h +++ b/cbrutekrag.h @@ -20,28 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - size_t lenght; - char **words; -} wordlist_t; - -char** str_split(char* a_str, const char a_delim); -void print_error(const char *format, ...); -void print_debug(const char *format, ...); -const char *str_repeat(char *str, size_t times); void update_progress(int count, int total, char* suffix, int bar_len); void print_banner(); void usage(const char *p); int try_login(const char *hostname, const char *username, const char *password); -wordlist_t load_wordlist(char *filename); diff --git a/debian/.gitignore b/debian/.gitignore deleted file mode 100644 index 9b25e96..0000000 --- a/debian/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -tarantool-luakit/ -files -stamp-* -*.substvars -*.log diff --git a/log.c b/log.c new file mode 100644 index 0000000..f729ed0 --- /dev/null +++ b/log.c @@ -0,0 +1,51 @@ +/* +Copyright (c) 2014-2018 Jorge Matricali + +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. +*/ + +#include /* fprintf, vfprintf, stderr */ +#include /* va_list, va_start, va_end */ +#include /* time_t, time, tm, localtime, strftime */ + +#include "log.h" + +int g_verbose; + +void print_output(int level, const char *file, int line, const char *head, + const char *tail, FILE *stream, const char *format, ...) +{ + if (level == LOG_DEBUG && g_verbose != 1) { + return; + } + time_t t = time(NULL); + struct tm *tm = localtime(&t); + + va_list arg; + char s[20]; + + s[strftime(s, sizeof(s), "%Y/%m/%d %H:%M:%S", tm)] = '\0'; + fprintf(stream, "%s[%s] ", head, s); + + va_start(arg, format); + vfprintf(stream, format, arg); + va_end (arg); + fprintf(stream, "%s\n", tail); + fflush(stream); +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..296ee3a --- /dev/null +++ b/log.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 2014-2018 Jorge Matricali + +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. +*/ + +#ifndef LOGGER_H +#define LOGGER_H + +extern int g_verbose; + +enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; + +#define log_error(...) print_output(LOG_ERROR, __FILE__, __LINE__, \ + "\033[91m", "\033[0m", stderr, __VA_ARGS__) +#define log_debug(...) print_output(LOG_DEBUG, __FILE__, __LINE__, \ + "\033[37m", "\033[0m", stderr, __VA_ARGS__) +#define log_output(...) print_output(LOG_DEBUG, __FILE__, __LINE__, \ + "", "", __VA_ARGS__) + +void print_output(int level, const char *file, int line, const char *head, + const char *tail, FILE *stream, const char *format, ...); + +#endif /* LOGGER_H */ diff --git a/str.c b/str.c new file mode 100644 index 0000000..bd63f68 --- /dev/null +++ b/str.c @@ -0,0 +1,84 @@ +/* +Copyright (c) 2014-2018 Jorge Matricali + +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. +*/ + +#include +#include +#include +#include + +#include "str.h" + +char** str_split(char* a_str, const char a_delim) +{ + char** result = 0; + size_t count = 0; + char* tmp = a_str; + char* last_comma = 0; + char delim[2]; + delim[0] = a_delim; + delim[1] = 0; + + /* Count how many elements will be extracted. */ + while (*tmp) { + if (a_delim == *tmp) { + count++; + last_comma = tmp; + } + tmp++; + } + + /* Add space for trailing token. */ + count += last_comma < (a_str + strlen(a_str) - 1); + + /* Add space for terminating null string so caller + knows where the list of returned strings ends. */ + count++; + + result = malloc(sizeof(char*) * count); + + if (result) { + size_t idx = 0; + char* token = strtok(a_str, delim); + + while (token) { + assert(idx < count); + *(result + idx++) = strdup(token); + token = strtok(0, delim); + } + assert(idx == count - 1); + *(result + idx) = 0; + } + + return result; +} + +const char *str_repeat(char *str, size_t times) +{ + if (times < 1) return NULL; + char *ret = malloc(sizeof(str) * times + 1); + if (ret == NULL) return NULL; + strcpy(ret, str); + while (--times > 0) { + strcat(ret, str); + } + return ret; +} diff --git a/str.h b/str.h new file mode 100644 index 0000000..6a10f0d --- /dev/null +++ b/str.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 2014-2018 Jorge Matricali + +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. +*/ + +#ifndef STR_H +#define STR_H + +#include + +char** str_split(char* a_str, const char a_delim); +const char *str_repeat(char *str, size_t times); + +#endif /* STR_H */ diff --git a/wordlist.c b/wordlist.c new file mode 100644 index 0000000..b3561ee --- /dev/null +++ b/wordlist.c @@ -0,0 +1,61 @@ +/* +Copyright (c) 2014-2018 Jorge Matricali + +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. +*/ + +#include +#include +#include + +#include "wordlist.h" +#include "log.h" + +wordlist_t wordlist_load(char *filename) +{ + FILE *fp; + wordlist_t ret; + char **words = NULL; + ssize_t read; + char *temp = 0; + size_t len; + + fp = fopen(filename, "r"); + if (fp == NULL) { + log_error("Error opening file. (%s)", filename); + exit(EXIT_FAILURE); + } + + for (int i = 0; (read = getline(&temp, &len, fp)) != -1; i++) { + strtok(temp, "\n"); + if (words == NULL) { + words = malloc(sizeof(temp)); + *words = strdup(temp); + } else { + words = realloc(words, sizeof(temp) * (i + 1)); + *(words + i) = strdup(temp); + } + ret.lenght = i + 1; + } + fclose(fp); + + ret.words = words; + + return ret; +} diff --git a/wordlist.h b/wordlist.h new file mode 100644 index 0000000..3f28609 --- /dev/null +++ b/wordlist.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 2014-2018 Jorge Matricali + +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. +*/ + +#ifndef WORDLIST_H +#define WORDLIST_H + +typedef struct { + size_t lenght; + char **words; +} wordlist_t; + +wordlist_t wordlist_load(char *filename); + +#endif /* WORDLIST_H */