# HG changeset patch # User Mychaela Falconia # Date 1615700557 0 # Node ID 34bbb0585cab32914eef1cee847cfd2c0bcc0fec # Parent b25d4dfe5798531572ee98e7bfd5d37d46e7f4b9 libutil: import from previous fc-pcsc-tools version diff -r b25d4dfe5798 -r 34bbb0585cab libutil/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/Makefile Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,17 @@ +CC= gcc +CFLAGS= -O2 +OBJS= alpha_decode.o alpha_fromfile.o alpha_valid.o decimal_str.o \ + filesearch.o gsm7_decode.o gsm7_encode.o gsm7_encode_table.o \ + gsm7_pack.o gsm7_unpack.o hexdigits.o hexread.o hexstr.o iccid_luhn.o \ + nibbles2asc.o number_decode.o number_encode.o pinentry.o plmncodes.o \ + plmnlist.o revnibbles.o shorthand.o +LIB= libutil.a + +all: ${LIB} + +${LIB}: ${OBJS} + ar rcu $@ ${OBJS} + ranlib $@ + +clean: + rm -f *.[oa] errs diff -r b25d4dfe5798 -r 34bbb0585cab libutil/alpha_decode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/alpha_decode.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,38 @@ +/* + * This module contains functions for decoding and displaying alpha fields + * that exist in various SIM files. + */ + +#include +#include + +static void +print_alpha_field_hex(data, nbytes, outf) + u_char *data; + unsigned nbytes; + FILE *outf; +{ + u_char *dp, *endp; + + fputs("HEX ", outf); + dp = data; + endp = data + nbytes; + while (dp < endp) + fprintf(outf, "%02X", *dp++); +} + +void +print_alpha_field(data, nbytes, outf) + u_char *data; + unsigned nbytes; + FILE *outf; +{ + if (!nbytes) { + fputs("\"\"", outf); + return; + } + if (data[0] & 0x80) + print_alpha_field_hex(data, nbytes, outf); + else + print_gsm7_string_to_file(data, nbytes, outf); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/alpha_fromfile.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/alpha_fromfile.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,107 @@ +/* + * This module implements functions for parsing alpha tag strings + * from input data files, to be used by commands like pb-update + * and smsp-restore. + */ + +#include +#include +#include + +extern u_char gsm7_encode_table[256]; + +char * +alpha_from_file_qstring(cp, record, maxlen, filename_for_errs, lineno_for_errs) + char *cp, *filename_for_errs; + u_char *record; + unsigned maxlen; +{ + unsigned acclen, nadd; + int c; + + for (acclen = 0; ; ) { + if (*cp == '\0') { +unterm_qstring: fprintf(stderr, + "%s line %d: unterminated quoted string\n", + filename_for_errs, lineno_for_errs); + return(0); + } + if (*cp == '"') + break; + c = *cp++; + if (c == '\\') { + if (*cp == '\0') + goto unterm_qstring; + c = *cp++; + if (c >= '0' && c <= '7' && isxdigit(*cp)) { + c = ((c - '0') << 4) | decode_hex_digit(*cp++); + goto bypass_encoding; + } + switch (c) { + case 'n': + c = '\n'; + goto bypass_encoding; + case 'r': + c = '\r'; + goto bypass_encoding; + case 'e': + c = 0x1B; + goto bypass_encoding; + case '"': + case '\\': + break; + default: + fprintf(stderr, + "%s line %d: non-understood backslash escape\n", + filename_for_errs, lineno_for_errs); + return(0); + } + } + c = gsm7_encode_table[c]; + if (c == 0xFF) { + fprintf(stderr, + "%s line %d: character in quoted string cannot be encoded in GSM7\n", + filename_for_errs, lineno_for_errs); + return(0); + } +bypass_encoding: + if (c & 0x80) + nadd = 2; + else + nadd = 1; + if (acclen + nadd > maxlen) { + fprintf(stderr, + "%s line %d: alpha tag string is longer than SIM limit\n", + filename_for_errs, lineno_for_errs); + return(0); + } + if (c & 0x80) + record[acclen++] = 0x1B; + record[acclen++] = c & 0x7F; + } + return(cp + 1); +} + +char * +alpha_from_file_hex(cp, record, maxlen, filename_for_errs, lineno_for_errs) + char *cp, *filename_for_errs; + u_char *record; + unsigned maxlen; +{ + unsigned acclen; + + for (acclen = 0; ; ) { + if (!isxdigit(cp[0]) || !isxdigit(cp[1])) + break; + if (acclen >= maxlen) { + fprintf(stderr, + "%s line %d: alpha tag string is longer than SIM limit\n", + filename_for_errs, lineno_for_errs); + return(0); + } + record[acclen++] = (decode_hex_digit(cp[0]) << 4) | + decode_hex_digit(cp[1]); + cp += 2; + } + return(cp); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/alpha_valid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/alpha_valid.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,152 @@ +/* + * This module contains functions for validating alpha fields + * that exist in various SIM files. + */ + +#include +#include +#include +#include +#include + +static +validate_classic_gsm(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp; + unsigned n; + + dp = data; + for (n = 0; n < nbytes; n++) { + if (*dp == 0xFF) + break; + if (*dp & 0x80) + return(-1); + dp++; + } + if (textlenp) + *textlenp = n; + for (; n < nbytes; n++) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_ucs2_80(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp, *endp; + + if (nbytes < 3) + return(-1); + dp = data + 1; + endp = data + nbytes; + while (dp < endp) { + if (dp + 1 == endp) { + if (*dp != 0xFF) + return(-1); + if (textlenp) + *textlenp = dp - data; + return(0); + } + if (dp[0] == 0xFF && dp[1] == 0xFF) + break; + dp += 2; + } + if (textlenp) + *textlenp = dp - data; + while (dp < endp) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_ucs2_81(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp, *endp; + unsigned textlen; + + if (nbytes < 4) + return(-1); + if (!data[1]) + return(-1); + textlen = data[1] + 3; + if (textlen > nbytes) + return(-1); + if (textlenp) + *textlenp = textlen; + dp = data + textlen; + endp = data + nbytes; + while (dp < endp) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_ucs2_82(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp, *endp; + unsigned textlen; + + if (nbytes < 5) + return(-1); + if (!data[1]) + return(-1); + textlen = data[1] + 4; + if (textlen > nbytes) + return(-1); + if (textlenp) + *textlenp = textlen; + dp = data + textlen; + endp = data + nbytes; + while (dp < endp) + if (*dp++ != 0xFF) + return(-1); + return(0); +} + +static +validate_empty(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + u_char *dp; + unsigned n; + + dp = data; + for (n = 0; n < nbytes; n++) + if (*dp++ != 0xFF) + return(-1); + if (textlenp) + *textlenp = 0; + return(0); +} + +validate_alpha_field(data, nbytes, textlenp) + u_char *data; + unsigned nbytes, *textlenp; +{ + if (data[0] < 0x80) + return validate_classic_gsm(data, nbytes, textlenp); + switch (data[0]) { + case 0x80: + return validate_ucs2_80(data, nbytes, textlenp); + case 0x81: + return validate_ucs2_81(data, nbytes, textlenp); + case 0x82: + return validate_ucs2_82(data, nbytes, textlenp); + case 0xFF: + return validate_empty(data, nbytes, textlenp); + default: + return -1; + } +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/decimal_str.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/decimal_str.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,41 @@ +/* + * This module implements some functions for initial parsing of decimal + * string arguments, intended for implementation of commands like + * write-iccid and write-imsi. + */ + +#include +#include +#include + +parse_decimal_string_arg(arg, dest, maxdigits) + char *arg; + u_char *dest; + unsigned maxdigits; +{ + unsigned n, ndig; + + if (!*arg) { + fprintf(stderr, + "error: empty argument given for decimal string\n"); + return(-1); + } + for (n = 0; *arg; ) { + if (!isdigit(*arg)) { + fprintf(stderr, + "error: non-digit char in decimal string argument\n"); + return(-1); + } + if (n >= maxdigits) { + fprintf(stderr, + "error: decimal string exceeds limit of %u digits\n", + maxdigits); + return(-1); + } + dest[n++] = *arg++ - '0'; + } + ndig = n; + while (n < maxdigits) + dest[n++] = 0xF; + return ndig; +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/filesearch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/filesearch.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,27 @@ +/* + * This module implements the function that searches for files + * in a dedicated directory for SIM programming scripts. + */ + +#include +#include +#include + +static char script_install_dir[] = "/opt/freecalypso/sim-scripts"; + +FILE * +open_script_input_file(req_filename) + char *req_filename; +{ + char pathbuf[256]; + FILE *f; + + if (!index(req_filename, '/') && strlen(req_filename) < 128) { + sprintf(pathbuf, "%s/%s", script_install_dir, req_filename); + f = fopen(pathbuf, "r"); + if (f) + return f; + } + f = fopen(req_filename, "r"); + return f; +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/gsm7_decode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/gsm7_decode.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,88 @@ +/* + * This module contains functions for decoding GSM7 strings + * that exist in various SIM files. + */ + +#include +#include + +static char gsm7_decode_table[128] = { + '@', 0, '$', 0, 0, 0, 0, 0, + 0, 0, '\n', 0, 0, '\r', 0, 0, + 0, '_', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + ' ', '!', '"', '#', 0, '%', '&', 0x27, + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 0, 0, 0, 0, 0, + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0, 0, 0, 0, 0 +}; + +static char gsm7ext_decode_table[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0, '\\', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0, + '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void +print_gsm7_string_to_file(data, nbytes, outf) + u_char *data; + unsigned nbytes; + FILE *outf; +{ + u_char *dp, *endp; + int b, c; + + dp = data; + endp = data + nbytes; + putc('"', outf); + while (dp < endp) { + b = *dp++; + if (b == 0x1B) { + if (dp >= endp || *dp == 0x1B || *dp == '\n' || + *dp == '\r') { + putc('\\', outf); + putc('e', outf); + continue; + } + b = *dp++; + c = gsm7ext_decode_table[b]; + if (!c) { + fprintf(outf, "\\e\\%02X", b); + continue; + } + } else { + c = gsm7_decode_table[b]; + if (!c) { + fprintf(outf, "\\%02X", b); + continue; + } + } + if (c == '\n') { + putc('\\', outf); + putc('n', outf); + continue; + } + if (c == '\r') { + putc('\\', outf); + putc('r', outf); + continue; + } + if (c == '"' || c == '\\') + putc('\\', outf); + putc(c, outf); + } + putc('"', outf); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/gsm7_encode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/gsm7_encode.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,76 @@ +/* + * This module implements functions for parsing quoted string + * arguments intended for GSM7 string encoding, and actually + * encoding them into GSM7 binary strings. + */ + +#include +#include +#include + +extern u_char gsm7_encode_table[256]; + +qstring_arg_to_gsm7(arg, record, maxlen) + char *arg; + u_char *record; + unsigned maxlen; +{ + unsigned acclen, nadd; + char *cp; + int c; + + cp = arg; + for (acclen = 0; *cp; ) { + c = *cp++; + if (c == '\\') { + if (*cp == '\0') { + fprintf(stderr, + "error: dangling backslash escape\n"); + return(-1); + } + c = *cp++; + if (c >= '0' && c <= '7' && isxdigit(*cp)) { + c = ((c - '0') << 4) | decode_hex_digit(*cp++); + goto bypass_encoding; + } + switch (c) { + case 'n': + c = '\n'; + goto bypass_encoding; + case 'r': + c = '\r'; + goto bypass_encoding; + case 'e': + c = 0x1B; + goto bypass_encoding; + case '"': + case '\\': + break; + default: + fprintf(stderr, + "error: non-understood backslash escape\n"); + return(-1); + } + } + c = gsm7_encode_table[c]; + if (c == 0xFF) { + fprintf(stderr, + "error: character in alpha tag string cannot be encoded in GSM7\n"); + return(-1); + } +bypass_encoding: + if (c & 0x80) + nadd = 2; + else + nadd = 1; + if (acclen + nadd > maxlen) { + fprintf(stderr, + "error: alpha tag string is longer than SIM limit\n"); + return(-1); + } + if (c & 0x80) + record[acclen++] = 0x1B; + record[acclen++] = c & 0x7F; + } + return(acclen); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/gsm7_encode_table.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/gsm7_encode_table.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,43 @@ +/* + * This library module contains the table for encoding from ISO 8859-1 + * into the GSM 7-bit default alphabet (03.38 or 23.038). High bit set + * in the output indicates escape encoding, used for ASCII characters + * [\]^ and {|}~. 0xFF indicates invalid chars. + */ + +#include + +u_char gsm7_encode_table[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x00 */ + 0xFF, 0xFF, '\n', 0xFF, 0xFF, '\r', 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x10 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ' ', '!', '"', '#', 0x02, '%', '&', 0x27, /* 0x20 */ + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30 */ + '8', '9', ':', ';', '<', '=', '>', '?', + 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 */ + 'X', 'Y', 'Z', 0xBC, 0xAF, 0xBE, 0x94, 0x11, + 0xFF, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 */ + 'x', 'y', 'z', 0xA8, 0xC0, 0xA9, 0xBD, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x80 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0x90 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x40, 0xFF, 0x01, 0x24, 0x03, 0xFF, 0x5F, /* 0xA0 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 0xB0 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, + 0xFF, 0xFF, 0xFF, 0xFF, 0x5B, 0x0E, 0x1C, 0x09, /* 0xC0 */ + 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, 0x5C, 0xFF, /* 0xD0 */ + 0x0B, 0xFF, 0xFF, 0xFF, 0x5E, 0xFF, 0xFF, 0x1E, + 0x7F, 0xFF, 0xFF, 0xFF, 0x7B, 0x0F, 0x1D, 0xFF, /* 0xE0 */ + 0x04, 0x05, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, + 0xFF, 0x7D, 0x08, 0xFF, 0xFF, 0xFF, 0x7C, 0xFF, /* 0xF0 */ + 0x0C, 0x06, 0xFF, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF +}; diff -r b25d4dfe5798 -r 34bbb0585cab libutil/gsm7_pack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/gsm7_pack.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,22 @@ +/* + * This library module implements the function for packing septets into octets. + */ + +#include + +gsm7_pack(inbuf, outbuf, noctets) + u_char *inbuf, *outbuf; + unsigned noctets; +{ + u_char *ip = inbuf, *op = outbuf; + unsigned n, c; + + for (n = 0; n < noctets; n++) { + c = n % 7; + *op++ = ((ip[1] << 7) | ip[0]) >> c; + if (c == 6) + ip += 2; + else + ip += 1; + } +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/gsm7_unpack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/gsm7_unpack.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,22 @@ +/* + * This library module implements unpacking of GSM 7-bit data + * from packed octets. + */ + +#include + +static u_char shift[8] = {0, 7, 6, 5, 4, 3, 2, 1}; + +gsm7_unpack(inbuf, outbuf, nseptets) + u_char *inbuf, *outbuf; + unsigned nseptets; +{ + u_char *inp = inbuf, *outp = outbuf; + unsigned n; + + for (n = 0; n < nseptets; n++) { + *outp++ = (((inp[1] << 8) | inp[0]) >> shift[n&7]) & 0x7F; + if (n & 7) + inp++; + } +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/hexdigits.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/hexdigits.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,23 @@ +/* + * This module contains elementary functions for working with hex digits. + */ + +decode_hex_digit(c) +{ + if (c >= '0' && c <= '9') + return(c - '0'); + if (c >= 'A' && c <= 'F') + return(c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return(c - 'a' + 10); + return(-1); +} + +encode_hex_digit(d) + unsigned d; +{ + if (d <= 9) + return(d + '0'); + else + return(d - 10 + 'A'); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/hexread.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/hexread.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,63 @@ +/* + * This module contains the function for reading hex files, + * to be used in the implementation of manual write commands. + */ + +#include +#include +#include +#include + +extern FILE *open_script_input_file(); + +read_hex_data_file(filename, databuf, maxlen) + char *filename; + u_char *databuf; + unsigned maxlen; +{ + FILE *inf; + unsigned count; + int c, c2; + + inf = open_script_input_file(filename); + if (!inf) { + perror(filename); + return(-1); + } + for (count = 0; ; ) { + do + c = getc(inf); + while (isspace(c)); + if (c < 0) + break; + if (c == '#') { + do + c = getc(inf); + while (c >= 0 && c != '\n'); + continue; + } + if (!isxdigit(c)) { +inv_input: fprintf(stderr, "%s: invalid hex file input\n", + filename); + fclose(inf); + return(-1); + } + c2 = getc(inf); + if (!isxdigit(c2)) + goto inv_input; + if (count >= maxlen) { + fprintf(stderr, "%s: hex input data is too long\n", + filename); + fclose(inf); + return(-1); + } + databuf[count++] = (decode_hex_digit(c) << 4) | + decode_hex_digit(c2); + } + fclose(inf); + if (!count) { + fprintf(stderr, "%s: no hex data input found\n", filename); + return(-1); + } + return(count); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/hexstr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/hexstr.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,38 @@ +/* + * This module contains the function for decoding hex strings. + */ + +#include +#include +#include + +decode_hex_data_from_string(arg, databuf, minlen, maxlen) + char *arg; + u_char *databuf; + unsigned minlen, maxlen; +{ + unsigned count; + + for (count = 0; ; count++) { + while (isspace(*arg)) + arg++; + if (!*arg) + break; + if (!isxdigit(arg[0]) || !isxdigit(arg[1])) { + fprintf(stderr, "error: invalid hex string input\n"); + return(-1); + } + if (count >= maxlen) { + fprintf(stderr, "error: hex string is too long\n"); + return(-1); + } + databuf[count] = (decode_hex_digit(arg[0]) << 4) | + decode_hex_digit(arg[1]); + arg += 2; + } + if (count < minlen) { + fprintf(stderr, "error: hex string is too short\n"); + return(-1); + } + return(count); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/iccid_luhn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/iccid_luhn.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,27 @@ +/* + * This module implements a function for computing the Luhn check digit + * for ICCIDs that follow the 18+1 convention. + */ + +#include + +compute_iccid_luhn(digits) + u_char *digits; +{ + int i, dig, sum; + + sum = 0; + for (i = 0; i < 18; i++) { + dig = digits[i]; + if (i & 1) { + dig *= 2; + if (dig > 9) + dig -= 9; + } + sum += dig; + } + dig = sum % 10; + if (dig) + dig = 10 - dig; + return dig; +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/nibbles2asc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/nibbles2asc.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,19 @@ +/* + * This module implements a function for turning a nibble array + * into printable ASCII. + */ + +#include + +void +nibbles_to_ascii(nib, len, out) + u_char *nib; + unsigned len; + char *out; +{ + unsigned n; + + for (n = 0; n < len; n++) + *out++ = encode_hex_digit(*nib++); + *out = '\0'; +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/number_decode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/number_decode.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,58 @@ +/* + * This module implements functions for decoding phone numbers. + */ + +#include + +static char gsm_address_digits[16] = + {'0','1','2','3','4','5','6','7','8','9','*','#','a','b','c','?'}; + +decode_phone_number(data, nbytes, out) + u_char *data; + unsigned nbytes; + char *out; +{ + u_char *dp, *endp; + int c; + + dp = data; + endp = data + nbytes; + while (dp < endp) { + c = *dp & 0xF; + if (c == 0xF) + return(-1); + *out++ = gsm_address_digits[c]; + c = *dp >> 4; + if (c == 0xF) { + if (dp + 1 == endp) + break; + else + return(-1); + } + *out++ = gsm_address_digits[c]; + dp++; + } + *out = '\0'; + return(0); +} + +decode_address_digits(inbuf, outbuf, ndigits) + u_char *inbuf; + char *outbuf; + unsigned ndigits; +{ + u_char *inp = inbuf; + char *outp = outbuf; + unsigned n = 0, b; + + while (n < ndigits) { + b = *inp++; + *outp++ = gsm_address_digits[b & 0xF]; + n++; + if (n >= ndigits) + break; + *outp++ = gsm_address_digits[b >> 4]; + n++; + } + *outp = '\0'; +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/number_encode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/number_encode.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,104 @@ +/* + * This module implements functions for encoding phone numbers. + */ + +#include +#include +#include +#include + +digit_char_to_gsm(ch) +{ + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return (ch - '0'); + case '*': + return 0xA; + case '#': + return 0xB; + case 'a': + case 'b': + case 'c': + return (ch - 'a' + 0xC); + case 'A': + case 'B': + case 'C': + return (ch - 'A' + 0xC); + } + return (-1); +} + +void +pack_digit_bytes(digits, dest, num_digit_bytes) + u_char *digits, *dest; + unsigned num_digit_bytes; +{ + u_char *sp, *dp; + unsigned n; + + sp = digits; + dp = dest; + for (n = 0; n < num_digit_bytes; n++) { + *dp++ = sp[0] | (sp[1] << 4); + sp += 2; + } +} + +encode_phone_number_arg(arg, fixp, mode) + char *arg; + u_char *fixp; +{ + u_char digits[20]; + unsigned ndigits, num_digit_bytes; + char *cp, *endp; + int c; + + cp = arg; + if (*cp == '+') { + fixp[1] = 0x91; + cp++; + } else + fixp[1] = 0x81; + if (digit_char_to_gsm(*cp) < 0) { +inv_arg: fprintf(stderr, "error: invalid phone number argument\n"); + return(-1); + } + for (ndigits = 0; ; ndigits++) { + c = digit_char_to_gsm(*cp); + if (c < 0) + break; + cp++; + if (ndigits >= 20) { + fprintf(stderr, "error: too many number digits\n"); + return(-1); + } + digits[ndigits] = c; + } + if (mode) + fixp[0] = ndigits; + if (ndigits & 1) + digits[ndigits++] = 0xF; + num_digit_bytes = ndigits >> 1; + if (!mode) + fixp[0] = num_digit_bytes + 1; + pack_digit_bytes(digits, fixp + 2, num_digit_bytes); + if (*cp == ',') { + cp++; + if (!isdigit(*cp)) + goto inv_arg; + fixp[1] = strtoul(cp, &endp, 0); + if (*endp) + goto inv_arg; + } else if (*cp) + goto inv_arg; + return(0); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/pinentry.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/pinentry.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,28 @@ +#include +#include +#include + +encode_pin_entry(arg, dest) + char *arg; + u_char *dest; +{ + unsigned n; + + n = 0; + while (*arg) { + if (!isdigit(*arg)) { + fprintf(stderr, + "error: PIN argument contains a non-digit character\n"); + return(-1); + } + if (n >= 8) { + fprintf(stderr, "error: PIN argument is too long\n"); + return(-1); + } + *dest++ = *arg++; + n++; + } + for (; n < 8; n++) + *dest++ = 0xFF; + return(0); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/plmncodes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/plmncodes.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,58 @@ +/* + * This module implements some functions for working with MCC-MNC PLMN codes. + */ + +#include +#include +#include + +decode_plmn_3bytes(bin, asc, space_pad) + u_char *bin; + char *asc; +{ + asc[0] = encode_hex_digit(bin[0] & 0xF); + asc[1] = encode_hex_digit(bin[0] >> 4); + asc[2] = encode_hex_digit(bin[1] & 0xF); + asc[3] = '-'; + asc[4] = encode_hex_digit(bin[2] & 0xF); + asc[5] = encode_hex_digit(bin[2] >> 4); + asc[6] = encode_hex_digit(bin[1] >> 4); + asc[7] = '\0'; + if (asc[6] == 'F') { + if (space_pad) + asc[6] = ' '; + else + asc[6] = '\0'; + } +} + +encode_plmn_3bytes(asc, bin) + char *asc; + u_char *bin; +{ + u_char mcc[3], mnc[3]; + + if (!isxdigit(asc[0]) || !isxdigit(asc[1]) || !isxdigit(asc[2])) + return(-1); + mcc[0] = decode_hex_digit(asc[0]); + mcc[1] = decode_hex_digit(asc[1]); + mcc[2] = decode_hex_digit(asc[2]); + asc += 3; + if (*asc == '-') + asc++; + if (!isxdigit(asc[0]) || !isxdigit(asc[1])) + return(-1); + mnc[0] = decode_hex_digit(asc[0]); + mnc[1] = decode_hex_digit(asc[1]); + asc += 2; + if (*asc == '\0') + mnc[2] = 0xF; + else if (isxdigit(asc[0]) && asc[1] == '\0') + mnc[2] = decode_hex_digit(*asc); + else + return(-1); + bin[0] = (mcc[1] << 4) | mcc[0]; + bin[1] = (mnc[2] << 4) | mcc[2]; + bin[2] = (mnc[1] << 4) | mnc[0]; + return(0); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/plmnlist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/plmnlist.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,69 @@ +/* + * This module implements a function for reading PLMN lists from files. + */ + +#include +#include +#include +#include +#include +#include + +extern FILE *open_script_input_file(); + +read_plmn_list_from_file(filename, buf, ef_len) + char *filename; + u_char *buf; + unsigned ef_len; +{ + FILE *inf; + int lineno, rc; + char linebuf[1024], *cp, *np; + u_char *dp, *endp; + + inf = open_script_input_file(filename); + if (!inf) { + perror(filename); + return(-1); + } + dp = buf; + endp = buf + ef_len; + for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) { + if (!index(linebuf, '\n')) { + fprintf(stderr, + "%s line %d: too long or missing newline\n", + filename, lineno); + fclose(inf); + return(-1); + } + for (cp = linebuf; ; ) { + while (isspace(*cp)) + cp++; + if (*cp == '\0' || *cp == '#') + break; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + if (dp >= endp) { + fprintf(stderr, + "%s line %d: number of PLMN codes exceeds EF size\n", + filename, lineno); + fclose(inf); + return(-1); + } + rc = encode_plmn_3bytes(np, dp); + if (rc < 0) { + fprintf(stderr, "%s line %d: invalid MCC-MNC\n", + filename, lineno); + fclose(inf); + return(-1); + } + dp += 3; + } + } + fclose(inf); + while (dp < endp) + *dp++ = 0xFF; + return(0); +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/revnibbles.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/revnibbles.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,40 @@ +/* + * This module implements some reversed-nibbles parsing functions. + */ + +#include + +decode_reversed_nibbles(bytes, nbytes, dest) + u_char *bytes; + unsigned nbytes; + char *dest; +{ + u_char *sp; + char *dp; + unsigned n, c; + + sp = bytes; + dp = dest; + for (n = 0; n < nbytes; n++) { + c = *sp & 0xF; + *dp++ = encode_hex_digit(c); + c = *sp >> 4; + *dp++ = encode_hex_digit(c); + sp++; + } +} + +pack_reversed_nibbles(nibbles, bytes, nbytes) + u_char *nibbles, *bytes; + unsigned nbytes; +{ + u_char *sp, *dp; + unsigned n; + + sp = nibbles; + dp = bytes; + for (n = 0; n < nbytes; n++) { + *dp++ = sp[0] | (sp[1] << 4); + sp += 2; + } +} diff -r b25d4dfe5798 -r 34bbb0585cab libutil/shorthand.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libutil/shorthand.c Sun Mar 14 05:42:37 2021 +0000 @@ -0,0 +1,64 @@ +/* + * This module implements the function for parsing shorthand decimal strings. + */ + +#include +#include +#include +#include +#include + +parse_decimal_shorthand(arg, dest, maxdigits) + char *arg; + u_char *dest; + unsigned maxdigits; +{ + unsigned n, ntail; + + if (!*arg) { + fprintf(stderr, + "error: empty argument given for decimal string\n"); + return(-1); + } + if (!isdigit(*arg)) { + fprintf(stderr, + "error: decimal string argument begins with a non-digit\n"); + return(-1); + } + for (n = 0; isdigit(*arg); ) { + if (n >= maxdigits) { +toolong: fprintf(stderr, + "error: decimal string exceeds limit of %u digits\n", + maxdigits); + return(-1); + } + dest[n++] = *arg++ - '0'; + } + if (!*arg) { + if (n != maxdigits) { + fprintf(stderr, + "error: %u digits required, %u digits given\n", + maxdigits, n); + return(-1); + } + return(0); + } + if (*arg++ != '-') { +malformed: fprintf(stderr, + "error: malformed shorthand decimal string argument\n"); + return(-1); + } + ntail = strlen(arg); + if (n + ntail >= maxdigits) + goto toolong; + while (n < maxdigits - ntail) + dest[n++] = 0; + if (!isdigit(*arg)) + goto malformed; + while (*arg) { + if (!isdigit(*arg)) + goto malformed; + dest[n++] = *arg++ - '0'; + } + return(0); +}