diff options
author | Timo Teräs <timo.teras@iki.fi> | 2014-05-06 13:23:55 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2014-05-06 16:56:23 +0300 |
commit | 4898593dd7fdb5dec3f0ccdbec5e7347b2146c48 (patch) | |
tree | fd4025d3918c2c761adc387648778ad588e64275 | |
parent | 3e62492bb468dbae22138a6238262696bce754c9 (diff) | |
download | aports-4898593dd7fdb5dec3f0ccdbec5e7347b2146c48.tar.bz2 aports-4898593dd7fdb5dec3f0ccdbec5e7347b2146c48.tar.xz |
testing/aaudit: new aport
Alpine Auditor - utility to track remote apkovls in a git tree and
email about changes
-rw-r--r-- | testing/aaudit/APKBUILD | 44 | ||||
-rwxr-xr-x | testing/aaudit/aaudit-create | 20 | ||||
-rwxr-xr-x | testing/aaudit/aaudit-emaildiff | 61 | ||||
-rwxr-xr-x | testing/aaudit/aaudit-import-tar | 173 | ||||
-rwxr-xr-x | testing/aaudit/aaudit-refresh | 15 | ||||
-rw-r--r-- | testing/aaudit/aaudit.conf | 25 |
6 files changed, 338 insertions, 0 deletions
diff --git a/testing/aaudit/APKBUILD b/testing/aaudit/APKBUILD new file mode 100644 index 0000000000..d253c9f152 --- /dev/null +++ b/testing/aaudit/APKBUILD @@ -0,0 +1,44 @@ +# Contributor: Timo Teräs <timo.teras@iki.fi> +# Maintainer: Timo Teräs <timo.teras@iki.fi> +pkgname=aaudit +pkgver=0.1 +pkgrel=0 +pkgdesc="Alpine Auditor" +url="http://alpinelinux.org" +arch="noarch" +license="GPL" +depends="lua5.2 lua-posix git" +makedepends="" +install="" +subpackages="" +replaces="" +source_libexec="aaudit-emaildiff aaudit-import-tar" +source_bin="aaudit-create aaudit-refresh" +source="$source_libexec $source_bin aaudit.conf" + +build() { + return 0 +} + +package() { + mkdir -p "$pkgdir"/etc/aaudit "$pkgdir"/usr/bin "$pkgdir"/usr/libexec/aaudit + cp aaudit.conf "$pkgdir"/etc/aaudit + cp $source_bin "$pkgdir"/usr/bin + cp $source_libexec "$pkgdir"/usr/libexec/aaudit +} + +md5sums="6ab0ebec3419a4c495a1935a07d4825c aaudit-emaildiff +d71863d014f844656b2fd1926f63826e aaudit-import-tar +5dafe6078c114ac0a445dcf0633371cd aaudit-create +9bcfb058c2b28b36d593203f838b90fa aaudit-refresh +43ca8205fec84b7fe8ead005d0cbd8f3 aaudit.conf" +sha256sums="56ec6e2c13a5e857ae604264a424fd8c6dc04bf37122d88197ddbbb92e42b560 aaudit-emaildiff +4ea264c0a0fd7e1a0ff52a42db9b098358cce545b3eec1066ecc977cfe06565e aaudit-import-tar +6643a7c1353253a417a319b0ac8558a348248cb97dcca2c724940350edef47b2 aaudit-create +6f3fb2d53141be5b58dfbda4977243628ed56de6ad3949ac349ad01013f43f75 aaudit-refresh +c23f1dd4fe68b5cbde0bb5c8cc9996c9569b1cb4a249523c995381c8b3eee8ee aaudit.conf" +sha512sums="114d931491faf8f2df71a050a87d2d895a73f48b3948da424f3c1def9da9ec9dec2db96b2a1fefafd25477dc285a010ea95ce0372174b139d081899e09be01d3 aaudit-emaildiff +a1db9c83165ca42bcddf37c13b23206b5d1e0d7c00f8d5f1ce942a8ee8d94d21f6ebd85d1e4be53111b7f7468968df18dc00b073c710f25a4ff1a726f11eee83 aaudit-import-tar +85911c1b5e548cfaf417b310abff0d42d0a5a77a49f40584275d55feef30a2c68413c1db70d946709a3bf794dc31ec70bc61c3e50f2a8e1d91e57e13dc6470b1 aaudit-create +6286214d25322f835156c2891cc509503df22fb979514c3a60a2bb3b520f0fe09e73bae80ed73ff0117e571956fa9cce17f1094e1d3f7698c19d14e80c36c5bd aaudit-refresh +da7bd0febcf45ee4db8fb32d54fe014830895aafb131b93ad5e1ee8e95bd0a67d12b7931362135ccd7661bbf54909d09be6308c68506970dfbdb7d6f8de70ad3 aaudit.conf" diff --git a/testing/aaudit/aaudit-create b/testing/aaudit/aaudit-create new file mode 100755 index 0000000000..450dec9e6e --- /dev/null +++ b/testing/aaudit/aaudit-create @@ -0,0 +1,20 @@ +#!/bin/sh -e + +IP="$1" +DESC="$2" + +if [ -z "$IP" -o -z "$DESC" ]; then + echo "usage: $0 <IP> <Description>" + exit 1 +fi + +git init --quiet --bare +echo "$IP" > aaudit-hostname +echo "$DESC ($IP)" > description + +if ! ssh root@$IP 'lbu package -' | gunzip | /usr/libexec/aaudit/aaudit-import-tar --initial-commit; then + git branch --quiet -D import + exit 1 +fi +git branch --quiet --force master import +git branch --quiet -D import diff --git a/testing/aaudit/aaudit-emaildiff b/testing/aaudit/aaudit-emaildiff new file mode 100755 index 0000000000..56d7541032 --- /dev/null +++ b/testing/aaudit/aaudit-emaildiff @@ -0,0 +1,61 @@ +#!/usr/bin/lua5.2 + +local posix = require 'posix' +local config_file = "/etc/aaudit/aaudit.conf" + +local function load_config(filename) + local F = io.open(filename, "r") + local cfg = "return {" .. F:read("*all").. "}" + F:close() + return loadstring(cfg, "config:"..filename)() +end + +local function match_file(fn, match_list) + if not match_list then return false end + local i, m + for i, pattern in ipairs(match_list) do + if posix.fnmatch(pattern, fn) then return true end + end + return false +end + +local CONF = load_config(config_file) +if CONF.notify_email == nil or CONF.smtp_server == nil then return end + +local visible, has_data = false, false +local diff = {} +for l in io.lines() do + local fn = l:match("^diff [^ \t]* a/([^ \t]*)") + if fn then + visible = not match_file(fn, CONF.no_notify_files) + if visible then + has_data = true + visible = not match_file(fn, CONF.private_files) + if not visible then + table.insert(diff, "Private file "..fn.." changed") + end + end + end + if visible then table.insert(diff, l) end +end + +if has_data then + local EMAIL = io.popen(string.format("sendmail -t -S %s", CONF.smtp_server), "w") + EMAIL:write(string.format([[ +From: %s <%s> +To: %s +Subject: Configuration change on %s +Date: %s + +This is automatically generated e-mail about the following configuration change: + +%s +]], + CONF.author_name or "Alpine Auditor", CONF.author_email or "auditor@alpine.local", + table.concat(CONF.notify_email, ", "), + arg[1], + os.date("%a, %d %b %Y %H:%M:%S"), + table.concat(diff, '\n') + )) + EMAIL:close() +end diff --git a/testing/aaudit/aaudit-import-tar b/testing/aaudit/aaudit-import-tar new file mode 100755 index 0000000000..effe937568 --- /dev/null +++ b/testing/aaudit/aaudit-import-tar @@ -0,0 +1,173 @@ +#!/usr/bin/lua5.2 + +local posix = require 'posix' +local branch_ref = "refs/heads/import" +local from_ref = "refs/heads/master" +local config_file = "/etc/aaudit/aaudit.conf" + +local function load_config(filename) + local F = io.open(filename, "r") + local cfg = "return {" .. F:read("*all").. "}" + F:close() + return loadstring(cfg, "config:"..filename)() +end + +local function match_file(fn, match_list) + if not match_list then return false end + local i, m + for i, pattern in ipairs(match_list) do + if posix.fnmatch(pattern, fn) then return true end + end + return false +end + +local function checksum_header(block) + local sum = 256 + for i = 1,148 do sum = sum + block:byte(i) end + for i = 157,500 do sum = sum + block:byte(i) end + return sum +end + +local function nullterm(s) return s:match("^[^%z]*") end +local function octal_to_number(str) return tonumber(nullterm(str), 8) end + +local function read_header_block(block) + local header = { + name = nullterm(block:sub(1,100)), + mode = octal_to_number(block:sub(101,108)), + uid = octal_to_number(block:sub(109,116)), + gid = octal_to_number(block:sub(117,124)), + size = octal_to_number(block:sub(125,136)), + mtime = octal_to_number(block:sub(137,148)), + chksum = octal_to_number(block:sub(149,156)), + typeflag = block:sub(157,157), + linkname = nullterm(block:sub(158,257)), + magic = block:sub(258,263), + version = block:sub(264,265), + uname = nullterm(block:sub(266,297)), + gname = nullterm(block:sub(298,329)), + devmajor = octal_to_number(block:sub(330,337)), + devminor = octal_to_number(block:sub(338,345)), + prefix = nullterm(block:sub(346,500)), + } + if header.magic ~= "ustar " and header.magic ~= "ustar\0" then + return false, "Invalid header magic "..header.magic + end + if header.version ~= "00" and header.version ~= " \0" then + return false, "Unknown version "..header.version + end + if not checksum_header(block) == header.chksum then + return false, "Failed header checksum" + end + return header +end + +function import_tar(CONF, TAR, GIT, initial_commit) + local blocksize = 512 + local zeroblock = string.rep("\0", blocksize) + local nextmark = 1 + local author_time = 0 + local all_files = {} + local long_name, long_link_name + local symlinkmode = tonumber('0120000', 8) + local rwmode = tonumber('0755', 8) + local romode = tonumber('0644', 8) + local wandmode = tonumber('0111', 8) + + local author_name = CONF.author_name or "Alpine Auditor" + local author_email = CONF.author_email or "auditor@alpine.local" + + while true do + local block = TAR:read(blocksize) + if not block then + return false, "Premature end of archive" + end + if block == zeroblock then break end + + local header, err = read_header_block(block) + if not header then return false, err end + + local file_data = TAR:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) + if header.typeflag == "L" then + long_name = nullterm(file_data) + elseif header.typeflag == "K" then + long_link_name = nullterm(file_data) + else + if long_name then + header.name = long_name + long_name = nil + end + if long_link_name then + header.linkname = long_link_name + long_link_name = nil + end + end + + if header.typeflag:match("^[0-46]$") and + not match_file(header.name, CONF.no_track_files) then + GIT:write('blob\nmark :'..nextmark..'\n') + if header.typeflag == "2" then + GIT:write('data '..#header.linkname..'\n'..header.linkname) + header.mode = symlinkmode + else + GIT:write('data '..header.size..'\n') + GIT:write(file_data) + end + GIT:write('\n') + + local fn = header.prefix..header.name + all_files[fn] = { mark=nextmark, mode=header.mode } + nextmark = nextmark + 1 + if header.mtime > author_time then author_time = header.mtime end + end + end + + GIT:write(string.format([[ +commit %s +author %s <%s> %d +0000 +committer %s <%s> %d +0000 +data <<END_OF_COMMIT_MESSAGE +%s +END_OF_COMMIT_MESSAGE + +]], + branch_ref, + author_name, author_email, author_time, + author_name, author_email, os.time(), + CONF.commit_message or "Changes" + )) + + if not initial_commit then GIT:write(string.format("from %s^0\n", from_ref)) end + GIT:write("deleteall\n") + local path, v + for path, v in pairs(all_files) do + local mode = v.mode + if mode ~= symlinkmode then + if bit32.band(mode, wandmode) then + mode = rwmode + else + mode = romode + end + end + GIT:write(string.format("M %o :%i %s\n", mode, v.mark, path)) + end + GIT:write("\n") + + return true +end + +local initial_commit = false +local a +for _, a in ipairs(arg) do + if a == '--initial-commit' then + initial_commit = true + else + os.exit(1) + end +end + +local GI = io.popen("git fast-import --quiet", "w") +local rc = import_tar(load_config(config_file), io.stdin, GI, initial_commit) +GI:close() + +if not rc then os.exit(1) end diff --git a/testing/aaudit/aaudit-refresh b/testing/aaudit/aaudit-refresh new file mode 100755 index 0000000000..6e400c5d8c --- /dev/null +++ b/testing/aaudit/aaudit-refresh @@ -0,0 +1,15 @@ +#!/bin/sh +if [ ! -f aaudit-hostname -o ! -f config -o ! -f description -o ! -d objects ]; then + echo "run in the created git repository" + exit 1 +fi +IP="$(cat aaudit-hostname)" +if ! ssh root@"$IP" 'lbu package -' | gunzip | /usr/libexec/aaudit/aaudit-import-tar; then + git branch --quiet -D import + exit 1 +fi +if ! git diff --quiet --exit-code master..import; then + git diff --patch-with-stat master..import | /usr/libexec/aaudit/aaudit-emaildiff "$(cat description)" + git branch --quiet --force master import +fi +git branch --quiet -D import diff --git a/testing/aaudit/aaudit.conf b/testing/aaudit/aaudit.conf new file mode 100644 index 0000000000..cfecde6e36 --- /dev/null +++ b/testing/aaudit/aaudit.conf @@ -0,0 +1,25 @@ +author_name = "Alpine Auditor"; +author_email = "audit@alpine.local"; +notify_email = { "engineers@alpine.local" }; +-- smtp_server = "<server>"; +commit_message = "Changes"; + +no_track_files = { + "*/.git/*", + "*.apk-new", + "*~", + "etc/unbound/root.hints", + "etc/chrony/chrony.drift", + "etc/ld.so.cache", +}; + +no_notify_files = { + "etc/acf/password", +}; + +private_files = { + "etc/shadow*", + "*.crt", + "*.pem", + "*.pfx", +}; |