FreeCalypso > hg > fc-sim-tools
changeset 9:c9ef9e91dd8e
new libcommon, initial version
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 14 Mar 2021 06:55:38 +0000 |
parents | 34bbb0585cab |
children | ddd767f6e15b |
files | libcommon/Makefile libcommon/apdu.c libcommon/apducmd.c libcommon/atr.c libcommon/backend.c libcommon/be_init.c libcommon/chkblank.c libcommon/dumpdirfunc.c libcommon/exit.c libcommon/file_id.h libcommon/globalopts.c libcommon/hexdump.c libcommon/localcd.c libcommon/names.c libcommon/simresp.h |
diffstat | 15 files changed, 696 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/Makefile Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,14 @@ +CC= gcc +CFLAGS= -O2 +OBJS= apdu.o apducmd.o atr.o backend.o be_init.o chkblank.o dumpdirfunc.o \ + exit.o globalopts.o hexdump.o localcd.o names.o +LIB= libcommon.a + +all: ${LIB} + +${LIB}: ${OBJS} + ar rcu $@ ${OBJS} + ranlib $@ + +clean: + rm -f *.[oa] errs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/apdu.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,84 @@ +#include <sys/types.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +extern FILE *cpipeF, *rpipeF; + +u_char sim_resp_data[258]; +unsigned sim_resp_data_len, sim_resp_sw; + +static void +send_cmd(cmd_apdu, cmd_apdu_len) + u_char *cmd_apdu; + unsigned cmd_apdu_len; +{ + unsigned n; + + for (n = 0; n < cmd_apdu_len; n++) + fprintf(cpipeF, "%02X", cmd_apdu[n]); + putc('\n', cpipeF); + fflush(cpipeF); +} + +static +parse_response_hex_string(input) + char *input; +{ + char *cp; + + sim_resp_data_len = 0; + for (cp = input; *cp; cp += 2) { + if (!isxdigit(cp[0]) || !isxdigit(cp[1])) { + fprintf(stderr, + "comm error: invalid hex string from back end\n"); + return(-1); + } + sim_resp_data[sim_resp_data_len++] = + (decode_hex_digit(cp[0]) << 4) | + decode_hex_digit(cp[1]); + } + return(0); +} + +apdu_exchange(cmd_apdu, cmd_apdu_len) + u_char *cmd_apdu; + unsigned cmd_apdu_len; +{ + char inbuf[518], *cp; + u_char *sw; + int rc; + + send_cmd(cmd_apdu, cmd_apdu_len); + if (!fgets(inbuf, sizeof inbuf, rpipeF)) { + fprintf(stderr, "comm error: EOF reading from back end\n"); + return(-1); + } + cp = index(inbuf, '\n'); + if (!cp) { + fprintf(stderr, + "comm error: response from back end has no newline\n"); + return(-1); + } + *cp = '\0'; + if (!inbuf[0]) { + fprintf(stderr, + "comm error: response from back end is an empty line\n"); + return(-1); + } + if (!isxdigit(inbuf[0]) || !isxdigit(inbuf[1]) || !isxdigit(inbuf[2]) + || !isxdigit(inbuf[3])) { + /* we got a back end error message */ + fprintf(stderr, "%s\n", inbuf); + return(-1); + } + rc = parse_response_hex_string(inbuf); + if (rc < 0) + return(rc); + sim_resp_data_len -= 2; + sw = sim_resp_data + sim_resp_data_len; + sim_resp_sw = (sw[0] << 8) | sw[1]; + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/apducmd.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,26 @@ +/* + * This module implements a low-level debug command + * for users to manually send arbitrary APDUs. + */ + +#include <sys/types.h> +#include <stdio.h> +#include "simresp.h" + +cmd_apdu(argc, argv) + char **argv; +{ + u_char cmd[260]; + int rc; + unsigned len; + + rc = decode_hex_data_from_string(argv[1], cmd, 5, 260); + if (rc < 0) + return(rc); + len = rc; + rc = apdu_exchange(cmd, len); + if (rc < 0) + return(rc); + printf("%04X\n", sim_resp_sw); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/atr.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,40 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +extern FILE *cpipeF, *rpipeF; +extern char be_atr_string[]; + +cmd_atr() +{ + char inbuf[128], *cp; + + /* do we have it already? */ + if (be_atr_string[0]) { + printf("ATR: %s\n", be_atr_string); + return(0); + } + /* nope - request it from the BE */ + fputs("atr\n", cpipeF); + fflush(cpipeF); + /* collect BE response */ + if (!fgets(inbuf, sizeof inbuf, rpipeF)) { + fprintf(stderr, "comm error: EOF reading from back end\n"); + return(-1); + } + cp = index(inbuf, '\n'); + if (!cp) { + fprintf(stderr, + "comm error: response from back end has no newline\n"); + return(-1); + } + *cp = '\0'; + if (!inbuf[0]) { + fprintf(stderr, + "comm error: response from back end is an empty line\n"); + return(-1); + } + puts(inbuf); + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/backend.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,82 @@ +/* + * This module is responsible for launching and connecting + * our SIM card communication back end. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +extern unsigned calypso_fd, pcsc_reader_num; + +static char calypso_be_pathname[] = "/opt/freecalypso/bin/fcsim-calypso-be"; +static char pcsc_be_pathname[] = "/opt/freecalypso/bin/fc-pcsc-backend"; + +static char *backend_prog, *backend_argv[3], backend_optarg[16]; + +FILE *cpipeF, *rpipeF; + +static void +setup_be_calypso() +{ + backend_prog = calypso_be_pathname; + backend_argv[0] = "fcsim-calypso-be"; + sprintf(backend_optarg, "-C%u", calypso_fd); + backend_argv[1] = backend_optarg; + backend_argv[2] = 0; +} + +static void +setup_be_pcsc() +{ + backend_prog = pcsc_be_pathname; + backend_argv[0] = "fc-pcsc-backend"; + sprintf(backend_optarg, "-p%u", pcsc_reader_num); + backend_argv[1] = backend_optarg; + backend_argv[2] = 0; +} + +launch_backend() +{ + int cpipe[2], rpipe[2], rc; + + if (calypso_fd) + setup_be_calypso(); + else + setup_be_pcsc(); + if (pipe(cpipe) < 0 || pipe(rpipe) < 0) { + perror("pipe"); + exit(1); + } + rc = vfork(); + if (rc < 0) { + perror("vfork for launching back end"); + exit(1); + } + if (!rc) { + /* we are in the child - prepare to exec the BE */ + dup2(cpipe[0], 0); + dup2(rpipe[1], 1); + close(cpipe[0]); + close(cpipe[1]); + close(rpipe[0]); + close(rpipe[1]); + /* do the exec */ + execv(backend_prog, backend_argv); + perror(backend_prog); + _exit(1); + } + close(cpipe[0]); + close(rpipe[1]); + cpipeF = fdopen(cpipe[1], "w"); + if (!cpipeF) { + perror("fdopen"); + exit(1); + } + rpipeF = fdopen(rpipe[0], "r"); + if (!rpipeF) { + perror("fdopen"); + exit(1); + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/be_init.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,59 @@ +/* + * This module is responsible for collecting the initial info + * strings emitted by the back end. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +extern FILE *rpipeF; + +#define MAX_INIT_STRING 254 + +char be_reader_name[MAX_INIT_STRING+1]; +char be_atr_string[MAX_INIT_STRING+1]; + +static void +copy_without_leading_space(input_str, dest) + char *input_str, *dest; +{ + char *cp; + + for (cp = input_str; isspace(*cp); cp++) + ; + strcpy(dest, cp); +} + +collect_backend_init_strings() +{ + char inbuf[MAX_INIT_STRING+2], *cp; + + for (;;) { + if (!fgets(inbuf, sizeof inbuf, rpipeF)) { + fprintf(stderr, + "start-up error: EOF reading init strings from back end\n"); + exit(1); + } + cp = index(inbuf, '\n'); + if (!cp) { + fprintf(stderr, + "start-up error: init string from back end has no newline\n"); + exit(1); + } + *cp = '\0'; + if (!inbuf[0]) + break; + switch (inbuf[0]) { + case 'A': + copy_without_leading_space(inbuf + 1, be_atr_string); + break; + case 'R': + copy_without_leading_space(inbuf + 1, be_reader_name); + break; + } + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/chkblank.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,14 @@ +#include <sys/types.h> +#include "simresp.h" + +check_simresp_all_blank() +{ + u_char *dp, *endp; + + dp = sim_resp_data; + endp = sim_resp_data + sim_resp_data_len; + while (dp < endp) + if (*dp++ != 0xFF) + return(0); + return(1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/dumpdirfunc.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,107 @@ +/* + * This module implements the common function for dumping EF_DIR. + */ + +#include <sys/types.h> +#include <stdio.h> +#include "simresp.h" + +static void +dump_aid(tlv, outf) + u_char *tlv; + FILE *outf; +{ + unsigned reclen, n; + + reclen = tlv[1]; + fputs(" AID:", outf); + for (n = 0; n < reclen; n++) + fprintf(outf, " %02X", tlv[n+2]); + putc('\n', outf); +} + +static void +dump_label(tlv, outf) + u_char *tlv; + FILE *outf; +{ + int rc; + unsigned textlen; + + fputs(" Label: ", outf); + rc = validate_alpha_field(tlv + 2, tlv[1], &textlen); + if (rc < 0) { + fputs("malformed\n", outf); + return; + } + print_alpha_field(tlv + 2, textlen, outf); + putc('\n', outf); +} + +static void +dump_unknown_tlv(tlv, outf) + u_char *tlv; + FILE *outf; +{ + unsigned reclen, n; + + reclen = tlv[1] + 2; + fputs(" TLV:", outf); + for (n = 0; n < reclen; n++) + fprintf(outf, " %02X", tlv[n]); + putc('\n', outf); +} + +void +dump_efdir_record(outf) + FILE *outf; +{ + unsigned totlen, reclen; + u_char *dp, *endp; + + if (sim_resp_data[0] != 0x61) { + fprintf(outf, " bad: first byte != 0x61\n"); + return; + } + totlen = sim_resp_data[1]; + if (totlen < 3 || totlen > 0x7F) { + fprintf(outf, " bad: global length byte 0x%02X is invalid\n", + totlen); + return; + } + if (totlen + 2 > sim_resp_data_len) { + fprintf(outf, + " bad: TLV global length exceeds EF record length\n"); + return; + } + dp = sim_resp_data + 2; + endp = sim_resp_data + 2 + totlen; + while (dp < endp) { + if (endp - dp < 2) { +trunc_error: fprintf(outf, " bad: truncated TLV record\n"); + return; + } + if ((dp[0] & 0x1F) == 0x1F) { + fprintf(outf, " bad: extended tag not supported\n"); + return; + } + if (dp[1] & 0x80) { + fprintf(outf, " bad: extended length not supported\n"); + return; + } + reclen = dp[1] + 2; + if (endp - dp < reclen) + goto trunc_error; + switch (dp[0]) { + case 0x4F: + dump_aid(dp, outf); + break; + case 0x50: + dump_label(dp, outf); + break; + default: + dump_unknown_tlv(dp, outf); + } + dp += reclen; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/exit.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +extern unsigned calypso_fd; +extern FILE *cpipeF; + +good_exit() +{ + if (calypso_fd) { + fputs("poweroff\n", cpipeF); + fflush(cpipeF); + } + exit(0); +} + +cmd_exit(argc, argv) + char **argv; +{ + if (argc < 2) + good_exit(); + if (!calypso_fd) { + fprintf(stderr, + "error: exit arguments are only meaningful with Calypso back end\n"); + return(-1); + } + if (!strcmp(argv[1], "bare")) + exit(0); + if (!strcmp(argv[1], "iota-off")) { + fputs("poweroff\n", cpipeF); + fflush(cpipeF); + exit(0); + } + fprintf(stderr, "error: \"%s\" is not an understood exit mode\n", + argv[1]); + return(-1); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/file_id.h Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,55 @@ +/* definitions of a few file IDs we find interesting */ + +#define FILEID_MF 0x3F00 +#define FILEID_ADF 0x7FFF + +#define DF_TELECOM 0x7F10 +#define DF_GSM 0x7F20 +#define DF_DCS1800 0x7F21 + +/* EFs under MF */ +#define EF_DIR 0x2F00 +#define EF_ICCID 0x2FE2 + +/* EFs under DF_GSM */ +#define EF_LP 0x6F05 +#define EF_IMSI 0x6F07 +#define EF_Kc 0x6F20 +#define EF_PLMNsel 0x6F30 +#define EF_HPLMN 0x6F31 +#define EF_ACMmax 0x6F37 +#define EF_SST 0x6F38 +#define EF_ACM 0x6F39 +#define EF_GID1 0x6F3E +#define EF_GID2 0x6F3F +#define EF_PUCT 0x6F41 +#define EF_CBMI 0x6F45 +#define EF_SPN 0x6F46 +#define EF_CBMID 0x6F48 +#define EF_CBMIR 0x6F50 +#define EF_BCCH 0x6F74 +#define EF_ACC 0x6F78 +#define EF_FPLMN 0x6F7B +#define EF_LOCI 0x6F7E +#define EF_AD 0x6FAD +#define EF_PHASE 0x6FAE +#define EF_ECC 0x6FB7 +#define EF_PNN 0x6FC5 +#define EF_OPL 0x6FC6 +#define EF_MBDN 0x6FC7 +#define EF_MBI 0x6FC9 +#define EF_MWIS 0x6FCA + +/* EFs under DF_TELECOM */ +#define EF_ADN 0x6F3A +#define EF_FDN 0x6F3B +#define EF_SMS 0x6F3C +#define EF_CCP 0x6F3D +#define EF_MSISDN 0x6F40 +#define EF_SMSP 0x6F42 +#define EF_SMSS 0x6F43 +#define EF_LND 0x6F44 +#define EF_SDN 0x6F49 +#define EF_EXT1 0x6F4A +#define EF_EXT2 0x6F4B +#define EF_EXT3 0x6F4C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/globalopts.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,32 @@ +/* + * This module implements parsing of global command line options. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +unsigned calypso_fd, pcsc_reader_num; + +parse_global_options(argc, argv) + char **argv; +{ + extern char *optarg; + int c; + + while ((c = getopt(argc, argv, "+C:p:")) != EOF) { + switch (c) { + case 'C': + calypso_fd = atoi(optarg); + continue; + case 'p': + pcsc_reader_num = atoi(optarg); + continue; + case '?': + default: + /* error msg already printed */ + exit(1); + } + } + return(0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/hexdump.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,44 @@ +#include <sys/types.h> +#include <stdio.h> +#include "simresp.h" + +display_sim_resp_in_hex(outf) + FILE *outf; +{ + unsigned off, cc, n, c; + + for (off = 0; off < sim_resp_data_len; off += cc) { + fprintf(outf, "%02X:", off); + cc = 16; + if (sim_resp_data_len - off < cc) + cc = sim_resp_data_len - off; + for (n = 0; n < 16; n++) { + if (n == 0 || n == 8) + putc(' ', outf); + putc(' ', outf); + if (n < cc) + fprintf(outf, "%02X", sim_resp_data[off + n]); + else { + putc(' ', outf); + putc(' ', outf); + } + } + putc(' ', outf); + putc(' ', outf); + for (n = 0; n < cc; n++) { + c = sim_resp_data[off + n]; + if (c < 0x20 || c > 0x7E) + c = '.'; + putc(c, outf); + } + putc('\n', outf); + } + return(0); +} + +cmd_sim_resp(argc, argv, outf) + char **argv; + FILE *outf; +{ + return display_sim_resp_in_hex(outf); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/localcd.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,18 @@ +/* + * This module implements the local cd command. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +cmd_cd(argc, argv) + char **argv; +{ + int rc; + + rc = chdir(argv[1]); + if (rc < 0) + perror(argv[1]); + return rc; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/names.c Sun Mar 14 06:55:38 2021 +0000 @@ -0,0 +1,79 @@ +/* + * This module contains the table of user-friendly file names + * and a function for searching this table. + */ + +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <stdlib.h> +#include "file_id.h" + +static struct nametab { + char *name; + int file_id; +} name_table[] = { + {"MF", FILEID_MF}, + {"DF_GSM", DF_GSM}, + {"DF_DCS1800", DF_DCS1800}, + {"DF_TELECOM", DF_TELECOM}, + {"gsm", DF_GSM}, + {"telecom", DF_TELECOM}, + /* EFs under MF */ + {"EF_DIR", EF_DIR}, + {"EF_ICCID", EF_ICCID}, + /* EFs under DF_GSM */ + {"EF_LP", EF_LP}, + {"EF_IMSI", EF_IMSI}, + {"EF_Kc", EF_Kc}, + {"EF_PLMNsel", EF_PLMNsel}, + {"EF_HPLMN", EF_HPLMN}, + {"EF_ACMmax", EF_ACMmax}, + {"EF_SST", EF_SST}, + {"EF_ACM", EF_ACM}, + {"EF_GID1", EF_GID1}, + {"EF_GID2", EF_GID2}, + {"EF_PUCT", EF_PUCT}, + {"EF_CBMI", EF_CBMI}, + {"EF_SPN", EF_SPN}, + {"EF_CBMID", EF_CBMID}, + {"EF_CBMIR", EF_CBMIR}, + {"EF_BCCH", EF_BCCH}, + {"EF_ACC", EF_ACC}, + {"EF_FPLMN", EF_FPLMN}, + {"EF_LOCI", EF_LOCI}, + {"EF_AD", EF_AD}, + {"EF_PHASE", EF_PHASE}, + {"EF_ECC", EF_ECC}, + {"EF_PNN", EF_PNN}, + {"EF_OPL", EF_OPL}, + {"EF_MBDN", EF_MBDN}, + {"EF_MBI", EF_MBI}, + {"EF_MWIS", EF_MWIS}, + /* EFs under DF_TELECOM */ + {"EF_ADN", EF_ADN}, + {"EF_FDN", EF_FDN}, + {"EF_SMS", EF_SMS}, + {"EF_CCP", EF_CCP}, + {"EF_MSISDN", EF_MSISDN}, + {"EF_SMSP", EF_SMSP}, + {"EF_SMSS", EF_SMSS}, + {"EF_LND", EF_LND}, + {"EF_SDN", EF_SDN}, + {"EF_EXT1", EF_EXT1}, + {"EF_EXT2", EF_EXT2}, + {"EF_EXT3", EF_EXT3}, + /* table search terminator */ + {0, -1} +}; + +find_symbolic_file_name(soughtname) + char *soughtname; +{ + struct nametab *tp; + + for (tp = name_table; tp->name; tp++) + if (!strcmp(tp->name, soughtname)) + break; + return tp->file_id; +}