view simtool/bfsearch.c @ 192:edaccdbac95b

doc/GrcardSIM2-security-model: document ADM11 MF quirk
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 06 Mar 2021 21:41:12 +0000
parents 26d7a8815515
children
line wrap: on
line source

/*
 * This module implements a brute force search of file ID space at a given
 * file system directory level.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "simresp.h"
#include "file_id.h"

static
parse_skip_ids(argv, array, total)
	char **argv;
	unsigned *array, total;
{
	unsigned n;

	for (n = 0; n < total; n++) {
		if (!isxdigit(argv[n][0]) || !isxdigit(argv[n][1]) ||
		    !isxdigit(argv[n][2]) || !isxdigit(argv[n][3]) ||
		    argv[n][4]) {
			fprintf(stderr, "error: argument is not 4-digit hex\n");
			return(-1);
		}
		array[n] = strtoul(argv[n], 0, 16);
	}
	return(0);
}

static void
report_ef_struct(outf)
	FILE *outf;
{
	unsigned total_size, record_len;

	fputs("EF, ", outf);
	total_size = (sim_resp_data[2] << 8) | sim_resp_data[3];
	switch (sim_resp_data[13]) {
	case 0x00:
		fprintf(outf, "transparent, length %u\n", total_size);
		return;
	case 0x01:
		fputs("linear fixed, ", outf);
		break;
	case 0x03:
		fputs("cyclic, ", outf);
		break;
	default:
		fprintf(outf, "struct 0x%02X\n", sim_resp_data[13]);
		return;
	}
	if (sim_resp_data_len < 15) {
		fprintf(outf, "response struct cut off\n");
		return;
	}
	record_len = sim_resp_data[14];
	fprintf(outf, "record length %u", record_len);
	if (record_len && total_size % record_len == 0)
		fprintf(outf, ", %u records", total_size / record_len);
	putc('\n', outf);
}

cmd_bfsearch(argc, argv, outf)
	char **argv;
	FILE *outf;
{
	unsigned skip_ids[8], num_skip_ids;
	unsigned bfs, n;
	int rc;

	num_skip_ids = argc - 1;
	rc = parse_skip_ids(argv + 1, skip_ids, num_skip_ids);
	if (rc < 0)
		return(rc);
	rc = elem_select_op(skip_ids[0]);
	if (rc < 0)
		return(rc);
	if (!rc) {
		fprintf(stderr, "error: starting file ID 0x%04X not found\n",
			skip_ids[0]);
		return(-1);
	}
	for (bfs = 0; bfs <= 0xFFFF; bfs++) {
		for (n = 0; n < num_skip_ids; n++) {
			if (bfs == skip_ids[n])
				break;
		}
		if (n < num_skip_ids)
			continue;
		rc = elem_select_op(bfs);
		if (rc < 0)
			return(rc);
		if (!rc)
			continue;
		rc = get_response_op();
		if (rc < 0)
			return(rc);
		fprintf(outf, "%04X: ", bfs);
		if (sim_resp_data_len < 14)
			fprintf(outf, "too-short response struct\n");
		else {
			switch (sim_resp_data[6]) {
			case 0x01:
				fprintf(outf, "MF\n");
				break;
			case 0x02:
				fprintf(outf, "DF\n");
				break;
			case 0x04:
				report_ef_struct(outf);
				break;
			default:
				fprintf(outf, "unknown file type %02X\n",
					sim_resp_data[6]);
			}
		}
		rc = elem_select_op(skip_ids[0]);
		if (rc < 0)
			return(rc);
		if (!rc) {
			fprintf(stderr,
			"reselecting starting file ID 0x%04X not-found error\n",
				skip_ids[0]);
			return(-1);
		}
	}
	return(0);
}

static
bfsearch_dir(path, pathlen, siblings, nsiblings, outf)
	unsigned *path, pathlen, *siblings, nsiblings;
	FILE *outf;
{
	unsigned bfs, n;
	unsigned df_children[255], ndfc;
	unsigned childpath[8];
	int rc;

	for (n = 0; n < pathlen; n++) {
		rc = elem_select_op(path[n]);
		if (rc < 0)
			return(rc);
		if (!rc) {
			fprintf(stderr,
				"error selecting 0x%04X: file not found\n",
				path[n]);
			return(-1);
		}
	}
	ndfc = 0;
	for (bfs = 0; bfs <= 0xFFFF; bfs++) {
		for (n = 0; n < pathlen; n++) {
			if (bfs == path[n])
				break;
		}
		if (n < pathlen)
			continue;
		for (n = 0; n < nsiblings; n++) {
			if (bfs == siblings[n])
				break;
		}
		if (n < nsiblings)
			continue;
		rc = elem_select_op(bfs);
		if (rc < 0)
			return(rc);
		if (!rc)
			continue;
		rc = get_response_op();
		if (rc < 0)
			return(rc);
		for (n = 0; n < pathlen; n++)
			fprintf(outf, "%04X/", path[n]);
		fprintf(outf, "%04X: ", bfs);
		if (sim_resp_data_len < 14)
			fprintf(outf, "too-short response struct\n");
		else {
			switch (sim_resp_data[6]) {
			case 0x01:
				fprintf(outf, "MF\n");
				break;
			case 0x02:
				fprintf(outf, "DF\n");
				if (ndfc < 255)
					df_children[ndfc++] = bfs;
				break;
			case 0x04:
				report_ef_struct(outf);
				break;
			default:
				fprintf(outf, "unknown file type %02X\n",
					sim_resp_data[6]);
			}
		}
		rc = elem_select_op(path[pathlen-1]);
		if (rc < 0)
			return(rc);
		if (!rc) {
			fprintf(stderr,
			"reselecting starting file ID 0x%04X not-found error\n",
				path[pathlen-1]);
			return(-1);
		}
	}
	if (pathlen >= 8)
		return(0);
	for (n = 0; n < pathlen; n++)
		childpath[n] = path[n];
	for (n = 0; n < ndfc; n++) {
		childpath[pathlen] = df_children[n];
		rc = bfsearch_dir(childpath, pathlen + 1, df_children, ndfc,
				  outf);
		if (rc < 0)
			return(rc);
	}
	return(0);
}

cmd_bfsearch_full(argc, argv, outf)
	char **argv;
	FILE *outf;
{
	unsigned initpath;

	initpath = FILEID_MF;
	return bfsearch_dir(&initpath, 1, &initpath, 1, outf);
}