Файлы управления пользователями

TL;DR: Unix хранит информацию о пользователях в простых текстовых файлах. /etc/passwd — учётные записи (uid, home, shell). /etc/shadow — хеши паролей (доступен только root). /etc/group — группы и их члены. Ядро работает только с числовыми uid/gid — имена пользователей существуют исключительно в пространстве пользователя.

Зачем это знать

Каждый процесс в Linux имеет числовой идентификатор пользователя (uid). Ядро не знает имён — оно оперирует числами. Файлы /etc/passwd и /etc/group — это маппинг между человекочитаемыми именами и числовыми идентификаторами. Понимание формата этих файлов объясняет:

  • Почему useradd без -m не создаёт домашнюю директорию (это лишь запись в файле)
  • Откуда берётся UID при создании процесса
  • Почему в контейнере пользователь видит I have no name! (файл /etc/passwd не содержит маппинга для его uid)
  • Как работает аутентификация при логине

/etc/passwd

Основной файл учётных записей. Читаем всеми пользователями системы — поэтому паролей здесь нет (они вынесены в /etc/shadow).

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
john:x:1000:1000:John Doe:/home/john:/bin/bash
appuser:x:999:999::/opt/app:/usr/sbin/nologin

Каждая строка — одна учётная запись, 7 полей через ::

username:password:uid:gid:gecos:home:shell
ПолеОписаниеПример
usernameИмя пользователяjohn
passwordЗаглушка (реальный хеш в /etc/shadow)x — означает «смотри shadow»
uidЧисловой ID пользователя1000
gidЧисловой ID основной группы1000
gecosКомментарий (полное имя, контакты)John Doe
homeДомашняя директория/home/john
shellОболочка при логине/bin/bash

Диапазоны UID

ДиапазонНазначение
0root (суперпользователь)
1–999Системные пользователи (сервисы: nginx, postgres, sshd)
1000+Обычные пользователи
65534nobody — пользователь без привилегий

Конкретные границы определяются в /etc/login.defs (параметры UID_MIN, UID_MAX, SYS_UID_MIN, SYS_UID_MAX).

Поле shell

Оболочка определяет что происходит при логине. Для сервисных учётных записей задаётся /usr/sbin/nologin или /bin/false — обе запрещают интерактивный вход:

# nologin — выводит сообщение и отказывает
$ su - appuser
This account is currently not available.
 
# false — молча возвращает код ошибки

Список допустимых оболочек: /etc/shells. Если shell пользователя не в этом файле, некоторые программы (например FTP-серверы) откажут в доступе.

Поле GECOS

Исторически — поле для информации из системы General Electric Comprehensive Operating System. Может содержать несколько значений через запятую: полное имя, номер комнаты, рабочий телефон, домашний телефон. Сейчас обычно только полное имя.

# Посмотреть
getent passwd john
# john:x:1000:1000:John Doe:/home/john:/bin/bash
 
# Изменить
sudo chfn john       # интерактивно
sudo usermod -c "John A. Doe" john

/etc/shadow

Хеши паролей и политика устаревания. Доступен только root (права 640, владелец root:shadow).

root:$6$rounds=5000$salt$hash...:19500:0:99999:7:::
john:$y$j9T$salt$hash...:19750:0:90:7:30::
appuser:!:19500:::::
locked:!*:19500:::::

9 полей через ::

username:hash:lastchange:min:max:warn:inactive:expire:reserved
ПолеОписаниеПример
usernameИмя (совпадает с /etc/passwd)john
hashХеш пароля$y$j9T$salt$hash...
lastchangeДата последней смены (дни с 1 января 1970)19750
minМинимум дней между сменами0
maxМаксимум дней до обязательной смены90
warnЗа сколько дней предупреждать7
inactiveДней после expire до блокировки30
expireДата блокировки (дни с epoch)пусто = никогда
reservedЗарезервированопусто

Формат хеша пароля

$id$salt$hash
IDАлгоритмАктуальность
$1$MD5Устаревший, не использовать
$5$SHA-256Допустимый
$6$SHA-512Стандарт для большинства дистрибутивов
$y$yescryptСовременный, по умолчанию в Debian 12+, Ubuntu 22.04+, Fedora 35+

Специальные значения поля hash

ЗначениеСмысл
$id$salt$hashНормальный хеш пароля
!Учётная запись заблокирована (пароль не задан)
!$id$salt$hashЗаблокирована, но хеш сохранён (можно разблокировать)
*Вход по паролю запрещён (системные аккаунты)
пустоПароль не требуется (опасно!)
# Заблокировать аккаунт (добавляет ! перед хешем)
sudo passwd -l john
 
# Разблокировать (убирает !)
sudo passwd -u john
 
# Проверить статус
sudo passwd -S john
# john P 2026-02-15 0 90 7 30 (P=password set, L=locked, NP=no password)
 
# Принудительная смена пароля при следующем логине
sudo chage -d 0 john
 
# Информация об устаревании
sudo chage -l john

/etc/group

Группы и их члены.

root:x:0:
sudo:x:27:john
docker:x:998:john,deploy
developers:x:1001:john,alice,bob

4 поля через ::

groupname:password:gid:members
ПолеОписаниеПример
groupnameИмя группыdevelopers
passwordПароль группы (практически не используется)x
gidЧисловой ID группы1001
membersСписок членов через запятуюjohn,alice,bob

Основная vs дополнительные группы

У каждого пользователя есть одна основная группа (поле gid в /etc/passwd) и ноль или более дополнительных (перечислены в /etc/group).

# john с uid=1000, gid=1000 (основная группа john)
# Дополнительные: sudo, docker, developers
$ id john
uid=1000(john) gid=1000(john) groups=1000(john),27(sudo),998(docker),1001(developers)

Основная группа пользователя может не быть перечислена в /etc/group в поле members — принадлежность определяется полем gid в /etc/passwd.

Файлы, создаваемые пользователем, получают его основную группу:

$ touch newfile
$ ls -l newfile
-rw-r--r-- 1 john john 0 Feb 18 12:00 newfile
#               ↑    ↑
#              uid  gid (основная группа)

/etc/login.defs

Конфигурация поведения useradd, userdel, passwd и других утилит управления пользователями.

# Ключевые параметры
UID_MIN         1000    # минимальный UID для обычных пользователей
UID_MAX        60000    # максимальный UID
SYS_UID_MIN      100    # минимальный UID для системных
SYS_UID_MAX      999    # максимальный UID для системных
 
PASS_MAX_DAYS   99999   # максимум дней действия пароля
PASS_MIN_DAYS       0   # минимум дней между сменами
PASS_WARN_AGE       7   # предупреждение за N дней
 
CREATE_HOME       yes   # создавать ли home при useradd
ENCRYPT_METHOD SHA512   # алгоритм хеширования паролей

/etc/nsswitch.conf — откуда брать данные

Name Service Switch определяет источники информации о пользователях и группах. Система не обязана читать именно файлы — данные могут приходить из LDAP, NIS, SSSD.

# /etc/nsswitch.conf (типичный)
passwd:     files systemd
group:      files systemd
shadow:     files
 
# С LDAP (корпоративная среда)
passwd:     files sss ldap
group:      files sss ldap
ИсточникОписание
filesЛокальные файлы (/etc/passwd, /etc/group)
systemdsystemd-userdbd (динамические пользователи)
sssSSSD (кеширующий прокси для LDAP/AD)
ldapLDAP-каталог напрямую
nisNIS (устаревший, но встречается)

Именно поэтому для чтения данных о пользователях правильнее использовать getent вместо прямого чтения файла — getent учитывает nsswitch:

# Правильно — ищет по всем настроенным источникам
getent passwd john
 
# Менее правильно — только локальный файл
grep john /etc/passwd

Как это работает при логине

1. Пользователь вводит username + password
            │
2. login/sshd/su ищет username в /etc/passwd
   (через NSS → getpwnam())
            │
3. Находит uid, gid, home, shell
            │
4. Читает /etc/shadow → достаёт хеш и параметры устаревания
            │
5. Хеширует введённый пароль тем же алгоритмом + salt
            │
6. Сравнивает хеши
            │
   ├── совпали → запускает shell с uid/gid пользователя
   │             переходит в home, читает дополнительные
   │             группы из /etc/group
   └── не совпали → отказ

Важно: В современных системах этим занимается PAM (Pluggable Authentication Modules), а не программы напрямую. PAM добавляет гибкость: двухфакторная аутентификация, ограничения по времени, LDAP-бэкенды — всё без изменения login/sshd.

PAM (Pluggable Authentication Modules)

PAM — модульная система аутентификации. Вместо того чтобы каждая программа (login, sshd, su, sudo) сама проверяла пароли, они вызывают PAM, а PAM делегирует проверку цепочке модулей.

Конфигурация

/etc/pam.d/           # конфигурации для каждой программы
  ├── login           # для login
  ├── sshd            # для SSH
  ├── sudo            # для sudo
  ├── su              # для su
  └── common-auth     # общие правила аутентификации (Debian/Ubuntu)

Каждая строка конфига:

# тип        контроль   модуль                аргументы
auth         required   pam_unix.so           nullok
account      required   pam_nologin.so
password     sufficient pam_unix.so           sha512 shadow
session      required   pam_limits.so
ТипЧто делает
authПроверка личности (пароль, ключ, OTP)
accountПроверка доступа (не истёк ли аккаунт, время входа)
passwordСмена пароля (требования сложности)
sessionДействия при входе/выходе (запись в лог, монтирование home)
КонтрольПоведение при ошибке
requiredОтказ, но продолжить проверку остальных (для логирования)
requisiteНемедленный отказ
sufficientУспех → пропустить остальные модули этого типа
optionalРезультат учитывается только если это единственный модуль

Частые модули

МодульНазначение
pam_unix.soПроверка пароля через /etc/shadow
pam_nologin.soБлокирует вход если существует /etc/nologin
pam_limits.soПрименяет лимиты из /etc/security/limits.conf
pam_deny.soВсегда отказывает (для блокировки)
pam_permit.soВсегда разрешает (осторожно!)
pam_google_authenticator.so2FA через Google Authenticator

getty и login

При текстовом входе в систему (консоль, не SSH) работает цепочка:

systemd → getty@tty1.service → agetty → показывает "login:" 
  → пользователь вводит имя → login → PAM → проверка пароля → shell

agetty (alternative getty) — программа, которая открывает терминал и показывает приглашение login:. После ввода имени пользователя передаёт управление программе login, которая через PAM проверяет пароль и запускает shell.

# Активные getty (виртуальные терминалы)
systemctl list-units 'getty@*'
# getty@tty1.service  active  running  Getty on tty1
 
# Переключение между виртуальными консолями
# Ctrl+Alt+F1..F6 — текстовые
# Ctrl+Alt+F7     — графическая (обычно)

Подводные камни

ПроблемаСимптомРешение
Редактирование /etc/passwd вручнуюСинтаксическая ошибка → никто не может залогинитьсяИспользовать vipw — валидирует синтаксис перед сохранением
Редактирование /etc/shadow вручнуюАналогичноvipw -s для shadow
Редактирование /etc/group вручнуюАналогичноvigr
usermod -G без -aПользователь выпадает из всех групп кроме указаннойВсегда usermod -aG
В контейнере I have no name!uid процесса не найден в /etc/passwdДобавить запись в /etc/passwd контейнера или использовать --user с существующим uid
Пустое поле hash в shadowВход без пароля (дыра в безопасности)passwd -l user для блокировки
getent passwd не показывает пользователяnsswitch настроен не на filesПроверить /etc/nsswitch.conf

Связанные материалы