Newsgroup: it.comp.lang.c++
Titolo: Domanda di design: Come connettersi a un DB

Ciao a tutti,
come alcuni di voi sanno sto scrivendo, con moooolta calma, una
libreria generica per l'accesso a DB relazionali. Con un approccio
molto poco originale il punto d'ingresso e' la classe
sql_cli::connection, che idealmente si usa cosi':
// Crea una connessione ad uno specifico backend, dove per backend
// si intende la tecnologia RDBMS sottostante:
// ODBC, Oracle, PostgreSQL, ecc.
sql_cli::connection conn("ODBC");
// Si connette ad uno specifico database
conn.connect(...);
Il problema e' cosa mettere al posto dei puntini. Ad un estremo c'e'
un approccio completamente indipendente dalla tecnologia sottostante;
assumo che tutti i DBMS prevedano l'uso di database, utente e password
e fornisco solo l'accesso tramite questi parametri:
conn.connect("Customer", "nmusatti", "password1");
E' un approccio comodo, soprattutto per chi non ha particolare
dimestichezza coi DB relazionali o deve scrivere codice indipendente
dalla tecnologia sottostante, ma e' poco generale.
L'approccio diametralmente opposto comporta l'utilizzo di una non
meglio specificata stringa di connessione, da passare immutata alle
routine specifiche di ciascuna piattaforma:
conn.connect("SERVER=Customer;UID=nmusatti;PWD=password1;");
Questo e' l'approccio massimamente generale, ma richiede di conoscere
dettagli particolari delle piattaforme che interessano.
Una possibile via di mezzo comporta l'utilizzo dei parametri db,
username e password, con in aggiunta un meccanismo opzionale per
specificare ulteriori parametri. Questo e' certamente generale come il
precedente, ma non sono convinto che ci sia un guadagno in termini di
chiarezza e semplicita'. Tra l'altro il fantomatico meccanismo
opzionale rendere necessaria una sintassi ad hoc per specificare i
parametri aggiuntivi, complicando ulteriormente le cose.
Cosa ne pensate? Vi ricordo che un obiettivo importante e' astrarre il
piu' possibile (ma non troppo!) dalla tecnologia sottostante.
Chi "vo' fa' l'americano" puo' trovare qui la versione internazionale
di questa richiesta: 
http://wthwdik.wordpress.com/2007/07/02/boostsqlcli-how-do-you-connect-to-a-database/
Ciao,
Nicola

 piu' possibile (ma non troppo!) dalla tecnologia sottostante.
Penso che si potrebbe prendere ad esempio la classe TCustomConnection
distribuita con la VCL di Delphi.
Come saprai, i nomi delle classi in Delphi hanno una T iniziale per
convenzione.
Ho sempre trovato interessanti gli approcci usati con questo prodotto
di Borland, perché si è sempre cercato di astrarre il più possibile,
tanto è vero che le varie tecnologie: ADO, dbExpress, BDE, ODBC,
ecc... per l'accesso ai dati o anche più generiche: SOAP, DCOM, CORBA,
si inquadrano benissimo in questa gerarchia di classi.
In particolare, a me piace dbExpress come motore generico di accesso
ai dati: tutto si basa su una TSQLConnection, derivata dalla classe
astratta TCustomConnection, la quale pubblica una proprietà Params: è
una map chiave/valore che viene poi elaborata dal driver sottostante.
Username e password figurano come chiavi di questa map.
Selezionando il DriverName, viene automaticamente impostata la
proprietà VendorLib con il nome della libreria appropriata e che è
scritta secondo i criteri standard di dbExpress. E' possibilissimo (e
l'ho fatto) sganciare la libreria per MySQL e metterci quella per
Oracle; non cambia nulla a livello applicativo.
Grazie al fatto che tutte le classi di connessione ai dati vengono per
convenzione fatte derivare da TCustomConnection (così come tutte le
classi che rappresentano un dataset, risultato ad esempio di una
select, vengono derivate dalla classe astratta TDataset), sono stato
in grado di costruire, tempo fa, un semplicissimo connection pooler
del tutto astratto: implementava solo la logica legata al pool di
connessioni, senza scendere nello specifico di cosa fossero realmente.
My 2 cents :-)

 libreria generica per l'accesso a DB relazionali.
Ma deve essere multipiattaforma? Immagino di sě, altrimenti potresti
utilizzare direttamente ADO e non reinventare la ruota, no?
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
The EMG Music page:         
http://www.emagsoftware.it/emgmusic

 specificare ulteriori parametri. 
propongo una via di mezzo:
sql_cli::connection conn("ODBC");
custom_option_t* custom = conn->get_custom_option();
//setto le opzioni che voglio agendo su custom
conn.connect("Customer", "nmusatti", "password1", custom);
-------------------------
in connect il parametro custom è opzionale.
custom_option_t è una classe interfaccia che viene implemetata con una
classe adhoc del db scelto.
custom_option_t deve avere metodi per modificare le opzioni del db,
questi metodi devono essere in primis il più generale possibile per
facilitare il lavoro e quando necessario anche specifiche:
custom->mysql_set_qualcosa();
l'implementazione sottostante prenderà i dati e li adatterà al db in
uso;
se ad esempio usiamo oracole, si ingoreranno le funzioni mysql_*
spero di essere stato abbastanza chiaro
Ciao
-- 
Andrea Corradi | Debian User | 
www.debian.org
Fingerprint: A41E F6B0 DBDB F04C 4940 E411 30F3 CD62 57B1 8458
gpg --keyserver 
keyserver.linux.it
 --recv-key 57B18458
Please avoid sending me Word or PowerPoint attachments.
http://www.gnu.org/philosophy/no-word-attachments.html

utilizzare direttamente ADO e non reinventare la ruota, no?
Benché ADO mi piaccia come concetto, non è secondo me la soluzione
migliore (ho visto funzionare bene i provider per Oracle e SQL Server,
comunque). Bisogna tener presente che è basato su COM (tecnologia
peraltro abbastanza bacata). A me piace più il modello dbExpress (che
è già multipiattaforma), più scarno e leggero.

//setto le opzioni che voglio agendo su custom
Hummm... a questo punto non è meglio una map key/value?

 piu' possibile (ma non troppo!) dalla tecnologia sottostante.
Io ti suggerirei di dare un occhio alle API di SQLAlchemy.
Al di la del fatto che C++ non ha i named parameters, potresti comunque
accettare una stringa *e* i parametri come varargs. 
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.

 Nicola
Cos'ha SOCI ( 
http://soci.sourceforge.net/
 ) che non ti piace?

 peraltro abbastanza bacata). 
...
Scusa ma ti chiedo di argomentare questa affermazione.
COM tecnologia abbastanza bacata ?!?!?!?!?!?
A me non sembra proprio.
--
GM

 COM tecnologia abbastanza bacata ?!?!?!?!?!?
E' abbastanza risaputo.

 
A parte il fatto che l'idea di passare username e password in questo 
modo č contraria a tutte le regole di sicurezza, sono d'accordo che č un 
sistema molto pratico e spesso usato.
Secondo me la soluzione giusta č quella che prevede sia una connection 
string specifica per il DB che ha il vantaggio enorme di poter essere 
memorizzata con facilitą nella configurazione dell'applicazione che a 
questo punto si limita a passarla alla libreria db.
Poi per alcuni parametri (vedi ad esempio username e password) che 
potrebbero essere gestiti in un qualche modo dall'applicazione (ad 
esempio chiusetui all'utente) vanno previsti appositi membri con 
rispettivi setter.
C'č da stabilire come ci si deve comportare in caso di doppia 
definizione (stringa + setter): credo che il setter debba sovrascrivere 
la stringa.
Ad esempio:
conn.SetUsername("nmusatti");
conn.SetPassword("pwd");
conn.connect(myApp.Config.ConnectionString);
--
GM


Da chi????
Ma dove???
COM č alla base di decine di migliaia di software.
Alcuni di essi possono essere anche bacati, ma non mi risulta proprio 
che sia bacata "COM" in quanto tecnologia.
Anzi a me sembra un gran bel progetto, e piů ci lavoro piů me ne convinco.
Casomai COM č una tecnologia "complessa" che pertanto va conosciuta e 
studiata a fondo.
Ma tu conosci COM per poter fare queste affermazioni?

 Ma tu conosci COM per poter fare queste affermazioni?
Sì. Tu invece quanto conosci COM per scongiurare che possieda dei bug?
Prima di difendere a spada tratta una tecnologia, devi assicurarti di
conoscerla bene.
Chiudo qui per non voglio scadere in polemica e perché nel thread non
si sta parlando di questo.
COM è una tecnologia proprietaria che non ha applicazione al di fuori
del mondo Microsoft (se non qualche timido tentativo sotto Linux),
mentre una libreria di accesso a un db dovrebbe mantenersi
multipiattaforma.

Ok, COM č bacata perchč nel modo č risaputo da molti...
Va bene ho capito: se non ti va di discuterne č effettivamente meglio se 
chiudiamo quě.
Anche perchč come giustamente fai notare siamo OT.
Ciao
GM

 un sistema molto pratico e spesso usato.
si può mettere la passwd in un file a parte, leggerlo e passarlo alla
lib, l'esempio portato da Nicola è per semplificare.


 Hummm... a questo punto non è meglio una map key/value?
in effetti si; e ogni implementazione va a guardarsi gli indici che le
interssano


 connessioni, senza scendere nello specifico di cosa fossero realmente.
Questa e' un'altra cosa alla quale dovro' pensare: "Deferred to next
rel"
Ciao,
Nicola

 utilizzare direttamente ADO e non reinventare la ruota, no?
L'idea sarebbe quella di realizzare una libreria presentabile a Boost,
e in seconda battuta al comitato di standardizzazione. Non e' affatto
detto che ci arrivero', ma questi obiettivi delimitano in modo preciso
il campo di azione, per cui certamente multipiattaforma rispetto sia
al sistema operativo che al DBMS sottostante.
Ciao,
Nicola

 se ad esempio usiamo oracole, si ingoreranno le funzioni mysql_*
Forse non ho capito bene, ma per non usare una sintassi specifica per
ciascun DBMS mi invento un meccanismo mio, altrettanto specifico per
DBMS? Non posso dire che la cosa mi torni tanto...
Ciao,
Nicola

 Il problema e' cosa mettere al posto dei puntini. 
Hai dato una occhiata al metodo usato da SQLAlchemy?
http://www.sqlalchemy.org/docs/dbengine.html#dbengine_establishing
http://www.sqlalchemy.org/docs/sqlalchemy_engine_url.html
Saluti  Manlio Perillo

 interssano
Questo pone dei problemi di cui parlero' in un altro post.
Ciao,
Nicola

 Cos'ha SOCI (
http://soci.sourceforge.net/
) che non ti piace?
Premetto che se SOCI fa quel che ti serve, va benissimo cosi'. Tieni
presente pero' che tutto ha origine in una discussione sulla
presentazione a Boost di una libreria per l'accesso a DB, destinata ad
entrare nello standard del C++.
Da questo punto di vista SOCI ha diversi difetti. Per primo, cerca di
fare troppe cose allo stesso tempo: accesso di base, mapping OO-
relazionale, ecc. imponendo in questo modo determinate scelte, che
potrebbero non essere le migliori per tutte le applicazioni. In
secondo luogo abusa dell'overloading degli operatori nell'interfaccia,
implementando metafore totalmente inventate, che non hanno riscontro
nel contesto di riferimento, quello dei database. Terzo, il disegno
dei backend mi pare esageratamente object oriented, con un certo abuso
del pattern "template method".
Ciao,
Nicola

 rispettivi setter.
Non intendo duplicare strutture dati presenti nella piattaforma
sottostante. Per fare quello che dici rischio di dover mantenere dei
membri dati "username" e "password", senza avere alcun controllo di
quando l'utente si degna di fornirmi tutti i parametri necessari.
Meglio chiedere tutto in una volta e lasciare da una parte all'utente
e dall'altra all'API sottostante la responsabilita' di non tenere in
giro troppo a lungo le informazioni di autenticazione.
Ciao,
Nicola

 lib, l'esempio portato da Nicola è per semplificare.
Soprattutto in qualunque meccanismo ci si possa inventare, da qualche
parte una chiamata sostanzialmente equivalente a quella qui sopra non
puo' non esserci.
Ciao,
Nicola

 e in seconda battuta al comitato di standardizzazione.
Azz! :-)


 sistema molto pratico e spesso usato.
D'altronde è il sistema usato da tutti i DBMS.

 rel"
Tanto per dare qualche spunto, la cosa bella della VCL è che il
TDataSet (te lo dico ma immagino che tu ne sia al corrente, avendo
lavorato con i tool Borland) è una classe astratta dalla quale deriva
qualunque classe voglia implementare un dataset specifico, legato a
una specifica piattaforma. La cosa simpatica è che qualunque controllo
data-aware attinge ai dati mediante un TDatasource e il TDatasource si
rifa a un TDataset, quindi tutto si mantiene modulare e
flessibilissimo. In particolare, io uso con enorme soddisfazione il
TClientDataSet che è uno strumento creato inizialmente per la
programmazione distribuita, il quale si poggia a un TDatasetProvider
per il reperimento fisico dei dati e quest'ultimo si rifa al TDataset
di basso livello specifico (la TQuery, per intenderci). Volendo
scrivere un'applicazione per la gestione dei dati, le form vengono
create rifacendosi a dei TDatasource, quindi vengono fisicamente
isolate dal motore di lettura/scrittura informazioni.
Uff... c'è troppo da dire :-)

 
Ovviamente non mi riferifo al fatto che la password sia hard coded, ma 
al fatto che la password sia in chiaro nella memoria del processo.
Stesso discorso se la password è in un file.
IMHO le password dovrebbero persistere solo nelle zucche degli utenti (a 
dire la verità non solo IMHO ma in certi casi anche per legge... ma 
questo è un altro discorso che ha a che fare con i dati sensibili)
Un DBMS che abbia a cuore la sicurezza fatta come si deve, dovrebbe 
prevedere un sistema di riconoscimento degli utenti basato sul sistema 
operativo, non password "passate" in qualsiasi modo (o perlomeno non in 
chiaro).

 IMHO le password dovrebbero persistere solo nelle zucche degli utenti
Andrebbe bene se il DBMS fosse in grado di leggere le menti. Purtroppo
così non è e la password, in qualche modo, dovrai passargliela.
Poi, è anche possibile che il meccanismo sottostante al driver
implementi un hashing e venga spedito il digest verso il server, al
posto della password reale, ma questo risolve il problema di
nascondere la password, sicuramente non quello della sicurezza.

 
Si vede che oggi non ci prendiamo :)
Ad esempio SQLServer prevede anche la cosiddetta "trusted security" che 
riconosce l'utente del SO che ha lanciato il processo. Siccome in 
pratica (a meno di mirabolanti giravolte) č l'unico modo per scrivere 
applicazioni in regola con la legge (parlo di applicazioni client 
tradizionali, non web per capirci), mi sembra strano che gli altri DBMS 
non offrano meccanismi analoghi...
Poi siamo d'accordo che tutti i DBMS forniscano la loro "home made" 
security ma ritengo anche che (a parte per test e qualche giochetto) sia 
buona norma non usarla.
--
GM

 
NO: l'utente la password la digita quando si logga al sistema (che si 
spera prenda le dovute precauzioni) e poi basta. Se ogni processo che ha 
a che fare con la sicurezza avesse delle password in memoria, avresti un 
colabrodo.

 non offrano meccanismi analoghi...
Altri DBMS offrono tale meccanismo.
Ad esempio PostgreSQL usa i socket locali (UNIX) + ident.
Saluti  Manlio Perillo

 colabrodo.
Mi permetto di fare una osservazione.
Su sistemi Unix, ad esempio, solo l'utente che ha creato il processo può 
accedere alla sua area di memoria, oppure il super user.
Ora:
1) Se qualcuno sul sistema è in grado di loggarsi con le tue credenziali, 
non c'è sistema che tenga.
Usando l'autenticazione "locale" il compito dell'attaccante è reso ancora 
più facile
2) Se devi preoccuparti che il super user può avere accesso al tuo 
processo, non ne esci più...
Saluti  Manlio Perillo

 
Il fatto che la memoria sia protetta offre qualche garanzia in più 
(anche se poi bisognerebbe vedere se è protetta fino in fondo) ma 
comunque avere password in chiaro in giro non è bello: se non ci sono 
password, non c'è nulla da rubare. La regola d'oro è che la password NON 
deve persistere da nessuna parte e deve stare in memoria il minimo tempo 
possibile e nel modo più sicuro possibile. Per questo conviene 
concentrare la gestione della sicurezza in un solo punto.
Del super user mi devo preoccupare eccome: se riesce a rubare la mia 
password potrebbe fare casini a nome mio e questo non è bene!
Il fatto che root possa fare casini ci può anche stare, ma non che li 
possa fare al mio posto.
In termini di legge credo che questo sia un vincolo (almeno per i dati 
sensibili) e in ogni caso avrei qualche problema a lavorare con un 
sistema che permette a qualcun'altro (root, Dio, san Franceso o chiunque 
altro) di assumere la mia identità quando ci sono in ballo dati 
sensibili e responsabilità personale.
Poi ci sono da gestire una miriade di dettagli per quanto riguarda la 
qualità delle password...
Per questi motivi, converrai con me che una applicazione ben disegnata 
per quel che riguarda la sicurezza le password non dovrebbe neanche 
sapere cosa sono, ma affidarsi alla sicurezza del SO.
GM

 sapere cosa sono, ma affidarsi alla sicurezza del SO.
Al contrario. Molto meglio un approccio per livelli di sicurezza
successivi. Quando mi collego al sistema posso leggere la posta,
navigare, ecc. Se devo compiere operazioni delicate mi collego ad un
sistema di secondo livello, con un meccanismo di autenticazione
specifico.
Ciao,
Nicola

 dire la verità non solo IMHO ma in certi casi anche per legge...
M'e' capitato molto piu' spesso di vedere l'obbligo di un duplicato sicuro 
accessibile solo dall'autorita' giudiziaria (per legge), che una richiesta 
esplicita di assenza duplicati (quest'ultimo mai per legge).
--
Marco

 GM
Saluti  Manlio Perillo

 ed il meccanismo sottostante risulta piu' semplice.
si ma al variare del db deve _anche_ cambiare il parametro passato,
mentre se fa una map, può cambiare solo la stringa identificativa del
database. Non è cambi molto ma si evitano un po di controlli.



La legge dice questo:
"Le credenziali di autenticazione consistono in un codice per 
l'identificazione dell'incaricato associato a una parola chiave 
riservata conosciuta solamente dal medesimo oppure in un dispositivo di 
autenticazione in possesso e uso esclusivo dell'incaricato, 
eventualmente associato a un codice identificativo o a una parola 
chiave, oppure in una caratteristica biometrica dell'incaricato, 
eventualmente associata a un codice identificativo o a una parola chiave."
tratto da 
http://www.giustizia.it/cassazione/leggi/dlgs196_03.html#allegatob
qualsiasi richiesta di duplicato è illegale. Io la mia password non la 
do a nessuno e non la scrivo da nessuna parte.
Se l'autorità vuole accedere, forza il sistema con un account a 
privilegio più elevato, non assume la mia identità!!!
Purtroppo in tema di sicurezza e responsabilità mi sa che ci sono in 
giro parecchie favole e in pochi conoscono il tema a fondo.

 colabrodo.
I sistemi che hanno a che fare con la sicurezza, di solito, non ha
"password in memoria", ma memorizzano hash delle password.


Si, perņ se la tua app chiede la pwd all'utente, ce l'avrą in memoria da 
qualche parte...

 privilegio più elevato, non assume la mia identità!!!
A meno di definire che si intenda per "assumere l'identità". Nel senso
più stretto significherebbe che l'autorità non può utilizzare il tuo
username *e* la tua password, ma credo che possa benissimo forzare
l'annullamento della password ed accedere ugualmente.

 Ok, COM è bacata perchè nel modo è risaputo da molti...
E' bacata perché è bacata. *Poi* sono in molti a saperlo, ma questo
non è una conseguenza del fatto originale.


Ok.
--
GM

 
Esatto! Ma a questo punto esiste traccia del reset della mia pwd da 
parte dell'admin, quindi è chiaro che da quel momento è admin che accede 
al sistema, non io.
--
GM

 qualche parte...
Non riesco a capirti, la pwd viene trasformata in un digest e solo
dopo viene confrontato il digest, non la pwd originale.
Qual è il problema a cui ti riferisci? intendi che all'atto di
richiedere una password, questa viene memorizzata (ed è quindi qui il
problema?) per _poi_ essere trasmessa come digest? Sii più chiaro. In
un qualsiasi sistema, all'atto iniziale di inserire una password, non
viene forse essa memorizzata, comunque, da qualche parte?
Faccio queste domande per curiosità...
p.s.: stiamo lentamente scivolando off topic rispetto al problema
iniziale proposto da Nicolae  che mi piaceva sicuramente di più, forse
è bene cambiare il subject e fare un fork del thread.

 
Se ti preoccupi di questo allora i dati te li devi criptare.
Anche su Windows un super utente può avere accesso a tutti i dati dei 
vari utenti.
Comunque sbagli nel dire "qualcuno dal CED".
Non è "qualcuno", è l'amministratore del sistema che si suppone sia 
persona fidata.
Saluti  Manlio Perillo

 giro parecchie favole e in pochi conoscono il tema a fondo.
Io sono più propenso a credere che sia chi fa le leggi a non avere le 
conoscenze corrette.
Come ho già scritto, sei sei super utente *puoi* assumere l'identità di 
qualsiasi altro utente.
E' per questo che se non ti fidi del sistema e di chi lo amministra, 
aggiungi livelli di sicurezza ulteriori.
Saluti  Manlio Perillo

 
Questo andrebbe anche bene, ma il meccansmo di autenticazione dovrebbe 
essere "robusto" e non lasciato alla singola applicazione. In questo 
caso preferisco l'approccio centralizzato: 1 sola richiesta di password 
al login (o allo sblocco della console) e le varie applicazioni 
configurate in modo opportuno.
--
GM

 varie applicazioni configurate in modo opportuno.
E se un'applicazione non necessita dell'intervento umano cosa fai?
Tipico caso del demone o servizio che si voglia. Da qualche parte deve 
finire la password. Che ci sia l'aiuto o meno del sistema operativo, 
qualcuno deve dire al demone chi è.
-- 
mai più senza: 
http://www.genux.com/scheda.asp?idprod=47974

 
OT alla grande!!!!
  anzi ormai non ce la faccio quasi più: non sono abituato a flamare e 
non ho più molto tempo. Per me possiamo davvero chiudere qui...

 
Su win c'è un utente system o network a seconda dei privilegi necessari. 
Ma in ogni caso anche usando un utente normale il demone (o servizio) 
gira con un utente determinato ed è sempre il SO che ne gestisce la 
password.
Su unix non so.
--
GM


Spiego meglio:
quando vuoi installare un servizio (se ne hai il diritto) specifichi 
sotto quale identità utente girerà.
--
GM

 memorizzare un hash SHA-1
Ovviamente possedendo l'hash ti si possono aprire le porte del 
paradiso.
Se il server è sulla macchina A, e il client sulla macchina B, che cosa 
manda il client? Qualsiasi cosa mandi lo può mandare anche anche un 
client cattivo. Ci vuole un sistema a domanda riposta che usa la 
password per criptare la risposta.


 Su win c'è un utente system o network a seconda dei privilegi necessari.
Che sono pochini. E' vero che il sistema degli utenti del sistema 
operativo permette di NON delegare il problema delle password 
all'applicativo, però esiste anche il mondo reale. Nel mondo reale è 
normale avere più utenti per un Http Server, un DB Server e così via. 
L'utente associato ad un demone/servizio è necessariamente uno solo. 
Nel mondo reale come gestisci la cosa? E questà è una problematica su 
cui mi scontro da tantissimi anni.
Scrivere le password su un file di configurazione e avere il computer 
accessibile solo all'amministratore ha il suo perché. Almeno io faccio 
così. Io da decenni scrivo applicazioni che non necessitano 
dell'interazione utente, mentre esse devono interagire con i più 
svariegati "servernti".
In realtà non faccio così e le protezioni sono a livello di firewall, 
ma non vorrei parlare troppo del mondo reale. Era giusto per dire che 
metodi perfettamente funzionanti in laboratorio, possono essere 
irrealizzabili nella realtà (a meno di non torturare il cliente per 
renderlo compatibile con le nostre soluzioni).


 
Su sistemi UNIX il demone viene eseguito da init con privilegi di root, e 
poi abbandona tali privilegi per assumere quelli di un utente limitato.
Tale utente limitato, poi, di solito non ha password (o shell di login).
Saluti  Manlio Perillo

 parecchie favole e in pochi conoscono il tema a fondo.
Forse stiamo parlando di due cose diverse. Parliamo d'identificazione o 
d'accesso?
Se parliamo di database, una web application (scelgo quest'esempio per 
invalidare buona parte delle policy di autenticazione "locali") non fa 
l'autenticazione di te sul database, ma identifica te e usa un suo account 
per l'accesso al database.
Se poi ci siamo spostati in generale dall'autenticazione sul DB, verso i 
sistemi di identificazione in genere, suggerisco un cambiamento di topic, 
un'aggiunta di [OT] e continuiamo pure parlando di biometria, su cui mi 
troverai completamente d'accordo su quanto hai citato (con la possibilita' 
di aggiungere anche altro).
--
Marco Foco 

Qualsiasi cosa mandi lo può mandare anche anche un client cattivo.
Ovvio. E' per questo che in un mio messaggio precedente dicevo che
questo meccanismo risolve solo il problema di memorizzare la password
in chiaro.

 poi abbandona tali privilegi per assumere quelli di un utente limitato.
Qui ho una ignoranza bestiale che mi piacerebbe colmare. Di solito 
sotto unix (che nel mio caso è al 99.9999 % un linux) un demone è 
semplicemente un processo in cui faccio una fork e in cui poi il padre 
termina. A questo punto il demone figlio che diritti ha? Di init? 
Oppure sono quelli dell'utente che ha lanciato il processo padre?


 in chiaro.
Devo dire che le password in chiaro sono molto comode :-)
Comunque in generale il problema della sicurezza è complesso, e non 
conosco soluzioni facili.
Nel caso della mia ditta poi la diffusione delle macchine virtuali sono 
un nuovo e bel problema. E' possibili bypassare nel nostre (basse) 
protezioni in modo ridicolmente facile oggi. Anche quelle altrui devo 
dire. Chiavette USB criptate a parte.


 parametri aggiuntivi, complicando ulteriormente le cose.
In realta', sia che si tratti di esprimere tutti i parametri, sia che
si tratti di esprimere solo quelli diversi dalla terna db/user/pw,
questo problema si riduce a come rappresentare un insieme di coppie
nome/valore.
Direi che esistono due famiglie di alternative: la prima e' la
codifica in una stringa, la seconda in una struttura dati.
Nel primo caso, come dicevo, e' possibile utilizzare le stringhe di
connessione previste da ciascun DBMS. E' vero che questo richiede di
sapere come queste sono codificate, ma e' altrettanto vero che chi
utilizza un particolare DBMS questo lo sa o e' in grado di recuperare
facilmente l'informazione.
In alternativa e' possibile usare una codifica diversa, come quella
suggerita da Peter Dimov sulla mailing list di Boost, ovvero gli URL.
Questa e' anche la tecnica utilizzata da SQLAlchemy, una libreria
Python. Questa e' certamente una sintassi familiare, ma richiede una
codifica ad hoc per tutti i parametri che esulano da
<dbms>://<utente>:<password>@<host>:<port>/<database>
Il secondo caso invece e' l'utilizzo di una qualche struttura dati
nella quale raccogliere le coppie nome/valore. L'approccio piu' ovvio
da un certo punto di vista e' usare una map:
typedef std::map<std::string,std::string> arg_map;
arg_map am;
am["username"] = nmusatti;
am["password"] = password1;
conn.connect(am);
dove connection::connect e' presumibilmente dichiarata come:
void connection::connect(std::map<std::string,std::string> const &
arg_map);
Il problema pero' e' il contesto, almeno ideale, della libreria. Una
simile interfaccia probabilmente non piacerebbe ne agli sviluppatori
Boost, ne ai membri del comitato di standardizzazione, due comunita'
per altro con una notevole sovrapposizione. Mi aspetto invece che
venga controproposta la seguente alternativa:
template <typename IteratorT>
void connection::connect(IteratorT first, IteratorT last);
dove dereferenziando un IteratorT si ottiene un std::pair<std::string,
std::string>. Io pero' non vorrei usare un template in questo
contesto, perche' puo' creare delle dipendenze sgradevoli tra
l'applicazione client e i meccanismi interni della libreria.
Questo stesso ragionamento tra l'altro rende impraticabile
l'implementazione di una classe ad hoc per rappresentare i parametri,
scelta che per altro non mi convince.
Ciao,
Nicola

 un'aggiunta di [OT] e continuiamo pure parlando di biometria
E se ti taglio una mano e ti cavo un'occhio? Mi ricordo una vecchissima 
puntata di Simon Templar con Roger Moore in cui usavano questo trucco 
per impossessarsi di credo un missile nucleare.


 [...]
Il caso che facevo era quello in cui i diversi processi vengono avviati da
init all'avvio della macchina, quindi senza intervento umano.
Saluti  Manlio Perillo

 Oppure sono quelli dell'utente che ha lanciato il processo padre?
Se non ricordo male init esegue la fork, nel processo figlio assume la
effective userid indicata a livello di configurazione e quindi esegue
l'exec dell'eseguibile indicato.
Ciao,
Nicola

 per impossessarsi di credo un missile nucleare.
Ma non fanno qualcosa di simile anche in "Mai dire mai", con Sean
Connery?
Ciao,
Nicola

 
a mio avviso l'autenticazione dell'utente sul sistema non centra niente
con un eventuale autenticazione ad un database. Questo sistema può
portare solo ad un incremento degli utenti di sistema e ciò è male,
bisogna anche tenere in conto che spesso il db si trova su un altra
macchina e quindi si perde questo tipo di autenticazione. Pensa anche
che se uno ha la tua passwd di accesso al sistema può automaticamente
accedere anche a tutti i database su cui se abilitato, mentre con un
sistema di autenticazione "classico" i db li salvi
Ciao
-- 
Andrea Corradi | Debian User | 
www.debian.org
Fingerprint: A41E F6B0 DBDB F04C 4940 E411 30F3 CD62 57B1 8458
gpg --keyserver 
keyserver.linux.it
 --recv-key 57B18458
Please avoid sending me Word or PowerPoint attachments.
http://www.gnu.org/philosophy/no-word-attachments.html

 accede al sistema, non io.
il superuser può cancellare anche i log quindi non è detto che possa
rimanerne traccia


 effective userid indicata a livello di configurazione
Circa uguale a Windows.
Il problema maggiore di windows è che gestire i token di sicurezza a 
livello di S.O. è terribilmente complicato, quindi non lo fa nessuno. 
Per certi versi è un peccato perché la granularità di privilegi che si 
può affibbiare ad un processo è impressionante.
Oggi con i servizi di directory è il tutto è ancora più complicato.


 Connery?
Sai che hai ragione tu?
Confondevo il vangelo secondo Bond con quello secondo Simon Templar :-)


 l'applicazione client e i meccanismi interni della libreria.
Puoi chiarire meglio questo punto?

 Puoi chiarire meglio questo punto?
Certamente. Eliminando i dettagli irrilevanti ho qualcosa come:
class connection {
  public:
    template <typename IteratorT>
    void connect(IteratorT first, IteratorT last);
  private:
    boost::scoped_ptr<connection_base> conn;
};
connection_base e' una classe base astratta che mi permette di
"nascondere" i dettagli relativi al backend corrente, salvo che
essendo connect() un template devo implementarlo nello header e far
vedere la definizione di connection_base.
template <typename IteratorT>
void connect(IteratorT first, IteratorT last) {
  conn->connect(first, last);
}
Perche' questo funzioni connection_base::connect() deve anch'esso
essere un template e quindi non puo' essere virtuale e ci ritroviamo
nel pasticcio che abbiamo discusso un po' di tempo fa, con la
differenza che non conosco a priori i tipi validi per il parametro del
template IteratorT, anzi sono potenzialmente infiniti.
Le alternative sono copiarsi in una mappa il contenuto del range e
passare quella alla chiamata interna oppure imporre l'uso di iteratori
indiretti, che nascondano il tipo effettivamente passato e permettano
di eliminare il template.
Alla fine della fiera quest'ultima e' forse l'ipotesi meno peggio, ma
l'idea della stringa acquista un certo fascino :-)
Ciao,
Nicola

 l'idea della stringa acquista un certo fascino :-)
Dunque, non so bene dove agganciarmi per dire la mia. :)
Ieri stavo cercando scrivere qualcosa nei pochi minuti liberi, ma mi accorgo
ora che l'evoluzione della discussione ha reso superflui gran parte dei
miei commenti.
Ricopio quello che avevo scritto.
---
Nel affrontare un problema analogo (anzi, identico, direi) avevo scelto di
passare alla 'connect' un oggetto che modellasse una mappa parametro/valore.
Il significato effettivo dei parametri sarebbe stato deciso all'interno
delle possibili implementazioni soggiacenti. 
(Non mi piaceva avere un'interfaccia che prevedesse espressamente la triade
tns/username/password, poiché dietro all'interfaccia avrebbe potuto esserci
anche un database che non prevedeva alcun tipo autenticazione, o consentiva
autenticazioni esotiche.) 
In ogni caso, siccome le credenziali per la connessione dovevano essere
ricavabili da un file di configurazione, ho dovuto definire una sintassi
per tradurre la mappa dei parametri in una forma leggibile e scrivibile da
un umano, ma non volevo che questa sintassi entrasse in gioco nella
chiamata alla 'connect'.
Inoltre, la 'connect' non riceveva un oggetto concreto, ma un riferimento a
una classe base astratta che esponeva un'interfaccia per accedere ai valori
dei parametri. Di questa classe base avevo poi fatto una particolare
implementazione che memorizzava le coppie parametro/valore in un certo modo
(std::map) e sapeva (de)serializzarsi usando la sintassi che avevo scelto.
Questo mi avrebbe consentito di cambiare l'implementazione della mappa e la
sua rappresentazione testuale senza toccare la 'connect' né le
implementazioni sottostanti. 
La stessa classe base, poi, serviva anche per specificare il tipo di
database e indirettamente selezionare l'implementazione, che nelle mie
intenzioni avrebbe dovuto essere caricabile anche a runtime tramite dlopen
o equivalenti. (Ma questa è un'altra storia.)
--
My 2 eurocents.
Max

 deve e inoltre vengono passati tra diversi sistemi.
*Era*. E` corretto da 5 mesi. A parte questo, non ci sono commenti  a
riguardo di cosa comporti rimuovere le password dalla memoria. La
password ora viene "rimossa" nel senso che viene sovrascritta da "x"
dopo essere stata usata (e quindi non esiste più in memoria) ma
comunque potrebbe essere in swap o in una miriade di oggetti intermedi
di Python usati nel programma. No, decisamente un linguaggio di
scripting non è il massimo in sicurezza. L'unica alternativa seria è
rendere la RAM dove leggiamo la password dalla tastiera non swap-abile
e cancellarla subito dopo. Ma anche così un semplice modulo del
kernel... :)
federico

 federico
Saluti  Manlio Perillo

 un pool di connessioni.
Il pool di connessioni non è un problema di psycopg ma, in generale,
ovviamente non è possibile gestire logiche di pool senza tenere la
password in memoria, cercare di far si che quella memoria non possa
finire in swap e incrociare le dita per il resto.
federico

 Oppure sono quelli dell'utente che ha lanciato il processo padre?
Alcune delle risposte sono contenute nel papello soprastante. Ovvero
quando fai una fork, il figlio ha gli *stessi* previlegi del padre. Un
processo spawnato da init ha pertanto i permessi di root e tipicamente
una delle prime cose che fa è abbassarsi i poteri (tipicamente è una
cosa che funziona in un senso ma non nell'altro, uid 0 può diventare
utente non privilegiato, ma il contrario non è in generale possibile).
Ora veniamo al modo canonico per lanciare un demone.
1. chiami umask(0); [ per maggiori info su umask, non è difficile, solo
non troppo importante ]
2. ottieni il numero massimo di descrittori di file possibile per quella
piattaforma (tipicamente usi la syscall getrlimit) e te lo salvi da
qualche parte.
3. forki una prima volta e dici al padre di terminare.
4. fai in modo che successivi aperture *non* allochino controlling TTYs.
Ora si usa tipicamente la chiamata sigaction per settare vari segnali da
ignorare, una volta si usava signal sui vari segnali per fare la stessa
cosa. Il succo è sostanzialmente rendersi immuni dalla morte del process
group leader.
5. forki nuovamente
6. chiudi tutti i descrittori di file (e lo fai precisamente ciclando da
0 al valore che hai preso al punto 2).  Resetti errno a 0 che di certo
si è preso qualche EBADF (dopotutto stai chiudendo un sacco di file che
non sono aperti :) )
7. cambi working directory. tipicamente la setti a "/" o "/tmp".
Qualcosa che comunque non 'blocchi' una data cartella in caso che uno
volesse smontare il volume in cui è presente
8. colleghi eventualmente stdin, stdout e stderr a /dev/null
9. inizializzi le facilities per usare syslog e analoghe
Gli ultimi due punti sono abbastanza opzionali. Potresti buttare stdout
e stderr a qualcosa di sensato, per dire. Comunque ci sono variazioni
sul tema di cui sopra, ma il succo è che ci sono *due* fork e che
bisogna 'distaccare' il figlio dalla morte del process group leader. 
Sigh, solo che adesso dovrei fare un altro mezzo papello sui process
group leaders. :(
-- 
blog:  
http://www.akropolix.net/rik0/blogs
 | Uccidete i filosofi,
site:  
http://www.akropolix.net/rik0/
      | tenetevi riso e
forum: 
http://www.akropolix.net/forum/
     | bacchette per voi.

 gran chè a livello di sicurezza.
E come potrebbe essere altrimenti? Root è in buona sostanza onnipotente.
Sono pochissime le cose che non può fare (che so, cambiare il flag che
indica ad una partizione di FreeBSD che quella partizione è append-only
senza riavviare).
Ma questa non è una falla di sicurezza. Sarebbe come dire che un sistema
non è sicuro perchè il system manager potrebbe impazzire.


 qui. Purtroppo il link suggerito non funziona più.
"demone" in senso lato è qualunque cosa gira in background. In senso più
stretto si assume che questo processo faccia un chdir sulla root, si
sganci dal tty di controllo e crei una nuova sessione, chiuda tutti gli
stream standard (sostituiti con /dev/null).
Luca
-- 
"Ricorda sempre che sei unico, esattamente come tutti gli altri".

 Ora veniamo al modo canonico per lanciare un demone.
Grazie mille. Tutto ciò è per me molto interessante (che bella cosa 
avere aperto un poco il news group).


 Grazie mille. 
Di nulla :)
Spero di non avere scritto scemenze (che tendono ad accumularsi nei post
lunghi). E mi rendo conto che la parte sul lancio del demone è fatta di
fretta e temo che sia poco comprensibile.


 fretta e temo che sia poco comprensibile.
Sai come funziona: non bisogna dare all'affamato il pesce, ma la rete 
per pescare. La storia dei descrittori da chiudere per esempio mi è 
risultata nuova, prima o poi vado a cercarmi il perché della cosa, 
visto che alla partenza di un programma mi risultava che al massimo 
dovrei avere 3 descrittore aperti, e diventare demone non alla partenza 
mi sembra una cosa più accademica che altro.


 partenza mi sembra una cosa piů accademica che altro.
rete per pescare:
1) man 3 daemon.  daemon(3) e' una funzione standard BSD che fa tutto
   quello che bisogna fare, nel giusto modo e nella giusta sequenza,
   per demonizzarsi.  e' anche presente nelle librerie di parecchie
   distribuzioni linux ed unix di discendenza system-v.
2) il libro di stevens, "advanced programmimg in the unix
   environment"; e' datato, ma e' un classico: e spiega uso e
   necessita' di ogni step, compresi i descrittori.
-- 
|   Maurizio Loreti -- 
ROT13:ybe...@cq.vasa.vg
   |  (@_
| Un. of Padova, Dept. of Physics, Padova, Italy |  //\
|     
http://www.pd.infn.it/~loreti/mlo.html
     |  V_/_

    necessita' di ogni step, compresi i descrittori.
Comunque esiste la II versione che è aggiornata mi pare al 2005 (io ho
datato network programming, e recente APUE).


    necessita' di ogni step, compresi i descrittori.
Eh, chiudere i descrittori. Ho imparato a farlo automaticamente la
prima volta che ho lavorato con i pipe, quand'erano ancora mono-
direzionali. Li' se non chiudevi i descrittori giusti non si muoveva
piu' niente...
In realta' posto per un altro motivo: sia tu che Enrico consigliate le
vecchie edizioni dei libri di Stevens. E' perche' le nuove sono
peggio? Certo sono curate da altri, visto che lui se n'e' andato anni
fa.
Ciao,
Nicola

 non è sicuro perchè il system manager potrebbe impazzire.
In realta' *e'* un buco di sicurezza, o meglio un punto di
vulnerabilita'. Per quel che ne so sui sistemi davvero sicuri i
privilegi di root sono spartiti su piu' ruoli, che si presumono
attribuiti a persone fisiche diverse.
Per contro non mi risulta che questo tipo di sistemi abbia una
particolare diffusione fuori dagli ambiti militari.
Ciao,
Nicola

 peggio?
non lo so :-)
visto che io _sono_ vecchio, ho comperato i libri di Stevens (oltre a
quello che ho citato, possiedo anche i due volumi di 'unix network
programming' ed i tre di 'tcp/ip illustrated') nelle "vecchie"
edizioni molto tempo fa; e non ho mai sentito la necessita' di
ricomprarli "nuovi"...


 Nicola
Saluti  Manlio Perillo

 fa.
Io ho comprato la vecchia versione di Network Programming. La ragione è
che è molto più portabile della nuova (che sono due volumoni immensi).
Quando mi scordo qualcosa di 'filosofico' ce lo trovo, mi mostra anche
parecchio codice e tutto.
Inoltre è un libro che si legge praticamente da pagina 1 fino alla fine.
Per leggermi da cima a fondo i due volumoni non avrei il tempo, per cui
non mi ci sono nemmeno messo.
Poi per gli aggiornamenti della API e simili i man funzionano
egregiamente.
Ho preso in mano anche i due libroni. Sono fatti bene, ricchi di
informazione e tutto. Ma li ho trovato 'troppi', in qualche modo un poco
dispersivi. 
Probabilmente se il mio lavoro principale fosse per l'appunto girare
attorno a POSIX a basso livello (che so, come fanno gli sviluppatori di
Twisted, che devono mantenere un bel polpettone cross-platform con
alcuni dettagli pesantemente implementation defined che debbono essere
schermati ai livelli superiori...) si, allora i due volumi credo che mi
farebbero comodo. Oppure che so... se dovessi lavorare pesantemente in
IPv6. Ad ogni modo, prima o poi li prenderò. 
A mano a mano che si va avanti il fatto che la prima edizione ha
qualcosa come 17 anni si farà sentire sempre di più.
Invece per Advanced Unix... ho comprato la nuova versione. Tratta
esplicitamente OS X e altri sistemi su cui mi capita di lavorare e la
uso come 'reference', visto che mi tiene aggiornato sulle mattane e
peculiarità delle varie piattaforme. Ma non è comunque un libro che ho
letto da copertina a copertina, anche se è perfettamente leggibile in
tal senso (mentre i due network programming hanno un sacco di API per
esempio di un sistema ma non di un altro, per cui in realtà sono fatti
per guardarsi le parti utili).
E comunque anche questo è un libro mastodontico. Ma appunto, non avevo
intenzione di leggerlo, ma di consultarlo alla bisogna. Sfortunatamente
non c'è verso, quando mi arrivano in mano certi tomi la lettura
dettagliata è impossibile. Idem per MacOS X System Internals. Mille e
passa pagine di roba.
Il dragonbook sono riuscito a spippolarmelo, principalmente perchè
c'erano capitoli che palesemente non mi interessavano e li ho saltati.
Allo stesso modo Cocoa Programming di Anguish lo ho letto (alla fine
tutto) ma a pezzi, mentre il libro di Hillegass lo ho divorato in meno
di una settimana.
Purtroppo non saprei consigliarti sulla vecchia che non ho letto.


 particolare diffusione fuori dagli ambiti militari.
No, in effetti no.
