8.17. Серийное добавление новых пользователей

Проблема

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

Решение

Воспользуйтесь сценарием mass_useradd. Это сценарий командного процессора, поэтому он должен работать практически везде. Вам также понадобится сценарий mass_passwd (листинг 8.2). Сохраните эти два сценария в одном каталоге. Также следует установить утилиту pwgen, генерирующую пароли.

Создайте список имён и паролей в формате:

имя_пользователя: имя фамилия

Также можно добавить дополнительные данные GECOS:

dawns:Dawn Marie Schroder,,123-4567,trainers

Затем запустите сценарий mass_useradd (листинг 8.1). Сценарий создаёт записи в /etc/passwd, /etc/group и /etc/shadow, домашние каталоги, персональные группы и пароли, которые становятся недействительными после первого использования.

Следующая команда приказывает mass_useradd использовать список новых пользователей из файла newusers с заменой/созданием выходного файла newlogins.txt:

sh mass_useradd < newusers > newlogins.txt

Присоединение новых имён и паролей к файлу newlogins.txt:

sh mass_useradd < newusers >> newlogins.txt

Помимо выходного файла, который представляет собой обычный список, mass_passwd создаёт для каждого пользователя отдельный файл с инструкциями. Эти файлы, а также файл журнала, хранятся в домашнем каталоге пользователя, запустившего сценарий (обычно root):

/root/mass_passwds/
dawns.passwd.txt
nikitah.passwd.txt
mass_passwd.log
rubst.passwd.txt

Комментарий

В сценариях используются стандартные средства Shadow Suite, поэтому они легко настраиваются посредством регулировки параметров утилит, задействованных в их работе.

Пример выходных данных:

dawns shabaefi 1002
nikitah gohbinga 1003
rubst ahtoohaa 1004

В файл /etc/passwd добавляются записи вида:

dawns:x:1002:1002:Dawn Marie Schroder,,123-4567,trainers:/home/dawns:/bin/bash
nikitah:x:1003:1003:Nikita Horse,,123-4567,equine:/home/nikitah:/bin/bash
rubst:x:1004:1004:Rubs The Cat,,234-5678,test:/home/rubst:/bin/bash

Листинг 8.1. Программа mass_useradd

#!/bin/sh
#
# Использование:
# sh mass_useradd < inputfile > new-passwords.txt
#
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:$PATH
# Чтение строки входных данных.
# Формат входного файла:
# имя_пользователя : имя фамилия
# Чтобы в качестве разделителя использовалась запятая, замените
# IFS=":$IFS" на IFS=",$IFS"
while IFS=":$IFS" read username realname; do
    # Сначала удаляем пустые строки и комментарии
    case "$username" in
        ''|\#*) continue ;;
    esac
    # Чтение /etc/passwd и /etc/group и вычисление следующих свободных значений UID и GID.
    # Программа начинает с id=1000, измените для своей системы.
    id=$( { getent passwd; getent group; } | cut -f3 -d: | sort -un | awk 'BEGIN { id=1000 } $1 == id { id++ } $1 > id { print id; exit }' )
    # Добавление новых пользователей в /etc/group и /etc/passwd.
    groupadd -g $id $username
    useradd -m -c "$realname" -g $username -u $id $username
    # Создание домашнего каталога с разрешениями 700.
    chmod 700 /home/$username
    # Назначение пароля с помощью сценария mass_passwd.
    $(dirname $0)/mass_passwd -M $username
done

Листинг 8.2. Программа mass_passwd

#!/bin/sh
# Каталог для сохранения файлов "username.passwd.txt"
# Если каталог не существует, он будет создан.
text_file_dir=$HOME/mass_passwds
log_file=mass_passwd.log
# Минимальный идентификатор для "обычных" пользователей
min_uid=1000
# Длина генерируемых паролей
pass_len=8
# Срок действия паролей (в днях)
pass_expire=90
# Получение имени программы (скорее всего, "mass_passwd")
prog=${0##*/}
usage() {
    echo "usage: $prog [-v] [-n] username ..."
    echo "       $prog [-v] [-n] [-g] groupname ..."
    echo "       $prog [-v] [-n] [-a]"
    echo " -g     change passwords of everyone in a group"
    echo " -a     change everyone's password"
    echo " -v     verbose"
    echo " -n     don't do it, just simulate (implies -v)"
    exit 0
}
short_usage() {
    echo >&2 "usage: $prog [-v] [-g] [-a] name..."
    echo >&2 "       $prog -h for help"
    exit 1
}
# Вывод в verbose режиме
vecho() {
    test -n "$verbose" && echo "$@"
}
# Генерация случайного пароля.
randompass() {
    pwgen $pass_len 1 2>/dev/null || \
    tr -d '[\000-\057][\072-\100][\133-\140][\173-\377]' < /dev/urandom | \
    dd bs=$pass_len count=1 2>/dev/null
}
# Получение списка пользователей в зависимости от режима
get_users() {
    if [ -n "$all_mode" ]; then
        getent passwd | awk -F: '{if ($3 >= '$min_uid') print $1}'
        return
    fi
    if [ -z "$group_mode" ]; then
        echo "$@"
        return
    fi
    while [ -n "$1" ]; do
        g_ent=$(getent group "$1" 2>/dev/null)
        if [ -z "$g_ent" ]; then
            echo >&2 "warning: $1: group not found"
            continue
        fi
        members=${g_ent##*:}
        gid=${g_ent%%:*}
        echo "$members" | tr '.' ' '
        getent passwd | awk -F: '{if ($4 == '$gid') { print $1 }}'
        shift
    done
}
# Основной код
group_mode=; verbose=; all_mode=; simulate=; eol=;
while [ -z "$eol" ]; do
    case "$1" in
        -g) group_mode=1; shift ;;
        -v) verbose=1; shift ;;
        -a) all_mode=1; shift ;;
        -n) simulate=true; verbose=1; shift ;;
        -M) mass_out=1; shift ;; # для вызова из mass_useradd
        -h | -? | --help) usage ;;
        --) eol=1; shift ;;
        -*) short_usage ;;
        *) eol=1 ;;
    esac
done
# Настройка безопасного окружения и каталога для текстовых файлов
PATH=/usr/sbin:/usr/bin:$PATH
umask 077
mkdir -p $text_file_dir
cd $text_file_dir
processed=0
for u in $(get_users "$@"); do
    vecho -n "generating password for $u..."
    pass=$(randompass)
    echo "$u:$pass" | eval $simulate chpasswd
    vecho -n "."
    eval $simulate chage -M $pass_expire -d 2003-01-01 $u
    vecho -n "."
    rm -f $u.passwd.txt
    echo > $u.passwd.txt "
Login name: $u
Password: $pass
Please log in and change your password. The system should
prompt you to do this when you log in. You can change your
password at any time with the 'passwd' command.
Choose a strong password. Everyday words, birthdays,
names of people or animals are too easy to guess.
Also, DO NOT give your password to anyone, ever. The IT
staff will never ask you for your password, and neither
should anyone else. You will be held responsible for all
activity done via your account.
"
    printf >> $log_file "$(date) %-12s %s\n" $u $pass
    vecho "$pass"
    if [ -n "$mass_out" ]; then
        uid=$(getent passwd $u | cut -f3 -d:)
        echo -e "$u\t$pass\t$uid"
    fi
    processed=$(expr $processed + 1)
done
if [ $processed -gt 0 ]; then
    test -z "$mass_out" && echo >&2 "$processed password(s) reset - see $text_file_dir/$log_file"
else
    echo >&2 "no users specified - see '$prog -h' for help"
fi

См. также

bash(1), pwgen(1); домашняя страница программы pwgen (http://sourceforge.net/projects/pwgen/).