Application.

This commit is contained in:
Mikaël Ates 2015-01-09 17:06:50 +01:00
parent 0110be74bf
commit e9f297251e
1 changed files with 516 additions and 0 deletions

516
cv2extractor/cv2extractor.c Normal file
View File

@ -0,0 +1,516 @@
/* $Id$
*
* cv2extractor - A free implementation of a reader of Carte Vitale 2 cards.
*
* Copyright (C) 2015 Entr'ouvert
* https://dev.entrouvert.org/projects/cv2extractor
*
* Authors: See AUTHORS file in top-level directory.
*
* 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 3 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
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <time.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gprintf.h>
#include "api_lec.h"
#include "api_err.h"
#include "config.h"
#include "errors.h"
#include "utils.h"
int send_file(gchar* filename) {
int rc = CV2EXTRACTOR_ERROR_UNDEFINED;
int command_rc;
gchar* command;
if (SSL_TRANSFER_SECRET != NULL && SSL_TRANSFER_SECRET[0] != '\0') {
command = g_strdup_printf("sshpass -p '%s' scp %s %s", SSL_TRANSFER_SECRET, filename, SSL_TRANSFER_TARGET);
} else {
command = g_strdup_printf("scp %s %s", filename, SSL_TRANSFER_TARGET);
}
command_rc = system(command);
goto_cleanup_if_fail_with_rc_with_warning(command_rc != -1, CV2EXTRACTOR_ERROR_SSH_COMMAND);
rc = CV2EXTRACTOR_NO_ERROR;
cleanup:
g_free(command);
return rc;
}
gchar* get_timestamped_filename() {
gchar* filename;
gchar str_date[24];
time_t t = time(NULL);
struct tm tm = *localtime(&t);
strftime(str_date, sizeof(str_date), "%Y-%d-%m-%H-%M-%S.xml", &tm);
if (!cv2extractor_strisempty(XML_FILE_PREFIX)) {
filename = g_strconcat(XML_FILE_PREFIX, str_date, NULL);
} else {
filename = str_date;
}
return filename;
}
int write_file(gchar* filename, gchar* stream, unsigned int size) {
int rc = CV2EXTRACTOR_ERROR_UNDEFINED;
FILE *file;
file = fopen(filename, "w+");
if(file == NULL) {
g_printf("\n! Error opening file.\n");
goto_cleanup_with_rc_with_critical("Error opening file", CV2EXTRACTOR_ERROR_OPENING_FILE);
}
size_t w_check;
w_check = fwrite(stream, 1, size, file);
if (w_check != size) {
g_printf("\n! Error writing file.\n");
goto_cleanup_with_rc_with_critical("Error writing file", CV2EXTRACTOR_ERROR_WRITING_FILE);
}
if (fclose(file) != CV2EXTRACTOR_NO_ERROR) {
g_printf("\n! Error closing file.\n");
goto_cleanup_with_rc_with_critical("Error closing file", CV2EXTRACTOR_ERROR_CLOSING_FILE);
}
rc = CV2EXTRACTOR_NO_ERROR;
cleanup:
return rc;
}
int main(){
g_type_init();
int rc = CV2EXTRACTOR_ERROR_UNDEFINED;
g_printf("------------------------\n");
g_printf("----- cv2extractor -----\n");
g_printf("------------------------\n\n");
/*
* Read configuration file
*/
g_printf("Reading configuration...\n");
g_printf("\t--> XML files will be written in : %s\n", XML_FILES_PATH);
if (SSL_TRANSFER_TARGET != NULL && SSL_TRANSFER_TARGET[0] != '\0') {
g_printf("\t--> XML files will be sent using ssh to : %s\n", SSL_TRANSFER_TARGET);
}
g_printf("\n");
gchar* filename;
/*
* Variables used by many library functions
*/
/* Hn_Init */
/* Reader behavior */
unsigned short pusMode = FLIP_FLOP;
/* Hn_TestPresence */
/* Reader state */
unsigned char pucStatut;
/* Hn_LectureVitale */
/* Will store the Carte Vitale content */
gchar pcDataOut[BUFFER_SIZE];
/* Size of the sapec allocated for Carte Vitale content and sizeof the content read */
unsigned int puiLgDataOut;
/*Hn_IntroductionMstCPS */
/**/
gchar tcCodeCivilite[3];
tcCodeCivilite[2] = '\0';
/**/
gchar szNomPatronymique[28];
szNomPatronymique[27] = '\0';
/* Will contain the value of bad PIn code entered in the CPS */
gchar pcPresentPINCode;
/* Hn_ControleCPS */
/* The pin code user entered, 1234 for cps testing cards */
gchar* tcPINCode;
/**/
gchar tcDateFinValidite[9];
tcDateFinValidite[8] = '\0';
/**/
gchar tcTypeCarte[3];
tcTypeCarte[2] = '\0';
/**/
gchar tcCategorie[3];
tcCategorie[2] = '\0';
/* Use at card reading */
short psEtatCarteCV;
/* Use at card reading */
short psEtatCarteCPS;
/* Function functionnal error code */
unsigned short pusCodeErreur = 0;
/* Function execution error code */
unsigned short err = 0;
/*
* API VITALE Session Opening.
*/
g_printf("Connect API VITALE library with the reader...\n");
err = Hn_Init(NULL , &pusMode, &pusCodeErreur);
if(err == CV2EXTRACTOR_NO_ERROR) {
g_printf("\t--> Reader connected.\n");
} else {
if(err == WAR_APICPS_NON_DISPONIBLE) {
g_printf("\t--> Reader connected.\n");
g_printf("\n--> Error loading CPS library, continue.\n");
}
else{
g_printf("\nError during connection (Hn_Init error %d)\n", err);
goto_cleanup_with_rc_with_critical("Error during connection (Hn_Init error)", err);
}
}
g_printf("\n");
/*
* Reading loop
*/
g_printf("<-------- Please insert card -------->\n");
do {
/*
* Wait for card insertion
*
* Use of Hn_TestPresence to test insertion. If nothing inserted,
* sleep and retest. Else, read.
*
* COUPLEUR_VITALE does not matter since err is equal to 0 whatever
* is put in the reader.
*
*/
err = Hn_TestPresence(COUPLEUR_VITALE , &pucStatut, &pusCodeErreur);
if(err == CV2EXTRACTOR_NO_ERROR && pucStatut == ETAT_CPRESENTE) {
/*
* Test the card inserted type.
*
* Maybe there's a way to know what kind of card it is using
* pusCodeErreur. But nothing clear from the doc.
*
* So we try to read it as a Carte Vitale. If it fails, as a CPS.
* Else, whatever.
*/
g_printf("\t--> Card inserted.\n");
/*
* Try to read a Carte vitale
*/
/* puiLgDataOut gives the buffer size in input but also gives
the size of the file read in output. It is thus required to set it
before each reading */
puiLgDataOut = BUFFER_SIZE;
err = Hn_LectureVitale(0, pcDataOut, &puiLgDataOut, &psEtatCarteCV, &pusCodeErreur);
if(err == CV2EXTRACTOR_NO_ERROR || err == WAR_DONNEES_ADM) {
/*
* Carte Vitale inserted
*/
g_printf("\t--> Carte Vitale inserted.\n");
if(err == WAR_DONNEES_ADM) {
g_printf("\t--> Only administrative data have been read.\n");
}
g_printf("%s\n", pcDataOut);
/*
* Write XML file.
*/
g_printf("\t--> The data read is %d bytes.\n", puiLgDataOut);
cv2extractor_message("The data read is %d bytes.", puiLgDataOut);
filename = get_timestamped_filename();
int write_err;
write_err = write_file(filename, pcDataOut, puiLgDataOut);
if (write_err != CV2EXTRACTOR_NO_ERROR) {
g_printf("\n! Error handling file.\n");
goto_cleanup_with_rc_with_critical("Error handling file", write_err);
}
g_printf("--> Write: %s\n", filename);
cv2extractor_message("Write file %s.", filename);
/*
* Send XML file.
*/
if (SSL_TRANSFER_TARGET != NULL && SSL_TRANSFER_TARGET[0] != '\0') {
int ret = 0;
ret = send_file(filename);
if(ret) {
g_printf("\n! Error sending file with error: %d.\n", ret);
cv2extractor_warning("Error sending file with error: %d.", ret);
} else {
g_printf("--> File sent.\n");
cv2extractor_message("File sent using ssh.");
}
}
/*
* Wait for card removal.
*/
g_printf("<------ Please remove CV2 card ------>\n");
do {
err = Hn_TestPresence(COUPLEUR_VITALE , &pucStatut, &pusCodeErreur);
if(err != CV2EXTRACTOR_NO_ERROR) {
g_printf("\nError testing for Carte Vitale removal (Hn_TestPresence error %d)\n", err);
cv2extractor_warning("Error testing for Carte Vitale removal (Hn_TestPresence error %d).", err);
//goto_cleanup_with_rc_with_critical("Error testing for Carte Vitale removal (Hn_TestPresence error)", err);
}
} while(pucStatut == ETAT_CPRESENTE);
g_printf("<-------- Please insert card -------->\n");
} else if(err == ERR_CARTE_INCONNUE) {
/* It is not a a Carte vitale, try to read a CPS */
err = Hn_IntroductionMstCPS(0, tcCodeCivilite, szNomPatronymique, &pcPresentPINCode, &psEtatCarteCPS, &pusCodeErreur);
if (err == CV2EXTRACTOR_NO_ERROR) {
/*
* Carte CPS inserted
*/
g_printf("\t--> CPS card inserted.\n");
g_printf("\t--> tcCodeCivilite: %s\n", tcCodeCivilite);
g_printf("\t--> szNomPatronymique: %s\n", szNomPatronymique);
g_printf("\t--> vecteur de retour %d\n", psEtatCarteCPS);
/*
* Check CPS card status
*/
short bit_0, bit_1, bit_2, bit_3, bit_4, bit_5, bit_6;
bit_0 = psEtatCarteCPS & 0x0001;
bit_1 = psEtatCarteCPS & 0x0002;
bit_2 = psEtatCarteCPS & 0x0004;
bit_3 = psEtatCarteCPS & 0x0008;
bit_4 = psEtatCarteCPS & 0x0010;
bit_5 = psEtatCarteCPS & 0x0020;
bit_6 = psEtatCarteCPS & 0x0040;
if(bit_6 == CPS_DETEST){
g_printf("\t--> CPS for testing. Can only unlock Carte Vitale for testing.\n");
}
if(bit_5 == CPS_NONAUTORISEE){
g_printf("\t--> This card don't unlock Carte Vitale cards.\n");
} else {
g_printf("\t--> This card unlock Carte Vitale cards.\n");
}
int valid = 1;
if (bit_1 == CPS_BLOQUEE){
g_printf("\t--> CPS locked.\n");
cv2extractor_warning("CPS locked (%s, %s).", tcCodeCivilite, szNomPatronymique);
valid = 0;
}
if (bit_3 == CPS_HORSVALIDITE) {
g_printf("\t--> CPS invalid.\n");
cv2extractor_warning("CPS invalid (%s, %s).", tcCodeCivilite, szNomPatronymique);
valid = 0;
}
if (bit_4 == CPS_IDENTINCORRECT){
g_printf("\t--> CPS missing application.\n");
cv2extractor_warning("CPS missing application (%s, %s).", tcCodeCivilite, szNomPatronymique);
valid = 0;
}
if (bit_2 == CPS_CODE_ACTIF) {
g_printf("\t--> The card is already unlocked\n");
} else if (valid == 1) {
/*
* The card is valid. Ask for PIN code to unlock the
* CPS card.
*/
if ((pcPresentPINCode != '0') && (pcPresentPINCode != '1') && (pcPresentPINCode != '2')) {
g_printf("\t--> The bad PIN code value is invalid: (%c). That should not happen, we don't pursue with this card.\n", pcPresentPINCode);
} else {
if (CPS_PIN_CODE == NULL || CPS_PIN_CODE[0] == '\0') {
/*
* User interactive mode
*/
int tries;
tries = PIN_TRIES - (pcPresentPINCode - '0');
int unlock = 0;
size_t max_bytes = PIN_DIGITS;
size_t read_bytes = 0;
tcPINCode = (char*) malloc(PIN_DIGITS + 1);
do {
/*
* Get user entry from stdin
*/
g_printf("<------ Enter the PIN code (Remaining %d attemps) ------>\n", tries);
do {
read_bytes = getline(&tcPINCode, &max_bytes, stdin);
if (read_bytes != (PIN_DIGITS + 1)) {
g_printf("\t--> A PIN code is %d digit long.\n", PIN_DIGITS);
}
} while (read_bytes != (PIN_DIGITS + 1));
/*
* Try to unlock CPS card with the pin
*/
err = Hn_ControleCPS(tcPINCode, tcDateFinValidite, tcTypeCarte, &pcPresentPINCode, tcCategorie, &pusCodeErreur);
if(err == CV2EXTRACTOR_NO_ERROR) {
/* CPS unlocked */
unlock = 1;
g_printf("\t--> CPS unlocked\n");
g_printf("\t--> tcDateFinValidite: %s\n", tcDateFinValidite);
g_printf("\t--> tcTypeCarte: %s\n", tcTypeCarte);
g_printf("\t--> pcPresentPINCode: %c\n", pcPresentPINCode);
g_printf("\t--> tcCategorie: %s\n", tcCategorie);
} else if (err == ERR_PINCODE_INACTIF) {
g_printf("\t--> The PIN code is invalid\n");
tries = PIN_TRIES - (pcPresentPINCode - '0');
} else {
g_printf("\t--> Error with PIN validation\n");
g_warning("Error processing PIN validation (Hn_ControleCPS: %d).", err);
tries = PIN_TRIES - (pcPresentPINCode - '0');
}
} while(tries > 0 && unlock == 0);
g_free(tcPINCode);
} else if (sizeof(CPS_PIN_CODE) == (PIN_DIGITS + 1)) {
tcPINCode = CPS_PIN_CODE;
/*
* Try to unlock CPS card with the pin
*/
err = Hn_ControleCPS(tcPINCode, tcDateFinValidite, tcTypeCarte, &pcPresentPINCode, tcCategorie, &pusCodeErreur);
if(err == CV2EXTRACTOR_NO_ERROR) {
/* CPS unlocked */
g_printf("\t--> CPS unlocked\n");
g_printf("\t--> tcDateFinValidite: %s\n", tcDateFinValidite);
g_printf("\t--> tcTypeCarte: %s\n", tcTypeCarte);
g_printf("\t--> pcPresentPINCode: %c\n", pcPresentPINCode);
g_printf("\t--> tcCategorie: %s\n", tcCategorie);
} else if (err == ERR_PINCODE_INACTIF) {
g_printf("\t--> The PIN code is invalid\n");
g_warning("The PIN code recorded is invalid.");
} else {
g_printf("\t--> Error with PIN validation\n");
g_warning("rror processing PIN validation (Hn_ControleCPS: %d).", err);
}
} else {
g_printf("\t--> A PIN code is recorded to avoid interactive mode but the length is not %d digits.\n", PIN_DIGITS);
cv2extractor_critical("A PIN code is recorded to avoid interactive mode but the length is not %d digits.", PIN_DIGITS);
}
}
}
/*
* Wait for card removal.
*/
g_printf("<------ Please remove CPS card ------>\n");
short sTempsAttente = CPS_WAITING_TIME;
err = Hn_RetraitMhtCPS(sTempsAttente, &pusCodeErreur);
if(err != CV2EXTRACTOR_NO_ERROR) {
g_printf("\nError testing for CPS removal (Hn_TestPresence error %d)\n", err);
cv2extractor_warning("Error testing for CPS removal (Hn_TestPresence error %d).", err);
//goto_cleanup_with_rc_with_critical("Error testing for CPS Vitale removal (Hn_TestPresence error)", err);
}
g_printf("<-------- Please insert card -------->\n");
} else if (err == ERR_CARTE_INCONNUE) {
/*
* Somebody introduced something unexpected in the reader...
*/
g_printf("Unknown card type.");
cv2extractor_warning("Unknown card type.");
} else {
g_printf("\nError trying to read a CPS (Hn_IntroductionMstCPS error %d)\n", err);
cv2extractor_warning("Error trying to read a CPS (Hn_IntroductionMstCPS error %d).", err);
//goto_cleanup_with_rc_with_critical("Error trying to read a CPS (Hn_IntroductionMstCPS error)", err);
}
} else {
g_printf("\nError trying to read a Carte Vitale (Hn_LectureVitale error %d) - Please retry\n", err);
cv2extractor_warning("Error trying to read a Carte Vitale (Hn_LectureVitale error %d).", err);
//goto_cleanup_with_rc_with_critical("Error trying to read a Carte Vitale (Hn_LectureVitale error)", err);
}
} else if(err != CV2EXTRACTOR_NO_ERROR) {
g_printf("\nError testing for card insertion (Hn_TestPresence error %d)\n", err);
cv2extractor_warning("Error testing for card insertion (Hn_TestPresence error %d).", err);
//goto_cleanup_with_rc_with_critical("Error testing for card insertion (Hn_TestPresence error)", err);
}
sleep(TIME_SLEEP);
} while(TRUE);
/*
* API VITALE Session closing.
*
* Not used. Exit loop not yet implemented.
*/
g_printf("Disconnect API VITALE library of the reader...\n");
err = Hn_Finir(&pusCodeErreur);
if(err == CV2EXTRACTOR_NO_ERROR) {
g_printf("\t--> Reader disconnected.\n");
} else {
if(err == WAR_APICPS_NON_DISPONIBLE) {
g_printf("\t--> Reader disconnected.\n");
g_printf("\n--> Error loading CPS library, continue.\n");
}
else{
g_printf("\nError %d during disconnection, exit (Hn_Init)!\n", err);
goto_cleanup_with_rc_with_critical("Error %d during disconnection, exit (Hn_Init)!", err);
}
}
g_printf("\n");
rc = CV2EXTRACTOR_NO_ERROR;
cleanup:
/* Cleaning... */
return rc;
}