---
tags: [linux, security]
verified: 2026-09-02
---

# Linux — пользователи, группы, PAM и systemd-logind

## Обзор

Вопрос «кто может войти в систему и что ему при этом полагается» в Linux разложен на три слоя, которые живут почти независимо и обычно смешиваются в голове в один. Первый отвечает за то, **что такое пользователь**: набор записей с числовыми идентификаторами, лежащих в файлах или приходящих из каталога. Второй — за то, **как принимается решение пустить**: стек модулей PAM, вызываемый программой входа. Третий — за то, **что происходит после**: сессия, её ресурсы и судьба процессов, которыми управляет `systemd-logind`.

Смешение слоёв объясняет большую часть недоумений. Пользователь есть в `/etc/passwd`, но войти не может — вопрос ко второму слою. Пароль принят, а команда сразу завершается — к первому (оболочка `nologin`). Вход прошёл, но фоновый процесс умирает при выходе — к третьему. Правка в `/etc/pam.d/` дала не тот результат — почти всегда к порядку строк, а не к самому модулю.

Статья идёт по этим слоям снизу вверх. Особое внимание — PAM: это единственный из трёх, где неверная правка стоит потери доступа к машине, и единственный, чья модель вычисления результата неочевидна настолько, что «поправить по аналогии» регулярно даёт противоположный эффект.

Версии-якоря: Linux-PAM 1.7, shadow-utils 4.20, systemd 261. Там, где поведение зависит от дистрибутива или менялось между версиями, это сказано явно — это как раз та тема, где умолчания Debian и Fedora расходятся, а документация описывает upstream.

## Учётные записи

### UID — единственное, что видит ядро

Ядро не знает имён пользователей. Оно оперирует числами: у процесса есть UID и GID, у файла — владелец и группа, тоже числа. Имя `alice` существует исключительно в пространстве пользователя, как результат поиска по числу в какой-нибудь базе.

Из этого следуют вещи, которые иначе выглядят странностями:

- Две записи с одним UID и разными именами — для ядра **один и тот же** пользователь. Права разделяются полностью; это иногда используют намеренно (второй root с UID 0 под другим именем), и это же изредка получается по ошибке.
- Удаление пользователя не меняет владельца его файлов. Владелец остаётся числом, и `ls -l` начинает показывать голый UID вместо имени. Следующий созданный пользователь, получивший тот же номер, унаследует чужие файлы.
- Переименование пользователя ничего не ломает: файлы принадлежат числу, а не имени.

### Три файла

```text
/etc/passwd   alice:x:1000:1000:Alice:/home/alice:/bin/bash
              имя :пароль:UID:GID:GECOS:домашний каталог:оболочка

/etc/shadow   alice:$y$j9T$...:20304::::::
              имя:хеш:смена:мин:макс:предупр:неактив:истечение:резерв

/etc/group    developers:x:1001:alice,bob
              имя:пароль:GID:список дополнительных членов
```

Разделение `passwd` и `shadow` историческое, но существенное: `/etc/passwd` обязан быть читаем всем (иначе `ls -l` не покажет имена), а хеши паролей в общедоступном файле — это офлайновый перебор. Поэтому `x` во втором поле означает «смотри в `/etc/shadow`», доступный только root.

В полях `shadow` стоит разобраться отдельно, потому что через них выражается устаревание паролей. Второе поле — хеш, третье — дата последней смены в днях от 1970-01-01, дальше — минимальный и максимальный возраст пароля, срок предупреждения, срок неактивности и дата истечения учётной записи. Ноль в поле даты смены означает «сменить при следующем входе», пустое поле — устаревание отключено.

Заметное изменение: в shadow-utils 4.20 поле минимального возраста пароля объявлено устаревшим — документация говорит, что оно должно быть пустым и игнорируется. Заодно убраны сами инструменты: `chage -m`, `passwd -n` и переменная `PASS_MIN_DAYS` в `login.defs` больше не существуют, и указание любого из них теперь завершается ошибкой, а не предупреждением. Следом помечены устаревшими и остальные поля устаревания — `sp_max`, `sp_warn`, `sp_inact` вместе с `chage -M`, `-W` и `-I`; upstream ссылается на NIST SP 800-63B, который прямо запрещает требовать периодическую смену пароля. Arch перешёл на 4.20 летом 2026 года, в стабильных дистрибутивах живут более старые ветки, так что на конкретной машине проверять надо свою.

Управлять этим руками не нужно, для всего есть команды:

```bash
chage -l alice                  # показать параметры устаревания
chage -E 2026-12-31 alice       # учётная запись истекает в конце года
passwd -l alice                 # заблокировать пароль
passwd -S alice                 # статус: L/P/NP — заблокирован/пароль/без пароля
```

### Заблокирован, без пароля и «пароль не подойдёт»

Три состояния поля пароля различаются, и разница практическая. Восклицательный знак в начале означает **заблокированный** пароль: `passwd -l` просто дописывает `!` перед хешем, и снятие блокировки возвращает прежний пароль. Звёздочка означает, что подобрать пароль невозможно в принципе — никакой ввод не даёт такой хеш; так помечают системные учётные записи. Пустое поле означает вход **без пароля** — и это ровно то, чего никогда не должно случиться на работающей системе.

Важная тонкость: ни `!`, ни `*` не запрещают вход **другими способами**. Заблокированная парольная аутентификация не мешает войти по SSH-ключу. Чтобы действительно закрыть учётную запись, меняют оболочку или ставят дату истечения.

### Системные и обычные пользователи

Граница — договорённость, выраженная в `/etc/login.defs`. По умолчанию обычные пользователи получают UID из диапазона `UID_MIN`–`UID_MAX`, то есть 1000–60000, а системные — из `SYS_UID_MIN`–`SYS_UID_MAX`, где нижняя граница по умолчанию 101, а верхняя — `UID_MIN` минус единица. Дистрибутивы эти числа подправляют, но порядок величин сохраняют.

Системным учётным записям обычно ставят оболочку `/usr/sbin/nologin`. Разница между ней и `/bin/false` небольшая, но осмысленная: `nologin` печатает вежливое сообщение и завершается с ненулевым кодом, `false` молча завершается. Сообщение настраивается через `/etc/nologin.txt`, и в логах его наличие помогает понять, что вход отвергла именно оболочка, а не аутентификация.

### Хеши паролей

Формат поля — `$идентификатор$параметры$соль$хеш`. Что встречается сегодня:

| Префикс | Алгоритм | Комментарий |
|---------|----------|-------------|
| `$y$` | yescrypt | умолчание в Debian, Ubuntu и Fedora; устойчив к перебору на GPU |
| `$6$` | sha512crypt | долгое время стандарт, upstream-умолчание shadow-utils |
| `$2b$` | bcrypt | распространён в приложениях, в системном `shadow` реже |
| `$1$` | md5crypt | безнадёжно устарел, встречается на древних системах |

Алгоритм задаётся параметром `ENCRYPT_METHOD` в `/etc/login.defs`, который принимает `BCRYPT`, `SHA256`, `SHA512` или `YESCRYPT`. Здесь снова расходятся upstream и дистрибутивы: в самом shadow-utils умолчание — `SHA512`, а Debian и производные ставят `YESCRYPT` в своём `login.defs`. Отсюда встречающаяся на практике пёстрая картина: на одной машине в `/etc/shadow` соседствуют записи с `$6$` и `$y$` — старые учётные записи сохраняют прежний хеш до следующей смены пароля.

### nsswitch.conf: откуда вообще берутся пользователи

Предположение «пользователи лежат в `/etc/passwd`» верно ровно до первой машины, подключённой к каталогу. Что именно является источником, определяет `/etc/nsswitch.conf`:

```conf
passwd:     files systemd sss
group:      files systemd sss
shadow:     files
hosts:      files resolve [!UNAVAIL=return] dns
```

Источники опрашиваются слева направо. `files` — привычные текстовые файлы, `sss` — SSSD, то есть LDAP, Active Directory или FreeIPA, `systemd` — модуль `nss-systemd`.

Последний стоит знать даже на машине без каталогов. Он отвечает за пользователей, которых нет ни в одном файле: динамические учётные записи сервисов с `DynamicUser=`, учётные записи `systemd-homed`, записи из JSON-файлов в `/etc/userdb/`. Он же гарантирует, что `root` и `nobody` остаются разрешимыми, даже если `/etc/passwd` повреждён или отсутствует. Документация рекомендует ставить `systemd` **после** `files`, чтобы файлы имели приоритет.

Практический вывод один, и он важнее остальных: **проверять пользователей нужно через `getent`, а не через `grep` по файлу**.

```bash
getent passwd alice          # спросит все источники по порядку
getent group developers
getent passwd | wc -l        # все видимые записи, включая каталог
id alice                     # UID, GID и полный список групп
```

`grep alice /etc/passwd` ничего не найдёт для доменного пользователя, который при этом прекрасно входит в систему, — и это регулярный источник путаницы при разборе чужой инфраструктуры.

## PAM

### Зачем он есть

До PAM каждая программа, проверявшая пароль, делала это сама: читала `/etc/shadow`, вычисляла хеш, сравнивала. Добавить в систему двухфакторную аутентификацию или LDAP означало пропатчить `login`, `su`, `sshd`, `ftpd` и всё остальное.

PAM (Pluggable Authentication Modules) выносит эту логику в разделяемые библиотеки, вызываемые через общий интерфейс. Программа говорит «аутентифицируй пользователя», а из каких модулей это сложится — вопрос конфигурации в `/etc/pam.d/`, где на каждый сервис приходится файл со своим именем.

### Четыре независимых стека

Первое, что нужно уложить в голове: типов не четыре фазы одного процесса, а **четыре независимых стека**, каждый со своим набором строк и своим результатом.

| Тип | Отвечает за | Типичное содержимое |
|-----|-------------|---------------------|
| `auth` | доказательство личности | проверка пароля, токен, отпечаток |
| `account` | право входить **сейчас** | срок действия записи, время суток, источник |
| `password` | смену пароля | требования к сложности, запись нового хеша |
| `session` | обвязку сессии | монтирование домашнего каталога, лимиты, логирование |

Успешная аутентификация ничего не говорит о том, что вход разрешён: `account` может отвергнуть пользователя с истёкшей записью, у которого пароль абсолютно верный. Симптом «пароль принимается, но вход не проходит» — это почти всегда `account`, а не `auth`, и искать надо в другом стеке.

### Флаги управления и почему порядок критичен

Каждая строка — это тип, флаг управления, модуль и его параметры:

```conf
auth    required    pam_unix.so    try_first_pass
```

Флагов четыре, и их семантика неочевидна:

| Флаг | При неудаче модуля | При успехе |
|------|--------------------|------------|
| `required` | стек **продолжается**, но итог уже провален | продолжается |
| `requisite` | немедленный выход с ошибкой | продолжается |
| `sufficient` | игнорируется, стек продолжается | немедленный успех, если раньше не падал `required` |
| `optional` | важно только если модуль в стеке единственный | то же |

Главная неочевидность — `required`. Провал не прерывает стек: остальные модули всё равно отработают, а отказ вернётся в конце. Сделано это намеренно, чтобы по времени ответа и поведению нельзя было определить, на каком именно шаге вход отвергнут. `requisite` ведёт себя «как ожидается» и прерывает сразу — его используют там, где продолжать бессмысленно или опасно.

Второй источник ошибок — `sufficient`. Он даёт немедленный успех **только если ни один предшествующий `required` не провалился**. Отсюда прямое следствие: `sufficient`, поставленный выше нужного `required`, открывает вход в обход проверки, а поставленный ниже — может не сработать вовсе. Порядок строк здесь не стилистика, а логика.

Полезно знать, что простые флаги — это сокращения. Документация приводит точные соответствия:

```text
required    [success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite   [success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient  [success=done new_authtok_reqd=done default=ignore]
optional    [success=ok new_authtok_reqd=ok default=ignore]
```

Развёрнутая форма `[значение=действие ...]` умеет больше: `die` — прервать с ошибкой, `done` — прервать с успехом, `ignore` — не влиять на итог, а число означает «пропустить столько следующих строк». Именно числовые переходы делают сложные стеки нечитаемыми, и именно они встречаются в конфигурации, которую генерируют дистрибутивные инструменты.

### include и substack

Строки не пишут заново для каждого сервиса — общие куски выносят. Debian и производные держат их в `common-auth`, `common-account`, `common-password`, `common-session`; RHEL и Fedora — в `system-auth` и `password-auth`.

Разница между двумя способами подключения тонкая, но иногда решающая. `include` вставляет строки так, будто они написаны здесь: переход `die` внутри включённого файла обрывает **весь** стек. `substack` изолирует: `done` и `die` внутри прерывают только вложенный стек, числовые переходы не выпрыгивают наружу, а сам подстек снаружи считается одним модулем при подсчёте пропускаемых строк.

Практически это значит, что заменять `include` на `substack` (и наоборот) «для порядка» нельзя — меняется поведение при отказах.

### Разбор реального стека

Пример из документации `pam_faillock` — хорошая иллюстрация того, как выглядит настоящая конфигурация:

```conf
auth     required                pam_securetty.so
auth     required                pam_env.so
auth     required                pam_nologin.so
auth     [success=1 default=bad] pam_unix.so
auth     [default=die]           pam_faillock.so authfail
auth     sufficient              pam_faillock.so authsucc
auth     required                pam_deny.so
```

Читается это так. Три первых модуля — предварительные проверки: терминал, окружение, наличие файла `/etc/nologin`. Дальше `pam_unix` проверяет пароль, и здесь начинается интересное: при успехе (`success=1`) пропускается **одна** следующая строка, то есть управление уходит на `pam_faillock authsucc`, который сбрасывает счётчик неудач и возвращает успех. При неудаче срабатывает `default=bad`, выполнение доходит до `pam_faillock authfail`, тот записывает неудачную попытку и обрывает стек через `default=die`.

Завершающий `pam_deny.so` — обязательный элемент: он гарантирует отказ, если управление дошло до конца стека, не встретив успеха. Стек `auth`, заканчивающийся ничем, вернул бы успех.

Из этого разбора видно, почему «добавить строку в `/etc/pam.d/`» — операция с последствиями. Вставка строки в середину сдвигает всё, на что указывают числовые переходы, и `success=1` начинает пропускать не тот модуль.

### Модули, которые встречаются постоянно

`pam_unix` — классическая проверка по `/etc/shadow`; он же участвует в смене пароля и в стеке сессии.

`pam_faillock` блокирует учётную запись после нескольких неудачных попыток; настраивается через `/etc/security/faillock.conf`. Пришёл на смену `pam_tally2`. Существенная деталь: root по умолчанию не блокируется, и это не недосмотр, а защита от отказа в обслуживании — иначе любой желающий мог бы запереть администратора снаружи, просто перебирая пароль root.

```bash
faillock --user alice            # показать неудачные попытки
faillock --user alice --reset    # сбросить счётчик
```

`pam_limits` применяет ограничения ресурсов из `/etc/security/limits.conf` и `limits.d/` — количество открытых файлов, процессов, размер памяти. Работает в стеке `session`, и отсюда типичная ловушка: лимиты применяются к сессиям входа, но не к сервисам systemd — у тех свои директивы в юнит-файлах.

`pam_systemd` регистрирует сессию в `logind`, без него не будет ни `XDG_RUNTIME_DIR`, ни корректного учёта сессий. Тоже в `session`.

`pam_env` расставляет переменные окружения из `/etc/environment` и `/etc/security/pam_env.conf`.

### Отладка без потери доступа

PAM — то место, где ошибка блокирует вход **всем**, включая вас. Правило одно, и оно не обсуждается: **держать вторую открытую сессию с правами root на протяжении всей правки** и проверять вход в третьей, не закрывая первые две. Уже открытая сессия переживает поломку конфигурации: PAM вычисляется при входе, а не постоянно.

```bash
# Терминал 1 — открыт, root, ничего не трогаем: это путь к откату
# Терминал 2 — правим конфигурацию
# Терминал 3 — проверяем вход
ssh -v user@host
```

Проверить стек, не подключаясь, помогает `pamtester` (пакет с тем же именем):

```bash
pamtester sshd alice authenticate       # прогнать стек auth сервиса sshd
pamtester -v login alice acct_mgmt      # проверить стек account
```

Отладочный вывод самих модулей включается параметром `debug` в строке и уходит в системный журнал:

```bash
journalctl -f -t sshd -t sudo -t su
journalctl _COMM=sshd --since "5 min ago"
```

Отдельно стоит помнить про `/etc/nologin`: если файл существует, `pam_nologin` не пустит никого, кроме root. Смотрит модуль и в `/run/nologin` — именно его `systemd-user-sessions.service` создаёт перед выключением и снимает после загрузки, так что искать надо оба. Файл иногда остаётся после неудачного завершения работы системы и выглядит как загадочный отказ во входе при заведомо верном пароле.

## systemd-logind

### Сессии и seats

`logind` учитывает, кто и как вошёл. Единица учёта — сессия; сессии группируются по **seat** — комплекту физических устройств ввода-вывода, обычно единственному (`seat0`). Каждой сессии соответствует cgroup, что и позволяет отслеживать её процессы как целое.

```bash
loginctl list-sessions
loginctl show-session 3 -p Type -p Remote -p Active
loginctl user-status alice
loginctl terminate-session 3
```

### Почему процессы умирают при выходе

Классический сюрприз: запустили долгую задачу, вышли из SSH, вернулись — процесса нет. Причина в `KillUserProcesses`: при значении `yes` cgroup сессии уничтожается вместе со всеми процессами при выходе.

Здесь важное расхождение, объясняющее противоречивые советы в интернете. Upstream-умолчание — `yes`, оно появилось в systemd 230 (май 2016) и вызвало заметный скандал именно потому, что ломало `screen`, `tmux` и `ssh-agent`. Debian вернул `no` в своей сборке, и производные унаследовали это. Поэтому на Debian и Ubuntu процессы обычно выживают, а на системах со сборкой по умолчанию — нет.

Проверить, что у вас:

```bash
loginctl show-session --property=KillUserProcesses   # без аргумента — свойства менеджера
```

Чинить это выключением `KillUserProcesses` — плохой путь: настройка глобальная и отключает учёт ресурсов сессии целиком. Правильных способов два.

**Linger** — разрешить пользователю иметь процессы вне сессий. Тогда для него постоянно работает экземпляр `user@UID.service`, живущий независимо от входов и выходов:

```bash
loginctl enable-linger alice
loginctl show-user alice -p Linger
```

**Вынести процесс из сессии** в отдельный scope под пользовательским менеджером — это то, что документация systemd предлагает для `screen` и `tmux`:

```bash
systemd-run --scope --user tmux new -d -s work
systemd-run --user --unit=backup /usr/local/bin/backup.sh
```

Оба варианта решают задачу правильно, в отличие от `nohup` и `setsid`: те отвязывают процесс от терминала, но не выводят его из cgroup сессии, поэтому при `KillUserProcesses=yes` он всё равно будет убит.

### user@.service

Пользовательский экземпляр systemd — это полноценный менеджер юнитов, работающий от имени пользователя. Юниты лежат в `~/.config/systemd/user/`, управление через `systemctl --user`, и там работают те же таймеры и зависимости, что и в системном. Общая механика юнитов разобрана в [статье про systemd](./linux-systemd.md); здесь существенно то, что без `linger` этот экземпляр запускается при первом входе и останавливается после последнего выхода.

## Нюансы и trade-off'ы

**Правка файлов вручную.** `/etc/passwd`, `/etc/shadow` и `/etc/group` правят через `vipw`, `vipw -s` и `vigr`, а не редактором напрямую. Эти обёртки берут блокировку и проверяют синтаксис перед сохранением — а сломанная строка в `/etc/passwd` означает, что войти не сможет никто.

**Членство в группах не обновляется на лету.** Добавили пользователя в группу — его текущие сессии об этом не узнают, потому что список групп фиксируется при входе. Требуется перелогин; `newgrp` даёт временный обходной путь в рамках одной оболочки. Регулярный источник недоумения при настройке доступа к `docker` или `dialout`.

**Повторное использование UID.** Удалили пользователя, создали нового — тот может получить освободившийся номер и стать владельцем файлов предшественника. При удалении лучше либо переносить файлы, либо оставлять UID зарезервированным.

**Сломанный источник NSS блокирует вход.** Если `sss` или другой модуль в `nsswitch.conf` перестал отвечать, обращения за пользователями начинают ждать тайм-аута. Симптом — вход занимает минуту вместо секунды, `ls -l` подвисает, `getent passwd` не возвращается. Диагностика начинается с `getent`, а не с PAM: если он висит, дело не в аутентификации.

**Лимиты применяются не ко всему.** `pam_limits` работает для сессий входа. Сервис systemd не проходит через PAM, и лимиты для него задаются в юните (`LimitNOFILE=` и родственные). Настройка `limits.conf` в надежде повлиять на демона — распространённая и безрезультатная процедура.

**Разница между `su` и `su -`.** Первая форма меняет UID, но сохраняет окружение, вторая имитирует полноценный вход и проходит другой стек PAM. Отсюда расхождения в `PATH` и в переменных, которые ставит `pam_env`.

## Сравнение с FreeBSD

Модель учётных записей выглядит похоже, но устроена иначе в двух отношениях.

**База пользователей компилируется.** Основной файл — `/etc/master.passwd`, у него больше полей, чем у линуксовой пары `passwd`/`shadow`: в одной строке и хеш, и класс входа, и время смены пароля, и срок истечения записи. Текстовый файл — только источник: `pwd_mkdb` собирает из него хеш-базы `/etc/pwd.db` и `/etc/spwd.db` (последняя доступна только root) и заодно генерирует урезанный `/etc/passwd` для совместимости. Прямая правка `master.passwd` без последующей сборки не даёт никакого эффекта — редактируют через `vipw`, который вызывает `pwd_mkdb` сам.

**Классы входа вместо разрозненных механизмов.** Пятое поле записи — login class, ссылка на запись в `/etc/login.conf`. Класс задаёт лимиты ресурсов, переменные окружения, учёт и параметры аутентификации разом. То, что в Linux размазано между `limits.conf`, `pam_env` и `pam_limits`, во FreeBSD собрано в одном месте и применяется по принадлежности пользователя к классу. Файл `login.conf` тоже компилируется — после правки нужен `cap_mkdb /etc/login.conf`, иначе изменения не подхватятся.

PAM во FreeBSD есть, но это другая реализация — OpenPAM, а не Linux-PAM. Конфигурация лежит в `/etc/pam.d/` (политики портов и пакетов — в `/usr/local/etc/pam.d/`) и выглядит знакомо, типы те же. А вот флаги расходятся: у OpenPAM их пять — добавлен `binding`, который при успехе обрывает цепочку с успехом, а при неудаче проваливает её целиком, — зато развёрнутой формы `[значение=действие]` и `substack` нет вовсе, так что числовые переходы из линуксовых стеков перенести не на что. Различия продолжаются в наборе модулей: части линуксовых модулей просто нет, а имена и параметры совпадают не всегда, поэтому переносить стек между системами копированием не стоит.

Управление сессиями отдельной подсистемы уровня `logind` не имеет: сессия завершается вместе с процессами по обычным правилам POSIX, никаких cgroup-групп и вопроса «убивать ли процессы при выходе» не возникает. Фоновый процесс, отвязанный через `nohup` или `daemon`, переживает выход всегда.

## Источники

- [shadow(5)](https://man7.org/linux/man-pages/man5/shadow.5.html) и [дерево shadow-utils](https://github.com/shadow-maint/shadow) — поля `/etc/shadow`, признаки блокировки, объявление поля минимального возраста устаревшим в 4.20
- [Release 4.20.0: Ibores](https://github.com/shadow-maint/shadow/releases/tag/4.20.0) — удаление `chage -m`, `passwd -n` и `PASS_MIN_DAYS`, список отложенных на будущее удалений и обоснование через NIST SP 800-63B
- [login.defs(5)](https://man7.org/linux/man-pages/man5/login.defs.5.html) — `ENCRYPT_METHOD` (`BCRYPT`, `SHA256`, `SHA512`, `YESCRYPT`), диапазоны `UID_MIN`/`UID_MAX` (1000–60000) и `SYS_UID_MIN`/`SYS_UID_MAX`
- [pam.conf(5), раздел синтаксиса](https://github.com/linux-pam/linux-pam/blob/master/doc/man/pam.conf-syntax.xml) — семантика флагов, их эквиваленты в форме `[значение=действие]`, различие `include` и `substack`
- [pam_faillock(8)](https://github.com/linux-pam/linux-pam/blob/master/modules/pam_faillock/pam_faillock.8.xml) — блокировка после неудачных попыток, разобранный пример стека, объяснение, почему root не блокируется
- [nss-systemd(8)](https://www.freedesktop.org/software/systemd/man/nss-systemd.html) — `DynamicUser=`, `systemd-homed`, drop-in записи в `/etc/userdb/`, рекомендация ставить `systemd` после `files`
- [logind.conf(5)](https://www.freedesktop.org/software/systemd/man/logind.conf.html) и [loginctl(1)](https://www.freedesktop.org/software/systemd/man/loginctl.html) — `KillUserProcesses`, `KillExcludeUsers`, `enable-linger`
- [systemd 230: смена умолчания KillUserProcesses](https://lwn.net/Articles/690166/) — история изменения и возврат к `no` в Debian
- [OpenPAM: pam.conf(5) в дереве FreeBSD](https://github.com/freebsd/freebsd-src/blob/main/contrib/openpam/doc/man/pam.conf.5) — порядок поиска политик, пять флагов управления вместе с `binding`, отсутствие формы `[значение=действие]`
- [FreeBSD: passwd(5)](https://man.freebsd.org/cgi/man.cgi?query=passwd&sektion=5), [pwd_mkdb(8)](https://man.freebsd.org/cgi/man.cgi?query=pwd_mkdb&sektion=8), [login.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=login.conf&sektion=5) — `master.passwd`, компиляция баз, классы входа

---

## Связанные заметки

- [Linux — безопасность: hardening, SELinux/AppArmor](./linux-security-hardening.md) — DAC, capabilities и что делать с правами после того, как пользователь вошёл
- [sudo, doas и sudo-rs — повышение привилегий](./sudo-vs-doas.md) — механизм повышения привилегий поверх этой модели; на Linux все три опираются на стек PAM
- [Linux — systemd: init, сервисы, таймеры](./linux-systemd.md) — юниты, cgroups и пользовательский экземпляр менеджера
- [SSH углублённо](./ssh-advanced.md) — что вызывает стек `/etc/pam.d/sshd` и как отлаживать вход, не потеряв доступ
- [FreeBSD — безопасность](./freebsd-security-hardening.md) — учётные записи и ограничения во FreeBSD
- [Linux — время и синхронизация](./linux-time-sync.md) — часы, от которых зависит TOTP-модуль в стеке `auth`
- [KDF для паролей: почему медленно и с памятью](./crypto-password-kdf.md) — механизм за таблицей префиксов: чем yescrypt отличается от sha512crypt и bcrypt и почему в `shadow` оказался он
