Newsgroup: it.comp.lang.perl
Titolo: Problema con SFTP in ambiente Windows

Ciao a tutti.
Devo realizzare uno script in Perl, in ambiente Windows, che
trasfrerisca via SFTP un file su un server remoto.
Ho installato Active Perl ma non riesco a collegarmi in nessun modo al
server.
Sto utilizzando il modulo Net::SFTP::Foreign
my $sftp= Net::SFTP::Foreign->new($host, user=> $user, password=>$psw,
ssh_cmd => $remote_dir,  expect_log_user => 1 , more => '-v' );
La connessione non riesce e questo è l'errore:
password autentication is not avaible. IO:Pty and Expect ara not
installed
Ho provato ad installare IO:Pty e Expect  da MCPAN ma anche li ho un
errore: manca il CL.exe
Qualcuno puo darmi un suggerimento su come fare?
Posso in ambiente Windows con Active Perl realizzare questo Script?
grazie


Da quel che si legge nella documentazione, per usare password devi
installare Expect. Non so cosa sia il CL.exe, hai provato a cercare in
giro?
Se puoi fare a meno dell'autenticazione con la password, prova ad
utilizzare quella mediante chiavi pubblica/privata.
Altrimenti... cambia sistema operativo :D
Ciao,
   Flavio.

 errore: manca il CL.exe
Per installare moduli Perl con il Perl ActiveState di solito si usa ppm.
Scrivi ppm da prompt di dos oppure Start->Programmi->Activeste
blabla->perl package manager
Premi l'icona più a sinistra e poi puoi cercare i moduli che ti mancano.
IO::Pty lo trovi, e anche Bundle-Expect che è un modulo "virtuale" con
l'elenco di quello che serve ad Expect.
Però... però manca IO::Tty. Ovvero io non trovo alcun repository ppm
(ovvero un sito web dove qualcuno ha messo dei moduli Perl in formato
ppm, diciamo così) con IO::Tty.
Tu hai cercato di usare perl -MCPAN per installare i moduli su Windows,
metodo non ortodosso ma che giocoforza puoi tentare se non trovi quel
modulo nei repository ppm.
Per farlo hai bisogno di nmake e di visual c (quel cl.exe dell'errore).
Questo perché per compilare moduli che comprendono delle parti in C devi
usare lo stesso compilatore usato per compilare perl. E ActiveState ha
usato visual c.
Dunque potresti:
1) scaricare visual c express edition oppure comprare visual studio...
(nmake immagino sia compreso nel pacchetto).
2) riprovare con perl -MCPAN
oppure:
1) scaricare Strawberry Perl (
http://strawberryperl.com/
)
2) usare quel perl con i propri tool per installare i moduli (e dunque
credo si possa usare tranquillamente perl -MCPAN)
oppure
1) scaricare l'ambiente cygwin
2) usare il perl di cygwin (con il quale puoi usare perl -MCPAN).

 Posso in ambiente Windows con Active Perl realizzare questo Script?
Forse sì.
Su questo che è il repository ppm più fornito:
http://trouchelle.com/perl/ppmrepview.pl
come diceva Andrea IO::Tty non è al momento disponibile, e di 
conseguenza neanche Expect; comunque annotati il repository (e mettilo 
tra i repository del package manager di ActivePerl, che Andrea ti ha 
detto come lanciare), perché è da lì che vanno presi i moduli per 
ActivePerl, almeno quelli binari (a meno di non volersi veramente male).
Inoltre non trovo report di test superati sotto Windows per 
Net-SFTP-Foreign-1.46:
http://bbbike.radzeit.de/~slaven/cpantestersmatrix.cgi?dist=Net-SFTP-Foreign+1.46
Dunque questo escluderebbe la versione 1.46, però fortunatamente la 
versione 1.44 sembra passare in un paio di casi:
http://bbbike.radzeit.de/~slaven/cpantestersmatrix.cgi?dist=Net-SFTP-Foreign%201.44
http://trouchelle.com/perl/ppmrepview.pl?l=Net-SFTP
e infatti abbiamo anche il ppm (bingo! :-)
http://trouchelle.com/perl/ppmrepview.pl?l=Net-SFTP
Quindi in sostanza le strade possibili sono:
1. provi ad installare il ppm di Net-SFTP-Foreign-1.44;
2. oppure, se per te è praticabile, ripieghi su Net::SFTP, di cui pure 
abbiamo il ppm (per Perl 5.8), come si vede dal link precedente;
3. o ancora, come estrema ratio, utilizzi Cygwin e la sua distribuzione 
Perl, dove funziona tutto (incluso Net-SFTP-Foreign-1.46):
http://cygwin.com/
 (come del resto già detto da Andrea);
4. la strada suggerita da Flavio ;-)
Ciao e buona fortuna.

 Ciao e buona fortuna.
Grazie ragazzi!
Proverò a fare come mi avete suggerito e poi riporterò qui i
risultati.
Approfitto per chiedere un'altra spiegazione... ma un Bundle come
funziona?
Mentre un modulo lo dichiaro nel codice con
use nome::modulo;
come si fa a utilizzare il bundle?
grazie ancora

 grazie ancora
Di nulla!

Ho provato ad utilizzare Net-SFTP-Foreign-1.44 ma anche in questo caso
sono richiesti i moduli IO::Tty etc.. che non ci sono. Quindi ho
rimosso  Active perl e installato Strawberry Perl ...
Con Net-SFTP-Foreign uguale problema che avevo con active perl...
richiede Expect e IO::Pty che non riesco ad installare
ecco un estratto del report...
*************************************************************************************
"CPAN.pm: Going to build R/RG/RGIERSIG/Expect-1.21.tar.gz
Checking if your kit is complete...
Looks good
Warning: prerequisite IO::Pty 1.03 not found.
Warning: prerequisite IO::Tty 1.03 not found.
Writing Makefile for Expect
---- Unsatisfied dependencies detected during ----
----        RGIERSIG/Expect-1.21.tar.gz       ----
    IO::Pty [requires]
    IO::Tty [requires]
Prepending C:\strawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/
arch C:\st
rawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/lib to PERL5LIB
for 'test'
Running make test
  Delayed until after prerequisites
Running make install
  Delayed until after prerequisites
Running install for module 'IO::Pty'
Running make for R/RG/RGIERSIG/IO-Tty-1.07.tar.gz
Prepending C:\strawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/
arch C:\st
rawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/lib to PERL5LIB
for 'get'
Prepending C:\strawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/
arch C:\st
rawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/lib to PERL5LIB
for 'make'
  CPAN.pm: Going to build R/RG/RGIERSIG/IO-Tty-1.07.tar.gz
Now let's see what we can find out about your system
(logfiles of failing tests are available in the conf/ dir)...
Looking for _getpty()...... not found.
Looking for getpt()........ not found.
Looking for grantpt()...... not found.
Looking for openpty()...... not found.
Looking for ptsname()...... not found.
Looking for ptsname_r().... not found.
Looking for sigaction().... not found.
Looking for strlcpy()...... not found.
Looking for ttyname()...... not found.
Looking for unlockpt()..... not found.
Looking for libutil.h...... not found.
Looking for pty.h.......... not found.
Looking for sys/pty.h...... not found.
Looking for sys/ptyio.h.... not found.
Looking for sys/stropts.h.. not found.
Looking for termio.h....... not found.
Looking for termios.h...... not found.
Looking for util.h......... not found.
Checking which symbols compile OK...
(sorry for the tedious check, but some systems have not too clean
 header files, to say the least;  '+' means OK, '-' means not defined
 and '*' has compile problems...)    "
...dopo un test molto lungo.....
"  CPAN.pm: Going to build R/RG/RGIERSIG/Expect-1.21.tar.gz
Warning: Prerequisite 'IO::Pty => 1.03' for 'RGIERSIG/
Expect-1.21.tar.gz' failed
 when processing 'RGIERSIG/IO-Tty-1.07.tar.gz' with 'make => NO'.
Continuing, bu
t chances to succeed are limited.
Warning: Prerequisite 'IO::Tty => 1.03' for 'RGIERSIG/
Expect-1.21.tar.gz' failed
 when processing 'RGIERSIG/IO-Tty-1.07.tar.gz' with 'make => NO'.
Continuing, bu
t chances to succeed are limited.
cp Expect.pm blib\lib\Expect.pm
cp Expect.pod blib\lib\Expect.pod
  RGIERSIG/Expect-1.21.tar.gz
  C:\strawberry\c\bin\dmake.EXE -- OK
Prepending C:\strawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/
arch C:\st
rawberry\cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/lib to PERL5LIB
for 'test'
Running make test
C:\strawberry\perl\bin\perl.exe "-Iblib\lib" "-Iblib\arch" 
test.pl
1..42
Can't locate IO/Pty.pm in @INC (@INC contains: blib\lib blib\arch C:
\strawberry\
cpan\build\Net-SFTP-Foreign-1.46-DqG2Nx/blib/arch C:\strawberry\cpan
\build\Net-S
FTP-Foreign-1.46-DqG2Nx/blib/lib C:/strawberry/perl/lib C:/strawberry/
perl/site/
lib .) at blib\lib/Expect.pm line 22.
BEGIN failed--compilation aborted at blib\lib/Expect.pm line 22.
Compilation failed in require at 
test.pl
 line 27.
BEGIN failed--compilation aborted at 
test.pl
 line 27.
dmake.EXE:  Error code 130, while making 'test_dynamic'
  RGIERSIG/Expect-1.21.tar.gz
  C:\strawberry\c\bin\dmake.EXE test -- NOT OK
//hint// to see the cpan-testers results for installing this module,
try:
  reports RGIERSIG/Expect-1.21.tar.gz
Running make install
  make test had returned bad status, won't install without force
Failed during this command:
 RGIERSIG/IO-Tty-1.07.tar.gz                  : make NO
 RGIERSIG/Expect-1.21.tar.gz                  : make_test NO"
fine delle trasmissioni...................
Ho provato a installare allora il modulo Net::SFTP
cerca di installare di tutto... a partire dal modulo SSH....
alla fine dopo una marea di moduli e domande... va in errore e non
installa nemmeno questo...

 rimosso  Active perl e installato Strawberry Perl ...
Purtroppo la rimozione di ActivePerl č stata forse prematura, perché era 
il caso di provare prima il ppm di Net::SFTP.
Strawberry č promettente, ma per adesso la strada ActivePerl + ppm č 
ancora la piů comoda sotto Windows, di gran lunga.
(Alle brutte, rimane anche Cygwin eh ;-) Lě posso garantirti che 
funziona, Expect compreso.

 il caso di provare prima il ppm di Net::SFTP.
Buona notizia: Net::SFTP sfrutta Net::SSH::Perl, che *non* usa Expect 
per l'utenticazione via password.
Pertanto potrebbe andare anche con password (o perlomeno non c'è il 
problema dell'indisponibilità di Expect).

 sono richiesti i moduli IO::Tty etc..
Ancora un'altra possibile strada per usare Net::SFTP::Foreign (anche la 
1.46) con tanto di password authentication: ti autentichi con 
Net::SSH::W32Perl (disponibile anche come ppm) e poi passi il socket 
all'opzione "transport" del costruttore di Net::SFTP::Foreign, 
grossomodo così (scritto al volo e non testato!):
--------------------------------------------------
use Net::SSH::W32Perl;
use Net::SFTP::Foreign;
my $host = '
foo.bar.com
';
my $ssh = Net::SSH::W32Perl->new( $host, [options] );
$ssh->login('user', 'password');
my $sftp = Net::SFTP::Foreign->new(
     transport => $ssh->sock
)
--------------------------------------------------
Con Perl, ce ne vuole prima di arrendersi ;-)

> Con Perl, ce ne vuole prima di arrendersi ;-)
:) :)
guarda sei un grande anche se non dovesse funzionare...
ora provo in questo modo ti faccio sapere! ;)

> ora provo in questo modo ti faccio sapere! ;)
rieccomi qua...
ho fatto cosi:
----------------------------------------------------
use Net::SFTP::Foreign;
use Net::SSH::W32Perl;
my $host = "xxx.xx.xx.xxxxx";
my $user ="xxxxxxxxx";
my $psw ="xxxxxxxxx";
my $remote_dir = "xxxxxxxxxxx";
my $ssh = new Net::SSH::W32Perl($host);
$ssh->login($user, $psw);
my ($out, $err, $exit) = $ssh->cmd('cat', 'Hello Net::SSH::W32Perl
User!');
--------------------------------------------------------
il risultato è un tremendo:
the getpwuid function is unimplemented at D:/perl/site/lib/Net/SSH/
Perl.pm line 110
:o|

Dopo una ricerca sul web sono arrivato alla conclusione che questa
funzione getpwuid  non è implementata in ambiente Win...

Ciao...
ho provato a cambiare modulo per trasferire il mio file e ho ripiegato
su Net::ssh2
sono riuscito finalmente a connettermi e autenticarmi, anche ad
ottenere una dir del server... MA non sono stato in grado di
trasferire il file dalla mia macchina al server.
Ho utilizzato scp_put ma la riga dove invoco questo metodo mi
restituisce un errore non specificato...
se qualcuno mi sa dire perche gli sarei grato.
questo il codice:
=========================================
#!/usr/bin/perl
use warnings;
use NET::SSH2;
my ($len, $buf);
my $ssh2 = Net::SSH2->new();
#$ssh2->debug(1);
if ($ssh2->connect($host)) {
if ($ssh2->auth_password($user,$pass)) {
# MOSTRA LA DIR
my $sftp = $ssh2->sftp();
my $dir1 = '/';
my $dh = $sftp->opendir($dir1);
while(my $item = $dh->read) {
    print $item->{'name'},"\n";
};
# PROVO A PUBBLICARE IL MIO FILE
my $dir = '/';
my $remote = "$dir";
my $file = 'arrivi.xml';
my $ssh3 = Net::SSH2->new();
$ssh3->scp_put('d:/perl/arrivi.txt', './') or die " --- errore: $!";
} else {
warn "auth failed.\n";
}
} else {
warn "Unable to connect Host $@ \n";
}
===================================================
buona serata

ho trascritto un . in piu in questa riga che ripropongo:
$ssh3->scp_put('d:/perl/arrivi.txt', '/') or die " --- errore: $!";


$ssh3 non ha mai effettuato l'autenticazione, o sbaglio?

> $ssh3 non ha mai effettuato l'autenticazione, o sbaglio?
ho provato aggiungendo questo:
my $ssh3 = Net::SSH2->new();
	if ($ssh3->connect($host)) {
		if ($ssh3->auth_password($user,$pass)) {
			print "\n - Connesso con SSH3 \n";
			$ssh3->scp_put('d:/perl/arrivi.txt', '/') or die " --- errore: $!";
		};
	};
mi stampa la riga " Connesso con SSH3" ma poi rimane cosi ... senza
dare errori.
Per uscire devo interrompere io tramite ctrl/c
booo


Non conosco il funzionamento interno di scp_put, ma l'ho usato con
successo, il che mi porta a pensare che forse stai dando per scontate
troppe cose. La cosa più lampante è che nel parametro "remote"
specifichi una directory anziché un nome di file; inoltre, al posto
tuo inizierei con un file nella directory corrente, senza impostare il
path completo (non so come libssh2 si comporti riguardo alle barrette,
ad esempio).
Buona fortuna,
   Flavio.

 funzione getpwuid  non è implementata in ambiente Win...
Difatti non serve.
Per evitare quell'errore, basta settare la variabile d'ambiente HOME
(non è che non te l'abbia detto per sadismo, è solo che non ne avevo
idea: era nascosto nel codice di Net::SSH::Perl::SSH2).
Lo snippet diventa quindi:
--------------------------------------
use Net::SSH::W32Perl;
use Net::SFTP::Foreign;
$ENV{HOME} = 'C:\Users\Pippo';
my $host = '192.168.0.1';
my $ssh = Net::SSH::W32Perl->new( $host, protocol=>2, debug=>1 );
$ssh->login('pippo', 'pippopasswd');
-------------------------
E fin qui funziona, ti logghi tranquillamente.
Quello che invece purtroppo non funziona è:
my $sftp = Net::SFTP::Foreign->new(
     transport => $ssh->sock
)
Quindi è senz'altro opportuno provare altre strade come NET::SSH2 (e
seguire i suggerimenti di Flavio).

avevo intuito che la strada Net::SSH::W32Perl; Net::SFTP::Foreign; non
era praticabile. Purtroppo...
Grazie Emanuele.
Flavio,
ho provato ad indicare solo il nome del file da trasferire, eliminando
il percorso,  e mettendolo nella stessa cartella del file perl... ma
anche cosi non cambia nulla
Ho letto che il parametro "remote" serve ad indicare il percorso
quindi la cartella dove verra salvato il file sul server remoto...
perchè mi dici di indicare un nome di file?


Beh, perché nell'esempio che avevo fatto in Linux funziona :) Tentare
non nuoce. Un esempio che ho provato e funziona sotto Linux è il
seguente (con le ovvie modifiche per server, username e password):
#!/usr/bin/perl
use strict;
use warnings;
use Perl6::Say qw( say );
use IO::Prompt qw( prompt );
chomp(my $utente   = prompt 'nome utente: ');
chomp(my $password = prompt 'password: ', -e => '*');
$utente = "$utente" || undef;
$password = "$password" || undef;
my $host = 'localhost';
use Net::SSH2;
use Fcntl;
my $ssh2 = Net::SSH2->new();
$ssh2->connect($host)
   or die "impossibile connettersi";
$ssh2->auth(username => $utente, password => $password)
   or die "autenticazione fallita";
# Scarica un file
$ssh2->scp_get('/etc/passwd', 'loro-passwd');
# Invia un file
$ssh2->scp_put('loro-passwd', '/tmp/vostro-passwd');
# Usa interfaccia stile SFTP
my $sftp = $ssh2->sftp();
# Scarica un file
my $fh = $sftp->open('/etc/passwd')
   or die 'SFTP open: errore';
print while <$fh>;
# Salva un file in remoto
my $fh2 = $sftp->open('/tmp/motd', O_WRONLY | O_CREAT)
   or die 'SFTP open in scrittura: errore';
print {$fh2} "All your base are belong to us!\n";

 era praticabile. Purtroppo...
Mai dire mai!
Così funziona, per giunta con il solo Net::SFTP::Foreign :-)
Passi preliminari:
1.
Se già non ce l'hai, scarica e installa PuTTY, incluso Plink:
http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
2.
Collegati con putty al tuo server via ssh, poi salva la sessione 
dandogli un nome, ad esempio "pippo_at_myserver" (nella sessione vengono 
salvati l'indirizzo dell'host, la porta, il protocollo ecc. ma *non* i 
dati di account).
OK, chiudi putty, non ti servirà più (è servito unicamente per salvare 
la sessione).
Ciò fatto, in questo modo Net::SFTP::Foreign funzionerà alla perfezione, 
tramite plink (testato su Vista + ActivePerl 5.8.9.825):
-------------------------------------------------------------------
use strict;
use warnings;
use Net::SFTP::Foreign;
my $sftp = Net::SFTP::Foreign->new(
     '', ssh_cmd => 'plink', more => [
         -load => 'pippo_at_myserver', # Sessione salvata con putty.
         -l    => 'pippo',             # Username utente.
         -pw   => 'pippo_passwd'       # Password utente.
     ]
);
$sftp->error and die 'Errore di collegamento: ' . $sftp->error;
### Opzionale      ###
# lista il contenuto della home di pippo
my $ls = $sftp->ls( '/home/pippo' )
     or die 'Impossibile listare la directory: ' . $sftp->error;
print "$_->{filename}\n" for (@$ls);
# Probabilmente non ti serve...
$sftp->setcwd( '/home/pippo' )
     or die "Impossibile cambiare directory di lavoro: " . $sftp->error;
### Fine Opzionale ###
# Scrivi il file nella home di pippo
$sftp->put( 'test.txt', 'test.txt' )
     or die "Errore scrittura file remoto: " . $sftp->error;
-------------------------------------------------------------------
Se avessi problemi fammi sapere, che mica è finita qui (con Perl c'è 
sempre un altro modo ;-)
Ciao.

 Ciao.
MITICO!
il mio maledetto file è ora sul server! Funziona alla grande!
Emanuele sei 'NU MAST' del perl... come si dice dalle mie parti! ;)
Grazie ancora :)

 Emanuele sei 'NU MAST' del perl... come si dice dalle mie parti! ;)
Napoli? :-)
---
Un'ultima nota sull'approccio /Plink/.
Se ne potrebbe dedurre che, per usarlo, si sia costretti a crearsi prima 
una sessione /manualmente/ con PuTTY, e che quindi non si tratti di una 
cosa totalmente automatizzabile.
In realtà anche le sessioni di PuTTY possono essere create in maniera 
automatica: PuTTY salva le sessioni nel Registry, precisamente sotto:
[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions]
per cui per generare una sessione ex-novo da programma, è sufficiente 
scrivere le apposite chiavi nel Registry, ad esempio con un modulo come 
Win32::TieRegistry, che rende la cosa semplice esattamente quanto 
assegnare valori ad un hash.
---
A rigore, stando alla documentazione di Plink, dovrebbe essere possibile 
passargli dalla command line direttamente l'host, senza neanche passare 
per le sessioni salvate da PuTTY. Questo renderebbe le cose ancora più 
semplici, ma purtroppo io non ci sono riuscito: Plink va sempre a 
cercare le sessioni salvate da PuTTY (almeno nel caso in cui ne esista 
già almeno una).
Se qualcuno riuscisse a svelare l'arcano (il sorgente di Plink è 
disponibile), ci faccia sapere ;-)