Inhaltsverzeichnis

FTP

SFTP-Server

SFTP-only mit Change Root

FTP-Server

welches ist der sicherste FTP-Server

Antwort: "keiner" → weil FTP die Daten (auch das Passwort) unverschlüsselt überträgt, solltest Du statt dessen SFTP verwenden; hier wird, wie bei SSH, die komplette Verbindung verschlüsselt (siehe SCP). Im Gegensatz zu SFTP und SCP bleibt bei FTPS die Datenübertragung unverschlüsselt und schnell aber der Login wird sicher behandelt. → Migration von FTP auf FTPS

Aber viele verwenden aus den unterschiedlichsten Gründen trotzdem das alte FTP-Protokoll und für die ist dieser Bertrag.

Auf dieser Seite werden drei FTP-Server miteinander verglichen: Evaluating FTP Servers: ProFTPd vs. PureFTPd vs. vsFTPd

Das Fatzit:

    • Eigenschaften:
    • Vorteile:
      • er ist sehr stark konfigurierbar;
      • Konfigurationssyntax lehnt sich an Apache an;
  1. Auch scheint TwoFTPd einen ernsthaften Blick wert zu sein.
  2. wu-ftpd ist der bekannteste, älteste und unsicherste FTP-Server

nativen FreeBSD 8.0 - FTP-Server (FTPD) einrichten

Gruppe anlegen:

# pw groupadd -n programmierer -g 2000

Benutzer anlegen:

# echo "geheim" | /usr/sbin/pw useradd -n fritz -u 2300 -c "Der Programmierer Fritz" -d /home/fritz -g programmierer -G admins -m -s /bin/tcsh -h 0
Passwort:   . . . . . . . . . . . .  geheim
User-Name:  . . . . . . . . . . . .  fritz
User-ID:  . . . . . . . . . . . . .  2300
Kommentar:  . . . . . . . . . . . .  Der Programmierer Fritz
Homeverzeichnis:  . . . . . . . . .  /home/fritz
Gruppen-Name:   . . . . . . . . . .  programmierer
Gruppen-Mittglied in der Gruppe:  .  admins
Shell:  . . . . . . . . . . . . . .  /bin/tcsh

Leider kann man die maximale Anzahl der Verbindungen nur mit dem inetd einstellen, als Daemon verursacht der FTP-Dienst aber weniger Systemlast.

als Daemon

aktivieren und den FTPD konfigurieren:

# vi /etc/rc.conf
...
ftpd_enable="YES"
ftpd_flags="-8 -h -l -M -m -t 7200 -u 007"
...

starten:

# /etc/rc.d/ftpd start

per Super-Server (inetd)

aktivieren und den inetd konfigurieren:

# vi /etc/rc.conf
...
inetd_enable="YES"
inetd_flags="-wW -C 60 -l -c 20"
...

den FTPD konfigurieren:

# vi /etc/inetd.conf
...
ftp     stream  tcp     nowait  root    /usr/libexec/ftpd       ftpd -8 -h -l -M -m -t 7200 -u 007
...

starten:

# /etc/rc.d/inetd start

Change-Root aktivieren

1. Change-Root - Variante
# vi /etc/ftpchroot
fritz
@programmierer

Der Benutzer fritz kann aus seinem Homeverzeichnis nicht raus, wenn er per FTP eingelogt ist. Ebenso geht es allen Benutzern, die der Gruppe programmierer angehoeren.

1. Change-Root - Variante

Eine andere Moeglichkeit fuer Change-Root wird mit der Konsolenkonfiguration erreicht.

Als erstes muss eine Klasse ftpchroot angelegt werden:

# vi /etc/login.conf
        ftpchroot|FTP Benutzerzugang:\
        :ftp-chroot:\
        :tc=default:
        

jetzt muss der FTP-Benutzer noch der Klasse ftpchroot zugewiesen werden:

# vipw
ftp:*:3000:3000:ftpchroot:0:0:FTP Benutzer:/var/ftp:/sbin/nologin

Man kann den Eintrag auch in einer Bestehenden Klasse mit aufnehmen.

Verbotsliste erstellen

# vi /etc/ftpusers
schultz
@webgruppe

Der Benutzer schultz darf sich, per FTP, nicht einloggen! Ebenso dürfen sich auch alle Benutzer der Gruppe webgruppe per FTP nicht einloggen!

FTP-Client

mit CurlFtpFs ein Laufwerk per FTP mounten

mit FreeBSD 11.1-RELEASE-p11 per Mount einbinden (ftpes)

> pkg install sysutils/fusefs-curlftpfs
> mkdir /he
> curlftpfs -o enable_epsv ftp://ftp12327624-405867:geheim@wp12327624.server-he.de  /he

> mount /he
> ls -lha /he/
> umount /he

gFTP

Das ist ein grafischer FTP-Client von Gnome, der eine Bandbreitenbegrenzung ermöglicht.

LFTP

LFTP ist dafür bekannt, dass es nicht die klassischen FTP-Kommandos verwendet, sondern sich mit seinen Kommandos an BASH orientiert. Das hat den Vorteil, dass hier ein rekursives löschen von ganzen Verzeichnisbäumen mit einem einzigen Kommando funktioniert. Und das beste daren, es ist 1:1 das gleiche Komando als wenn man auf dem entfernten Rechner in einer BASH wäre: rm -fr Dir.

zum Beispiel kann man so ein komplettes Verzeichnis (hier pages) löschen und anschließend neu übertragen:

> echo "cd /wiki/data/ ; rm -fr pages ; mirror -cRF pages" | lftp ftp://ftp12345678:geheim@wp12345678.server-he.de

So einfach ging es auf der CLI noch nie… :-)

NcFTP

Das ist ein sehr flexibler FTP-Client, der ursprünglich von NetBSD stammt und mittlerweile auch zu anderen UNI*en portiert wurde.

Leider funktioniert der NcFTP 3.2.3 (July 23, 2009) seit FreeBSD 8.0-RELEASE nicht mehr. Um ihn wieder ans Rennen zu bekommen, muss man ihn patchen.

Was das für ein Problem ist und wo man den Patch bekommt, steht hier: http://www.mail-archive.com/freebsd-stable@freebsd.org/msg107277.html

# vi server1.cfg
host ftp.server.net
user fritz
pass geheim

normales einloggen, wie mit jedem anderen auch:

# ncftp -u fritz -p geheim ftp.server.net

ein "ls" auf dem entfernten Rechner über das Verzeichnis "/ftp" mit langer (-l) Ausgabe:

# ncftpls -u fritz -p geheim -l ftp.server.net /ftp

das Verzeichnis "daten" rekursiv hochschieben:

# ncftpput -u fritz -p geheim -S .tmp -m -R ftp.server.net /ftp /tmp/daten

das Verzeichnis "daten" rekursiv hochschieben, alle Dateien, die Fehlerlos hochgeladen wurden, sind aus dem Verzeichnis "/tmp/daten" gelöscht worden:

# ncftpput -u fritz -p geheim -S .tmp -m -R -DD ftp.server.net /ftp /tmp/daten

das Verzeichnis "daten" rekursiv hochschieben (mit Konfigurationsdatei):

# ncftpput -f server1.cfg -S .tmp -m -R -DD /ftp /tmp/daten

FTP (FreeBSD)

LFTP per FTPS

Die im folgenden vorgestellte Vorgehensweise wurde am Beispiel eines einfachen FTP-Zugangs bei HostEurope, am 16. Februar 2024, getestet.

damit man das Passwort nicht jedesmal von Hand eingeben muß:

> touch ~/.netrc
> chmod 0600 ~/.netrc
> echo "machine ftp.server.net login fritz password geheim" > ~/.netrc

sollte es zu dieser Fehlermeldung kommen:

> echo "ls -1" | lftp ftp://fritz@domain.de
ls: ls -1: Fatal error: Certificate verification: subjectAltName does not match ‘domain.de’ (A2:A6:A9:AF:AE:AC:A6:A3:A1:A7:A5:A0:A9:A1:A0:AE:A0:A3:A9:A4)

wie es aussieht, brauchen wir jetzt das lftp-Konfigurationsverzeichnis und da SSL vom Remote-Host erzwungen wird, können wir es in der Konfigurationsdatei auch gleich einschalten:

> mkdir -p ~/.lftp/
> echo "set ftp:ssl-auth SSL" >> ~/.lftp/rc

dann kann man nachschauen, welcher Name erwartet wird:

> echo QUIT | openssl s_client -connect domain.de:21 -starttls ftp -showcerts

wenn es mit dem richtigen Domain-Namen immer noch nicht funktioniert, dann kann man (wenn man es hat) das richtige CA-Zertifikat mitgeben:

> echo "set ssl:ca-file /etc/ssl/certs.pem" >> ~/.lftp/rc

oder man schaltet diese Sicherheitsüberprüfung für diesen SSL-Fingerabdruck ab:

> echo "set ssl:verify-certificate/A2:A6:A9:AF:AE:AC:A6:A3:A1:A7:A5:A0:A9:A1:A0:AE:A0:A3:A9:A4 no" >> ~/.lftp/rc

NcFTP

Da ich jetzt keine Lust habe den NcFTP zu patchen, verwende ich dann doch den FTP-Client, der bei FreeBSD (/usr/bin/ftp) schon dabei ist.

Im Grunde ist der garnicht so schlecht, er kann

  1. ~/.netrc auslesen
  2. für jedes einzelne Verzeichnis eine separate Bandbreitenbegrenzung (-T)
  3. Bandbreitenbegrenzung kann für beide Richtungen (hin/zurück) sogar unterschied eingestellt werden (rate)
  4. in Script's verwendet werden

allerdings nicht ganz so schön wie der NcFTP aber dafür funktioniert er. ;-)

früher

Eine Möglichkeit diesen FTP-Client in einem Script (automatisiert) zu verwenden war diese (letztes mal getestet irgendwann zwischen 2003 und 2005):

ftp ftp://fritz:geheim@ftp.server.net:/ftp/ << EOF
put Datei01.txt
put Datei02.txt
put Datei03.txt
put Datei04.txt
by

EOF
FreeBSD 8.0 RELEASE p3

Als erstes schreiben wir mal die "~/.netrc":

# vi ~/.netrc
machine ftp.server.net login fritz password geheim
# chown ich:meinegruppe ~/.netrc
# chmod 0600 ~/.netrc
Variante 1 (Script)

Ich lege hier erst das Verzeichnis an und trenne die Verbindung dann wieder bevor ich das Verzeichnis mit Daten fülle.

Der Grund ist der, das es ja die beiden Möglichkeiten gibt, dass das Verzeichnis noch nicht existiert oder das es schon existiert. Eigentlich müsste man erst mal nachsehen ob es schon existiert, aber den Aufwand spare ich mir.

In diesem Fall wird die Verbindung sauber beendet, wenn das Verzeichnis angelegt werden konnte. Wenn es aber schon existiert, dann bricht die Verbindung ab, das ist aber egal, da es in unserem Fall ja kein Fehler ist, sondern wir vorher ja nur einen "unnötigen" Arbeitsschritt durchgeführt haben.

Danach wird die Verbindung wieder aufgebaut und evtl. vorhandene Daten werden aus dem Verzeichnis gelöscht, dann kommen die neuen Daten rein.

#!/bin/sh

# cd /lokales/verzeichnis

# ftp -p -i -N ~/.netrc ftp.server.net << EOF
mdir ftp
by
EOF

# ftp -p -i -N ~/.netrc ftp.server.net << EOF
cd ftp
pwd
ls -l
mode bin
prompt
mdelete *
mput *
by
EOF

Das Kommando "prompt" schaltet die Bestätigungsabfragen (Interaktionen) an bzw. aus.

Variante 2 (Script)

Dieses Beispiel ist deutlich einfacher gehalten, hier wird nur in ein Verzeichnis gewechselt, dann das aktuelle Verzeichnis und der Inhalt ausgegeben.

#!/bin/sh

cd /lokales/verzeichnis

echo "
cd /ftp
pwd
ls -l
by
" | ftp -p -i -N ~/.netrc ftp.server.net
Variante 3 (Kommandozeile)

Hier wurde das Beispiel aus "Variante 2" in einer Kommandozeilentauglichen Form dargestellt.

Der Befehl "echo" muss den Parameter "-e" bekommen, damit er die Schreibweise "\n" für "Zeilenumbruch" versteht. So kann man mehrere Zeilen in einer einzigen darstellen.

# echo -e "cd /ftp\npwd\nls -l\nby" | ftp -p -i -N ~/.netrc ftp.server.net

Skript zum Download von einem FTP-Push-Server

In diesem Beispiel werden in unregelmäßigen Abständen Dateien auf einem FTP-Push-Server abgelegt, der aus dem Internet immer erreichbar ist.

Mit diesem Beispielskript werden die Dateien dann regelmäßig abgeholt.

hier liegen die Zugangsdaten für das FTP-Programm von FreeBSD:

> vi ~/etc/ftp-push.cfg
# Diese Datei muss die Rechte 0400 oder 0600 haben!
machine ftp.push.org login fritz password geheim

dieses Skript listet alle Dateien aus der Root ("/") des FTP-Push-Server's auf:

> vi ~/bin/ftp-push_ls.sh
#!/bin/sh

CFGDATEI="~/etc/ftp-push.cfg"

#
ftp -i -p -N ${CFGDATEI} ftp.push.org << EOF
cd /
pwd
mode bin
ls
by
EOF
#

Dieses Skript saugt alle Dateien, die sich auf dem FTP-Push-Server befinden und beginnt mit der Größten Datei.
Es wird hier nicht mit dem FreeBSD-FTP-Programm gesaugt, sondern mit dem "wget", weil dieses ein paar Vorzüge biete.
Allerdings muss man den entsprechenden Pfad im Skript auf seine individuellen Bedürfnisse anpassen:

wget -t 0 -c http://${WWWHOST}/otr/${DATEI} && TRANSFER="OK"

Alle Dateien, die fehlerfrei gesaugt werden konnten, werden auf dem FTP-Push-Server gelöscht.

> vi ~/bin/saug_vom_push-server.sh
#!/bin/sh

VERSION="v2013060900"

VERSUCHE="9"    # wie oft bei einem Fehler der Download versucht werden soll

PATH="/bin:/usr/local/bin:/usr/bin"
cd /Export/OTR/Video/Download || exit 1

#------------------------------------------------------------------------------#
### PID-Datei erstellen
PIDDATEI="/tmp/$(basename ${0}).pid"
if [ -e ${PIDDATEI} ] ; then
        echo "
        Das Skript '${0}' laeft schon: $(cat ${PIDDATEI})
        "
        ls -lha ${PIDDATEI}
        exit 1
else
        date +'%F %T' >> ${PIDDATEI}
fi
#------------------------------------------------------------------------------#

CFGDATEI="~/etc/ftp-push.cfg"
FTPHOST="$(awk '/^[a-zA-Z0-9]/{print $2}' ${CFGDATEI} | head -n1)"
WWWHOST="$(awk '/^[a-zA-Z0-9]/{sub("ftp","www");print $2}' ${CFGDATEI} | head -n1)"
BENUTZER="$(awk '/^[a-zA-Z0-9]/{print $4}' ${CFGDATEI} | head -n1)"
PASSWORT="$(awk '/^[a-zA-Z0-9]/{print $6}' ${CFGDATEI} | head -n1)"

ALLEDATEIGR="$(~/bin/ftp-push_ls.sh | awk '/rw-r--r--/{print $5,$NF}' | sort -rn)"
ALLEDATEIEN="$(echo "${ALLEDATEIGR}" | awk '{print $NF}')"


for DATEI in ${ALLEDATEIEN}
do
    NOCHEINMAL=Ja
    DURCHLAUF="${VERSUCHE}"
    echo "#----------------------------------------------------------------------#"
    while [ "${NOCHEINMAL}" == "Ja" ]
    do
        echo "
        #-> sauge '${DATEI}'"
        #echo "wget -nv -t 0 -c http://${WWWHOST}/otr/${DATEI}"
        echo "wget -t 0 -c http://${WWWHOST}/otr/${DATEI}"
        wget -t 0 -c http://${WWWHOST}/otr/${DATEI} && TRANSFER="OK" || TRANSFER="Nein"

        if [ "${TRANSFER}" == "OK" ] ; then
            echo "TRANSFER='${TRANSFER}'"
            GROESSEFTP="$(echo "${ALLEDATEIGR}" | fgrep "${DATEI}" | awk '{print $1}')"
            GROESSELOKAL="$(ls -l "${DATEI}" | awk '{print $5}')"
            if [ "${GROESSEFTP}" -eq "${GROESSELOKAL}" ] ; then
                echo "#-> delete '${DATEI}'"

                #
                ftp -i -p -N ${CFGDATEI} ${FTPHOST} << EOF
                cd /
                pwd
                mode bin
                delete ${DATEI}
                by
EOF
                #

                FTPRETURN="$?"
                if [ "${FTPRETURN}" -eq "0" ] ; then
                    NOCHEINMAL=Nein
                    #echo "NOCHEINMAL='${NOCHEINMAL}'"
                    echo "#-> geloescht: '${DATEI}'"
                    /home/bin/otr-download_verschieben.sh ${DATEI}
                else
                    NOCHEINMAL=Ja
                    #echo "NOCHEINMAL='${NOCHEINMAL}'"
                    echo "#-> konnte nicht loeschen: '${DATEI}'"
                fi
            else
                NOCHEINMAL=Ja
                #echo "NOCHEINMAL='${NOCHEINMAL}'"
                echo "'${GROESSEFTP}' != '${GROESSELOKAL}'"
                if [ "${DURCHLAUF}" -gt "0" ] ; then
                        DURCHLAUF="$(echo "${DURCHLAUF}" | awk '{print $1-1}')"
                        echo "DURCHLAUF='${VERSUCHE}-${DURCHLAUF}'"
                else
                        NOCHEINMAL=Nein
                fi
                sleep 100
            fi
        else
                NOCHEINMAL=Ja
                #echo "NOCHEINMAL='${NOCHEINMAL}'"
                #echo "TRANSFER='${TRANSFER}'"
                echo -n "."
                if [ "${DURCHLAUF}" -gt "0" ] ; then
                        DURCHLAUF="$(echo "${DURCHLAUF}" | awk '{print $1-1}')"
                        echo "DURCHLAUF='${VERSUCHE}-${DURCHLAUF}'"
                else
                        NOCHEINMAL=Nein
                fi
                sleep 1
        fi
    done
done

#------------------------------------------------------------------------------#
### PID-Datei entfernen
echo "#-> BEGINN: $(cat ${PIDDATEI})"
rm -vf ${PIDDATEI}
echo "#-> ENDE: $(date +'%F %T')"
#------------------------------------------------------------------------------#

Der Aufruf erfolgt am besten so:

> screen -d -m -S FTPpush ~/bin/saug_vom_push-server.sh