/*************************************************************************** $RCSfile: memcard.cpp,v $ ------------------- cvs : $Id: memcard.cpp,v 1.15 2003/05/08 12:26:43 aquamaniac Exp $ begin : Fri May 31 2002 copyright : (C) 2002 by Martin Preuss email : martin@libchipcard.de **************************************************************************** * 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, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ****************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif /* Internationalization */ #ifdef HAVE_GETTEXT_ENVIRONMENT # include # include # define I18N(m) gettext(m) #else # define I18N(m) m #endif #define I18NT(m) m #include #include #include #include #define k_PRG "memcard" #define k_PRG_VERSION_INFO \ "memcard v0.3.2 (part of libchipcard v"k_CHIPCARD_VERSION_STRING")\n"\ "(c) 2003 Martin Preuss\n" \ "This program is free software licensed under GPL.\n"\ "See COPYING for details.\n" void usage(string name) { fprintf(stderr,"%s%s%s%s", I18N("MemCard - A tool to read/write data from/to a memory chip card\n" "(c) 2003 Martin Preuss\n" "This library is free software; you can redistribute it and/or\n" "modify it under the terms of the GNU Lesser General Public\n" "License as published by the Free Software Foundation; either\n" "version 2.1 of the License, or (at your option) any later version.\n" "\n" "Usage:\n" "%s COMMAND -a ADDR -s SIZE [-f FILE] [-p PIN] [-C CONFIGFILE]\n" " COMMAND\n" " read : read from the card and store to FILE (or stdout) \n" " write: write FILE (or stdin) to the card\n" " ADDR - start address on chip card\n" " SIZE - size of data to manipulate\n" " FILE - path of the file to use for this manipulation.\n" " If omitted stdin/stdout will be used, respectively\n" " PIN - used for pin-protected cards. This is a 6 digit code.\n" " CONFIGFILE - configuration file of libchipcard to be used\n" " General Options:\n" " --logfile F - use given F as log file\n" " --logtype T - use given T as log type\n" " These are the valid types:\n" " stderr (log to standard error channel)\n" " file (log to the file given by --logfile)\n"), #ifdef HAVE_SYSLOG_H I18N(" syslog (log via syslog)\n"), #else "", #endif I18N(" Default is stderr\n" " --loglevel L - set the loglevel\n" " Valid levels are:\n" " emergency, alert, critical, error,\n" " warning, notice, info and debug\n" " Default is \"warning\".\n") , name.c_str()); } struct s_args { int addr; // -a int size; // -s string filename; // -f string pin; // -p string configFile; // -C string logFile; // --logfile LOGGER_LOGTYPE logType; // --logtype LOGGER_LEVEL logLevel; // --loglevel list params; }; int checkArgs(s_args &args, int argc, char **argv) { int i; string tmp; i=1; args.size=0; args.addr=0; args.configFile=CHIPCARDC_CFGFILE; args.logFile="memcard.log"; args.logType=LoggerTypeConsole; args.logLevel=LoggerLevelWarning; while (i=argc) return 1; args.addr=atoi(argv[i]); } else if (tmp=="-C") { i++; if (i>=argc) return 1; args.configFile=argv[i]; } else if (tmp=="-s") { i++; if (i>=argc) return 1; args.size=atoi(argv[i]); } else if (tmp=="-p") { i++; if (i>=argc) return 1; args.pin=argv[i]; } else if (tmp=="-f") { i++; if (i>=argc) return 1; args.filename=argv[i]; } else if (tmp=="-h" || tmp=="--help") { usage(argv[0]); return -1; } else if (tmp=="-V" || tmp=="--version") { fprintf(stdout,k_PRG_VERSION_INFO); return -1; } else if (tmp=="--logfile") { i++; if (i>=argc) return 1; args.logFile=argv[i]; } else if (tmp=="--logtype") { i++; if (i>=argc) return 1; if (strcmp(argv[i],"stderr")==0) args.logType=LoggerTypeConsole; else if (strcmp(argv[i],"file")==0) args.logType=LoggerTypeFile; #ifdef HAVE_SYSLOG_H else if (strcmp(argv[i],"syslog")==0) args.logType=LoggerTypeSyslog; #endif else { fprintf(stderr,I18N("Unknown log type \"%s\"\n"), argv[i]); return 1; } } else if (tmp=="--loglevel") { i++; if (i>=argc) return 1; if (strcmp(argv[i], "emergency")==0) args.logLevel=LoggerLevelEmergency; else if (strcmp(argv[i], "alert")==0) args.logLevel=LoggerLevelAlert; else if (strcmp(argv[i], "critical")==0) args.logLevel=LoggerLevelCritical; else if (strcmp(argv[i], "error")==0) args.logLevel=LoggerLevelError; else if (strcmp(argv[i], "warning")==0) args.logLevel=LoggerLevelWarning; else if (strcmp(argv[i], "notice")==0) args.logLevel=LoggerLevelNotice; else if (strcmp(argv[i], "info")==0) args.logLevel=LoggerLevelInfo; else if (strcmp(argv[i], "debug")==0) args.logLevel=LoggerLevelDebug; else { fprintf(stderr, I18N("Unknown log level \"%s\"\n"), argv[i]); return 1; } } else // otherwise add param args.params.push_back(tmp); i++; } // while // that's it return 0; } int _transformPin(const string &pin, string &tpin) { unsigned char c; unsigned int i; tpin.erase(); // check for the pin if (!pin.empty()) { if (pin.length()!=4) { fprintf(stderr,I18N("Pin needs to have 6 digits !\n")); return 1; } for (i=0; i<4; i++) { c=pin[i]; if (c<'0') { fprintf(stderr, I18N("Pin digits must be hexadecimal " "digits (0-9,A-F) !\n")); return 1; } c-='0'; if (c>9) c-=7; if (c>0xf) c-=32; if (c>0xf) { fprintf(stderr, I18N("Pin digits must be hexadecimal " "digits (0-9,A-F) !\n")); return 1; } if (i&1) tpin[i/2]|=(c & 0x0f); else { c=c<<4; tpin+=(char)c; } } // for } return 0; } int openCard(CTPointer &card, bool quiet=false) { CTPointer trader; CTError err; CTCard *cp; trader=new CTCardTrader(false, 0, 0, CHIPCARD_STATUS_INSERTED, CHIPCARD_STATUS_INSERTED | CHIPCARD_STATUS_LOCKED_BY_OTHER, CHIPCARD_STATUS_INSERTED); err=trader.ref().start(); if (!err.isOk()) { fprintf(stderr, I18N("Could not initialize trader")); return 2; } if (!quiet) fprintf(stderr, I18N("Please insert your card into any reader\n")); // get the card err=trader.ref().getNext(cp, 30); if (!err.isOk()) { if (err.code()==k_CTERROR_API && (err.subcode1()==CHIPCARD_ERROR_NO_TRANSPORT || err.subcode1()==CHIPCARD_ERROR_NO_REQUEST)) { fprintf(stderr, I18N("Service unreachable, maybe \"chipcardd\" is not running?\n") ); return 2; } fprintf(stderr,I18N("No card inserted within some seconds, aborting.\n")); return 2; } err=trader.ref().stop(); if (!err.isOk()) { fprintf(stderr, I18N("Could not stop trader")); return 2; } card=cp; if (card.ref().isProcessorCard()) { fprintf(stderr, I18N("Not a memory card")); return 3; } if (!quiet) fprintf(stderr,I18N("Card is inserted, working.\n")); return 0; } int readCard(s_args args) { FILE *f; CTPointer card; CTPointer basecard; CTError err; string data; string tpin; int size; int t; int addr; int rv; if (args.size==0) { fprintf(stderr,I18N("ERROR: You need to give the size option.\n")); return 1; } if (args.filename.empty()) f=stdout; else f=fopen(args.filename.c_str(),"w+"); if (!f) { fprintf(stderr,I18N("ERROR: Could not open file.\n")); return 2; } rv=openCard(basecard); if (rv!=0) return rv; card=new CTMemoryCard(basecard.ref()); basecard=0; err=card.ref().openCard(); if (!err.isOk()) { fprintf(stderr,"%s\n",err.errorString().c_str()); return 3; } size=args.size; addr=args.addr; // check for the pin if (!args.pin.empty()) { // transform digits to binary t=_transformPin(args.pin,tpin); if (t) return t; // verify pin err=card.ref().verifyPin(tpin); if (!err.isOk()) { fprintf(stderr, I18N("Error verifying pin: %s\n"), err.errorString().c_str()); return 2; } } while(size>0) { if (size>255) t=255; else t=size; err=card.ref().readBinary(data,addr,t); if (!err.isOk()) { fprintf(stderr, I18N("%s (reading card)\n"),err.errorString().c_str()); return 2; } if (fwrite(data.data(),1,data.length(),f)!=data.length()) { fprintf(stderr,I18N("ERROR: Could not write to file.\n")); return 2; } size-=t; addr+=t; } // while if (f!=stdout) if (fclose(f)) { fprintf(stderr,I18N("ERROR: Could not close file.\n")); return 2; } err=card.ref().closeCard(); if (!err.isOk()) { fprintf(stderr, I18N("%s (closing card)\n"),err.errorString().c_str()); return 2; } return 0; } int writeCard(s_args args) { FILE *f; CTPointer card; CTPointer basecard; CTError err; string data; int rest; int addr; int t; char buffer[1024]; string tpin; int rv; if (args.filename.empty()) f=stdin; else f=fopen(args.filename.c_str(),"r"); if (!f) { fprintf(stderr,I18N("ERROR: Could not open file.\n")); return 2; } rest=args.size; rv=openCard(basecard); if (rv!=0) return rv; card=new CTMemoryCard(basecard.ref()); basecard=0; err=card.ref().openCard(); if (!err.isOk()) { fprintf(stderr,"%s\n",err.errorString().c_str()); return 3; } // check for the pin if (!args.pin.empty()) { // transform digits to binary t=_transformPin(args.pin,tpin); if (t) return t; // verify pin err=card.ref().verifyPin(tpin); if (!err.isOk()) { fprintf(stderr, I18N("%s (verifying pin)\n"), err.errorString().c_str()); return 2; } else fprintf(stderr,I18N("Pin is ok.\n")); } addr=args.addr; while (!feof(f)) { if (args.size) { // size given if (rest<(int)sizeof(buffer)) t=rest; else t=sizeof(buffer); } else // size not given, read as much as possible t=sizeof(buffer); // read from file t=fread(buffer,1,t,f); if (t<1) { fprintf(stderr, I18N("ERROR: Could not read from file. (%s)\n"), strerror(errno)); return 2; } data.assign(buffer,t); // write to card err=card.ref().updateBinary(data,addr); if (!err.isOk()) { fprintf(stderr, I18N("%s (writing card)\n"),err.errorString().c_str()); return 2; } rest-=t; addr+=t; if (args.size) if (rest<1) break; } // while // close card err=card.ref().closeCard(); if (!err.isOk(0x62)) { fprintf(stderr, I18N("%s (closing card)\n"),err.errorString().c_str()); return 2; } // close file if (f!=stdout) if (fclose(f)) { fprintf(stderr,I18N("ERROR: Could not close file.\n")); return 2; } return 0; } int main(int argc, char **argv) { s_args args; int rv; string cmd; #ifdef HAVE_GETTEXT_ENVIRONMENT setlocale(LC_ALL,""); if (bindtextdomain("memcard", I18N_PATH)==0) { fprintf(stderr," Error bindtextdomain()\n"); } if (textdomain("memcard")==0) { fprintf(stderr," Error textdomain()\n"); } #endif rv=checkArgs(args,argc,argv); if (rv==-1) return 0; else if (rv) return rv; if (args.params.empty()) { usage(argv[0]); return 1; } try { if (Logger_Open("memcard", args.logFile.c_str(), args.logType, LoggerFacilityUser)) { fprintf(stderr,I18N("Could not start logging, aborting.\n")); return 2; } Logger_SetLevel(args.logLevel); rv=ChipCard_Init(args.configFile.c_str(),0); if (rv!=CHIPCARD_SUCCESS) { fprintf(stderr, I18N("Error initializing libchipcard (%d), aborting.\n"),rv); return 2; } cmd=args.params.front(); if (cmd=="read") rv=readCard(args); else if (cmd=="write") rv=writeCard(args); else { fprintf(stderr,I18N("Unknown command.\n")); usage(argv[0]); rv=1; } } // try catch (CTError xerr) { fprintf(stderr,"Exception: %s\n", xerr.errorString().c_str()); rv=3; } ChipCard_Fini(); return rv; }