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 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 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 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 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 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 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 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