17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5004388ebScasper * Common Development and Distribution License (the "License").
6004388ebScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*4a7ceb24Sjjj * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include "packer.h"
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * This file steers the creation of the Crack Dictionary Database.
327c478bd9Sstevel@tonic-gate * Based on a list of source dictionaries specified by the administrator,
337c478bd9Sstevel@tonic-gate * we create the Database by sorting each dictionary (in memory, one at
347c478bd9Sstevel@tonic-gate * a time), writing the sorted result to a temporary file, and merging
357c478bd9Sstevel@tonic-gate * all the temporary files into the Database.
367c478bd9Sstevel@tonic-gate *
377c478bd9Sstevel@tonic-gate * The current implementation has a number of limitations
387c478bd9Sstevel@tonic-gate * - each single source dictionary has to fit in memory
397c478bd9Sstevel@tonic-gate * - each single source dictionary has to be smaller than 2GByte
407c478bd9Sstevel@tonic-gate * - each single source dictionary can only hold up to 4GB words
417c478bd9Sstevel@tonic-gate * None of these seem real, practical, problems to me.
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * All of this is meant to be run by one thread per host. The caller is
447c478bd9Sstevel@tonic-gate * responsible for locking things appropriately (as make_dict_database
457c478bd9Sstevel@tonic-gate * in dict.c does).
467c478bd9Sstevel@tonic-gate */
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #include <stdio.h>
497c478bd9Sstevel@tonic-gate #include <stdlib.h>
507c478bd9Sstevel@tonic-gate #include <unistd.h>
517c478bd9Sstevel@tonic-gate #include <ctype.h>
527c478bd9Sstevel@tonic-gate #include <string.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <sys/stat.h>
557c478bd9Sstevel@tonic-gate #include <fcntl.h>
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate /* Stuff used for sorting the dictionary */
587c478bd9Sstevel@tonic-gate static char *buf; /* used to hold the source dictionary */
597c478bd9Sstevel@tonic-gate static uint_t *offsets; /* array of word-offsets into "buf" */
607c478bd9Sstevel@tonic-gate static uint_t off_idx = 0; /* first free index in offsets array */
617c478bd9Sstevel@tonic-gate static size_t off_size = 0; /* offsets array size */
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate /* stuff to keep track of the temporary files */
647c478bd9Sstevel@tonic-gate #define FNAME_TEMPLATE "/var/tmp/authtok_check.XXXXXX"
657c478bd9Sstevel@tonic-gate #define MAXTMP 64
667c478bd9Sstevel@tonic-gate static FILE *tmpfp[MAXTMP]; /* FILE *'s to (unlinked) temporary files */
677c478bd9Sstevel@tonic-gate static int tmpfp_idx = 0; /* points to first free entry in tmpfp */
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate #define MODNAME "pam_authtok_check::packer"
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate * int writeout(void)
737c478bd9Sstevel@tonic-gate *
747c478bd9Sstevel@tonic-gate * Write the sorted wordlist to disk. We create a temporary file
757c478bd9Sstevel@tonic-gate * (in /var/tmp), and immediately unlink() it. We keep an open
767c478bd9Sstevel@tonic-gate * FILE pointer to it in tmpfp[] for later use.
777c478bd9Sstevel@tonic-gate *
787c478bd9Sstevel@tonic-gate * returns 0 on success, -1 on failure (can't create file/output failure).
797c478bd9Sstevel@tonic-gate */
807c478bd9Sstevel@tonic-gate int
writeout(void)817c478bd9Sstevel@tonic-gate writeout(void)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate int i = 0;
847c478bd9Sstevel@tonic-gate char tmpname[sizeof (FNAME_TEMPLATE)];
857c478bd9Sstevel@tonic-gate int fd;
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate if (tmpfp_idx == MAXTMP) {
887c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": too many temporary "
897c478bd9Sstevel@tonic-gate "files (maximum %d exceeded)", MAXTMP);
907c478bd9Sstevel@tonic-gate return (-1);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate (void) strcpy(tmpname, FNAME_TEMPLATE);
947c478bd9Sstevel@tonic-gate if ((fd = mkstemp(tmpname)) == -1) {
957c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": mkstemp() failed: %s\n",
967c478bd9Sstevel@tonic-gate strerror(errno));
977c478bd9Sstevel@tonic-gate return (-1);
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate (void) unlink(tmpname);
1007c478bd9Sstevel@tonic-gate
101004388ebScasper if ((tmpfp[tmpfp_idx] = fdopen(fd, "w+F")) == NULL) {
1027c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": fdopen failed: %s",
1037c478bd9Sstevel@tonic-gate strerror(errno));
1047c478bd9Sstevel@tonic-gate (void) close(fd);
1057c478bd9Sstevel@tonic-gate return (-1);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate /* write words to file */
1097c478bd9Sstevel@tonic-gate while (i < off_idx) {
1107c478bd9Sstevel@tonic-gate if (fprintf(tmpfp[tmpfp_idx], "%s\n", &buf[offsets[i++]]) < 0) {
1117c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": write to file failed: %s",
1127c478bd9Sstevel@tonic-gate strerror(errno));
1137c478bd9Sstevel@tonic-gate (void) close(fd);
1147c478bd9Sstevel@tonic-gate return (-1);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /* we have one extra tmpfp */
1197c478bd9Sstevel@tonic-gate tmpfp_idx++;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate return (0);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate * int insert_word(int off)
1267c478bd9Sstevel@tonic-gate *
1277c478bd9Sstevel@tonic-gate * insert an offset into the offsets-array. If the offsets-array is out of
1287c478bd9Sstevel@tonic-gate * space, we allocate additional space (in CHUNKs)
1297c478bd9Sstevel@tonic-gate *
1307c478bd9Sstevel@tonic-gate * returns 0 on success, -1 on failure (out of memory)
1317c478bd9Sstevel@tonic-gate */
1327c478bd9Sstevel@tonic-gate int
insert_word(int off)1337c478bd9Sstevel@tonic-gate insert_word(int off)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate #define CHUNK 10000
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate if (off_idx == off_size) {
1387c478bd9Sstevel@tonic-gate uint_t *tmp;
1397c478bd9Sstevel@tonic-gate off_size += CHUNK;
1407c478bd9Sstevel@tonic-gate tmp = realloc(offsets, sizeof (uint_t) * off_size);
1417c478bd9Sstevel@tonic-gate if (tmp == NULL) {
1427c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": out of memory");
1437c478bd9Sstevel@tonic-gate free(offsets);
1447c478bd9Sstevel@tonic-gate off_idx = off_size = 0;
1457c478bd9Sstevel@tonic-gate offsets = NULL;
1467c478bd9Sstevel@tonic-gate return (-1);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate offsets = tmp;
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate offsets[off_idx++] = off;
1527c478bd9Sstevel@tonic-gate return (0);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate * translate(buf, size)
1577c478bd9Sstevel@tonic-gate *
1587c478bd9Sstevel@tonic-gate * perform "tr '[A-Z]' '[a-z]' | tr -cd '\012[a-z][0-9]'" on the
1597c478bd9Sstevel@tonic-gate * words in "buf" and insert each of them into the offsets-array.
1607c478bd9Sstevel@tonic-gate * We refrain from using 'isupper' and 'islower' to keep this strictly
1617c478bd9Sstevel@tonic-gate * ASCII-only, as is the original Cracklib code.
1627c478bd9Sstevel@tonic-gate *
1637c478bd9Sstevel@tonic-gate * returns 0 on success, -1 on failure (failure of insert_word)
1647c478bd9Sstevel@tonic-gate */
1657c478bd9Sstevel@tonic-gate int
translate(char * buf,size_t size)1667c478bd9Sstevel@tonic-gate translate(char *buf, size_t size)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate char *p, *q, *e;
1697c478bd9Sstevel@tonic-gate char c;
1707c478bd9Sstevel@tonic-gate int wordstart;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate e = &buf[size];
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate wordstart = 0;
1757c478bd9Sstevel@tonic-gate for (p = buf, q = buf; q < e; q++) {
1767c478bd9Sstevel@tonic-gate c = *q;
1777c478bd9Sstevel@tonic-gate if (c >= 'A' && c <= 'Z') {
1787c478bd9Sstevel@tonic-gate *(p++) = tolower(c);
1797c478bd9Sstevel@tonic-gate } else if (c == '\n') {
1807c478bd9Sstevel@tonic-gate *(p++) = '\0';
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * make sure we only insert words consisting of
1837c478bd9Sstevel@tonic-gate * MAXWORDLEN-1 bytes or less
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate if (p-&buf[wordstart] > MAXWORDLEN)
1867c478bd9Sstevel@tonic-gate buf[wordstart+MAXWORDLEN-1] = '\0';
1877c478bd9Sstevel@tonic-gate if (insert_word(wordstart) != 0)
1887c478bd9Sstevel@tonic-gate return (-1);
1897c478bd9Sstevel@tonic-gate wordstart = p-buf;
1907c478bd9Sstevel@tonic-gate } else if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
1917c478bd9Sstevel@tonic-gate *(p++) = c;
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate return (0);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate * int compare(a, b)
1997c478bd9Sstevel@tonic-gate *
2007c478bd9Sstevel@tonic-gate * helper-routine used for quicksort. we compate two words in the
2017c478bd9Sstevel@tonic-gate * buffer, one start starts at index "a", and the other one that starts
2027c478bd9Sstevel@tonic-gate * at index "b"
2037c478bd9Sstevel@tonic-gate */
2047c478bd9Sstevel@tonic-gate int
compare(const void * a,const void * b)2057c478bd9Sstevel@tonic-gate compare(const void *a, const void *b)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate int idx_a = *(uint_t *)a, idx_b = *(uint_t *)b;
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate return (strcmp(&buf[idx_a], &buf[idx_b]));
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate *
2147c478bd9Sstevel@tonic-gate * int sort_file(fname)
2157c478bd9Sstevel@tonic-gate *
2167c478bd9Sstevel@tonic-gate * We sort the file in memory: we read the dictionary file, translate all
2177c478bd9Sstevel@tonic-gate * newlines to '\0's, all uppercase ASCII characters to lowercase characters
2187c478bd9Sstevel@tonic-gate * and removing all characters but '[a-z][0-9]'.
2197c478bd9Sstevel@tonic-gate * We maintain an array of offsets into the buffer where each word starts
2207c478bd9Sstevel@tonic-gate * and sort this array using qsort().
2217c478bd9Sstevel@tonic-gate *
2227c478bd9Sstevel@tonic-gate * This implements the original cracklib code that did an execl of
2237c478bd9Sstevel@tonic-gate * sh -c "/usr/bin/cat <list of files> |
2247c478bd9Sstevel@tonic-gate * /usr/bin/tr '[A-Z]' '[a-z]' | /usr/bin/tr -cd '\012[a-z][0-9]' |
2257c478bd9Sstevel@tonic-gate * sort -o tmfpfile
2267c478bd9Sstevel@tonic-gate *
2277c478bd9Sstevel@tonic-gate * returns 0 on success, -1 on failure.
2287c478bd9Sstevel@tonic-gate */
2297c478bd9Sstevel@tonic-gate int
sort_file(char * fname)2307c478bd9Sstevel@tonic-gate sort_file(char *fname)
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate int fd;
2337c478bd9Sstevel@tonic-gate struct stat statbuf;
2347c478bd9Sstevel@tonic-gate ssize_t n;
2357c478bd9Sstevel@tonic-gate int ret = -1;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate if ((fd = open(fname, O_RDONLY)) == -1) {
2387c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": failed to open %s: %s",
2397c478bd9Sstevel@tonic-gate fname, strerror(errno));
2407c478bd9Sstevel@tonic-gate return (-1);
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate if (fstat(fd, &statbuf) == -1) {
2447c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": fstat() failed (%s)",
2457c478bd9Sstevel@tonic-gate strerror(errno));
2467c478bd9Sstevel@tonic-gate (void) close(fd);
2477c478bd9Sstevel@tonic-gate return (-1);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate if ((buf = malloc(statbuf.st_size + 1)) == NULL) {
2507c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": out of memory");
2517c478bd9Sstevel@tonic-gate goto error;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate n = read(fd, buf, statbuf.st_size);
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate if (n == -1) {
2577c478bd9Sstevel@tonic-gate if (errno == EINVAL)
2587c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": %s is too big. "
2597c478bd9Sstevel@tonic-gate "Split the file into smaller files.", fname);
2607c478bd9Sstevel@tonic-gate else
2617c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": read failed: %s",
2627c478bd9Sstevel@tonic-gate strerror(errno));
2637c478bd9Sstevel@tonic-gate goto error;
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate if (translate(buf, n) == 0) {
2677c478bd9Sstevel@tonic-gate qsort((void *)offsets, off_idx, sizeof (int), compare);
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate if (writeout() == 0)
2707c478bd9Sstevel@tonic-gate ret = 0;
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate error:
2747c478bd9Sstevel@tonic-gate (void) close(fd);
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate if (buf != NULL)
2777c478bd9Sstevel@tonic-gate free(buf);
2787c478bd9Sstevel@tonic-gate if (offsets != NULL)
2797c478bd9Sstevel@tonic-gate free(offsets);
2807c478bd9Sstevel@tonic-gate offsets = NULL;
2817c478bd9Sstevel@tonic-gate off_size = 0;
2827c478bd9Sstevel@tonic-gate off_idx = 0;
2837c478bd9Sstevel@tonic-gate return (ret);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate * We merge the temporary files created by previous calls to sort_file()
2887c478bd9Sstevel@tonic-gate * and insert the thus sorted words into the cracklib database
289*4a7ceb24Sjjj *
290*4a7ceb24Sjjj * returns 0 on success, -1 on failure.
2917c478bd9Sstevel@tonic-gate */
292*4a7ceb24Sjjj int
merge_files(PWDICT * pwp)2937c478bd9Sstevel@tonic-gate merge_files(PWDICT *pwp)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate int ti;
2967c478bd9Sstevel@tonic-gate char *words[MAXTMP];
2977c478bd9Sstevel@tonic-gate char lastword[MAXWORDLEN];
2987c478bd9Sstevel@tonic-gate int choice;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate lastword[0] = '\0';
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate for (ti = 0; ti < tmpfp_idx; ti++)
303*4a7ceb24Sjjj if ((words[ti] = malloc(MAXWORDLEN)) == NULL) {
304*4a7ceb24Sjjj while (--ti >= 0)
305*4a7ceb24Sjjj free(words[ti]);
306*4a7ceb24Sjjj return (-1);
307*4a7ceb24Sjjj }
308*4a7ceb24Sjjj
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * we read the first word of each of the temp-files into words[].
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate for (ti = 0; ti < tmpfp_idx; ti++) {
3137c478bd9Sstevel@tonic-gate (void) fseek(tmpfp[ti], 0, SEEK_SET);
3147c478bd9Sstevel@tonic-gate (void) fgets(words[ti], MAXWORDLEN, tmpfp[ti]);
3157c478bd9Sstevel@tonic-gate words[ti][MAXWORDLEN-1] = '\0';
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate * next, we emit the word that comes first (lexicographically),
3207c478bd9Sstevel@tonic-gate * and replace that word with a new word from the file it
3217c478bd9Sstevel@tonic-gate * came from. If the file is exhausted, we close the fp and
3227c478bd9Sstevel@tonic-gate * swap the fp with the last fp in tmpfp[].
3237c478bd9Sstevel@tonic-gate * we then decrease tmpfp_idx and continue with what's left until
3247c478bd9Sstevel@tonic-gate * we run out of open FILE pointers.
3257c478bd9Sstevel@tonic-gate */
3267c478bd9Sstevel@tonic-gate while (tmpfp_idx != 0) {
3277c478bd9Sstevel@tonic-gate choice = 0;
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate for (ti = 1; ti < tmpfp_idx; ti++)
3307c478bd9Sstevel@tonic-gate if (strcmp(words[choice], words[ti]) > 0)
3317c478bd9Sstevel@tonic-gate choice = ti;
3327c478bd9Sstevel@tonic-gate /* Insert word in Cracklib database */
3337c478bd9Sstevel@tonic-gate (void) Chomp(words[choice]);
3347c478bd9Sstevel@tonic-gate if (words[choice][0] != '\0' &&
3357c478bd9Sstevel@tonic-gate strcmp(lastword, words[choice]) != 0) {
3367c478bd9Sstevel@tonic-gate (void) PutPW(pwp, words[choice]);
3377c478bd9Sstevel@tonic-gate (void) strncpy(lastword, words[choice], MAXWORDLEN);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate if (fgets(words[choice], MAXWORDLEN, tmpfp[choice]) == NULL) {
3417c478bd9Sstevel@tonic-gate (void) fclose(tmpfp[choice]);
3427c478bd9Sstevel@tonic-gate tmpfp[choice] = tmpfp[tmpfp_idx - 1];
3437c478bd9Sstevel@tonic-gate tmpfp_idx--;
3447c478bd9Sstevel@tonic-gate } else
3457c478bd9Sstevel@tonic-gate words[choice][MAXWORDLEN-1] = '\0';
3467c478bd9Sstevel@tonic-gate }
347*4a7ceb24Sjjj return (0);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate /*
3517c478bd9Sstevel@tonic-gate * int packer(list)
3527c478bd9Sstevel@tonic-gate *
3537c478bd9Sstevel@tonic-gate * sort all dictionaries in "list", and feed the words into the Crack
3547c478bd9Sstevel@tonic-gate * Password Database.
3557c478bd9Sstevel@tonic-gate *
3567c478bd9Sstevel@tonic-gate * returns 0 on sucess, -1 on failure.
3577c478bd9Sstevel@tonic-gate */
3587c478bd9Sstevel@tonic-gate int
packer(char * list,char * path)3597c478bd9Sstevel@tonic-gate packer(char *list, char *path)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate PWDICT *pwp;
3627c478bd9Sstevel@tonic-gate char *listcopy, *fname;
3637c478bd9Sstevel@tonic-gate int ret = 0;
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate if ((listcopy = strdup(list)) == NULL) {
3667c478bd9Sstevel@tonic-gate syslog(LOG_ERR, MODNAME ": out of memory");
3677c478bd9Sstevel@tonic-gate return (-1);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate
370004388ebScasper if (!(pwp = PWOpen(path, "wF")))
3717c478bd9Sstevel@tonic-gate return (-1);
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate fname = strtok(listcopy, " \t,");
3747c478bd9Sstevel@tonic-gate while (ret == 0 && fname != NULL) {
3757c478bd9Sstevel@tonic-gate if ((ret = sort_file(fname)) == 0)
3767c478bd9Sstevel@tonic-gate fname = strtok(NULL, " \t,");
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate free(listcopy);
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate if (ret == 0)
381*4a7ceb24Sjjj ret = merge_files(pwp);
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate (void) PWClose(pwp);
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate return (ret);
3867c478bd9Sstevel@tonic-gate }
387