void do_regex_crack(struct db_main *db, const char *regex) { c_simplestring_ptr buffer = c_simplestring_new(); c_iterator_ptr iter = NULL; charset encoding = CHARSET_UTF8; int ignore_case = 0; char word[WORDSIZE]; if (john_main_process) fprintf(stderr, "Warning: regex mode currently can't be " "resumed if aborted\n"); rexgen_setlocale(); status_init(&get_progress, 0); rec_restore_mode(restore_state); rec_init(db, save_state); crk_init(db, fix_state, NULL); iter = c_regex_iterator_cb(regex, ignore_case, encoding, callback); if (!iter) { fprintf(stderr, "Error, invalid regex expression. John exiting now\n"); exit(1); } while (c_iterator_next(iter)) { c_iterator_value(iter, buffer); c_simplestring_to_binary_string(buffer, &word[0], sizeof(word)); c_simplestring_clear(buffer); if (ext_filter((char*)word)) { if (crk_process_key((char*)word)) break; } } c_simplestring_delete(buffer); c_iterator_delete(iter); crk_done(); rec_done(event_abort); }
static void john_mpi_wait(void) { if (!database.password_count && !options.reload_at_crack) { int i; for (i = 0; i < mpi_p; i++) { if (i == mpi_id) continue; if (mpi_req[i] == NULL) mpi_req[i] = mem_alloc_tiny(sizeof(MPI_Request), MEM_ALIGN_WORD); else if (*mpi_req[i] != MPI_REQUEST_NULL) continue; MPI_Isend("r", 1, MPI_CHAR, i, JOHN_MPI_RELOAD, MPI_COMM_WORLD, mpi_req[i]); } } if (john_main_process) { log_event("Waiting for other node%s to terminate", mpi_p > 2 ? "s" : ""); fprintf(stderr, "Waiting for other node%s to terminate\n", mpi_p > 2 ? "s" : ""); mpi_teardown(); } /* Close and possibly remove our .rec file now */ rec_done(!event_abort ? -1 : -2); }
static void john_omp_fallback(char **argv) { if (!getenv("JOHN_NO_OMP_FALLBACK") && john_omp_threads_new <= 1) { rec_done(-2); #define OMP_FALLBACK_PATHNAME JOHN_SYSTEMWIDE_EXEC "/" OMP_FALLBACK_BINARY execv(OMP_FALLBACK_PATHNAME, argv); perror("execv: " OMP_FALLBACK_PATHNAME); } }
void rec_init(struct db_main *db, void (*save_mode)(FILE *file)) { rec_done(1); if (!rec_argc) return; rec_name_complete(); if ((rec_fd = open(path_expand(rec_name), O_RDWR | O_CREAT, 0600)) < 0) pexit("open: %s", path_expand(rec_name)); rec_lock(); if (!(rec_file = fdopen(rec_fd, "w"))) pexit("fdopen"); rec_db = db; rec_save_mode = save_mode; }
void do_external_crack(struct db_main *db) { unsigned char *internal; c_int *external; log_event("Proceeding with external mode: %.100s", ext_mode); if (!f_generate) { log_event("! No generate() function defined"); fprintf(stderr, "No generate() for external mode: %s\n", ext_mode); error(); } internal = (unsigned char *)int_word; external = ext_word; while (*external) *internal++ = *external++; *internal = 0; status_init(NULL, 0); rec_restore_mode(restore_state); rec_init(db, save_state); crk_init(db, fix_state, NULL); do { c_execute(f_generate); if (!ext_word[0]) break; c_execute(f_filter); if (!ext_word[0]) continue; internal = (unsigned char *)int_word; external = ext_word; while (*external) *internal++ = *external++; *internal = 0; if (crk_process_key(int_word)) break; } while (1); crk_done(); rec_done(event_abort); }
static void john_wait(void) { int waiting_for = john_child_count; log_event("Waiting for %d child%s to terminate", waiting_for, waiting_for == 1 ? "" : "ren"); log_flush(); fprintf(stderr, "Waiting for %d child%s to terminate\n", waiting_for, waiting_for == 1 ? "" : "ren"); log_flush(); /* Tell our friends there is nothing more to crack! */ if (!database.password_count && !options.reload_at_crack && cfg_get_bool(SECTION_OPTIONS, NULL, "ReloadAtDone", 0)) raise(SIGUSR2); /* * Although we may block on wait(2), we still have signal handlers and a timer * in place, so we're relaying keypresses to child processes via signals. */ while (waiting_for) { int i, status; int pid = wait(&status); if (pid == -1) { if (errno != EINTR) perror("wait"); } else for (i = 0; i < john_child_count; i++) { if (john_child_pids[i] == pid) { john_child_pids[i] = 0; waiting_for--; children_ok = children_ok && WIFEXITED(status) && !WEXITSTATUS(status); break; } } } /* Close and possibly remove our .rec file now */ rec_done((children_ok && !event_abort) ? -1 : -2); }
static void single_done(void) { struct db_salt *salt; if (!event_abort) { if ((salt = single_db->salts)) { log_event("- Processing the remaining buffered " "candidate passwords, if any"); do { if (!salt->list) continue; if (salt->keys->count) if (single_process_buffer(salt)) break; } while ((salt = salt->next)); } progress = 100; } rec_done(event_abort || (status.pass && single_db->salts)); }
static void john_set_mpi(void) { options.node_min += mpi_id; options.node_max = options.node_min; if (mpi_p > 1) { if (!john_main_process) { if (rec_restoring_now) { unsigned int node_id = options.node_min; rec_done(-2); rec_restore_args(1); if (node_id != options.node_min + mpi_id) fprintf(stderr, "Inconsistent crash recovery file:" " %s\n", rec_name); options.node_min = options.node_max = node_id; } } } fflush(stdout); fflush(stderr); }
void do_external_crack(struct db_main *db) { unsigned char *internal; c_int *external; log_event("Proceeding with external mode: %.100s", ext_mode); #ifdef HAVE_MPI if (mpi_p > 1) log_event("MPI: each node will process 1/%u of candidates", mpi_p); #endif internal = (unsigned char *)int_word; external = ext_word; while (*external) *internal++ = *external++; *internal = 0; status_init(&get_progress, 0); rec_restore_mode(restore_state); rec_init(db, save_state); crk_init(db, fix_state, NULL); do { c_execute_fast(f_generate); if (!ext_word[0]) break; if (f_filter) { c_execute_fast(f_filter); if (!ext_word[0]) continue; } #ifdef HAVE_MPI // MPI distribution if (mpi_line++ % mpi_p != mpi_id) continue; #endif int_word[0] = ext_word[0]; if ((int_word[1] = ext_word[1])) { internal = (unsigned char *)&int_word[2]; external = &ext_word[2]; do { if (!(internal[0] = external[0])) break; if (!(internal[1] = external[1])) break; if (!(internal[2] = external[2])) break; if (!(internal[3] = external[3])) break; internal += 4; external += 4; } while (1); } int_word[maxlen] = 0; if (crk_process_key(int_word)) break; } while (1); if (!event_abort) progress = 100; // For reporting DONE after a no-ETA run crk_done(); rec_done(event_abort); }
void do_wordlist_crack(struct db_main *db, char *name, int rules) { union { char buffer[2][LINE_BUFFER_SIZE + CACHE_BANK_SHIFT]; ARCH_WORD dummy; } aligned; char *line = aligned.buffer[0], *last = aligned.buffer[1]; struct rpp_context ctx; char *prerule, *rule, *word; char *(*apply)(char *word, char *rule, int split, char *last); int dist_rules, dist_switch; unsigned long my_words, their_words, my_words_left; log_event("Proceeding with wordlist mode"); if (name) { if (!(word_file = fopen(path_expand(name), "r"))) pexit("fopen: %s", path_expand(name)); log_event("- Wordlist file: %.100s", path_expand(name)); } else { word_file = stdin; log_event("- Reading candidate passwords from stdin"); } length = db->format->params.plaintext_length; if (rules) { if (rpp_init(rule_ctx = &ctx, SUBSECTION_WORDLIST)) { log_event("! No wordlist mode rules found"); if (john_main_process) fprintf(stderr, "No wordlist mode rules found in %s\n", cfg_name); error(); } rules_init(length); rule_count = rules_count(&ctx, -1); log_event("- %d preprocessed word mangling rules", rule_count); apply = rules_apply; } else { rule_ctx = NULL; rule_count = 1; log_event("- No word mangling rules"); apply = dummy_rules_apply; } rule_number = 0; line_number = 0; status_init(get_progress, 0); rec_restore_mode(restore_state); rec_init(db, save_state); crk_init(db, fix_state, NULL); prerule = rule = ""; if (rules) prerule = rpp_next(&ctx); /* A string that can't be produced by fgetl(). */ last[0] = '\n'; last[1] = 0; dist_rules = 0; dist_switch = rule_count; /* never */ my_words = ~0UL; /* all */ their_words = 0; if (options.node_count) { int rule_rem = rule_count % options.node_count; const char *now, *later = ""; dist_switch = rule_count - rule_rem; if (!rule_rem || rule_number < dist_switch) { dist_rules = 1; now = "rules"; if (rule_rem) later = ", then switch to distributing words"; } else { dist_switch = rule_count; /* never */ my_words = options.node_max - options.node_min + 1; their_words = options.node_count - my_words; now = "words"; } log_event("- Will distribute %s across nodes%s", now, later); } my_words_left = my_words; if (their_words) { if (line_number) { /* Restored session. line_number is right after a word we've actually used. */ int for_node = line_number % options.node_count + 1; if (for_node < options.node_min || for_node > options.node_max) { /* We assume that line_number is at the beginning of other nodes' block */ if (skip_lines(their_words, line) && /* Check for error since a mere EOF means next rule (the loop below should see * the EOF again, and it will skip to next rule if applicable) */ ferror(word_file)) prerule = NULL; } else { my_words_left = options.node_max - for_node + 1; } } else { /* New session. Skip lower-numbered nodes' lines. */ if (skip_lines(options.node_min - 1, line)) prerule = NULL; } } if (prerule) do { if (rules) { if (dist_rules) { int for_node = rule_number % options.node_count + 1; if (for_node < options.node_min || for_node > options.node_max) goto next_rule; } if ((rule = rules_reject(prerule, -1, last, db))) { if (strcmp(prerule, rule)) log_event("- Rule #%d: '%.100s'" " accepted as '%.100s'", rule_number + 1, prerule, rule); else log_event("- Rule #%d: '%.100s'" " accepted", rule_number + 1, prerule); } else { log_event("- Rule #%d: '%.100s' rejected", rule_number + 1, prerule); goto next_rule; } } while (fgetl(line, LINE_BUFFER_SIZE, word_file)) { line_number++; if (line[0] != '#') { process_word: if ((word = apply(line, rule, -1, last))) { last = word; if (ext_filter(word)) if (crk_process_key(word)) { rules = 0; break; } } next_word: if (--my_words_left) continue; if (skip_lines(their_words, line)) break; my_words_left = my_words; continue; } if (strncmp(line, "#!comment", 9)) goto process_word; goto next_word; } if (ferror(word_file)) break; if (rules) { next_rule: if (!(rule = rpp_next(&ctx))) break; rule_number++; if (rule_number >= dist_switch) { log_event("- Switching to distributing words"); dist_rules = 0; dist_switch = rule_count; /* not anymore */ my_words = options.node_max - options.node_min + 1; their_words = options.node_count - my_words; } line_number = 0; if (fseek(word_file, 0, SEEK_SET)) pexit("fseek"); if (their_words && skip_lines(options.node_min - 1, line)) break; } my_words_left = my_words; } while (rules); crk_done(); rec_done(event_abort || (status.pass && db->salts)); if (ferror(word_file)) pexit("fgets"); if (name) { if (event_abort) progress = get_progress(); else progress = 100; if (fclose(word_file)) pexit("fclose"); word_file = NULL; } }
static void john_fork(void) { int i, pid; int *pids; fflush(stdout); fflush(stderr); #if HAVE_MPI /* * We already initialized MPI before knowing this is actually a fork session. * So now we need to tear that "1-node MPI session" down before forking, or * all sorts of funny things might happen. */ mpi_teardown(); #endif /* * It may cost less memory to reset john_main_process to 0 before fork()'ing * the children than to do it in every child process individually (triggering * copy-on-write of the entire page). We then reset john_main_process back to * 1 in the parent, but this only costs one page, not one page per child. */ john_main_process = 0; pids = mem_alloc_tiny((options.fork - 1) * sizeof(*pids), sizeof(*pids)); for (i = 1; i < options.fork; i++) { switch ((pid = fork())) { case -1: pexit("fork"); case 0: sig_preinit(); options.node_min += i; options.node_max = options.node_min; #if HAVE_OPENCL // Poor man's multi-device support if (options.gpu_devices->count && strstr(database.format->params.label, "-opencl")) { // Pick device to use for this child opencl_preinit(); gpu_id = gpu_device_list[i % get_number_of_devices_in_use()]; platform_id = get_platform_id(gpu_id); // Hide any other devices from list gpu_device_list[0] = gpu_id; gpu_device_list[1] = -1; // Postponed format init in forked process fmt_init(database.format); } #endif if (rec_restoring_now) { unsigned int node_id = options.node_min; rec_done(-2); rec_restore_args(1); if (node_id != options.node_min + i) fprintf(stderr, "Inconsistent crash recovery file:" " %s\n", rec_name); options.node_min = options.node_max = node_id; } sig_init_child(); return; default: pids[i - 1] = pid; } } #if HAVE_OPENCL // Poor man's multi-device support if (options.gpu_devices->count && strstr(database.format->params.label, "-opencl")) { // Pick device to use for mother process opencl_preinit(); gpu_id = gpu_device_list[0]; platform_id = get_platform_id(gpu_id); // Hide any other devices from list gpu_device_list[1] = -1; // Postponed format init in mother process fmt_init(database.format); } #endif john_main_process = 1; john_child_pids = pids; john_child_count = options.fork - 1; options.node_max = options.node_min; }
void do_incremental_crack(struct db_main *db, char *mode) { char *charset; int min_length, max_length, max_count; char *extra; FILE *file; struct charset_header *header; unsigned int check; char allchars[CHARSET_SIZE + 1]; char char1[CHARSET_SIZE + 1]; char2_table char2; chars_table chars[CHARSET_LENGTH - 2]; unsigned char *ptr; unsigned int length, fixed, count; unsigned int real_count; int last_length, last_count; int pos; if (!mode) { if (db->format == &fmt_LM) mode = "LanMan"; else if (db->format == &fmt_NETLM) mode = "LanMan"; else if (db->format == &fmt_NETHALFLM) mode = "LanMan"; else mode = "All"; } log_event("Proceeding with \"incremental\" mode: %.100s", mode); if (!(charset = cfg_get_param(SECTION_INC, mode, "File"))) { log_event("! No charset defined"); fprintf(stderr, "No charset defined for mode: %s\n", mode); error(); } extra = cfg_get_param(SECTION_INC, mode, "Extra"); if ((min_length = cfg_get_int(SECTION_INC, mode, "MinLen")) < 0) min_length = 0; if ((max_length = cfg_get_int(SECTION_INC, mode, "MaxLen")) < 0) max_length = CHARSET_LENGTH; max_count = cfg_get_int(SECTION_INC, mode, "CharCount"); if (min_length > max_length) { log_event("! MinLen = %d exceeds MaxLen = %d", min_length, max_length); fprintf(stderr, "MinLen = %d exceeds MaxLen = %d\n", min_length, max_length); error(); } if (min_length > db->format->params.plaintext_length) { log_event("! MinLen = %d is too large for this hash type", min_length); fprintf(stderr, "MinLen = %d exceeds the maximum possible " "length for the current hash type (%d)\n", min_length, db->format->params.plaintext_length); error(); } if (max_length > db->format->params.plaintext_length) { log_event("! MaxLen = %d is too large for this hash type", max_length); fprintf(stderr, "Warning: " "MaxLen = %d is too large for the current hash type, " "reduced to %d\n", max_length, db->format->params.plaintext_length); max_length = db->format->params.plaintext_length; } if (max_length > CHARSET_LENGTH) { log_event("! MaxLen = %d exceeds the compile-time limit of %d", max_length, CHARSET_LENGTH); fprintf(stderr, "\n" "MaxLen = %d exceeds the compile-time limit of %d\n\n" "There are several good reasons why you probably don't " "need to raise it:\n" "- many hash types don't support passwords " "(or password halves) longer than\n" "7 or 8 characters;\n" "- you probably don't have sufficient statistical " "information to generate a\n" "charset file for lengths beyond 8;\n" "- the limitation applies to incremental mode only.\n", max_length, CHARSET_LENGTH); error(); } if (!(file = fopen(path_expand(charset), "rb"))) pexit("fopen: %s", path_expand(charset)); header = (struct charset_header *)mem_alloc(sizeof(*header)); charset_read_header(file, header); if (ferror(file)) pexit("fread"); if (feof(file) || (memcmp(header->version, CHARSET_V1, sizeof(header->version)) && memcmp(header->version, CHARSET_V2, sizeof(header->version))) || !header->count) inc_format_error(charset); if (header->min != CHARSET_MIN || header->max != CHARSET_MAX || header->length != CHARSET_LENGTH) { log_event("! Incompatible charset file: %.100s", charset); fprintf(stderr, "Incompatible charset file: %s\n", charset); error(); } if (header->count > CHARSET_SIZE) inc_format_error(charset); check = (unsigned int)header->check[0] | ((unsigned int)header->check[1] << 8) | ((unsigned int)header->check[2] << 16) | ((unsigned int)header->check[3] << 24); if (!rec_restoring_now) rec_check = check; if (rec_check != check) { log_event("! Charset file has changed: %.100s", charset); fprintf(stderr, "Charset file has changed: %s\n", charset); error(); } fread(allchars, header->count, 1, file); if (ferror(file)) pexit("fread"); if (feof(file)) inc_format_error(charset); allchars[header->count] = 0; if (expand(allchars, extra ? extra : "", sizeof(allchars))) inc_format_error(charset); real_count = strlen(allchars); if (max_count < 0) max_count = CHARSET_SIZE; if (min_length != max_length) log_event("- Lengths %d to %d, up to %d different characters", min_length, max_length, max_count); else log_event("- Length %d, up to %d different characters", min_length, max_count); if ((unsigned int)max_count > real_count) { log_event("! Only %u characters available", real_count); fprintf(stderr, "Warning: only %u characters available\n", real_count); } if (!(db->format->params.flags & FMT_CASE)) switch (is_mixedcase(allchars)) { case -1: inc_format_error(charset); case 1: log_event("! Mixed-case charset, " "but the hash type is case-insensitive"); fprintf(stderr, "Warning: mixed-case charset, " "but the current hash type is case-insensitive;\n" "some candidate passwords may be unnecessarily " "tried more than once.\n"); } if (header->length >= 2) char2 = (char2_table)mem_alloc(sizeof(*char2)); else char2 = NULL; for (pos = 0; pos < (int)header->length - 2; pos++) chars[pos] = (chars_table)mem_alloc(sizeof(*chars[0])); rec_compat = 0; rec_entry = 0; memset(rec_numbers, 0, sizeof(rec_numbers)); status_init(NULL, 0); rec_restore_mode(restore_state); #ifdef WEBAPI if(packet_id) { int ret; // This is a new packet inc_rec_state.initialized = 0; inc_rec_state.words_requested = packet_rounds; inc_rec_state.words_generated = 0; inc_rec_state.cc_0 = -1; inc_rec_state.cc_1 = -1; inc_rec_state.cc_2 = -1; ret = sscanf(packet_state, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%127[^\n]", &rec_entry, &rec_numbers[0], &rec_numbers[1], &rec_numbers[2], &rec_numbers[3], &rec_numbers[4], &rec_numbers[5], &rec_numbers[6], &rec_numbers[7], &inc_rec_state.pos, &inc_rec_state.numbers_cache, &inc_rec_state.cc_0, &inc_rec_state.cc_1, &inc_rec_state.cc_2, inc_rec_state.key_i); if(ret < 14 || ret > 15) { log_event("Invalid packet state, found %d fields in %s", ret, packet_state); // XXX - Handle more gracefully.. error(); } status_init(webapi_inc_get_progress, 0); } #endif rec_init(db, save_state); ptr = header->order + (entry = rec_entry) * 3; memcpy(numbers, rec_numbers, sizeof(numbers)); crk_init(db, fix_state, NULL); last_count = last_length = -1; entry--; while (ptr < &header->order[sizeof(header->order) - 1]) { entry++; length = *ptr++; fixed = *ptr++; count = *ptr++; if (length >= CHARSET_LENGTH || fixed > length || count >= CHARSET_SIZE) inc_format_error(charset); if (entry != rec_entry) memset(numbers, 0, sizeof(numbers)); if (count >= real_count || (fixed && !count)) continue; if ((int)length + 1 < min_length || (int)length >= max_length || (int)count >= max_count) continue; if ((int)length != last_length) { inc_new_length(last_length = length, header, file, charset, char1, char2, chars); last_count = -1; } if ((int)count > last_count) inc_new_count(length, last_count = count, charset, allchars, char1, char2, chars); if (!length && !min_length) { min_length = 1; if (crk_process_key("")) break; } #if 0 log_event("- Trying length %d, fixed @%d, character count %d", length + 1, fixed + 1, count + 1); #endif if (inc_key_loop(length, fixed, count, char1, char2, chars)) break; } crk_done(); rec_done(event_abort); for (pos = 0; pos < (int)header->length - 2; pos++) MEM_FREE(chars[pos]); MEM_FREE(char2); MEM_FREE(header); fclose(file); }
void do_external_crack(struct db_main *db) { unsigned char *internal; c_int *external; int my_words, their_words; log_event("Proceeding with external mode: %.100s", ext_mode); internal = (unsigned char *)int_word; external = ext_word; while (*external) *internal++ = *external++; *internal = 0; seq = 0; status_init(&get_progress, 0); rec_restore_mode(restore_state); rec_init(db, save_state); crk_init(db, fix_state, NULL); my_words = options.node_max - options.node_min + 1; their_words = options.node_min - 1; if (seq) { /* Restored session. seq is right after a word we've actually used. */ int for_node = seq % options.node_count + 1; if (for_node < options.node_min || for_node > options.node_max) { /* We assume that seq is at the beginning of other nodes' block */ their_words = options.node_count - my_words; } else { my_words = options.node_max - for_node + 1; their_words = 0; } } do { c_execute_fast(f_generate); if (!ext_word[0]) break; if (options.node_count) { seq++; if (their_words) { their_words--; continue; } if (--my_words == 0) { my_words = options.node_max - options.node_min + 1; their_words = options.node_count - my_words; } } if (f_filter) { c_execute_fast(f_filter); if (!ext_word[0]) continue; } int_word[0] = ext_word[0]; if ((int_word[1] = ext_word[1])) { internal = (unsigned char *)&int_word[2]; external = &ext_word[2]; do { if (!(internal[0] = external[0])) break; if (!(internal[1] = external[1])) break; if (!(internal[2] = external[2])) break; if (!(internal[3] = external[3])) break; internal += 4; external += 4; } while (1); } int_word[maxlen] = 0; if (options.mask) { if (do_mask_crack(int_word)) break; } else if (crk_process_key(int_word)) break; } while (1); if (!event_abort) progress = 100; // For reporting DONE after a no-ETA run crk_done(); rec_done(event_abort); }
static void rec_name_complete(void) { if (rec_name_completed) return; #ifndef HAVE_MPI if (options.fork && !john_main_process) { #else if (!john_main_process && options.node_min) { #endif char *suffix = mem_alloc(1 + 20 + strlen(RECOVERY_SUFFIX) + 1); sprintf(suffix, ".%u%s", options.node_min, RECOVERY_SUFFIX); rec_name = path_session(rec_name, suffix); MEM_FREE(suffix); } else { rec_name = path_session(rec_name, RECOVERY_SUFFIX); } rec_name_completed = 1; } #if OS_FLOCK || FCNTL_LOCKS static void rec_lock(int shared) { int lockmode; #if FCNTL_LOCKS int blockmode; struct flock lock; #endif /* * In options.c, MPI code path call rec_restore_args(mpi_p) * relying on anything >1 meaning LOCK_SH. After restore, the * root node must block, in case some other node has not yet * closed the original file */ if (shared == 1) { #if FCNTL_LOCKS lockmode = F_WRLCK; blockmode = F_SETLKW; #else lockmode = LOCK_EX; #endif #ifdef HAVE_MPI if (!rec_restored || mpi_id || mpi_p == 1) #endif #if FCNTL_LOCKS blockmode = F_SETLK; #else lockmode |= LOCK_NB; #endif } else #if FCNTL_LOCKS { lockmode = F_RDLCK; blockmode = F_SETLK; } #else lockmode = LOCK_SH | LOCK_NB; #endif #ifdef LOCK_DEBUG fprintf(stderr, "%s(%u): Locking session file...\n", __FUNCTION__, options.node_min); #endif #if FCNTL_LOCKS memset(&lock, 0, sizeof(lock)); lock.l_type = lockmode; if (fcntl(rec_fd, blockmode, &lock)) { if (errno == EAGAIN || errno == EACCES) { #else if (flock(rec_fd, lockmode)) { if (errno == EWOULDBLOCK) { #endif #ifdef HAVE_MPI fprintf(stderr, "Node %d@%s: Crash recovery file is" " locked: %s\n", mpi_id + 1, mpi_name, path_expand(rec_name)); #else fprintf(stderr, "Crash recovery file is locked: %s\n", path_expand(rec_name)); #endif error(); } else #if FCNTL_LOCKS pexit("fcntl()"); #else pexit("flock()"); #endif } #ifdef LOCK_DEBUG fprintf(stderr, "%s(%u): Locked session file (%s)\n", __FUNCTION__, options.node_min, shared == 1 ? "exclusive" : "shared"); #endif } static void rec_unlock(void) { #if FCNTL_LOCKS struct flock lock = { 0 }; lock.l_type = F_UNLCK; #endif #ifdef LOCK_DEBUG fprintf(stderr, "%s(%u): Unlocking session file\n", __FUNCTION__, options.node_min); #endif #if FCNTL_LOCKS if (fcntl(rec_fd, F_SETLK, &lock)) pexit("fcntl(F_UNLCK)"); #else if (flock(rec_fd, LOCK_UN)) pexit("flock(LOCK_UN)"); #endif } #else #define rec_lock(lock) \ {} #define rec_unlock() \ {} #endif void rec_init(struct db_main *db, void (*save_mode)(FILE *file)) { rec_done(1); if (!rec_argc) return; rec_name_complete(); if ((rec_fd = open(path_expand(rec_name), O_RDWR | O_CREAT, 0600)) < 0) pexit("open: %s", path_expand(rec_name)); rec_lock(1); if (!(rec_file = fdopen(rec_fd, "w"))) pexit("fdopen"); rec_db = db; rec_save_mode = save_mode; } void rec_save(void) { int save_format; #ifdef HAVE_MPI int fake_fork; #endif int add_argc = 0, add_enc = 1, add_2nd_enc = 1; int add_mkv_stats = (options.mkv_stats ? 1 : 0); long size; char **opt; log_flush(); if (!rec_file) return; if (fseek(rec_file, 0, SEEK_SET)) pexit("fseek"); #ifdef _MSC_VER if (_write(fileno(rec_file), "", 0)) pexit("ftruncate"); #elif __CYGWIN__ if (ftruncate(rec_fd, 0)) pexit("ftruncate"); #endif save_format = !options.format && rec_db->loaded; #ifdef HAVE_MPI fake_fork = (mpi_p > 1); #endif opt = rec_argv; while (*++opt) { #ifdef HAVE_MPI if (!strncmp(*opt, "--fork", 6)) fake_fork = 0; else #endif if (!strncmp(*opt, "--encoding", 10) || !strncmp(*opt, "--input-encoding", 16)) add_enc = 0; else if (!strncmp(*opt, "--internal-encoding", 19) || !strncmp(*opt, "--target-encoding", 17)) add_2nd_enc = 0; else if (!strncmp(*opt, "--mkv-stats", 11)) add_mkv_stats = 0; } if (add_2nd_enc && (options.flags & FLG_STDOUT) && (pers_opts.input_enc != UTF_8 || pers_opts.target_enc != UTF_8)) add_2nd_enc = 0; add_argc = add_enc + add_2nd_enc + add_mkv_stats; #ifdef HAVE_MPI add_argc += fake_fork; #endif fprintf(rec_file, RECOVERY_V "\n%d\n", rec_argc + (save_format ? 1 : 0) + add_argc); opt = rec_argv; while (*++opt) { /* Add defaults as if they were actually on **argv */ if (options.wordlist && !(strcmp(*opt, "--wordlist") && strcmp(*opt, "--loopback"))) fprintf(rec_file, "%s=%s\n", *opt, options.wordlist); else if (!strcmp(*opt, "--rules")) fprintf(rec_file, "%s=%s\n", *opt, pers_opts.activewordlistrules); else if (!strcmp(*opt, "--single")) fprintf(rec_file, "%s=%s\n", *opt, pers_opts.activesinglerules); else if (!strcmp(*opt, "--incremental")) fprintf(rec_file, "%s=%s\n", *opt, options.charset); else if (!strcmp(*opt, "--markov")) fprintf(rec_file, "%s=%s\n", *opt, options.mkv_param); else fprintf(rec_file, "%s\n", *opt); } if (save_format) fprintf(rec_file, "--format=%s\n", rec_db->format->params.label); if (add_enc) fprintf(rec_file, "--input-encoding=%s\n", cp_id2name(pers_opts.input_enc)); if (add_2nd_enc && pers_opts.input_enc == UTF_8 && pers_opts.target_enc == UTF_8) fprintf(rec_file, "--internal-encoding=%s\n", cp_id2name(pers_opts.internal_enc)); else if (add_2nd_enc) fprintf(rec_file, "--target-encoding=%s\n", cp_id2name(pers_opts.target_enc)); if (add_mkv_stats) fprintf(rec_file, "--mkv-stats=%s\n", options.mkv_stats); #ifdef HAVE_MPI if (fake_fork) fprintf(rec_file, "--fork=%d\n", mpi_p); #endif fprintf(rec_file, "%u\n%u\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n" "%d\n%d\n%d\n%x\n", status_get_time() + 1, status.guess_count, status.combs.lo, status.combs.hi, status.combs_ehi, status.crypts.lo, status.crypts.hi, status.cands.lo, status.cands.hi, status.compat, status.pass, status_get_progress ? (int)status_get_progress() : -1, rec_check); if (rec_save_mode) rec_save_mode(rec_file); if (options.flags & FLG_MASK_STACKED) mask_save_state(rec_file); if (ferror(rec_file)) pexit("fprintf"); if ((size = ftell(rec_file)) < 0) pexit("ftell"); if (fflush(rec_file)) pexit("fflush"); #ifndef _MSC_VER if (ftruncate(rec_fd, size)) pexit("ftruncate"); #endif #if HAVE_WINDOWS_H==0 if (!options.fork && fsync(rec_fd)) pexit("fsync"); #endif }