Seni: менеджер входа

Красивый вход на Wayland без GNOME и без «голой» сессии под гретером. Демон на Rust отвечает за безопасность, интерфейс на Vala выглядит как остальная система.

Зачем нужен Seni

Менеджер входа это первое, что видит пользователь, и одна из самых чувствительных частей системы: он работает с паролями и от имени root запускает сеанс. Для Atomic Niri нужен был вход, который:

  • красиво выглядит и работает на Wayland;
  • не требует GNOME: GDM слишком тесно связан с GNOME Shell;
  • не запускает ради картинки входа отдельную «голую» сессию niri, как это делает связка greetd и regreet;
  • подключён к PAM, а не изобретает свою проверку паролей;
  • не тревожит gnome-keyring в сессии гретера и нативно работает с niri.

Готового гретера, который подошёл бы по всем этим критериям, в природе не нашлось. Поэтому появился Seni: архитектура GDM, перенесённая на наш стек.

Почему Seni. «Сени» в русской избе это помещение у входа, через которое входят в дом. Для менеджера входа название подходит идеально: Seni это вход в систему.

Стек

Демон на Rust

Работает от root, написан на Rust (tokio и zbus). Там, где ошибка в коде значит повышение привилегий, нужна безопасность памяти.

Гретер на Vala

Интерфейс на Vala, GTK4 и libadwaita, нативный для GTK. Выглядит так же, как остальная система и панель Niti.

cage

Гретер запускается внутри cage: минимальный композитор Wayland для одного окна. Никакой лишней сессии рабочего стола.

PAM и D-Bus

Проверка пароля идёт через штатный PAM. Демон и гретер говорят по D-Bus, контракт описан в одном файле для обеих сторон.

Исходный код: Seni, лицензия GPL-2.0 или новее. Перенесённые из GDM приёмы сохраняют указание авторства в шапках файлов.

Как проходит вход

  1. Загрузкаsystemd запускает seni.service, демон следит за рабочими местами через logind и ждёт графическое место (seat).
  2. ГретерНа каждом графическом месте демон запускает cage seni-greeter от отдельного пользователя _greeter. Упавший гретер запускается заново.
  3. Проверка пароляГретер передаёт пароль демону по D-Bus, а демон проверяет его через PAM. Пароль не попадает в аргументы процессов.
  4. СессияПосле успеха демон открывает сессию PAM, сбрасывает привилегии до выбранного пользователя и запускает niri.

Безопасность

Принцип проекта: безопасность через PAM важнее всего остального. Любая новая поверхность проверки пароля обязана идти через PAM, а не в обход и не самодельно.

  • Rust в привилегированной части. Демон работает от root, и ошибки памяти там были бы опасны. Rust устраняет их целыми классами.
  • Только штатный PAM. Демон сам не хранит и не сравнивает пароли. Проверку выполняет стек PAM системы (в ALT это pam_tcb), а привязка к PAM написана вручную на несколько десятков строк без тяжёлых зависимостей.
  • Пароль не светится. Пароль передаётся через каналы, а не через аргументы командной строки, где его видно в /proc. Строка с паролем затирается в памяти при освобождении.
  • Гретер без прав. Интерфейс входа работает от пользователя _greeter, а не от root. Привилегированную часть выполняет только демон.
  • Один вход, один PAM-дескриптор. Проверка пароля и открытие сессии идут одним вызовом PAM, а не в долгоживущем демоне и не во втором дескрипторе.
  • Защита от перебора. В образе включён pam_faillock: после 10 неудачных попыток за 15 минут учётная запись блокируется на 5 минут. Это относится ко входу, разблокировке экрана, sudo и su. Root не блокируется.
  • Проверки в CI. Тесты на Rust, сквозная проверка D-Bus от запроса до завершения проверки пароля и статический поиск опасных шаблонов в коде на Vala.

Защита от перебора и счётчик попыток относятся ко всему образу, а не только к Seni: это системная политика PAM. Описание в документации образа: «Ограничение попыток пароля».

Что умеет

Быстрый вход

Для последнего вошедшего пользователя сразу показывается поле пароля, «Другой пользователь» это маленькая ссылка. Запоминаются и тема, и последний пользователь.

Выбор сессии

Шестерёнка в углу открывает выбор сессии. Сейчас одна, niri, но место уже готово под другие, например игровую.

Питание

Выключить и перезагрузить прямо с экрана входа.

Тот же вид, что у Niti

Часы и значки состояния в стиле панели Niti, обои с размытием и цвета, подхваченные из палитры рабочего стола.

Несколько мониторов и мест

Гретер показывается на всех мониторах. Для нескольких рабочих мест (multi-seat) запускается отдельный гретер на каждое.

Автовход

Для киоска или Live ISO можно включить автоматический вход: строка имя boot в /etc/seni/autologin входит один раз за загрузку. Root не подходит никогда.

Экран блокировки

К Seni относится и экран блокировки seni-lockscreen. Он использует протокол ext-session-lock-v1 и работает внутри уже запущенной сессии niri, как swaylock или hyprlock. Закрывает все мониторы и запрашивает пароль.

  • Пароль проверяет вспомогательная программа seni-unlock-helper через отдельный PAM-сервис seni-unlock. Новая сессия при этом не открывается.
  • Помощник проверяет только вашу собственную учётную запись и запускается с правами группы chkpwd (так в ALT принято для блокировщиков), а не от root.
  • Сам ничего не запускает: подключается снаружи, по сочетанию клавиш (например Super+L) или через swayidle перед сном и по таймеру бездействия.

Настройка

ФайлЧто в нём
/etc/seni/greeter.jsonОбои, размытие и его сила, цветовая схема
/etc/seni/autologinУчётные записи с автовходом. Строка имя boot входит при загрузке
/etc/seni/colors.cssЦвета гретера. Создаётся автоматически из палитры рабочего стола при старте демона

Настройки гретера планируется вынести в отдельную страницу Tuner.

Чего пока нет

  • Вход пользователей из доменов (SSSD, IPA): демон читает список локальных пользователей, ручного ввода имени нет. Поддержка в планах.
  • Настройки гретера пока только в файле, без графического интерфейса.

Для разработчиков

Seni собирается в контейнере: Rust-демон через cargo, гретер и экран блокировки через meson. Гретер можно проверить без реального железа: cage умеет работать без экрана (WLR_BACKENDS=headless), а скриншот снимает grim.