static void process_shadow_line(char *line)
{
    static struct shadow_entry **entry = NULL;
    struct shadow_entry *last;
    char *login, *passwd, *tail;

    if (!(passwd = strchr(line, ':'))) {
        while (*line == ' ' || *line == '\t') line++;
        /* AIX */
        if (!strncmp(line, "password = "******"u_name=", 7)) {
        if ((passwd = strstr(passwd, ":u_pwd=")))
            passwd += 7;
    } else
        /* HP-UX tcb */
        if (!strncmp(passwd, "u_pwd=", 6) && entry) {
            passwd += 6;
            if ((tail = strchr(passwd, ':')))
                *tail = 0;
            (*entry)->passwd = str_alloc_copy(passwd);
            return;
        }

    if (passwd && (tail = strchr(passwd, ':')))
        *tail = 0;

    entry = &shadow_table[login_hash(login)];
    last = *entry;
    *entry = mem_alloc_tiny(sizeof(struct shadow_entry), MEM_ALIGN_WORD);
    (*entry)->next = last;
    (*entry)->login = str_alloc_copy(login);
    (*entry)->passwd = passwd ? str_alloc_copy(passwd) : "*";
}
Beispiel #2
0
char * str_alloc_copy_func(char * src
#if defined(MEMDBG_ON)
						   ,
						   char * file,
						   int line
#endif
						   )
{
	size_t size;

	if (!src) return "";
	if (!*src) return "";

	size = strlen(src) + 1;
#if defined(MEMDBG_ON)
	return (char *) memcpy(
		mem_alloc_tiny_func(size, MEM_ALIGN_NONE, file, line), src, size);
#else
	return (char *) memcpy(mem_alloc_tiny(size, MEM_ALIGN_NONE), src, size);
#endif
}
Beispiel #3
0
static void init(struct fmt_main *self)
{
	DES_std_init();

#if DES_BS
	DES_bs_init(0, (DES_bs_cpt + 28) / 29);
#if DES_bs_mt
	fmt_BSDI.params.min_keys_per_crypt = DES_bs_min_kpc;
	fmt_BSDI.params.max_keys_per_crypt = DES_bs_max_kpc;
#endif

	DES_std_set_salt(0);
	DES_count = 1;
#else
	current_salt = -1;
#endif

	buffer = mem_alloc_tiny(
	    sizeof(*buffer) * fmt_BSDI.params.max_keys_per_crypt,
	    MEM_ALIGN_CACHE);
}
/* We're essentially using three salts, but we're going to pack it into a single blob for now.
   |Client Challenge (8 Bytes)|Server Challenge (8 Bytes)|Unicode(Username (<=20).Domain (<=15))
*/
static void *get_salt(char *ciphertext)
{
  static unsigned char *binary_salt;
  unsigned char identity[USERNAME_LENGTH + DOMAIN_LENGTH + 1];
  UTF16 identity_ucs2[USERNAME_LENGTH + DOMAIN_LENGTH + 1];
  int i, identity_length;
  int identity_ucs2_length;
  char *pos = NULL;

  if (!binary_salt) binary_salt = mem_alloc_tiny(SALT_SIZE, MEM_ALIGN_WORD);

  /* Calculate identity length */
  for (pos = ciphertext + 9; *pos != '$'; pos++);
  identity_length = pos - (ciphertext + 9);

  /* Convert identity (username + domain) string to NT unicode */
  strnzcpy((char *)identity, ciphertext + 9, sizeof(identity));
  identity_ucs2_length = enc_to_utf16((UTF16 *)identity_ucs2, USERNAME_LENGTH + DOMAIN_LENGTH, (UTF8 *)identity, identity_length) * sizeof(int16);

  if (identity_ucs2_length < 0) // Truncated at Unicode conversion.
	  identity_ucs2_length = strlen16((UTF16 *)identity_ucs2) * sizeof(int16);

  binary_salt[16] = (unsigned char)identity_ucs2_length;
  memcpy(&binary_salt[17], (char *)identity_ucs2, identity_ucs2_length);

  /* Set server challenge */
  ciphertext += 10 + identity_length;

  for (i = 0; i < 8; i++)
    binary_salt[i] = (atoi16[ARCH_INDEX(ciphertext[i*2])] << 4) + atoi16[ARCH_INDEX(ciphertext[i*2+1])];

  /* Set client challenge */
  ciphertext += 2 + CHALLENGE_LENGTH / 2 + CIPHERTEXT_LENGTH;

  for (i = 0; i < 8; ++i)
    binary_salt[i + 8] = (atoi16[ARCH_INDEX(ciphertext[i*2])] << 4) + atoi16[ARCH_INDEX(ciphertext[i*2+1])];

  /* Return a concatenation of the server and client challenges and the identity value */
  return (void*)binary_salt;
}
Beispiel #5
0
static void cfg_add_line(char *line, int number)
{
	struct cfg_list *list;
	struct cfg_line *entry;

	entry = mem_alloc_tiny(sizeof(struct cfg_line), MEM_ALIGN_WORD);
	entry->next = NULL;

	entry->data = str_alloc_copy(line);
	entry->number = number;
	entry->cfg_name = cfg_name;

	list = cfg_database->list;
	if (list->tail) {
		entry->id = list->tail->id + 1;
		list->tail = list->tail->next = entry;
	}
	else {
		entry->id = 0;
		list->tail = list->head = entry;
	}
}
static void *get_salt(char *ciphertext)
{
	char *ctcopy = strdup(ciphertext);
	char *keeptr = ctcopy;
	int i;
	char *p;
	ctcopy += 11;	/* skip over "$keychain$*" */
	salt_struct = mem_alloc_tiny(sizeof(struct custom_salt), MEM_ALIGN_WORD);
	p = strtok(ctcopy, "*");
	for (i = 0; i < SALTLEN; i++)
		salt_struct->salt[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
			+ atoi16[ARCH_INDEX(p[i * 2 + 1])];
	p = strtok(NULL, "*");
	for (i = 0; i < IVLEN; i++)
		salt_struct->iv[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
			+ atoi16[ARCH_INDEX(p[i * 2 + 1])];
	p = strtok(NULL, "*");
	for (i = 0; i < CTLEN; i++)
		salt_struct->ct[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
			+ atoi16[ARCH_INDEX(p[i * 2 + 1])];

	free(keeptr);
	return (void *)salt_struct;
}
Beispiel #7
0
static int valid(char *ciphertext, struct fmt_main *pFmt)
{
	int length, count_base64, id, pw_length;
	char pw[PLAINTEXT_LENGTH + 1], *new_ciphertext;
/* We assume that these are zero-initialized */
	static char sup_length[BINARY_SIZE], sup_id[0x80];

	length = count_base64 = 0;
	while (ciphertext[length]) {
		if (atoi64[ARCH_INDEX(ciphertext[length])] != 0x7F &&
		    (ciphertext[0] == '_' || length >= 2))
			count_base64++;
		length++;
	}

	if (length < 13 || length >= BINARY_SIZE)
		return 0;

	id = 0;
	if (length == 13 && count_base64 == 11)
		id = 1;
	else
	if (length >= 13 &&
	    count_base64 >= length - 2 && /* allow for invalid salt */
	    (length - 2) % 11 == 0)
		id = 2;
	else
	if (length == 20 && count_base64 == 19 && ciphertext[0] == '_')
		id = 3;
	else
	if (ciphertext[0] == '$') {
		id = (unsigned char)ciphertext[1];
		if (id <= 0x20 || id >= 0x80)
			id = 9;
	} else
	if (ciphertext[0] == '*' || ciphertext[0] == '!') /* likely locked */
		id = 10;

/* Previously detected as supported */
	if (sup_length[length] > 0 && sup_id[id] > 0)
		return 1;

/* Previously detected as unsupported */
	if (sup_length[length] < 0 && sup_id[id] < 0)
		return 0;

	pw_length = ((length - 2) / 11) << 3;
	if (pw_length >= sizeof(pw))
		pw_length = sizeof(pw) - 1;
	memcpy(pw, ciphertext, pw_length); /* reuse the string, why not? */
	pw[pw_length] = 0;

#if defined(_OPENMP) && defined(__GLIBC__)
/*
 * Let's use crypt_r(3) just like we will in crypt_all() below.
 * It is possible that crypt(3) and crypt_r(3) differ in their supported hash
 * types on a given system.
 */
	{
		struct crypt_data **data = &crypt_data[0];
		if (!*data) {
/*
 * **data is not exactly tiny, but we use mem_alloc_tiny() for its alignment
 * support and error checking.  We do not need to free() this memory anyway.
 *
 * The page alignment is to keep different threads' data on different pages.
 */
			*data = mem_alloc_tiny(sizeof(**data), MEM_ALIGN_PAGE);
			memset(*data, 0, sizeof(**data));
		}
		new_ciphertext = crypt_r(pw, ciphertext, *data);
	}
#else
	new_ciphertext = crypt(pw, ciphertext);
#endif

	if (strlen(new_ciphertext) == length &&
	    !strncmp(new_ciphertext, ciphertext, 2)) {
		sup_length[length] = 1;
		sup_id[id] = 1;
		return 1;
	}

	if (id != 10 && !ldr_in_pot)
#ifdef HAVE_MPI
	if (mpi_id == 0)
#endif
		fprintf(stderr, "Generic crypt(3) module: "
		    "hash encoding string length %d, type id %c%c\n"
		    "appears to be unsupported on this system; "
		    "will not load such hashes.\n",
		    length, id > 0x20 ? '$' : '#', id > 0x20 ? id : '0' + id);

	if (!sup_length[length])
		sup_length[length] = -1;
	if (!sup_id[id])
		sup_id[id] = -1;
	return 0;
}
Beispiel #8
0
static void *get_salt(char *ciphertext)
{
	unsigned int i;
	size_t count;
	/* extract data from "salt" */
	char *encoded_salt;
	char *saltcopy = strdup(ciphertext);
	char *keep_ptr = saltcopy;
	static rarfile rarfile;

	saltcopy += 7;		/* skip over "$RAR3$*" */
	rarfile.type = atoi(strtok(saltcopy, "*"));
	encoded_salt = strtok(NULL, "*");
	for (i = 0; i < 8; i++)
		rarfile.salt[i] = atoi16[ARCH_INDEX(encoded_salt[i * 2])] * 16 + atoi16[ARCH_INDEX(encoded_salt[i * 2 + 1])];
	if (rarfile.type == 0) {	/* rar-hp mode */
		char *encoded_ct = strtok(NULL, "*");
		rarfile.raw_data = (unsigned char*)mem_alloc_tiny(16, MEM_ALIGN_WORD);
		for (i = 0; i < 16; i++)
			rarfile.raw_data[i] = atoi16[ARCH_INDEX(encoded_ct[i * 2])] * 16 + atoi16[ARCH_INDEX(encoded_ct[i * 2 + 1])];
	} else {
		char *p = strtok(NULL, "*");
		int inlined;
		for (i = 0; i < 4; i++)
			rarfile.crc.c[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])];
		rarfile.pack_size = atoll(strtok(NULL, "*"));
		rarfile.unp_size = atoll(strtok(NULL, "*"));
		inlined = atoi(strtok(NULL, "*"));

		/* load ciphertext. We allocate and load all files here, and
		   they don't get unloaded until program ends */
		rarfile.raw_data = (unsigned char*)mem_alloc_tiny(rarfile.pack_size, MEM_ALIGN_WORD);
		if (inlined) {
			unsigned char *d = rarfile.raw_data;
			p = strtok(NULL, "*");
			for (i = 0; i < rarfile.pack_size; i++)
				*d++ = atoi16[ARCH_INDEX(p[i * 2])] * 16 + atoi16[ARCH_INDEX(p[i * 2 + 1])];
		} else {
			FILE *fp;
			rarfile.archive_name = strtok(NULL, "*");
			rarfile.pos = atol(strtok(NULL, "*"));

			if (!(fp = fopen(rarfile.archive_name, "rb"))) {
				fprintf(stderr, "! %s: %s\n", rarfile.archive_name, strerror(errno));
				error();
			}
			fseek(fp, rarfile.pos, SEEK_SET);
			count = fread(rarfile.raw_data, 1, rarfile.pack_size, fp);
			if (count != rarfile.pack_size) {
				fprintf(stderr, "Error loading file from archive '%s', expected %llu bytes, got %zu. Archive possibly damaged.\n", rarfile.archive_name, rarfile.pack_size, count);
				exit(0);
			}
			fclose(fp);
		}
		p = strtok(NULL, "*");
		rarfile.method = atoi16[ARCH_INDEX(p[0])] * 16 + atoi16[ARCH_INDEX(p[1])];
		if (rarfile.method != 0x30)
			rarfile.crc.w = ~rarfile.crc.w;
	}
	MEM_FREE(keep_ptr);
	return (void*)&rarfile;
}
static void *get_salt(char *ciphertext)
{
	int i;
	my_salt salt, *psalt;
	static unsigned char *ptr;
	/* extract data from "ciphertext" */
	u8 *copy_mem = (u8*)strdup(ciphertext);
	u8 *cp, *p;

	if (!ptr) ptr = mem_alloc_tiny(sizeof(my_salt*),sizeof(my_salt*));
	p = copy_mem + TAG_LENGTH+1; /* skip over "$zip2$*" */
	memset(&salt, 0, sizeof(salt));
	p = pkz_GetFld(p, &cp); // type
	salt.v.type = atoi((const char*)cp);
	p = pkz_GetFld(p, &cp); // mode
	salt.v.mode = atoi((const char*)cp);
	p = pkz_GetFld(p, &cp); // file_magic enum (ignored)
	p = pkz_GetFld(p, &cp); // salt
	for (i = 0; i < SALT_LENGTH(salt.v.mode); i++)
		salt.salt[i] = (atoi16[ARCH_INDEX(cp[i<<1])]<<4) | atoi16[ARCH_INDEX(cp[(i<<1)+1])];
	p = pkz_GetFld(p, &cp);	// validator
	salt.passverify[0] = (atoi16[ARCH_INDEX(cp[0])]<<4) | atoi16[ARCH_INDEX(cp[1])];
	salt.passverify[1] = (atoi16[ARCH_INDEX(cp[2])]<<4) | atoi16[ARCH_INDEX(cp[3])];
	p = pkz_GetFld(p, &cp);	// data len
	sscanf((const char *)cp, "%x", &salt.comp_len);

	// later we will store the data blob in our own static data structure, and place the 64 bit LSB of the
	// MD5 of the data blob into a field in the salt. For the first POC I store the entire blob and just
	// make sure all my test data is small enough to fit.

	p = pkz_GetFld(p, &cp);	// data blob

	// Ok, now create the allocated salt record we are going to return back to John, using the dynamic
	// sized data buffer.
	psalt = (my_salt*)mem_calloc(1, sizeof(my_salt) + salt.comp_len);
	psalt->v.type = salt.v.type;
	psalt->v.mode = salt.v.mode;
	psalt->comp_len = salt.comp_len;
	psalt->dsalt.salt_alloc_needs_free = 1;  // we used mem_calloc, so JtR CAN free our pointer when done with them.
	memcpy(psalt->salt, salt.salt, sizeof(salt.salt));
	psalt->passverify[0] = salt.passverify[0];
	psalt->passverify[1] = salt.passverify[1];

	// set the JtR core linkage stuff for this dyna_salt
	psalt->dsalt.salt_cmp_offset = SALT_CMP_OFF(my_salt, comp_len);
	psalt->dsalt.salt_cmp_size = SALT_CMP_SIZE(my_salt, comp_len, datablob, psalt->comp_len);


	if (strcmp((const char*)cp, "ZFILE")) {
	for (i = 0; i < psalt->comp_len; i++)
		psalt->datablob[i] = (atoi16[ARCH_INDEX(cp[i<<1])]<<4) | atoi16[ARCH_INDEX(cp[(i<<1)+1])];
	} else {
		u8 *Fn, *Oh, *Ob;
		long len;
		uint32_t id;
		FILE *fp;

		p = pkz_GetFld(p, &Fn);
		p = pkz_GetFld(p, &Oh);
		p = pkz_GetFld(p, &Ob);

		fp = fopen((const char*)Fn, "rb");
		if (!fp) {
			psalt->v.type = 1; // this will tell the format to 'skip' this salt, it is garbage
			goto Bail;
		}
		sscanf((const char*)Oh, "%lx", &len);
		if (fseek(fp, len, SEEK_SET)) {
			fclose(fp);
			psalt->v.type = 1;
			goto Bail;
		}
		id = fget32LE(fp);
		if (id != 0x04034b50U) {
			fclose(fp);
			psalt->v.type = 1;
			goto Bail;
		}
		sscanf((const char*)Ob, "%lx", &len);
		if (fseek(fp, len, SEEK_SET)) {
			fclose(fp);
			psalt->v.type = 1;
			goto Bail;
		}
		if (fread(psalt->datablob, 1, psalt->comp_len, fp) != psalt->comp_len) {
			fclose(fp);
			psalt->v.type = 1;
			goto Bail;
		}
		fclose(fp);
	}
Bail:
	MEM_FREE(copy_mem);

	memcpy(ptr, &psalt, sizeof(my_salt*));
	return (void*)ptr;
}
Beispiel #10
0
void rec_restore_args(int lock)
{
	char line[LINE_BUFFER_SIZE];
	int index, argc;
	char **argv;
	char *save_rec_name;

	rec_name_complete();
	if (!(rec_file = fopen(path_expand(rec_name), "r+"))) {
		if (options.fork && !john_main_process && errno == ENOENT) {
			fprintf(stderr, "%u Session completed\n",
			    options.node_min);
			if (options.flags & FLG_STATUS_CHK)
				return;
			log_event("No crash recovery file, terminating");
			log_done();
			exit(0);
		}
		pexit("fopen: %s", path_expand(rec_name));
	}
	rec_fd = fileno(rec_file);

	if (lock) rec_lock();

	if (!fgetl(line, sizeof(line), rec_file)) rec_format_error("fgets");

	rec_version = 0;
	if (!strcmp(line, RECOVERY_V4)) rec_version = 4; else
	if (!strcmp(line, RECOVERY_V3)) rec_version = 3; else
	if (!strcmp(line, RECOVERY_V2)) rec_version = 2; else
	if (!strcmp(line, RECOVERY_V1)) rec_version = 1; else
	if (strcmp(line, RECOVERY_V0)) rec_format_error(NULL);

	if (fscanf(rec_file, "%d\n", &argc) != 1)
		rec_format_error("fscanf");
	if (argc < 2)
		rec_format_error(NULL);
	argv = mem_alloc_tiny(sizeof(char *) * (argc + 1), MEM_ALIGN_WORD);

	argv[0] = "john";

	for (index = 1; index < argc; index++)
	if (fgetl(line, sizeof(line), rec_file))
		argv[index] = str_alloc_copy(line);
	else
		rec_format_error("fgets");

	argv[argc] = NULL;

	save_rec_name = rec_name;
	opt_init(argv[0], argc, argv);
	rec_name = save_rec_name;
	rec_name_completed = 1;

	if (fscanf(rec_file, "%u\n%u\n%x\n%x\n",
	    &status_restored_time,
	    &status.guess_count,
	    &status.combs.lo,
	    &status.combs.hi) != 4)
		rec_format_error("fscanf");
	if (!status_restored_time)
		status_restored_time = 1;

	if (rec_version >= 4) {
		if (fscanf(rec_file, "%x\n%x\n%x\n%x\n%x\n%d\n",
		    &status.combs_ehi,
		    &status.crypts.lo,
		    &status.crypts.hi,
		    &status.cands.lo,
		    &status.cands.hi,
		    &status.compat) != 6)
			rec_format_error("fscanf");
	} else {
/* Historically, we were reusing what became the combs field for candidates
 * count when in --stdout mode */
		status.cands = status.combs;
		status.compat = 1;
	}

	if (rec_version == 0) {
		status.pass = 0;
		status.progress = -1;
	} else
	if (fscanf(rec_file, "%d\n%d\n", &status.pass, &status.progress) != 2)
		rec_format_error("fscanf");
	if (status.pass < 0 || status.pass > 3)
		rec_format_error(NULL);

	if (rec_version < 3)
		rec_check = 0;
	else
	if (fscanf(rec_file, "%x\n", &rec_check) != 1)
		rec_format_error("fscanf");

	rec_restoring_now = 1;
}
Beispiel #11
0
void list_init(struct list_main **list)
{
	*list = mem_alloc_tiny(sizeof(struct list_main), MEM_ALIGN_WORD);
	(*list)->tail = (*list)->head = NULL;
	(*list)->count = 0;
}
Beispiel #12
0
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;
}
Beispiel #13
0
static char *split(char *ciphertext, int index, struct fmt_main *pFmt) {
#else
static char *split(char *ciphertext, int index) {
#endif
    static char out[8 + CIPHERTEXT_LENGTH + 1];

    if (!strncmp(ciphertext, "$SHA256$", 8))
        return ciphertext;

    memcpy(out, "$SHA256$", 8);
    memcpy(out + 8, ciphertext, CIPHERTEXT_LENGTH + 1);
    strlwr(out + 8);
    return out;
}

/* ------- To binary functions ------- */
static void * get_binary(char *ciphertext) {
    static unsigned char *out;
    uint32_t * b;
    char *p;
    int i;

    if (!out) out = mem_alloc_tiny(FULL_BINARY_SIZE, MEM_ALIGN_WORD);

    p = ciphertext + 8;
    for (i = 0; i < (FULL_BINARY_SIZE / 2); i++) {
        out[i] =
                (atoi16[ARCH_INDEX(*p)] << 4) |
                 atoi16[ARCH_INDEX(p[1])];
        p += 2;
    }
    b = (uint32_t *) out;
    b[0] = SWAP32(b[3]) - 0xa54ff53a;

    return out;
}

static void * get_full_binary(char *ciphertext) {
    static unsigned char *out;
    char *p;
    int i;

    if (!out) out = mem_alloc_tiny(FULL_BINARY_SIZE, MEM_ALIGN_WORD);

    p = ciphertext + 8;
    for (i = 0; i < FULL_BINARY_SIZE; i++) {
        out[i] =
                (atoi16[ARCH_INDEX(*p)] << 4) |
                 atoi16[ARCH_INDEX(p[1])];
        p += 2;
    }

    return out;
}

/* ------- Crypt function ------- */
static void crypt_all(int count) {
    //Send data to device.
    HANDLE_CLERROR(clEnqueueWriteBuffer(queue[ocl_gpu_id], pass_buffer, CL_FALSE, 0,
                sizeof(sha256_password) * global_work_size, plaintext, 0, NULL, NULL),
                "failed in clEnqueueWriteBuffer pass_buffer");

    //Enqueue the kernel
    HANDLE_CLERROR(clEnqueueNDRangeKernel(queue[ocl_gpu_id], crypt_kernel, 1, NULL,
            &global_work_size, &local_work_size, 0, NULL, profilingEvent),
            "failed in clEnqueueNDRangeKernel");

    //Read back hashes
    HANDLE_CLERROR(clEnqueueReadBuffer(queue[ocl_gpu_id], hash_buffer, CL_FALSE, 0,
            sizeof(uint32_t) * global_work_size, calculated_hash, 0, NULL, NULL),
            "failed in reading data back");

    //Do the work
    HANDLE_CLERROR(clFinish(queue[ocl_gpu_id]), "failed in clFinish");
}
Beispiel #14
0
int dynamic_LOAD_PARSER_FUNCTIONS(int which, struct fmt_main *pFmt)
{
	int ret, cnt;
	struct cfg_line *gen_line;

	nPreloadCnt = 0;
	nFuncCnt = 0;

	if (!dynamic_LOAD_PARSER_SIGNATURE(which))
	{
#ifdef HAVE_MPI
		if (mpi_id == 0)
#endif
		fprintf(stderr, "Could not find section [List.Generic:dynamic_%d] in the john.ini/conf file\n", which);
		error();
	}

	// Setup the 'default' format name
	sprintf(SetupName, "$dynamic_%d$", which);
	sprintf(SetupNameID, "dynamic_%d", which);
	Setup.szFORMAT_NAME = str_alloc_copy(SetupName);

	// allocate (and set null) enough file pointers
	cnt = Count_Items("Func=");
	Setup.pFuncs = mem_alloc_tiny((cnt+1)*sizeof(DYNAMIC_primitive_funcp), MEM_ALIGN_WORD);
	memset(Setup.pFuncs, 0, (cnt+1)*sizeof(DYNAMIC_primitive_funcp));

	// allocate (and set null) enough Preloads
	cnt = Count_Items("Test=");
	cnt += Count_Items("TestU=");
	cnt += Count_Items("TestA=");
	Setup.pPreloads = mem_alloc_tiny((cnt+1)*sizeof(struct fmt_tests), MEM_ALIGN_WORD);
	memset(Setup.pPreloads, 0, (cnt+1)*sizeof(struct fmt_tests));

	// allocate (and set null) enough constants (if we have 8, we still need a null to specify the end of the list)
	cnt = Count_Items("CONST");
	Setup.pConstants = mem_alloc_tiny((cnt+1)*sizeof(DYNAMIC_Constants), MEM_ALIGN_WORD);
	memset(Setup.pConstants, 0, (cnt+1)*sizeof(DYNAMIC_Constants));

	Setup.flags = 0;
	Setup.startFlags = 0;
	Setup.SaltLen = 0;
	Setup.MaxInputLen = 0;

	// Ok, now 'grind' through the data  I do know know how to use
	// the config stuff too much, so will grind for now, and later
	// go back over this, and do it 'right', if there is a right way
	gen_line = gen_source->head;

	while (gen_line)
	{
		if (!dynamic_LOAD_PARSER_FUNCTIONS_LoadLINE(gen_line))
		{
#ifdef HAVE_MPI
			if (mpi_id == 0)
#endif
			fprintf(stderr, "Error parsing section [List.Generic:dynamic_%d]\nError in line %d file is %s\n", which, gen_line->number, gen_line->cfg_name);
			error();
		}
		gen_line = gen_line->next;
	}

	ret = dynamic_SETUP(&Setup, pFmt);

	return ret;
}
Beispiel #15
0
static void ldr_load_pw_line(struct db_main *db, char *line)
{
	struct fmt_main *format;
	int index, count;
	char *login, *ciphertext, *gecos, *home;
	char *piece;
	void *binary, *salt;
	int salt_hash, pw_hash;
	struct db_salt *current_salt, *last_salt;
	struct db_password *current_pw, *last_pw;
	struct list_main *words;
	size_t pw_size, salt_size;

	extern struct fmt_main fmt_mscash;
	extern struct fmt_main fmt_oracle;

	count = ldr_split_line(&login, &ciphertext, &gecos, &home,
		NULL, &db->format, db->options, line);
	if (count <= 0) return;
	if (count >= 2) db->options->flags |= DB_SPLIT;

	format = db->format;

	words = NULL;

	if (db->options->flags & DB_WORDS) {
		pw_size = sizeof(struct db_password);
		salt_size = sizeof(struct db_salt);
	} else {
		if (db->options->flags & DB_LOGIN)
			pw_size = sizeof(struct db_password) -
				sizeof(struct list_main *);
		else
			pw_size = sizeof(struct db_password) -
				(sizeof(char *) + sizeof(struct list_main *));
		salt_size = sizeof(struct db_salt) -
			sizeof(struct db_keys *);
	}


	for (index = 0; index < count; index++) {
		if (db->format == &fmt_mscash)
		{
			piece = (char *) mem_alloc_tiny(strlen(login) + strlen(ciphertext) + 4, MEM_ALIGN_NONE);
			sprintf(piece, "M$%s#%s", login, ciphertext);
		}
		else if (db->format == &fmt_oracle)
		{
			piece = (char *) mem_alloc_tiny(strlen(login) + strlen(ciphertext) + 4, MEM_ALIGN_NONE);
			sprintf(piece, "O$%s#%s", login, ciphertext);
		}
		else
			piece = format->methods.split(ciphertext, index);
		
		binary = format->methods.binary(piece);
		pw_hash = LDR_HASH_FUNC(binary);

		if ((current_pw = db->password_hash[pw_hash]))
		do {
			if (!memcmp(current_pw->binary, binary,
			    format->params.binary_size) &&
			    !strcmp(current_pw->source, piece)) {
				if (!(db->options->flags & DB_WORDS) ||
				    !strcmp(current_pw->login, login)) break;
			}
		} while ((current_pw = current_pw->next_hash));

		if (current_pw) continue;

		salt = format->methods.salt(piece);
		salt_hash = format->methods.salt_hash(salt);

		if ((current_salt = db->salt_hash[salt_hash]))
		do {
			if (!memcmp(current_salt->salt, salt,
			    format->params.salt_size))
				break;
		} while ((current_salt = current_salt->next));

		if (!current_salt) {
			last_salt = db->salt_hash[salt_hash];
			current_salt = db->salt_hash[salt_hash] =
				mem_alloc_tiny(salt_size, MEM_ALIGN_WORD);
			current_salt->next = last_salt;

			current_salt->salt = mem_alloc_copy(
				format->params.salt_size, MEM_ALIGN_WORD,
				salt);

			current_salt->index = fmt_dummy_hash;
			current_salt->list = NULL;
			current_salt->hash = &current_salt->list;
			current_salt->hash_size = -1;

			current_salt->count = 0;

			if (db->options->flags & DB_WORDS)
				current_salt->keys = NULL;

			db->salt_count++;
		}

		current_salt->count++;
		db->password_count++;

		last_pw = current_salt->list;
		current_pw = current_salt->list = mem_alloc_tiny(
			pw_size, MEM_ALIGN_WORD);
		current_pw->next = last_pw;

		last_pw = db->password_hash[pw_hash];
		db->password_hash[pw_hash] = current_pw;
		current_pw->next_hash = last_pw;

		current_pw->binary = mem_alloc_copy(
			format->params.binary_size, MEM_ALIGN_WORD, binary);

		current_pw->source = str_alloc_copy(piece);

		if (db->options->flags & DB_WORDS) {
			if (!words)
				words = ldr_init_words(login, gecos, home);
			current_pw->words = words;
		}

		if (db->options->flags & DB_LOGIN) {
			if (count > 1) {
				current_pw->login = mem_alloc_tiny(
					strlen(login) + 3, MEM_ALIGN_NONE);
				sprintf(current_pw->login, "%s:%d",
					login, index + 1);
			} else
			if (words)
				current_pw->login = words->head->data;
			else
				current_pw->login = str_alloc_copy(login);
		}
	}
}
Beispiel #16
0
static void log_file_flush(struct log_file *f)
{
	int count;
	long int pos_b4 = 0;
#if FCNTL_LOCKS
	struct flock lock;
#endif

	if (f->fd < 0) return;

	count = f->ptr - f->buffer;
	if (count <= 0) return;

#if OS_FLOCK || FCNTL_LOCKS
#ifdef LOCK_DEBUG
	fprintf(stderr, "%s(%u): Locking %s...\n", __FUNCTION__, options.node_min, f->name);
#endif
#if FCNTL_LOCKS
	memset(&lock, 0, sizeof(lock));
	lock.l_type = F_WRLCK;
	while (fcntl(f->fd, F_SETLKW, &lock)) {
		if (errno != EINTR)
			pexit("fcntl(F_WRLCK)");
	}
#else
	while (flock(f->fd, LOCK_EX)) {
		if (errno != EINTR)
			pexit("flock(LOCK_EX)");
	}
#endif
#ifdef LOCK_DEBUG
	fprintf(stderr, "%s(%u): Locked %s exclusively\n", __FUNCTION__, options.node_min, f->name);
#endif
#endif

	if (f == &pot) {
		pos_b4 = (long int)lseek(f->fd, 0, SEEK_END);
#if defined(LOCK_DEBUG)
		fprintf(stderr, "%s(%u): writing %d at %ld, ending at %ld to file %s\n", __FUNCTION__, options.node_min, count, pos_b4, pos_b4+count, f->name);
#endif
	}

	if (write_loop(f->fd, f->buffer, count) < 0) pexit("write");
	f->ptr = f->buffer;

	if (f == &pot && pos_b4 == crk_pot_pos)
		crk_pot_pos += count;

#if OS_FLOCK || FCNTL_LOCKS
#ifdef LOCK_DEBUG
	fprintf(stderr, "%s(%u): Unlocking %s\n", __FUNCTION__, options.node_min, f->name);
#endif
#if FCNTL_LOCKS
	lock.l_type = F_UNLCK;
	fcntl(f->fd, F_SETLK, &lock);
#else
	if (flock(f->fd, LOCK_UN))
		pexit("flock(LOCK_UN)");
#endif
#endif

#ifdef SIGUSR2
	/* We don't really send a sync trigger "at crack" but
	   after it's actually written to the pot file. That is, now. */
	if (f == &pot && !event_abort && options.reload_at_crack) {
#ifdef HAVE_MPI
		if (mpi_p > 1) {
			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]);
			}
		} else
#endif
		if (options.fork)
			raise(SIGUSR2);
	}
#endif
}
Beispiel #17
0
static void ldr_load_pw_line(struct db_main *db, char *line)
{
	static int skip_dupe_checking = 0;
	struct fmt_main *format;
	int index, count;
	char *login, *ciphertext, *gecos, *home;
	char *piece;
	void *binary, *salt;
	int salt_hash, pw_hash;
	struct db_salt *current_salt, *last_salt;
	struct db_password *current_pw, *last_pw;
	struct list_main *words;
	size_t pw_size, salt_size;

	count = ldr_split_line(&login, &ciphertext, &gecos, &home,
		NULL, &db->format, db->options, line);
	if (count <= 0) return;
	if (count >= 2) db->options->flags |= DB_SPLIT;

	format = db->format;

	words = NULL;

	if (db->options->flags & DB_WORDS) {
		pw_size = sizeof(struct db_password);
		salt_size = sizeof(struct db_salt);
	} else {
		if (db->options->flags & DB_LOGIN)
			pw_size = sizeof(struct db_password) -
				sizeof(struct list_main *);
		else
			pw_size = sizeof(struct db_password) -
				(sizeof(char *) + sizeof(struct list_main *));
		salt_size = sizeof(struct db_salt) -
			sizeof(struct db_keys *);
	}

	if (!db->password_hash)
		ldr_init_password_hash(db);

	for (index = 0; index < count; index++) {
		piece = format->methods.split(ciphertext, index, format);

		binary = format->methods.binary(piece);
		pw_hash = db->password_hash_func(binary);

		if (!(db->options->flags & DB_WORDS) && !skip_dupe_checking) {
			int collisions = 0;
			if ((current_pw = db->password_hash[pw_hash]))
			do {
				if (!memcmp(binary, current_pw->binary,
				    format->params.binary_size) &&
				    !strcmp(piece, format->methods.source(
				    current_pw->source, current_pw->binary))) {
					db->options->flags |= DB_NODUP;
					break;
				}
				if (++collisions <= LDR_HASH_COLLISIONS_MAX)
					continue;
				if (format->params.binary_size)
					fprintf(stderr, "Warning: "
					    "excessive partial hash "
					    "collisions detected\n%s",
					    db->password_hash_func !=
					    fmt_default_binary_hash ? "" :
					    "(cause: the \"format\" lacks "
					    "proper binary_hash() function "
					    "definitions)\n");
				else
					fprintf(stderr, "Warning: "
					    "check for duplicates partially "
					    "bypassed to speedup loading\n");
				skip_dupe_checking = 1;
				current_pw = NULL; /* no match */
				break;
			} while ((current_pw = current_pw->next_hash));

			if (current_pw) continue;
		}

		salt = format->methods.salt(piece);
		salt_hash = format->methods.salt_hash(salt);

		if ((current_salt = db->salt_hash[salt_hash]))
		do {
			if (!memcmp(current_salt->salt, salt,
			    format->params.salt_size))
				break;
		} while ((current_salt = current_salt->next));

		if (!current_salt) {
			last_salt = db->salt_hash[salt_hash];
			current_salt = db->salt_hash[salt_hash] =
				mem_alloc_tiny(salt_size, MEM_ALIGN_WORD);
			current_salt->next = last_salt;

			current_salt->salt = mem_alloc_copy(salt,
				format->params.salt_size,
				format->params.salt_align);

			current_salt->index = fmt_dummy_hash;
			current_salt->bitmap = NULL;
			current_salt->list = NULL;
			current_salt->hash = &current_salt->list;
			current_salt->hash_size = -1;

			current_salt->count = 0;

			if (db->options->flags & DB_WORDS)
				current_salt->keys = NULL;

			db->salt_count++;
		}

		current_salt->count++;
		db->password_count++;

		last_pw = current_salt->list;
		current_pw = current_salt->list = mem_alloc_tiny(
			pw_size, MEM_ALIGN_WORD);
		current_pw->next = last_pw;

		last_pw = db->password_hash[pw_hash];
		db->password_hash[pw_hash] = current_pw;
		current_pw->next_hash = last_pw;

/* If we're not going to use the source field for its usual purpose, see if we
 * can pack the binary value in it. */
		if (format->methods.source != fmt_default_source &&
		    sizeof(current_pw->source) >= format->params.binary_size)
			current_pw->binary = memcpy(&current_pw->source,
				binary, format->params.binary_size);
		else
			current_pw->binary = mem_alloc_copy(binary,
				format->params.binary_size,
				format->params.binary_align);

		if (format->methods.source == fmt_default_source)
			current_pw->source = str_alloc_copy(piece);

		if (db->options->flags & DB_WORDS) {
			if (!words)
				words = ldr_init_words(login, gecos, home);
			current_pw->words = words;
		}

		if (db->options->flags & DB_LOGIN) {
			if (count >= 2 && count <= 9) {
				current_pw->login = mem_alloc_tiny(
					strlen(login) + 3, MEM_ALIGN_NONE);
				sprintf(current_pw->login, "%s:%d",
					login, index + 1);
			} else
			if (login == no_username)
				current_pw->login = login;
			else
			if (words && *login)
				current_pw->login = words->head->data;
			else
				current_pw->login = str_alloc_copy(login);
		}
	}
}
Beispiel #18
0
void MD5_std_init(void)
{
    int index;
    MD5_pool *current;
#if MD5_std_mt
    int t, n;

    if (!MD5_std_all_p) {
        n = omp_get_max_threads();
        if (n < 1)
            n = 1;
        if (n > MD5_std_mt_max)
            n = MD5_std_mt_max;
        MD5_std_min_kpc = n * MD5_N;
        {
            int max = n * MD5_std_cpt;
            while (max > MD5_std_mt_max)
                max -= n;
            n = max;
        }
        MD5_std_max_kpc = n * MD5_N;
        /*
         * The array of MD5_std_all's is not exactly tiny, but we use mem_alloc_tiny()
         * for its alignment support and error checking.  We do not need to free() this
         * memory anyway.
         */
        MD5_std_all_p = mem_alloc_tiny(n * MD5_std_all_size,
                                       MEM_ALIGN_PAGE);
        MD5_std_nt = n;
    }
#endif

    for_each_t(MD5_std_nt) {
#if !MD5_IMM
        MD5_std_all.data = MD5_data_init;
#endif

        current = pool;
        for (index = 0; index < MD5_N; index++) {
#define init_line(line, init_even, init_odd) \
	order[line][index].even = init_even; \
	order[line][index].odd = init_odd;
            init_line(0, &current->e.p, &current->o.psp);
            init_line(1, &current->e.spp, &current->o.pp);
            init_line(2, &current->e.spp, &current->o.psp);
            init_line(3, &current->e.pp, &current->o.ps);
            init_line(4, &current->e.spp, &current->o.pp);
            init_line(5, &current->e.spp, &current->o.psp);
            init_line(6, &current->e.pp, &current->o.psp);
            init_line(7, &current->e.sp, &current->o.pp);
            init_line(8, &current->e.spp, &current->o.psp);
            init_line(9, &current->e.pp, &current->o.psp);
            init_line(10, &current->e.spp, &current->o.p);
            init_line(11, &current->e.spp, &current->o.psp);
            init_line(12, &current->e.pp, &current->o.psp);
            init_line(13, &current->e.spp, &current->o.pp);
            init_line(14, &current->e.sp, &current->o.psp);
            init_line(15, &current->e.pp, &current->o.psp);
            init_line(16, &current->e.spp, &current->o.pp);
            init_line(17, &current->e.spp, &current->o.ps);
            init_line(18, &current->e.pp, &current->o.psp);
            init_line(19, &current->e.spp, &current->o.pp);
            init_line(20, &current->e.spp, &current->o.psp);
#undef init_line
            current++;
        }
    }
}
Beispiel #19
0
static void ldr_show_pw_line(struct db_main *db, char *line)
{
	int show;
	char source[LINE_BUFFER_SIZE];
	struct fmt_main *format;
	char *(*split)(char *ciphertext, int index);
	int index, count, unify;
	char *login, *ciphertext, *gecos, *home;
	char *piece;
	int pass, found, chars;
	int hash;
	struct db_cracked *current;

	extern struct fmt_main fmt_mscash;
	extern struct fmt_main fmt_oracle;

	format = NULL;
	count = ldr_split_line(&login, &ciphertext, &gecos, &home,
		source, &format, db->options, line);
	if (!count) return;

	show = !(db->options->flags & DB_PLAINTEXTS);

	if (format) {
		split = format->methods.split;
 		if(format == &fmt_mscash)
 		{
 			char * ciphertext2 = (char *) mem_alloc_tiny(strlen(login) + strlen(ciphertext) + 4, MEM_ALIGN_NONE);
 			sprintf(ciphertext2, "M$%s#%s", login, ciphertext);
 			ciphertext = ciphertext2;
 		}
 		if(format == &fmt_oracle)
 		{
 			char * ciphertext2 = (char *) mem_alloc_tiny(strlen(login) + strlen(ciphertext) + 4, MEM_ALIGN_NONE);
 			sprintf(ciphertext2, "O$%s#%s", login, ciphertext);
 			ciphertext = ciphertext2;
 		}
		unify = format->params.flags & FMT_SPLIT_UNIFIES_CASE;
	} else {
		split = fmt_default_split;
		count = 1;
		unify = 0;
	}

	if (!*ciphertext) {
		found = 1;
		if (show) {
			if(mpi_id == 0) {
				printf("%s:NO PASSWORD", login);
			}
		}

		db->guess_count++;
	} else
	for (found = pass = 0; pass == 0 || (pass == 1 && found); pass++)
	for (index = 0; index < count; index++) {
		piece = split(ciphertext, index);
		if (unify)
			piece = strcpy(mem_alloc(strlen(piece) + 1), piece);

		hash = ldr_cracked_hash(piece);

		if ((current = db->cracked_hash[hash]))
		do {
			if (!strcmp(current->ciphertext, piece))
				break;
/* This extra check, along with ldr_cracked_hash() being case-insensitive,
 * is only needed for matching some pot file records produced by older
 * versions of John and contributed patches where split() didn't unify the
 * case of hex-encoded hashes. */
			if (unify &&
			    format->methods.valid(current->ciphertext) == 1 &&
			    !strcmp(split(current->ciphertext, 0), piece))
				break;
		} while ((current = current->next));

		if (unify)
			MEM_FREE(piece);

		if (pass) {
 			//modification by bartavelle, catches the no format bug
 			/*
 			if(format)
 				chars = format->params.plaintext_length;
 			else
 				chars = 0;
 
 			if (current && show && index < count - 1)
 			if ((int)strlen(current->plaintext) != chars)
 				current = NULL;
 			*/
 
			chars = 0;
			if (show) {
				if (format)
					chars = format->params.plaintext_length;
				if (index < count - 1 && current &&
				    (int)strlen(current->plaintext) != chars)
					current = NULL;
			}

			if (current) {
				if (show) {
					if(mpi_id == 0) {
						printf("%s", current->plaintext);
					}
				} else
					list_add(db->plaintexts,
						current->plaintext);

				db->guess_count++;
			} else
			if (show) {
				if(mpi_id == 0) {
					do {
						putchar('?');
					} while (--chars);
				}
			}
		} else
		if (current) {
			found = 1;
			if (show) {
				if(mpi_id == 0) {
					printf("%s:", login);
				}
			}
			break;
		}
	}

	if (found && show) {
		if(mpi_id == 0) {
			if (source[0])
				printf(":%s", source);
			else
				putchar('\n');
		}
	}

	if (format || found) db->password_count += count;
}
Beispiel #20
0
void *mem_alloc_copy(size_t size, size_t align, void *src)
{
	return memcpy(mem_alloc_tiny(size, align), src, size);
}
Beispiel #21
0
void rec_restore_args(int lock)
{
	char line[LINE_BUFFER_SIZE];
	int index, argc;
	char **argv;
	char *save_rec_name;

	rec_name_complete();
	if (!(rec_file = fopen(path_expand(rec_name), "r+"))) {
#ifndef HAVE_MPI
		if (options.fork && !john_main_process && errno == ENOENT) {
#else
		if (options.node_min > 1 && errno == ENOENT) {
#endif
			fprintf(stderr, "%u Session completed\n",
			    options.node_min);
			if (options.flags & FLG_STATUS_CHK)
				return;
			log_event("No crash recovery file, terminating");
			log_done();
#ifdef HAVE_MPI
			mpi_teardown();
#endif
			exit(0);
		}
#ifdef HAVE_MPI
		if (mpi_p > 1) {
			fprintf(stderr, "%u@%s: fopen: %s: %s\n",
				mpi_id + 1, mpi_name,
				path_expand(rec_name), strerror(errno));
			error();
		}
#endif
		pexit("fopen: %s", path_expand(rec_name));
	}
	rec_fd = fileno(rec_file);

	if (lock) rec_lock(lock);

	if (!fgetl(line, sizeof(line), rec_file)) rec_format_error("fgets");

	rec_version = 0;
	if (!strcmp(line, RECOVERY_V4)) rec_version = 4; else
	if (!strcmp(line, RECOVERY_V3)) rec_version = 3; else
	if (!strcmp(line, RECOVERY_V2)) rec_version = 2; else
	if (!strcmp(line, RECOVERY_V1)) rec_version = 1; else
	if (strcmp(line, RECOVERY_V0)) rec_format_error(NULL);

	if (fscanf(rec_file, "%d\n", &argc) != 1)
		rec_format_error("fscanf");
	if (argc < 2)
		rec_format_error(NULL);
	argv = mem_alloc_tiny(sizeof(char *) * (argc + 1), MEM_ALIGN_WORD);

	argv[0] = "john";

	for (index = 1; index < argc; index++)
	if (fgetl(line, sizeof(line), rec_file))
		argv[index] = str_alloc_copy(line);
	else
		rec_format_error("fgets");

	argv[argc] = NULL;

	save_rec_name = rec_name;
	opt_init(argv[0], argc, argv, 0);
	rec_name = save_rec_name;
	rec_name_completed = 1;

	if (fscanf(rec_file, "%u\n%u\n%x\n%x\n",
	    &status_restored_time,
	    &status.guess_count,
	    &status.combs.lo,
	    &status.combs.hi) != 4)
		rec_format_error("fscanf");
	if (!status_restored_time)
		status_restored_time = 1;

	if (rec_version >= 4) {
		if (fscanf(rec_file, "%x\n%x\n%x\n%x\n%x\n%d\n",
		    &status.combs_ehi,
		    &status.crypts.lo,
		    &status.crypts.hi,
		    &status.cands.lo,
		    &status.cands.hi,
		    &status.compat) != 6)
			rec_format_error("fscanf");
	} else {
/* Historically, we were reusing what became the combs field for candidates
 * count when in --stdout mode */
		status.cands = status.combs;
		status.compat = 1;
	}

	if (rec_version == 0) {
		status.pass = 0;
		status.progress = -1;
	} else
	if (fscanf(rec_file, "%d\n%d\n", &status.pass, &status.progress) != 2)
		rec_format_error("fscanf");
	if (status.pass < 0 || status.pass > 3)
		rec_format_error(NULL);

	if (rec_version < 3)
		rec_check = 0;
	else
	if (fscanf(rec_file, "%x\n", &rec_check) != 1)
		rec_format_error("fscanf");

	rec_restoring_now = 1;
}

void rec_restore_mode(int (*restore_mode)(FILE *file))
{
	rec_name_complete();

	if (!rec_file) return;

	if (restore_mode)
	if (restore_mode(rec_file)) rec_format_error("fscanf");

	if (options.flags & FLG_MASK_STACKED)
	if (mask_restore_state(rec_file)) rec_format_error("fscanf");
/*
 * Unlocking the file explicitly is normally not necessary since we're about to
 * close it anyway (which would normally release the lock).  However, when
 * we're the main process running with --fork, our newborn children may hold a
 * copy of the fd for a moment (until they close the fd themselves).  Thus, if
 * we don't explicitly remove the lock, there may be a race condition between
 * our children closing the fd and us proceeding to re-open and re-lock it.
 */
	rec_unlock();

	if (fclose(rec_file)) pexit("fclose");
	rec_file = NULL;

	rec_restoring_now = 0;
}