Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package apparmor for openSUSE:Factory checked in at 2021-11-12 15:58:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apparmor (Old) and /work/SRC/openSUSE:Factory/.apparmor.new.1890 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apparmor" Fri Nov 12 15:58:56 2021 rev:159 rq:930527 version:3.0.3 Changes: -------- --- /work/SRC/openSUSE:Factory/apparmor/apparmor.changes 2021-10-19 23:03:32.497265163 +0200 +++ /work/SRC/openSUSE:Factory/.apparmor.new.1890/apparmor.changes 2021-11-12 15:58:58.062556784 +0100 @@ -1,0 +2,6 @@ +Tue Nov 9 17:45:22 UTC 2021 - Christian Boltz <suse-b...@cboltz.de> + +- add aa-notify-more-arch-mr809.diff: Add support for reading s390x + and aarch64 wtmp files (boo#1181155) + +------------------------------------------------------------------- New: ---- aa-notify-more-arch-mr809.diff ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apparmor.spec ++++++ --- /var/tmp/diff_new_pack.2iLaA6/_old 2021-11-12 15:58:58.862557148 +0100 +++ /var/tmp/diff_new_pack.2iLaA6/_new 2021-11-12 15:58:58.866557150 +0100 @@ -84,6 +84,9 @@ # add samba-bgqd profile (submitted upstream 2021-10-15 https://gitlab.com/apparmor/apparmor/-/merge_requests/807) Patch8: add-samba-bgqd.diff +# aa-notify: Add support for reading s390x and aarch64 wtmp file (boo#1181155) (merged upstream 2021-11-08 in master and 3.0 branch - https://gitlab.com/apparmor/apparmor/-/merge_requests/809) +Patch9: aa-notify-more-arch-mr809.diff + PreReq: sed BuildRoot: %{_tmppath}/%{name}-%{version}-build %define apparmor_bin_prefix %{?usrmerged:/usr}/lib/apparmor @@ -348,6 +351,7 @@ %patch5 %patch7 -p1 %patch8 -p1 +%patch9 -p1 %build %define _lto_cflags %{nil} ++++++ aa-notify-more-arch-mr809.diff ++++++ This patch contains the code changes from https://gitlab.com/apparmor/apparmor/-/merge_requests/809 It does NOT include the added unit tests because adding binary test files with a patch is too hard. diff --git a/utils/aa-notify b/utils/aa-notify index 91d0f3b9c240e1ff0fec8aa673ef70fa78cf33bc..024044a0c58ed4827502da66786acb4e9b54fc2f 100755 --- a/utils/aa-notify +++ b/utils/aa-notify @@ -34,7 +34,6 @@ import os import re import sys import time -import struct import notify2 import psutil import pwd @@ -45,6 +44,7 @@ import apparmor.ui as aaui import apparmor.config as aaconfig from apparmor.common import DebugLogger, open_file_read from apparmor.fail import enable_aa_exception_handler +from apparmor.notify import get_last_login_timestamp from apparmor.translations import init_translation import LibAppArmor # C-library to parse one log line @@ -61,48 +61,6 @@ def get_user_login(): return username -def get_last_login_timestamp(username): - '''Directly read wtmp and get last login for user as epoch timestamp''' - timestamp = 0 - filename = '/var/log/wtmp' - last_login = 0 - - debug_logger.debug('Username: {}'.format(username)) - - with open(filename, "rb") as wtmp_file: - offset = 0 - wtmp_filesize = os.path.getsize(filename) - debug_logger.debug('WTMP filesize: {}'.format(wtmp_filesize)) - while offset < wtmp_filesize: - wtmp_file.seek(offset) - offset += 384 # Increment for next entry - - type = struct.unpack("<L", wtmp_file.read(4))[0] - debug_logger.debug('WTMP entry type: {}'.format(type)) - - # Only parse USER lines - if type == 7: - # Read each item and move pointer forward - pid = struct.unpack("<L", wtmp_file.read(4))[0] - line = wtmp_file.read(32).decode("utf-8", "replace").split('\0', 1)[0] - id = wtmp_file.read(4).decode("utf-8", "replace").split('\0', 1)[0] - user = wtmp_file.read(32).decode("utf-8", "replace").split('\0', 1)[0] - host = wtmp_file.read(256).decode("utf-8", "replace").split('\0', 1)[0] - term = struct.unpack("<H", wtmp_file.read(2))[0] - exit = struct.unpack("<H", wtmp_file.read(2))[0] - session = struct.unpack("<L", wtmp_file.read(4))[0] - timestamp = struct.unpack("<L", wtmp_file.read(4))[0] - usec = struct.unpack("<L", wtmp_file.read(4))[0] - entry = (pid, line, id, user, host, term, exit, session, timestamp, usec) - debug_logger.debug('WTMP entry: {}'.format(entry)) - - # Store login timestamp for requested user - if user == username: - last_login = timestamp - - # When loop is done, last value should be the latest login timestamp - return last_login - def format_event(event, logsource): output = [] diff --git a/utils/apparmor/notify.py b/utils/apparmor/notify.py new file mode 100644 index 0000000000000000000000000000000000000000..1101a29346d79dd873c347fd12dd79cda1e1c786 --- /dev/null +++ b/utils/apparmor/notify.py @@ -0,0 +1,105 @@ +#! /usr/bin/python3 +# ---------------------------------------------------------------------- +# Copyright (C) 2018???2019 Otto Kek??l??inen <o...@kekalainen.net> +# Copyright (C) 2021 Christian Boltz +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# ---------------------------------------------------------------------- + +import os +import struct + +from apparmor.common import AppArmorBug, DebugLogger + +debug_logger = DebugLogger('apparmor.notify') + + +def sane_timestamp(timestamp): + ''' Check if the given timestamp is in a date range that makes sense for a wtmp file ''' + + if timestamp < 946681200: # 2000-01-01 + return False + elif timestamp > 2524604400: # 2050-01-01 + return False + + return True + +def get_last_login_timestamp(username, filename='/var/log/wtmp'): + '''Directly read wtmp and get last login for user as epoch timestamp''' + timestamp = 0 + last_login = 0 + + debug_logger.debug('Username: {}'.format(username)) + + with open(filename, "rb") as wtmp_file: + offset = 0 + wtmp_filesize = os.path.getsize(filename) + debug_logger.debug('WTMP filesize: {}'.format(wtmp_filesize)) + + if wtmp_filesize < 356: + return 0 # (nearly) empty wtmp file, no entries + + # detect architecture based on utmp format differences + wtmp_file.seek(340) # first possible timestamp position + timestamp_x86_64 = struct.unpack("<L", wtmp_file.read(4))[0] + timestamp_aarch64 = struct.unpack("<L", wtmp_file.read(4))[0] + timestamp_s390x = struct.unpack(">L", wtmp_file.read(4))[0] + debug_logger.debug('WTMP timestamps: x86_64 %s, aarch64 %s, s390x %s' % (timestamp_x86_64, timestamp_aarch64, timestamp_s390x)) + + if sane_timestamp(timestamp_x86_64): + endianness = '<' # little endian + extra_offset_before = 0 + extra_offset_after = 0 + elif sane_timestamp(timestamp_aarch64): + endianness = '<' # little endian + extra_offset_before = 4 + extra_offset_after = 12 + elif sane_timestamp(timestamp_s390x): + endianness = '>' # big endian + extra_offset_before = 8 + extra_offset_after = 8 + else: + raise AppArmorBug('Your /var/log/wtmp is broken or has an unknown format. Please open a bugreport with /var/log/wtmp and the output of "last" attached!') + + while offset < wtmp_filesize: + wtmp_file.seek(offset) + offset += 384 + extra_offset_before + extra_offset_after # Increment for next entry + + type = struct.unpack('%sH' % endianness, wtmp_file.read(2))[0] + debug_logger.debug('WTMP entry type: {}'.format(type)) + wtmp_file.read(2) # skip padding + + # Only parse USER lines + if type == 7: + # Read each item and move pointer forward + pid = struct.unpack("<L", wtmp_file.read(4))[0] + line = wtmp_file.read(32).decode("utf-8", "replace").split('\0', 1)[0] + id = wtmp_file.read(4).decode("utf-8", "replace").split('\0', 1)[0] + user = wtmp_file.read(32).decode("utf-8", "replace").split('\0', 1)[0] + host = wtmp_file.read(256).decode("utf-8", "replace").split('\0', 1)[0] + term = struct.unpack("<H", wtmp_file.read(2))[0] + exit = struct.unpack("<H", wtmp_file.read(2))[0] + session = struct.unpack("<L", wtmp_file.read(4))[0] + if extra_offset_before: + wtmp_file.read(extra_offset_before) + timestamp = struct.unpack('%sL' % endianness, wtmp_file.read(4))[0] + if extra_offset_after: + wtmp_file.read(extra_offset_after) + usec = struct.unpack("<L", wtmp_file.read(4))[0] + entry = (pid, line, id, user, host, term, exit, session, timestamp, usec) + debug_logger.debug('WTMP entry: {}'.format(entry)) + + # Store login timestamp for requested user + if user == username: + last_login = timestamp + + # When loop is done, last value should be the latest login timestamp + return last_login