Ir al contenido principal
En mi último blog hablé sobre la automatización de las transferencias de archivos mediante FTP. Hay tres problemas con el uso de FTP. Primero, su contraseña se envía a través de la red en texto claro haciéndola disponible a cualquiera con un analizador de protocolo. Segundo, tus datos también se envían en texto claro. Tercero, tienes que registrar tu contraseña en algún lugar del módulo, ya sea en el macro o en el archivo .netrc. Debido a estos problemas, muchos sitios han ordenado o están pensando en ordenar que se use SFTP, el subsistema FTP seguro de SSH, en lugar de FTP. Sin embargo, no se puede reemplazar el ftp por sftp en la macro de comandos (figura 1) y esperar que funcione (figura 2).

 

&attach_input
sftp 172.16.1.116
nd
MYPASSWORD
put foo
&if (command_status) ^= 226 &then &goto ERROR1
get bar
&if (command_status) ^= 226 &then &goto ERROR2
quit
&
&label ERROR1
..display_line Could not put file
quit
&return
&
&label ERROR2
..display_line Could not get file
quit
&return

Figura 1 - sftp1.cm - reemplazando el comando ftp por sftp en un comando macro

 

sftp1
Connecting to 172.16.1.116...
dup2: Bad file number.
Error on line 3 of sftp1.
command_processor: Object not found. nd. In command macro
%phx_vos#m15_mas>SysAdmin>Noah_Davids>sftp1.cm
ready  12:39:59

 

Figura 2 - corriendo sftp1.cm
El problema es una incompatibilidad entre la forma en que los comandos nativos de VOS y los de código abierto POSIX tratan la entrada. Sin embargo, el SFTP, como el FTP, permite crear un archivo con una lista de peticiones (figura 3) que se ejecutará de forma automática (figura 4).

 


put foo
get bar

 

Figura 3 - sftp2.input - archivo que contiene las peticiones para que sftp se ejecute

 


sftp -b sftp2_input nd@172.16.1.116
nd@172.16.1.116's password:
sftp> put foo
Uploading foo to /SysAdmin/Noah_Davids/foo
sftp> get bar
Couldn't stat remote file: No such file or directory
File "/SysAdmin/Noah_Davids/bar" not found.
Ready  13:06:45

 

Figura 4 - ejecución con un archivo de entrada de solicitudes y un aviso de contraseña
Notarán en la figura 4 que sftp está pidiendo una contraseña. No hay forma de poner la contraseña en el archivo de entrada. La ÚNICA forma de evitar el mensaje de la contraseña es usar la autenticación de clave pública (figura 5).

 

sftp -b sftp2_input nd@172.16.1.116
sftp> put foo
Uploading foo to /SysAdmin/Noah_Davids/foo
sftp> get bar
Couldn't stat remote file: No such file or directory
File "/SysAdmin/Noah_Davids/bar" not found.
Ready  13:12:28

 

Figura 5 - ejecución con un archivo de entrada de solicitudes, utilizando la autenticación de clave pública para eliminar el aviso de contraseña

 

Puede encontrar un artículo sobre cómo establecer la autenticación de clave pública aquí - http://members.cox.net/ndav1/self_published/publickey_authentication_setup.html

Desafortunadamente, sftp sólo ejecutará todas las solicitudes en el archivo de entrada una tras otra, no hay ningún mecanismo para probar si la transferencia funcionó o no.

Ya que no se pueden utilizar macros de comando, ¿hay alguna alternativa? El producto gnu_tools se envía con un programa llamado expect. Puede ser usado para enviar comandos, esperar cualquier número de respuestas diferentes y hacer algo basado en lo que ve en el flujo de salida. No soy un experto en expect, pero el script de la figura 6 le ayudará a empezar. Si busca en la web "scripts de espera" encontrará muchas referencias que le ayudarán a personalizar mi sencillo ejemplo.

 

# If we get an end-of-file (eof) it means that the sftp process
# terminated. Report the last command that was sent.
#
proc goteof {cmd} {
puts "sftp connection unexpectedly closed n"
puts "last text received wasn"
puts "<<"
puts $cmd
puts ">>nnn"
exit
}
# Este procedimiento hace coincidir las expresiones regulares buscando las cadenas clave
# en la salida recolectada del comando que fue ejecutado. En este caso
# Sólo estoy informando el tipo de error, pero otras cosas se pueden hacer
# también. También sólo compruebo dos errores. Hay otros. Tendrás
# para añadirlos a medida que los encuentres.
#
proc checkforerrors {buf cmd} {
if [regexp {.*no encontrado} $buf] {
pone "$cmd FALLIDO: no encontrado"
retorno 1
}
if [regexp {.*Permiso denegado} $buf] {
pone "$cmd FALLADO: problemas de acceso"
retorno 1
}
retorno 0
}# establecer el tiempo de espera a -1 para que no haya tiempo de espera. El valor predeterminado es de 10 segundos
# y la mayoría de las transferencias de archivos toman más tiempo que eso. Decidí establecer no
# Tiempo muerto, puedes cambiar eso.
establecer el tiempo de espera -1

# Start sftp
spawn sftp nd@172.16.1.116

# esperar el prompt de sftp pero si obtenemos un prompt de autenticación, que termina en
# sí/no informar de un problema de seguridad y salir.
esperar {
"¿sí/no?" { pone
"nnnNos hemos conectado a un servidor equivocado o el servidor ha sido recargado".
puts
"Hay que validar la clave del servidor antes de volver a ejecutar este script.nnn"
exit }
sftp>
}

# cambiar a un directorio conveniente para las pruebas
enviar "cd sftp_testr"
esperar {
eof { goteof "cd sftp_test" }
sftp>
}

# llamar a la comprobación de errores pasando todos los caracteres recogidos hasta el
# sftp> prompt. También el comando que se envió a sftp. Si el procedimiento
# procedimiento checkforerrors devuelve 1 salga del script. De nuevo, puedes
# hacer otras cosas.
if {[checkforerrors $expect_out(buffer) "cd sftp_test"] == 1} { salir }

enviar "put foor"
esperar {
eof { goteof "put foo" }
sftp>
}
if {[checkforerrors $expect_out(buffer) "put foo"] == 1} { exit }

enviar "get barr"
esperar {
eof { goteof "get bar" }
sftp>
}
if {[checkforerrors $expect_out(buffer) "get bar"] == 1} { exit }

enviar "quitr"
espera eof
pone "script donenn"

 

Figura 6 - sftp3.exp - espera que el script automatice el SFTP

 

expect sftp3.exp
spawn sftp nd@172.16.1.116
Connecting to 172.16.1.116...
The authenticity of host 172.16.1.116(172.16.1.116)' can't be established
+.
RSA key fingerprint is 37:f4:1a:56:64:af:ab:8a:7c:0b:36:47:c5:6c:1d:1a.
Are you sure you want to continue connecting (yes/no)?
Nos hemos conectado al servidor equivocado o el servidor ha sido recargado.
La clave del servidor debe ser validada antes de que este script pueda ser ejecutado de nuevo.ready 10:41:10

 

Figura 7 - ejecución de sftp3.exp expect script con aviso de seguridad

 

expect sftp3.exp
spawn sftp nd@172.16.1.116
Connecting to 172.16.1.116...
sftp> cd sftp_test
sftp> put foo
Uploading foo to /SysAdmin/Noah_Davids/sftp_test/foo
sftp> get bar
No se pudo establecer un archivo remoto: No hay tal archivo o directorio
El archivo "/SysAdmin/Noah_Davids/sftp_test/bar" no se ha encontrado.
sftp> get bar FALLADO: no se encuentra ya 10:42:11

 

Figura 8 - ejecución de sftp3.exp espera el script sin advertencia pero con una transferencia fallida

Por último, en mi blog de FTP mencioné que el FTP era capaz de leer los archivos que aún estaban abiertos y esto en ocasiones ha dado lugar a que se transfieran archivos incompletos, sugerí que si el macro de FTP espera a que un archivo aparezca en una ubicación y luego lo transfiere, el macro debe comprobar que ya no está bloqueado. El mismo problema puede ocurrir con el SFTP y la solución es la misma. Puede colocar la comprobación de bloqueo de archivos en una macro de comando (figura 9) y luego, cuando el archivo ya no esté bloqueado, llamar a esperar con el script apropiado.

&label AGAIN
&if (exists new_file) = 1 & (locked new_file) = 0 &then &goto EXPECT
display_line new_file not ready for transfer as of (time)
sleep -seconds 15
&goto AGAIN
&
&
&label EXPECT
expect sftp3.exp

 

Figura 9 - comando macro de prueba para el bloqueo de archivos antes de llamar a expect