Наступает момент, когда системному администратору необходимо определить дату последнего входа в систему каждого из пользователей, а также подготовить список тех аккаунтов, которые этого так и не сделали. Если б Вы ранее не знали команду lastlog, то удивились бы, насколько легко и быстро она может предоставить Вам эти данные.



Если же Вы все-таки задумались об этом, то не забывайте, что данная команда — это также один из хороших методов проверки безопасности, которую можно проводить на серверах под управлением Linux систем. Она поможет Вам установить потенциальные проблемы. Те аккаунты, которые были неактивны в течение долгого времени, например, может означать, что они больше не нужны и могут быть отключены. А вот аккаунты, которые были активны в то время, когда их пользователи должны были быть в отпуске где-нибудь на Багамах — могут намекать о проблемах с безопасностью на сервере.

Команда lastlog хранит информацию о последнем входе пользователя в систему, но он предоставит информацию только по тем логам, которые имеются в файле wtmp. Записи в данном файле делаются в двоичном формате, так что просматривать их можно только с помощью специальных команд. Думаю многие из Вас обращали внимание на то, что когда Вы авторизируетесь в консоли, на экране появляется примерно следующее сообщение:

Last login: Wed Nov 11 13:19:44 on ttys002

Эта строка формируется утилитой login, которая после авторизации пользователя обращается к файлу /var/log/lastlog, извлекает оттуда информацию о предыдущем успешном входе, выдает ее на экран, а затем обновляет запись в файле lastlog. В отличие от файла /var/log/lastlog, который содержит записи о времени последнего входа в систему каждого пользователя, в файле /var/log/wtmp запоминаются все входы и выходы пользователей в систему с момента создания этого файла.

Что бы посмотреть данные по конкретному пользователю необходимо использовать следующую команду last xxx, где ххх — логин пользователя. А использование команды сортировки head с параметром 5 в свою очередь поможет Вам отобразить на экране только 5 последних результатов:

# last | head -5
root     pts/0        193.178.187.30   Wed Nov 11 14:21   still logged in   
tuto     ftpd3292     ::ffff:176.104.0 Wed Nov 11 11:11 - 11:15  (00:04)    
tuto     ftpd29523    ::ffff:176.104.0 Tue Nov 10 18:58 - 19:03  (00:04)    
naturcok ftpd23502    ::ffff:176.104.0 Tue Nov 10 13:55 - 13:55  (00:00)    
naturcok ftpd20128    ::ffff:176.104.0 Tue Nov 10 13:50 - 13:55  (00:05) 

Как “глубоко” Вы можете просмотреть историю последних команд зависит от того как долго существует файл wtmp. Например, Вы можете использовать утилиту logrotate, которая следит за файлами протоколов и обеспечивает так называемую ротацию этих файлов в случае, если они превысили указанный размер (или по истечению указанного временного интервала). Также она позволяет поддерживать более одного wtmp файл и имеет запись в logrotate.conf наподобие этой:

/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

Даже имея несколько файлов wtmp, данные некоторых Ваших пользователей могут просто не отобразиться. Если в результате индивидуальной проверки пользователя Вы никаких данных по нем не получили, то это означает, что записей по конкретному пользователю в файле wtmp нет. Чтобы узнать дату создания файла wtmp, следует ввести в консоли last mia:

# last mia

wtmp begins Thu Sep 17 16:10:00 2015

Лучшим способом найти информацию о последнем входе в систему для каждого пользователя является использование команды lastlog. Если какой-либо из пользователей никогда не авторизировался в системе, то вместо имени терминала и времени последнего входа будет указана строка **Never logged in**. Если результат вывода будет состоять из большого количества строк, то можете использовать еще и команду more, которая в отличие от команды less, выведет содержимое файла на экран отдельными страницами. Результат будет выглядеть примерно так:

# lastlog | more
Username         Port     From             Latest
root             pts/0    xxx.xxx.xxx.xxx   Wed Nov 11 14:21:59 +0200 2015
bin                                        **Never logged in**
daemon                                     **Never logged in**
adm                                        **Never logged in**
ispmaster        pts/0    xxx.xxx.xxx.xxx   Thu Nov  5 17:00:44 +0200 2015

Многие из нас возможно будут удивлены, увидев, что bin, daemon, adm и другие служебные учетные записи никогда не авторизировались в системе. Это и в самом деле так, и означает лишь только то, что для оболочек, назначенных в момент регистрации пользователей (login shells), задан параметр /sbin/nologin, что делает авторизацию невозможной. Остальные данные по входам показывают дату и время системы, с которой была осуществлена авторизация.

Чтобы создать список всех учетных записей, которые никогда не входили в систему, стоит использовать следующий набор команд. С командой lastlog мы уже знакомы и я на ней подробно останавливаться не буду, дальше стоит добавить утилиту grep для поиска по ключевому слову, в нашем случаи это слово Never, а для того, чтобы выводился только первый столбец с данными, можно воспользоваться утилитой awk со следующим синтаксисом — '{print $1}':

# lastlog | grep Never | awk '{print $1}'
bin
daemon
adm
. . .
ntp
user1819
user1939

Записи в lastlog перечислены согласно идентификаторов пользователей (User identifier — UID) — от суперпользователя (root) до пользователя с самым большим значением UID в Вашем файле /etc/passwd. Это связано с форматом самого файла lastlog. В отличие от большинства лог-файл Unix, в файле lastlog для записи логов каждого пользователя резервируется отдельное место, и в свою очередь место каждой записи проиндексировано по UID. После этого файлы будут фиксированного размера, особенно если Ваша система имеет аккаунты с наивысшим лимитом своего возможного диапазона UID — такого как 16-битный UID 65536. Также при этом образуется большой объем неиспользуемого пространства, правда только в том случаи если Ваши идентификаторы не являются строго последовательными. Если же Ваша система поддерживает 32-битные UIDы, файл может быть очень большим и иметь 4 294 967 296 (232) различных значений идентификаторов.

Каждая запись в файле lastlog содержит имя пользователя, имя терминала, с которого вошел пользователь и время последнего входа в систему. Запись для суперпользователя (UID 0) в верхней части файла может иметь следующий вид:

# od -xc /var/log/lastlog | more
0000000    fba3    563d    7470    2f73    0030    0000    0000    0000
        243 373   =   V   p   t   s   /   0  \0  \0  \0  \0  \0  \0  \0
0000020    0000    0000    0000    0000    0000    0000    0000    0000
         \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040    0000    0000    3138    392e    2e35    3831    2e34    3532
         \0  \0  \0  \0   8   1   .   9   5   .   1   8   4   .   2   5
0000060    0034    0000    0000    0000    0000    0000    0000    0000
          4  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000100    0000    0000    0000    0000    0000    0000    0000    0000
         \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0

При выполнении команды lastlog на некоторых компьютерах в определенных случаях может возникнуть впечатление, что команда «зависла». Это происходит в силу того, что даже если в системе зарегистрировано всего два пользователя (root и user), в файле /var/log/lastlog все равно отведено место для максимально возможного числа пользователей, которые могут работать в системе. Поэтому в файле /var/log/lastlog могут иметься большие промежутки между номерами идентификаторов работавших в системе пользователей. Поскольку при просмотре таких интервалов программа не выводит информацию на экран, и возникает впечатление «зависания». Потому не спешите нажимать кнопки и закрывать консоль, а дождитесь ответа команды.

Как мы с Вами установили, команда lastlog может быть очень полезна для проверки логов тех пользователей, поддержку которых Вы еще осуществляете, чтобы убедиться, что аккаунты в системе используются должным образом и они все еще актуальны. Также не забывайте проверять размер логов, а то может оказаться, что их объем уже значительно превышает общий размер Вашей системы.

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

Комментарии (13)


  1. Meklon
    11.11.2015 23:47
    +3

    Пригодится, спасибо) пусть я и гордый админ локалхоста)


  1. conformist
    12.11.2015 00:39
    +2

    Люблю Ваши статьи, обычно интересные и развёрнутые. Но на этот раз — почти ман, чуть подробнее.
    Кстати,

    # lastlog | grep Never | awk '{print $1}'
    

    вполне удобнее заменить на:
    $ lastlog | awk '/Never/{print $1}'
    


    1. yermulnik
      12.11.2015 02:01

      Кстати, оба варианта ошибочно в данном случае отобразят юзера Never, если таковой имеется в системе.


    1. Self_Perfection
      12.11.2015 02:02
      +1

      Я на этом месте статьи в который раз подумал, что надо бы написать свой пост под заголовком «grep не нужен».

      И вы вскрыли только самый поверхностный слой проблем этого однострочника. А что если в системе есть пользователь 'DieNever'? Но самое страшное — вот:

      $ LC_MESSAGES='ru_RU.UTF-8' lastlog | grep '^nobody'
      nobody                                     **Никогда не входил в систему**

      Но я не вижу утилиты, которая бы позволила получить список никогда не логинившихся пользователей семантически правильно. Похоже, в данном случае без фильтрации строк по шаблону не обойтись. Для надёжности стоит сделать хотя бы так:
      lastlog | awk '/\*\*$/{print $1}'


      1. yermulnik
        12.11.2015 02:22
        +1

        Как вариант более-менее универсальный:

        LC_ALL=C lastlog ...
        


      1. m0s
        12.11.2015 02:29

        Ну с таким подходом – для вас единственно-правильный вариант будет парсить /var/log/lastlog

        Вот например простенький one-liner из интернетов, который выводит информацию из lastlog в понятном человеку виде виде

        perl -we '$recs = ""; while (<>) {$recs .= $_};$uid = 0;foreach (split(/(.{292})/s,$recs)) {next if length($_) == 0;my ($binTime,$line,$host) = $_ =~/(.{4})(.{32})(.{256})/;if (defined $line && $line =~ /\w/) {$line =~ s/\x00+//g;$host =~ s/\x00+//g;printf("%5d %s %8s %s\n",$uid,scalar(gmtime(unpack("I4",$binTime))),$line,$host)}$uid++}print"\n"' < /var/log/lastlog
        

        Тут лишь нужно учитывать, что в зависимости от архитектуры и версий, структура данных может быть не только 4+32+256

        Беглое изучение вопроса показало, что встречаются также другие варианты и самый верный способ — посмотреть соответствующие значения в хедерах (например для Linux это будут UT_LINESIZE и UT_HOSTSIZE в /usr/include/bits/utmp.h)
        / информация выше взята из этой статьи /

        Нужно понимать, что lastlog хранит только записи о логинившихся пользователях, а т.к. исходная задача стояла в получении тех, кто не логинился ни разу – то, соответственно, ими являются все остальные UIDы, кроме полученных в выводе этого скрипта.


        1. Self_Perfection
          12.11.2015 02:49

          И если идти до конца, то самым надёжным/правильным способом будет не парсить lastlog своим поделием, а дописать утилите last дополнительные ключи запуска, которые позволят выводить только никогда не логинившихся пользователей (и заслать патч в апстрим).

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


  1. m0s
    12.11.2015 00:39
    +2

    Чтобы узнать дату создания файла wtmp, следует ввести в консоли last mia

    Так же можно ввести last vincent или же last jules, равно как и имя любого другого существующего или не очень существующего пользователя системы.

    На самом деле команда last USERNAME выводит содержимое lastlog для конкретного пользователя, не более того. После вывода лога, она добавляет строку с датой и временем создания соответствующих логфайлов и если по конкретному пользователю записей нет — в вывод попадает только эта вспомогательная информация


  1. m0s
    12.11.2015 00:43
    +5

    Но давайте будем честны, это всего лишь вольный пересказ вот этой статьи близко к тексту.
    Хоть бы из вежливости об оригинале вспомнили


  1. yermulnik
    12.11.2015 02:19
    +7

    использование команды сортировки head

    head не сортирует, а всего лишь выводит n-строк от начала файла.

    Чтобы узнать дату создания файла wtmp, следует ввести в консоли last mia:

    Для того, чтобы узнать дату создания файла, существует команда stat

    можете использовать еще и команду more, которая в отличие от команды less, выведет содержимое файла на экран отдельными страницами

    Что за бред? На фоне less утилита more представляет из себя убогий pager. О чём, кстати, упоминает man more.

    Это и в самом деле так, и означает лишь только то, что для оболочек, назначенных в момент регистрации пользователей (login shells), задан параметр /sbin/nologin, что делает авторизацию невозможной.

    Это означает лишь только то, что пользователь с данным логином ни разу не авторизовался в системе. Оболочка (шелл) тут вторична.

    Также она позволяет поддерживать более одного wtmp файл

    Не позволяет. /var/log/wtmp один. Все остальные (в данном контексте) — его архивные копии.

    ps: пардон за снобизм. статья в целом интересная для новичков, но уж слишком много допущено в ней ошибок.


  1. boombick
    12.11.2015 11:22
    +2

    Статья отличная! Прочитал на одном дыхании. А можно еще подобную на тему «Как же посмотреть список файлов в каталоге?»


  1. la0
    12.11.2015 11:42

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


  1. ComodoHacker
    12.11.2015 12:51
    +1

    Статья переводная, а источник не указан. Некрасиво.