Pure-Ftpd и pure-uploadscript

сряда, декември 15th, 2010

Когато опре до пускане на ftp server с virtual users vsftpd не е първи избор, особено ако искаме sql backend. По тази причина, а и заради някои други благини моят избор в такива случаи пада върху pure-ftpd. Една от въпросните благини е pure-uploadscript, която за да не преразкавам, прави следното:

If Pure-FTPd is compiled with –with-uploadscript (default in binary distributions), and if the -o (or –uploadscript) is passed to the server, a named pipe called /var/run/pure-ftpd.upload.pipe is created. You will also notice an important file called /var/run/pure-ftpd.upload.lock, used for locking.
After a successful upload, the file name is written to the pipe.
pure-uploadscript reads this pipe to automatically run any program or script to process the newly uploaded file.

When the upload script is run, the name of the newly uploaded file is the first argument passed to the script (referenced as $1 by most shells) . Some environment variables are also filled by useful info about the file. UPLOAD_SIZE The size of the file, in bytes. UPLOAD_PERMS The permissions, as an octal integer. UPLOAD_UID The numerical UID of the owner. UPLOAD_GID The numerical GID of the owner. UPLOAD_USER The login of the owner. UPLOAD_GROUP The group name the files belongs to. UPLOAD_VUSER The full user name, or the virtual user name (127 chars max) .

Което е нещо доста полезно. Реално не е много трудно да се напише някой скрипт, който би правил същото. Но защо, след като го има имплементирано. Ползвал съм въпросната функция често пъти, например за да се изпрати mail с известие за качени файлове от даден потребител, или пък да се извърши последваща обработка.

Съществува обаче един проблем, който вече на два пъти ме тормози (а и не само мен). Да, като не си записвам нещо, което вече съм debug-нал, се налага да го debug-вам втори път. Именно това и инспирира този ми блог пост. За какво по-точно става дума. Pure-Ftpd по принцип идва без конфигурационен файл, въпреки че има такава опция и тя се ползва активно от дистрибуциите използващи пакетни мениджъри. Това всъщност не е от голямо значение в случая, но го споменавам защото аз по принцип ползвам такава. Първият път когато срещнах проблема, за който ще пиша по-долу всъщност беше под Slackware. Проблемът се проявява, ако човек пропусне ето тази забележка в README файла:

- ‘-o’: Write all uploaded files to ‘/var/run/pure-ftpd.upload.pipe’ so
that the ‘pure-uploadscript’ program can run. Don’t enable that option if
you don’t actually use ‘pure-uploadscript’ otherwise pure-ftpd will hang
waiting for pure-uploadscript to start.

Та хубаво е да се има предвид, че ако pure-ftpd бъде стартиран с ключ „-o“ то  чака pure-uploadscript да бъде стартиран, и ако не го намери, то се получава неприятна изненада. pure-ftpd не се оплаква, дори се вижда като процес, но реално зависва в очакване на pure-uploadscript. Според мен не е лошо това да се добави като коментар и в man-а или пък в секцията засягаща uploadscript в pure-ftpd.conf, въпреки че е изрично описано в README и във FAQ на сайта (ping-нах разработчиците по въпроса).

Та ако сме решили да ползваме pure-uploadscript, ще трябва да го стартираме сами, понеже:

For security purposes, the server never launches any external program. It’s why there is a separate daemon, that reads new uploads pushed into a named pipe by the server. Uploads are processed synchronously and sequencially.It’s why on loaded or untrusted servers, it might be a bad idea to use pure-uploadscript with lenghty or cpu-intensive scripts.

като имаме предвид следното:

IMPORTANT: YOU MUST START PURE-FTPD _FIRST_ and _THEN_ START PURE-UPLOADSCRIPT. THE REVERSE ORDER WON’T WORK.

За тази цел на базата на това си спретнах един скрипт, който да добавя в /etc/init.d/, като преди това е важно да се отбележат следните неща:

  • Приоритета на стартиране на pure-uploadscript трябва да е по-висок от този на init скрипта на pure-ftpd
  • „/usr/local/bin/uploadscript.sh“ е скрипт-а, който ще се изпълнява при успешен upload на файл /не се прави проверка, дали uploadscript.sh съществува/
  • не се прави проверка дали pure-uploadscript вече не е стартиран.
#!/bin/sh
#
# Startup script for the pure-ftpd pure-uploadscript
#
# chkconfig: - 90 10
# description: pure-upload script is a nice Pure-FTPD feature regarding \
# uploads. Any external program or script can be automatically called after a \
# successful upload. 
 
### BEGIN INIT INFO
# Provides:
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start:
# Default-Stop:
# Short-Description:
# Description:
### END INIT INFO
 
# Source function library.
. /etc/rc.d/init.d/functions
 
exec="/usr/sbin/pure-uploadscript"
prog="pure-uploadscript"
#call an external program or script after successfull upload
callscript="/usr/local/bin/uploadscript.sh"
 
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
 
lockfile=/var/lock/subsys/$prog
 
start() {
 # Make sure the pure-ftpd is running
if [ ! -e /var/lock/subsys/pure-ftpd ]; then
        echo $"Pure-FTPd is not running - exiting"
        exit 1
fi
    [ -x $exec ] || exit 5
    echo -n $"Starting $prog: "
    daemon $exec -B -r $callscript
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
 
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
 
restart() {
    stop
    start
}
 
reload() {
    restart
}
 
force_reload() {
    restart
}
 
rh_status() {
    status $prog
}
 
rh_status_q() {
    rh_status > /dev/null 2>&1
}
 
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

Понеже изглежда, че WP-Syntax има собствено мнение относно визуализацията на „&&“ и „>“ то скрипта може да бъде свален и направо от тук.

Patch and recompile source rpm

четвъртък, април 30th, 2009

Както обикновено когато е последен работен ден изникват странни проблеми. Днес попаднах на интересен client/server side bug, който се наложи да оправям. Оказа се, че в PureFTPd има проблем засягащ timestamp на файлове. При upload на файл timestamp-а локално и този на сървъра се различават с по няколко часа, в зависимост от часовата зона, като за нашата часовете са 2. Това е когато се използва preserve timestamp опцията от страна на клиента, и е доста неудобно при синхронизация на файлове. За щастие проблема се оказа елементарен за решаване – описано е как да стане тук. Аз обаче нямах време да чакам bugfix от upstream-a и взех нещата в свои ръце. Реших да прекомпилирам source rpm и по-надолу ще опиша как точно може да се направи това.

  • Като за начало имаме нужда от rpm-build, така че ако го няма, се налага да го инсталираме :
yum -y install rpm-build
  • Намираме и инсталираме src rpm-а. В моя случай той е ето тук.
rpm -ivh pure-ftpd-1.0.21-15.el5.src.rpm
  • Отиваме в specs директорията:
cd /usr/src/redhat/SPECS/
  • Където подготвяме source за компилиране, като го разархивираме и apply-ваме вече дефинираните patch-ове
rpmbuild -bp pure-ftpd.spec

#Възможно е да има проблеми със зависимости, като естествено трябва да инсталираме посочените пакети, ако има такава необходимост

  • Отиваме в /usr/src/redhat/BUILD където би трябвало да има директория от рода pure-ftpd-1.0.21. Правиме й backup, който ще ползваме при генериране на patch-a в последствие.
cd /usr/src/redhat/BUILD

cp -r pure-ftpd-1.0.21 pure-ftpd-1.0.21.orig

Промяната, която трябва да направим е да заменим "mktime()" с "timegm()" във файла ftpd.c. И така с любимия файлов редактор vim, правим нужната промяна във файла /usr/src/redhat/BUILD/pure-ftpd-1.0.21/src/ftpd.c

  • Генерираме patch-a
diff -Naur pure-ftpd-1.0.21.orig/src/ftpd.c pure-ftpd-1.0.21/src/ftpd.c > ../SOURCES/pure-ftpd-1.0.21-utime.patch

като той трябва да съдържа нещо от рода:

1
2
3
4
5
6
7
8
9
10
11
--- pure-ftpd-1.0.21.orig/src/ftpd.c    2009-04-30 13:39:37.000000000 +0300
+++ pure-ftpd-1.0.21/src/ftpd.c 2009-04-30 13:40:55.000000000 +0300
@@ -2541,7 +2541,7 @@
tm.tm_mon--;
tm.tm_year -= 1900;
if (tm.tm_mon < 0 || tm.tm_year <= 0 ||
-       (ts = mktime(&tm)) == (time_t) -1) {
+       (ts = timegm(&tm)) == (time_t) -1) {
addreply_noformat(501, MSG_TIMESTAMP_FAILURE);
return;
}
  • Редактираме spec файла /usr/src/redhat/SPECS/pure-ftpd.spec като правим следните промени
Release:    15%{?dist}

на

Release:    15%{?dist}.1
  • Добавяме ред, в който описваме направения patch
Patch3:     pure-ftpd-1.0.21-utime.patch
  • в %prep секцията, добавяме следния ред, след другите patch-ове
%patch3 -p1 -b .utime
  • в %changelog секцията описваме направената промяна
1
2
* Thu Apr 30 2009 package maintainer <mail> - 1.0.21-15.1
- patch pure-ftpd "SITE UTIME" bug</mail>
  • остава да прекомпилираме пакета
rpmbuild -ba pure-ftpd.spec
  • Ако всичко мине гладко, готовият RPM трябва да се намира в /usr/src/redhat/RPMS/$arch/ и можем да пристъпим към update/инсталация на готовия пакет.

Още информация:

http://docs.fedoraproject.org/drafts/rpm-guide-en/ch-rpmbuild.html

http://linux.die.net/man/8/rpmbuild

Допълнение:

Настройка на winscp за Daylight saving time (DST) - http://winscp.net/eng/docs/ui_login_environment#daylight_saving_time

Stop ACTA