campo-sirio/include/dongle.cpp
guy 5356e8206f Patch level : 10.0
Files correlati     : tutti
Ricompilazione Demo : [ ]
Commento            :
Aggiunto log_message per diagnostica su file campo.log
Ora utilizzato per verifica login a chiavi hw/sw


git-svn-id: svn://10.65.10.50/branches/R_10_00@22592 c028cbd2-c16b-5b4b-a496-9718f37d4682
2012-03-01 14:03:42 +00:00

1473 lines
34 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <xvt.h>
#include <applicat.h>
#include <config.h>
#include <dongle.h>
#include <isamrpc.h>
#include <modaut.h>
#include <scanner.h>
#include <utility.h>
#include <xvtility.h>
#include <urldefid.h>
///////////////////////////////////////////////////////////
// Dongle stuff
///////////////////////////////////////////////////////////
#define USERADR 26952
#define AGAADR 26953
#define REFKEY (unsigned char*)"CAMPOKEY"
#define VERKEY (unsigned char*)"ìpÙˆ¬cê<"
#pragma pack(push, 1)
struct TEutronHeader
{
char _serno[8]; // 8
unsigned short _year_assist; // 10
unsigned short _max_users; // 12
unsigned long _last_date; // 16
unsigned long _scad_date; // 20
unsigned long _checksum; // 24
unsigned short _version; // 26
unsigned short _patch; // 28
unsigned short _offset_to_bits; // 30
unsigned short _size_of_bits; // 32
};
#pragma pack(pop)
///////////////////////////////////////////////////////////
// Current dongle
///////////////////////////////////////////////////////////
static TDongle* _dongle = NULL;
TDongle& dongle()
{
if (_dongle == NULL)
_dongle = new TDongle;
return *_dongle;
}
bool destroy_dongle()
{
bool ok = _dongle != NULL;
if (ok)
{
delete _dongle;
_dongle = NULL;
}
return ok;
}
///////////////////////////////////////////////////////////
// Bit helper functions
///////////////////////////////////////////////////////////
inline bool test_bit(word w, int b)
{
bool on = (w & (1 << b)) != 0;
return on;
}
inline void set_bit(word& w, int b, bool on = true)
{
if (on)
w |= 1 << b;
else
w &= ~(1 << b);
}
inline void reset_bit(word& w, byte b)
{
w &= ~(1 << b);
}
///////////////////////////////////////////////////////////
// TDongle
///////////////////////////////////////////////////////////
TDongle::TDongle()
: _hardware(_dongle_unknown), _type(_no_dongle), _serno(0xFFFF),
_max_users(1), _year_assist(2009), _dirty(false), _OEM(-1)
{
memset(_eprom, 0, sizeof(_eprom));
}
TDongle::~TDongle()
{
if (_serno != 0xFFFF)
logout();
}
const TString& TDongle::administrator(TString* pwd) const
{
if (_admin.blank())
oem();
if (pwd)
*pwd = _admpwd;
return _admin;
}
// Data punta ad un array di 4 words
// Deve essere cosi' per problemi del C,
// non trasformare in array: pena di morte!
void TDongle::garble(word* data) const
{
switch (_hardware)
{
case _dongle_hardlock:
xvt_dongle_hl_crypt(data);
break;
case _dongle_eutron:
xvt_dongle_sl_crypt(data);
break;
case _dongle_ssa:
xvt_dongle_sa_crypt(data); // Reversible XOR encryption
break;
default:
break;
}
}
bool TDongle::already_programmed() const
{
if (_hardware == _dongle_hardlock)
{
word data[4];
memcpy(data, &_eprom[60], sizeof(data));
garble(data);
if (data[0] < 1997 || data[0] > 2997)
return false;
if (data[1] == 0 || data[1] >= 10000)
return false;
const TDate today(TODAY);
const long giulio = *((const long*)&data[2]);
const long yyyymmdd = today.julian2date(giulio);
const TDate d(yyyymmdd);
if (d.year() < 1997 || d > today)
return false;
} else
if (_hardware == _dongle_eutron)
{
const TEutronHeader* eh = (const TEutronHeader*)_eprom;
if (eh->_serno[0] == 0 || eh->_checksum == 0)
return false; // Really virgin.
unsigned long cs = 0;
for (byte* ptr = (byte*)_eprom; ptr < (byte*)&eh->_checksum; ptr++)
cs += *ptr | ~(short(*ptr << 8));
if (eh->_checksum != cs)
return false; // Malicious programming!
}
return true;
}
void TDongle::set_developer_permissions()
{
if (_serno == 0 && is_power_station())
{
_module.set(255); // Last module on key
_module.set(); // Activate all modules
}
else
{
_module.reset(-1);
_module.set(0, true);
}
_shown.reset();
_max_users = 1;
_last_update = TDate(TODAY);
_year_assist = 3000;
}
bool TDongle::hardlock_login(bool test_all_keys)
{
bool ok = true;
_type = _user_dongle;
if (test_all_keys)
{
xvt_dongle_hl_logout();
if (xvt_dongle_hl_login(AGAADR, REFKEY, VERKEY))
_type = _aga_dongle;
}
xvt_dongle_hl_logout();
ok = xvt_dongle_hl_login(USERADR, REFKEY, VERKEY) != 0;
if (ok)
{
_hardware = _dongle_hardlock;
xvt_dongle_hl_read_block((unsigned char*)_eprom);
word data[4];
memcpy(data, _eprom, sizeof(data));
garble(data);
if (data[0] == 0xFAE8)
_serno = data[1];
else
{
if (data[0] == 0x3283 || data[0] == 0xA3AA) // chiave programmatori !!
{
if (_type == _user_dongle)
_type = _developer_dongle;
_serno = 0;
#ifdef DBG
if (test_all_keys && is_power_station())
_type = _aga_dongle;
#endif
}
}
}
else
log_message("hardlock_login() failed");
if (ok)
{
_max_users = 1;
_last_update = TDate(TODAY);
_year_assist = _last_update.year();
if (_type == _user_dongle) //chiave cliente
{
const bool already = already_programmed();
_module.reset(); // Disattiva tutti i moduli
_shown.reset();
const int last_word = already ? 12 : 4;
word data[4];
// Legge flag di attivazione dei moduli
for (int i = 0; i < last_word; i += 4)
{
memcpy(data, &_eprom[48+i], sizeof(data));
garble(data);
if (data[3] == _serno) // Validate block
{
for (int j = 0; j < 3; j++)
{
word parola = data[j] ^ _serno;
if (parola)
{
for (int b = 15; b >= 0; b--)
{
if (test_bit(parola, b))
{
const word bit = i * 12 + j * 16 + b;
_module.set(bit+1);
}
}
}
}
}
else
break;
}
_module.set(0, true); // Forza l'attivazione della base
// Legge anno di assitenza e numero massimo di utenti
memcpy(data, &_eprom[60], sizeof(data));
garble(data);
if (already)
{
_year_assist = data[0];
_max_users = data[1];
const long giulio = *((const long*)&data[2]);
const long yyyymmdd = _last_update.julian2date(giulio);
_last_update = yyyymmdd;
}
else
{
_year_assist = 0;
_dirty = true;
}
}
else
set_developer_permissions();
}
else
_type = _no_dongle;
return ok;
}
bool TDongle::eutron_login(bool /*test_all_keys*/) // AGA dongle pitifully died
{
bool ok = false;
const char* labels[2] = { "AGA.CAMPO", "25EBAI" };
TDongleType types[2] = { _user_dongle, _developer_dongle };
for (int k = 0; k < 2; k++)
{
const unsigned char* pwd = (const unsigned char*)::encode(labels[k]);
ok = xvt_dongle_sl_login((const unsigned char*)labels[k], pwd) != 0;
if (ok)
{
_hardware = _dongle_eutron;
_type = types[k];
break;
}
else
log_message("eutron_login(\"%s\") failed", labels[k]);
}
if (ok)
{
_serno = 0;
_max_users = 1;
_last_update = TDate(TODAY);
_year_assist = _last_update.year();
if (_type == _user_dongle) //chiave cliente
{
_module.reset(); // Disattiva tutti i moduli
if (read_words(0, sizeof(TEutronHeader) / 2, _eprom))
{
const TEutronHeader* eh = (const TEutronHeader*)_eprom;
TString16 serno; serno.strncpy(eh->_serno, 8);
_serno = unsigned(atol(serno));
if (already_programmed())
{
_max_users = eh->_max_users;
_last_update = eh->_last_date;
_year_assist = eh->_year_assist;
// Calcola il numero della word dove cominciano i bit di attivazione
unsigned short otb = eh->_offset_to_bits;
if (otb == 0) otb = 16; // Compatibile Hardlock
unsigned short sob = eh->_size_of_bits;
if (sob == 0) sob = 16; // Compatibile Hardlock
word data[64];
if (read_words(otb, sob, data))
{
int module = 1;
for (word w = 0; w < sob; w++)
{
for (int b = 0; b < 16; b++)
{
if (test_bit(data[w], b))
_module.set(module);
module++;
}
}
}
}
else
_dirty = true;
}
_module.set(0, true); // Forza l'attivazione della base
}
else
set_developer_permissions();
}
return ok;
}
bool TDongle::ssa_login(const char* mod)
{
if (mod && *mod)
{
return xvt_dongle_sa_login(mod) == 0;
}
_max_users = 1;
_last_update = TDate(TODAY);
_year_assist = _last_update.year();
_module.reset(); // Disattiva tutti i moduli
_module.set(0L); // Attiva la base
const int err = xvt_dongle_sa_login(NULL);
_serno = (err >= 0) ? err : 0xFFFF;
if (_serno != 0xFFFF)
{
_hardware =_dongle_ssa;
_type = _serno ? _user_dongle : _developer_dongle;
if (_serno)
{
Tdninst dn;
if (dn.find_serno())
_year_assist = dn.assist_year();
else
_year_assist = 2121;
for (word m = BAAUT; m < ENDAUT; m++)
{
const TString& name = module_code2name(m);
if (xvt_dongle_sa_test(name) == 0)
_module.set(m);
}
}
else
set_developer_permissions();
}
else
log_message("ssa_login() failed with code %d", err);
return _serno != 0xFFFF;
}
bool TDongle::network_login(bool test_all_keys)
{
const char* appname = main_app().name();
if (network() && ok())
rpc_UserLogout(appname);
TString server = "127.0.0.1";
if (!xvt_sys_dongle_server_is_running())
server = ini_get_string(CONFIG_INSTALL, "Server", "Dongle");
// const char* guest = "******";
// const TString16 appname = main_app().name();
// const char* utente = (!main_app().is_running() && appname == "ba0100") ? guest : (const char *) user();
const char* utente = user();
bool ok = rpc_UserLogin(server, utente, "******", appname);
if (ok)
{
_hardware = _dongle_network;
_type = _user_dongle;
_max_users = 1;
_last_update = TDate(TODAY);
// Let's try to spare some network band!
ok = rpc_DongleInfo(_serno, _year_assist, _module);
if (!ok)
{
_serno = rpc_DongleNumber();
_year_assist = rpc_DongleYear();
ok = rpc_DongleModules(_module);
if (ok && main_app().name() == "ba0100")
warning_box("ATTENZIONE! Il server di protezione non e' aggiornato:\n"
"Controllare la corretta installazione del servizio");
}
}
else
log_message("rpc_UserLogin(%s, %s) failed", (const char*)server, (const char*)utente);
return ok;
}
int TDongle::can_try_server() const
{
// Se authoriz sta andando sono obbligato ad usarlo
if (xvt_sys_dongle_server_is_running())
return 3;
// Se sono un client ed ho l'indirizzo di authoriz sono obbligato ad usarlo
const TString& dongle = ini_get_string(CONFIG_INSTALL, "Server", "Dongle");
if (dongle.full())
return ini_get_int(CONFIG_INSTALL, "Main", "Type") == 3 ? 3 : 1;
return 0;
}
bool TDongle::login(bool test_all_keys)
{
bool ok = true;
if (_type != _no_dongle) // Already logged in
logout();
TDongleHardware hw = _hardware;
if (hw == _dongle_unknown)
{
if (can_try_server())
hw = _dongle_network;
else
hw = (TDongleHardware)ini_get_int(CONFIG_INSTALL, "Main", "Donglehw");
}
switch(hw)
{
case _dongle_hardlock: ok = hardlock_login(test_all_keys); break;
case _dongle_eutron : ok = eutron_login(test_all_keys); break;
case _dongle_network : ok = network_login(test_all_keys); break;
case _dongle_ssa : ok = ssa_login(NULL); break;
default : ok = false; break;
}
if (!ok)
{
// retry login for various dongles ...
const int should_use_server = can_try_server();
if (should_use_server != 3) // Non sono obbligato ad usare il Dongle Server
{
if (!ok && hw != _dongle_eutron)
ok = eutron_login(test_all_keys);
if (!ok && hw != _dongle_hardlock)
ok = hardlock_login(test_all_keys);
if (!ok && hw != _dongle_ssa)
ok = ssa_login(NULL);
}
if (ok)
ini_set_int(CONFIG_INSTALL, "Main", "Donglehw", (int)_hardware);
else
{ // DEMO
_hardware = _dongle_unknown;
_type = _no_dongle;
_serno = 0xFFFF; //numero di serie più alto possibile (65535 in esadecimale: non sarà mai raggiunto da chiavi clienti...magari!)
_max_users = 1;
_last_update = TDate(TODAY);
_year_assist = 3000; // anno di assistenza a 3000 per non avere problemi con le versioni nei vari anni
_module.set(ENDAUT); // Last module on key
_module.set(); // Activate all modules
_shown.reset();
}
}
return ok;
}
bool TDongle::login(const char* module)
{
const word code = module_name2code(module);
bool ok = active(code);
if (ok && _hardware == _dongle_ssa)
ok = ssa_login(module);
return ok;
}
bool TDongle::logout()
{
switch (_hardware)
{
case _dongle_hardlock:
xvt_dongle_hl_logout();
break;
case _dongle_eutron:
xvt_dongle_sl_logout();
break;
case _dongle_network:
rpc_UserLogout(main_app().name());
break;
case _dongle_ssa:
xvt_dongle_sa_logout(NULL);
break;
default:
break;
}
_type = _no_dongle;
_serno = 0xFFFF;
return true;
}
// Data punta ad un array di 4 words
// Deve essere cosi' per problemi del C,
// non trasformare in array: pena di morte!
bool TDongle::read_words(word reg, word len, word* ud) const
{
bool ok = false;
switch (_hardware)
{
case _dongle_hardlock:
{
for (word i = 0; i < len; i++)
xvt_dongle_hl_read(reg+i, &ud[i]);
ok = true;
}
break;
case _dongle_eutron:
while (len > 0)
{
const unsigned short size = (len <= 16) ? len : 16;
ok = xvt_dongle_sl_read_block(reg, size, ud) != 0;
if (!ok)
{
yesnofatal_box("EUTRON read error");
break;
}
len -= size;
reg += size;
ud += size;
}
break;
default:
break;
}
return ok;
}
// Data punta ad un array di 4 words
// Deve essere cosi' per problemi del C,
// non trasformare in array: pena di morte!
bool TDongle::write_words(word reg, word len, word* data) const
{
bool ok = false;
switch(_hardware)
{
case _dongle_hardlock:
{
for (word r = 0; r < len; r++)
{
const word address = reg+r;
ok = xvt_dongle_hl_write(address, data[r]) != 0;
}
}
break;
case _dongle_eutron:
while (len > 0)
{
const unsigned short size = (len <= 16) ? len : 16;
ok = xvt_dongle_sl_write_block(reg, size, data) != 0;
if (!ok)
break;
len -= size;
reg += size;
data += size;
}
break;
default:
break;
}
return ok;
}
int TDongle::oem() const
{
if (_OEM < 0)
{
TString& firm = (TString&) _reseller;
TString& campo = (TString&) _product;
TString& breve = (TString&) _shortname;
TString& admin = (TString&)_admin;
TString& admpwd = (TString&)_admpwd;
int& oem = (int&)_OEM;
//nuovo metodo di rilevamento producer (dalla 10.0 in avanti); il producer sta nel file oem.ini sotto la cartella
//setup, sia nel CD che soprattutto nel programma installato
TConfig ini(CONFIG_OEM, "MAIN");
oem = ini.get_int("OEM", NULL, -1, -1);
if (oem >= 0)
{
TString8 para; para << "OEM_" << oem;
ini.set_paragraph(para);
campo = decode(ini.get("Product"));
firm = decode(ini.get("Reseller"));
breve = decode(ini.get("Name"));
admin = decode(ini.get("Administrator"));
admpwd = decode(ini.get("Password"));
}
if (firm.blank()) //vecchio metodo di rilevamento del producer: sta in install.ini
{
firm = decode(ini_get_string(CONFIG_GENERAL, "Main", "Producer"));
campo = breve = " ";
}
//nuovo metodo: cerca produttore (Name) e prodotto (Product)
if (firm.blank())
{
ignore_xvt_errors(true);
char* p = firm.get_buffer(80);
xvt_res_get_str(STR_FIRMNAME, p, firm.size());
ignore_xvt_errors(false);
}
if (admin.blank())
{
admin = decode(ini_get_string(CONFIG_GENERAL, "Main", "Administrator"));
if (admin.blank())
{
admin = "ADMIN";
admpwd = "ad.min";
}
}
if (admpwd.blank())
{
admpwd = decode(ini_get_string(CONFIG_GENERAL, "Main", "Password"));
if (admpwd.blank())
{
admpwd = admin;
admpwd.lower();
admpwd.insert(".", 2);
}
}
if (campo.blank())
campo = "Campo Enterprise";
if (firm.blank())
firm = "Sirio Informatica e Sistemi s.p.a.";
if (breve.blank())
breve = "Campo";
if (oem < 0) oem = 1;
}
return _OEM;
}
// Ritorna il nome della ditta che vende il programma attuale
const TString& TDongle::reseller() const
{
if (_reseller.empty())
oem();
return _reseller;
}
const TString& TDongle::product() const
{
if (_product.empty())
oem();
return _product;
}
const TString& TDongle::short_name() const
{
if (_shortname.empty())
oem();
return _shortname;
}
const TString& TDongle::server_name() const
{
if (network() && !xvt_sys_dongle_server_is_running())
return ini_get_string(CONFIG_INSTALL, "Server", "Dongle");
TString& tmp = get_tmp_string(32);
xvt_sys_get_host_name(tmp.get_buffer(), tmp.size());
return tmp;
}
bool TDongle::active(word module) const
{
const bool yes = (module < ENDAUT) && _module[module] && shown(module);
return yes;
}
bool TDongle::activate(word module, bool on)
{
bool ok = module < ENDAUT;
if (ok)
{
_module.set(module, on && shown(module));
_dirty = true;
}
return ok;
}
bool TDongle::burn_hardlock()
{
word data[4];
const TDate today(TODAY);
const bool already = already_programmed();
if (already)
{
memcpy(data, &_eprom[60], sizeof(data));
garble(data);
if (data[0] < 2001 || data[0] > 3001)
return error_box("On Line Assistance error.");
if (data[1] == 0 || data[1] >= 10000)
return error_box("Bad users number.");
const long val = *((const long*)&data[2]);
const long yyyymmdd = today.julian2date(val);
const TDate date(yyyymmdd);
if (date > today)
return error_box("Too late sir: key has already expired!");
}
data[0] = _year_assist;
data[1] = _max_users;
long* val = (long*)&data[2];
*val = today.date2julian();
garble(data);
write_words(60, 4, data);
_last_update = today;
// Il primo bit della memoria della chiave corrisponde al modulo uno
// non allo zero (che e' la base ed e' sempre attivo)
word module = 1;
for (int octect = 0; octect < 3; octect++)
{
for(int parola = 0; parola < 3; parola++)
{
word& p = data[parola];
p = 0;
for (int bit = 0; bit < 16; bit++)
{
if (active(module))
set_bit(p, bit);
module++;
}
p ^= _serno;
}
data[3] = _serno;
garble(data);
write_words(48 + 4*octect, 4, data);
}
return true;
}
bool TDongle::burn_eutron()
{
TEutronHeader* eh = (TEutronHeader*)_eprom;
memset(eh, 0, sizeof(TEutronHeader));
_last_update = TDate(TODAY);
sprintf(eh->_serno, "%lu", (unsigned long)_serno);
eh->_year_assist = _year_assist;
eh->_max_users = _max_users;
eh->_last_date = atol(_last_update.string(ANSI));
eh->_scad_date = 0;
unsigned long cs = 0;
for (byte* ptr = (byte*)_eprom; ptr < (byte*)&eh->_checksum; ptr++)
cs += *ptr | ~(short(*ptr << 8));
eh->_checksum = cs;
const word otb = sizeof(TEutronHeader) / 2;
const word sob = 16;
eh->_offset_to_bits = otb;
eh->_size_of_bits = sob;
bool ok = write_words(0, otb, _eprom);
if (ok)
{
word data[sob]; memset(data, 0, sizeof(data));
for (int module = 1; module < 256; module++)
{
if (active(module))
{
word& w = data[(module-1) / 16];
set_bit(w, (module-1) % 16, true);
}
}
ok = write_words(otb, sob, data);
}
return ok;
}
bool TDongle::burn()
{
bool ok = local() && _type == _user_dongle;
if (ok)
{
switch(_hardware)
{
case _dongle_hardlock: ok = burn_hardlock(); break;
case _dongle_eutron : ok = burn_eutron(); break;
default : ok = false; break;
}
}
if (ok)
_dirty = false;
return ok;
}
const TString_array& TDongle::info() const
{
if (_info.items() == 0)
{
TScanner scanner("campo.aut");
for (int aut = 0; ; aut++)
{
const TString& row = scanner.line();
if (row.blank())
break;
TToken_string* tok = new TToken_string;
tok->strncpy(row, 3);
const TString& name = row.mid(3);
if (name.full())
*tok << dictionary_translate(name);
((TString_array&)_info).add(tok);
}
}
return _info;
}
word TDongle::module_name2code(const char* mod) const
{
int i = BAAUT;
if (mod && *mod && xvt_str_compare_ignoring_case(mod, "sy") != 0)
{
if (real::is_natural(mod))
{
i = atoi(mod);
// Trasforma il numero 77 nel codice M77AUT
if (i == 77)
i = M77AUT;
}
else
{
const TString_array& modinfo = info();
for (i = modinfo.last(); i >= 0; i--)
{
const TString& autstr = modinfo.row(i);
if (autstr.starts_with(mod, true))
break;
}
}
}
return word(i);
}
const TString& TDongle::module_code2name(word mod) const
{
const TString_array& modinfo = info();
if (mod < modinfo.items())
return modinfo.row(mod).left(2);
return EMPTY_STRING;
}
const TString& TDongle::module_code2desc(word mod) const
{
const TString_array& modinfo = info();
return mod < modinfo.items() ? modinfo.row(mod).mid(3) : EMPTY_STRING;
}
const TString& TDongle::module_name2desc(const char* mod) const
{
const word cod = module_name2code(mod);
if (cod == 0)
{
if (xvt_str_compare_ignoring_case(mod, "sy") == 0)
return get_tmp_string() = TR("Sistema");
}
return module_code2desc(cod);
}
bool TDongle::shown(word code) const
{
bool yes = code < ENDAUT;
if (yes)
{
yes = _shown[code];
if (!yes) // Puo' voler dire "nascosto" ma anche "non ho mai controllato"
{
const TString4 mod = module_code2name(code);
yes = mod.not_empty();
if (yes && code > BAAUT && code < ENDAUT)
{
TAuto_token_string ee = ini_get_string(CONFIG_GENERAL, mod, "OEM"); // Modern OEM handling
if (ee.full())
yes = ee.get_pos(oem()) >= 0;
}
if (yes)
((TBit_array&)_shown).set(code); // Setto il flag di visibilta' per la prossima volta
}
}
return yes;
}
bool TDongle::demo() const
{ return hardware() == _dongle_unknown && type() == _no_dongle; }
///////////////////////////////////////////////////////////////////////////////
// TEnigma_machine
///////////////////////////////////////////////////////////////////////////////
#define DNINST_PATH "setup/dninst.zip"
class TEnigma_machine : public TObject
{
TScanner* _scan;
int _year_assist;
protected:
void init_key(char key[8]) const;
bool decode_string(const TString& datain, TString& dataout) const;
bool encode_string(const TString& linein, TString& lineout) const;
bool init();
void uninit();
public:
virtual bool ok() const { return _scan != NULL && !_scan->eof(); }
bool line(TString& data);
bool find_serno(long serno);
int year_assist() const { return _year_assist; }
bool encode(const TString& txtfile); // dninst.txt -> dninst.zip
TEnigma_machine();
~TEnigma_machine();
};
void TEnigma_machine::init_key(char key[8]) const
{
for (int i = 0; i < 8; i++)
key[i] = 'A' + ::rand() % 26;
}
bool TEnigma_machine::decode_string(const TString& datain, TString& dataout) const
{
dataout.cut(0);
if (datain.not_empty())
{
char* tmp = dataout.get_buffer(datain.len());
char key[8]; init_key(key);
int i;
for (i = 0; datain[i]; i++)
tmp[i] = datain[i] - (i < 8 ? key[i] : tmp[i - 8]);
tmp[i] = '\0';
}
return dataout.full();
}
bool TEnigma_machine::encode_string(const TString& linein, TString& lineout) const
{
lineout.cut(0);
if (linein.full() && !linein.starts_with("//"))
{
char key[8]; init_key(key);
char* buf = lineout.get_buffer(linein.len());
size_t i = 0;
for (i = 0; linein[i]; i++)
buf[i] = linein[i] + (i < 8 ? key[i] : linein[i - 8]);
buf[i] = '\0';
}
return lineout.full();
}
bool TEnigma_machine::line(TString& data)
{ return _scan != NULL ? decode_string(_scan->line(), data) : false; }
bool TEnigma_machine::find_serno(long serno)
{
if (serno == 0)
return true;
TToken_string row(80, ';');
if (_year_assist > 2100)
{
TString8 para; para << '[' << serno << ']';
while (line(row))
{
if (row == para)
return true;
}
}
else
{
while (line(row))
{
if (row.get_long(0) == serno)
return true;
}
}
return false;
}
bool TEnigma_machine::encode(const TString& txtfile)
{
uninit();
ofstream o(DNINST_PATH);
TString lineout;
TScanner s(txtfile);
const TString& year = s.line();
::srand(883);
encode_string(year, lineout);
o << lineout << endl;
::srand(atoi(year));
while (s.good())
{
const TString& linein = s.line();
if (linein.empty())
break;
encode_string(linein, lineout);
o << lineout << endl;
}
init();
return o.good();
}
void TEnigma_machine::uninit()
{
_year_assist = 0;
if (_scan != NULL)
{
delete _scan;
_scan = NULL;
}
}
bool TEnigma_machine::init()
{
uninit();
if (fexist(DNINST_PATH))
{
_scan = new TScanner(DNINST_PATH);
::srand(883);
TString4 l1; line(l1);
_year_assist = atoi(l1);
::srand(_year_assist);
}
return _scan != NULL;
}
TEnigma_machine::TEnigma_machine()
: _scan(NULL), _year_assist(0)
{ init(); }
TEnigma_machine::~TEnigma_machine()
{ uninit(); }
int Tdninst::assistance_year2solar(int ay) const
{ return (ay/1000)*1000 + (ay%1000)/10; }
int Tdninst::parse_date(const TString& line, TString& key, TDate& datascad) const
{
const int equal = line.find('=');
if (equal > 0 && equal <= 16)
{
key = line.left(equal); key.trim();
TString16 strdate = line.mid(equal+1, 16); strdate.trim();
if (strdate.empty())
{
datascad = TODAY; // Mettiamo una data valida comunque
return key.full() ? 1 : 0;
}
int d, m, y;
if (sscanf(strdate, "%2d-%2d-%4d", &d, &m, &y) == 3)
{
datascad = TDate(d, m, y);
return datascad.ok() ? 2 : 0;
}
}
return 0;
}
bool Tdninst::compare_cmdline(const TString& cmdline, const TString& pattern) const
{
if (cmdline == pattern)
return true;
bool is_pattern = false;
if (pattern.len() > 2)
{
for (int i = 2; pattern[i]; i++)
{
if (pattern[i]=='*' || pattern[i] == '?')
is_pattern = true;
}
}
if (is_pattern)
return cmdline.match(pattern, true);
return false;
}
int Tdninst::test_cmdline(const TString& cmdline, bool key_must_exist, TString& msg) const
{
msg.cut(0);
const TDongle& don = dongle();
const long serno = don.number();
if (serno == 0)
{
if (is_power_reseller(true))
return 0; // Solo chiavi per uso interno aga
msg = TR("Chiave di sviluppo non autorizzata");
return 1;
}
const TString4 strmod = cmdline.left(2);
if (!key_must_exist) // Le personalizzazioni non hanno un modulo vero e proprio
{
const int space_pos = cmdline.find(' ');
if (space_pos < 0 || space_pos == 3)
{
const word codmod = don.module_name2code(strmod);
if (codmod == BAAUT)
return 0;
}
}
TEnigma_machine em;
const int dninst_ass = em.year_assist();
const TDate oggi(TODAY);
bool bFound = false;
if (dninst_ass > 2100)
{
if (em.find_serno(serno))
{
TString80 dninst_line;
TString16 key;
TDate datascad;
while (em.line(dninst_line))
{
if (dninst_line.empty() || dninst_line.starts_with("["))
break; // Fine file o paragrafo
if (parse_date(dninst_line, key, datascad))
{
const TDate oggi(TODAY);
const bool scaduto = datascad < oggi;
if (key == "*")
{
if (scaduto)
{
msg << TR("Chiave scaduta il ") << datascad;
return 7;
}
} else
if (compare_cmdline(cmdline, key))
{
bFound = true;
if (scaduto)
{
msg << TR("Applicazione scaduta il ") << datascad;
return 8;
}
} else
if (key == strmod)
{
if (scaduto)
{
msg << TR("Modulo scaduto il ") << datascad;
return 9;
}
}
}
}
}
}
else
{
TToken_string dninst_line(80, ';');
while (em.line(dninst_line))
{
bFound = dninst_line.get_long(0) == serno;
if (bFound)
{
if (dninst_line.get_pos(strmod) > 0)
{
msg << TR("Modulo non attivo in dninst.zip : ") << strmod;
return 5;
}
break;
}
}
}
if (!bFound && key_must_exist)
{
msg << TR("Impossibile trovare ") << cmdline;
return 6;
}
return 0;
}
bool Tdninst::can_I_run(const bool is_personal_program) const
{
TFilename cmdline = main_app().argv(0);
cmdline = cmdline.name_only();
if (cmdline.starts_with("ba", true) || cmdline.ends_with("cnv", true))
return true;
const bool me = is_personal_program || (cmdline.len()>3 && !cmdline.ends_with("mod", true));
const char* option = main_app().argc() > 1 ? main_app().argv(1) : "";
if (*option == '-' && isdigit(*(option+1)))
cmdline << ' ' << option;
cmdline.lower();
TString msg;
return test_cmdline(cmdline, me, msg) == 0;
}
bool Tdninst::find_serno() const
{
const word serno = dongle().number();
if (serno == 0)
return true;
const TDate oggi(TODAY);
bool good = false;
TEnigma_machine em;
if (em.ok())
{
if (em.year_assist() > 2100)
{
good = em.find_serno(serno);
}
else
{
TToken_string l(80, ';');
while (em.line(l))
{
if (l.get_long(0) == serno)
{
good = true;
break;
}
}
}
}
return good;
}
bool Tdninst::find_killed(TToken_string& kill_list) const
{
kill_list.cut(0);
const int serno = dongle().number();
if (serno == 0)
return true;
bool good = false;
TEnigma_machine em;
if (em.ok())
{
if (em.year_assist() > 2100)
{
TToken_string l(80, '=');
good = em.find_serno(serno);
if (good)
{
const TDate oggi(TODAY);
TString16 str;
TDate ds;
while (em.line(l))
{
if (l.empty() || l[0] == '[')
break;
if (parse_date(l, str, ds) && ds < oggi)
kill_list.add(str);
}
}
}
else
{
TToken_string l(80, ';');
while (em.line(l))
{
if (l.get_long(0) == serno)
{
const int semicolon = l.find(l.separator());
if (semicolon > 0)
{
kill_list = l.mid(semicolon+1);
kill_list.lower();
kill_list.replace(l.separator(), kill_list.separator());
}
good = true;
break;
}
}
}
}
return good;
}
bool Tdninst::find_expiring(int days, TString& module, TDate& expires) const
{
const TDate oggi(TODAY);
expires = oggi; expires += days;
module.cut(0);
const word serno = dongle().number();
if (serno == 0)
return false;
TEnigma_machine em;
if (em.ok() && em.year_assist() > 2100 && em.find_serno(serno))
{
TToken_string l(80, '=');
TString16 str;
TDate ds;
while (em.line(l))
{
if (l.empty() || l[0] == '[')
break;
if (parse_date(l, str, ds) && ds >= oggi && ds <= expires)
{
module = str;
expires = ds;
}
}
}
return module.full();
}
int Tdninst::check_customer() const
{
int error = 2; // Not found
const word serno = dongle().number();
if (serno == 0)
error = is_power_station() ? 0 : 2;
else
{
TEnigma_machine em;
if (em.ok() && em.year_assist() > 2100 && em.find_serno(serno))
{
error = 0;
TToken_string l(80, '=');
while (em.line(l) && error == 0)
{
if (l.empty() || l[0] == '[')
break;
if (l[0]=='*' || l.starts_with("MustCall"))
{
const TDate oggi(TODAY);
TString16 str;
TDate ds;
if (parse_date(l, str, ds) && oggi >= ds)
error = (l[0] == '*') ? 2 : 1;
}
}
}
}
return error;
}
bool Tdninst::decode(const TString& f) const
{
ofstream o(f);
TEnigma_machine em;
o << em.year_assist() << endl;
size_t nlines = 0;
TString256 l;
while (em.line(l))
{
o << l << endl;
nlines++;
}
return nlines > 0;
}
bool Tdninst::encode(const TString& f) const
{
TEnigma_machine em;
return em.encode(f);
}
Tdninst::Tdninst() : _year_assist(0)
{
TEnigma_machine s;
_year_assist = s.year_assist(); // 2091 or 2101?
}