diff options
-rwxr-xr-x | contrib/jenkins.sh | 1 | ||||
-rwxr-xr-x | pySim-prog.py | 183 | ||||
-rw-r--r-- | pySim/card_handler.py | 108 |
3 files changed, 214 insertions, 78 deletions
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index fdcd0cb..a70f139 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -12,6 +12,7 @@ fi virtualenv -p python2 venv --system-site-packages . venv/bin/activate pip install pytlv +pip install pyyaml cd pysim-testdata ../tests/pysim-test.sh diff --git a/pySim-prog.py b/pySim-prog.py index 13e8bb5..55634a5 100755 --- a/pySim-prog.py +++ b/pySim-prog.py @@ -30,6 +30,7 @@ import os import random import re import sys +import traceback try: import json @@ -41,6 +42,7 @@ from pySim.commands import SimCardCommands from pySim.cards import _cards_classes from pySim.utils import h2b, swap_nibbles, rpad, derive_milenage_opc, calculate_luhn, dec_iccid from pySim.ts_51_011 import EF +from pySim.card_handler import * def parse_options(): @@ -163,6 +165,9 @@ def parse_options(): help="Perform a 'dry run', don't actually program the card", default=False, action="store_true") + parser.add_option("--card_handler", dest="card_handler", metavar="FILE", + help="Use automatic card handling machine") + (options, args) = parser.parse_args() if options.type == 'list': @@ -610,6 +615,74 @@ def card_detect(opts, scc): return card +def process_card(opts, first, card_handler): + + if opts.dry_run is False: + # Connect transport + card_handler.get(first) + + if opts.dry_run is False: + # Get card + card = card_detect(opts, scc) + if card is None: + print "No card detected!" + return -1 + + # Probe only + if opts.probe: + return 0 + + # Erase if requested + if opts.erase: + print "Formatting ..." + card.erase() + card.reset() + + # Generate parameters + if opts.source == 'cmdline': + cp = gen_parameters(opts) + elif opts.source == 'csv': + imsi = None + iccid = None + if opts.read_iccid: + if opts.dry_run: + # Connect transport + card_handler.get(false) + (res,_) = scc.read_binary(['3f00', '2fe2'], length=10) + iccid = dec_iccid(res) + elif opts.read_imsi: + if opts.dry_run: + # Connect transport + card_handler.get(false) + (res,_) = scc.read_binary(EF['IMSI']) + imsi = swap_nibbles(res)[3:] + else: + imsi = opts.imsi + cp = read_params_csv(opts, imsi=imsi, iccid=iccid) + if cp is None: + print "Error reading parameters\n" + return 2 + print_parameters(cp) + + if opts.dry_run is False: + # Program the card + print "Programming ..." + card.program(cp) + else: + print "Dry Run: NOT PROGRAMMING!" + + # Write parameters permanently + write_parameters(opts, cp) + + # Batch mode state update and save + if opts.num is not None: + opts.num += 1 + save_batch(opts) + + card_handler.done() + return 0 + + if __name__ == '__main__': # Parse options @@ -638,88 +711,42 @@ if __name__ == '__main__': # Batch mode init init_batch(opts) + if opts.card_handler: + card_handler = card_handler_auto(sl, opts.card_handler) + else: + card_handler = card_handler(sl) + # Iterate - done = False first = True card = None - while not done: - - if opts.dry_run is False: - # Connect transport - print "Insert card now (or CTRL-C to cancel)" - sl.wait_for_card(newcardonly=not first) + while 1: + try: + rc = process_card(opts, first, card_handler) + except (KeyboardInterrupt): + print "" + print "Terminated by user!" + sys.exit(0) + except (SystemExit): + raise + except: + print "" + print "Card programming failed with an execption:" + print "---------------------8<---------------------" + traceback.print_exc() + print "---------------------8<---------------------" + print "" + rc = -1 + + # Something did not work as well as expected, however, lets + # make sure the card is pulled from the reader. + if rc != 0: + card_handler.error() + + # If we are not in batch mode we are done in any case, so lets + # exit here. + if not opts.batch_mode: + sys.exit(rc) - # Not the first anymore ! first = False - if opts.dry_run is False: - # Get card - card = card_detect(opts, scc) - if card is None: - if opts.batch_mode: - first = False - continue - else: - sys.exit(-1) - - # Probe only - if opts.probe: - break; - - # Erase if requested - if opts.erase: - print "Formatting ..." - card.erase() - card.reset() - - # Generate parameters - if opts.source == 'cmdline': - cp = gen_parameters(opts) - elif opts.source == 'csv': - imsi = None - iccid = None - if opts.read_iccid: - if opts.dry_run: - # Connect transport - print "Insert card now (or CTRL-C to cancel)" - sl.wait_for_card(newcardonly=not first) - (res,_) = scc.read_binary(['3f00', '2fe2'], length=10) - iccid = dec_iccid(res) - print iccid - elif opts.read_imsi: - if opts.dry_run: - # Connect transport - print "Insert card now (or CTRL-C to cancel)" - sl.wait_for_card(newcardonly=not first) - (res,_) = scc.read_binary(EF['IMSI']) - imsi = swap_nibbles(res)[3:] - else: - imsi = opts.imsi - cp = read_params_csv(opts, imsi=imsi, iccid=iccid) - if cp is None: - print "Error reading parameters\n" - sys.exit(2) - print_parameters(cp) - - if opts.dry_run is False: - # Program the card - print "Programming ..." - if opts.dry_run is not True: - card.program(cp) - else: - print "Dry Run: NOT PROGRAMMING!" - - # Write parameters permanently - write_parameters(opts, cp) - - # Batch mode state update and save - if opts.num is not None: - opts.num += 1 - save_batch(opts) - - # Done for this card and maybe for everything ? - print "Done !\n" - - if not opts.batch_mode: - done = True diff --git a/pySim/card_handler.py b/pySim/card_handler.py new file mode 100644 index 0000000..46ec93e --- /dev/null +++ b/pySim/card_handler.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +""" pySim: card handler utilities +""" + +# +# (C) 2019 by Sysmocom s.f.m.c. GmbH +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + + +import subprocess +import sys +import yaml + +# Manual card handler: User is prompted to insert/remove card from the reader. +class card_handler: + + sl = None + + def __init__(self, sl): + self.sl = sl + + def get(self, first = False): + print "Ready for Programming: Insert card now (or CTRL-C to cancel)" + self.sl.wait_for_card(newcardonly=not first) + + def error(self): + print "Programming failed: Remove card from reader" + print "" + + def done(self): + print "Programming successful: Remove card from reader" + print "" + +# Automatic card handler: A machine is used to handle the cards. +class card_handler_auto: + + sl = None + cmds = None + verbose = True + + def __init__(self, sl, config_file): + print "Card handler Config-file: " + str(config_file) + self.sl = sl + with open(config_file) as cfg: + self.cmds = yaml.load(cfg, Loader=yaml.FullLoader) + + self.verbose = (self.cmds.get('verbose') == True) + + def __print_outout(self,out): + print "" + print "Card handler output:" + print "---------------------8<---------------------" + stdout = out[0].strip() + if len(stdout) > 0: + print "stdout:" + print stdout + stderr = out[1].strip() + if len(stderr) > 0: + print "stderr:" + print stderr + print "---------------------8<---------------------" + print "" + + def __exec_cmd(self, command): + print "Card handler Commandline: " + str(command) + + proc = subprocess.Popen([command], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + out = proc.communicate() + rc = proc.returncode + + if rc != 0 or self.verbose: + self.__print_outout(out) + + if rc != 0: + print "" + print "Error: Card handler failure! (rc=" + str(rc) + ")" + sys.exit(rc) + + def get(self, first = False): + print "Ready for Programming: Transporting card into the reader-bay..." + self.__exec_cmd(self.cmds['get']) + self.sl.connect() + + def error(self): + print "Programming failed: Transporting card to the error-bin..." + self.__exec_cmd(self.cmds['error']) + print "" + + def done(self): + print "Programming successful: Transporting card into the collector bin..." + self.__exec_cmd(self.cmds['done']) + print "" |