Application.
This commit is contained in:
parent
0110be74bf
commit
e9f297251e
|
@ -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;
|
||||
}
|
Reference in New Issue