Автор Тема: Ограниченные права установки пакетов  (Прочитано 4274 раз)

0 Пользователей и 1 Гость просматривают эту тему.

leva

  • *
  • Сообщений: 5
  • Karma: +0/-0
Часто Debian (Ubuntu и др.) ставиться на машину, на которой работают несколько пользователей, часто не знающих пароль root'a. Для выполнения своей повседневной работы этих юзеров можно включать в группы. Например, audio - для работы с ALSA, dip - для дозвона, plugdev - для монтирования внешних ЗУ. Часто, с помощью sudo, можно дать юзеру некоторые специфические права.

Но беда в том, что новые программы (пакет) рядовой юзер установить не может. Конечно, многие пакеты слишком системны для того, чтобы их ставить рядовыми юзерами. Многие пакеты в корне меняют принципы загрузки/работы системы, например, kdm (зависимость зависимости kdebase) после инсталляции установит графичекий login. Установка многих пакетов может повредить системе только из-за того, что пользователь может дать плохие ответы на вопросы Debconf'а. Например, инсталляция пакета sash при конфигурации Debconf'ом предлагает создать sashroot (ещё одного пользователя с uid=0 т.е. администратора) и задать ему пароль!

Часто обычному пользователю и даже разработчику такие вещи не нужны. Но такой пользователь хотел бы иметь возможность установить доки или книги (например, c++-annotations), вьюверы для их прочтения (например, kpdf, kdvi), различные библиотеки (скомпилированные *.so и headerы), любимые addonы к браузеру, учебные программы, локализации.

Я сделал попытку решить эту проблему, написав на sh пока очень кривой скрипт. Надеюсь, что сама идея будет кому-нибудь интересна.

leva

  • *
  • Сообщений: 5
  • Karma: +0/-0
(Нет темы)
« Ответ #1 : 28 Октября 2008, 08:53 »
Сам скрипт можно посмотреть на http://http://rapidshare.com/files/157744696/limited-apt-install. Скрипт предоставляет собой очень ограничивающий вариант "aptitude install", используя последний как backend. Поэтому его нужно прописать в sudo:
Cmnd_Alias  APTINSTALL = /usr/local/bin/limited-apt-install *
%aptinstallers LOCAL = APTINSTALL
aptinstallers - это и есть группа тех пользователей, которые могут ставить "несистемные" пакеты.

Синтаксис команды простой: limited-apt-install <package1> <package2> ... <packageN>
Раз "aptitude install" используется как backend, то становятся возможной не только инсталляция пакетов, но также:
<package>+M - инсталлировать и сразу же пометить как автоматически установленный.
<package>- - деисталлировать.
<package>_ - purge.
<package>= - зоморозить версию (чтобы не обновлялся сейчас и в будущем).
<package>: - зоморозить версию (чтобы сейчас не обновлялся).
<package>&M - пометить как автоматически установленный.
<package>&m - пометить как установленный вручную.

Пример: sudo limited-apt-install iptables- sudo_
Очевидно, что все эти дополнительные возможности нужно запретить. Для этого я сделал регулярное выражение:NAMEREGEXP="^[a-z0-9][a-z0-9+.-]*[a-z0-9+]$", на соответствие которому скрипт проверяет имена пакетов, перечисленные как аргументы команды limited-apt-install. Оно запрещает символы -,_,=,:,&M,&m на конце.

Теперь подходим к самому главному. Нужно проверить, не является ли пакет, желаемый для установки пользователем, слишком системным. Я реализовал это используя debtags. Я просто запрещаю пакеты, имеющие tagи из фасетов "admin", "hardware" и "security":
# Checks if package is system (and dangerous for install by ordinary user).
#
# Current variation relys on debtags
IsPackageDangerous()
{
    PACKAGENAME=$1

    DANGEROUSFACETS="admin hardware security"

    for LINE in `debtags tag ls $PACKAGENAME`; do
        FACET=`echo $LINE | awk -F:: '{print $1}'`
        for DANGEROUSFACET in $DANGEROUSFACETS; do
            if [ $FACET = $DANGEROUSFACET ]; then
                echo "E: Package """$PACKAGENAME""" is dangerous! ""(""$FACET"")"
                return 1
            fi
        done
    done

    return 0
}
Я прекрасно понимаю недостатки своего решения:
    Таги не могут помочь правильно отличить системный (опасный) пакет от несистемного. Таги предназначены для поиска!
    Maintainerы могут выложить пакет в дистрибутив, не успев дать таги
    Фасет или таг может быть ещё не придуман
    Сама концепция "запретить всё кроме" является порочной по своей сути
Я думаю, что нужно просто составить список несистемных пакетов и проверять, есть ли в нём имя данного пакета. Тем более, что пакетов в Debianе немного (около 27000).

Также необходимо удостовериться, что желаемый пакет будем установлен из нужного (используемого администратором) дистрибутива (suite). Это предотвратит от установки пользователем чего-нибудь из experimental  :). Для этого, в первую очередь, нужно явно указать suite для команды "aptitude install":SUITE="testing"
INSTALLEROPTIONS="--target-release ""$SUITE" # used to explicitly indicate suite
aptitude $INSTALLEROPTIONS install $ALLPARAMS
. Но, к примеру, если желаемого пакета нет testingе, то "aptitude install" установит его из unstable. Поэтому нужно обязательно проверять, есть ли какая-нибудь версия этого пакета в нужном дистрибутиве. Это можно сделать так:# Checks if our suite contains given package otherwise aptitude will install this package from other suite.
# This will prevent system to be inadequate versions installed on.
CheckSuiteHasPackage()
{
    PACKAGENAME=$1

    NOGIVENSUITESTR="No ""$SUITE"" version"
    #TODO: use $NOGIVENSUITESTR variable
    if
        apt-show-versions -a -p $PACKAGENAME | grep 'No testing version' > /dev/null 2>&1
    then
        echo "E: There are no version in suite ""$SUITE"" for package: """$PACKAGENAME"""."
        return 1
    else
        return 0
    fi
}

leva

  • *
  • Сообщений: 5
  • Karma: +0/-0
(Нет темы)
« Ответ #2 : 30 Октября 2008, 12:49 »
Но вот в чём главная трудность: "aptitude install" устанавливает пакеты с их зависимостями (также рекомендуемыми и предлагаемыми пакетами (в зависимости от настроек пользователя)). Поэтому необходимо проверять на "несистемность" и наличие в нужном дистрибутиве не только сами пакеты (параметры командной строки), но и всё дерево их зависимостей, которые aptitude захочет установить! Например, пакет phpbb3 - несистемный (с точки зрения моей функции IsPackageDangerous()), но он зависит от пакета dbconfig-common, который имеет таги admin::configuring и admin::package-management.

Первая идея, которая пришла мне в голову заключается в том, что нужно рекурсивно (используя output комманды "apt-cache depends") проверять на несистемность все неустановленные зависимости. Тогда, конечно, необходимо проверять всё дерево зависимостей и на конфликты: конфликтует ли пакет с каким-нибудь уже установленным. Разумеется, такие конфликты допускать нельзя, иначе пользователь сможет деинсталлировать некоторые пакеты.

Но здесь есть подводные камни, и этот метод правильно работать не будет! Во первых, среди пакетов пользователя (или из зависимостей) могут быть виртуальные, которые "aptitude install"' может заменить на реальные, но ... их зависимости нельзя узнать. Во вторых, мы не знаем будет ли "aptitude install" автоматически ставить рекомендуемые и предлагаемые пакеты (это зависит от насктроек). В третьих, некоторые пакеты aptitudом могут быть брошены или downgraded.

Из-за этого я отбросил первую идею и решить полностью положиться на output команды "aptitude install". Её нужно заранее запускать с опциями --simulate (чтобы она не начала инсталлировать, пока скрипт ещё ничего не проверил) и --assume-yes (чтобы не задавала вопросов).

Сторока за строкой я читаю вывод комманды aptitude $INSTALLEROPTIONS --simulate --assume-yes install $ALLPARAMS и ищю, где начинается и где кончается список пакетов для инсталляции, проверяя сообщения команды "aptitudе install". Для этого мне даже пришлось составить список сообщений:    INSTALLEDPRELIMINARYSTR="The following NEW packages will be installed:"
    REMOVEDPRELIMINARYSTR="The following packages will be REMOVED:"
    BROKENPRELIMINARYSTR="The following packages are BROKEN:"
    UPGRADEDPRELIMINARYSTR="The following packages will be upgraded:"
    DOWNGRADEDPRELIMINARYSTR="The following packages will be DOWNGRADED:"
Найденные строки с пакетами для установки нужно парсить и удалять из них флаги (типа {a}), после чего проверять их на "несистемность" и наличие в нужном дистрибутиве. Удобно то, что "aptitude install" сам составит полное дерево зависимостей так, как ему угодно, и выведет его в стандартный поток вывода. Тут же можно и проверить, собирается ли "aptitude install" что-либо деисталлировать, бросать или даунгрэйдить (из-за конфликтов). Читайте код функции CheckSafetyOfAllInstalledPackages() в моём скрипте (ссылка выше).

Я прекрасно понимаю, что моя реализации жутко кривая :(. Конечно, нельзя полагать на output, который предназначен только для удобства пользователя и его формат может быть изменён. Код функции выглядит даже как-то маразматически.

leva

  • *
  • Сообщений: 5
  • Karma: +0/-0
(Нет темы)
« Ответ #3 : 30 Октября 2008, 01:21 »
Но, я думаю, что моя идея будет кому-нибудь интересна.

Думаю, что её можно правильно реализовать, используя, какие-нибудь API APTа (может быть, python-apt).

Недостаток идеи в том, что пользователь сможет инсталлировать пакет, но не сможет его позже деинсталлировать. Но я думаю, что и эту проблему можно решить. Можно создать список пакетов, которые (не включая зависимости) поставил с помощью limited-apt-install данный пользователь, и разрешить ему деинсталлировать только эти пакеты. Правда я не знаю как узнать из скрипта имя пользователя, который запустил данный скрипт через sudo. :?:

Можно реализовать и что-то вроде подсчёта ссылок. Для этого нужно разрешить пользователю A устанавливать пакет, если он уже установлен пользователем B (вместо инсталляции тогда нужно будет просто добавить пакет в список пользователя B). При "деинсталляции" имя пакета нужно просто удалять из списка данного пользователя. А когда имя пакета удалено из списков всех пользователей, нужно деинсталлировать пакет физически.

leva

  • *
  • Сообщений: 5
  • Karma: +0/-0
(Нет темы)
« Ответ #4 : 30 Октября 2008, 01:51 »
Немного порассуждаю о безопасности подобной штуки...

При инсталляции (иногда и при обновлении) некоторых пакетов Debconf задаёт вопросы пользователю. Что сделать, чтобы пользователь не наконфигурировал абы-что и чтобы данная конфигурация не ущемила безопасность системы? Может быть нужно поднять наименьший приоритет вопросов Debconfа до critical для данной инсталляции (это можно сделать используя переменную окружения $DEBIAN_PRIORITY)? Может быть давать ответы на вопросы в noninteractive-режиме, используя готовые базы ответов?

А вот сейчас мне пришла ещё одна интересная идея. Что если вообще оставлять пакет несконфигурированным (лучше, наверное, задать какие-нибудь умолчания), а оставить конфигурирование администратору. Можно, например, отправлять ему почтовое сообщение с именами пакетов, которые нужно сконфигурировать Debconfом.

Ещё одна проблема: что будет, если по какой-нибудь причине пакет останется "наполовину установленным" (в состоянии half-installed, unpacked или half-configured)?

Как я уже говорил, нужно научиться правильно отличать "несистемные" (безопасные для установки рядовым пользователем) пакеты от "системных". Для этого можно просто составить список "несистемных" пакетов.

Конечно, необходимо чтобы все инсталлируемые пакеты были подписаны цифровой подписью, иначе пользователь сможет подменить пакет с помощью сложных сетевых манипуляций.