среда, 26 октября 2011 г.

Настройка FastCGI и PHP с индивидуальными правами пользователей

Перевод статьи: Setup FastCGI and PHP with individual user permissions

Автор: silverjam и другие.

Примечания переводчика: для порядка я иногда перевожу материалы, которыми собираюсь воспользоваться. Начав делать этот перевод, я сразу же пожалел о том, что ввязался в это гиблое дело - статья разжёвывает элементарные вещи вроде заведения пользователей, групп, членство в группах и права доступа. Ну и запуск сценариев инициализации из cron'а я, конечно, не одобряю. Кроме того, автор использовал FreeBSD 6.2, в которой существовало ограничение на максимальное количество групп для одного пользователя. В качестве решения автор предлагает перейти на FreeBSD 8.0, однако я думаю, что есть по меньшей мере ещё два решения: 1. воспользоваться TCP-сокетами, вместо сокетов домена Unix, 2. воспользоваться каким-нибудь дистрибутивом Linux.

Перво-наперво отметим, что этот рецепт является только примером, поэтому не предъявляйте претензий, если предпочитаете делать такие вещи другим способом, или рассердили клиентов или что-то в этом роде...

Execwrap или php-fpm можно использовать в тех же целях, но этот рецепт не касается этих методов.

Замечание: Этот рецепт работает только на операционных системах типа Unix. Я не знаю, как сделать подобное на Windows.

Введение

Запуск хостинга веб-сайтов для обслуживания индивидуальных пользователей/клиентов потребует дополнительного доведения до ума настроек вашего веб-сервера.

Для начала, нужно назначить каждому пользователю собственную учётную запись на веб-сервере. Пользователь загрузит файлы своих скриптов PHP в его собственный виртуальный корневой каталог документов.

Нужно, чтобы все файлы скриптов PHP выполнялись с правами того же пользователя, который управляет этим виртуальным узлом. Если это так, то можно быть уверенным, что ни один из пользователей не сможет увидеть чужие скрипты PHP.

Рассмотрим следующий скрипт PHP, выполняемый на веб-сервере без индивидуальных разрешений пользователя (не пытайтесь сделать это, поскольку вы можете кончить тем, что полиция постучится в вашу дверь!):
<?php
  $filename = "/path_to_other_users_vhost_root/index.php";
  $handle = fopen($filename, "rb");
  $contents = fread($handle, filesize($filename));
  fclose($handle);
  echo $contents;
?>
Этот сценарий прочитает и покажет исходный код скрипта PHP какого-то другого пользователя. Исходный код может содержать пароли, используемые для подключения к пользовательским базам данных MySQL, или другую интересную информацию. Можно даже сделать скрипт PHP, который сможет перезаписать файлы в каталогах пользователя другого виртуального узла!

Мы хотим этого избежать!

Как насчёт встроенного в PHP безопасного режима safe_mode?

Я не хочу сказать что-то плохое о PHP, но я не рекомендую использовать PHP с возможностями встроенного безопасного режима safe_mode. (Обратитесь к документации по safe_mode на php.net за более подробным описанием.)

Однако, некоторые настройки php.ini могут предотвратить или замедлить большинство видов атак без необходимости изменять исходный код. Для предотвращения удалённого доступа из php воспользуйтесь allow_url_fopen, а для предотвращения вставки удалённых файлов в php вы можете воспользоваться allow_url_include. Настройка open_basedir - это хороший способ усложнить работу взломщика, но этот способ не заменит разрешений пользователей. Для замедления некоторых видов угона сеансов можно отключить опцию session.use_trans_sid.

Но всё же будет лучше, если положиться на возможности ограничения доступа пользователей, встроенные в операционную систему.

Установка

Подразумевается, что на сервере уже установлены Lighttpd и PHP с поддержкой FastCGI. (Как установить PHP с поддержкой FastCGI.)

Чтобы выполнить установку, нужно войти под пользователем root.

1. Добавим пользователей в операционную систему

(Это необходимо только в том случае, если пользователи ещё не добавлены.)

Нужно добавить учётную запись пользователя в операционную систему для каждого пользователя, права которого требуется отделить, чтобы предотвратить возможность доступа к чужому исходному коду.

Предположим, что таких пользователей три (fred, george и ron).

Выполним следующие команды:
# useradd fred
# useradd george
# useradd ron
2. Добавим группы пользователей в операционную систему

Нужно добавить по одной группе для каждого из добавленных выше пользователей. Для простоты назовём группы так же, как и пользователей:

Выполним следующие команды:
# groupadd fred
# groupadd george
# groupadd ron
Теперь нужно добавить каждого пользователя в его группу. В каждой группе пользователей будет два члена: сам пользователь и пользователь демона lighttpd.

Группы пользователей можно настроить, отредактировав файл /etc/group в любом текстовом редакторе.

Файл должен выглядеть примерно так (номера групп могут отличаться):
... [пропущенные строки]
fred:x:441:fred,lighttpd
george:x:442:george,lighttpd
ron:x:443:ron,lighttpd
Можно также воспользоваться командой sed:
# sed -i "s/^\(fred.*\)$/\1,fred,lighttpd/g" /etc/group
# sed -i "s/^\(george.*\)$/\1,george,lighttpd/g" /etc/group
# sed -i "s/^\(ron.*\)$/\1,ron,lighttpd/g" /etc/group
Эти команды добавят самого пользователя и пользователя lighttpd в группы.

3. Настроим структуру файловой системы

Предположим, что мы хотим сохранить все связанные с веб-сервером файлы виртуальных узлов в подкаталогах "/var/www". (Конечно, вы можете выбрать другое место, просто удостоверьтесь, что созданные пользователи имеют права на чтение и выполнение их каталогов. (Например, "chmod 755 /var/www && chown root:root /var/www").

3.1 Создадим корневой каталог

Теперь, создадим два каталога: один для нескольких сценариев запуска, к которому будет иметь доступ только пользователь root, и другой для всех виртуальных узлов:

Выполним следующие команды:
# cd /var/www
# mkdir fastcgi
# mkdir vhosts
# chown lighttpd:lighttpd *
# chmod 755 *
# ls -l /var/www
drwxr-xr-x 2 lighttpd lighttpd 4096 Feb 15 12:17 fastcgi
drwxr-xr-x 9 lighttpd lighttpd 4096 Feb 15 11:21 vhosts
3.2 Создадим каталог для каждого из виртуальных узлов

Теперь создадим каталог для каждого из виртуальных узлов в каталоге "/var/www/vhosts" и зададим соответствующие права для их пользователей:

Выполним следующие команды:
# cd /var/www/vhosts
# mkdir fred-weasley.com
# mkdir george-weasley.com
# mkdir ron-weasley.com
# chown fred:fred fred-weasley.com
# chown george:george george-weasley.com
# chown ron:ron ron-weasley.com
# chmod 750 *
# ls -l /var/www/vhosts
drwxr-x--- 7 fred fred 4096 Feb 15 20:18 fred-weasley.com
drwxr-x--- 6 george george 4096 Feb 15 11:02 george-weasley.com
drwxr-x--- 6 ron ron 4096 Feb 15 11:23 ron-weasley.com
Теперь у нас есть три каталога, в которых три пользователя не могут увидеть файлы друг друга, однако демон lighttpd может видеть их все.

3.3 Создадим структуру каталогов для каждого виртуального узла

Теперь нужно создать структуру каталогов для каждого виртуального узла:

Выполним следующие команды:
# cd /var/www/vhosts/fred-weasley.com
# mkdir html
# mkdir includes (не обязательно)
# mkdir logs
# chown fred:fred *
# chown lighttpd:fred logs
# chmod 750 *
# ls -l /var/www/vhosts/fred-weasley.com
drwxr-x--- 14 fred fred 4096 Feb 17 11:55 html
drwxr-x--- 2 fred fred 4096 Feb 15 12:05 includes
drwxr-x--- 2 lighttpd fred 4096 Feb 15 11:11 logs
Нужно повторить эти команды для каждого из пользователей виртуального узла, заменяя имя пользователя "fred" на имя соответствующего пользователя.

3.4 Создадим каталог FastCGI для каждого пользователя

Теперь мы готовы приступить к самому интересному!

Теперь, перейдём в каталог "/var/www/fastcgi", где мы хотим создать каталог каждого из пользователей. (Когда мы закончим, эти каталоги будут содержать сокеты процессов сервера FastCGI):

Выполним следующие команды:
# cd /var/www/fastcgi
# mkdir fred
# mkdir george
# mkdir ron
# chown fred:fred fred
# chown george:george george
# chown ron:ron ron
# chmod 750 *
# ls -l /var/www/fastcgi
drwxr-x--- 7 fred fred 4096 Feb 15 20:18 fred
drwxr-x--- 6 george george 4096 Feb 15 11:02 george
drwxr-x--- 6 ron ron 4096 Feb 15 11:23 ron
(Отметим, что пользователь lighttpd может читать все каталоги, в то время как три пользователя имеют доступ только к собственным каталогам.)

4. Создадим скрипт запуска FastCGI для каждого пользователя

Создадим каталог, который будет содержать все скрипты запуска FastCGI, выполнив следующие команды:
# cd /var/www/fastcgi
# mkdir startup
# chmod 750 startup
# ls -l /var/www/fastcgi
drwxr-x--- 7 fred fred 4096 Feb 15 20:18 fred
drwxr-x--- 6 george george 4096 Feb 15 11:02 george
drwxr-x--- 6 ron ron 4096 Feb 15 11:23 ron
drwxr-x--- 6 root root 4096 Feb 15 11:23 startup
Теперь, перейдём в каталог "/var/www/fastcgi/startup", создадим скрипт запуска для пользователя fred (давайте назовём его fred-startup.sh), воспользовавшись любым текстовым редактором:

Скрипт оболочки:
#!/bin/sh

## АБСОЛЮТНЫЙ путь к двоичному файлу spawn-fcgi
SPAWNFCGI="/usr/bin/spawn-fcgi" 

## АБСОЛЮТНЫЙ путь к двоичному файлу PHP
FCGIPROGRAM="/usr/bin/php-cgi" 

## Прослушивание порта TCP на localhost
FCGISOCKET="/var/www/fastcgi/fred/fred.socket" 

## Раскомментируйте строку PHPRC, если имеется дополнительный файл php.ini для этого пользователя
## Положите этот файл php.ini в /var/www/fastcgi/fred/php.ini
## С помощью этого файла php.ini можно увеличить безопасность системы
## Просто настройте параметр open_basedir на веб-каталоги пользователей
## Например: (добавьте эту строку в ваш настроенный файл php.ini)
## open_basedir = /var/www/vhosts/fred/html
#PHPRC="/var/www/fastcgi/fred/" 

## Количество детей PHP порождаемых дополнительно к основным. Минимум 2.
## Действительное количество детей = PHP_FCGI_CHILDREN + 1
PHP_FCGI_CHILDREN=5

## Количество запросов выполненных сервером к одному процессу php, прежде чем этот процесс будет перезапущен
PHP_FCGI_MAX_REQUESTS=1000

## IP-адреса, с которых PHP должен принимать соединения серверов
FCGI_WEB_SERVER_ADDRS="127.0.0.1" 

# Доступные переменные окружения, разделённые пробелами
ALLOWED_ENV="PATH USER" 

## Если этот скрипт запускается от имени пользователя root, то fastcgi переключится на следующего пользователя:
USERID=fred
GROUPID=fred

################## После этой строки настроек нет
if test x$PHP_FCGI_CHILDREN = x; then
  PHP_FCGI_CHILDREN=5
fi
export PHP_FCGI_MAX_REQUESTS
export FCGI_WEB_SERVER_ADDRS
export PHPRC
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS PHPRC"

# Скопируем доступные переменные окружения
E=
for i in $ALLOWED_ENV; do
  E="$E $i=$(eval echo "\$$i")" 
done

# Очистим переменные окружения и настроим новые
env - $E $SPAWNFCGI -s $FCGISOCKET -f $FCGIPROGRAM -u $USERID -g $GROUPID -C $PHP_FCGI_CHILDREN
chmod 770 $FCGISOCKET
Будьте аккуратны с путями, USERID и GROUPID.

Отметим, что в этом примере процессы php запускаются от имени пользователя, созданного ранее ("fred"). Это означает, что код php будет иметь права доступа к файлам html и php. Это может быть удобно, но может быть менее безопасно.

В качестве альтернативы можно задать USERID значение "nobody" (или любого другого пользователя без каких-либо особых разрешений), чтобы запретить процессу php запись.

Нужно повторить процесс и создать скрипт запуска для каждого пользователя из каталога "/var/www/fastcgi/startup". (Просто скопируйте фалй и замените FCGISOCKET, USERID и GROUPID на правильные значения).

Не забудьте установить разрешения на выполнение всех скриптов запуска:

Выполним следующие команды:
# cd /var/www/fastcgi/startup
# chmod 750 *
5. Проверим настройку PHP

Если вы не знаете точно, где находится файл php.ini, просто выполните следующие команды:
$ php-cgi -i | grep php.ini
Удостоверьтесь, что в файле php.ini имеется следующая строка:
cgi.fix_pathinfo=1
Если вы раскомментировали строку PHPRC в скрипте из раздела 4, проверьте владельца и права доступа к файлу php.ini. Чтобы он использовался, нужно выполнить команды:
# chmod 644 php.ini
# chown root:root php.ini
6. Запустим все скрипты запуска FastCGI

Теперь запустим все процессы-серверы FastCGI, выполнив следующие команды:
# /var/www/fastcgi/startup/fred-startup.sh
spawn-fcgi.c.170: child spawned successfully: PID: xxxxx
# /var/www/fastcgi/startup/george-startup.sh
spawn-fcgi.c.170: child spawned successfully: PID: xxxxx
# /var/www/fastcgi/startup/ron-startup.sh
spawn-fcgi.c.170: child spawned successfully: PID: xxxxx
Если будут какие-то сообщения об ошибках, проверьте скрипты запуска и права доступа к каталогу "/var/www/fastcgi", включая все подкаталоги.

7. Настроим виртуальные узлы на сервере lighttpd

Отредактируем файл "/etc/lighttpd.conf" в любом текстовом редакторе:
...[некоторое количество строк конфигурации]...
$HTTP["host"] =~ "(^|\.)fred-weasley.com$" {
  server.document-root = "/var/www/vhosts/fred-weasley.com/html" 
  accesslog.filename = "/var/www/vhosts/fred-weasley.com/logs/access_log" 
  fastcgi.server = (
    ".php" => (
      (
        "socket" => "/var/www/fastcgi/fred/fred.socket",
        "broken-scriptfilename" => "enable" 
      )
    )
  )
}

$HTTP["host"] =~ "(^|\.)george-weasley.com$" {
  server.document-root = "/var/www/vhosts/george-weasley.com/html" 
  accesslog.filename = "/var/www/vhosts/george-weasley.com/logs/access_log" 
  fastcgi.server = (
    ".php" => (
      (
        "socket" => "/var/www/fastcgi/george/george.socket",
        "broken-scriptfilename" => "enable" 
      )
    )
  )
}

$HTTP["host"] =~ "(^|\.)ron-weasley.com$" {
  server.document-root = "/var/www/vhosts/ron-weasley.com/html" 
  accesslog.filename = "/var/www/vhosts/ron-weasley.com/logs/access_log" 
  fastcgi.server = (
    ".php" => (
      (
        "socket" => "/var/www/fastcgi/ron/ron.socket",
        "broken-scriptfilename" => "enable" 
      )
    )
  )
}
Обратите внимание на пути к сокетам FastCGI каждого виртуального узла.

Условные блоки НЕ оказывают действия на server.errorlog, все сообщения об ошибках попадают в последний указанный файл журнала. Поэтому используется один глобальный журнал.

8. Перезапустим процесс демона lighttpd

Просто выполним следующую команду:
# /etc/init.d/lighttpd restart
Если будут какие-то сообщения об ошибках, проверьте файл конфигурации "/etc/lighttpd.conf".

9. Здравствуй мир!

Теперь, войдём под пользователем fred и создадим скрипт PHP в его виртуальном узле (например, "/var/www/vhosts/fred-weasley.com/html/index.php"):
<?php
  echo "<h1>Здравствуй мир!</h1>";
  echo "<p>Идентификатор текущего пользователя: ". posix_getuid();
  echo "<p>Идентификатор текущей группы: ". posix_getgid();
?>
Убедитесь, что вы задали разрешения на доступ к файлу:

Выполните следующие команды:
# chown fred:fred /var/www/vhosts/fred-weasley.com/html/index.php
# chmod 640 /var/www/vhosts/fred-weasley.com/html/index.php
# ls -l /var/www/vhosts/fred-weasley.com/html
-rw-r----- 1 fred fred 116 Jul 25 2004 index.php
Теперь, запустим веб-браузер и проверим вывод скрипта PHP. (Здесь: http://www.fred-weasley.com/index.php)

Если всё хорошо, вы увидите страницу, на которой будут отображены идентификаторы пользователя и группы fred. (Вы можете увидеть эти идентификаторы в файлах "/etc/passwd" и "/etc/group").

10. Автоматический вызов скриптов запуска FastCGI

При желании можно также создать запись в планировщике задач crontab для автоматического вызова скриптов запуска FastCGI при загрузке сервера.

Воспользуемся следующей командой для редактирования заданий планировщика crontab:
# crontab -e
Теперь добавим следующую строку:
@reboot for i in /var/www/fastcgi/startup/*.sh; do $i; done
А затем введём ":x" для сохранения и выхода.

Эта запись в планировщике задач crontab выполнит все файлы с расширением .sh, найденные в каталоге /var/www/fastcgi/startup, после загрузки сервера.

Поздравляю! Теперь у вас есть быстрый сервер, настроенный с отдельными правами для пользователей.

Ограничения

Таким образом мы создали отдельные группы процессов fastcgi для каждого пользователя. Это означает, что у этих процессов нет общей памяти. Поэтому, если этот способ используется на компьютере с большим количеством пользователей, потребуется значительное количество доступной оперативной памяти. Также, если используется какой-нибудь кэш транслированного кода PHP, например, xcache, apc или eaccelerator, этот способ приведёт к созданию собственного кэша у каждого из пользователей (что полезно для повышения безопасности, но приводит к увеличению использования памяти). Можно уменьшить использование памяти с помощью файлов php.ini, в которых настроить ускоритель с разными объёмами кэша, а также изменить значение переменной PHP_FCGI_CHILDREN в каждом из пользовательских скриптов startup.sh.

В FreeBSD (6.2) каждый пользователь может состоять максимум в 14 группах. Этот верхний предел экземпляров fastcgi для виртуальных узлов, поскольку пользователю lighttpd (www) необходим доступ к этим сокетам. Я настроил мой веб-сервер 1-2 года назад этим способом и столкнулся с проблемой несколько недель назад, когда добавил пользователя www в пятнадцатую группу. Не было никаких сообщений об ошибках, иди-свищи ответа у google. Но всё-таки, есть ли решение? ;) Да, в FreeBSD 8.0 этот предел был поднят до 1024.

Разрешения

У mod_fastcgi имеется опция check-local. Если она включена, Lighttpd использует своего пользователя для проверки существования файла в document-root. Если вы хотите, чтобы пользователь Lighttpd не имел доступа к document-root, нужно отключить эту опцию.

пятница, 14 октября 2011 г.

Postfix maildir umask

Захотел написать небольшое веб-приложение для управления почтовым сервером. Одна из функций этого приложения - удаление почтового ящика из БД. Стандартная задача, которая обычно возникает при удалении почтового ящика, - это создать пересылку с удалённого адреса на другой и перенести уже принятые письма в каталог преемника.

Пример: сотрудник раздавал клиентам визитки со своим электронным адресом. Сотрудник уволился, но его электронную почту нужно обрабатывать, чтобы не потерять клиентов. Для этого можно создать пересылку на другой почтовый ящик, уже полученные письма перенести в почтовый ящик преемника, а сам почтовый ящик уволившегося сотрудника удалить.

Переносом писем по задумке должно заниматься веб-приложение, работающее с правами веб-сервера. Чтобы веб-сервер мог перенести письма, ему нужно иметь соответствующие права доступа. Для этого я включил пользователя www-data в группу vmail, затем дал группе vmail права rwx на каталоги почтовых ящиков.

Каталоги почтовых ящиков создаёт программа virtual почтовой системы Postfix. Можно задать uid и gid, с которыми будет работать эта программа. Это делается с помощью параметров virtual_uid и virtual_gid. Я для пробы решил создать один почтовый ящик и отправить на него письмо. virtual создал каталоги почтового ящика, но выставил для группы vmail права доступа, которые не позволяют ей делать ничего с этим ящиком.

Я прочитал man virtual в надежде найти какой-нибудь параметр вроде virtual_umask, но не нашёл. Попробовал выставить umask в файле /etc/init.d/postfix, перезапустил его, удалил каталог почтового ящика и снова отправил тестовое письмо. Каталог создался с теми же правами. В недоумении я стал искать в интернете, не сталкивался ли кто с такой же проблемой.

Оказалось - сталкивались. А параметра virtual_umask нет и не будет. Вьетце Венема аргументирует свою позицию тем, что он сисадмин с 20-летним стажем и доступ к письмам со стороны левых программ может отрицательно отразиться на безопасности почтовой системы. Никаких других доводов он слышать не желает. В том числе он не желает слышать о том, что система прав в Unix задумана такой не для того, чтобы искусственно обходить её стороной. Патчи, если кто такие и напишет, судя по молчанию Вьетце, приняты в основную ветку не будут.

Единственное приемлемое решение моей задачи, по мнению Вьетце Венема, - это забрать почту по протоколу POP из этого ящика и отправить её на другой ящик по протоколу SMTP.

У меня отношение к этому простое - безопасность ради безопасности не нужна. Я лучше постараюсь заменить Courier на какую-нибудь другую программу, которая сама умеет складывать письма в почтовые ящики и имеет собственный модуль доставки для Postfix или умеет работать по протоколу LMTP. В качестве замены исправно работающего много лет Courier воспользуюсь Dovecot.

В общем, если что - не удивляйтесь невменяемости этого уважаемого всеми товарища.

P.S. Настроил Dovecot вместо Courier и... всё то же самое. Настройка umask у Dovecot в прошлом была, но потом была удалена. Вместо неё придумали плагины для работы с общими почтовыми ящиками. Не смешно, но для такой простой операции, видимо, придётся воспользоваться чем-то вроде fetchmail. Хотя, можно воспользоваться sudo, в конфиге которой прописать одну строго ограниченную команду, можно сделать скрипт, работающий по cron'у, можно пропатчить сам Dovecot, а вот использование LMTP из Dovecot тоже не поможет.

вторник, 4 октября 2011 г.

Remmina

Сегодня вновь посмотрел на программу Remmina и на этот раз она мне понравилась, т.к. я нашёл в ней функцию подключения по протоколу RDP через SSH-туннель, а также нашёл удобный апплет для XFCE.

Сама Remmina в Debian находится в пакете remmina и по умолчанию поддерживает только протоколы SSH и SFTP. Плагин для подключения по RDP находится в пакете remmina-rdp, а апплет находится в пакете remmina-xfce.

Для начала поставим всё это хозяйство:
# apt-get install remmina remmina-rdp remmina-xfce
Разобраться в настройках легко, я просто покажу как она выглядит.

Главное окно Remmina:

Окно настройки RDP:


Окно настройки SSH:

Окно настройки SFTP:

Кусочек экрана с апплетом для XFCE:

Удалённый рабочий стол, открытый по протоколу RDP с помощью Remmina:

Теперь подключаться к удалённым компьютерам стало значительно удобнее!

понедельник, 3 октября 2011 г.

Программы, которыми я пользуюсь в Debian GNU/Linux

Решил выложить обновлённую заметку Программы, которыми я пользуюсь в Linux. С тех пор много воды утекло и теперь я пользуюсь другими программами.

Пользуюсь средой XFCE. До этого я пользовался KDE3, но эта ветка прекратила своё существование в пользу более новой - KDE4, которая мне не понравилась. Я последовательно перепробовал IceWM, затем LXDE, и остановился на XFCE, которым сейчас и пользуюсь. Смена графической среды повлекла за собой замену многих программ из лагеря KDE/Qt на аналогичные из лагеря Gnome/GTK.

Сеть:

1. Torrent-клиент - Transmission.
2. FTP-клиент

Iceweasel или Chromium - когда нужно просто скачать несколько файлов.

lftp или ncftp - когда я работаю в консоли или мне нужно работать с FTP-сервером из скрипта.

3. Web-браузер - Iceweasel или Chromium.
4. Почтовый клиент - пользуюсь GMail.
5. RDP-клиент - Remmina.
6. Эмулятор терминала - Terminal (пакет xfce4-terminal).
7. IM-клиент - Pidgin.

Раньше пользовался Psi. Сейчас стал пользоваться Pidgin по двум причинам:
1. America Online продала ICQ компании Mail.ru. Mail.ru поменяли политику - открыли протокол, перестали его менять, разрешили использовать альтернативные ICQ-клиенты. Поэтому я вновь стал пользоваться ICQ, в дополнение к Jabber.
2. KDE4 мне не понравился, поэтому с KDE3 я перешёл на XFCE. Для XFCE родным тулкитом является GTK, поэтому вместо логичного для KDE мультипротокольного клиента Kopete я выбрал Pidgin, который лучше подходит для XFCE.

Офисные программы:

1. Офисный пакет - Openoffice.org.

В дальнейшем, видимо, будет заменён на LibreOffice. Почему - я думаю понятно без объяснений.

2. Калькулятор - KCalc или bc.
3. Просмотр PDF, DjVu, PostScript - Evince.
4. Просмотр FB2 - fbreader.
5. Файловый менеджер - Thunar и bash.
6. Архиватор - Xarchiver или консольные tar, bzip2/bunzip2, gzip/gunzip, unzip, unrar.

Картинки:

1. Просмотр картинок - GPicView.
2. Редактор картинок - KolourPaint (альтернатив не искал, т.к. практически не пользуюсь).
3. Скриншоты - ScreenShooter из XFCE (пакет xfce4-screenshooter).

Мультимедиа:

1. CD-риппер - консольный риппер ripit.
2. Запись CD/DVD - K3b (увы, лучше него пока ничего не нашёл).
3. Аудио-плеер - DeadBeef.
4. Простановка тегов в музыкальных треках - ExFalso.
5. Видеоплеер - SMPlayer.

Разработка:

1. Редактор кода, в том числе C и HTML - Geany или vim-lite.
2. Текстовый редактор - LeafPad, MousePad.
3. Переводы страниц руководства - POEdit и po4a.

Разное:

1. Учёт личных финансов - GNUCash.

Ещё я пользуюсь рядом самописных и подсмотренных где-то скриптов. В частности это скрипты для конвертирования кодировок текстовых файлов (на основе iconv), конвертирования кодировок в тегах mp3-файлов (на основе mid3iconv из пакета python-mutagen), конвертирования из doc, rtf и html в текст (antidoc, unrtf и unhtml соответственно), скрипты переименования фотографий по EXIF-тегам (exiftool из пакета libimage-exiftool-perl), скрипты разбивки FLAC-файлов (shntool).

Я перестал пользоваться клиентами DC++, т.к. в уфанетовском хабе с некоторых пор наблюдается голяк. На первый план вышли torrent-трекеры.

Перестал пользоваться менеджером дисков Gnome Catalog, так как купил жёсткий диск на 1 Терабайт. Кроме того, запись дисков отнимает очень много времени, которого у меня теперь мало. Да и барахольщиком нынче быть не очень выгодно, т.к. тарифы на интернет стали очень дешёвыми - что угодно можно найти и быстро скачать из Интернета в любой момент.

Перестал вообще пользоваться двухпанельными менеджерами файлов. Это связано со предыдущими пунктами: дешёвые тарифы на интернет, распространение торрентов, объёмный жёсткий диск, нехватка времени - теперь реже нужно разгребать завалы файлов.

Перестал играть в компьютерные игры - нет времени. Стал читать вместо этого книги. Обычные, бумажные.

Изменения от 4 октября 2011:

Для просмотра PDF, PostScript и DjVu вместо программ KPDF, KGhostView и DjView4 теперь пользуюсь Evince.

Вместо FreeRDP теперь использую Remmina - менеджер подключений SSH, SFTP и RDP (и других, которыми не пользуюсь). Плагин RDP использует для подключения FreeRDP. Использую апплет Remmina для XFCE.