campo-sirio/include/dongle.cpp

1038 lines
24 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 <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ê<"
///////////////////////////////////////////////////////////
// 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(2015), _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
{
xvt_dongle_sa_crypt(data); // Reversible XOR encryption
}
bool TDongle::already_programmed() const
{
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::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(long(BAAUT)); // ... tranne 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 = 2091; // Vecchia versione
for (word m = BAAUT+1; m < ENDAUT; m++)
{
const TString& name = module_code2name(m);
if (xvt_dongle_sa_test(name) == 0)
_module.set(long(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_running() & 0x1))
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(TR("ATTENZIONE! Il server di protezione non è aggiornato:\n"
"Controllare la corretta installazione del servizio"));
}
}
else
log_message("rpc_UserLogin(%s, %s) failed", (const char*)server, (const char*)utente);
return ok;
}
bool TDongle::login(bool test_all_keys)
{
bool ok = true;
if (_type != _no_dongle) // Already logged in
logout();
TDongleHardware hw = _hardware;
const int srv = xvt_sys_dongle_server_running();
if (srv != 0)
{
if (srv & 2)
hw = _dongle_ssanet;
else
hw = _dongle_network;
}
else
{
const TString& port = ini_get_string(CONFIG_SSA, "", "SSA-PORT");
if (port.full())
hw = _dongle_ssanet;
else
{
const TString& dongle = ini_get_string(CONFIG_INSTALL, "Server", "Dongle");
hw = dongle.full() ? _dongle_network : _dongle_ssa;
}
}
if (hw == _dongle_network)
ok = network_login(test_all_keys);
else
ok = ssa_login(NULL);
if (ok)
{
_hardware = hw;
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();
}
if (!ok && local())
{
TString_array ssa;
const int n = list_files("*.ssa", ssa);
switch (n)
{
case 0: error_box(FR("Non esistono file SSA validi")); break;
case 1: error_box(FR("File SSA non valido:\n%s"),
(const char*)ssa.row(0));
break;
default:
error_box(FR("Sono presenti troppi file SSA:\n%s,%s,..."),
(const char*)ssa.row(0), (const char*)ssa.row(1));
break;
}
}
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_network:
rpc_UserLogout(main_app().name());
break;
case _dongle_ssanet:
case _dongle_ssa:
xvt_dongle_sa_logout(NULL);
break;
default:
break;
}
_type = _no_dongle;
_serno = 0xFFFF;
return true;
}
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_running())
{
if (hardware() == _dongle_ssanet)
return ini_get_string(CONFIG_SSA, NULL, "Port");
return ini_get_string(CONFIG_INSTALL, "Server", "Dongle");
}
TString& tmp = get_tmp_string(50);
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;
}
const TString_array& TDongle::info() const
{
if (_info.empty())
{
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_same(mod, "sy"))
{
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_same(mod, "sy"))
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_station())
return 0; // Solo chiavi per uso interno Sirio
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 bool scaduto = datascad < oggi;
if (key == "*")
{
if (scaduto)
{
msg.format(FR("Chiave %ld scaduta il %s"), serno, datascad.string());
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 << TR(" tra i programmi abilitati");
return 6;
}
return 0;
}
bool Tdninst::can_I_run(const bool is_personal_program, const bool verbose) const
{
const TApplication& app = main_app();
TFilename cmdline = app.argv(0);
cmdline = cmdline.name_only();
if (cmdline.starts_with("ba", true) || cmdline.ends_with("cnv", true))
return true;
const char* option = app.argc() > 1 ? app.argv(1) : "";
if (*option == '-' && isdigit(*(option+1)))
cmdline << ' ' << option;
cmdline.lower();
TString msg;
bool ok = test_cmdline(cmdline, is_personal_program, msg) == 0;
if (!ok && verbose)
error_box(msg);
return ok;
}
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(); // 2101, 2121, 2151
}