Visualizzazione post con etichetta server. Mostra tutti i post
Visualizzazione post con etichetta server. Mostra tutti i post

3 dicembre 2013

ProFTPd

Dopo secoli torno a parlare di tecnologia e lo faccio nel modo più classico del mondo: sono inciampato in un argomento apparentemente banale, in realtà spinoso. Uscitone vittorioso, ne condivido il percorso, per la gioia di grandi e piccini.

Task: installare un server FTP su una macchina linux e configurarlo per degli accessi da utenti specifici.
Livello di banalità apparente: 10/10
Sbatti reale: 1000

La prima cosa è scegliere quale server installare. La macchina ha su Debian e la scelta si gioca principalmente fra ProFTPd, PureFTPd e vsftpd. Qui un breve confronto fra i tre concorrenti.
Per ragioni che non sto a sviscerare scelgo ProFTPd.

NOTA BENE: questa non è una guida alla configurazione sicura e ottimizzata del serer proFTPd e non intende esserlo, ma è solo una guida veloce a come risolvere dei problemi comuni senza perdere ore su internet e vagare per mille pagine di manuale, dando invece una visione organica e funzionale in pochi minuti.

L'installazione è banale come un semplice

apt-get install proftpd-basic

Un attimo e siamo online...e invece? E invece scegliendo per un server gestito da xined invece che standalone ci si butta in un piccolo delirio che non vale la pena di affrontare: le risorse occupate sono oggettivamente così poche che vale la pena tenerlo acceso e risparmiarsi lo sbatti.
Quindi, nella configurazione ( /etc/proftpd/proftpd.conf ) bisogna assicurarsi di avere la riga:

ServerType                      standalone

E con questo, magia, parte.
Primo accesso con un utente di sistema e tutto funziona. Ma come si arginano gli utenti a non andare in giro a curiosare per il mondo?
La cara vecchia impostazione dei permessi potrebbe pure essere una strada, ma non è praticabile, perchè significa precludere agli utenti locali di girovagare per il sistema. Quindi?
Quindi la risposta è in questa riga nel file di conf:

DefaultRoot ~

Ossia gli utenti si trovano ad avere la loro home ( ~, appunto, per chi non ha dimestichezza) come root, durante il loro accesso ftp. Da lì non si esce. Ci sono degli effetti collaterali, in questo, che sono ben spiegati in questa pagina sul chroot.

Per riavviare il server basta il solito:

/etc/init.d/proftpd restart

Fatto?
No, a meno che non vogliate creare un utente di sistema per ogni utente ftp, cosa che a volte va bene e a volte no.
Qui parte uno sbatti facile, ma lungo e articolato, se non ci avete mai avuto a che fare.

Step 1: abilitare l'autenticazione su un file alternativo

Nel file di conf deve essere aggiunta una riga come questa:

AuthOrder                       mod_auth_unix.c mod_auth_file.c

dove mod_auth_file.c indica che proFTPd può leggere i dati di autenticazione dell'utente in un file ad hoc separato da quello delle password di unix/linux. Qui si può leggere un approfondimento, che parla anche della questione del chroot discussa prima.
L'ordine conta e quindi prima il server usa mod_auth_unix.c (verifica fra gli utenti di sitema), poi in un file esterno.
Ma quale file?

Step 2: indicare il file alternativo di autenticazione

Semplice, si fa con questa riga:

AuthUserFile /etc/proftpd/vusers.conf

si indica dov'è il file in questione. Il path è arbitrario, come il nome file. Meglio scegliere un percorso fuori dal path raggiungibile/visibilie/modificabile dagli utenti. Nel mio caso l'ho messo nella stessa cartella del file principale di configurazione.
Il file deve essere esistente e leggibile, ma può anche essere vuoto.

Step 3: popolare il file per gli utenti virtuali

Un file di utenti vuoto serve a poco. Il modo più facile per popolarlo è usare il comando ftpasswd.
Per usarlo basta scrivere nella shall:

ftpasswd --passwd --file=/etc/proftpd/vusers.conf --name=myuser --uid=15000 --home=/path/to/home --shell=/bin/sh

Il comando chiede la password da assegnare al'utente e ne mette una hash nel file selezionato, alla riga dell'utente. Se l'utente esiste già propone di modificare la password, altrimenti appende una nuova riga per il nuovo utente al file.

Dove --file indica il path al file indicato nel file di cofigurazione di proFTPd, e --uid è un qualunque uid (user ID, per i neofitissimi), anche inventato. Si può specificare anche un group id che, se omesso, è di default uguale all'uid.

La home per l'utente non viene creata, quindi deve essere un path esistente (non necessariamente subito, ma al primo accesso). La shell ha usi speciali che non interessano adesso, ma deve essere una shell esistente, quindi /bin/sh è la scelta di comodo.

Se volete che l'utente entri con lo stesso utente con cui gira apache, quindi possa leggere e scrivere in una cartella da cui legge e scrive una web-app, basta indicare lo uid di quell'utente. Per esempio, su debian/ubuntu l'utente è www-data, nel fail /etc/passwd c'è una riga relativa all'utente www-data ad cui si può prendere lo uid assegnatogli.
Stessa cosa per qualunque altro utente, se volete evitare la configurazione di dettaglio dei permessi.

ATTENZIONE: non mettete un utente virtuale con la home in una cartella in cui può fare danni. Per girare intorno al problema create nella webapp un link alla home dell'utente. In questo modo la webapp accede con percorsi relativi alla cartella ftp, ma non viceversa.


The END!
A questo punto è tutto configurato, e basta un semplice riavvio del server per vedere tutto funzionare. Volendo si può riavviare già alla fine dello step 2, dal momento che il contenuto del file degli utenti è letto dinamicamente al login.

Note di sistema
Mentre tutto va beatamente liscio usando debian/ubuntu, centOS riserva, tanto per cambiare, le sue piccole e fastidiose sorprese.
Prima fra tutte, il pacchetto proftpd NON è disponibile di default con yum.
Per usarlo bisogna seguire questi semplici step (presi in prestito dai tutorial di Digital Ocean, visto che decine di alternative simili che si trovano online non funzionano e si rischia di perdere ore alla ricerca del repository giusto...e non imbarcatevi nel download degli rpm, perchè le dipendenze sono più forti di quelle di un tossico allo stadio terminale), che sono però duri da trovare online:


rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm

e magicamente ci appare il pacchetto...ora si può pacificamente fare:

yum install proftpd

Inutile dire che la struttura dei file di configurazione cambia, ma il senso no. Banalmente proftpd.conf non è più in /etc/proftpd ma direttamente in /etc. Fossero questi i problemi....


Enjoy ;)











Read more

9 giugno 2009

Console remota embeddable in python

Altro post di informatica pura, che del resto è il mio mondo molto più di quanto non lo sia la politica o la sociologia ;)

A parte le cazzate, il tema odierno è una facility che usai un tempo tramite twisted matrix, una grossa libreria che permette di rendere asincrono praticamente tutto, anche lo svegliarsi rispetto all'alzarsi dal letto, purche lo si faccia in python.

La facility in questione era l'esposizione di una console di python via rete. Sin qui è già una bella magia ma non stratosferica, più interessante il fatto che fosse anche integrata in un programma esistente (ed in esecuzione), dando quindi accesso, per i più svariati scopi, al programma medesimo, come se lo stessimo eseguendo dall'interactive console (IDLE, per intenderci) .

In rete ci sono pochissimi riferimenti a come ottenere il medesimo risultato senza portarsi dietro il tonno che è Twisted Matrix, per il quale non provo oltretutto grande simpatia.

C'è qualcuno che fa cose simili, ma o non le fa in rete ma con widget, o usa trucchi distruttivi sull'ambiente del programma rendendo impossibile l'integrazione in un contesto già esistente, o lo fa in modo così triviale che lo sforzo per renderlo funzionante in un contesto più generico supera il beneficio di avere già una base di partenza.

Mi è costato una giornata di prove assortite, ma alla fine sono arrivato a scrivere un pezzo convincente di codice, che come si vedrà, alla fine, è anche piuttosto ridotto, ma contiene dei barbatrucchi piuttosto importanti.

Come al solito, prima il codice poi i commenti! Eccolo:



I pezzi importanti sono due, il resto è solo un po' di fumo al contorn, ma lo vedremo.

Il pezzo chiave del tutto è il metodo mainloop della classe ipconsole.
Qui viene istanziato un interprete a cui vengono passate le stringhe lette dalla rete, qui si fa la lettura dalla rete e le varie interazioni con l'interprete medesimo.
Tutto sembrerebbe a posto, se non fosse che non c'è modo di redirigere l'output dell'interprete in questione senza gabbarlo. è qui che casca l'asino in quasi tutte le implementazioni che si trovano in giro.
Il modo logicamente più semplice di fregare l'interprete, e anche più pulito, sarebbe stato quello di eseguirlo in un ambiente modificato in cui il riferimento a sys fosse modificato (verso un clone di tutto il modulo sys e non un suo riferimento che non serve a nulla. In tale contesto diventa facile fare quello che si vuole di sys.stdout, sys.stderr ed eventualmente sys.stdin del sys clonato.
Se si riuscisse a ottenere questo clone, passarlo come contesto all'interprete sarebbe semplice, ma...peccato che non ci sia verso in Python di clonare un modulo (oddio, forse qualche modulo stupido sì, ma sys no). Che fare allora?
Si tarocca direttamente sys.stdout!
La soluzione è un po' invasiva e fa si che non sia completamente generica, ma almeno nei casi comuni (quelli che non manipolano sys.stdout e sys.stderr runtime e non si mettono a giocare coi reload di sys) è trasparente. Il trucco consiste nel creare una classe ponte che nasconda le 2 istanze stdout e stderr, incapsulandole.
Questa classe è appunto la mia fakeout.
fakeout manipola il metodo write, quello che, per questioni di interfacce, tutti gli stream writers devono esporre e stdout, che è un outputfile, non può esimersi da mettere a disposizione e viene usato anche da statement come "print".
Nel nuovo write, se il thread corrente non si è registrato, si passa la chiamata allo streamwriter originale (stdout o chi per lui), che è stato incapsulato durante la creazione dell'istanza di fakeout, se invece il thread corrente si è registrato, usando il metodo setout4thread, si usa il writer passato durante la registrazione.
In questo modo thread diversi possono registrarsi, ognuno usando come stdout taroccato un proprio writer.

Questa genialata mi è stata suggerita da una discussione su una newsletter (che mi sono salvato e potete leggere qui, perché è giusto che il merito vada a chi ha le idee) ed è la base della soluzione a tutti i problemi!

Beh, tutti si fa per dire, perché in realtà un problema rimane: la formattazione dell'output.
Il programma funziona correttamente con il telnet di Linux come client, ha dei problemi di formattazione con la raw connection di putty, nel senso che quando va a capo non torna a inizio linea, e non funziona con telnet di putty, che si ostina a mandare spazzatura ad inizio linea nonostante io provi a impostarlo diversamente, risultato netto: non interpreta nulla.
Credo comunque che siano problemi di configurazione del client e se qualcuno ha una idea di come arginarli o, ancora meglio, risolverli...ben venga!

Ah....quasi dimenticavo...per usare il tutto basta copiare il pezzo di codice di sopra in un file qualunque, chiamiamolo tcpconsole.py. A questo punto vi basta fare import tcpconsole dal vostro codice e poi una chiamata alla funzione tcpconsole.createServer passandole come parametro ip e porta su cui ascoltare.

Nulla di più semplice....sempre se il firewall di vista ve lo lascia fare....
Read more