From 1ef2e3451139befd628394799acc53878f891bd8 Mon Sep 17 00:00:00 2001 From: "T. von Dein" Date: Wed, 5 Nov 2025 22:31:56 +0100 Subject: [PATCH] move to codeberg and fix memory leaks (#1) --- .gitignore | 2 + .woodpecker/build.yaml | 29 +++++++ README.md | 10 ++- dicepwgen.c | 177 ++++++++++++++++++++--------------------- dicepwgen.h | 23 +++--- dictfile.c | 107 ++++++++++++------------- 6 files changed, 191 insertions(+), 157 deletions(-) create mode 100644 .gitignore create mode 100644 .woodpecker/build.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56d1bc5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +dicepwgen diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml new file mode 100644 index 0000000..97402f6 --- /dev/null +++ b/.woodpecker/build.yaml @@ -0,0 +1,29 @@ +matrix: + platform: + - linux/amd64 + +labels: + platform: ${platform} + +steps: + build-n-test: + when: + event: [push] + image: alpine:latest + commands: + - apk update + - apk add --no-cache bash build-base words-en gdb valgrind + # build + - make + # look for memory leaks etc + - valgrind --leak-check=full --show-reachable=yes ./dicepwgen 2>&1 | tee log | grep "All heap blocks were freed" + - cat log + # enable in case of a crash + #- gdb -batch -ex "run" -ex "bt" --args dicepwgen + # check if we really get a password + - ./dicepwgen -y | grep -E '[a-z]*%' + # check a custom dict file and if we get 6 words when requested + - test 6 -eq $(./dicepwgen -f contrib/american-english-insane -c 6 | tee log | sed 's/[a-zA-Z]//g' | wc -c) + - cat log + + diff --git a/README.md b/README.md index 98c8d02..8f6dccf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ +[![status-badge](https://ci.codeberg.org/api/badges/15537/status.svg)](https://ci.codeberg.org/repos/15537) +[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://codeberg.org/scip/diceware/raw/branch/master/LICENSE) +[![Documentation](https://img.shields.io/badge/manpage-documentation-blue)](https://codeberg.org/scip/diceware/raw/branch/main/dicepwgen.pod) + ## dicepwgen - A diceware password generator -This is the README file for the password generator dicepwgen. +`dicepwgen` generates a [diceware password](https://de.wikipedia.org/wiki/Diceware) +using a dictionary file. By default it uses pseudo random dice tosses, +but it is also possible to use real dices and enter the numbers by using +the option `-t`, which is the most secure way to generate diceware passwords. + ## Documentation diff --git a/dicepwgen.c b/dicepwgen.c index cd284ba..f442e4e 100644 --- a/dicepwgen.c +++ b/dicepwgen.c @@ -37,15 +37,13 @@ int usage() { "-y --symbols Replace space with -, add non-letters\n" "-d --debug Enable debug output\n" "-v --version Print program version\n" - "-h -? --help Print this help screen\n" - ); + "-h -? --help Print this help screen\n"); return 1; } int WMIN, WMAX, humantoss, verbose, dontjump, symbols; - -int main (int argc, char **argv) { +int main(int argc, char **argv) { int count = 4; char *dictfile = NULL; int opt; @@ -53,81 +51,82 @@ int main (int argc, char **argv) { WMIN = 6; WMAX = 10; humantoss = verbose = dontjump = symbols = 0; - + static struct option longopts[] = { - { "wordcount", required_argument, NULL, 'c' }, - { "minlen", required_argument, NULL, 'l' }, - { "maxlen", required_argument, NULL, 'm' }, - { "humantoss", required_argument, NULL, 't' }, - { "dictfile", required_argument, NULL, 'f' }, - { "dontjump", no_argument, NULL, 'n' }, - { "symbols", no_argument, NULL, 'y' }, - { "version", no_argument, NULL, 'v' }, - { "help", no_argument, NULL, 'h' }, - { "debug", no_argument, NULL, 'd' }, + {"wordcount", required_argument, NULL, 'c'}, + {"minlen", required_argument, NULL, 'l'}, + {"maxlen", required_argument, NULL, 'm'}, + {"humantoss", required_argument, NULL, 't'}, + {"dictfile", required_argument, NULL, 'f'}, + {"dontjump", no_argument, NULL, 'n'}, + {"symbols", no_argument, NULL, 'y'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {"debug", no_argument, NULL, 'd'}, }; - while ((opt = getopt_long(argc, argv, "l:m:tf:c:vh?dny", longopts, NULL)) != -1) { - switch (opt) { - case 'v': - fprintf(stderr, "This is %s version %s\n", argv[0], VERSION); - return 1; - break; - case 'h': - case '?': - return usage(); - break; - case 'c': - count = atoi(optarg); - break; - case 'l': - WMIN = atoi(optarg); - break; - case 'm': - WMAX = atoi(optarg); - break; - case 't': - humantoss = 1; - break; - case 'y': - symbols = 1; - break; - case 'd': - verbose++; - break; - case 'n': - dontjump = 1; - break; - case 'f': - dictfile = malloc(strlen(optarg)); - strncpy(dictfile, optarg, strlen(optarg)); - break; - default: + while ((opt = getopt_long(argc, argv, "l:m:tf:c:vh?dny", longopts, NULL)) != + -1) { + switch (opt) { + case 'v': + fprintf(stderr, "This is %s version %s\n", argv[0], VERSION); + return 1; + break; + case 'h': + case '?': return usage(); break; - } - } + case 'c': + count = atoi(optarg); + break; + case 'l': + WMIN = atoi(optarg); + break; + case 'm': + WMAX = atoi(optarg); + break; + case 't': + humantoss = 1; + break; + case 'y': + symbols = 1; + break; + case 'd': + verbose++; + break; + case 'n': + dontjump = 1; + break; + case 'f': + dictfile = malloc(strlen(optarg)); + strncpy(dictfile, optarg, strlen(optarg)); + break; + default: + return usage(); + break; + } + } - if(dictfile == NULL) { - dictfile = STRINGIZE_VALUE_OF(DICTFILE); - } + if (dictfile == NULL) { + dictfile = STRINGIZE_VALUE_OF(DICTFILE); + } - if(dontjump) { - WMIN = 0; - WMAX = 128; - } - - debug(" using dictfile: %s", dictfile); - debug("minimum word length: %d", WMIN); - debug("maximum word length: %d", WMAX); - if(humantoss) - debug("user rolls dices"); - else - debug("program rolls dices"); - - getwords(dictfile, count); + if (dontjump) { + WMIN = 0; + WMAX = 128; + } - return 0; + debug(" using dictfile: %s", dictfile); + debug("minimum word length: %d", WMIN); + debug("maximum word length: %d", WMAX); + if (humantoss) + debug("user rolls dices"); + else + debug("program rolls dices"); + + getwords(dictfile, count); + + return 0; } void getwords(char *dictfile, int count) { @@ -140,20 +139,20 @@ void getwords(char *dictfile, int count) { int *tossed; char sep = ' '; unsigned char *tosses; - + words = fetch_dict(dictfile); tossed = malloc(count * sizeof(int)); - - for(i=0; i -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include "debug.h" #include "dictfile.h" #include "tossing.h" -#include "debug.h" #define STRINGIZE(x) #x #define STRINGIZE_VALUE_OF(x) STRINGIZE(x) -#define VERSION "1.2.0" -#define RLEN 1024 +// #define VERSION "1.3.0" +#define RLEN 1024 +static const char VERSION[] = "1.3.0"; extern int humantoss; extern int verbose; @@ -48,7 +49,7 @@ extern int WMIN; extern int WMAX; int usage(); -int main (int argc, char **argv); +int main(int argc, char **argv); void getwords(char *dictfile, int count); #endif diff --git a/dictfile.c b/dictfile.c index 559ae9f..782e49b 100644 --- a/dictfile.c +++ b/dictfile.c @@ -27,39 +27,35 @@ int *incr_dicedigit(int *digits) { be a multiple of 10000, the 2nd a multiple of 1000 and so on. */ - if(digits[4] == 6) { + if (digits[4] == 6) { digits[4] = 1; - if(digits[3] == 60) { + if (digits[3] == 60) { digits[3] = 10; - if(digits[2] == 600) { - digits[2] = 100; - if(digits[1] == 6000) { - digits[1] = 1000; - digits[0] += 10000; /* may overflow to 71111, must be catched by caller */ - } - else - digits[1] += 1000; - } - else - digits[2] += 100; - } - else + if (digits[2] == 600) { + digits[2] = 100; + if (digits[1] == 6000) { + digits[1] = 1000; + digits[0] += + 10000; /* may overflow to 71111, must be catched by caller */ + } else + digits[1] += 1000; + } else + digits[2] += 100; + } else digits[3] += 10; - } - else + } else digits[4]++; return digits; } - int get_dicenum(int *digits) { /* get the actual number of an array of dice digits */ int i = 0; int pos = 0; - for(i=0; i<5; i++) + for (i = 0; i < 5; i++) pos += digits[i]; return pos; @@ -82,73 +78,72 @@ char **fetch_dict(char *dictfile) { FILE *DICT; int *digits; - if((DICT = fopen(dictfile, "rb")) == NULL) { + if ((DICT = fopen(dictfile, "rb")) == NULL) { perror("Could not open dictfile"); exit(1); } - words = malloc(66666 * sizeof(char *)); + words = malloc(66667 * sizeof(char *)); digits = malloc(5 * sizeof(int)); jump = rand_lim(32); - - digits[0] = 10000; - digits[1] = 1000; - digits[2] = 100; - digits[3] = 10; - digits[4] = 1; - pos = 11111; + digits[0] = 10000; + digits[1] = 1000; + digits[2] = 100; + digits[3] = 10; + digits[4] = 1; + + pos = 11111; next = 0; - for(i=0; i<6666; i++) + for (i = 0; i < 66667; i++) words[i] = NULL; - - LOOP: +LOOP: while ((linelen = getline(&line, &len, DICT)) != -1) { - if(! dontjump) { - if(jump > 0) { - jump--; - continue; - } - else { - jump = rand_lim(32); + if (!dontjump) { + if (jump > 0) { + jump--; + continue; + } else { + jump = rand_lim(32); } } - if(linelen >= WMIN+1 && linelen <= WMAX+1) { - line[linelen-1] = '\0'; /* remove newline */ + if (linelen >= WMIN + 1 && linelen <= WMAX + 1) { + line[linelen - 1] = '\0'; /* remove newline */ - for(i=0; i 1) - debug("add to wordlist at index %d: %s", pos, line); + strncpy(words[pos], line, linelen); + if (verbose > 1) + debug("add to wordlist at index %d: %s", pos, line); digits = incr_dicedigit(digits); pos = get_dicenum(digits); - /* this is what pos gets next after 66666, which is max reachable with 5 dices */ - if(pos == 71111) - break; + /* this is what pos gets next after 66666, which is max reachable with 5 + * dices */ + if (pos == 71111) + break; } /* endif word 4<=>10 */ } /* while read */ - if(pos < 66666) { + if (pos < 66666) { fseek(DICT, 0L, SEEK_SET); goto LOOP; } - + fclose(DICT); free(line); free(digits);