commit 78622e630e3da58f30499f3333102fa54bb7ab42 Author: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon Sep 30 10:35:53 2019 -0400 Package init diff --git a/Fix-a-buffer-overflow-processing-long-words.patch b/Fix-a-buffer-overflow-processing-long-words.patch new file mode 100644 index 0000000..fc1f4de --- /dev/null +++ b/Fix-a-buffer-overflow-processing-long-words.patch @@ -0,0 +1,44 @@ +From 33d7fa4585247cd2247a1ffa032ad245836c6edb Mon Sep 17 00:00:00 2001 +From: Jan Dittberner +Date: Thu, 25 Aug 2016 17:17:53 +0200 +Subject: [PATCH 07/13] Fix a buffer overflow processing long words + +A buffer overflow processing long words has been discovered. This commit +applies the patch from +https://build.opensuse.org/package/view_file/Base:System/cracklib/0004-overflow-processing-long-words.patch +by Howard Guo. + +See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=835386 and +http://www.openwall.com/lists/oss-security/2016/08/23/8 +--- + src/NEWS | 1 + + src/lib/rules.c | 5 ++--- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/fascist.c b/lib/fascist.c +index d193cc0..3a2aa46 100644 +--- a/lib/fascist.c ++++ b/lib/fascist.c +@@ -438,7 +438,7 @@ + int i; + int len; + char *mp; +- char area[STRINGSIZE]; ++ char area[STRINGSIZE * 2] = {0}; + char revarea[STRINGSIZE]; + + /* use destructors to turn password into rawtext */ +diff --git a/lib/rules.c b/lib/rules.c +index d193cc0..3a2aa46 100644 +--- a/lib/rules.c ++++ b/lib/rules.c +@@ -437,8 +437,7 @@ + { + int limit; + register char *ptr; +- char area2[STRINGSIZE]; +- area[0] = '\0'; ++ char area2[STRINGSIZE * 2] = {0}; + strcpy(area, input); + + for (ptr = control; *ptr; ptr++) diff --git a/Fix-build-on-illumos-pwp-dfp-is-void-and-should-be-c.patch b/Fix-build-on-illumos-pwp-dfp-is-void-and-should-be-c.patch new file mode 100644 index 0000000..2a7e21a --- /dev/null +++ b/Fix-build-on-illumos-pwp-dfp-is-void-and-should-be-c.patch @@ -0,0 +1,39 @@ +From 5ec42885b29419fd384b672c546af913491b9700 Mon Sep 17 00:00:00 2001 +From: Alexander Pyhalov +Date: Thu, 26 Nov 2015 23:43:37 +0300 +Subject: [PATCH 01/13] Fix build on illumos (pwp->dfp is void * and should be + converted to FILE *) + +--- + lib/packlib.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/packlib.c b/lib/packlib.c +index 2711d94..8acb7be 100644 +--- a/lib/packlib.c ++++ b/lib/packlib.c +@@ -408,7 +408,7 @@ PutPW(pwp, string) + fwrite((char *) &datum, sizeof(datum), 1, pwp->ifp); + + fputs(pwp->data_put[0], pwp->dfp); +- putc(0, pwp->dfp); ++ putc(0, (FILE*) pwp->dfp); + + ostr = pwp->data_put[0]; + +@@ -421,10 +421,10 @@ PutPW(pwp, string) + if (nstr[0]) + { + for (j = 0; ostr[j] && nstr[j] && (ostr[j] == nstr[j]); j++); +- putc(j & 0xff, pwp->dfp); ++ putc(j & 0xff, (FILE*) pwp->dfp); + fputs(nstr + j, pwp->dfp); + } +- putc(0, pwp->dfp); ++ putc(0, (FILE*) pwp->dfp); + + ostr = nstr; + } +-- +2.19.1 + diff --git a/Fix-distdifference.patch b/Fix-distdifference.patch new file mode 100644 index 0000000..808e1f2 --- /dev/null +++ b/Fix-distdifference.patch @@ -0,0 +1,31 @@ +From 696a9fb5d042e9d4e8f2ae785374595748078114 Mon Sep 17 00:00:00 2001 +From: Colin Read +Date: Wed, 1 Aug 2018 17:48:11 +0200 +Subject: [PATCH 09/13] Fix distdifference + +--- + python/cracklib.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/python/cracklib.py b/python/cracklib.py +index 9de7e89..f4c98cd 100644 +--- a/python/cracklib.py ++++ b/python/cracklib.py +@@ -53,12 +53,12 @@ def distdifferent(old, new, i, j): + """Calculate how different two strings are in terms of the number + of character removals, additions, and changes needed to go from one + to the other.""" +- if i == 0 or len(old) <= i: ++ if i == 0 or len(old) < i: + cval = 0 + else: + cval = old[i - 1] + +- if j == 0 or len(new) <= j: ++ if j == 0 or len(new) < j: + dval = 0 + else: + dval = new[j - 1] +-- +2.19.1 + diff --git a/bugfix-cracklib-format.patch b/bugfix-cracklib-format.patch new file mode 100644 index 0000000..b9be8ad --- /dev/null +++ b/bugfix-cracklib-format.patch @@ -0,0 +1,23 @@ +From 7611d421fb3170b445eda400899cf04519201aa4 Mon Sep 17 00:00:00 2001 +From: sunguoshuai +Date: Wed, 23 Jan 2019 19:10:44 +0800 +Subject: [PATCH] modify cracklib format + +reason: modify cracklib format + +Signed-off-by:sunguoshuai +--- + util/cracklib-format | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/cracklib-format b/util/cracklib-format +index 7d7953f..3465fbc 100644 +--- a/util/cracklib-format ++++ b/util/cracklib-format +@@ -8,5 +8,5 @@ export LC_ALL + gzip -cdf "$@" | + grep -a -E -v '^.{30,}$' | + tr '[:upper:]' '[:lower:]' | +- tr -cd '\n[:graph:]' | ++ sed s/[[:space:]]//g | + sort -u diff --git a/cracklib-2.9.0-python-gzdicts.patch b/cracklib-2.9.0-python-gzdicts.patch new file mode 100644 index 0000000..feac201 --- /dev/null +++ b/cracklib-2.9.0-python-gzdicts.patch @@ -0,0 +1,104 @@ +diff -up cracklib-2.9.0/python/_cracklib.c.gzdicts cracklib-2.9.0/python/_cracklib.c +--- cracklib-2.9.0/python/_cracklib.c.gzdicts 2013-06-01 16:47:13.000000000 +0200 ++++ cracklib-2.9.0/python/_cracklib.c 2013-08-20 12:37:32.028611493 +0200 +@@ -23,6 +23,7 @@ + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#include "config.h" + #ifdef PYTHON_H + #include PYTHON_H + #else +@@ -72,9 +73,8 @@ static char _cracklib_FascistCheck_doc [ + static PyObject * + _cracklib_FascistCheck(PyObject *self, PyObject *args, PyObject *kwargs) + { +- char *candidate, *dict; +- char *defaultdict = NULL; +- const char *result; ++ char *candidate; ++ const char *result, *dict; + struct stat st; + char *keywords[] = {"pw", "dictpath", NULL}; + char *dictfile; +@@ -103,44 +103,35 @@ _cracklib_FascistCheck(PyObject *self, P + "second argument was not an absolute path!"); + return NULL; + } +- dictfile = malloc(strlen(dict) + sizeof(DICT_SUFFIX)); +- if (dictfile == NULL) +- { +- PyErr_SetFromErrnoWithFilename(PyExc_OSError, dict); +- return NULL; +- } +- sprintf(dictfile, "%s" DICT_SUFFIX, dict); +- if (lstat(dictfile, &st) == -1) +- { +- PyErr_SetFromErrnoWithFilename(PyExc_OSError, dictfile); +- free(dictfile); +- return NULL; +- } +- free(dictfile); + } else + { +- defaultdict = strdup(GetDefaultCracklibDict()); +- if (errno == ENOMEM) { +- PyErr_SetFromErrno(PyExc_OSError); +- return NULL; +- } +- dictfile = malloc(strlen(defaultdict) + sizeof(DICT_SUFFIX)); +- if (dictfile == NULL) +- { +- PyErr_SetFromErrnoWithFilename(PyExc_OSError, defaultdict); +- free(defaultdict); +- return NULL; +- } +- sprintf(dictfile, "%s" DICT_SUFFIX, defaultdict); ++ /* No need to strdup() anything as this is a constant value */ ++ dict = GetDefaultCracklibDict(); ++ } ++ ++ dictfile = malloc(strlen(dict) + sizeof(DICT_SUFFIX) + 3); ++ if (dictfile == NULL) ++ { ++ PyErr_SetFromErrnoWithFilename(PyExc_OSError, dict); ++ return NULL; ++ } ++ sprintf(dictfile, "%s" DICT_SUFFIX, dict); ++ if (lstat(dictfile, &st) == -1) ++ { ++#ifdef HAVE_ZLIB_H ++ sprintf(dictfile, "%s" DICT_SUFFIX ".gz", dict); + if (lstat(dictfile, &st) == -1) + { ++ sprintf(dictfile, "%s" DICT_SUFFIX, dict); ++#endif + PyErr_SetFromErrnoWithFilename(PyExc_OSError, dictfile); +- free(defaultdict); + free(dictfile); + return NULL; ++#ifdef HAVE_ZLIB_H + } +- free(dictfile); ++#endif + } ++ free(dictfile); + + setlocale(LC_ALL, ""); + #ifdef ENABLE_NLS +@@ -148,14 +139,9 @@ _cracklib_FascistCheck(PyObject *self, P + #endif + + LOCK(); +- result = FascistCheck(candidate, dict ? dict : defaultdict); ++ result = FascistCheck(candidate, dict); + UNLOCK(); + +- if (defaultdict != NULL) +- { +- free(defaultdict); +- } +- + if (result != NULL) + { + PyErr_SetString(PyExc_ValueError, result); diff --git a/cracklib-2.9.1-inttypes.patch b/cracklib-2.9.1-inttypes.patch new file mode 100644 index 0000000..c8d8fe8 --- /dev/null +++ b/cracklib-2.9.1-inttypes.patch @@ -0,0 +1,22 @@ +Do not depend on config.h in public header. +diff -up cracklib-2.9.1/lib/packer.h.inttypes cracklib-2.9.1/lib/packer.h +--- cracklib-2.9.1/lib/packer.h.inttypes 2013-12-03 15:00:15.000000000 +0100 ++++ cracklib-2.9.1/lib/packer.h 2013-12-09 09:07:38.306394809 +0100 +@@ -30,17 +30,7 @@ + #define _(String) (String) + #endif + +-#if defined(HAVE_INTTYPES_H) +-#include +-#else +-#if defined(HAVE_STDINT_H) + #include +-#else +-typedef unsigned int uint32_t; +-typedef unsigned short uint16_t; +-#endif +-#endif +- + + struct pi_header + { diff --git a/cracklib-2.9.6-cve-2016-6318.patch b/cracklib-2.9.6-cve-2016-6318.patch new file mode 100644 index 0000000..370b403 --- /dev/null +++ b/cracklib-2.9.6-cve-2016-6318.patch @@ -0,0 +1,144 @@ +diff -up cracklib-2.9.6/lib/fascist.c.overflow cracklib-2.9.6/lib/fascist.c +--- cracklib-2.9.6/lib/fascist.c.overflow 2015-10-23 16:58:38.403319225 +0200 ++++ cracklib-2.9.6/lib/fascist.c 2016-12-08 17:28:41.490101358 +0100 +@@ -515,7 +515,7 @@ FascistGecosUser(char *password, const c + char gbuffer[STRINGSIZE]; + char tbuffer[STRINGSIZE]; + char *uwords[STRINGSIZE]; +- char longbuffer[STRINGSIZE * 2]; ++ char longbuffer[STRINGSIZE]; + + if (gecos == NULL) + gecos = ""; +@@ -596,38 +596,47 @@ FascistGecosUser(char *password, const c + { + for (i = 0; i < j; i++) + { +- strcpy(longbuffer, uwords[i]); +- strcat(longbuffer, uwords[j]); +- +- if (GTry(longbuffer, password)) ++ if (strlen(uwords[i]) + strlen(uwords[j]) < STRINGSIZE) + { +- return _("it is derived from your password entry"); +- } +- +- strcpy(longbuffer, uwords[j]); +- strcat(longbuffer, uwords[i]); ++ strcpy(longbuffer, uwords[i]); ++ strcat(longbuffer, uwords[j]); + +- if (GTry(longbuffer, password)) +- { +- return _("it's derived from your password entry"); ++ if (GTry(longbuffer, password)) ++ { ++ return _("it is derived from your password entry"); ++ } ++ ++ strcpy(longbuffer, uwords[j]); ++ strcat(longbuffer, uwords[i]); ++ ++ if (GTry(longbuffer, password)) ++ { ++ return _("it's derived from your password entry"); ++ } + } + +- longbuffer[0] = uwords[i][0]; +- longbuffer[1] = '\0'; +- strcat(longbuffer, uwords[j]); +- +- if (GTry(longbuffer, password)) ++ if (strlen(uwords[j]) < STRINGSIZE - 1) + { +- return _("it is derivable from your password entry"); ++ longbuffer[0] = uwords[i][0]; ++ longbuffer[1] = '\0'; ++ strcat(longbuffer, uwords[j]); ++ ++ if (GTry(longbuffer, password)) ++ { ++ return _("it is derivable from your password entry"); ++ } + } + +- longbuffer[0] = uwords[j][0]; +- longbuffer[1] = '\0'; +- strcat(longbuffer, uwords[i]); +- +- if (GTry(longbuffer, password)) ++ if (strlen(uwords[i]) < STRINGSIZE - 1) + { +- return _("it's derivable from your password entry"); ++ longbuffer[0] = uwords[j][0]; ++ longbuffer[1] = '\0'; ++ strcat(longbuffer, uwords[i]); ++ ++ if (GTry(longbuffer, password)) ++ { ++ return _("it's derivable from your password entry"); ++ } + } + } + } +diff -up cracklib-2.9.6/lib/rules.c.overflow cracklib-2.9.6/lib/rules.c +--- cracklib-2.9.6/lib/rules.c.overflow 2015-10-23 16:58:38.000000000 +0200 ++++ cracklib-2.9.6/lib/rules.c 2016-12-08 18:03:27.041941297 +0100 +@@ -158,6 +158,8 @@ Pluralise(string, area) /* returns a po + register int length; + length = strlen(string); + strcpy(area, string); ++ if (length > STRINGSIZE - 3) /* we add 2 characters at worst */ ++ return (area); + + if (!Suffix(string, "ch") || + !Suffix(string, "ex") || +@@ -462,11 +464,11 @@ Mangle(input, control, area) /* returns + Pluralise(area2, area); + break; + case RULE_REFLECT: +- strcat(area, Reverse(area, area2)); ++ strncat(area, Reverse(area, area2), STRINGSIZE - strlen(area) - 1); + break; + case RULE_DUPLICATE: + strcpy(area2, area); +- strcat(area, area2); ++ strncat(area, area2, STRINGSIZE - strlen(area) - 1); + break; + case RULE_GT: + if (!ptr[1]) +@@ -514,7 +516,8 @@ Mangle(input, control, area) /* returns + } else + { + area2[0] = *(++ptr); +- strcpy(area2 + 1, area); ++ strncpy(area2 + 1, area, STRINGSIZE - 2); ++ area2[STRINGSIZE - 1] = '\0'; + strcpy(area, area2); + } + break; +@@ -528,8 +531,10 @@ Mangle(input, control, area) /* returns + register char *string; + string = area; + while (*(string++)); +- string[-1] = *(++ptr); +- *string = '\0'; ++ if (string < area + STRINGSIZE) { ++ string[-1] = *(++ptr); ++ *string = '\0'; ++ } + } + break; + case RULE_EXTRACT: +@@ -600,6 +605,10 @@ Mangle(input, control, area) /* returns + } + p1 = area; + p2 = area2; ++ if (strlen(p1) > STRINGSIZE - 2) { ++ /* truncate */ ++ p1[STRINGSIZE - 2] = '\0'; ++ } + while (i && *p1) + { + i--; diff --git a/cracklib-2.9.6-packlib-reentrant.patch b/cracklib-2.9.6-packlib-reentrant.patch new file mode 100644 index 0000000..9ca7fa7 --- /dev/null +++ b/cracklib-2.9.6-packlib-reentrant.patch @@ -0,0 +1,672 @@ +diff -up cracklib-2.9.6/lib/fascist.c.reentrant cracklib-2.9.6/lib/fascist.c +--- cracklib-2.9.6/lib/fascist.c.reentrant 2015-08-18 20:41:16.000000000 +0200 ++++ cracklib-2.9.6/lib/fascist.c 2015-10-22 18:17:20.338290974 +0200 +@@ -36,8 +36,8 @@ typedef unsigned short uint16_t; + #undef DEBUG + #undef DEBUG2 + +-extern char *Reverse(char *buf); +-extern char *Lowercase(char *buf); ++extern char *Reverse(char *buf, char *area); ++extern char *Lowercase(char *buf, char *area); + + static char *r_destructors[] = { + ":", /* noop - must do this to test raw word. */ +@@ -439,6 +439,8 @@ GTry(rawtext, password) + int i; + int len; + char *mp; ++ char area[STRINGSIZE]; ++ char revarea[STRINGSIZE]; + + /* use destructors to turn password into rawtext */ + /* note use of Reverse() to save duplicating all rules */ +@@ -447,7 +449,7 @@ GTry(rawtext, password) + + for (i = 0; r_destructors[i]; i++) + { +- if (!(mp = Mangle(password, r_destructors[i]))) ++ if (!(mp = Mangle(password, r_destructors[i], area))) + { + continue; + } +@@ -462,10 +464,10 @@ GTry(rawtext, password) + } + + #ifdef DEBUG +- printf("%-16s = %-16s (destruct %s reversed)\n", Reverse(mp), rawtext, r_destructors[i]); ++ printf("%-16s = %-16s (destruct %s reversed)\n", Reverse(mp, revarea), rawtext, r_destructors[i]); + #endif + +- if (!strncmp(Reverse(mp), rawtext, len)) ++ if (!strncmp(Reverse(mp, revarea), rawtext, len)) + { + return (1); + } +@@ -473,7 +475,7 @@ GTry(rawtext, password) + + for (i = 0; r_constructors[i]; i++) + { +- if (!(mp = Mangle(rawtext, r_constructors[i]))) ++ if (!(mp = Mangle(rawtext, r_constructors[i], area))) + { + continue; + } +@@ -520,7 +522,7 @@ FascistGecosUser(char *password, const c + + strncpy(tbuffer, gecos, STRINGSIZE); + tbuffer[STRINGSIZE-1] = '\0'; +- strcpy(gbuffer, Lowercase(tbuffer)); ++ Lowercase(tbuffer, gbuffer); + + wc = 0; + ptr = gbuffer; +@@ -695,6 +697,7 @@ FascistLookUser(PWDICT *pwp, char *instr + char junk[STRINGSIZE]; + char *password; + char rpassword[STRINGSIZE]; ++ char area[STRINGSIZE]; + uint32_t notfound; + + notfound = PW_WORDS(pwp); +@@ -731,7 +734,7 @@ FascistLookUser(PWDICT *pwp, char *instr + return _("it does not contain enough DIFFERENT characters"); + } + +- strcpy(password, (char *)Lowercase(password)); ++ strcpy(password, (char *)Lowercase(password, area)); + + Trim(password); + +@@ -787,7 +790,7 @@ FascistLookUser(PWDICT *pwp, char *instr + { + char *a; + +- if (!(a = Mangle(password, r_destructors[i]))) ++ if (!(a = Mangle(password, r_destructors[i], area))) + { + continue; + } +@@ -802,13 +805,13 @@ FascistLookUser(PWDICT *pwp, char *instr + } + } + +- strcpy(password, (char *)Reverse(password)); ++ strcpy(password, (char *)Reverse(password, area)); + + for (i = 0; r_destructors[i]; i++) + { + char *a; + +- if (!(a = Mangle(password, r_destructors[i]))) ++ if (!(a = Mangle(password, r_destructors[i], area))) + { + continue; + } +diff -up cracklib-2.9.6/lib/packer.h.reentrant cracklib-2.9.6/lib/packer.h +--- cracklib-2.9.6/lib/packer.h.reentrant 2015-10-22 18:17:20.335290902 +0200 ++++ cracklib-2.9.6/lib/packer.h 2015-10-22 18:17:20.338290974 +0200 +@@ -82,7 +82,7 @@ extern int PWClose(PWDICT *pwp); + extern unsigned int FindPW(PWDICT *pwp, char *string); + extern int PutPW(PWDICT *pwp, char *string); + extern int PMatch(char *control, char *string); +-extern char *Mangle(char *input, char *control); ++extern char *Mangle(char *input, char *control, char *area); + extern char Chop(char *string); + extern char *Trim(char *string); + extern char *FascistLook(PWDICT *pwp, char *instring); +diff -up cracklib-2.9.6/lib/packlib.c.reentrant cracklib-2.9.6/lib/packlib.c +--- cracklib-2.9.6/lib/packlib.c.reentrant 2015-08-18 20:41:16.000000000 +0200 ++++ cracklib-2.9.6/lib/packlib.c 2015-10-22 18:19:52.154911451 +0200 +@@ -67,8 +67,8 @@ PWOpen(prefix, mode) + char *mode; + { + int use64 = 0; +- static PWDICT pdesc; +- static PWDICT64 pdesc64; ++ PWDICT *pdesc; ++ PWDICT64 pdesc64; + char iname[STRINGSIZE]; + char dname[STRINGSIZE]; + char wname[STRINGSIZE]; +@@ -76,13 +76,11 @@ PWOpen(prefix, mode) + void *ifp; + void *wfp; + +- if (pdesc.header.pih_magic == PIH_MAGIC) +- { +- fprintf(stderr, "%s: another dictionary already open\n", prefix); ++ pdesc = malloc(sizeof(*pdesc)); ++ if (pdesc == NULL) + return NULL; +- } + +- memset(&pdesc, '\0', sizeof(pdesc)); ++ memset(pdesc, '\0', sizeof(*pdesc)); + memset(&pdesc64, '\0', sizeof(pdesc64)); + + snprintf(iname, STRINGSIZE, "%s.pwi", prefix); +@@ -91,77 +89,80 @@ PWOpen(prefix, mode) + + if (mode[0] == 'r') + { +- pdesc.flags &= ~PFOR_USEZLIB; ++ pdesc->flags &= ~PFOR_USEZLIB; + /* first try the normal db file */ +- if (!(pdesc.dfp = fopen(dname, mode))) ++ if (!(pdesc->dfp = fopen(dname, mode))) + { + #ifdef HAVE_ZLIB_H +- pdesc.flags |= PFOR_USEZLIB; ++ pdesc->flags |= PFOR_USEZLIB; + /* try extension .gz */ + snprintf(dname, STRINGSIZE, "%s.pwd.gz", prefix); +- if (!(pdesc.dfp = gzopen(dname, mode))) ++ if (!(pdesc->dfp = gzopen(dname, mode))) + { + perror(dname); ++ free(pdesc); + return NULL; + } + #else + perror(dname); ++ free(pdesc); + return NULL; + #endif + } + } + else + { +- pdesc.flags &= ~PFOR_USEZLIB; ++ pdesc->flags &= ~PFOR_USEZLIB; + /* write mode: use fopen */ +- if (!(pdesc.dfp = fopen(dname, mode))) ++ if (!(pdesc->dfp = fopen(dname, mode))) + { + perror(dname); ++ free(pdesc); + return NULL; + } + } + +- if (!(pdesc.ifp = fopen(iname, mode))) ++ if (!(pdesc->ifp = fopen(iname, mode))) + { + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) +- gzclose(pdesc.dfp); ++ if(pdesc->flags & PFOR_USEZLIB) ++ gzclose(pdesc->dfp); + else + #endif +- fclose(pdesc.dfp); ++ fclose(pdesc->dfp); + perror(iname); ++ free(pdesc); + return NULL; + } + +- if ((pdesc.wfp = fopen(wname, mode))) ++ if ((pdesc->wfp = fopen(wname, mode))) + { +- pdesc.flags |= PFOR_USEHWMS; ++ pdesc->flags |= PFOR_USEHWMS; + } + +- ifp = pdesc.ifp; +- dfp = pdesc.dfp; +- wfp = pdesc.wfp; ++ ifp = pdesc->ifp; ++ dfp = pdesc->dfp; ++ wfp = pdesc->wfp; + + if (mode[0] == 'w') + { +- pdesc.flags |= PFOR_WRITE; +- pdesc.header.pih_magic = PIH_MAGIC; +- pdesc.header.pih_blocklen = NUMWORDS; +- pdesc.header.pih_numwords = 0; ++ pdesc->flags |= PFOR_WRITE; ++ pdesc->header.pih_magic = PIH_MAGIC; ++ pdesc->header.pih_blocklen = NUMWORDS; ++ pdesc->header.pih_numwords = 0; + +- fwrite((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp); ++ fwrite((char *) &pdesc->header, sizeof(pdesc->header), 1, ifp); + } else + { +- pdesc.flags &= ~PFOR_WRITE; ++ pdesc->flags &= ~PFOR_WRITE; + +- if (!fread((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp)) ++ if (!fread((char *) &pdesc->header, sizeof(pdesc->header), 1, ifp)) + { + fprintf(stderr, "%s: error reading header\n", prefix); + +- pdesc.header.pih_magic = 0; + fclose(ifp); + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) ++ if(pdesc->flags & PFOR_USEZLIB) + gzclose(dfp); + else + #endif +@@ -170,10 +171,11 @@ PWOpen(prefix, mode) + { + fclose(wfp); + } ++ free(pdesc); + return NULL; + } + +- if ((pdesc.header.pih_magic == 0) || (pdesc.header.pih_numwords == 0)) ++ if ((pdesc->header.pih_magic == 0) || (pdesc->header.pih_numwords == 0)) + { + /* uh-oh. either a broken "64-bit" file or a garbage file. */ + rewind (ifp); +@@ -181,10 +183,9 @@ PWOpen(prefix, mode) + { + fprintf(stderr, "%s: error reading header\n", prefix); + +- pdesc.header.pih_magic = 0; + fclose(ifp); + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) ++ if (pdesc->flags & PFOR_USEZLIB) + gzclose(dfp); + else + #endif +@@ -193,6 +194,7 @@ PWOpen(prefix, mode) + { + fclose(wfp); + } ++ free(pdesc); + return NULL; + } + if (pdesc64.header.pih_magic != PIH_MAGIC) +@@ -200,10 +202,9 @@ PWOpen(prefix, mode) + /* nope, not "64-bit" after all */ + fprintf(stderr, "%s: error reading header\n", prefix); + +- pdesc.header.pih_magic = 0; + fclose(ifp); + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) ++ if (pdesc->flags & PFOR_USEZLIB) + gzclose(dfp); + else + #endif +@@ -213,23 +214,23 @@ PWOpen(prefix, mode) + { + fclose(wfp); + } ++ free(pdesc); + return NULL; + } +- pdesc.header.pih_magic = pdesc64.header.pih_magic; +- pdesc.header.pih_numwords = pdesc64.header.pih_numwords; +- pdesc.header.pih_blocklen = pdesc64.header.pih_blocklen; +- pdesc.header.pih_pad = pdesc64.header.pih_pad; ++ pdesc->header.pih_magic = pdesc64.header.pih_magic; ++ pdesc->header.pih_numwords = pdesc64.header.pih_numwords; ++ pdesc->header.pih_blocklen = pdesc64.header.pih_blocklen; ++ pdesc->header.pih_pad = pdesc64.header.pih_pad; + use64 = 1; + } + +- if (pdesc.header.pih_magic != PIH_MAGIC) ++ if (pdesc->header.pih_magic != PIH_MAGIC) + { + fprintf(stderr, "%s: magic mismatch\n", prefix); + +- pdesc.header.pih_magic = 0; + fclose(ifp); + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) ++ if (pdesc->flags & PFOR_USEZLIB) + gzclose(dfp); + else + #endif +@@ -239,17 +240,17 @@ PWOpen(prefix, mode) + { + fclose(wfp); + } ++ free(pdesc); + return NULL; + } + +- if (pdesc.header.pih_numwords < 1) ++ if (pdesc->header.pih_numwords < 1) + { + fprintf(stderr, "%s: invalid word count\n", prefix); + +- pdesc.header.pih_magic = 0; + fclose(ifp); + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) ++ if (pdesc->flags & PFOR_USEZLIB) + gzclose(dfp); + else + #endif +@@ -258,17 +259,17 @@ PWOpen(prefix, mode) + { + fclose(wfp); + } ++ free(pdesc); + return NULL; + } + +- if (pdesc.header.pih_blocklen != NUMWORDS) ++ if (pdesc->header.pih_blocklen != NUMWORDS) + { + fprintf(stderr, "%s: size mismatch\n", prefix); + +- pdesc.header.pih_magic = 0; + fclose(ifp); + #ifdef HAVE_ZLIB_H +- if (pdesc.flags & PFOR_USEZLIB) ++ if (pdesc->flags & PFOR_USEZLIB) + gzclose(dfp); + else + #endif +@@ -277,10 +278,11 @@ PWOpen(prefix, mode) + { + fclose(wfp); + } ++ free(pdesc); + return NULL; + } + +- if (pdesc.flags & PFOR_USEHWMS) ++ if (pdesc->flags & PFOR_USEHWMS) + { + int i; + +@@ -288,27 +290,27 @@ PWOpen(prefix, mode) + { + if (fread(pdesc64.hwms, 1, sizeof(pdesc64.hwms), wfp) != sizeof(pdesc64.hwms)) + { +- pdesc.flags &= ~PFOR_USEHWMS; ++ pdesc->flags &= ~PFOR_USEHWMS; + } +- for (i = 0; i < sizeof(pdesc.hwms) / sizeof(pdesc.hwms[0]); i++) ++ for (i = 0; i < sizeof(pdesc->hwms) / sizeof(pdesc->hwms[0]); i++) + { +- pdesc.hwms[i] = pdesc64.hwms[i]; ++ pdesc->hwms[i] = pdesc64.hwms[i]; + } +- } +- else if (fread(pdesc.hwms, 1, sizeof(pdesc.hwms), wfp) != sizeof(pdesc.hwms)) ++ } ++ else if (fread(pdesc->hwms, 1, sizeof(pdesc->hwms), wfp) != sizeof(pdesc->hwms)) + { +- pdesc.flags &= ~PFOR_USEHWMS; ++ pdesc->flags &= ~PFOR_USEHWMS; + } + #if DEBUG + for (i=1; i<=0xff; i++) + { +- printf("hwm[%02x] = %d\n", i, pdesc.hwms[i]); ++ printf("hwm[%02x] = %d\n", i, pdesc->hwms[i]); + } + #endif + } + } + +- return (&pdesc); ++ return (pdesc); + } + + int +@@ -318,6 +320,7 @@ PWClose(pwp) + if (pwp->header.pih_magic != PIH_MAGIC) + { + fprintf(stderr, "PWClose: close magic mismatch\n"); ++ /* we do not try to free memory that is probably corrupted */ + return (-1); + } + +@@ -329,12 +332,14 @@ PWClose(pwp) + if (fseek(pwp->ifp, 0L, 0)) + { + fprintf(stderr, "index magic fseek failed\n"); ++ free(pwp); + return (-1); + } + + if (!fwrite((char *) &pwp->header, sizeof(pwp->header), 1, pwp->ifp)) + { + fprintf(stderr, "index magic fwrite failed\n"); ++ free(pwp); + return (-1); + } + +@@ -368,6 +373,7 @@ PWClose(pwp) + } + + pwp->header.pih_magic = 0; ++ free(pwp); + + return (0); + } +diff -up cracklib-2.9.6/lib/rules.c.reentrant cracklib-2.9.6/lib/rules.c +--- cracklib-2.9.6/lib/rules.c.reentrant 2015-08-18 20:41:16.000000000 +0200 ++++ cracklib-2.9.6/lib/rules.c 2015-10-22 18:17:20.339290998 +0200 +@@ -82,12 +82,12 @@ Suffix(myword, suffix) + } + + char * +-Reverse(str) /* return a pointer to a reversal */ ++Reverse(str, area) /* return a pointer to a reversal */ + register char *str; ++ char *area; + { + register int i; + register int j; +- static char area[STRINGSIZE]; + j = i = strlen(str); + while (*str) + { +@@ -98,11 +98,11 @@ Reverse(str) /* return a pointer to a + } + + char * +-Uppercase(str) /* return a pointer to an uppercase */ ++Uppercase(str, area) /* return a pointer to an uppercase */ + register char *str; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + while (*str) + { +@@ -115,11 +115,11 @@ Uppercase(str) /* return a pointer to + } + + char * +-Lowercase(str) /* return a pointer to an lowercase */ ++Lowercase(str, area) /* return a pointer to an lowercase */ + register char *str; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + while (*str) + { +@@ -132,11 +132,11 @@ Lowercase(str) /* return a pointer to + } + + char * +-Capitalise(str) /* return a pointer to an capitalised */ ++Capitalise(str, area) /* return a pointer to an capitalised */ + register char *str; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + + while (*str) +@@ -151,11 +151,11 @@ Capitalise(str) /* return a pointer to + } + + char * +-Pluralise(string) /* returns a pointer to a plural */ ++Pluralise(string, area) /* returns a pointer to a plural */ + register char *string; ++ char *area; + { + register int length; +- static char area[STRINGSIZE]; + length = strlen(string); + strcpy(area, string); + +@@ -192,13 +192,13 @@ Pluralise(string) /* returns a pointer + } + + char * +-Substitute(string, old, new) /* returns pointer to a swapped about copy */ ++Substitute(string, old, new, area) /* returns pointer to a swapped about copy */ + register char *string; + register char old; + register char new; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + while (*string) + { +@@ -210,12 +210,12 @@ Substitute(string, old, new) /* returns + } + + char * +-Purge(string, target) /* returns pointer to a purged copy */ ++Purge(string, target, area) /* returns pointer to a purged copy */ + register char *string; + register char target; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + while (*string) + { +@@ -372,13 +372,13 @@ PolyStrchr(string, class) + } + + char * +-PolySubst(string, class, new) /* returns pointer to a swapped about copy */ ++PolySubst(string, class, new, area) /* returns pointer to a swapped about copy */ + register char *string; + register char class; + register char new; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + while (*string) + { +@@ -390,12 +390,12 @@ PolySubst(string, class, new) /* returns + } + + char * +-PolyPurge(string, class) /* returns pointer to a purged copy */ ++PolyPurge(string, class, area) /* returns pointer to a purged copy */ + register char *string; + register char class; ++ char *area; + { + register char *ptr; +- static char area[STRINGSIZE]; + ptr = area; + while (*string) + { +@@ -428,40 +428,41 @@ Char2Int(character) + } + + char * +-Mangle(input, control) /* returns a pointer to a controlled Mangle */ ++Mangle(input, control, area) /* returns a pointer to a controlled Mangle */ + char *input; + char *control; ++ char *area; + { + int limit; + register char *ptr; +- static char area[STRINGSIZE]; + char area2[STRINGSIZE]; + area[0] = '\0'; + strcpy(area, input); + + for (ptr = control; *ptr; ptr++) + { ++ strcpy(area2, area); + switch (*ptr) + { + case RULE_NOOP: + break; + case RULE_REVERSE: +- strcpy(area, Reverse(area)); ++ Reverse(area2, area); + break; + case RULE_UPPERCASE: +- strcpy(area, Uppercase(area)); ++ Uppercase(area2, area); + break; + case RULE_LOWERCASE: +- strcpy(area, Lowercase(area)); ++ Lowercase(area2, area); + break; + case RULE_CAPITALISE: +- strcpy(area, Capitalise(area)); ++ Capitalise(area2, area); + break; + case RULE_PLURALISE: +- strcpy(area, Pluralise(area)); ++ Pluralise(area2, area); + break; + case RULE_REFLECT: +- strcat(area, Reverse(area)); ++ strcat(area, Reverse(area, area2)); + break; + case RULE_DUPLICATE: + strcpy(area2, area); +@@ -548,7 +549,6 @@ Mangle(input, control) /* returns a poi + Debug(1, "Mangle: extract: weird argument in '%s'\n", control); + return NULL; + } +- strcpy(area2, area); + for (i = 0; length-- && area2[start + i]; i++) + { + area[i] = area2[start + i]; +@@ -619,10 +619,10 @@ Mangle(input, control) /* returns a poi + return NULL; + } else if (ptr[1] != RULE_CLASS) + { +- strcpy(area, Purge(area, *(++ptr))); ++ Purge(area2, *(++ptr), area); + } else + { +- strcpy(area, PolyPurge(area, ptr[2])); ++ PolyPurge(area2, ptr[2], area); + ptr += 2; + } + break; +@@ -633,11 +633,11 @@ Mangle(input, control) /* returns a poi + return NULL; + } else if (ptr[1] != RULE_CLASS) + { +- strcpy(area, Substitute(area, ptr[1], ptr[2])); ++ Substitute(area2, ptr[1], ptr[2], area); + ptr += 2; + } else + { +- strcpy(area, PolySubst(area, ptr[2], ptr[3])); ++ PolySubst(area2, ptr[2], ptr[3], area); + ptr += 3; + } + break; diff --git a/cracklib-2.9.6-simplistic.patch b/cracklib-2.9.6-simplistic.patch new file mode 100644 index 0000000..650b103 --- /dev/null +++ b/cracklib-2.9.6-simplistic.patch @@ -0,0 +1,112 @@ +diff -up cracklib-2.9.6/lib/fascist.c.simplistic cracklib-2.9.6/lib/fascist.c +--- cracklib-2.9.6/lib/fascist.c.simplistic 2015-10-22 18:21:51.099748012 +0200 ++++ cracklib-2.9.6/lib/fascist.c 2015-10-22 18:21:51.101748060 +0200 +@@ -55,7 +55,6 @@ static char *r_destructors[] = { + + "/?p@?p", /* purging out punctuation/symbols/junk */ + "/?s@?s", +- "/?X@?X", + + /* attempt reverse engineering of password strings */ + +@@ -454,6 +453,12 @@ GTry(rawtext, password) + continue; + } + ++ if (len - strlen(mp) >= 3) ++ { ++ /* purged too much */ ++ continue; ++ } ++ + #ifdef DEBUG + printf("%-16s = %-16s (destruct %s)\n", mp, rawtext, r_destructors[i]); + #endif +@@ -480,6 +485,12 @@ GTry(rawtext, password) + continue; + } + ++ if (len - strlen(mp) >= 3) ++ { ++ /* purged too much */ ++ continue; ++ } ++ + #ifdef DEBUG + printf("%-16s = %-16s (construct %s)\n", mp, password, r_constructors[i]); + #endif +@@ -699,6 +710,7 @@ FascistLookUser(PWDICT *pwp, char *instr + char rpassword[STRINGSIZE]; + char area[STRINGSIZE]; + uint32_t notfound; ++ int len; + + notfound = PW_WORDS(pwp); + /* already truncated if from FascistCheck() */ +@@ -748,6 +760,7 @@ FascistLookUser(PWDICT *pwp, char *instr + return _("it is all whitespace"); + } + ++ len = strlen(password); + i = 0; + ptr = password; + while (ptr[0] && ptr[1]) +@@ -759,10 +772,9 @@ FascistLookUser(PWDICT *pwp, char *instr + ptr++; + } + +- /* Change by Ben Karsin from ITS at University of Hawaii at Manoa. Static MAXSTEP +- would generate many false positives for long passwords. */ +- maxrepeat = 3+(0.09*strlen(password)); +- if (i > maxrepeat) ++ /* We were still generating false positives for long passwords. ++ Just count systematic double as a single character. */ ++ if (len - i < MINLEN) + { + return _("it is too simplistic/systematic"); + } +@@ -795,6 +807,12 @@ FascistLookUser(PWDICT *pwp, char *instr + continue; + } + ++ if (len - strlen(a) >= 3) ++ { ++ /* purged too much */ ++ continue; ++ } ++ + #ifdef DEBUG + printf("%-16s (dict)\n", a); + #endif +@@ -815,6 +833,13 @@ FascistLookUser(PWDICT *pwp, char *instr + { + continue; + } ++ ++ if (len - strlen(a) >= 3) ++ { ++ /* purged too much */ ++ continue; ++ } ++ + #ifdef DEBUG + printf("%-16s (reversed dict)\n", a); + #endif +diff -up cracklib-2.9.6/util/cracklib-format.simplistic cracklib-2.9.6/util/cracklib-format +--- cracklib-2.9.6/util/cracklib-format.simplistic 2015-10-22 18:21:51.101748060 +0200 ++++ cracklib-2.9.6/util/cracklib-format 2014-07-09 17:24:45.000000000 +0200 +@@ -3,8 +3,10 @@ + # This preprocesses a set of word lists into a suitable form for input + # into cracklib-packer + # ++LC_ALL=C ++export LC_ALL + gzip -cdf "$@" | +- grep -v '^\(#\|$\)' | +- tr '[A-Z]' '[a-z]' | +- tr -cd '\012[a-z][0-9]' | +- env LC_ALL=C sort -u ++ grep -a -E -v '^.{30,}$' | ++ tr '[:upper:]' '[:lower:]' | ++ tr -cd '\n[:graph:]' | ++ sort -u diff --git a/cracklib-2.9.6.tar.gz b/cracklib-2.9.6.tar.gz new file mode 100644 index 0000000..bc5a474 Binary files /dev/null and b/cracklib-2.9.6.tar.gz differ diff --git a/cracklib-words-2.9.6.gz b/cracklib-words-2.9.6.gz new file mode 100644 index 0000000..67173dc Binary files /dev/null and b/cracklib-words-2.9.6.gz differ diff --git a/cracklib.spec b/cracklib.spec new file mode 100644 index 0000000..eb89595 --- /dev/null +++ b/cracklib.spec @@ -0,0 +1,149 @@ +%define dictdir %{_datadir}/cracklib +%define dictpath %{dictdir}/pw_dict + +Name: cracklib +Version: 2.9.6 +Release: 17 +Summary: A password-checking library + +License: LGPLv2+ +URL: http://sourceforge.net/projects/cracklib/ +Source0: https://github.com/cracklib/cracklib/releases/download/cracklib-%{version}/cracklib-%{version}.tar.gz +Source1: https://github.com/cracklib/cracklib/releases/download/cracklib-%{version}/cracklib-words-%{version}.gz +Source10: missing-words.gz + +Patch1: cracklib-2.9.1-inttypes.patch +Patch2: cracklib-2.9.0-python-gzdicts.patch +Patch4: cracklib-2.9.6-packlib-reentrant.patch +Patch6: cracklib-2.9.6-simplistic.patch +Patch8: cracklib-2.9.6-cve-2016-6318.patch + +Patch6001: Fix-build-on-illumos-pwp-dfp-is-void-and-should-be-c.patch +Patch6002: Fix-a-buffer-overflow-processing-long-words.patch +Patch6003: Fix-distdifference.patch + +Patch9000: bugfix-cracklib-format.patch + +BuildRequires: gcc, words, gettext, gettext-autopoint, zlib-devel +BuildRequires: python2-devel +Conflicts: cracklib-dicts < 2.8 +Requires: gzip + +Provides: cracklib-dicts +Provides: %{name}-python = %{version}-%{release} +Provides: %{name}-python%{?_isa} = %{version}-%{release} +Obsoletes: cracklib-dicts +Obsoletes: %{name}-python < %{version}-%{release} + +%description +CrackLib tests passwords to determine whether they match certain +security-oriented characteristics, with the purpose of preventing users +from choosing passwords that could easily be guessed. + +CrackLib is a library containing a C function which may be used in a +"passwd"-like program. If you install CrackLib, you will also want to +install the cracklib-dicts package. + +%package devel +Summary: Development files for %{name} +Requires: %{name} = %{version}-%{release} + +%description devel +The cracklib-devel package contains the header files and libraries needed +for compiling applications which use cracklib. + +%package_help + +%package -n python2-cracklib +Summary: Python 2 bindings for applications which use cracklib +Requires: %{name} = %{version}-%{release} + +%description -n python2-cracklib +The python2-cracklib package contains a module which permits applications +written in the Python 2 programming language to use cracklib. + +%prep +%autosetup -n %{name}-%{version} -p1 + +mkdir cracklib-dicts +for dict in %{SOURCE10} %{SOURCE1} +do + cp -fv ${dict} cracklib-dicts/ +done +chmod +x util/cracklib-format + +%build +sed -i 's,util/cracklib-check <,util/cracklib-check $(DESTDIR)/$(DEFAULT_CRACKLIB_DICT) <,' Makefile.in +%configure \ + --disable-static \ + --with-pic \ + --with-python \ + --with-default-dict=%{dictpath} +make -C po update-gmo +make + +%install +[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT 'pythondir=${pyexecdir}' +./util/cracklib-format cracklib-dicts/* | \ +./util/cracklib-packer $RPM_BUILD_ROOT/%{dictpath} +./util/cracklib-format $RPM_BUILD_ROOT/%{dictdir}/cracklib-small | \ +./util/cracklib-packer $RPM_BUILD_ROOT/%{dictdir}/cracklib-small +rm -f $RPM_BUILD_ROOT/%{dictdir}/cracklib-small +sed s,/usr/lib/cracklib_dict,%{dictpath},g lib/crack.h > $RPM_BUILD_ROOT/%{_includedir}/crack.h +ln -s cracklib-format $RPM_BUILD_ROOT/%{_sbindir}/mkdict +ln -s cracklib-packer $RPM_BUILD_ROOT/%{_sbindir}/packer +touch $RPM_BUILD_ROOT/top + +toprelpath=.. +touch $RPM_BUILD_ROOT/top +while ! test -f $RPM_BUILD_ROOT/%{_libdir}/$toprelpath/top ; do + toprelpath=../$toprelpath +done +rm -f $RPM_BUILD_ROOT/top +if test %{dictpath} != %{_libdir}/cracklib_dict ; then +ln -s $toprelpath%{dictpath}.hwm $RPM_BUILD_ROOT/%{_libdir}/cracklib_dict.hwm +ln -s $toprelpath%{dictpath}.pwd $RPM_BUILD_ROOT/%{_libdir}/cracklib_dict.pwd +ln -s $toprelpath%{dictpath}.pwi $RPM_BUILD_ROOT/%{_libdir}/cracklib_dict.pwi +fi +rm -f $RPM_BUILD_ROOT/%{_libdir}/python*/site-packages/_cracklib*.*a +rm -f $RPM_BUILD_ROOT/%{_libdir}/libcrack.la + +%find_lang %{name} + +%check +make test + +%ldconfig_scriptlets + +%files -f %{name}.lang +%defattr(-,root,root) +%doc README-LICENSE AUTHORS +%license COPYING.LIB +%{_sbindir}/*cracklib* +%{_sbindir}/mkdict +%{_sbindir}/packer +%{_libdir}/libcrack.so.* +%{_libdir}/cracklib_dict.* +%dir %{_datadir}/cracklib +%{_datadir}/cracklib/pw_dict.* +%{_datadir}/cracklib/cracklib-small.* +%{_datadir}/cracklib/cracklib.magic + +%files devel +%{_includedir}/* +%{_libdir}/libcrack.so + +%files help +%doc README README-WORDS NEWS + +%files -n python2-cracklib +%{_libdir}/python*/site-packages/_cracklib*.so +%{_libdir}/python*/site-packages/*.py* + +%changelog +* Fri Sep 27 2019 openEuler Buildteam - 2.9.7-17 +- Add python2-cracklib package + +* Fri Sep 20 2019 openEuler Buildteam - 2.9.7-16 +- Package init diff --git a/missing-words.gz b/missing-words.gz new file mode 100644 index 0000000..3503e00 Binary files /dev/null and b/missing-words.gz differ